内容:很多的教学软件或系统监视软件可以自动记录回放用户的输入文字或点击按钮等操作操作,这个功能的实现是使用
了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指向的区域中,系统就会执行该消息,从而实现了消息回放。

//以下是VC做的小例子

// replayView.cpp : implementation of the CReplayView class

#include "stdafx.h"
#include "replay.h"

#include "replayDoc.h"
#include "replayView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

LRESULT CALLBACK RecHook(int code,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK PlayHook(int code,WPARAM wParam,LPARAM lParam);

HHOOK recHook,playHook;
EVENTMSG EventArray[1000];
int recordedEvent=0;
int playedEvent=0;

/
// CReplayView

IMPLEMENT_DYNCREATE(CReplayView, CEditView)

BEGIN_MESSAGE_MAP(CReplayView, CEditView)
 //{{AFX_MSG_MAP(CReplayView)
 ON_COMMAND(ID_FUNCTION_START, OnFunctionStart)
 ON_COMMAND(ID_FUNCTION_STOP, OnFunctionStop)
 ON_COMMAND(ID_FUNCTION_REPLAY, OnFunctionReplay)
 //}}AFX_MSG_MAP
 // Standard printing commands
 ON_COMMAND(ID_FILE_PRINT, CEditView::OnFilePrint)
 ON_COMMAND(ID_FILE_PRINT_DIRECT, CEditView::OnFilePrint)
 ON_COMMAND(ID_FILE_PRINT_PREVIEW, CEditView::OnFilePrintPreview)
END_MESSAGE_MAP()

/
// CReplayView construction/destruction

CReplayView::CReplayView()
{
 // TODO: add construction code here

}

CReplayView::~CReplayView()
{
}

BOOL CReplayView::PreCreateWindow(CREATESTRUCT& cs)
{
 // TODO: Modify the Window class or styles here by modifying
 //  the CREATESTRUCT cs

BOOL bPreCreated = CEditView::PreCreateWindow(cs);
 cs.style &= ~(ES_AUTOHSCROLL|WS_HSCROLL); // Enable word-wrapping

return bPreCreated;
}

/
// CReplayView drawing

void CReplayView::OnDraw(CDC* pDC)
{
 CReplayDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 // TODO: add draw code for native data here
}

/
// CReplayView printing

BOOL CReplayView::OnPreparePrinting(CPrintInfo* pInfo)
{
 // default CEditView preparation
 return CEditView::OnPreparePrinting(pInfo);
}

void CReplayView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
 // Default CEditView begin printing.
 CEditView::OnBeginPrinting(pDC, pInfo);
}

void CReplayView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo)
{
 // Default CEditView end printing
 CEditView::OnEndPrinting(pDC, pInfo);
}

/
// CReplayView diagnostics

#ifdef _DEBUG
void CReplayView::AssertValid() const
{
 CEditView::AssertValid();
}

void CReplayView::Dump(CDumpContext& dc) const
{
 CEditView::Dump(dc);
}

CReplayDoc* CReplayView::GetDocument() // non-debug version is inline
{
 ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CReplayDoc)));
 return (CReplayDoc*)m_pDocument;
}
#endif //_DEBUG

/
// CReplayView message handlers

void CReplayView::OnFunctionStart()
{
 // TODO: Add your command handler code here
 recordedEvent=0;
 recHook=SetWindowsHookEx(WH_JOURNALRECORD,(HOOKPROC)RecHook,(HINSTANCE)AfxGetApp()->m_hInstance,0);
 
}

void CReplayView::OnFunctionStop()
{
 // TODO: Add your command handler code here
 UnhookWindowsHookEx(recHook);
}

void CReplayView::OnFunctionReplay()
{
 // TODO: Add your command handler code here
 playedEvent=0;
 playHook=SetWindowsHookEx(WH_JOURNALPLAYBACK,(HOOKPROC)PlayHook,(HINSTANCE)AfxGetApp()->m_hInstance,0);
}
LRESULT CALLBACK RecHook(int code,WPARAM wParam,LPARAM lParam)
{
 
 static int recOK=1;
 if(code<0)
  return CallNextHookEx(recHook,code,wParam,lParam);
 else if(code==HC_SYSMODALON)
  recOK=0;
 else if(code==HC_SYSMODALOFF)
  recOK=1;
 else if(recOK && (code==HC_ACTION))
 {
  EventArray[recordedEvent]= *((PEVENTMSG)lParam);
  recordedEvent++;
  if(recordedEvent==1000)
  {
   UnhookWindowsHookEx(recHook);
  }
 }
 return 0;
}

LRESULT CALLBACK PlayHook(int code,WPARAM wParam,LPARAM lParam)
{
 static BOOL fDelay;
 static int playOK=1;
 if(code<0)
  return CallNextHookEx(playHook,code,wParam,lParam);
 else if(code==HC_SYSMODALON)
  playOK=0;
 else if(code==HC_SYSMODALOFF)
 {
  playOK=1;
 }
 else if(playOK && (code==HC_GETNEXT))
 {
  if(fDelay)
  {
   fDelay=FALSE;
   return 50;
  }
  *((PEVENTMSG)lParam)=EventArray[playedEvent];
 }
 else if(playOK && (code==HC_SKIP))
 {
  fDelay=TRUE;
  playedEvent++;
 }
 if(playedEvent>=recordedEvent)
 {
  UnhookWindowsHookEx(playHook);
 }
 return 0;
}

