2

I have a simple code

KEYBDINPUT k1 = { VK_MENU, 0, 0, 0, 0 };
KEYBDINPUT k2 = { VK_TAB, 0, 0, 0, 0 };
KEYBDINPUT k3 = { VK_TAB, 0, KEYEVENTF_KEYUP, 0, 0 };
KEYBDINPUT k4 = { VK_MENU, 0, KEYEVENTF_KEYUP, 0, 0 };
int cnt = 0;

while (cnt < 10)
{
    Sleep(1000);
    INPUT in1 = { INPUT_KEYBOARD };
    in1.ki = k1;
    SendInput(1, &in1, sizeof(INPUT));

    INPUT in2 = { INPUT_KEYBOARD };
    in2.ki = k2;
    INPUT in3 = { INPUT_KEYBOARD };
    in3.ki = k3;
    SendInput(1, &in2, sizeof(INPUT));
    SendInput(1, &in3, sizeof(INPUT));

    cnt++;
}

INPUT in4 = { INPUT_KEYBOARD };
in4.ki = k4;
SendInput(1, &in4, sizeof(INPUT));

return 0;

This does not work. If I change from VK_TAB to VK_ESCAPE it works.

I would want emulate Alt-Tab as Alt-Esc does not have a visual representation. Is there something special about VK_TAB?

Adorn
  • 1,403
  • 1
  • 23
  • 46
  • Have you tried passing SendInput an array with both events, and also checking the return value to see if the call succeeded? – Retired Ninja Feb 10 '15 at 07:58
  • @RetiredNinja yes, have tried that.. return value is 1 when sending event independently and is 2 when sending them in array – Adorn Feb 10 '15 at 08:31
  • Passing `1` as the `nInputs` parameter to [SendInput](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310.aspx) is the epitome of cluelessness: *"These events are not interspersed with other keyboard or mouse input events [...]"* – IInspectable Feb 10 '15 at 11:50

1 Answers1

0

When VKs fail, using SendInput with keyboard scan codes instead often works.

The example below demonstrates how to simulate alt-tab with SendInput and keyboard scan codes.

The alt_tab function takes a count. It will simulate holding down the left alt key, hitting the tab key "count" times, then letting go of the left alt key.

The keypress delay is pretty big, mostly to give adequate time to visually demonstrate the effect. Shorter delays will be more efficient for automation, but you probably cannot remove them altogether.

I pass 1 as the input count to SendInput because I only want to send one at a time. Manipulating KEYBDINPUT timestamps does not work the way one might expect.

To build this example, start with a Win32 Console project.

#include <Windows.h>

void sendkey(WORD scan_code, bool tf_down_up, bool extended=false) {
    INPUT input = {0};
    input.type = INPUT_KEYBOARD;
    input.ki.wScan = scan_code;
    input.ki.dwFlags                  = KEYEVENTF_SCANCODE;
    if(!tf_down_up) input.ki.dwFlags |= KEYEVENTF_KEYUP;
    if(extended)    input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
    SendInput(1, &input, sizeof(input));
}

void keydown(WORD scan_code, bool extended=false) {
    sendkey(scan_code, true, extended);
}

void keyup(WORD scan_code, bool extended=false) {
    sendkey(scan_code, false, extended);
}

static const WORD TAB_SCANCODE      = 0x0f;
static const WORD LEFT_ALT_SCANCODE = 0x38;

static const DWORD keypress_delay_ms = 500;

void alt_tab(int tab_count=1) {
    keydown(LEFT_ALT_SCANCODE);
    Sleep(keypress_delay_ms);
    for(int i=0; i<tab_count; ++i) {
        keydown(TAB_SCANCODE);
        Sleep(keypress_delay_ms);
        keyup(TAB_SCANCODE);
        Sleep(keypress_delay_ms);
    }
    keyup(LEFT_ALT_SCANCODE);
}

int main() {
    Sleep(1000);
    alt_tab(3);
}
Christopher Oicles
  • 3,017
  • 16
  • 11
  • 2
    No, seriously, you do **not** ever want to send a single input event. Ever. *Key down* and *key up* events absolutely **must** not be interspersed with other input. Failing to generate them in a single `SendInput` invocation is failing to provide a robust solution. Please study the [documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310.aspx) in depth. – IInspectable Feb 10 '15 at 13:11
  • There would be no way to control the timing of input events if saddled with the requirement of treating each set of inputs as some kind of atomic transaction. All events in the list would happen immediately, so there would be no way to simulate holding a key down for any length of time which would resemble a human keystroke. This kind of automation isn't expecting to fight with the human over keyboard input. – Christopher Oicles Feb 10 '15 at 17:14
  • [SendInput](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310.aspx): *"The SendInput function inserts the events in the INPUT structures **serially** into the keyboard or mouse input stream."* (emphasis mine) – IInspectable Feb 10 '15 at 17:24
  • The point that @IInspectable makes is the entire raise d'etre for `SendInput`. Put them in an array and inject them as an atomic unit. – David Heffernan Feb 10 '15 at 19:22
  • Keeping aside the good way of doing it, this still does NOT work? @ChristopherOicles, on which system have you tested this? – Adorn Feb 12 '15 at 07:21
  • @adorn I think this does not work on Win8+ systems as we need to have uiAccess=true or be a service as per: https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/4b6dbc43-a026-4957-9178-91d2001e2d0d/windows-8-block-alttab-simulation?forum=windowsaccessibilityandautomation can you please verify Chrsitopher – yatg Jul 02 '15 at 17:44
  • @IInspectable do you have an alternative solution? I see no solutions to this question and I am also in need for a solution in which the application has uiAccess=false and is not a service – yatg Jul 02 '15 at 17:47
  • @DavidHeffernan do you have a soution by chance? I see people saying this is wrong but no one sharing a solution. :( – yatg Jul 02 '15 at 17:47
  • I think a solution would be to run SendSAS before this code: https://msdn.microsoft.com/en-us/library/windows/desktop/dd979761%28v=vs.85%29.aspx . IF uiAccess=false and app is not a service, SendSAS will only work if the process is the currently focused/active window/process *I THINK* – yatg Jul 02 '15 at 17:54
  • @yatg: How is this related to the *secure attention sequence* (SAS)? – IInspectable Jul 02 '15 at 18:53
  • @IInspectable I'm not sure I'm not the expert, I'm just trying to help provide a solution here as I only see people saying "wrong" but not providing much else. Based on my reading from the social.msdn topic I linked 3 comments ago I suspect that, if it's not right it would be awesome if you could share you knowledge with us. I'm actually having this same issue where alt+tab wont work. – yatg Jul 02 '15 at 20:23