Vois mon code :
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if ((nCode == HC_ACTION) && (wParam == WM_KEYDOWN))
{
char nomTouche[256] = "";
int i = 0;
// On récupère la touche
GetKeyNameText(lParam, nomTouche, 256);
printf("Traduction : ");
for(i = 0; i < 256; i++) printf("%c", nomTouche[i]);
printf("\n");
}
// Renvoi des messages au sytème pour permettre d'autres hooks
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
Si quelqu'un pouvait m'expliquer pourquoi j'ai ce problème, je vous en
serais reconnaissant.
> Comme ToAscii ne gère pas les dead keys, je me suis rabattu sur
> GetKeyNameText et le soucis c'est que cette fonction me retourne
> toujours la lettre 'G' (en vraie elle retourne 1, càd la longueur de
> 'G' et inscrit 'G' dans le buffer).
Il faut faire, par exemple, pour un Hook WH_KEYBOARD_LL =>
(il faut normalement aussi tester les touches comme VK_RMENU avec
GetKeyState()...)
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam;
DWORD dwMsg = 1;
dwMsg += (pkbhs->scanCode << 16);
dwMsg += (pkbhs->flags << 24);
char sKeyName[MAX_PATH] = "";
GetKeyNameText (dwMsg, sKeyName, MAX_PATH);
char sBuffer[MAX_PATH];
CharToOem(sKeyName, sBuffer);
printf("%s\n", sBuffer);
Merci pour ta réponse, elle fonctionne selon mes attentes. Mais si je
veux enregistrer la frappe dans un fichier texte à l'aide de CreateFile
(); je ne suis pas obligé d'utiliser CharToOem(); vu que ce n'est pas
pour l'afficher dans la console. N'est-ce pas ?
> Merci pour ta réponse, elle fonctionne selon mes attentes. Mais si je
> veux enregistrer la frappe dans un fichier texte à l'aide de CreateFile
> (); je ne suis pas obligé d'utiliser CharToOem(); vu que ce n'est pas
> pour l'afficher dans la console. N'est-ce pas ?
Tout-à-fait, c'est juste pour l'affichage.
WriteFile() suffit.
Merci pour ton aide. Maintenant je me heurte à un second problème.
Alors voilà comment fonctionne mon hook :
Intercepte message clavier:
Si touche = dead key
On rend la main en mettant BOOL deadkey = TRUE; pour le
prochain appel
On traite le message
Si deadkey != TRUE
ToAscii(message); //schématique ici vu que ToAscii attend
en vrai 5 paramètres
Sinon
GetKeyNameText(message);
On rend la main
Mon problème maintenant ce serait de traiter CAPS LOCK. Car avec ce
schéma là, si CAPS LOCK est appuyé, on affiche [CAPS LOCK] à l'écran.
Mais si on appuie sur ')' alors que CAPS LOCK est appuyé, mon
programme affiche ')' et non '°'.
En clair, je voudrais transformer mon schéma en ceci :
Intercepte message clavier:
Si touche = dead key
On rend la main en mettant BOOL deadkey = TRUE; pour le
prochain appel
Si CAPS LOCK est appuyé
BOOL maj = TRUE;
On traite le message
Si deadkey != TRUE && maj != TRUE
ToAscii(message); //schématique ici vu que ToAscii attend
en vrai 5 paramètres
Sinon
GetKeyNameText(message);
On rend la main
Pourrais-tu me dire comment faire pour savoir que CAPS LOCK est
appuyé ? Car avec la msdnn, je m'y perds un peu... J'ai cru comprendre
que cette information était contenue dans lParam (je me trompe peut
être) et même plus précisément dans KBDLLHOOKSTRUCT (idem) mais je ne
suis pas sûr de savoir comment l'extraire.
Une petite aide ? Merci.
Alors pour ce soucis de CAPS LOCK, j'ai procédé comme ceci :
KBDLLHOOKSTRUCT *hookstruct = ((KBDLLHOOKSTRUCT*)lParam);
static BOOL maj;
if(hookstruct->vkCode == VK_CAPITAL)
{
if(maj)
{
myfprintf("[CAPS LOCK OFF]");
maj = FALSE;
}
else if(!hookstruct->flags)
{
myfprintf("[CAPS LOCK ON]");
maj = TRUE;
}
}
Et ensuite, en même temps que je teste si c'est une deadkey, je teste
aussi la valeur de maj. Si maj == TRUE alors on utilise
GetKeyNameText, sinon on utilise ToAscii.
Cette solution fonctionne, à l'affichage j'ai : "[CAPS LOCK ON]TEST
[CAPS LOCK OFF]test".
Mais le soucis que j'ai, c'est que si CAPS LOCK était déjà appuyé
avant la mise en route du Hook, lorsque j'affiche les messages
interceptés à l'écran, je me retrouve avec : "[CAPS LOCK ON]TEST[CAPS
LOCK OFF]TEST" où le [CAPS LOCK ON] est le moment où je désactive CAPS
LOCK et [CAPS LOCK OFF] le moment où je l'active...
Un complément de solution ? Ou carrément une autre solution ?
Merci
> Pourrais-tu me dire comment faire pour savoir que CAPS LOCK est
> appuyé ?
Comme je l'avais évoqué pour AltGr (VK_RMENU), avec GetKeyState() =>
BOOL bCapsOn = GetKeyState(VK_CAPITAL) & 0x0001;
J'ai essayer d'adapter ton exemple (qui fonctionne parfaitement pour
VK_CAPITAL) pour VK_MENU et VK_RMENU en faisant comme ceci :
DWORD bAltGrOn;
DWORD bAltOn;
bAltGrOn = (DWORD)(GetKeyState(VK_RMENU)) & 0x1000;
if(bAltGrOn == 0x1000) printf'("AltGr : On\n");
bAltOn = (DWORD)(GetKeyState(VK_MENU)) & 0x1000;
if(bAltOn == 0x1000) printf("Alt on\n");
Cela fonctionne lorsque j'appuie sur Alt (left), car en sortie j'ai :
'Alt on'
Mais lorsque j'appuie sur Alt (right), en sortie j'ai :
'Alt On
AltGr On
Alt On
AltGr On'
Alors pourquoi est-ce que j'ai les deux touches d'affichées alors que
je n'appuie que sur AltGr ? Et pourquoi me l'affiche-t-il deux fois ?
Comme si il l'affichait lorsque AltGr était enfoncé, puis relâché.
> Alors pourquoi est-ce que j'ai les deux touches d'affichées alors que
> je n'appuie que sur AltGr ? Et pourquoi me l'affiche-t-il deux fois ?
> Comme si il l'affichait lorsque AltGr était enfoncé, puis relâché.
Le code n'est pas bon.
Pour AltGr, qui n'est pas "lockable" comme Caps Lock, c'est :
BOOL bAltGrDown = GetKeyState(VK_RMENU) & 0x8000;
J'avais compris la différence entre Caps Lock et AltGr. Juste mon
erreur était le '& 0x1000' alors qu'on était avec de l'hexadécimale.
Donc j'ai corrigé comme tu me le proposes, et j'ai toujours ce
problème :
BOOL bAltOn; //'ALT ON'
BOOL bAltGrOn; //'ALT GR'
bAltGrOn = GetKeyState(VK_RMENU) & 0x8000;
if(bAltGrOn) printf("AltGr on\n");
bAltOn = GetKeyState(VK_MENU) & 0x8000;
if(bAltOn) printf("Alt on\n");
Qui me donne en sortie :
'Alt on
AltGr on
Alt on
AltGr on' lorsque j'appuie sur AltGr.
J'ai pensé que cela pouvait venir de la répétition des touches. Alors
j'ai ajouté :
if (((DWORD)lParam & 0x40000000) != FALSE) //Bit 30 permet de savoir
si c'est une répétition
return CallNextHookEx (hHook, nCode, wParam, lParam);
Le problème c'est que ce code ne règle pas l'autre soucis (qui doit
surement venir d'autre part) mais en plus, lorsque je maintient la
touche 'a' enfoncé, la console m'affiche 'aaaaaaaaaaaaaaaaaaaaaaaaa'
au lieu de 'a' (par exemple).
Saurais-tu m'aider à résoudre ces deux problèmes ?
Dans un de mes vieux Keyloggers, je teste :
if(nCode == HC_ACTION && ( wParam == WM_KEYDOWN || wParam ==
WM_SYSKEYDOWN ) & !IsModifierKey(pkbhs->vkCode))
{
BOOL bAltGrDown = GetKeyState(VK_RMENU) & 0x8000;
BOOL bAltDown = GetKeyState(VK_LMENU) & 0x8000;
// ... etc...
}
avec :
BOOL
IsModifierKey(DWORD vkCode)
{
return
VK_CONTROL == vkCode || VK_RCONTROL == vkCode || VK_LCONTROL ==
vkCode ||
VK_SHIFT == vkCode || VK_RSHIFT == vkCode || VK_LSHIFT == vkCode
||
VK_MENU == vkCode || VK_LMENU == vkCode || VK_RMENU == vkCode;
}
Excuse moi mais je n'ai pas saisi l'intérêt de ta fonction. De ce que
j'ai compris, elle retourne TRUE si vkCode est l'une de ces touches.
Et ensuite dans ta fonction CALLBACK, tu n'entre pas dans ta condition
si cette fonction IsModifierKey vaut TRUE alors qu'après tu traites le
cas de VK_RMENU et VK_LMENU par exemple.
Si j'ai bien saisi la logique de ta fonction, le traitement de
VK_RMENU et VK_LMENU ne seras jamais fait car si on entre dans la
condition, c'est que vkCode n'est pas l'une de ces touches (entre
autres).
Pourrais-tu m'éclaircir sur ce point ? Et aussi me dire pourquoi la
répétition des touches est quand même prise en compte alors que
j'ai :
// Pour éviter les répétitions
// Bit 30 : Spécifie si la touche est maintenue (si TRUE, on passe
notre chemin)
if (((DWORD)lParam & 0x40000000) != FALSE)
return CallNextHookEx (hHook, nCode, wParam, lParam);
Merci
> Si j'ai bien saisi la logique de ta fonction, le traitement de
> VK_RMENU et VK_LMENU ne seras jamais fait car si on entre dans la
> condition, c'est que vkCode n'est pas l'une de ces touches (entre
> autres).
> Pourrais-tu m'éclaircir sur ce point ?
Si, le traitement sera fait : c'est pour éviter d'enregistrer le
premier appui sur Shift par exemple
(on ne logge que si on a Shif+Touche, pas Shift seul)
>Et aussi me dire pourquoi la
> répétition des touches est quand même prise en compte alors que
> j'ai :
> // Pour éviter les répétitions
> // Bit 30 : Spécifie si la touche est maintenue (si TRUE, on passe
> notre chemin)
> if (((DWORD)lParam & 0x40000000) != FALSE)
> return CallNextHookEx (hHook, nCode, wParam, lParam);
Le "repeat count", soit HIWORD(lParam) & KF_REPEAT n'est normalement
pas pris en compte par un LowLevel hook, mais bien pris par un hook
clavier classique (avec une DLL)
(je viens de retester les 2 hooks sur XP SP2...)
Pardon pour le temps de réponse, mais j'étais ailleurs ces derniers
temps.
Sinon j'ai tenté quelques manipulations pour m'en sortir avec ce Alt,
et je crois que j'ai réussi à m'en sortir en faisant comme ceci :
http://pastebin.com/m1bbe819
(Je préfère la coloration syntaxique de ce site plutôt que rien du
tout)
Je voudrais surtout que l'on me confirme les lignes 28, 79 et 168,
pour savoir ci ce que j'ai fait fonctionnera bel et bien chez tout le
monde (je pense aux Windoziens NT) ou si ces lignes de codes auront un
résultat différent en fonction des ordinateurs, claviers, etc.
Aussi je voudrais une dernière aide (normalement). Lorsque Caps lock
est sur 'On', et que j'appuie sur '_', cela m'affiche bien '8'. Mais
lorsque je combine 'Shift' + '_', cela m'affiche '_' et non '8'.
Comme régler ce problème ?
Merci.
> Aussi je voudrais une dernière aide (normalement). Lorsque Caps lock
> est sur 'On', et que j'appuie sur '_', cela m'affiche bien '8'. Mais
> lorsque je combine 'Shift' + '_', cela m'affiche '_' et non '8'.
> Comme régler ce problème ?
C'est le comportement normal.. (avec notepad)
Tous les 'case' sont inutiles aussi
Pour Alt, tu te compliques la vie , au lieu de sauter les 'modifier
keys', mais si ça marche sous XP, ça marchera en principe sous NT
(meme noyau)...
Pourrais-tu m'expliquer comment faire plus simplement ? Comment puis-
je éviter les 'case' et aussi comment faire simple avec 'Alt' ?
> > Pour Alt, tu te compliques la vie , au lieu de sauter les 'modifier
> > keys', mais si ça marche sous XP, ça marchera en principe sous NT
> > (meme noyau)...
>
> Pourrais-tu m'expliquer comment faire plus simplement ? Comment puis-
> je éviter les 'case' et aussi comment faire simple avec 'Alt' ?
Comme ça a été dit au-dessus pour 'Alt' mais si ta méthode marche,
c'est bon., et pour les 'case', tu les enlèves, vu que GetKeyNameText
() le fait déjà.