У меня есть хук низкого уровня, но я обнаружил, что toUnicodeEx не может правильно обрабатывать состояния Shift- и Alt-gr. Я нашел исправление для Shift, но не для Alt-gr.
У меня есть задача по автоматизации, и поэтому я столкнулся с этой проблемой, используя язык программирования AutoIt (базовый тип), но он кажется универсальным, я обнаружил множество аналогичных описаний проблем от людей, использующих другие языки. К сожалению, ни одно из представленных решений не сработало.
Я понял, что в низкоуровневом хуке, который отслеживает конкретное приложение (некоторые люди называют это кейлоггером), перевод кода сканирования в реальный код символа с помощью ToUnicodeEx является проблемой, поскольку информация о состоянии клавиатуры и раскладке клавиатуры из процесса мониторинга вместо отслеживаемого процесса.
Обычно все приложения используют одну и ту же раскладку клавиатуры по умолчанию, поэтому я могу использовать GetKeyboardLayout (GetDesktopWindow ()) и получать результаты, которые для меня достаточно хороши. К сожалению, это обеспечивает только правильное отображение строчных букв a-z.
Чтобы получить смещенные буквы, я понял, что мне нужен результат функции getKeyboardState, но это работает только для нажатий клавиш, отправляемых процессу, владеющему обработчиком низкоуровневых перехватов клавиатуры. Но поскольку структура представляет собой простой массив, содержащий байт состояния для каждого виртуального ключа, я попытался заменить его собственным и установить байты состояния в соответствии с моими потребностями.
Это хорошо работает для клавиш [Shift], но не для [Alt-gr].
?? Как мне заставить Alt-gr перевод работать в ToUnicodeEx ??
Func LowLevelKeyboardProc($nCode, $wParam, $lParam)
If $nCode < 0 Then
Return _WinAPI_CallNextHookEx($hK_Hook, $nCode, $wParam, $lParam)
EndIf
Local $tKEYStruct = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
local $vkCode = DllStructGetData($tKEYStruct, "vkCode")
local $scanCode = DllStructGetData($tKEYStruct, "scanCode")
If $wParam = $WM_KEYUP Then ;Key Up
; create a zeroed 256 byte array
Local $tKeyboardState = DllStructCreate("byte[256]")
; set the keystate flag(s)
if $LShiftState = true Then
DLLStructSetData($tKeyboardState, 1, 0x81, $VK_CAPITAL + 1) ; Shift
EndIf
If $AltGrState Then
DLLStructSetData($tKeyboardState, 1, 0x80, $VK_MENU + 1) ; Alt-Gr
DLLStructSetData($tKeyboardState, 1, 0x80, $VK_CONTROL + 1)
EndIf
Local $keyBuffer = ""
Local $result = _User32_ToUnicodeEx($vkCode, $scanCode, DllStructGetPtr($tKeyboardState) , $keyBuffer, 5,0, _WinAPI_GetKeyboardLayout(_WinAPI_GetDesktopWindow ( )))
ConsoleWrite("Key Up " & $result & " Scancode: 0x" & Hex($scanCode) & " VirtualkeyCode: 0x" & Hex($vkCode) & " [" & $keyBuffer & "]" & @CRLF)
if $result > 0 then
endif
Switch $vkCode
case $VK_LSHIFT
$LShiftState = false
case $VK_RMENU
$AltGrState = false
EndSwitch
Else ; Key Down
; ConsoleWrite("Key Dwn " & " Scancode: 0x" & Hex($scanCode) & " VirtualkeyCode: 0x" & Hex($vkCode) & @CRLF)
Switch $vkCode
case $VK_LSHIFT
$LShiftState = true
case $VK_RMENU
$AltGrState = true
EndSwitch
EndIf
$tKeyboardState = 0 ; free memory
Return _WinAPI_CallNextHookEx($hK_Hook, $nCode, $wParam, $lParam)
EndFunc
Этот подход почти работает. Мне удобно использовать раскладку клавиатуры по умолчанию, приложения обычно не используют разную раскладку клавиатуры. Состояния [Shift] корректно обрабатываются, например, ToUnicodeEx возвращает "!" если я впихну в скан- и вк-код клавиши «1». Кроме того, все специальные клавиши символов, например, Немецкие умлауты (äöüÄÖÜß) работают.
К сожалению, если я установлю комбинации клавиш Alt и Ctrl (также безуспешно пробовал VK_RMENU), я не получу такие символы Alt-gr, как (немецкая клавиатура) @, €, {, [,],}, \ and и так далее.
Обратите внимание, что подпрограмма работает, если вызывается напрямую (без использования подключаемой процедуры), поэтому я чувствую, что почти на месте.
Пожалуйста, не чувствуйте себя отчужденным, потому что я предоставляю код AutoIt, он похож на другие языки, я думаю, что проблема связана с API, а не языком. Autoit предоставляет некоторые средства для взаимодействия с Windows API, а именно три важные функции:
DllStructCreate - создать байтовую структуру, которую можно передавать в API-интерфейсы Windows ...
DllStructGetPtr - получить указатель на структуру, которую можно передать в API Windows
DLLStructGetData, DLLStructSetData - доступ к структуре для чтения или изменения байтов (примечание: нумерация байтов основана на 1)
AutoIt также предоставляет обширную библиотеку функций, которые обертывают функции Windows API, схема именования всегда WinAPI + имя функции Windows, поэтому, например, _WinAPI_CallNextHookEx () вызывает CallNextHookEx () и _User32_ToUnicodeEx соответствует ToUnicodeEx ().