Sendinput Doesn't Perform Click Mouse Button Unless I Move Cursor

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.

SendInput Mouse input click only?

You need to fill out an (array of) INPUT struct(s) containing the mouse details you want, and then you pass that array to SendInput(). This is pretty clearly explained in the SendInput() documentation:

Parameters

cInputs

Type: UINT

The number of structures in the pInputs array.

pInputs

Type: LPINPUT

An array of INPUT structures. Each structure represents an event to be inserted into the keyboard or mouse input stream.

cbSize

Type: int

The size, in bytes, of an INPUT structure. If cbSize is not the size of an INPUT structure, the function fails.

Also, your call to GetKeyState() is wrong, as it will never return a SHORT value that has its 9th bit set to 1. Per the GetKeyState() documentation, only the low (1st) bit or the high (16th) bit will ever be set to 1:

The return value specifies the status of the specified virtual key, as follows:

  • If the high-order bit is 1, the key is down; otherwise, it is up.
  • If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.

So, if your goal is to check if the left mouse button is currently held down, you need to use & 0x8000 (or < 0) instead of & 0x100 (even better, consider using GetAsyncKeyState() instead). See Check if left mouse button is held down?.

Try this instead:

if (toggled && (GetKeyState(VK_LBUTTON) < 0 /*& 0x8000*/))
{
INPUT input = {};
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, &input, sizeof(INPUT));
Sleep((rand() % 1000 / cps));
}

JNA / WinAPI. Simulate mouse click without moving the cursor doesn't work correctly

For the 3rd case, you did not use the MOUSEEVENTF_MOVE flag to move the mouse, so the mouse did not actually move. And also according to the document:

If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain
normalized absolute coordinates between 0 and 65,535

void mouseMove(int x, int y) {
INPUT move[2] = {};

DWORD fScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
DWORD fScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
move[0].type = move[1].type = INPUT_MOUSE;
move[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;// Release the mouse before moving it
move[1].mi.dx = MulDiv(x, 65535, fScreenWidth);
move[1].mi.dy = MulDiv(y, 65535, fScreenHeight);
move[1].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;

SendInput(2, move, sizeof(INPUT));
}

Then use the MOUSEEVENTF_LEFTDOWN and MOUSEEVENTF_LEFTUP to click the current postion.

Or you can directly merge the mouse move into the click event:

void mouseMoveClick(int x, int y) {
INPUT click[3] = {};

click[0].type = INPUT_MOUSE;
click[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;// Release the mouse before moving it

DWORD fScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
DWORD fScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
click[1].type = INPUT_MOUSE;
click[1].mi.dx = click[2].mi.dx= MulDiv(x, 65535, fScreenWidth);
click[1].mi.dy = click[2].mi.dy= MulDiv(y, 65535, fScreenHeight);
click[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;

click[2].type = INPUT_MOUSE;
click[2].mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;

SendInput(3, click, sizeof(INPUT));
}

If you want to move back to the original position after the mouse click, you can use GetCursorPos to record the current position before moving. Then use mouseMove event or simpler SetCursorPos to return to the position.

void click(int xCord, int yCord) {
//mouseMove(xCord, yCord);
POINT p = {};
GetCursorPos(&p);
mouseMoveClick(xCord, yCord);
SetCursorPos(p.x, p.y);
}

Performing a mouse click without moving cursor

You should use Win32 API.
Use pInvoked SendMessage from user32.dll

pInvoked Function

Then read about mouse events:
Mouse Input on msdn

And then read about: System events and Mouse Mess.......

Also there is lots of info:
Info

Mouse position values for SendInput

As discussed in the following question:

SendInput doesn't perform click mouse button unless I move cursor

The screen coordinates returned by GetCursorPos need to be converted to absolute and passed to SendInput:

dx =  (x * 65536) / GetSystemMetrics(SystemMetric.SM_CXSCREEN);
dy = (y * 65536) / GetSystemMetrics(SystemMetric.SM_CYSCREEN);

Lance.

Simulate mouse click without moving the cursor

Is there a way to simulate a mouseclick on a spot on the screen relative to the Windows location without actually moving the cursor?

To answer your specific question - NO. Mouse clicks can only be directed where the mouse cursor actually resides at the time of the click. The correct way to simulate mouse input is to use SendInput() (or mouse_event() on older systems). But those functions inject simulated events into the same input queue that the actual mouse driver posts to, so they will have a physical effect on the mouse cursor - ie move it around the screen, etc.

How do I simulate input without SendInput?

SendInput operates at the bottom level of the input stack. It is just a backdoor into the same input mechanism that the keyboard and mouse drivers use to tell the window manager that the user has generated input. The SendInput function doesn't know what will happen to the input. That is handled by much higher levels of the window manager, like the components which hit-test mouse input to see which window the message should initially be delivered to.

When something gets added to a queue, it takes time for it to come out the front of the queue

When you call Send­Input, you're putting input packets into the system hardware input queue. (Note: Not the official term. That's just what I'm calling it today.) This is the same input queue that the hardware device driver stack uses when physical devices report events.

The message goes into the hardware input queue, where the Raw Input Thread picks them up. The Raw Input Thread runs at high priority, so it's probably going to pick it up really quickly, but on a multi-core machine, your code can keep running while the second core runs the Raw Input Thread. And the Raw Input thread has some stuff it needs to do once it dequeues the event. If there are low-level input hooks, it has to call each of those hooks to see if any of them want to reject the input. (And those hooks can take who-knows-how-long to decide.) Only after all the low-level hooks sign off on the input is the Raw Input Thread allowed to modify the input state and cause Get­Async­Key­State to report that the key is down.

The only real way to do what you are asking for is to find the HWND of the UI control that is located at the desired screen coordinates. Then you can either:

  1. send WM_LBUTTONDOWN and WM_LBUTTONUP messages directly to it. Or, in the case of a standard Win32 button control, send a single BM_CLICK message instead.

  2. use the AccessibleObjectFromWindow() function of the UI Automation API to access the control's IAccessible interface, and then call its accDoDefaultAction() method, which for a button will click it.

That being said, ...

I don't have access to the buttons handle that is supposed to be clicked.

You can access anything that has an HWND. Have a look at WindowFromPoint(), for instance. You can use it to find the HWND of the button that occupies the desired screen coordinates (with caveats, of course: WindowFromPoint, ChildWindowFromPoint, RealChildWindowFromPoint, when will it all end?).



Related Topics



Leave a reply



Submit