SendInput doesn't perform click mouse button unless I move cursor
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.
Related videos on Youtube
Dmitris
Updated on December 01, 2020Comments
-
Dmitris over 3 years
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.
-
user1703401 over 12 yearsIt isn't clear where you are getting the x and y coordinates from and what they exactly mean. The missing MOUSEEVENTF_ABSOLUTE flag does look like a problem.
-
-
Dmitris over 12 yearsThanks a lot for the help, it actually explains few things I have been wondering about.
-
Jet almost 11 yearsThanks. But do you know how to do it without moving the mouse to that cordinate? (I want to create double-mouse).
-
tcboy88 almost 10 yearshow to simulate mouse click without moving the cursor position first? liked mentioned in the question.
-
tcboy88 almost 10 yearssimulate mouse clicks without moving the cursor position first. The cursor position should remain in where it was.
-
Hans almost 10 years@tcboy88: The only way I can think of is using Windows messages such as WM_LBUTTONDOWN and the Win32 API SendMessage.