Имитация длительного нажатия клавиш - PullRequest
0 голосов
/ 08 февраля 2020

В моей программе я хочу имитировать нажатия клавиш. Например, я хочу сказать Press (KeyA, 1000), где первый параметр - это KeyCode, а второй - время в миллисекундах. KeyA и т. Д. Являются typedefs, и методы отлично работают для однократного нажатия кнопки.

void PressKey(INPUT &ip, int keycode, int ms)
{
    // Press the  key
    ip.ki.wVk = keycode; // virtual-key code for the key
    ip.ki.dwFlags = 0; // 0 for key press
    SendInput(1, &ip, sizeof(INPUT));

    sleep(ms);

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

int main()
{


    // input event
    INPUT ip;
    INPUT ipMouse;

    ip.type = INPUT_KEYBOARD;
    ip.ki.wScan = 0; // hardware scan code for key
    ip.ki.time = 0;
    ip.ki.dwExtraInfo = 0;



    PressKey(ip, KeyM, 1000);


Я думал, что нажатие клавиши и ожидание ее отпускания будет считаться нажатием удерживаемой кнопки, но это не так. , Также я не хочу просто тысячу раз нажать PressKey (ip, KeyM), чтобы получить такой же ввод, как нажатие кнопки в течение 5 секунд. Кто-нибудь сейчас, как заставить программу имитировать более длинные входы?

Ответы [ 2 ]

0 голосов
/ 10 февраля 2020

Однако такого API для имитации удерживаемого нажатия не существует.

При тестировании оконного приложения оно будет получать непрерывное сообщение WM_KEYDOWN при нажатии и удерживании клавиши на клавиатуре.

Если ваше приложение является оконным приложением, а не консольным приложением, вы можете обнаружить первый WM_KEYDOWN в низкоуровневой клавиатуре и запустить таймер на 5 секунд, когда время таймера истекло, отправить сообщение WM_KEYUP, чтобы имитировать удерживаемое нажатие. Вы можете позвонить SendInput только один раз и отправить одно нажатие клавиши.

Для консольного приложения оно не может быть перехвачено, повторный вызов SendInput в течение указанного времени - решение для вас. Есть беспокойство по этому поводу?

0 голосов
/ 09 февраля 2020

Я отвечу на более общий вопрос: «Как воспроизвести прогон моей игры с указанными c входами?»

Трюк для воспроизведения входов, для профилирования, для проверки детерминизма или для общего QA должен отделить два элемента от обработки игры:

  • Любой доступ к таймеру
  • Любое чтение входных данных от игрока

Если ваша игра хорошо написано (без неопределенного поведения), с заданным набором входных данных и связанных таймингов, оно всегда должно вести себя одинаково. Одни и те же входные данные одновременно приводят к одинаковым выходным данным.

Итак, оберните TimeGetTime (), std :: clock, rdts c или все, что вы используете для чтения времени, в свою собственную функцию getTime (). Аналогично, оберните входное чтение win32 и / или считывание скан-кода в свой собственный getInputs ().

Запустите игру, но сохраните все входные данные и временные метки в дополнение к их использованию. Log.txt или что-то еще. В идеале ваша игра должна запрашивать время только один раз за кадр, но, эй, я видел игры, которые запрашивают текущее время тысячи раз за каждый кадр.

Теперь измените свою игру так, чтобы вместо получения реальные входные данные или реальные настенные часы, он получает значения из файла журнала. Если ваша игра детерминирована c, теперь вы сможете воспроизводить ту же последовательность событий.

Вы можете затем профилировать его. Обратите внимание, что, поскольку время считывается из файла, если при воспроизведении игра замедляется, это не проблема. Ваши персонажи будут прыгать одинаковой длины, падать в одном месте и т. Д. c ... Это будет выглядеть медленнее. Это позволяет вам использовать самые интенсивные настройки профилирования, даже если игра воспроизводится в 10 раз медленнее, она все равно работает точно так же, и вы получаете достоверное измерение того, где было потрачено время.

Это также готовит вас к настройте, где QA может сохранять повторы, и вы можете отлаживать.

Это больше работы для регистрации всего этого, и требуется некоторая осторожность, чтобы не иметь никакого недетерминизма.

Но, на оборотной стороне сторона, если вы go с вашим первоначальным предложением, ввод ввода не произойдет точно в то же время. Вы теряете некоторые QA репро способности. От бега к бегу поведение будет немного расходиться.

Служебные данные профилировщика также влияют на время, делая измерения недействительными время от времени.

Итак, мое предложение:

  • приблизиться к определению c game (скорее всего, всегда будут небольшие различия)
  • обернуть все входы (включая время) за функцией регистрации
  • сохранить их все для записи
  • заменить их на logged история для воспроизведения

Чтобы конкретно решить вопрос: вместо подачи входных данных через систему win32, игра вызывает ваш собственный метод getInput () и, при воспроизведении, получает сохраненные входные данные, таким образом обходя вся система win32.

...