当前位置: 首页 > news >正文

【小沐学C++】C++ 实现鼠标键盘钩子HOOK

文章目录

  • 1、简介
  • 2、相关函数
    • 2.1 SetWindowsHookEx
    • 2.2 UnhookWindowsHookEx
    • 2.3 CallNextHookEx
  • 3、相关结构体
    • 3.1 KBDLLHOOKSTRUCT
    • 3.2 MSLLHOOKSTRUCT
  • 4、挂钩过程
  • 5、代码测试
    • 5.1 代码1
  • 结语

1、简介

https://learn.microsoft.com/zh-cn/windows/win32/winmsg/about-hooks

挂钩是应用程序截获消息、鼠标操作和击键等事件的机制。 截获特定类型的事件的函数称为 挂钩过程。 挂钩过程可以对其接收的每个事件执行操作,然后修改或放弃该事件。
在这里插入图片描述

挂钩是系统消息处理机制中的一个点,其中应用程序可以安装子例程来监视系统中的消息流量,并在某些类型的消息到达目标窗口过程之前对其进行处理。
在这里插入图片描述

以下一些示例使用 挂钩:

  • 监视用于调试的消息
  • 支持录制和播放宏
  • 为帮助密钥 (F1) 提供支持
  • 模拟鼠标和键盘输入
  • 实现基于计算机的训练 (CBT) 应用程序

在这里插入图片描述

2、相关函数

2.1 SetWindowsHookEx

将应用程序定义的挂钩过程安装到挂钩链中。 你将安装挂钩过程来监视系统的某些类型的事件。 这些事件与特定线程或与调用线程位于同一桌面中的所有线程相关联。

HHOOK SetWindowsHookExA([in] int       idHook,[in] HOOKPROC  lpfn,[in] HINSTANCE hmod,[in] DWORD     dwThreadId
);HHOOK SetWindowsHookExW([in] int       idHook,[in] HOOKPROC  lpfn,[in] HINSTANCE hmod,[in] DWORD     dwThreadId
);
  • WH_KEYBOARD
    安装用于监视击键消息的挂钩过程。 有关详细信息,请参阅 KeyboardProc 挂钩过程。
LRESULT CALLBACK KeyboardProc(_In_ int    code,_In_ WPARAM wParam,_In_ LPARAM lParam
);
  • WH_KEYBOARD_LL
    安装用于监视低级别键盘输入事件的挂钩过程。 有关详细信息,请参阅 [LowLevelKeyboardProc] (/windows/win32/winmsg/lowlevelkeyboardproc) 挂钩过程。
LRESULT CALLBACK LowLevelKeyboardProc(_In_ int    nCode,_In_ WPARAM wParam,_In_ LPARAM lParam
);
// 其中lParam指向 KBDLLHOOKSTRUCT 结构的指针。
  • WH_MOUSE
    安装监视鼠标消息的挂钩过程。 有关详细信息,请参阅 MouseProc 挂钩过程。
LRESULT CALLBACK MouseProc(_In_ int    nCode,_In_ WPARAM wParam,_In_ LPARAM lParam
);
  • WH_MOUSE_LL
    安装用于监视低级别鼠标输入事件的挂钩过程。 有关详细信息,请参阅 LowLevelMouseProc 挂钩过程。
LRESULT CALLBACK LowLevelMouseProc(_In_ int    nCode,_In_ WPARAM wParam,_In_ LPARAM lParam
);
// 其中lParam指向 MSLLHOOKSTRUCT 结构的指针。

2.2 UnhookWindowsHookEx

删除 SetWindowsHookEx 函数安装在挂钩链中的挂钩过程。

BOOL UnhookWindowsHookEx([in] HHOOK hhk
);

2.3 CallNextHookEx

将挂钩信息传递给当前挂钩链中的下一个挂钩过程。 挂钩过程可以在处理挂钩信息之前或之后调用此函数。

LRESULT CallNextHookEx([in, optional] HHOOK  hhk,[in]           int    nCode,[in]           WPARAM wParam,[in]           LPARAM lParam
);

3、相关结构体

3.1 KBDLLHOOKSTRUCT

包含有关低级别键盘输入事件的信息。

