Тема: AHK: Определение символов, посылаемых с клавиатуры
Требует AHK_L.
Скрипт определяет символы, посылаемые с клавиатуры окнам других приложений и показывает их в своём окне.
SetBatchLines, -1
Gui, Add, Edit, x0 y0 w200 h100 ReadOnly hwndhEdit
Gui, Show, w200 h100 NA
OnExit, Exit
hHookKeybd := DllCall("SetWindowsHookEx" . (A_IsUnicode ? "W" : "A")
, Int, WH_KEYBOARD_LL := 13
, Ptr, RegisterCallback("LowLevelKeyboardProc", "Fast")
, Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
, UInt, 0, Ptr)
OnExit, Exit
Return
GuiClose:
ExitApp
Exit:
DllCall("UnhookWindowsHookEx", Ptr, hHookKeybd)
ExitApp
LowLevelKeyboardProc(nCode, wParam, lParam)
{
global
Critical
if (wParam = 0x100) ; WM_KEYDOWN = 0x100
{
vk := NumGet(lParam+0, "UInt")
sc := NumGet(lParam+0, 4, "UInt")
SetTimer, ShowChar, -10
}
Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)
ShowChar:
Char := GetCharOfKey(vk, sc)
Control, EditPaste, % Char,, ahk_id %hEdit%
Return
}
GetCharOfKey(vk, sc)
{
ThreadID := DllCall("GetWindowThreadProcessId", UInt, WinExist("A"), UInt, 0)
InputLocaleID := DllCall("GetKeyboardLayout", UInt, ThreadID)
VarSetCapacity(KeyState, 256)
DllCall("AttachThreadInput", UInt, ThreadID
, UInt, DllCall("GetCurrentThreadId")
, UInt, 1)
DllCall("GetKeyboardState", UInt, &KeyState)
VarSetCapacity(Buffer, 2)
A_IsUnicode ? DllCall("ToUnicodeEx"
, UInt, vk, UInt, sc
, UInt, &KeyState, Str, Buffer
, Int, 1, UInt, 0, UInt, InputLocaleID) : DllCall("ToAsciiEx"
, UInt, vk, UInt, sc
, UInt, &KeyState, Str, Buffer
, UInt, 0, UInt, InputLocaleID)
Return Buffer
}
Для перехвата клавиатурных событий скрипт устанавливает хук, callback-функция которого (LowLevelKeyboardProc) определяет виртуальный и скан-код нажатой клавиши. После этого мы выходим из обработчика событий, чтобы не создавать задержки, и остальные действия будем выполнять асинхронно в подпрограмме таймера.
Теперь для определения символа, посланного нажатой клавишей, нужно узнать текущую раскладку клавиатуры в активном окне (ф-ция GetKeyboardLayout) и статусы клавиш Shift и Caps Lock. Ф-ция GetKeyboardState делает снимок состояний всех виртуальных клавиш и помещает его в буфер. Чтобы иметь возможность сделать такой снимок для другого потока, нужно предварительно вызвать AttachThreadInput.
Сейчас у нас есть все данные, нужные для определения символа. В Unicode-версии AHK это делается с помщью ф-ции ToUnicodeEx, в ANSI-версии — посредством ToAsciiEx. Скрипт сам определит нужный вариант по значению переменной A_IsUnicode.