WPF stop mouse down event gaining Application focus - c#

In WinForms I used the following block of code to stop the application gaining focus by being clicked on:
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 0x0004;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
return;
}
base.WndProc(ref m);
}
Is there any alternative to this in a WPF application? Can I use a HwndSource? Here is what I have so far (WM_MOUSEACTIVATE alone does not work as required and the application still gets focus):
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle messages...
int WM_MOUSEACTIVATE = 0x0021;
int WM_LBUTTONDOWN = 0x0201; //513
int WM_LBUTTONUP = 0x0202; //514
int WM_LBUTTONDBLCLK = 0x0203; //515
if (msg == WM_MOUSEACTIVATE || msg == MA_NOACTIVATEANDEAT || msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP || msg == WM_LBUTTONDBLCLK)
{
handled = true;
}
return IntPtr.Zero;
}
How can I get the Message Result?

Resolved by using:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle messages...
int WM_MOUSEACTIVATE = 0x0021;
if (msg == WM_MOUSEACTIVATE )
{
handled = true;
return new IntPtr(MA_NOACTIVATEANDEAT);
}
return IntPtr.Zero;
}

Related

How to stop further processing global hotkeys in C#

I am trying to create a C# application that will react on a global hotkey; ALT+H and then when I release the ALT key. This actually does work very well but my problem is that when my application has done whatever it should do with the hotkey then it should stop this hotkey from being processed by other applications. I got most of my code below from this StackOverflow post, Global keyboard capture in C# application, but I have seen somewhere else that return (IntPtr)1; should be able to stop further processing of the key.
But... when I am in e.g. Word or Wordpad and I press ALT+H then Word shows all kind of menus - I don't want it to as I only want my application to do something :-)
I am sorry for this rather long code but I assume it is important so you can get the full overview. There is only 1 place where I use return (IntPtr)1;.
My code:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Input;
namespace MyNewProgram
{
static class Program
{
// Enable hotkeys
// https://stackoverflow.com/a/604417/2028935
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private const int WM_SYSKEYUP = 0x0105;
private const int VK_SHIFT = 0x10;
private const int VK_MENU = 0x12;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
// Other variables
public static bool isAltPressedInThisApp = false;
private static MainWindow MyMainWindow;
// --------------------------------------------------------------------------------------
[STAThread] // STAThreadAttribute indicates that the COM threading model for the application is single-threaded apartment, https://stackoverflow.com/a/1361048/2028935
static void Main()
{
// Hook application to keyboard
_hookID = SetHook(_proc);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MyMainWindow = new MainWindow();
Application.Run(MyMainWindow);
// Unhook application from keyboard
UnhookWindowsHookEx(_hookID);
}
// --------------------------------------------------------------------------------------
// Required functions for globally hooking the keyboard
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern short GetKeyState(int keyCode);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
// --------------------------------------------------------------------------------------
// Hook the keyboard - action
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
// React on KEYDOWN
if (nCode >= 0 && ((wParam == (IntPtr)WM_KEYDOWN) || (wParam == (IntPtr)WM_SYSKEYUP)))
{
int vkCode = Marshal.ReadInt32(lParam);
// H
if ((Keys)vkCode == Keys.H)
{
isAltPressedInThisApp = true;
// Is ALT pressed down
if ((GetKeyState(VK_MENU) & 0x8000) != 0)
{
Console.WriteLine("ALT + H");
return (IntPtr)1; // do not allow others to hook this key combo
}
}
}
// React on KEYUP
if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP)
{
int vkCode = Marshal.ReadInt32(lParam);
// Is ALT not pressed down
if ((Keys)vkCode == Keys.LMenu)
{
Console.WriteLine("ALT UP");
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
// --------------------------------------------------------------------------------------
// Hook the keyboard
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
}
}
I am not a solid C# developer as I am taking my first few babysteps here - so why would I throw myself in the deep waters of global hotkeys as one of the first things ;-) Is there anyone that can give some hints here as I probably have a silly mistake somewhere?
The idea behind, whenever the alt key pressed, it starts to swallow keys into one local list. if the pattern we need to see has been seen, it won't send, but for the every other pattern, it starts to send the keys again in the order it receives.
the code for examination phase:
enum WM
{
WM_KEYDOWN = 0x0100,
WM_KEYUP = 0x0101,
WM_SYSKEYUP = 0x0105,
WM_SYSKEYDOWN = 0x0104,
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
return CallNextHookEx(_hookID, nCode, wParam, lParam);
KBDLLHOOKSTRUCT kbd = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
Enum.TryParse<Keys>($"{kbd.vkCode}", out Keys key);
Enum.TryParse<WM>($"{wParam}", out WM message);
Console.WriteLine($"{message}:{key}");
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
when pressing alt+h and releasing, output:
WM_SYSKEYDOWN:LMenu
WM_SYSKEYDOWN:H
WM_SYSKEYUP:H
WM_KEYUP:LMenu
as you can see, windows sent both alt and h key. the code you provided only catch H key, so the window which receives keyboard messages think that alt pressed.
no one can fetch and filter out previously pressed key, so we need to catch alt key whenever we see it is pressed. if the next key not H, we should send the keys we have fetched in the order we received.
i have written the below code to handle the situation, but i can not be pretty sure how it works on the real windows machine cause i have an osx operating system just because of that i am running windows in the virtual machine which is also change key strokes when i'm pressing.
if it's still not enough, you can wait and i may be able to try and figure it out at my office in the real windows machine. but i think you get the idea and work it out on your own.
[StructLayout(LayoutKind.Sequential)]
public class KBDLLHOOKSTRUCT
{
public uint vkCode;
public uint scanCode;
public KBDLLHOOKSTRUCTFlags flags;
public uint time;
public UIntPtr dwExtraInfo;
}
[Flags]
public enum KBDLLHOOKSTRUCTFlags : uint
{
LLKHF_EXTENDED = 0x01,
LLKHF_INJECTED = 0x10,
LLKHF_ALTDOWN = 0x20,
LLKHF_UP = 0x80,
}
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
enum WM
{
WM_KEYDOWN = 0x0100,
WM_KEYUP = 0x0101,
WM_SYSKEYUP = 0x0105,
WM_SYSKEYDOWN = 0x0104,
}
private static void ReSendKeys(int index = -1)
{
_index = -1;
var copiedKeys = _swallowedKeys.ToArray();
for (int i = 0; i < copiedKeys.Length; ++i)
{
bool up = copiedKeys[i].Item1 == (IntPtr)WM.WM_SYSKEYUP || copiedKeys[i].Item1 == (IntPtr)WM.WM_KEYUP;
keybd_event((byte)copiedKeys[i].Item2.vkCode, (byte)copiedKeys[i].Item2.scanCode, up ? 2u : 0u, UIntPtr.Zero);
}
_index = index;
_swallowedKeys.Clear();
}
private static List<Tuple<IntPtr, KBDLLHOOKSTRUCT>> _swallowedKeys = new List<Tuple<IntPtr, KBDLLHOOKSTRUCT>>();
private static int _index = 0;
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
return CallNextHookEx(_hookID, nCode, wParam, lParam);
KBDLLHOOKSTRUCT kbd = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
Enum.TryParse<Keys>($"{kbd.vkCode}", out Keys key);
Enum.TryParse<WM>($"{wParam}", out WM message);
Console.Write($"{message}:{key}");
// we know that when _index is -1, ReSendKeys function has been called
// so do not filter out first alt key
if (_index == -1)
{
_index++;
Console.WriteLine();
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
// we are at the beginning of the sequence we will catch
// if it's alt key filter it out, and increment the variable
if (_index == 0)
{
_swallowedKeys.Add(new Tuple<IntPtr, KBDLLHOOKSTRUCT>(wParam, kbd));
if (message == WM.WM_SYSKEYDOWN && key == Keys.LMenu)
{
_index++;
Console.WriteLine(" filtered out");
return (IntPtr)1;
}
else
{
_swallowedKeys.Clear();
// do nothing
}
}
if (_index == 1)
{
_swallowedKeys.Add(new Tuple<IntPtr, KBDLLHOOKSTRUCT>(wParam, kbd));
// if the next key is H, then filter it out also
if (message == WM.WM_SYSKEYDOWN && key == Keys.H)
{
_index++;
_swallowedKeys.RemoveAt(_swallowedKeys.Count - 1);
Console.WriteLine(" filtered out");
return (IntPtr)1;
}
// if not, we filtered out wrong sequence, we need to resend them
else
{
Console.WriteLine();
ReSendKeys();
return (IntPtr)1;
}
}
if (_index == 2)
{
_swallowedKeys.Add(new Tuple<IntPtr, KBDLLHOOKSTRUCT>(wParam, kbd));
if (message == WM.WM_SYSKEYUP && key == Keys.H)
{
_index++;
_swallowedKeys.RemoveAt(_swallowedKeys.Count - 1);
Console.WriteLine(" filtered out");
return (IntPtr)1;
}
else
{
// if user pressed H but not released and pressed another key at the same time
// i will pass that situation, if u need to handle something like that, you got the idea, please fill that block of code
}
}
if (_index == 3)
{
_swallowedKeys.Add(new Tuple<IntPtr, KBDLLHOOKSTRUCT>(wParam, kbd));
if (message == WM.WM_KEYUP && key == Keys.LMenu)
{
_index = 0;
_swallowedKeys.Clear();
Console.WriteLine(" filtered out");
Console.WriteLine("shortcut disabled");
return (IntPtr)1;
}
else
{
Console.WriteLine();
// user has been pressed Alt + H, H released but not alt, so we can expect one H again, but we need to send this pressed key with Alt prefixed
ReSendKeys(1);
return (IntPtr)1;
}
}
Console.WriteLine();
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

How to synchronize scrolling of a textbox and listbox

I want to design a textbox which has index of each line on a separate list-box beside itself.everything is almost done but scrolling is still a problem for me.when I use WndProc to control scrolling, WM_VSCROLL works very well and makes both control scroll in same time,but when I want to send WM_MOUSEWHEEL via List-box,it doesn't work.I thought I can use a trick and iterate WM_VSCROLL when user moves mouse wheel but It doesn't work too.
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_VSCROLL )
{
Message newMessage = Message.Create(Sequence.Handle, m.Msg, m.WParam, m.LParam);
Sequence.DirectMessage(newMessage);//turn to thread
}
else if(m.Msg == WM_MOUSEWHEEL)
{
if((int)m.WParam<0)
{
Message newMessage = Message.Create(Sequence.Handle, WM_VSCROLL,(IntPtr)1,(IntPtr) 0);
Message newMessage2 = Message.Create(this.Handle, WM_VSCROLL, (IntPtr)1, (IntPtr)0);
Sequence.DirectMessage(newMessage);
base.WndProc(ref newMessage2);
}
else
{
Message newMessage = Message.Create(Sequence.Handle, WM_VSCROLL, (IntPtr)0, (IntPtr)0);
Message newMessage2 = Message.Create(this.Handle, WM_VSCROLL, (IntPtr)0, (IntPtr)0);
Sequence.DirectMessage(newMessage);
base.WndProc(ref newMessage2);
}
}
}
Sequence is the name of my list-box and this infers to my textbox.I would appreciate any kind of help... .
Do the same as WM_SCROLL:
[DllImport("user32.dll", EntryPoint = "SendMessage")]
internal static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL)
{
SendMessage(Sequence.Handle, (UInt32)m.Msg, m.WParam, m.LParam);
}
base.WndProc(ref m);
}

IntPtr WndProc no suitable method found to override c#

i was trying to override this WndProc in my win form application but got error IntPtr WndProc no suitable method found to override. my code as follows
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == NativeCalls.APIAttach && (uint)lParam == NativeCalls.SKYPECONTROLAPI_ATTACH_SUCCESS)
{
// Get the current handle to the Skype window
NativeCalls.HWND_BROADCAST = wParam;
handled = true;
return new IntPtr(1);
}
// Skype sends our program messages using WM_COPYDATA. the data is in lParam
if (msg == NativeCalls.WM_COPYDATA && wParam == NativeCalls.HWND_BROADCAST)
{
COPYDATASTRUCT data = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
StatusTextBox.Items.Add(data.lpData + Environment.NewLine);
// Check for connection
//if (data.lpData.IndexOf("CONNSTATUS ONLINE") > -1)
// ConnectButton.IsEnabled = false;
// Check for calls
IsCallInProgress(data.lpData);
handled = true;
return new IntPtr(1);
}
return IntPtr.Zero;
}
anyone can guide me what i am missing. thanks
Your method signature is incorrect, Form.WndProc you are overriding returns void.
protected virtual void WndProc(ref Message m)
I don't know where you got that code, port from C++ maybe? but it won't work with a WinForms form.

How to use this WndProc in Windows Forms application?

