4

On a program that I'm developing I have to simulate keystrokes, and to do so I use the SendInput() method, passing as argument a vector containing the inputs which are part of the keystroke. My current code seems to work properly with all the combinations I'm testing, except Alt codes.

This is what I do currently:

// Press ALT
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_LMENU;
input.ki.wScan = 0;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Press NumPad2
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD2;
input.ki.wScan = 0;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Release NumPad2
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD2;
input.ki.wScan = 0;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Press NumPad1
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD1;
input.ki.wScan = 0;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Release NumPad1
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD1;
input.ki.wScan = 0;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Press NumPad2
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD2;
input.ki.wScan = 0;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Release NumPad2
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_NUMPAD2;
input.ki.wScan = 0;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

// Release ALT
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_LMENU;
input.ki.wScan = 0;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;    
keystroke.push_back(input);

SendInput(keystroke.size(), &keystroke[0], sizeof(keystroke[0]));

The push_backs are done in a for cycle, that's why I entirely redefine the input variable everytime.

This approach seems to work for every combination excluding Alt codes. How can I make them work too? Thank you.

PS: As you can notice, dwFlags never declares ALT (VK_LMENU) as an ExtendedKey since from my understanding only VK_RMENU (and not VK_LMENU) is such. This MSDN page seems to confirm so.

DiHase
  • 43
  • 5
  • 1
    Using magic numbers for the buttons and flags doesn't help the readability of the code. – tambre Mar 11 '18 at 19:52
  • I've replaced the raw values for virtual-key codes and dwFlags with their corresponding #define keywords. – DiHase Mar 11 '18 at 23:23

1 Answers1

3

Use scan codes instead of virtual keys. That injects keys a much lower level into the system and simulates real user typing more reliably than Virtual Keys.

It took me a while to find the definitive list of scan codes since there's some variances out there. But referencing the "set 1" column from the big table in the middle of this page seemed to work.

INPUT createScanCodeEvent(WORD scancode, bool isDown)
{
    INPUT input = {};
    input.type = INPUT_KEYBOARD;
    input.ki.wVk = 0;
    input.ki.wScan = scancode;
    input.ki.dwFlags = (isDown ? 0 : KEYEVENTF_KEYUP) | KEYEVENTF_SCANCODE;
    input.ki.time = 0;
    input.ki.dwExtraInfo = 0;
    return input;
}

int inject()
{
    std::vector<INPUT> keystroke;
    const WORD SCANCODE_ALT = 0x38;
    const WORD SCANCODE_NUMPAD_1 = 0x4f;
    const WORD SCANCODE_NUMPAD_2 = 0x50;

    keystroke.push_back(createScanCodeEvent(SCANCODE_ALT, true) );

    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_2, true));
    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_2, false));

    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_1, true));
    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_1, false));

    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_2, true));
    keystroke.push_back(createScanCodeEvent(SCANCODE_NUMPAD_2, false));

    keystroke.push_back(createScanCodeEvent(SCANCODE_ALT, false));

    SendInput(keystroke.size(), keystroke.data(), sizeof(keystroke[0]));

    return 0;
}
selbie
  • 100,020
  • 15
  • 103
  • 173
  • It worked, thank you a lot!!! Do you know why virtual keys aren't enough for the task? From what I've understood, virtual keys and scan codes share the same target - identifying a key - but while virtual keys are machine-independent, scan codes aren't and so virtual keys sounded like a better option to me. By the way, since what I have in input are virtual keys, I'm now using `MapVirtualKey(vKey, MAPVK_VK_TO_VSC)` to get the scan code from the virtual key. – DiHase Mar 11 '18 at 23:41
  • It's been a while, but as I recall, scan codes get injected at a much lower level in the input stack. Whereas VK's are pretty high in the stack. Some applications, such as games, exclusively listen for keyboard input at the lower levels and will miss any injected VKs. If you are trying to simulate a `╘` getting pressed with ALT+221, I suspect Windows is doing the translation somewhere in the middle. – selbie Mar 12 '18 at 00:51
  • can this work with alt + enter? – Nguyen Manh Feb 01 '23 at 04:43
  • @NguyenManh - yes. – selbie Feb 01 '23 at 08:13