typedef struct tagKBDLLHOOKSTRUCT {DWORD     vkCode;DWORD     scanCode;DWORD     flags;DWORD     time;ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

3.2 MSLLHOOKSTRUCT

包含有关低级别鼠标输入事件的信息。

typedef struct tagMSLLHOOKSTRUCT {POINT     pt;DWORD     mouseData;DWORD     flags;DWORD     time;ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;

4、挂钩过程

  • 定义挂钩过程
    为了利用特定类型的挂钩,开发人员提供了一个挂钩过程,并使用 SetWindowsHookEx 函数将其安装到与挂钩关联的链中。 挂钩过程必须具有以下语法:
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam
)
{// process event...return CallNextHookEx(NULL, nCode, wParam, lParam);
}

SetWindowsHookEx 函数始终在挂钩链的开头安装挂钩过程。 当发生由特定类型的挂钩监视的事件时,系统会在与挂钩关联的挂钩链的开头调用过程。 链中的每个挂钩过程确定是否将事件传递给下一个过程。 挂钩过程通过调用 CallNextHookEx 函数将事件传递给下一过程。

  • 安装和释放挂钩过程
    SetWindowsHookEx 传递模块句柄、指向挂钩过程入口点的指针,以及线程标识符的 0,指示挂钩过程应与调用线程位于同一桌面中的所有线程相关联。 以下示例中显示了此序列。
HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL; 
static HHOOK hhookSysMsg; hinstDLL = LoadLibrary(TEXT("c:\\myapp\\sysmsg.dll")); 
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc"); hhookSysMsg = SetWindowsHookEx( WH_SYSMSGFILTER,hkprcSysMsg,hinstDLL,0);

可以通过调用 UnhookWindowsHookEx 函数来释放特定于线程的挂钩过程, (从挂钩链) 中删除其地址,并指定要释放的挂钩过程的句柄。 一旦应用程序不再需要挂钩过程,就立即释放它。

5、代码测试

5.1 代码1


#include "pch.h"
#include <Windows.h>
#include <iostream>std::string get_time()
{SYSTEMTIME sys;GetLocalTime(&sys);char time[255] = { 0 };sprintf_s(time, "[%4d/%02d/%02d %02d:%02d:%02d]", sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond);return std::string(time);
}LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{/*typedef struct tagKBDLLHOOKSTRUCT {DWORD     vkCode;		// 按键代号DWORD     scanCode;		// 硬件扫描代号,同 vkCode 也可以作为按键的代号。DWORD     flags;		// 事件类型,一般按键按下为 0 抬起为 128。DWORD     time;			// 消息时间戳ULONG_PTR dwExtraInfo;	// 消息附加信息,一般为 0。}KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT;*/KBDLLHOOKSTRUCT* ks = (KBDLLHOOKSTRUCT*)lParam;		// 包含低级键盘输入事件信息char buffer[255];DWORD code = ks->vkCode;std::string t = get_time();char state[20];if (wParam == WM_KEYDOWN){strcpy_s(state, "按下");}else if (wParam == WM_KEYUP){strcpy_s(state, "抬起");}sprintf_s(buffer, "[键盘]%s 键代码:%d %s", t.c_str(), code, state);std::cout << buffer << std::endl;//return 1;	// 拦截消息return CallNextHookEx(NULL, nCode, wParam, lParam);
}LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{/*typedef struct tagMOUSEHOOKSTRUCT {POINT   pt;					// Point数据HWND    hwnd;				// 接收鼠标消息的窗体的句柄UINT    wHitTestCode;		// 指定点击测试值ULONG_PTR dwExtraInfo;		// 指定和该消息相关联的附加信息。} MOUSEHOOKSTRUCT, FAR* LPMOUSEHOOKSTRUCT, * PMOUSEHOOKSTRUCT;*/MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;POINT pt = ms->pt;std::string time = get_time();char buffer[1024];char state[20] = "未知";if (wParam == WM_LBUTTONDOWN){strcpy_s(state, "左键按下");}else if (wParam == WM_LBUTTONUP){strcpy_s(state, "左键抬起");}else if (wParam == WM_RBUTTONDOWN){strcpy_s(state, "右键按下");}else if (wParam == WM_RBUTTONUP){strcpy_s(state, "右键抬起");}else if (wParam == WM_MOUSEMOVE){strcpy_s(state, "移动");}sprintf_s(buffer, "[鼠标]%s 键代码:x:%d y:%d %s", time.c_str(), pt.x, pt.y, state);std::cout << buffer << std::endl;//return 1;	// 拦截消息return CallNextHookEx(NULL, nCode, wParam, lParam);}int main()
{HINSTANCE hM = GetModuleHandle(NULL), hK = GetModuleHandle(NULL);HHOOK g_Hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, hK, 0);HHOOK g_Hook2 = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, hM, 0);// 消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}UnhookWindowsHookEx(g_Hook);return 0;
}

