4

If I wanted to simulate a keypress using an extended scan code like 0xE0 0x1D (for right CTRL), how would I simulate such a keypress in C? I've tried calling SendInput with two INPUT structs, but only the left CTRL key was "pressed". The same thing happens in the case of other keys that have a "twin" (Shift and Alt).

Secondly, how would one cause a keyup event for an "extended" key?

Mona the Monad
  • 2,265
  • 3
  • 19
  • 30
  • https://batchloaf.wordpress.com/2012/10/18/simulating-a-ctrl-v-keystroke-in-win32-c-or-c-using-sendinput/ – c-smile May 01 '16 at 22:32
  • 1
    The code at that link seems to be using virtual key codes instead of hardware scan codes. I'm looking for scan codes. – Mona the Monad May 01 '16 at 23:20
  • https://msdn.microsoft.com/en-us/library/windows/desktop/ms646306(v=vs.85).aspx – c-smile May 01 '16 at 23:34
  • @c-smile: Please don't ever link to online content that proposes to use `SendInput` with an *nInputs* argument of 1. It is published by people that have not read or have not comprehended the [documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310.aspx). – IInspectable May 02 '16 at 00:08
  • For the benefit of others, IInspectable posts many comments like that. Perhaps IInspectable considers their position to be the inspector but as far as I know it is not official. – Sam Hobbs May 02 '16 at 06:40

2 Answers2

4

The KEYBDINPUT structure has a KEYEVENTF_EXTENDEDKEY flag to handle the 0xE0 byte for you:

If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).

Try something like this:

INPUT inputs[2];
ZeroMemory(inputs, sizeof(inputs));

inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wScan = 0x1D;
inputs[0].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY;

CopyMemory(&inputs[1], &inputs[0], sizeof(INPUT));
inputs[1].ki.dwFlags |= KEYEVENTF_KEYUP;

SendInput(2, inputs, sizeof(INPUT));

However, I would suggest using a virtual key instead of a scan code:

INPUT inputs[2];
ZeroMemory(inputs, sizeof(inputs));

inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = VK_CONTROL;
inputs[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;

CopyMemory(&inputs[1], &inputs[0], sizeof(INPUT));
inputs[1].ki.dwFlags |= KEYEVENTF_KEYUP;

SendInput(2, inputs, sizeof(INPUT));

But, if you absolutely need a scan code, at least have a look at MapVirtualKey() to convert a virtual key into a scan code:

inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wScan = MapVirtualKey(VK_RCONTROL, MAPVK_VK_TO_VSC);
inputs[0].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
-2

You did not specify whether the keys are to be sent to the same application or another application. Using SendInput, we cannot specify where keys go. We must somehow ensure that the window is active and that the focus is set properly. Note that a SendInput will send a WM_KEYDOWN or WM_KEYUP message. You have more flexibility if you use SendMesage directly to send WM_KEYDOWN and WM_KEYUP messages. You specify the window handle of the window to send to. The window handle is for a text box or a control that takes text, not the window that the text box or other control is in.

This is how to determine the exact parameters to use in a SendMessage. Note that a SendInput will produce a SendMessage.

In Visual Studio click on the Tools menu. You will see "Spy++" and "Spy++ x64". I am not sure when we need one or the other but if one does not work then try the other. In Spy++ click on the Messages menu then "Logging Options...". In the upper-right area click on the Findor Tool and drag to a window. After you release the mouse, click on the Messages tab. Then click on "Clear All" then check the checkbox for "Keyboard". Note that the Messages menu also has commands for starting and stopping the logging but I think it is on by default. Go to the selected window and type the keys you want to try. Then look at the messages logged in Spy++. You will see all the messages that were sent to/from the window. I usually stop the logging as soon as I have everything I need since, depending on the messages selected for logging, there might be too many messages logged to be useful. If you are only logging keyboard messages then you won't get too many messages logged.

For me the Extended field is 1 for the right Ctrl and 0 for the left Ctrl.

Sam Hobbs
  • 2,594
  • 3
  • 21
  • 32
  • The question is asking, which parameters to pass to `SendInput`. Observing the messages that are generated from the (injected) input is of no help. – IInspectable May 02 '16 at 07:55
  • P.S.: You pick Spy++ with the bitness matching the bitness of the target process. – IInspectable May 02 '16 at 07:59
  • @IInspectable, no, the question is not "which parameters to pass to SendInput". It asks "how would I simulate such a keypress". The Spy++ tool shows exactly how to do that. It shows the exact parameters to use in a SendMessage. Knowing how to use Spy++ will help with many more things in the future. – Sam Hobbs May 03 '16 at 00:41
  • [You can't simulate keyboard input using PostMessage](https://blogs.msdn.microsoft.com/oldnewthing/20050530-11/?p=35513/). – IInspectable May 03 '16 at 05:04