SendInput doesn't perform click mouse button unless I move cursor.
I would appreciate a help on this one, as I seems cannot wrap my head around it.
I have a program that perform mouse click on foreground window, in which I am using SendInput to emulate left mouse click. The issue is, that if I move cursor to clicking position than SendInput will make the click, however if I don't move cursor than no click happens even trough I do pass x and y points to the MouseInputData. I would like to perform left mouse click without the need of actually moving the cursor at all.
Bellow is the class I have (it fairly simple and stright forward)
namespace StackSolution.Classes { public static class SendInputClass { [DllImport("user32.dll", SetLastError = true)] static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize); [DllImport("user32.dll")] static extern bool SetCursorPos(int X, int Y); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool GetCursorPos(out Point lpPoint); [StructLayout(LayoutKind.Sequential)] struct INPUT { public SendInputEventType type; public MouseKeybdhardwareInputUnion mkhi; } [StructLayout(LayoutKind.Explicit)] struct MouseKeybdhardwareInputUnion { [FieldOffset(0)] public MouseInputData mi; [FieldOffset(0)] public KEYBDINPUT ki; [FieldOffset(0)] public HARDWAREINPUT hi; } [StructLayout(LayoutKind.Sequential)] struct KEYBDINPUT { public ushort wVk; public ushort wScan; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; } [StructLayout(LayoutKind.Sequential)] struct HARDWAREINPUT { public int uMsg; public short wParamL; public short wParamH; } struct MouseInputData { public int dx; public int dy; public uint mouseData; public MouseEventFlags dwFlags; public uint time; public IntPtr dwExtraInfo; } [Flags] enum MouseEventFlags : uint { MOUSEEVENTF_MOVE = 0x0001, MOUSEEVENTF_LEFTDOWN = 0x0002, MOUSEEVENTF_LEFTUP = 0x0004, MOUSEEVENTF_RIGHTDOWN = 0x0008, MOUSEEVENTF_RIGHTUP = 0x0010, MOUSEEVENTF_MIDDLEDOWN = 0x0020, MOUSEEVENTF_MIDDLEUP = 0x0040, MOUSEEVENTF_XDOWN = 0x0080, MOUSEEVENTF_XUP = 0x0100, MOUSEEVENTF_WHEEL = 0x0800, MOUSEEVENTF_VIRTUALDESK = 0x4000, MOUSEEVENTF_ABSOLUTE = 0x8000 } enum SendInputEventType : int { InputMouse, InputKeyboard, InputHardware } public static void ClickLeftMouseButton(int x, int y) { INPUT mouseInput = new INPUT(); mouseInput.type = SendInputEventType.InputMouse; mouseInput.mkhi.mi.dx = x; mouseInput.mkhi.mi.dy = y; mouseInput.mkhi.mi.mouseData = 0; //getting current cursor location Point p; if (GetCursorPos(out p)) SetCursorPos(x, y); mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN; SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP; SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); //returning cursor to previous position SetCursorPos(p.X, p.Y); } } }
Same ClickLeftMouseButton function will not click if I remove getting cursor position like that.
public static void ClickLeftMouseButton(int x, int y) { INPUT mouseInput = new INPUT(); mouseInput.type = SendInputEventType.InputMouse; mouseInput.mkhi.mi.dx = x; mouseInput.mkhi.mi.dy = y; mouseInput.mkhi.mi.mouseData = 0; mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN; SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP; SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); }
Thank you in advance.
There are a few things you should consider when using the SendInput
function.
If you do not specify the MOUSEEVENTF_ABSOLUTE
flag then dx
and dy
(MouseInputData structure) are relative coordinates to the current mouse position. If you do specify MOUSEEVENTF_ABSOLUTE
then dx
and dy
are absolute coordinates between 0 and 65535. So if your x and y coordinates are screen coordinates you should use the following function to calculate dx
and dy
:
enum SystemMetric { SM_CXSCREEN = 0, SM_CYSCREEN = 1, } [DllImport("user32.dll")] static extern int GetSystemMetrics(SystemMetric smIndex); int CalculateAbsoluteCoordinateX(int x) { return (x * 65536) / GetSystemMetrics(SystemMetric.SM_CXSCREEN); } int CalculateAbsoluteCoordinateY(int y) { return (y * 65536) / GetSystemMetrics(SystemMetric.SM_CYSCREEN); }
Furthermore before you send the MOUSEDOWN and MOUSEUP events to via SendInput you have to move the mouse to the control you want to click on:
public static void ClickLeftMouseButton(int x, int y) { INPUT mouseInput = new INPUT(); mouseInput.type = SendInputEventType.InputMouse; mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x); mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y); mouseInput.mkhi.mi.mouseData = 0; mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE |MouseEventFlags.MOUSEEVENTF_ABSOLUTE; SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN; SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP; SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); }
The above code assumes that x
and y
are screen pixel coordinates. You can calculate those coordinates for a button (the target) on a winform by using the following code:
Point screenCoordsCentre= button1.PointToScreen(new Point(button1.Width/2, button1.Height/2));
Hope, this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With