DELPHI使用键盘钩子
小读了一下《Delphi下深入Windows核心编程》感觉里面的东西写得还算可以,至少有学到东西
于是整理了一下书中的代码,并加上注注释发上来
首先是最重要的键盘钩子使用的DLL:
unit UnitDll; interface uses Windows; const BUFFER_SIZE = 16 * 1024; // 文件映射到内存的大小 const HOOK_MEM_FILENAME = 'MEM_FILE'; // 映像文件名 const HOOK_MUTEX_NAME = 'MUTEX_NAME'; // 互斥名 type // 共享结构 TShared = record Keys: array[0..BUFFER_SIZE] of Char; KeyCount: Integer; end; // 共享结构指针 PShared = ^TShared; var MemFile, HookMutex: THandle; // 文件句柄和互斥句柄 hOldKeyHook: HHook; // 钩子变量 Shared: PShared; // 共享变量 implementation // 重要:键盘钩子回调 function KeyHookProc(iCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; export; const KeyPressMask = $80000000; begin if iCode < 0 then Result := CallNextHookEx(hOldKeyHook, iCode, wParam, lParam) else begin if ((lParam and KeyPressMask) = 0) then begin // 键盘消息捕获 Shared^.Keys[Shared^.KeyCount] := Char(wParam and $00FF); Inc(Shared^.KeyCount); // 超出内存限定大小则重置 if Shared^.KeyCount >= BUFFER_SIZE - 1 then Shared^.KeyCount := 0; end; result:=0; end; end; // 安装钩子 function EnableKeyHook: BOOL; export; begin Shared^.KeyCount := 0; if hOldKeyHook = 0 then begin // 设置钩子过滤 {WH_KEYBOARD: 安装的是键盘钩子 KeyHookProc: 消息回调, HInstance: 回调函数实例 线程ID} hOldKeyHook := SetWindowsHookEx(WH_KEYBOARD, KeyHookProc, HInstance, 0); end; Result := (hOldKeyHook <> 0); end; {撤消钩子过滤函数} function DisableKeyHook: BOOL; export; begin if hOldKeyHook <> 0 then begin UnHookWindowsHookEx(hOldKeyHook); hOldKeyHook := 0; Shared^.KeyCount := 0; end; Result := (hOldKeyHook = 0); end; // 得到获得多少按键 function GetKeyCount: Integer; export; begin Result := Shared^.KeyCount; end; // 得到第I个按键 function GetKey(index: Integer): Char; export; begin Result := Shared^.Keys[index]; end; // 清空按键 procedure ClearKeyString; export; begin Shared^.KeyCount := 0; end; // 导出函数列表 exports EnableKeyHook, DisableKeyHook, GetKeyCount, ClearKeyString, GetKey; initialization // 创建互斥变量,DLL只能有一个进程可以使用 HookMutex := CreateMutex(nil, True, HOOK_MUTEX_NAME); // 打开文件映像 MemFile := OpenFileMapping(FILE_MAP_WRITE, False, HOOK_MEM_FILENAME); // 如果不存在该文件映像则创建 if MemFile = 0 then MemFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TShared), HOOK_MEM_FILENAME); // 文件映射内存 Shared := MapViewOfFile(MemFile, File_MAP_WRITE, 0, 0, 0); // 释放互斥变量 ReleaseMutex(HookMutex); // 关闭互斥句柄 CloseHandle(HookMutex); finalization // 撤消钩子过滤 if hOldKeyHook <> 0 then DisableKeyHook; // 释放映射 UnMapViewOfFile(Shared); // 关闭映像文件 CloseHandle(MemFile); end.
这个看懂了之后就可以直接写个CLIENT调用了
unit Unit2; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Memo1: TMemo; bSetHook: TButton; bCancelHook: TButton; bReadKeys: TButton; bClearKeys: TButton; Panel2: TPanel; procedure bSetHookClick(Sender: TObject); procedure bCancelHookClick(Sender: TObject); procedure bReadKeysClick(Sender: TObject); procedure bClearKeysClick(Sender: TObject); end; var Form1: TForm1; implementation {$R *.DFM} function EnableKeyHook: BOOL; external 'KEYHOOK.DLL'; function DisableKeyHook: BOOL; external 'KEYHOOK.DLL'; function GetKeyCount: Integer; external 'KEYHOOK.DLL'; function GetKey(idx: Integer): Char; external 'KEYHOOK.DLL'; procedure ClearKeyString; external 'KEYHOOK.DLL'; procedure TForm1.bSetHookClick(Sender: TObject); begin EnableKeyHook; bSetHook.Enabled := False; bCancelHook.Enabled := True; bReadKeys.Enabled := True; bClearKeys.Enabled := True; Panel2.Caption := ' 键盘钩子已经设置'; end; procedure TForm1.bCancelHookClick(Sender: TObject); begin DisableKeyHook; bSetHook.Enabled := True; bCancelHook.Enabled := False; bReadKeys.Enabled := False; bClearKeys.Enabled := False; Panel2.Caption := ' 键盘钩子没有设置'; end; procedure TForm1.bReadKeysClick(Sender: TObject); var i: Integer; begin Memo1.Lines.Clear;{在Memo1中显示击键历史记录} for i := 0 to GetKeyCount - 1 do Memo1.Text := Memo1.Text + GetKey(i); end; procedure TForm1.bClearKeysClick(Sender: TObject); begin Memo1.Clear; ClearKeyString; end; end.