SendInput() не равно нажатию клавиши на клавиатуре вручную в C++?

Я хотел написать код на C++ для эмуляции нажатия клавиши "A":

// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;

// Press the "..." key
ip.ki.wVk = code; // virtual-key code for the "a" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));

// Release the "..." key
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));

Он отлично работает, когда я запускаю другую программу и жду, пока выполнится моя программа, нажимается "A" и первая программа реагирует на него. Но я обнаружил, что в другом приложении мои действия были каким-то образом предотвращены (я могу вручную нажать "A" на клавиатуре, но использование моей программы не вызывает никаких действий).

Итак, что я могу сделать, чтобы сделать нажатие "A" из программы более идентичным нажатию вручную "A" (чтобы вторая программа не распознала, что он был вызван из программы)?

У меня нет исходного кода второй программы и я не знаю, как он распознает, что "A" не был нажат вручную.

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

3 ответа

Вы также можете использовать SendInput() для отправки кодов аппаратного сканирования (в отличие от кодов виртуального сканирования, которые DirectInput может игнорировать). Это плохо документировано, но SendInput() действительно может обойти DirectInput. Причина, по которой решение Эрика не сработало, заключается в том, что он установил код сканирования оборудования, но в итоге использовал код виртуального сканирования (установив dwFlags в 0 и wVk в ненулевое значение).

По сути, чтобы сделать нажатие клавиши, вы хотите установить:

ip.ki.dwFlags = KEYEVENTF_SCANCODE;

И чтобы сделать ключ разблокировки, установите:

ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;

Полный рабочий образец приведен ниже и печатает букву "а". Вы можете найти другие коды сканирования здесь.

#define WINVER 0x0500
#include <windows.h>

using namespace std;

int main()
{

    //Structure for the keyboard event
    INPUT ip;

    Sleep(5000);

    //Set up the INPUT structure
    ip.type = INPUT_KEYBOARD;
    ip.ki.time = 0;
    ip.ki.wVk = 0; //We're doing scan codes instead
    ip.ki.dwExtraInfo = 0;

    //This let's you do a hardware scan instead of a virtual keypress
    ip.ki.dwFlags = KEYEVENTF_SCANCODE;
    ip.ki.wScan = 0x1E;  //Set a unicode character to use (A)

    //Send the press
    SendInput(1, &ip, sizeof(INPUT));

    //Prepare a keyup event
    ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
    SendInput(1, &ip, sizeof(INPUT));



    return 0;
}

Примечание: Вы можете комбинировать нажатия клавиш (например, shift + a для A), передавая SendInput() массив структур INPUT.

Вам часто нужно установить код сканирования:

// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = MapVirtualKey(code, MAPVK_VK_TO_VSC); // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;

// Press the "..." key
ip.ki.wVk = code; // virtual-key code for the "a" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));

И создание массива, как предполагает IInspectable, также определенно поможет.

Если вы хотите создать игрового бота, вы смотрели программу AutoHotKey? http://www.autohotkey.com/

Он предлагает язык сценариев, который позволяет вам выполнять множество задач, связанных с созданием "ботов", и это гораздо проще, чем пытаться делать все это в C++.

(Это определенно сыграло роль в Фармвилле для меня, когда вся моя семья заставила меня создать аккаунт)

Другие вопросы по тегам