c++ - SendInput() неправильно управляет кодами Alt

В программе, которую я разрабатываю, мне нужно имитировать нажатия клавиш, и для этого я использую метод SendInput(), передавая в качестве аргумента вектор, содержащий входные данные, которые являются частью нажатия клавиши. Мой текущий код, кажется, работает правильно со всеми комбинациями, которые я тестирую, кроме кодов Alt.

Это то, что я делаю в настоящее время:

// 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]));

push_back выполняются в цикле for, поэтому я каждый раз полностью переопределяю переменную input.

Этот подход работает для любой комбинации, кроме альтернативных кодов. Как я могу заставить их тоже работать? Спасибо.

PS: Как вы можете заметить, dwFlags никогда не объявляет ALT (VK_LMENU) как ExtendedKey, поскольку, насколько я понимаю, таковым является только VK_RMENU (а не VK_LMENU). Эта страница MSDN вроде подтверждает.


person DiHase    schedule 11.03.2018    source источник
comment
Использование магических чисел для кнопок и флажков не улучшает читаемость кода.   -  person tambre    schedule 11.03.2018
comment
Я заменил необработанные значения для кодов виртуальных ключей и dwFlags соответствующими ключевыми словами #define.   -  person DiHase    schedule 12.03.2018


Ответы (1)


Используйте скан-коды вместо виртуальных ключей. Это вводит ключи гораздо более низкого уровня в систему и более надежно имитирует ввод текста пользователем, чем виртуальные ключи.

Мне потребовалось некоторое время, чтобы найти окончательный список кодов сканирования, так как там есть некоторые различия. Но ссылка на столбец «набор 1» из большой таблицы в середине этой страницы казалось, работает.

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;
}
person selbie    schedule 11.03.2018
comment
Сработало, большое спасибо!!! Знаете, почему виртуальных ключей недостаточно для этой задачи? Насколько я понял, виртуальные ключи и скан-коды имеют одну и ту же цель — идентификацию ключа, — но в то время как виртуальные ключи не зависят от машины, скан-коды — нет, поэтому виртуальные ключи кажутся мне лучшим вариантом. Кстати, поскольку у меня на входе есть виртуальные ключи, я теперь использую MapVirtualKey(vKey, MAPVK_VK_TO_VSC) для получения скан-кода из виртуального ключа. - person DiHase; 12.03.2018
comment
Прошло некоторое время, но, насколько я помню, коды сканирования вводятся на гораздо более низком уровне входного стека. Принимая во внимание, что ВКонтакте довольно высоко в стеке. Некоторые приложения, такие как игры, прослушивают исключительно ввод с клавиатуры на более низких уровнях и пропускают любые введенные ВК. Если вы пытаетесь имитировать нажатие клавиши с помощью ALT+221, я подозреваю, что Windows выполняет перевод где-то посередине. - person selbie; 12.03.2018