0

Given the following code

void foo() {
    INPUT input{};
    input.type = INPUT_MOUSE;
    input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    SendInput(1, &input, sizeof(input));
    input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
    SendInput(1, &input, sizeof(input));
};

is it a bug to pass a single-element array to SendInput in consecutive calls? This seems to be perfectly supported by the documentation.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • The question could be renamed to "How to correctly send a sequence of input events with SendInput?" because it is essentially what answer is all about. – user7860670 Oct 14 '17 at 14:02
  • @VTT: Yes, it could be. But that's not the question that gets asked. The question that gets asked over and over again is the one, that's in the title. Here's a [reference](https://stackoverflow.com/questions/46742660/c-execution-causes-monitor-to-disconnect#comment80434590_46742660). – IInspectable Oct 14 '17 at 14:05
  • 2
    The question title should be easier to find for users struggling with such issues and looking for help. I think that more generic title variant would be easier to discover. Passing `2` or `3` or `4` as a first argument could be a potential bug too if input sequence is supposed to be longer. So title just about passing `1` is too narrow. – user7860670 Oct 14 '17 at 14:14
  • 2
    @VTT: Then they are looking for a different question, not this one. – BoltClock Oct 14 '17 at 14:15
  • 1
    @BoltClock It seems that the point of this question is to cover a *common* case of `SendInput` misuse when users split input sequence sending into several `SendInput` invocations. – user7860670 Oct 14 '17 at 14:23
  • There is a [ongoing meta discussion](https://meta.stackoverflow.com/questions/357835/whats-primarily-opinion-based-about-the-question-does-this-code-exhibit-a-b#357835) about this question. It would be good if all the discussions could happen there. – BDL Oct 14 '17 at 14:26

1 Answers1

9

Short answer: Maybe.

Longer answer: It depends.

To see what it depends on, and when this matters, it helps to understand, why SendInput was introduced into the Windows API: For one, it consolidates the keybd_event and mouse_event APIs into a single API call. More importantly, it adds a significant feature that isn't available to the previous calls. This is called out in the documentation:

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.

In other words: SendInput establishes atomicity of injected input sequences, irrespective of external events outside the control of the calling code.

It is usually important to atomically inject input, when the input consists of a sequence of individual events, like in the question. The code injects a mouse button down followed by a mouse button up in 2 individual calls to SendInput. While the intention is to have a single mouse click event, the implementation allows other input sources to intersperse input. When another input source produces a mouse move event in between the mouse button down and up events, the intended click has turned into a drag-and-drop operation. Instead of selecting a file in File Explorer, that very same code has thrown the file into the Recycle Bin. That clearly constitutes a bug.

Likewise, injecting keyboard input consisting of key combinations generally requires atomicity guarantees. Injecting Ctrl+C requires all four input events to be in a single transaction. Otherwise, a (malicious) input source could synthesize a Ctrl key up event right after the Ctrl key down, leaving the code injecting a C, with a stray Ctrl key up event trailing. That's probably not what was intended either.

In summary: It is a bug to call SendInput repeatedly, passing 1 as the first argument if the following conditions are true:

  • The input consists of a sequence of individual input events.
  • The input is required to be interpreted as a single unit.
IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • 1
    This answer is just unnecessary verbose rehearsal of documentation. – user7860670 Oct 14 '17 at 13:42
  • 1
    @VTT: Is it? [This](https://stackoverflow.com/q/8021954/1889329) would disagree with not being necessary. Or [this](https://stackoverflow.com/a/11438156/1889329). [This](https://stackoverflow.com/q/11438677/1889329), [this](https://stackoverflow.com/q/23203944/1889329), or [this](https://stackoverflow.com/q/31606962/1889329). In fact, pick *any* random `SendInput` question, and you'll see, that this Q&A is dearly needed. – IInspectable Oct 14 '17 at 13:47
  • 1
    It could be shortened considerably, basically "If you are sending a sequence of input events and don't want other events getting in-between you must send the whole pack with a single call to `SendInput`." – user7860670 Oct 14 '17 at 13:58
  • 3
    @VTT: This is a Q&A site for everyone. If you believe you can do better, go ahead and submit your own answer. – IInspectable Oct 14 '17 at 14:00
  • 1
    I have checked and double checked many times that this supposed atomicity of `SendInput` is completely false. If `SendInput` is called right when a key is auto-repeating (i.e. the user is holding a key down), the auto-repeating key will be intermixed with the characters injected by `SendInput`. – GetFree May 07 '20 at 08:46
  • @get I cannot comment on test code I cannot see, nor on the presumed implications or consequences. – IInspectable May 07 '20 at 09:07
  • @IInspectable, I know and I'm sorry for that. I'll post a question showing the problem and I'll link it here. – GetFree May 07 '20 at 21:05