简介

  • 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);
}

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

  1. 综合设计一个OPPE主页--页面的插件引用(animate.css)--d动画的使用--滚轮或鼠标到该位置时,才有动画的切换---所以我们需要用jquery监听鼠标滚轮的滚动事件

    Animate.css | A cross-browser library of CSS animations. 里面有许多css的效果 首先使用 animate.css文件 link rel=&qu ...

  2. java 监听鼠标点击_java 事件监听 - 鼠标

    java 事件监听 - 鼠标 //事件监听 //鼠标事件监听 //鼠标事件监听有两个实现接口 //1.MouseListener 普通的鼠标操作 //2.MouseMotionListener 鼠标的 ...

  3. css 鼠标滚动事件,js监听鼠标的滚轮滚动事件教程

    不同的有不同的滚轮事件.主要是有两种,onmousewheel(firefox不支持)和dommousescroll(只有firefox支持),关于这两个事件这里不做详述,想要了解的朋友请移步:鼠标滚 ...

  4. esc键退出全屏 vue_解决了VUE在浏览器全屏下监听不到Esc键盘事件

    说明: 实测可以在谷歌.火狐.360 浏览器使用 解决了在浏览器全屏下监听不到键盘Esc事件 解决了取消全屏和全屏的同步问题,ESC按键下可以同步 以下是完整的代码, // data() { retu ...

  5. 解决VUE在浏览器全屏下监听不到Esc键盘事件

    实测可以在谷歌.火狐.360 浏览器使用 解决了在浏览器全屏下监听不到键盘Esc事件 解决了取消全屏和全屏的同步问题,ESC按键下可以同步 以下是完整的代码, // data() {return {i ...

  6. vuejs监听苹果iphone手机键盘事件

    在iphone手机中,vue提供的keyup事件是不能监听iphone键盘的,但是h5提供的input事件可以做到. 只需要向下面这样处理,就可以解决iphone不响应键盘事件的bug <tem ...

  7. 鼠标移入事件_NSTrackingArea 监听鼠标移入与移出事件

    在NSView中: var area:NSTrackingArea! override func updateTrackingAreas() {if area != nil {self.removeT ...

  8. python pyhook监听扫码_Python——pyHook监听鼠标键盘事件

    pyHook包为Windows中的全局鼠标和键盘事件提供回调. 底层C库报告的信息包括事件的时间,事件发生的窗口名称,事件的值,任何键盘修饰符等. 而正常工作需要pythoncom等操作系统的API的 ...

  9. python监听鼠标事件_Python中使用PyHook监听鼠标和键盘事件实例

    Python 中使用 PyHook 监听鼠标和键盘事件实例 PyHook 是一个基于 Python 的"钩子"库,主要用于监 听当前电脑上鼠标和键盘的事件.这个库依赖于另一个 Py ...

  10. python获取键盘事件_50-用Python监听鼠标和键盘事件

    PyHook是一个基于Python的"钩子"库,主要用于监听当前电脑上鼠标和键盘的事件.这个库依赖于另一个Python库PyWin32,如同名字所显示的,PyWin32只能运行在W ...

最新文章

  1. 查看当前正在运行的python进程
  2. 如何优化linux服务器,手把手教你如何优化linux服务器
  3. php神盾 var 1.54,PHP变量可用字符 - 神盾加密解密教程(一)
  4. MVC4做网站后台:栏目管理1、添加栏目
  5. ubuntu安装node.js
  6. Apollo之灰度发布
  7. 设计模式:依赖倒置原则
  8. bzoj2242 [SDOI2011]计算器 exgcd+ksm+bsgs
  9. php5d,php挖洞基础知识篇以及防范方法
  10. Python:hashlib加密,flask模块写接口
  11. 位置度标注方法图解_追踪主力-散户操盘实战图解:操盘手法分析
  12. 浩哥带你学习JDK1.1源码——第1天
  13. 认识网络通信中的 ACK、NACK 和 REX
  14. 2007年五一通过了驾驶证考试(5/7,5/8)
  15. 仓库实现降本增效的秘密法宝,WMS智能仓储系统
  16. c++虚函数实现原理
  17. Java中合理使用局部变量替代成员变量、静态变量
  18. 2022年各大高校最新博士薪资汇总~
  19. 滤波电容为什么要靠近放置,储能电容为什么均匀放置?去耦半径是什么?滤波电容如何打孔?
  20. Azure Kinect DK 基本开发流程

热门文章

  1. c语言中局部变量存放在哪里,C语言全局变量存放在哪里?
  2. 超好用的后台管理的框架
  3. 《未来世界的幸存者-阮一峰》系列分享专栏
  4. MAX30102脉搏血氧仪和心率传感器(一)驱动程序
  5. 企业erp管理软件价格
  6. 基于FPGA的VGA显示,简单的历程和注释(DE2-115)
  7. HCDA学习笔记(二)
  8. 分享一个千万数据的磁力搜索网站 bt书虫 php+mysql+nginx
  9. 搜索引擎这样用才有效率
  10. 四川师范大学地信概论(3- 空间数据模型)90分以上版本