Qt win32 全局鼠标键盘钩子 的实现
win32 中 实现全局钩子,需要用到 SetWindowsHookEx 和 UnhookWindowsHookEx 两个API 并且必须在 动态链接库(DLL)中实现对消息的截获。
在这里我们用到了 qt 信号槽 方便的通知机制,在DLL中导出了 可以对全局鼠标键盘消息进行截获 并用发射信号的方式通知给代码用户。
api 说明
SetWindowsHookEx API
原型
1 HHOOK SetWindowsHookEx( 2 int idHook, // hook type 3 HOOKPROC lpfn, // hook procedure 4 HINSTANCE hMod, // handle to application instance 5 DWORD dwThreadId // thread identifier 6 );
目的:安装 指定类型的消息钩子,指定其消息处理函数,并返回 钩子的句柄。
参数:
int idHook:in,指定钩子的类型,可取的值有 WH_MOUSE_LL(底层鼠标钩子)、WH_KEYBOARD_LL(底层键盘钩子)等等,我们用到的就是这两种钩子。
HOOKPROC lpfn:in,指定消息处理函数的地址,不同的钩子参数的意义不同,键盘钩子处理函数原型如下:
LRESULT CALLBACK hookProc( int code, // 钩子类型标志 WPARAM wParam, // 按键按下与抬起标志,可取值 有 WM_KEYUP 和 WM_KEYDOWN。 LPARAM lParam // 指向 按键钩子信息结构体 KBDLLHOOKSTRUCT 的指针,该结构体含有按键消息的各种属性。 );
返回值:钩子句柄。
UnhookWindowsHookEx API
原型
BOOL UnhookWindowsHookEx( HHOOK hhk // handle to hook procedure );
目的:卸载 指定的消息钩子。
参数:
HHOOK hhk;要卸载的钩子句柄。
返回值:卸载成功返回true否则返回false。
DLL 实现
文件列表:
- GlobalHook.pro // 省略,项目向导中选择 C++ Library 模板即可。
- XGlobalHook.h
- XGlobalHook.cpp
1 #ifndef XGLOBALHOOK_H 2 #define XGLOBALHOOK_H 3 4 #include <QObject> 5 #include <QtGlobal> 6 #include <QMutex> 7 #include <QSharedPointer> 8 #include "windows.h" 9 10 #if defined(GLOBALHOOK_LIBRARY) 11 # define GLOBALHOOKSHARED_EXPORT Q_DECL_EXPORT 12 #else 13 # define GLOBALHOOKSHARED_EXPORT Q_DECL_IMPORT 14 #endif 15 16 #define xHook XGlobalHook::instance().data() 17 18 class GLOBALHOOKSHARED_EXPORT XGlobalHook : public QObject 19 { 20 Q_OBJECT 21 22 /// 单例 23 private: 24 XGlobalHook(QObject* parent = 0) : QObject(parent) {} 25 XGlobalHook(const XGlobalHook& hook) = delete; 26 XGlobalHook& operator==(const XGlobalHook&) = delete; 27 28 public: 29 virtual ~XGlobalHook() final; 30 static QSharedPointer<XGlobalHook>& instance(); 31 32 private: 33 static QMutex mutex; 34 static QSharedPointer<XGlobalHook> hook_instance; 35 36 /// 用户接口 37 public: 38 // 鼠标钩子 39 bool installMouseHook(); // 安装钩子 40 bool uninstallMouseHook(); // 卸载钩子 41 bool isMouseHookRunning() const; // 运行状态 42 // 键盘钩子 43 bool installKeyHook(); // 安装钩子 44 bool uninstallKeyHook(); // 卸载钩子 45 bool isKeyHookRunning() const; // 运行状态 46 47 signals: 48 void mouseEvent(PMOUSEHOOKSTRUCT pMouseHookStruct); 49 void keyEvent(PKBDLLHOOKSTRUCT pKeyHookStruct); 50 51 /// DLL 钩子接口 52 #if defined GLOBALHOOK_LIBRARY 53 public: 54 void onMouseEvent(PMOUSEHOOKSTRUCT pMouseHookStruct); 55 void onKeyEvent(PKBDLLHOOKSTRUCT pKeyHookStruct); 56 #endif 57 }; 58 59 #endif // XGLOBALHOOK_H
1 #include "XGlobalHook.h" 2 3 /// 静态变量定义 4 QMutex XGlobalHook::mutex; 5 QSharedPointer<XGlobalHook> XGlobalHook::hook_instance; 6 7 /// 全局变量定义 8 HINSTANCE g_hInstance = Q_NULLPTR; 9 HHOOK g_hMouseHook = Q_NULLPTR; //鼠标钩子 句柄 10 HHOOK g_hKeyHook = Q_NULLPTR; //键盘钩子 句柄 11 12 /// 全局函数定义 13 // DllMain 14 BOOL WINAPI DllMain( 15 HINSTANCE hinstDLL, // DLL模块的句柄 16 DWORD fdwReason, // 调用的情况 17 LPVOID lpReserved // reserved 18 ); 19 20 // 鼠标钩子处理函数 21 LRESULT CALLBACK MouseProc(int nCode, // 钩子码 22 WPARAM wParam, // 消息ID 23 LPARAM lParam // 鼠标坐标 24 ); 25 26 // 键盘钩子处理函数 27 LRESULT CALLBACK KeyboardProc(int nCode, // 钩子码 28 WPARAM wParam, // 虚拟键码 29 LPARAM lParam // 键击信息 30 ); 31 32 33 XGlobalHook::~XGlobalHook() 34 { 35 uninstallMouseHook(); 36 uninstallKeyHook(); 37 } 38 39 QSharedPointer<XGlobalHook>&XGlobalHook::instance() 40 { 41 if (hook_instance.isNull()) 42 { 43 QMutexLocker mutexLocker(&mutex); 44 if (hook_instance.isNull()) 45 hook_instance = QSharedPointer<XGlobalHook>(new XGlobalHook()); 46 } 47 return hook_instance; 48 } 49 50 bool XGlobalHook::installMouseHook() 51 { 52 g_hMouseHook =SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)MouseProc, g_hInstance, 0); 53 return Q_LIKELY(g_hMouseHook); 54 } 55 56 bool XGlobalHook::uninstallMouseHook() 57 { 58 if (Q_UNLIKELY(!g_hMouseHook)) { 59 return true; 60 } 61 62 bool success = false; 63 success = UnhookWindowsHookEx(g_hMouseHook); 64 if (success) { 65 g_hMouseHook = Q_NULLPTR; 66 } 67 return success; 68 } 69 70 bool XGlobalHook::isMouseHookRunning() const 71 { 72 return Q_LIKELY(g_hMouseHook); 73 } 74 75 bool XGlobalHook::installKeyHook() 76 { 77 g_hKeyHook =SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardProc, g_hInstance, 0); 78 return Q_LIKELY(g_hKeyHook); 79 } 80 81 bool XGlobalHook::uninstallKeyHook() 82 { 83 if (Q_UNLIKELY(!g_hKeyHook)) { 84 return true; 85 } 86 87 bool success = false; 88 success = UnhookWindowsHookEx(g_hKeyHook); 89 if (success) { 90 g_hKeyHook = Q_NULLPTR; 91 } 92 return success; 93 } 94 95 bool XGlobalHook::isKeyHookRunning() const 96 { 97 return Q_LIKELY(g_hKeyHook); 98 } 99 100 /// DLL 钩子接口 101 #if defined GLOBALHOOK_LIBRARY 102 103 void XGlobalHook::onMouseEvent(PMOUSEHOOKSTRUCT pMouseHookStruct) 104 { 105 emit mouseEvent(pMouseHookStruct); 106 } 107 108 void XGlobalHook::onKeyEvent(PKBDLLHOOKSTRUCT pKeyHookStruct) 109 { 110 emit keyEvent(pKeyHookStruct); 111 } 112 113 #endif 114 115 LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) 116 { 117 118 PMOUSEHOOKSTRUCT pmshs = reinterpret_cast<PMOUSEHOOKSTRUCT>(lParam); 119 xHook->onMouseEvent(pmshs); 120 return CallNextHookEx(g_hMouseHook,nCode,wParam,lParam); 121 } 122 123 LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam) 124 { 125 PKBDLLHOOKSTRUCT pkbhs = reinterpret_cast<PKBDLLHOOKSTRUCT>(lParam); 126 xHook->onKeyEvent(pkbhs); 127 return CallNextHookEx(g_hKeyHook, nCode, wParam, lParam); 128 } 129 130 BOOL WINAPI DllMain( 131 HINSTANCE hinstDLL, // DLL模块的句柄 132 DWORD fdwReason, // 调用的情况 133 LPVOID lpReserved ) // reserved 134 { 135 Q_UNUSED(lpReserved); 136 // 在不同的情况下都会调用DllMain函数,分别处理 137 switch( fdwReason ) 138 { 139 // 加载Dll 140 case DLL_PROCESS_ATTACH: 141 { 142 g_hInstance = hinstDLL; 143 break; 144 } 145 // 新建线程 146 case DLL_THREAD_ATTACH: 147 break; 148 // 线程退出 149 case DLL_THREAD_DETACH: 150 break; 151 // 释放Dll 152 case DLL_PROCESS_DETACH: 153 g_hInstance = Q_NULLPTR; 154 break; 155 } 156 return TRUE; 157 }
类库使用:
- 包含 XGlobalHook.h 文件
- 指定 Lib 文件
- 将 DLL 放到可执行文件
- xHook 为 XGlobalHook 单例类的对象指针 ,操作同 qApp