QT中使用钩子需要
#include <Windows.h>
鼠标键盘钩子各有两个,一个是普通的,一个是底层钩子,代码的写法差不多,区别是底层钩子比普通钩子更早接收到消息,还有个debug钩子,在所有的普通钩子前接收到消息。
不同的钩子对应的回调函数的写法(形参、返回值的意义):https://blog.csdn.net/jiangxinyu/article/details/5284067,如果链接失效,自行搜索《HOOK钩子机制学习笔记(4) - 钩子函数说明》
安装钩子:
HHOOK keyHook=NULL;
HHOOK mouseHook=NULL;
void install_Hook()//安装钩子
{
//这两个底层钩子,不要DLL就可以全局
//底层鼠标钩子
//mouseHook =SetWindowsHookEx( WH_MOUSE_LL,mouseProc,GetModuleHandle(NULL),0);
//底层键盘钩子
keyHook =SetWindowsHookEx( WH_KEYBOARD_LL,keyProc,GetModuleHandle(NULL),0);//GetModuleHandle(NULL)取得本程序的句柄
if(NULL == keyHook)
qDebug() << "warning: keyHook failed!";
}
卸载钩子:
//卸载钩子
void unHook()
{
UnhookWindowsHookEx(keyHook);
// UnhookWindowsHookEx(mouseHook);
}
键盘钩子的回调函数:
/* 功能:键盘钩子回调,钩子类型不同,则形参的意义也不同,对于底层LL键盘钩子,形参为:
* 形参:nCode
* wParam 按键的状态,可能的值为WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN、WM_SYSKEYUP
* lParam 按键的软件码、硬件码、标志位、扩展信息(需强转转为KBDLLHOOKSTRUCT *类型) *
* */
LRESULT CALLBACK keyProc(int nCode,WPARAM wParam,LPARAM lParam )
{
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam;
//如果nCode等于HC_ACTION则处理该消息,如果小于0,则钩子子程就必须将该消息传递给 CallNextHookEx
if(nCode == HC_ACTION)
{
// qDebug() << "pkbhs->vkCode=" << pkbhs->vkCode;
qDebug() << "vkCode = " << pkbhs->vkCode << ", flags = " << pkbhs->flags ;
if(pkbhs->vkCode == VK_ESCAPE && GetAsyncKeyState(VK_CONTROL)& 0x8000 && GetAsyncKeyState(VK_SHIFT)&0x8000){
qDebug() << "Ctrl+Shift+Esc";
}else if(pkbhs->vkCode == VK_ESCAPE && GetAsyncKeyState(VK_CONTROL) & 0x8000){
qDebug() << "Ctrl+Esc";
}else if(pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN){
qDebug() << "Alt+Tab";
}else if(pkbhs->vkCode == VK_ESCAPE && pkbhs->flags &LLKHF_ALTDOWN){
qDebug() << "Alt+Esc";
}else if(pkbhs->vkCode == VK_LWIN || pkbhs->vkCode == VK_RWIN){
qDebug() << "LWIN/RWIN";
}else if(pkbhs->vkCode == VK_F4 && pkbhs->flags & LLKHF_ALTDOWN){
qDebug() << "Alt+F4";
}
if(pkbhs->vkCode == VK_F12)
{
void unHook();
qApp->quit();
}
return 1;//返回1表示截取消息不再传递,返回0表示不作处理,消息继续传递
}
else
return CallNextHookEx(keyHook, nCode, wParam, lParam);
}
上面的例子通过return 1截断了键盘的消息,如果想修改键盘的消息,可以在return 1之前加上以下代码:
DWORD keyUpFlag = (wParam == WM_KEYUP) ? KEYEVENTF_KEYUP : 0;//方法1
//DWORD keyUpFlag = (pkbhs->flags & 0x80) == 0? 0 : KEYEVENTF_KEYUP;//方法2
static const int scanCode = MapVirtualKey('A', MAPVK_VK_TO_VSC);
keybd_event('A', scanCode, keyUpFlag, pkbhs->dwExtraInfo);
return 1;
keybd_event用来模拟产生一个键盘消息,4个参数分别为:按键值、按键的硬件码、按下还是弹起、额外信息。
注意第三个参数,按下或者弹起这个标志位,这个标志位只能填0或KEYEVENTF_KEYUP,分别代表压下和弹起,
截获的消息中有两个地方可以得知按下还是弹起,一个是wParam,另一个是lParam(pkbhs->flags)