钩子函数-建立键盘鼠标动作记录与回放相关推荐

  1. 用C#实现键盘鼠标动作捕获

    由于近期需要编写一个程序,通过右键退出播放,一般情况下,只在鼠标离开运行程序的窗口,就不能捕获键盘鼠标的动作了,原来只熟悉delphi的开发,由于delphi监测键盘鼠标动作需要封装DLL,以钩子的形 ...

  2. 使用PreTranslateMessage替代钩子函数处理键盘消息

    2002年左右,我所在公司在开发基于H.323的VoIP电话系统(用了以色列一家公司的库,具体名字忘记了). 去电信科技研究院测试系统,同事发现处理键盘消息总有一些莫名其妙的问题,比如延迟或异常. 我 ...

  3. Python ctypes 调用API函数模拟键盘鼠标事件

    在Python编程中, 有时需要模拟键盘或鼠标事件, 自动操作计算机, 比如玩游戏等. 本文介绍使用ctypes模块调用API函数, 模拟键盘鼠标事件的方法. 目录 1.导入ctypes模块 2.通过 ...

  4. 【Python】实现键盘鼠标动作录制和执行的小工具

    突发奇想做一个可以实现鼠标键盘操作录制,并可以回放操作的小工具.依托于pynput模块来实现鼠标键盘的控制,tkinter来实现图形界面的绘制.分为以下几个步骤: 一 录制(记录过程,并将用户的操作保 ...

  5. Pyautogui 实现键盘鼠标动作

    安装 PyAutoGUI支持Python 2.x和Python 3.x Windows:PyAutoGUI没有任何依赖,因为它用Python的ctypes模块所以不需要pywin32 pip inst ...

  6. 使用UInput模拟系统键盘鼠标动作 UInput driver分析

    当uinput driver已经insmod, 且node 已经建立后.即可使用它们传递系统输入设备消息. <wbr></wbr> 1. 打开UInputDevice: 应用程 ...

  7. Windows API——SendInput总结(模拟键盘鼠标动作)

    SendInput()函数: SendInput()函数用于合成键盘事件和鼠标事件,用来模拟鼠标或者键盘操作. 函数原型: UINT SendInput([in] UINT cInputs,[in] ...

  8. 用Delphi实现Windows的鼠标钩子函数

    用Delphi实现Windows的鼠标钩子函数 Delphi是基于PASCAL语言的Windows编程工具,功能十分强大.然而在Delphi的帮助 文件中,对Windows API函数的说明沿袭了 V ...

  9. 可二次开发的USB键盘鼠标 Lao-UKM V3.1 (简介 应用举例)

    USB键盘鼠标模拟器简介 用一句话来阐述,就是一个可以2次开发的USB键盘鼠标,硬件如图: 控制命令从左侧的串口进入,经过转化变成标准的USB键盘鼠标操作从右侧输出, USB插入电脑就是标准的键盘鼠标 ...

最新文章

  1. Linux下添加新硬盘,分区及挂载
  2. 二十四、redis发布订阅
  3. python【Numpy科学计算库】连女朋友都会用的Numpy(真の能看懂~!)
  4. 租车信息系统数据库设计(3)
  5. fckeditor2.63 上传图片的一个问题的解决办法
  6. 多态部分作业 3..创建Rodent(啮齿动物):Mnouse(老鼠),Gerbil(鼹鼠),Hamster(大颊鼠)
  7. Linux文件系统和文本编辑器
  8. Devexpress xaf针对某个用户登录后在面板中设置导航无效的解决方法
  9. python pdb调试基本命令整理
  10. PyTorch——解决报错“RuntimeError: running_mean should contain *** elements not ***”
  11. 子类调用父类构造器的几种情况
  12. (微信编辑器)UEditor富文本嵌入135编辑器
  13. 傅里叶变换与时域频域关系
  14. mac 建 android 签名,mac android app 签名工具
  15. wifi一到晚上服务器无响应,一到晚上九点,网络就开始卡了?主要原因是这三点!...
  16. ensp 不兼容 virtualbox,virtualbox version not support (AR 报错40 41 解决思路)
  17. 嵌入式硬件-读懂原理图
  18. RxSwift+Moya之项目实战
  19. 合数python_python输出100以内的质数与合数
  20. 爱情还能找人托管?| 搞笑囧图

热门文章

  1. android 做渠道统计,umeng 渠道统计 android
  2. Java--HIbernate中的SessionFactory和Session
  3. mysql查询第八页_第八节:MySQL之Select指令详解和相关练习
  4. 本周 火火火火 的开源项目!
  5. CTF从零到一 信息收集 常见的搜集
  6. 给中国学生的第七封信--21世纪最需要的7种人才
  7. 区块链安全入门笔记(二) | 慢雾科普
  8. 亚马逊红人买家秀关联视频是合规安全提升转化的有力工具
  9. 查看Xcode安装进度
  10. 使用vivado2019.2和petalinux 2019.2制作带无线wifi的ultra96v2的BSP软件包