Я разрабатываю интерфейс для дополнения к игре. Я не могу использовать игровой API (по нескольким причинам, включая тот факт, что код должен быть независимым от игры), и мне нужно получать ввод с клавиатуры от пользователя, поэтому я решил использовать клавиатурный хук (WH_KEYBOARD) для обработки пользователя. ввода при выполнении определенных условий.
Проблема в том, что, хотя я могу правильно получать и обрабатывать ввод, когда мой хук возвращает TRUE вместо CallNextHookEx системе требуется много времени (намного более 800 мс), прежде чем все пойдет как положено, и это неприемлемо потому что он даже не позволяет плавно печатать.
Чего мне нужно добиться, так это предотвратить попадание сообщения о нажатии клавиши в WndProc, поэтому вопрос в том, что я могу сделать, чтобы достичь своей цели, не навредив игре. производительность настолько велика, что результат будет неприемлемым?
РЕДАКТИРОВАТЬ: из-за особых требований (игры, использующие античиты, которые могут создать проблемы с моим кодом, несмотря на то, что они не связаны с читерством), создание подкласса активного wndproc не является вариантом.
KeyboardProc, возвращающий TRUE, вызывает падение производительности
Ответы (4)
Сначала вам нужно, чтобы ваша DLL была внедрена в целевой процесс с помощью перехватчиков или любого по-другому.
Найдите дескриптор интересующего окна.
Получите текущую оконную процедуру этого окна, вызвав GetWindowLongPtr(wnd, GWLP_WNDPROC), и сохраните ее.
Создайте подкласс окна, вызвав SetWindowLongPtr( wnd, GWLP_WNDPROC, &NewWndProc ), где NewWndProc — ваша процедура обработки сообщений, реализованная в библиотеке DLL.
Внутри NewWndProc вы захотите обрабатывать сообщения клавиатуры (их дюжина, введите «ввод с клавиатуры» в индексе MSDN, я не могу опубликовать более 1 ссылки). Для остальных сообщений Windows вызывается исходная оконная процедура, которую вы сохранили во время (3), и возвращаете значение, которое она вернула. Не вызывайте его напрямую, вместо этого используйте CallWindowProc.
Этот способ не очень надежен, некоторым антивирусам и программам защиты от ботов (например, «клиент надзирателя») он может не понравиться, а отладка может быть сложной.
Однако это должно работать.
Крюк клавиатуры не должен замедлять работу. Вероятно, что-то еще происходит, что вызывает задержку в 800 мс. Это все еще медленно, если ваш хук ничего не делает и просто возвращает TRUE?
Если вы хотите, чтобы сообщение не поступало в WndProc, вам необходимо создать подкласс, используя SetWindowLong, таким образом вы сможете перехватывать все сообщения и решать, продолжать ли их маршрут.
Как бы мне не нравилось отвечать на мой собственный вопрос, я нашел причину задержки. Насос сообщений в играх, на которых я тестировал свой код, был реализован с помощью while(PeekMessage) { GetMessage... }, и удаление сообщения ввода с клавиатуры каким-то образом приводило к блокировке GetMessage на какое-то время. Использование PostMessage и WM_NULL помогло предотвратить блокировку GetMessage.