tagger tag windows unicode diacritics keyboard-hook

windows - tagger - tag folders



ToAscii/ToUnicode en un gancho de teclado destruye las llaves muertas (5)

Parece que si llama a ToAscii() o ToUnicode() mientras está en un gancho global WH_KEYBOARD_LL, y se pulsa una tecla muerta, se ''destruirá''.

Por ejemplo, suponga que ha configurado su idioma de entrada en Windows como español y desea escribir una letra acentuada á en un programa. Normalmente, presionaría la tecla de comilla simple (la tecla de la muerte), luego la letra "a", y luego en la pantalla se mostraría un acentuado, como se esperaba.

Pero esto no funciona si llama a ToAscii() o ToUnicode() en una función de ToUnicode() teclado de bajo nivel. Parece que la clave muerta está destruida, por lo que no aparece ninguna letra acentuada en la pantalla. Eliminar una llamada a las funciones anteriores resuelve el problema ... pero desafortunadamente, necesito poder llamar esas funciones.

Busqué en Google por un tiempo, y aunque muchas personas parecían tener este problema, no se proporcionó una buena solución.

¡Cualquier ayuda sería muy apreciada!

EDITAR: Estoy llamando a ToAscii() para convertir el código de clave virtual y el código de exploración recibidos en mi función de enlace LowLevelKeyboardProc en el carácter resultante que se mostrará en pantalla para el usuario.

MapVirtualKey(kbHookData->vkCode, 2) , pero esta no es una función "completa" como ToAscii() ; por ejemplo, si presiona Mayús + 2, obtendrá ''2'', no ''@'' (o lo que sea que Shift + 2 produzca para el diseño / idioma del teclado del usuario).

ToAscii() es perfecto ... hasta que se presione una tecla muerta.

EDIT2: Aquí está la función de enlace , con información irrelevante eliminada:

LRESULT CALLBACK keyboard_LL_hook_func(int code, WPARAM wParam, LPARAM lParam) { LPKBDLLHOOKSTRUCT kbHookData = (LPKBDLLHOOKSTRUCT)lParam; BYTE keyboard_state[256]; if (code < 0) { return CallNextHookEx(keyHook, code, wParam, lParam); } WORD wCharacter = 0; GetKeyboardState(&keyboard_state); int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode, keyboard_state, &wCharacter, 0); /* If ta == -1, a dead-key was pressed. The dead-key will be "destroyed" * and you''ll no longer be able to create any accented characters. Remove * the call to ToAscii() above, and you can then create accented characters. */ return CallNextHookEx(keyHook, code, wParam, lParam); }


  1. deja de usar ToAscii () y usa ToUncode ()
  2. recuerde que ToUnicode no puede devolverle nada en las llaves muertas; es por eso que se les llama llaves muertas.
  3. Cualquier tecla tendrá un código de exploración o un código de tecla virtual pero no será necesario un carácter.

No debe combinar los botones con caracteres, suponiendo que cualquier tecla / botón tenga una representación de texto (Unicode) incorrecta.

Asi que:

  • para el texto de entrada use los caracteres informados por Windows
  • para presionar el botón presionado (por ejemplo, juegos) use códigos de escaneo o claves virtuales (probablemente las teclas virtuales son mejores).
  • para atajos de teclado, use códigos de teclas virtuales .

Llame a la función ''ToAscii'' dos veces para un procesamiento correcto de la tecla muerta, como en:

int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode, keyboard_state, &wCharacter, 0); int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode, keyboard_state, &wCharacter, 0); If (ta == -1) ...


Llamar a ToAscii o ToUnicode dos veces es la respuesta. ¡Encontré esto y lo convertí para Delphi, y funciona!

cnt:=ToUnicode(VirtualKey, KeyStroke, KeyState, chars, 2, 0); cnt:=ToUnicode(VirtualKey, KeyStroke, KeyState, chars, 2, 0); //yes call it twice


Copio el vkCode en una cola y hago la conversión de otro hilo

@HOOKPROC def keyHookKFunc(code,wParam,lParam): global gkeyQueue gkeyQueue.append((code,wParam,kbd.vkCode)) return windll.user32.CallNextHookEx(0,code,wParam,lParam)

Esto tiene la ventaja de no retrasar el procesamiento de claves por el sistema operativo


Todo un hilo viejo Lamentablemente, no contenía la respuesta que estaba buscando y ninguna de las respuestas parecía funcionar correctamente. Finalmente resolví el problema comprobando el MSB de la función MapVirtualKey , antes de llamar a ToUnicode / ToAscii . Parece estar funcionando como un encanto:

if(!(MapVirtualKey(kbHookData->vkCode, MAPVK_VK_TO_CHAR)>>(sizeof(UINT)*8-1) & 1)) { ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode, keyboard_state, &wCharacter, 0); }

Citando MSDN en el valor de retorno de MapVirtualKey , si se usa MAPVK_VK_TO_CHAR :

[...] Las teclas muertas (signos diacríticos) se indican configurando el bit superior del valor de retorno. [...]