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)