I have code very similar to this question running in a windows tray application, even with this exact code from the question I get the same behavior. It all works well on classic windows applications, such as Firefox, Chrome, Windows Explorer etc. However when the mouse focus gets to a UWP app such as Edge or Calendar or Mail the scroll becomes jittery and after a few dozen scrolls performed my application hangs and can't even be terminated from task manager (permission denied), this behavior is very reproducible.
I'll paste the code from the question here:
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace EnableMacScrolling
{
class InterceptMouse
{
const int INPUT_MOUSE = 0;
const int MOUSEEVENTF_WHEEL = 0x0800;
const int WH_MOUSE_LL = 14;
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
if (_hookID == null)
{
MessageBox.Show("SetWindowsHookEx Failed");
return;
}
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
Console.WriteLine(hookStruct.mouseData);
if (hookStruct.flags != -1) //prevents recursive call to self
{
INPUT input;
input = new INPUT();
input.type = INPUT_MOUSE;
input.mi.dx = 0;
input.mi.dy = 0;
input.mi.dwFlags = MOUSEEVENTF_WHEEL;
input.mi.time = 0;
input.mi.dwExtraInfo = 0;
input.mi.mouseData = -(hookStruct.mouseData >> 16);
try
{
SendInput(1, ref input, Marshal.SizeOf(input));
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
return (IntPtr)1;
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private enum MouseMessages
{
WM_MOUSEWHEEL = 0x020A
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public int mouseData;
public int flags;
public int time;
public IntPtr dwExtraInfo;
}
public struct INPUT
{
public int type;
public MOUSEINPUT mi;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public uint dwFlags;
public int time;
public int dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc 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);
[DllImport("User32.dll", SetLastError = true)]
public static extern int SendInput(int nInputs, ref INPUT pInputs, int cbSize);
} }
Is it possible that I'm dealing with a bug in windows here? Any pointers to how I can find out what's going on?
Update:
I have created a test Win32 application in C++ to more easily reproduce/demonstrate the problem. The issue is with the SendCommand which when executed while any classic application is in focus works fine. However when executed while a UWP application is in focus, or even the windows launch/start menu causes the calling application (my application) to hang and be stuck until windows is restarted.
An effective workaround/solution for this problem is to perform the SendCommand call on another thread from the thread handling the hook callback. Immediately launching the thread that executes SendCommand and returning from the hook callback produces the desired behavior and doesn't cause any problems.
if (hookStruct.flags != -1) //prevents recursive call to self
That's rather important, yes. But how the statement could possibly do its job is very unclear. The expected value of this field is 0, 1 or 3. Never -1. You perhaps got mislead by another mouse hook that is active on your machine.
Now it does matter whether a WinRT app is in the foreground. Because then the message broker is involved and the field value changes, the LLMHF_LOWER_IL_INJECTED bit is turned on. WinRT apps run in a sandbox that run at a lower integrity level. So the field will not be -1 and your SendInput() call triggers the mouse hook again. On and on it goes, show is over when it runs out of stack.
So first possible fix is to use the field as intended, change the statement to:
if ((hookStruct.flags & 1) == 0)
Won't work if that presumed wonky mouse hook is corrupting the field, then consider using a static bool field in your class to break the recursion. Set it to true before the SendInput() call, false afterwards.
But I think I know why you are doing this, I too have been a victim of a trackpad that got it backwards. There is a much easier way to do it, just modify the FlipFlopWheel setting.
Related
I'm creating a desktop UWP app and I need to set a global low level mouse hook to detect and change the position of it when it is moved to certain locations of the screen.
It works fine while my app's window is in focus and the values get logged correctly to the output window(meaning that the hook is working correctly).
This UWP app isn't going to be on the store and will only be used on a Windows 10 desktop (1903+).
I've tried calling SetWindowsHookEx on a different thread (which didn't do anything).
Tried also passing a thread ID when calling SetWindowsHookEx to no avail.
Also tried using the following restricted capabilities to prevent the app to suspend when not on focus: extendedExecutionUnconstrained and extendedBackgroundTaskTime along with the PreventFromSuspending method shown here.
Another thing I tried was to set uiAccess to true on the app manifest, which also didn't work.
The global hook is supposed to work even when the app isn't in the foreground, but instead it just works when it has the active window focus.
#region Structures
[StructLayout(LayoutKind.Sequential)]
/* MSLLHOOKSTRUCT */
public struct NativeMouseLowLevelHook
{
public override string ToString()
{
return $"{nameof(Point)}: {Point}, {nameof(MouseData)}: {MouseData}, {nameof(Flags)}: {Flags}";
}
public NativePoint Point;
public int MouseData;
public int Flags;
public int Time;
public UIntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public class NativePoint
{
public override string ToString()
{
return $"{nameof(X)}: {X}, {nameof(Y)}: {Y}";
}
public int X;
public int Y;
}
#endregion
#region Hook
public class ManagedMouseHook : SafeHandleZeroOrMinusOneIsInvalid
{
public static List<ManagedMouseHook> KnownHooks { get; set; } = new List<ManagedMouseHook>();
public HookProc HookImpl { get; set; }
public ManagedMouseHook() : base(true)
{
Hook();
}
private void Hook()
{
HookImpl = NativeHookCallback;
KnownHooks.Add(this);
using (var curProcess = Process.GetCurrentProcess())
using (var curModule = curProcess.MainModule)
{
DoHook(curModule);
}
}
private void DoHook(ProcessModule curModule)
{
SetHandle(SetWindowsHookEx(14 /*WH_MOUSE_LL*/, HookImpl, GetModuleHandle(curModule.ModuleName), 0));
}
private bool UnHook()
{
var result = UnhookWindowsHookEx(DangerousGetHandle());
KnownHooks.Remove(this);
HookImpl = null;
return result;
}
/* LowLevelMouseProc */
private IntPtr NativeHookCallback(int code, IntPtr wparam, IntPtr lparam)
{
if (code >= 0)
{
var info = (NativeMouseLowLevelHook) Marshal.PtrToStructure(lparam,
typeof(NativeMouseLowLevelHook));
Debug.WriteLine(info); //Output example: Point: X: 408, Y: 535, MouseData: 0, Flags: 0
return new IntPtr(-1);
}
return CallNextHookEx(IntPtr.Zero, code, wparam, lparam);
}
protected override bool ReleaseHandle()
{
return UnHook();
}
}
#endregion
#region Interop
public delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr hMod, ulong dwThreadId);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam,
IntPtr lParam);
#endregion
Then, to start using it:
public ManagedMouseHook MouseHook { get; set; }
MouseHook/*property*/ = new ManagedMouseHook();
And to unhook:
MouseHook/*property*/.Close();
UWP apps are running in the sandbox, so that doesn't sound strange. If you think a bit it is a security problem if the app can receive such an input and as 'Security' is listed as No.1 characteristic of the UWP this behavior is expected.
I've decided with the help of the comments that the best way to do this is to use my UWP app as a front-end and using a win32 app for the hooking functionality itself.
I borrowed the following code I found online (the comments aren't even mine). When I click a button on my form, it waits and detects my next mouse click. Whatever I click on, it gets that information in the winHandle object inside the HookCallback method:
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
static IntPtr hHook = IntPtr.Zero;
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
// The application runs to here when you click on the window whose handle you want to get
POINT cusorPoint;
bool ret = GetCursorPos(out cusorPoint);
// cusorPoint contains your cusor’s position when you click on the window
// Then use cusorPoint to get the handle of the window you clicked
IntPtr winHandle = WindowFromPoint(cusorPoint);
// winHandle is the Hanle you need
// Now you have get the handle, do what you want here
// ………………………………………………….
Debug.WriteLine("Handle: " + winHandle.ToString());
// Because the hook may occupy much memory, so remember to uninstall the hook after
// you finish your work, and that is what the following code does.
UnhookWindowsHookEx(hHook);
hHook = IntPtr.Zero;
// Here I do not use the GetActiveWindow(). Let's call the window you clicked "DesWindow" and explain my reason.
// I think the hook intercepts the mouse click message before the mouse click message delivered to the DesWindow's
// message queue. The application came to this function before the DesWindow became the active window, so the handle
// abtained from calling GetActiveWindow() here is not the DesWindow's handle, I did some tests, and What I got is always
// the Form's handle, but not the DesWindow's handle. You can do some test too.
//IntPtr handle = GetActiveWindow();
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[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, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc 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);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out POINT lpPoint);
[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(POINT Point);
private void GetProcess_Click(object sender, EventArgs e)
{
if (IntPtr.Zero == hHook){
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
hHook = SetWindowsHookEx(WH_MOUSE_LL, _proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
}
The problem is I need to use the information from that object elsewhere in my code. But, since it doesn't return that information, I'm not sure how I could get access to it.
I don't think I can return it because it goes instead over to the CallNextHookEx method; I've tried putting it in its own class, but inside the HookCallBack method I don't have access to this. or datasets or anything else.
So what can I do to get that information from outside the static method HookCallback?
I'm using the following code trying to get OS wide keyboard inputs with no luck:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
while(true)
continue;
}
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);
}
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine(vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[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);
}
HookCallback is simply not being called. I have a suspicion it's trying to listen only to a form which doesn't exist rather than running system wide.
Low-level Windows hooks internally use Windows messaging. The thread that calls SetWindowsHookEx must have the message loop in the end, which allows to call HookCallback function. In C++ message loop looks like this:
MSG msg;
BOOL result;
for (;;)
{
result = GetMessage(&msg, nullptr, 0, 0);
if (result <= 0)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Find all required PInvoke definitions for GetMessage, TranslateMessage, DispatchMessage and MSG, translate this code to C# and place it instead of your endless loop while(true). You can find all this stuff at PInvoke.Net, see also this Microsoft forum discussion:
Console keyboard hook not getting called
https://social.msdn.microsoft.com/Forums/vstudio/en-US/ed5be22c-cef8-4615-a625-d05caf113afc/console-keyboard-hook-not-getting-called?forum=csharpgeneral
I'm obviously very late but just hoping I could help (if the OP haven't have yet the help he/she needed) so I'm posting my answer.
It says in the MSDN documentation that when you want to set a system-wide hook, you must give the hMod parameter a
handle to the DLL containing the hook procedure pointed to by the lpfn
parameter
and
If the dwThreadId parameter is zero or specifies the identifier of a
thread created by a different process, the lpfn parameter must point
to a hook procedure in a DLL
but, look at this:
SetWindowsHookEx(2, kbdHookProc, GetModuleHandle("user32"), 0)
kbdHookProc is a function in my C# winforms application but the value I gave in the hMod parameter is the hinstance obtained by loading user32.dll via GetModuleHandle. I am using the keyboard hook (WH_KEYBOARD) to monitor locking of capslock, numlock and scroll lock keys. Don't ask me why I did that and would it work or why it works because I don't know but, yes, IT WORKS!
For a full answer to this;
As Alex says, you'll need a message loop to process windows messages and call your hooks,
public class MessageLoop
{
[DllImport("user32.dll")]
private static extern int GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin,
uint wMsgFilterMax);
[DllImport("user32.dll")]
private static extern bool TranslateMessage([In] ref MSG lpMsg);
[DllImport("user32.dll")]
private static extern IntPtr DispatchMessage([In] ref MSG lpmsg);
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
IntPtr hwnd;
uint message;
UIntPtr wParam;
IntPtr lParam;
int time;
POINT pt;
int lPrivate;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
X = x;
Y = y;
}
public static implicit operator System.Drawing.Point(POINT p)
{
return new System.Drawing.Point(p.X, p.Y);
}
public static implicit operator POINT(System.Drawing.Point p)
{
return new POINT(p.X, p.Y);
}
public override string ToString()
{
return $"X: {X}, Y: {Y}";
}
}
private Action InitialAction { get; }
private Thread? Thread { get; set; }
public bool IsRunning { get; private set; }
public MessageLoop(Action initialAction)
{
InitialAction = initialAction;
}
public void Start()
{
IsRunning = true;
Thread = new Thread(() =>
{
InitialAction.Invoke();
while (IsRunning)
{
var result = GetMessage(out var message, IntPtr.Zero, 0, 0);
if (result <= 0)
{
Stop();
continue;
}
TranslateMessage(ref message);
DispatchMessage(ref message);
}
});
Thread.Start();
}
public void Stop()
{
IsRunning = false;
}
}
I use a separate thread here to avoid blocking the main thread.
The InterceptKeys class as shown in the question needs no modification;
class InterceptKeys
{
// ...
public static void Main()
{
var loop = new MessageLoop(() => {
_hookID = SetHook(_proc);
});
while (Console.ReadKey(true) != ConsoleKey.X) // For exemplary purposes
{
continue;
}
loop.Stop();
}
// ...
}
EDIT3:
I need a list from all windows a thread has. Not FindWindowsEnum() because it only returns Top level Windows.... I need the window handle befor it's visible
END EDIT3
EDIT2:
Short desciption: I need a method, where i can get a "window handle" from a thread.
END EDIT2:
EDIT:
First of all i can't use FindWindowsEnum()!!!
Because it only returns the top windows. I have to kill the window befor it is visible. So i have to get The Handle of the window by a Thread ID.
EDIT END:
I got a problem by a window which i have to close which is not focused or something like that. I have to close the window as it pops up. I only use code.
What i got:
This is the extern class where I import one dll and some functions which use the functions from the dll.
class FindWindowApi
{
//[DllImport("user32.dll", SetLastError = true)]
//public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public IntPtr[] GetWindowHandlesForThread(int threadHandle)
{
_results.Clear();
EnumWindows(WindowEnum, threadHandle);
return _results.ToArray();
}
public delegate int EnumWindowsProc(IntPtr hwnd, int lParam);
[DllImport("user32.Dll")]
public static extern int EnumWindows(EnumWindowsProc x, int y);
public List<IntPtr> _results = new List<IntPtr>();
public int WindowEnum(IntPtr hWnd, int lParam)
{
_results.Add(hWnd);
return 1;
}
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
public static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowText(
IntPtr handle,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder caption,
int count);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowTextLength(IntPtr handle);
public const UInt32 WM_CLOSE = 0x0010;
}
at this class i use the functions from the extern class.
I start a Thread which runs every 10 milli secounds and kill a window in another method.
public Disk_UC()
{
InitializeComponent();
Thread killit = new Thread(this.killIt);
killit.Start();
comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
comboBox2.DropDownStyle = ComboBoxStyle.DropDownList;
Thread nt = new Thread(this.fillData);
nt.Start();
}
//Thread Method
private void killIt()
{
bool blac = false;
Int32 oldThreadID = threadID;
FindWindowApi api = new FindWindowApi();
while ((!blac)
&& (!MainDiag.isGoingDown))
{
if (oldThreadID != threadID)
{
IntPtr[] windows = api.GetWindowHandlesForThread(threadID);
if (windows != null && windows.Length > 0)
foreach (IntPtr hWnd in windows)
{
killWindow(hWnd, threadID);
}
}
Thread.Sleep(10);
}
}
//Method which calls all the extern dll stuff
private bool killWindow(IntPtr handle, int param)
{
var length = FindWindowApi.GetWindowTextLength(handle);
var caption = new StringBuilder(length + 1);
FindWindowApi.GetWindowText(handle, caption, caption.Capacity);
IntPtr windowPtr = FindWindowApi.FindWindowByCaption(IntPtr.Zero, caption.ToString());
if (windowPtr == IntPtr.Zero)
{
return false;
}
FindWindowApi.SendMessage(windowPtr, FindWindowApi.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
return true;
}
My Problem is now how can i get this specific window handle.
when the Thread "fillData" pops up the window. So i save the thread ID from this Thread fillData.
Now i call the other Methods with this thread id. I got the Thread ID and i get so many windows from the Process. But i need this specific window from that thread.
This question already has answers here:
Capturing mouse/keyboard events outside of form (app running in background)
(2 answers)
Closed 5 years ago.
I know how to modify cursor position from examples on MSDN.
My question is how to check position of mouse while mouse moves and then print X and Y position to representing labels?
EDIT: Lets say I want to track my mouse position from my entire screen.
EDIT 2: My app will be in the back ground/minimized.
I'm already using Mouse Hooks:
namespace Program
{
public partial class MouseHook
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
public void DoMouseClick()
{
int X = Cursor.Position.X;
int Y = Cursor.Position.Y;
IntPtr newP = new IntPtr(Convert.ToInt64("0", 16));
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, newP);
}
}
}
Here is the msdn documentation on system level mouse event handling calls (low level mouse proc).
Here is an example of using low level mouse procs to change the scroll event.
In the answer in the second link use WM_MOUSEMOVE from here instead of WM_MOUSEWHEEL.
One thing to note: for this program to continue to capture mouse events when the mouse is over a program with elevated privileges, this program will have to be launch with elevated privileges.
Code (not tested):
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace CatchMouseMove
{
class InterceptMouse
{
const int INPUT_MOUSE = 0;
const int MOUSEEVENTF_WHEEL = 0x0800;
const int WH_MOUSE_LL = 14;
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
if (_hookID == null)
{
MessageBox.Show("SetWindowsHookEx Failed");
return;
}
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
int xPos = 0;
int yPos = 0;
if (nCode >= 0 && MouseMessages.WM_MOUSEMOVE == (MouseMessages)wParam)
{
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
//do stuff with xPos and yPos
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private enum MouseMessages
{
WM_MOUSEMOVE = 0x0200
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public int mouseData;
public int flags;
public int time;
public IntPtr dwExtraInfo;
}
public struct INPUT
{
public int type;
public MOUSEINPUT mi;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public uint dwFlags;
public int time;
public int dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc 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);
}
}
You need to set a Windows hook in order to achieve this. The MSDN article How to set a Windows hook in Visual C# .NET shows how to set a mouse hook.
I tried it, it captures the mouse all over the form, even when the mouse cursor is over a control.
You can use the EventArgs of the MouseMove event, because it holds the mouse coordinates. From there you can easily set the text property of the label to the X or Y coordinate you will take from e (the MouseMove EventArgs).
private void Form_MouseMove(object sender, MouseEventArgs e)
{
// Update the mouse coordinates displayed in the textbox.
myTextBox.Text = e.Location.ToString();
}