2009-12-26 2 views
13

Il semble que si vous appelez ToAscii() ou ToUnicode() alors que dans un hook WH_KEYBOARD_LL global, et une touche morte est pressée, il sera 'détruit'. Par exemple, supposons que vous avez configuré votre langue d'entrée dans Windows comme étant l'espagnol et que vous voulez taper une lettre accentuée á dans un programme. Normalement, vous devez appuyer sur la touche de guillemets simples (la touche morte), puis sur la lettre "a", puis sur l'écran á sera affiché, comme prévu.ToAscii/ToUnicode dans un crochet de clavier détruit les touches mortes

Mais cela ne fonctionne pas si vous appelez ToAscii() ou ToUnicode() dans une fonction de crochet de bas niveau. Il semble que la clé morte est détruite, et donc aucune lettre accentuée á apparaît à l'écran. Supprimer un appel aux fonctions ci-dessus résout le problème ... mais malheureusement, je dois pouvoir appeler ces fonctions.

J'ai fait une recherche Google pendant un certain temps, et même si beaucoup de gens semblaient avoir ce problème, aucune bonne solution n'a été fournie.

Toute aide serait grandement appréciée!

EDIT: J'appelle ToAscii() pour convertir le code virtuel clé et code de balayage reçu dans ma LowLevelKeyboardProc fonction de crochet dans le caractère résultant qui sera affiché à l'écran pour l'utilisateur.

J'ai essayé MapVirtualKey(kbHookData->vkCode, 2), mais ce n'est pas aussi "complet" une fonction que ToAscii(); Par exemple, si vous appuyez sur Maj + 2, vous obtiendrez '2', pas '@' (ou tout ce que Shift + 2 produira pour la disposition/langue du clavier de l'utilisateur).

ToAscii() est parfait ... jusqu'à ce qu'une touche morte soit enfoncée.

EDIT2: est ici la fonction de crochet, avec des informations non pertinentes enlevé:

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); 
} 
+0

Veuillez indiquer le code d'appel de ToUnicode(). Où obtenez-vous le paramètre lpKeyState? – jdigital

+0

@jdigital: Eh bien, j'appelle personnellement ToAscii, mais j'ai lu que ça arrive aussi avec ToUnicode. Mon appel est essentiellement ToAscii (kbHookData-> vkCode, kbHookData-> scanCode, GetKeyboardState(), & lpchar, 0) dans la fonction de hook WH_KEYBOARD_LL. Lorsque l'appel ToAscii renvoie -1, cela signifie qu'une touche morte a été enfoncée ... et la clé morte est 'détruite' comme je l'ai expliqué ci-dessus. – 00010000

+0

J'ai supprimé ma réponse, il était complètement incorrect basé sur l'hypothèse que vous faisiez référence à des fonctions c-runtime pour convertir des chaînes plutôt que Win32 apis pour convertir des scancodes ... désolé. –

Répondre

3
  1. arrêt à l'aide ToAscii() et utiliser ToUncode()
  2. rappeler que ToUnicode peut vous retourner rien sur les touches mortes - C'est pourquoi ils sont appelés clés mortes.
  3. Toute clé aura un code scancode ou un code de touche virtuelle mais pas nécessairement un caractère.

Vous ne devez pas combiner les boutons avec des caractères - en supposant que toute touche/bouton a une représentation de texte (Unicode) est incorrecte.

Alors:

  • pour texte d'entrée utiliser les caractères signalés par Windows
  • pour le contrôle de bouton enfoncé (jeux ex.) Utiliser scancodes ou touches virtuelles (probablement les clés virtuelles sont meilleures).
  • pour raccourcis clavier utiliser clé virtuelle codes.
+0

J'ai essayé d'utiliser ToUnicode(), mais la même chose arrive ... la "dead-key" est détruite, et donc un double accent est affiché quand j'appuie sur la touche accent, et je ne peux pas faire de lettres accentuées. La désinstallation du crochet résout immédiatement le problème. Ne pas appeler ToAscii() ou ToUnicode() corrige immédiatement le problème. – 00010000

+0

Essayez de faire une copie de la structure de l'état du clavier afin d'empêcher Windows de modifier l'original. – sorin

2

Appel 'ToAscii' fonction deux fois pour un traitement correct de clé morte, comme dans:

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) 
... 
+3

Cela "tue" simplement la clé morte pour moi. Par exemple. 'ë' devient 'e', ​​mais appuyer deux fois sur une touche morte donne encore par ex.¨¨ –

2

L'appel de la ToAscii ou ToUnicode est la réponse à deux reprises. Je l'ai trouvé et l'ai converti pour Delphi, et ça marche!

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

C'est un peu mieux car mon caractère '^' est affiché seulement après la deuxième touche, comme prévu, mais ne fonctionne pas parce que l'accent ne va pas sur la lettre car il devrait produire 'ô', mais seulement produit 'o' – Flox

+0

En fait, votre réponse est la même que les yeux @Blue ci-dessous: https: //stackoverflow.com/a/3625039/2165463 – Flox

0

je copie le vkCode dans une file d'attente et faire la conversion d'un autre thread

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

Ceci a l'avantage de ne pas retarder le traitement clé par l'os

1

Tout à fait un vieux fil. Malheureusement, il ne contenait pas la réponse que je cherchais et aucune des réponses ne semblait fonctionner correctement. J'ai finalement résolu le problème en vérifiant le MSB de la fonction MapVirtualKey, avant d'appeler ToUnicode/ToAscii. Semble travailler comme un charme:

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

MSDN sur la citant valeur de retour de MapVirtualKey, si MAPVK_VK_TO_CHAR est utilisé:

[...] Les touches mortes (diacritiques) sont indiqués en réglant la premier bit de la valeur de retour. [...]

+0

pourriez-vous s'il vous plaît élaborer plus? Je ne reçois pas votre code, et si vous ne saisissez pas le if()? Ne rien faire? –

+1

Dans le cas où il n'y a pas d'entrée, la touche actuelle enfoncée est une touche morte. En fonction de ce que vous souhaitez réaliser, vous pouvez réagir, ou simplement l'ignorer, au cas où vous souhaiteriez uniquement écouter des touches non-mortes. J'espère que cela t'aides. –

+0

Merci, je l'ai eu –

Questions connexes