The subject is all in the title. Sorry if it's a duplicate, I really couldn't find anything on SO.
Asked
Active
Viewed 1,707 times
3
-
1See this [`link`](http://www.codeproject.com/Questions/362352/Csharp-Mouse-Event-outside-the-Form), it refers to the `WinForms`, but for WPF will be the same. Also see this question: http://stackoverflow.com/questions/13732070/how-can-i-capture-mouse-events-that-occur-outside-of-a-wpf-window – Anatoliy Nikolaev Mar 26 '14 at 12:22
1 Answers
5
Well, many thanks to Anatoliy Nikolaev for steering me in the right direction! That article helped me much and this answer was useful to make code from the article work. This is what I have now:
internal static class MouseHook
{
private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
private static int _mouseHookHandle;
private static HookProc _mouseDelegate;
private static event MouseUpEventHandler MouseUp;
public static event MouseUpEventHandler OnMouseUp
{
add
{
Subscribe();
MouseUp += value;
}
remove
{
MouseUp -= value;
Unsubscribe();
}
}
private static void Unsubscribe()
{
if (_mouseHookHandle != 0)
{
int result = UnhookWindowsHookEx(_mouseHookHandle);
_mouseHookHandle = 0;
_mouseDelegate = null;
if (result == 0)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode);
}
}
}
private static void Subscribe()
{
if (_mouseHookHandle == 0)
{
_mouseDelegate = MouseHookProc;
_mouseHookHandle = SetWindowsHookEx(WH_MOUSE_LL,
_mouseDelegate,
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
0);
if (_mouseHookHandle == 0)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode);
}
}
}
private static int MouseHookProc(int nCode, int wParam, IntPtr lParam)
{
if (nCode >= 0)
{
MSLLHOOKSTRUCT mouseHookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
if (wParam == WM_LBUTTONUP)
{
if (MouseUp != null)
{
MouseUp.Invoke(null, new Point(mouseHookStruct.pt.x, mouseHookStruct.pt.y));
}
}
}
return CallNextHookEx(_mouseHookHandle, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private const int WM_LBUTTONUP = 0x0202;
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern int UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);
}
public delegate void MouseUpEventHandler(object sender, Point p);
And using it is pretty simple:
MouseHook.OnMouseUp += MouseHookMouseUp;
-
i haven't actually checked if this works , but just by the look of it +1 . i'll let you know , this is exactly what i was looking for. – eran otzap Apr 03 '14 at 14:48
-
this works great , do you know of a way to cancel to the message processing after MouseHookProc , lets say i have a winform control and i wan't to revert click events from it , WM_LBUTTONDOWN i catch the message process and in some condition i would like it to stop there , and the control would not receive the mouse input. – eran otzap Apr 03 '14 at 15:11
-
@eran otzap If I understand you correctly, if you are using the code from my answer you need to unsubscribe: `MouseHook.OnMouseUp -= MouseHookMouseUp`. To stop control receiving mouse input I guess, you'll need to use a more "traditional" event handler like `control.MouseUp+=control_MouseUp` and a method should look like this: `void control_MouseUp(object sender, MouseButtonEventArgs e) { e.Handled = true; }` – lena Apr 04 '14 at 04:57
-
:) , i'm using a wimform component , it's Z-order is always higher and would occur before mouseup routed event handler. with this new information , can i re ask the above question? – eran otzap Apr 04 '14 at 14:33
-
Winforms component in WPF? Every time I was using Windows Forms Host it was pain because of airspace issue, some events weren't received at all. Anyway you better ask a separate question, it becomes hard for me to realize what you need without some code :) – lena Apr 04 '14 at 17:14