在这里插入图片描述

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

相关文章:

【小沐学C++】C++ 实现鼠标键盘钩子HOOK

文章目录 1、简介2、相关函数2.1 SetWindowsHookEx2.2 UnhookWindowsHookEx2.3 CallNextHookEx 3、相关结构体3.1 KBDLLHOOKSTRUCT3.2 MSLLHOOKSTRUCT 4、挂钩过程5、代码测试5.1 代码1 结语 1、简介 https://learn.microsoft.com/zh-cn/windows/win32/winmsg/about-hooks 挂…...

【pycharm】常见问题与解决

记录一些Pycharm中经常遇到的问题 1. “Open file or Project” always in loading state (hang) a) 老版本 (2021年左右) since build 211.6693.14, it is possible to use a native file chooser on Windows. The feature is experimental; to enable it, add the followi…...

flask web学习之表单(一)

文章目录 一、使用Flask-WTF处理表单1.1 安装Flask-WTF库1.2 定义WTForms表单类常用的WTForm字段实例化字段类常用参数常用的WTForm验证器 1.3 输出HTML代码使用render_kw属性在调用字段时传入 1.4 在模板中渲染表单 在web程序中&#xff0c;表单是用户交互最常见的方式之一。用…...

@ControllerAdvice 使用场景

ControllerAdvice 是Spring 框架中的注解&#xff0c;多用在Spring MVC应用程序中。 使用场景1&#xff1a;处理异常 # 示例1 import org.apache.ibatis.javassist.NotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.Respons…...

二极管选型怎么选?常用参数要熟练~

同学们大家好&#xff0c;今天我们继续学习杨欣的《电子设计从零开始》&#xff0c;这本书从基本原理出发&#xff0c;知识点遍及无线电通讯、仪器设计、三极管电路、集成电路、传感器、数字电路基础、单片机及应用实例&#xff0c;可以说是全面系统地介绍了电子设计所需的知识…...

【小白专用】C#关于角色权限系统

&#xff08;C#&#xff09;用户、角色、权限 https://www.cnblogs.com/huangwen/articles/638050.html 权限管理系统——数据库的设计&#xff08;一&#xff09; https://www.cnblogs.com/cmsdn/p/3371576.html 权限管理系统——菜单模块的实现&#xff08;二&#xff09; …...

代码随想录算法训练营

一刷打卡记录&#xff1a; 日期打卡2023/10/25 day01二分查找有点转不过弯&#xff0c;快慢指针能理解&#xff0c;自己写也可能写不出来&#xff0c;但是能记住了&#xff0c;能看懂&#xff0c;还有其他解法待补充看完&#xff0c;花了挺长时间的2023/10/26 day02还好&#…...

统计学-R语言-3

文章目录 前言给直方图增加正态曲线的不恰当之处直方图与条形图的区别核密度图时间序列图洛伦茨曲线计算绘制洛伦茨曲线所需的各百分比数值绘制洛伦茨曲线 练习 前言 本篇文章是介绍对数据的部分图形可视化的图型展现。 给直方图增加正态曲线的不恰当之处 需要注意的是&#…...

spring动态控制定时任务

在spring框架中&#xff0c;对于简单的定时任务&#xff0c;可以使用 Scheduled 注解实现&#xff0c;在实际项目中&#xff0c;经常需要动态的控制定时任务&#xff0c;比如通过接口增加、启动、停止、删除定时任务&#xff0c;动态的改变定时任务的执行时间等。 我们可以通过…...

3. Mybatis 中SQL 执行原理