Please guide me how to use this WndProc in Windows Forms application:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == NativeCalls.APIAttach && (uint)lParam == NativeCalls.SKYPECONTROLAPI_ATTACH_SUCCESS)
{
// Get the current handle to the Skype window
NativeCalls.HWND_BROADCAST = wParam;
handled = true;
return new IntPtr(1);
}
// Skype sends our program messages using WM_COPYDATA. the data is in lParam
if (msg == NativeCalls.WM_COPYDATA && wParam == NativeCalls.HWND_BROADCAST)
{
COPYDATASTRUCT data = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
StatusTextBox.AppendText(data.lpData + Environment.NewLine);
// Check for connection
if (data.lpData.IndexOf("CONNSTATUS ONLINE") > -1)
ConnectButton.IsEnabled = false;
// Check for calls
IsCallInProgress(data.lpData);
handled = true;
return new IntPtr(1);
}
return IntPtr.Zero;
}
I have seen people use the above code in this way in WPF like
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// Attach WndProc
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
You can use Application.AddMessageFilter Method.
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public class TestMessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
// Blocks all the messages relating to the left mouse button.
if (m.Msg >= 513 && m.Msg <= 515)
{
Console.WriteLine("Processing the messages : " + m.Msg);
return true;
}
return false;
}
}
The prototype for WndProc in C# is:
protected virtual void WndProc(ref Message m)
So, you need to override this procedure in your class, assumed that it's derived from Control.
protected override void WndProc(ref Message m)
{
Boolean handled = false; m.Result = IntPtr.Zero;
if (m.Msg == NativeCalls.APIAttach && (uint)m.Param == NativeCalls.SKYPECONTROLAPI_ATTACH_SUCCESS)
{
// Get the current handle to the Skype window
NativeCalls.HWND_BROADCAST = m.WParam;
handled = true;
m.Result = new IntPtr(1);
}
// Skype sends our program messages using WM_COPYDATA. the data is in lParam
if (m.Msg == NativeCalls.WM_COPYDATA && m.WParam == NativeCalls.HWND_BROADCAST)
{
COPYDATASTRUCT data = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));
StatusTextBox.AppendText(data.lpData + Environment.NewLine);
// Check for connection
if (data.lpData.IndexOf("CONNSTATUS ONLINE") > -1)
ConnectButton.IsEnabled = false;
// Check for calls
IsCallInProgress(data.lpData);
handled = true;
m.Result = new IntPtr(1);
}
if (handled) DefWndProc(ref m); else base.WndProc(ref m);
}

WndProc to detect device unplug and plug

How can I know a devices is plug or unplug in WPF?
I am using the code below to detect device changes:
private void OnSourceInitialized(object sender, EventArgs e)
{
IntPtr windowHandle = (new WindowInteropHelper(this)).Handle;
HwndSource src = HwndSource.FromHwnd(windowHandle);
src.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle WM_DEVICECHANGE...
if (msg == 0x219)
{
InitHead();
}
return IntPtr.Zero;
}
Thank you.
EDITED:
I did the below, still not working:
if (msg == 0x0219)
{
switch (wParam.ToInt32())
{
case 0x8000:
{
InitHead();
}
break;
}
}
To detect if a device has been plugged in, , we add the hook to our Window_Loaded method that looks like the following
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(this.WndProc));
The handler looks as follows:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 0x0219 && (int)wParam == 0x8000) // 0x8000 is DBT_DEVICEARRIVAL
{
ProcessConnected();
}
return IntPtr.Zero;
}
Unfortunately, none of the DBT_DEVICE constants are triggered when a device is unplugged, rather they are called when you try to eject the device from Windows.

Categories

Resources