在实际应用中,有时程序需要在特定的鼠标和按键事件后执行一些操作,比如:

1、点击触摸屏时触发蜂鸣器。

2、在休眠状态下点击触摸屏后,让程序结束休眠状态。

3、设置全局键功能,如一键截图或一键关机。

4、过滤一些鼠标或键盘操作等等。

这时候你可以用键盘鼠标挂钩来实现这些功能。

钩子是WINDOWS/WINCE系统特有的消息处理机制。通过系统调用,将报文处理程序段挂入系统,获得报文处理的优先控制权,在报文到达目的窗口前进行处理。钩子函数可以决定是处理(改变)消息,还是继续传递消息而不处理,或者强制结束消息传递。

钩子有很多种,WINCE系统已经缩减到只有四种钩子。同时,钩子也可以是局部钩子或全局钩子。局部钩子只在指定的进程中生效,全局钩子在系统中生效。通用的全局钩子需要挂载在dll中才能使用。本文介绍的鼠标钩子和键盘钩子比较特殊,不需要挂载在dll中就可以全局生效。

钩子的运行逻辑如下所示。每个钩子都可以挂在任意数量的钩子函数中,并存储在一个链表中。系统优先考虑链表顶部的钩子,然后将消息依次传递给后面的钩子进行处理。后面挂起的钩子位于链表的前端。

施用方式

添加挂钩分为三个步骤。

1、编写钩子函数处理代码

2、调用API函数将钩子函数钩入系统。

3、创建一个消息循环以使钩子工作。

添加参考

使用钩子需要函数,比如SetWindowsHookEx,UnhookWindowsHookEx,CallNextHookEx。而键盘钩子和鼠标钩子的定义,键盘消息和鼠标消息的结构定义都是在pwinuser.h中定义的

#包含' pwinuser.h '

创建一个需要挂入系统的消息处理函数。

也就是钩子函数,定义了必须公式化的格式。

钩子函数根据实际应用需求决定是否调用CallNextHookEx,并将消息传递给后面的钩子进行处理。

第一个钩子函数的返回值决定了消息是被丢弃还是被传递给系统消息处理函数,然后被分发到各个窗口。

下面是键盘和鼠标钩子函数的例子。

键盘挂钩功能

在这个键盘钩子示例函数中,当检测到键“1”被按下时,调用Beep函数来触发蜂鸣器。

LRESULT回调KeyboardProc(intnCode,WPARAM wParam,LPARAM lParam)

{

KBDLLHOOKSTRUCT * pkbhs=(KBDLLHOOKSTRUCT *)lParam;

如果(wParam==WM_KEYDOWN) //按钮被按下。

{

开关(pkbhs-vkCode)

{

Case0x31: //button ' '

beep();

打破;

默认:

打破;

}

}

returnCallNextHookEx(NULL,nCode,wParam,lParam);

}

注意:

1、 WinCE键盘钩子函数记录的WPARAM的消息类别,比如按键是按下消息WM_KEYDOWN还是弹出消息WM_KEYUP。

LPARAM指向键盘消息结构KBDLLHOOKSTRUCT,其中记录了详细的信息,比如触发的键是什么,按下的是ALT键还是CTRL键等等。

2、挂钩队列中第一个挂钩的返回值决定了系统是否可以接受消息。

返回0意味着消息被传递给系统消息处理程序以继续处理。

返回1意味着该消息将被丢弃,系统将不会接收到它。

调用CallNextHookEx意味着调用下一个钩子消息处理函数。如果不调用它,下面的钩子函数将不起作用。

鼠标(触摸屏)挂钩功能

在这个鼠标钩子示例函数中,当检测到鼠标或触摸屏点击时,调用Beep函数来触发蜂鸣器。

LRESULT回调MouseHookProc(intnCode,WPARAM wParam,LPARAM lParam)

{

MSLLHOOKSTRUCT * pmshs=(MSLLHOOKSTRUCT *)lParam;

If(wParam==WM_LBUTTONDOWN) //鼠标点击处理代码

{

beep();

}

returnCallNextHookEx(NULL,nCode,wParam,lParam);

}

注意:

1、 WINCE鼠标钩子函数记录的WPARAM的消息类别,比如鼠标是按下还是弹起,还是双击、移动等等。

LPARAM记录了详细的信息,比如点击坐标,轮子参数等等。

2、触摸屏消息与鼠标消息相同。

3、挂钩队列中第一个挂钩的返回值决定了系统是否可以接受消息。

返回0意味着消息被传递给系统消息处理程序以继续处理。

返回1意味着该消息将被丢弃,系统将不会接收到它。

调用CallNextHookEx意味着调用下一个钩子消息处理函数。如果不调用它,下面的钩子函数将不起作用。

蜂鸣功能

在本例中,嵌入式板卡GPIO15连接了一个蜂鸣器,通过设置GPIO的电平来触发蜂鸣器。

在程序的初始段打开GPIO,获取GPIO句柄。

#包含“isa_dio.h”

处理hGpio

Hg Pio=open gpio(_ T(' Pio 1:));

增加蜂鸣功能,通过GPIO手柄操作GPIO15。

voidBeep()

{

GPIO_OutClear(hGpio,GPIO 15);

睡眠(10);

GPIO _ outlet(Hg Pio,GPIO 15);

}

添加挂钩

在主线程中调用SetWindowsHookEx函数给系统添加钩子。

第一个参数是添加的钩子类型,WH _键盘_LL是键盘钩子,WH _鼠标_LL是鼠标钩子。

第二个参数是注入的消息处理程序指针,这是前面定义的钩子函数。

第三个参数是钩子程序的实例指针。本文中介绍的钩子不需要安装在dll中,所以只需将其设置为NULL。

最后一个参数是与钩子关联的线程句柄,其中0表示关联所有线程,也就是全局钩子。

函数返回NULL,表示添加钩子失败,钩子句柄返回成功。

示例代码如下:

HINSTANCE hInstance=NULL

HHOOK g _ hKBDhook=NULL

HHOOK g _ hMouseHook=NULL

g _ hKBDhook=SetWindowsHookEx(WH _键盘_LL,KeyboardProc,hInstance,0);

if(g_hKBDhook==NULL)

{

返回false;

}

g _ hMouseHook=SetWindowsHookEx(WH _鼠标_LL,MouseHookProc,hInstance,0);

if(g_hMouseHook==NULL)

{

返回false;

}

添加消息循环

钩子机制是基于消息循环的,所以需要添加消息循环。如果不添加消息循环,系统消息进入钩子后会卡死。

MFC框架程序有自己的消息循环。

命令行程序需要在main函数中添加以下代码。

味精味精;

while(GetMessage(msg,NULL,0,0)) {

翻译消息(msg);

DispatchMessage(消息);

}

删除挂钩

不需要挂钩时,应主动释放。

unhook windowshookex(g _ hKBDhook);

unhook windowshookex(g _ hMouseHook);

盈创提供了例程和源代码,有需求的客户可以联系盈创工程师获取。