2. Mybatis 中SQL 执行原理 这里有两种方式&#xff0c;一种为常用的 Spring 依赖注入 Mapper 的方式。另一种为直接使用 SqlSessionTemplate 执行 Sql 的方式。 Spring 依赖注入 Mapper 的方式 Mapper 接口注入 SpringIOC 容器 Spring 容器在扫描 BeanDefinition 阶段会扫…...

第一次在RUST官方论坛上留言发布我的Rust板箱

第一次在RUST官方论坛上发帖子&#xff0c;有点紧张~地址在这里&#xff1a; 【My Rust Crate】obtains linux local information - The Rust Programming Language Forum (rust-lang.org)...

LabVIEW 智能化矿用定向钻机液压系统监测

简介 在矿用定向钻机的液压系统监测中&#xff0c;实现实时监控和异常预警对于保障设备运行的稳定性至关重要。传统的人工监测方法效率低下而且准确性不能满足要求&#xff0c;针对这种情况采用 LabVIEW 开发平台&#xff0c;设计并实现了一套智能化矿用定向钻机液压系统的状态…...

GO数据库操作

Golang 出色的 ORM 库为 GORM。 官网文档&#xff1a;https://gorm.io/docs/ 我们来说说增删改查的用法&#xff0c;更深入的研究可以去官网看看。 GORM功能概览&#xff1a; 关联&#xff08;有一个、有多个、属于、多对多、多态性、单表继承&#xff09;挂钩&#xff08;创…...

PyTorch简单理解ChannelShuffle与数据并行技术解析

目录 torch.nn子模块详解 nn.ChannelShuffle 用法与用途 使用技巧 注意事项 参数 示例代码 nn.DataParallel 用法与用途 使用技巧 注意事项 参数 示例 nn.parallel.DistributedDataParallel 用法与用途 使用技巧 注意事项 参数 示例 总结 torch.nn子模块详…...

MySQL 8查询语句之查询所有字段、特定字段、去除重复字段、Where判断条件

《MySQL 8创建数据库、数据表、插入数据并且查询数据》里边有我使用到的数据。 再使用下方的语句补充一些数据&#xff1a; insert into Bookbought.bookuser(id,username,userphone,userage,sex,userpassword) values (11,Book Break,22245678911,18,male,good#111); insert…...

LLaMA-Factory添加adalora

感谢https://github.com/tsingcoo/LLaMA-Efficient-Tuning/commit/f3a532f56b4aa7d4200f24d93fade4b2c9042736和https://github.com/huggingface/peft/issues/432的帮助。 在LLaMA-Factory中添加adalora 1. 修改src/llmtuner/hparams/finetuning_args.py代码 在FinetuningArg…...

多端多用户万能DIY商城系统源码:自营+多商户入驻商城系统 独立部署 带完整的安装代码包以及搭建教程

电子商务行业日新月异&#xff0c;许多企业希望能够通过线上商城拓展业务。但是&#xff0c;传统商城系统往往无法满足多样化、个性化的需求&#xff0c;而且开发周期长、成本高。罗峰就来给大家分享一款多端多用户万能DIY商城系统源码&#xff0c;搭建简单。 以下是部分代码示…...

Qt 6之七:学习资源

Qt 6之七&#xff1a;学习资源 Qt是一种跨平台的C应用程序开发框架&#xff0c;它提供了一套丰富的工具和库&#xff0c;可以帮助开发者快速构建跨平台的应用程序&#xff0c;用于开发图形用户界面&#xff08;GUI&#xff09;和非GUI应用程序。 Qt 6之一&#xff1a;简介、安…...

解决大模型的幻觉问题:一种全新的视角

在人工智能领域&#xff0c;大模型已经成为了一个重要的研究方向。然而&#xff0c;随着模型规模的不断扩大&#xff0c;一种新的问题开始浮出水面&#xff0c;那就是“幻觉”问题。这种问题的出现&#xff0c;不仅影响了模型的性能&#xff0c;也对人工智能的发展带来了新的挑…...

mysql进阶-重构表

目录 1. 原因 2. 如何重构表呢&#xff1f; 2.1 命令1&#xff1a; 2.2 命令2&#xff1a; 2.3 命令3&#xff1a; 1. 原因 正常的业务开发&#xff0c;为什么需要重构表呢&#xff1f; 原因1&#xff1a;某张表存在大量的新增和删除操作&#xff0c;导致表经历过大量的…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...