很多的教学软件或系统监视软件可以自动记录回放用户的输入文字或点击按钮等操作操作,这个功能的实现是使用
了Windows的Hook函数。
Windows提供API函数SetwindowsHookEx来建立一个Hook,通过这个函数可以将一个
程序添加到Hook链中监视Windows
消息,函数语法为:
SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST; dwThreadId: DWORD)
其中参数idHook指定建立的监视函数类型。通过Windows MSDN帮助可以看到,SetwindowsHookEx函数提供15种不同
的消息监视类型,在这里我们将使用WH_JOURNALRECORD和WH_JOURNALPLAYBACK来监视键盘和鼠标操作。参数lpfn指定消
息函数,在相应的消息产生后,系统会调用该函数并将消息值传递给该函数供处理。函数的一般形式为:
Hookproc (code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
其中code为系统指示标记,wParam和lParam为附加参数,根据不同的消息监视类型而不同。只要在
程序中建立这样
一个函数再通过SetwindowsHookEx函数将它加入到消息监视链中就可以处理消息了。
在不需要监视系统消息时需要调用提供UnHookWindowsHookEx来解除对消息的监视。
WH_JOURNALRECORD和WH_JOURNALPLAYBACK类型是两种相反的Hook类型,前者获得鼠标、键盘动作消息,后者回放鼠
标键盘消息。所以在
程序中我们需要建立两个消息函数,一个用于纪录鼠标键盘操作并保存到一个数组中,另一个用于
将保存的操作返给系统回放。
下面来建立
程序,在Delphi中建立一个工程,在Form1上添加3个按钮用于
程序操作。另外再添加一个按钮
控件和一
个Edit
控件用于验证操作。
下面是Form1的全部代码
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Edit1: TEdit;
Button4: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
EventArr:array[0..1000]of EVENTMSG;
EventLog:Integer;
PlayLog:Integer;
hHook,hPlay:Integer;
recOK:Integer;
canPlay:Integer;
bDelay:Bool;
implementation
{$R *.DFM}
Function PlayProc(iCode:Integer;wParam:wParam;lParam:lParam):LRESULT;stdcall;
begin
canPlay:=1;
Result:=0;
if iCode < 0 then //必须将消息传递到消息链的下一个接受单元
Result := CallNextHookEx(hPlay,iCode,wParam,lParam)
else if iCode = HC_SYSMODALON then
canPlay:=0
else if iCode = HC_SYSMODALOFF then
canPlay:=1
else if ((canPlay =1 )and(iCode=HC_GETNEXT)) then begin
if bDelay then begin
bDelay:=False;
Result:=50;
end;
pEventMSG(lParam)^:=EventArr[PlayLog];
end
else if ((canPlay = 1)and(iCode = HC_SKIP))then begin
bDelay := True;
PlayLog:=PlayLog+1;
end;
if PlayLog>=EventLog then begin
UNHookWindowsHookEx(hPlay);
end;
end;
function HookProc(iCode:Integer;wParam:wParam;lParam:lParam):LRESULT;stdcall;
begin
recOK:=1;
Result:=0;
if iCode < 0 then
Result := CallNextHookEx(hHook,iCode,wParam,lParam)
else if iCode = HC_SYSMODALON then
recOK:=0
else if iCode = HC_SYSMODALOFF then
recOK:=1
else if ((recOK>0) and (iCode = HC_ACTION)) then begin
EventArr[EventLog]:=pEventMSG(lParam)^;
EventLog:=EventLog+1;
if EventLog>=1000 then begin
UnHookWindowsHookEx(hHook);
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Caption:='纪录';
Button2.Caption:='停止';
Button3.Caption:='回放';
Button4.Caption:='范例';
Button2.Enabled:=False;
Button3.Enabled:=False;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
EventLog:=0;
//建立键盘鼠标操作消息纪录链
hHook:=SetwindowsHookEx(WH_JOURNALRECORD,HookProc,HInstance,0);
Button2.Enabled:=True;
Button1.Enabled:=False;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
UnHookWindowsHookEx(hHook);
hHook:=0;
Button1.Enabled:=True;
Button2.Enabled:=False;
Button3.Enabled:=True;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
PlayLog:=0;
//建立键盘鼠标操作消息纪录回放链
hPlay:=SetwindowsHookEx(WH_JOURNALPLAYBACK,PlayProc,
HInstance,0);
Button3.Enabled:=False;
end;
end.
代码添加完毕后,运行
程序,点击“纪录”按钮开始纪录操作,这时你可以在文本
控件中输入一些文字或者点击
“范例”按钮,然后点击“停止”按钮停止纪录,再点击“回放”按钮就可以讲先前所做的操作回放。
在上面的
程序中,HookProc是纪录操作的消息函数,每当有鼠标键盘消息发生时,系统都会调用该函数,消息信
息就保存在地址lParam中,我们可以讲消息保存在一个数组中。PlayProc是消息回放函数,当系统可以执行消息回放
时调用该函数,
程序就将先前纪录的消息值返回到lParam指向的区域中,系统就会执行该消息,从而实现了消息回放。
附录:关于Keyboard HOOK的返回码
API描述:
LRESULT CALLBACK KeyboardProc(
int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
);
wParam的返回值:
返回键值(Key passed,按下某个键的返回值,而非抬起某个键值):
键名 十六进制值
------------------------------------------------(功能键)
F1 70
F2 71
F3 72
F4 73
F5 74
F6 75
F7 76
F8 77
F9 78
F10 79
F11 7A
F12 7B
------------------------------------------------(特殊键)
PrintScreen 无
ScrollLock 91
Pause 13
Insert 2D
Delete 2E
Home 24
End 23
PageUp 21
PageDown 22
Left 25
Up 26
Down 28
Right 27
------------------------------------------------(小键盘 - 常规键)
NumLock 90
/ 6F
* 6A
- 6D
+ 6B
Enter 0D
------------------------------------------------(小键盘On)
. 6E
0 60
1 61
2 62
3 63
4 64
5 65
6 66
7 67
8 68
9 69
------------------------------------------------(小键盘Off)
Del 2E
Ins 2D
End 23
Down 28
PgDn 22
Left 25
(5) 0C
Right 27
Home 24
Up 26
PgUp 21
------------------------------------------------(大键盘 - 数字及符号)
` C0
1 31
2 32
3 33
4 34
5 35
6 36
7 37
8 38
9 39
0 30
- BD
= BB
\ DC
[ DB
] DD
; BA
' DE
, BC
. BE
/ BF
Space 20
------------------------------------------------(大键盘 - 字母)
q 51
w 57
e 45
r 52
t 54
y 59
u 55
i 49
o 4F
p 50
a 41
s 53
d 44
f 46
g 47
h 48
j 4A
k 4B
l 4C
z 5A
x 58
c 43
v 56
b 42
n 4E
m 4D
------------------------------------------------(大键盘 - 控制)
Esc 1B
Tab 09
CapsLock 14
Shift 10
Ctrl 11
Win 5B
Alt 12
App 5D
Enter 0D
BackSpace 08