0

I need to be able to simulate a mouse click on a control in another process. I came up with the following method:

BOOL SimulateMouseClick(POINT* pPntAt)
{
    //Simulate mouse left-click
    //'pPntAt' = mouse coordinate on the screen
    //RETURN:
    //      = TRUE if success
    BOOL bRes = FALSE;

    if(pPntAt)
    {
        //Get current mouse position
        POINT pntMouse = {0};
        BOOL bGotPntMouse = ::GetCursorPos(&pntMouse);

        //Move mouse to a new position
        ::SetCursorPos(pPntAt->x, pPntAt->y);

        //Send mouse click simulation
        INPUT inp = {0};
        inp.type = INPUT_MOUSE;
        inp.mi.dx = pPntAt->x;
        inp.mi.dy = pPntAt->y;
        inp.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
        if(SendInput(1, &inp, sizeof(inp)) == 1)
        {
            //Do I need to wait here?
            Sleep(100);

            inp.mi.dwFlags = MOUSEEVENTF_LEFTUP;
            if(SendInput(1, &inp, sizeof(inp)) == 1)
            {
                //Do I need to wait here before restoring mouse pos?
                Sleep(500);

                //Done
                bRes = TRUE;
            }
        }

        //Restore mouse
        if(bGotPntMouse)
        {
            ::SetCursorPos(pntMouse.x, pntMouse.y);
        }
    }

    return bRes;
}

My question is do I need to introduce those artificial delays like a human mouse click would have?

user2864740
  • 60,010
  • 15
  • 145
  • 220
c00000fd
  • 20,994
  • 29
  • 177
  • 400

1 Answers1

5

The documentation for SendInput contains the following:

The SendInput function inserts the events in the INPUT structures serially into the keyboard or mouse input stream. These events are not interspersed with other keyboard or mouse input events inserted either by the user (with the keyboard or mouse) or by calls to keybd_event, mouse_event, or other calls to SendInput.

This is the reason, why SendInput was introduced. Placing artificial delays between individual calls of SendInput completely defies its purpose.

The short answer is: No, you do not need to introduce delays between synthesized input. You also do not need to call SetCursorPos; the INPUT structure already contains the location of the mouse input.

Of course, you wouldn't have to deal with any of this, if you went with UI Automation instead. A design goal of UI Automation is "to manipulate the UI by means other than standard input. UI Automation also allows automated test scripts to interact with the UI."

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • As of 2020 (Windows 10), it seems that it is important to wait between calls of SetCursorPos and SendInput. Sometimes a Mouse down via SendInput is executed _before_ the cursor postion is updated. (Of course, if you do not use SetCursorPos at all, then you are safe) – eikuh May 26 '20 at 13:50
  • (^ This at least holds true for moving windows, i.e. dragging windows via title bar) – eikuh May 26 '20 at 14:05
  • @eik It's unclear why you would ever find a need to intermix `SetCursorPos` and `SendInput`. The latter allows you to specify mouse positions already. It's likewise unclear why you would ever find a need to move a window by means of injected input. Sure, your observations might be true. But then, if you are doing it wrong, all sorts of wrong can happen. – IInspectable May 26 '20 at 15:54
  • I am working via Windows Remote Desktop at the moment (Corona). Maybe this is why I observed such strange things. (The local mouse cursor has to be synchronized with the remote one) And maybe without Remote, things stay in order as you would expect. So maybe, forget what I have written. – eikuh May 29 '20 at 13:15
  • @eik You observe *"strange things"* because your expectations are off. There is no guaranteed order with respect to sequencing input from `SetCursorPos` and `SendInput`. And no one would ever need that guarantee anyway; `SendInput` allows you to do everything that `SetCursorPos` does. It's still wildly unclear, why you insist on intermixing those two API calls, when `SendInput` is sufficient for all intents and purposes. – IInspectable May 29 '20 at 13:27
  • Don't get me wrong: I do not insist on intermixing those two API calls. I just can imagine that people would do that because SetCurosPos is easier to use (no calculations). So my comment was just to warn people. – eikuh May 29 '20 at 13:46