1

Тема: 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.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

2

Re: AHK: Определение символов, посылаемых с клавиатуры

Код исправлен для поддержки AHK_L x64.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg