600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > QT 使用全局钩子监听鼠标事件和键盘事件

QT 使用全局钩子监听鼠标事件和键盘事件

时间:2019-12-19 02:56:48

相关推荐

QT 使用全局钩子监听鼠标事件和键盘事件

简介

include <windows.h>本版本使用的LL版,提供了获取虚拟键码,鼠标坐标等方法,比较全面。采用了观察者模式,将所有注册进来的函数放置到list里面,当事件触发的时候遍历和调用。hookhelper.h 和 hookhelper.cpp 考虑了移植性和多线程,所以写的复杂了许多,但是功能是全面的,且做成DLL也是比较方便的。重要文档 SetWindowsHookExA 键盘监听: WH_KEYBOARD_LL LPARAM: PKBDLLHOOKSTRUCT 鼠标监听: WH_MOUSE_LL LPARAM: PMSLLHOOKSTRUCT

源代码

hookhelper.h

#ifndef HOOKHELPER_H#define HOOKHELPER_H#include <iostream>#include <Windows.h>#include <string>#include <list>#include <mutex>using namespace std;enum class e_WParam;typedef void (*f_keyEvent )(e_WParam wParam, LPARAM lParam);typedef void (*f_print)(string str);// 键盘消息struct s_KeyCallMsg{string name;WPARAM listenWParam;f_keyEvent callback;};// 鼠标消息struct s_MouseCallMsg{string name;WPARAM listenWParam;f_keyEvent callback;};// HOOK的种类enum class e_HookType{MOUSE,KEY_BOARD};// 触发的事件enum class e_WParam{// 按键KEYDOWN=0x0100,KEYUP=0x0101,SYSKEYDOWN=0x0104,SYSKEYUP=0x0105,// 鼠标LBUTTONUP=0x0202,LBUTTONDOWN=0x0201,RBUTTONDOWN=0x0204,RBUTTONUP=0x0205,// 滚动事件MOUSEHWHEEL=0x020E,MOUSEWHEEL=0x020A,// 鼠标移动MOUSEMOVE=0x0200};/*** @brief 获取虚拟键码* @param lParam* @return*/DWORD GetKeyCode(LPARAM lParam);/*** @brief 获取鼠标位置* @param lParam* @return*/POINT GetMousePoint(LPARAM lParam);/*** @brief 设置打印函数* @param f*/void SetPrintFunction(f_print f);/*** @brief 添加新的键盘回调函数* @param callMsg* @return*/BOOL AddKeyBoardHookCallBack(s_KeyCallMsg callMsg);/*** @brief 添加新的鼠标回调函数* @param callMsg* @return*/BOOL AddMouseHookCallBack(s_MouseCallMsg callMsg);/*** @brief 卸载钩子* @param name 钩子名称* @param type 钩子类型* @return*/BOOL UninstallHook(string name,e_HookType type);/*** @brief 卸载所有的钩子* @param type 钩子类型* @return*/BOOL UninstallAllHook(e_HookType type) ;#endif // HOOKHELPER_H

hookhelper.cpp

#include "hookhelper.h"// 必要的静态链接库//#pragma comment (lib,"User32.lib")//#pragma comment (lib,"Gdi32.lib")// 配置打印方式HHOOK g_keyHHook;HHOOK g_mouseHHook;list<s_KeyCallMsg> g_keyCallMsgList;list<s_MouseCallMsg> g_mouseCallMsgList;BOOL g_keyIsInstall=FALSE;BOOL g_mouseIsInstall=FALSE;f_print g_print = NULL;static mutex g_keyMu; // 线程锁static mutex g_mouseMu; // 线程锁void _PrivateLog(string str){if(g_print==NULL){return;}(*g_print)(str);}/*** @brief 获取虚拟键码* @param lParam* @return*/DWORD GetKeyCode(LPARAM lParam){PKBDLLHOOKSTRUCT st = (PKBDLLHOOKSTRUCT)lParam;return st->vkCode;}/*** @brief 获取鼠标位置* @param lParam* @return*/POINT GetMousePoint(LPARAM lParam){PMSLLHOOKSTRUCT st =(PMSLLHOOKSTRUCT)lParam;return st->pt;}/// <summary>/// 键盘回调/// </summary>/// <param name="code"></param>/// <param name="wParam"></param>/// <param name="lParam"></param>/// <returns></returns>LRESULT CALLBACK ProcForKeyBoard(int code, WPARAM wParam, LPARAM lParam) {if (code < 0 || code == HC_NOREMOVE) {// 如果代码小于零,则挂钩过程必须将消息传递给CallNextHookEx函数,而无需进一步处理,并且应返回CallNextHookEx返回的值。此参数可以是下列值之一。(来自官网手册)return CallNextHookEx(g_keyHHook, code, wParam, lParam);}DWORD vkCode = GetKeyCode(lParam);for(auto it=g_keyCallMsgList.begin();it!=g_keyCallMsgList.end();it++){s_KeyCallMsg callMsg = *it;if(callMsg.listenWParam == 0){// 监听任何一个回调callMsg.callback(e_WParam(wParam),lParam);}else if(callMsg.listenWParam == vkCode){// 监听指定的回调callMsg.callback(e_WParam(wParam),lParam);}}// 0x0200// 将钩子往下传return CallNextHookEx( g_keyHHook, code, wParam, lParam);}/// <summary>/// 键盘回调/// </summary>/// <param name="code"></param>/// <param name="wParam"></param>/// <param name="lParam"></param>/// <returns></returns>LRESULT CALLBACK ProcForMouseBoard(int code, WPARAM wParam, LPARAM lParam) {if (code < 0 || code == HC_NOREMOVE) {// 如果代码小于零,则挂钩过程必须将消息传递给CallNextHookEx函数,而无需进一步处理,并且应返回CallNextHookEx返回的值。此参数可以是下列值之一。(来自官网手册)return CallNextHookEx(g_mouseHHook, code, wParam, lParam);}for(auto it=g_mouseCallMsgList.begin();it!=g_mouseCallMsgList.end();it++){s_MouseCallMsg callMsg = *it;if(callMsg.listenWParam == 0){// 监听任何一个回调callMsg.callback(e_WParam(wParam),lParam);}else if(callMsg.listenWParam == wParam){// 监听指定的回调callMsg.callback(e_WParam(wParam),lParam);}}// 0x0200// 将钩子往下传return CallNextHookEx( g_mouseHHook, code, wParam, lParam);}/*** @brief 设置打印函数* @param f*/void SetPrintFunction(f_print f){g_print = f;}/*** @brief 安装钩子* @return*/BOOL InstallHook(e_HookType type) {BOOL flag = FALSE;if(type==e_HookType::KEY_BOARD){// 键盘回调事件if(!g_keyIsInstall){g_keyMu.lock();// 两次判断防止出现线程安全问题if(!g_keyIsInstall){// 【参数1】钩子的类型,这里代表键盘钩子// 【参数2】钩子处理的函数// 【参数3】如果是DLL项目得写 GetModuleHandle("dll文件名"),如果应用程序,直接写 GetModuleHandle(NULL)或者nullptr都行// 【参数4】线程的ID,如果是全局钩子的话,这里要填0,如果是某个线程的钩子,那就需要写线程的IDg_keyHHook = SetWindowsHookEx(WH_KEYBOARD_LL, ProcForKeyBoard, nullptr, 0);if ( g_keyHHook == NULL) {// 钩子安装失败_PrivateLog("全局钩子注册失败");flag = FALSE;g_keyIsInstall = FALSE;}else{flag = TRUE;g_keyIsInstall = TRUE;}}g_keyMu.unlock();}}else if(type == e_HookType::MOUSE){// 鼠标回调事件if(!g_mouseIsInstall){g_mouseMu.lock();if(!g_mouseIsInstall){// 【参数1】钩子的类型,这里代表键盘钩子// 【参数2】钩子处理的函数// 【参数3】如果是DLL项目得写 GetModuleHandle("dll文件名"),如果应用程序,直接写 GetModuleHandle(NULL)或者nullptr都行// 【参数4】线程的ID,如果是全局钩子的话,这里要填0,如果是某个线程的钩子,那就需要写线程的IDg_mouseHHook = SetWindowsHookEx(WH_MOUSE_LL, ProcForMouseBoard, GetModuleHandle(NULL), 0);if ( g_mouseHHook == NULL) {// 钩子安装失败_PrivateLog("全局钩子注册失败");flag = FALSE;g_mouseIsInstall = FALSE;}else{flag = TRUE;g_mouseIsInstall = TRUE;}}g_mouseMu.unlock();}}return flag;}/*** @brief 添加新的回调函数* @param callMsg* @return*/BOOL AddKeyBoardHookCallBack(s_KeyCallMsg callMsg){BOOL flag = InstallHook(e_HookType::KEY_BOARD);if(!flag){// 安装钩子失败return FALSE;}// 安装成功g_keyCallMsgList.push_back(callMsg);return TRUE;}/*** @brief 添加新的回调函数* @param callMsg* @return*/BOOL AddMouseHookCallBack(s_MouseCallMsg callMsg){BOOL flag = InstallHook(e_HookType::MOUSE);if(!flag){// 安装钩子失败return FALSE;}// 安装成功g_mouseCallMsgList.push_back(callMsg);return TRUE;}/*** @brief 卸载钩子* @param name 钩子名称* @param type 钩子类型* @return*/BOOL UninstallHook(string name,e_HookType type) {BOOL unFlag = FALSE;switch(type){case e_HookType::KEY_BOARD:// 卸载键盘钩子g_keyMu.lock();if(g_keyIsInstall){size_t size = g_keyCallMsgList.size();if(size==1){unFlag = UnhookWindowsHookEx( g_keyHHook);if(unFlag){g_keyCallMsgList.clear();}g_keyIsInstall = unFlag ? FALSE : TRUE;}else if(size>1){// 找到要卸载的钩子的名称for(auto it=g_keyCallMsgList.begin();it!=g_keyCallMsgList.end();it++){s_KeyCallMsg callMsg = *it;if(callMsg.name == name){g_keyCallMsgList.erase(it);break;}}unFlag=TRUE;}}else{// 钩子已经被卸载unFlag = TRUE;}g_keyMu.unlock();return unFlag;case e_HookType::MOUSE:// 卸载鼠标钩子g_mouseMu.lock();if(g_mouseIsInstall){size_t size = g_mouseCallMsgList.size();if(size==1){unFlag = UnhookWindowsHookEx(g_mouseHHook);if(unFlag){g_mouseCallMsgList.clear();}g_mouseIsInstall = unFlag ? FALSE : TRUE;}else if(size>1){for(auto it=g_mouseCallMsgList.begin();it!=g_mouseCallMsgList.end();it++){s_MouseCallMsg callMsg = *it;if(callMsg.name == name){g_mouseCallMsgList.erase(it);break;}}unFlag=TRUE;}}else{// 钩子已经被卸载unFlag = TRUE;}g_mouseMu.unlock();return unFlag;default:return TRUE;}}/*** @brief 卸载所有的钩子* @param name 钩子名称* @param type 钩子类型* @return*/BOOL UninstallAllHook(e_HookType type) {BOOL unFlag = FALSE;switch(type){case e_HookType::KEY_BOARD:// 卸载键盘钩子g_keyMu.lock();if(g_keyIsInstall){unFlag = UnhookWindowsHookEx( g_keyHHook);if(unFlag){g_keyCallMsgList.clear();}g_keyIsInstall = unFlag ? FALSE : TRUE;}else{// 钩子已经被卸载unFlag = TRUE;}g_keyMu.unlock();return unFlag;case e_HookType::MOUSE:// 卸载鼠标钩子g_mouseMu.lock();if(g_mouseIsInstall){unFlag = UnhookWindowsHookEx(g_mouseHHook);if(unFlag){g_mouseCallMsgList.clear();}g_mouseIsInstall = unFlag ? FALSE : TRUE;}else{// 钩子已经被卸载unFlag = TRUE;}g_mouseMu.unlock();return unFlag;default:return TRUE;}}

QT 中使用示例

#include "mainwindow.h"#include "ui_mainwindow.h"#include "hookhelper.h"void keyEvent(e_WParam wParam, LPARAM lParam){DWORD keyCode;switch(wParam){case e_WParam::KEYUP:keyCode = GetKeyCode(lParam);qDebug()<< keyCode <<",按键松开了";break;case e_WParam::KEYDOWN:qDebug()<<"按键按下了";break;case e_WParam::SYSKEYDOWN:qDebug()<<"系统按键按下了";break;case e_WParam::SYSKEYUP:qDebug()<<"按键松开了";break;}}void mouseEvent(e_WParam wParam, LPARAM lParam){POINT p;switch(wParam){case e_WParam::LBUTTONUP:p = GetMousePoint(lParam);qDebug()<< p.x << "," << p.y<<",鼠标左键松开了";break;case e_WParam::LBUTTONDOWN:qDebug()<<"鼠标左键按下了";break;case e_WParam::RBUTTONDOWN:qDebug()<<"鼠标右键按下了";break;case e_WParam::RBUTTONUP:qDebug()<<"鼠标右键松开了";break;}}void _print(std::string str){qDebug() << "输出:"<< QString::fromLocal8Bit(str.data());}MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow){ui->setupUi(this);SetPrintFunction(_print);}MainWindow::~MainWindow(){delete ui;}void MainWindow::on_pushButton_clicked(){// 设置传送信息s_KeyCallMsg callMsg;callMsg.name = "keyCall";callMsg.callback = keyEvent;callMsg.listenWParam = 0;BOOL flag = AddKeyBoardHookCallBack(callMsg);qDebug() << "Hook结果" << flag;}void MainWindow::on_pushButton_3_clicked(){// 设置传送信息s_MouseCallMsg callMsg;callMsg.name = "mouseCall";callMsg.callback = mouseEvent;callMsg.listenWParam = 0;BOOL flag = AddMouseHookCallBack(callMsg);qDebug() << "Hook结果" << flag;}void MainWindow::on_pushButton_2_clicked(){UninstallAllHook(e_HookType::KEY_BOARD);UninstallAllHook(e_HookType::MOUSE);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。