当前位置: 首页 > 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;导致表经历过大量的…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...