4
votes

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?

2
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
@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. - IInspectable
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. - user34660

2 Answers

4
votes

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;
-2
votes

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.