В который раз наблюдаю поднятие подобной темы, и на этот раз все же укротил лень.
Для начала рекомендую изучить следующее:
http://autoit-script.ru/index.php?topic=20850.msg123312#msg123312
https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms644967(v=vs.85).aspx
Флаги, которые "палят" эмуляцию -
LLKHF_LOWER_IL_INJECTED,
LLKHF_INJECTED. В спецификации
LowLevelKeyboardProc ничего не сказано о том, что поля структуры не подлежат изменению (non const), следовательно наши изменения будут переданы вниз по цепочки callback'ов (хотя это вовсе не следует, так, спойлер сделал
).
Для демонстрации набросал следующий пример:
#include <StructureConstants.au3>
#include <WinAPI.au3>
OnAutoItExitRegister("Cleanup")
HotKeySet("{F6}", "_Exit")
Global Const $LLKHF_LOWER_IL_INJECTED = 0x00000002
; --
Global Const $g_INJECTED_MASK = BitOr($LLKHF_LOWER_IL_INJECTED, $LLKHF_INJECTED)
Global $g_hHook, $g_hStub_KeyProc
; ---
$g_hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
$g_hHook = _WinAPI_SetWindowsHookEx( _
$WH_KEYBOARD_LL, _
DllCallbackGetPtr($g_hStub_KeyProc), _
_WinAPI_GetModuleHandle(0) _
)
If Not $g_hHook Then _
Exit
Sleep(5000)
While Sleep(100)
If Random(1, 10, 1) = 5 Then
ConsoleWrite("Sending key..." & @CRLF)
Send("T")
EndIf
WEnd
Func _KeyProc($nCode, $wParam, $lParam)
Local $tKEYHOOKS
; ---
$tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
If Not ($nCode < 0) Then
If BitAnd($tKEYHOOKS.flags, $g_INJECTED_MASK) Then
If $wParam = 0x0100 Then _ ; prevent some spam (WM_KEYDOWN)
ConsoleWrite( "Detected injected flag at key: " & Hex($tKEYHOOKS.vkCode, 2) & @CRLF)
; Remove injected flags
$tKEYHOOKS.flags = BitAnd(BitNot($g_INJECTED_MASK), $tKEYHOOKS.flags)
EndIf
EndIf
Return _WinAPI_CallNextHookEx($g_hHook, $nCode, $wParam, $lParam)
EndFunc
Func Cleanup()
_WinAPI_UnhookWindowsHookEx($g_hHook)
DllCallbackFree($g_hStub_KeyProc)
EndFunc ;==>Cleanup
Func _Exit()
Exit
EndFunc
Поясню немного:
Пример обрабатывает все события клавиатуры и при обнаружении эмуляции (один из флагов
injected установлен) - подтирает соответствующий флаг. Для демонстрации цикл
while содержит в себе эмуляцию нажатия клавиши "T".
Имеются также и недостатки, а именно:
1. Пример убирает абсолютно на любом событии флаги эмуляции (если таковые возведены), что не является "адекватным" поведением. Наиболее корректно будет фильтровать и обрабатывать только собственные события, для этого можно воспользоваться полями структуры
$tagKBDLLHOOKSTRUCT -
time и/или
dwExtraInfo (последний придется возводить самому). Ну или банально возводить некую глобальную переменную в скрипте (ожидаем клавишу и т.д.).
2. Хук должен быть всегда последним зарегистрированным (первым в цепочке), а значит быть зарегистрирован после игрового. Как наиболее корректно решить этот вопрос я писал вот тут (ответ на вторую цитату):
http://autoit-script.ru/index.php?topic=20810.msg123235#msg123235