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

12.3 实现模拟鼠标录制回放

本节将向读者介绍如何使用键盘鼠标操控模拟技术,键盘鼠标操控模拟技术是一种非常实用的技术,可以自动化执行一些重复性的任务,提高工作效率,在Windows系统下,通过使用各种键盘鼠标控制函数实现动态捕捉和模拟特定功能的操作。

有时我们经常需要进行重复性的鼠标操作,例如繁琐的点击、拖拽。这些任务可能消耗大量时间和精力,为了解决这个问题,可自行设计并实现一个简单而强大的鼠标录制回放工具,旨在帮助用户轻松录制鼠标动作,通过借助鼠标录制回放工具,用户可以轻松实现自动化操作,从而解放双手。

首先我们需要创建一个Write_File函数,当用户每次调用该函数时都会向特定的文件内追加写入一条记录,此外还需要增加一个split函数,该函数用于将特定的一条记录根据特定的分隔符切割,保留分隔符后面的坐标信息。

// 切割字符串
int split(char dst[][32], char* str, const char* spl)
{int n = 0;char* result = NULL;result = strtok(str, spl);while (result != NULL){strcpy(dst[n++], result);result = strtok(NULL, spl);}return n;
}// 每次写入一行
int Write_File(char* path, char* msg)
{FILE* fp = fopen(path, "a+");if (fp == NULL) return -1;char ch, buffer[1024];int index = 0;while (msg[index] != '\0'){fputc(msg[index], fp);index++;}fclose(fp);return 1;
}

接着我们需要实现Recording()函数部分,该函数的左右是用于捕捉当前鼠标坐标与点击事件,函数中通过调用GetCursorPos()获取当前鼠标的屏幕坐标位置,这个函数参数传递非常简单,只需要传入一个POINT类型的结构体变量,其函数原型如下所示;

BOOL GetCursorPos(LPPOINT lpPoint);

参数:

  • lpPoint:指向 POINT 结构的指针,用于接收鼠标的屏幕坐标位置。

返回值:

  • 如果函数成功,返回值为非零,表示获取鼠标位置成功;
  • 如果函数失败,返回值为零,表示获取鼠标位置失败。

POINT 结构包含了两个成员变量 xy,分别表示鼠标在屏幕上的横坐标和纵坐标。

当有了当前鼠标坐标位置以后,接着就是需要获取到鼠标点击事件,鼠标点击可使用GetAsyncKeyState 获取指定虚拟键码对应的键盘键的状态,该函数原型如下所示;

SHORT GetAsyncKeyState(int vKey);

参数:

  • vKey:指定虚拟键码,它是一个整数,表示要获取的键的键码。

返回值:

  • 如果指定的虚拟键处于按下状态,返回值的最高位(符号位)为 1,其余位表示次数(持续时间)。如果指定的虚拟键处于释放状态或者参数无效,返回值为 0。

GetAsyncKeyState 函数允许检测键盘中某个虚拟键的状态,无论这个虚拟键是否处于焦点的窗口中。它适用于各种应用,通过VK_LBUTTON可用于检测鼠标左键是否被按下,通过VK_RBUTTON则可用于检测鼠标右键状态。

代码的主要功能如下:

  1. Recording 函数中,使用一个死循环不断检测鼠标的位置和按键状态。
  2. 使用 GetCursorPos 函数获取当前鼠标的位置,并将其保存在 xy 变量中。
  3. 使用 GetAsyncKeyState 函数检测鼠标左键和右键的状态,并将其保存在 lbuttonrbutton 变量中。
  4. 如果当前的鼠标位置或按键状态与之前保存的值不同,表示鼠标动作发生了变化,将当前的位置和按键状态记录下来。
  5. 将记录的鼠标动作信息以字符串的形式写入脚本文件,格式为 “X:位置,Y:位置,L:左键状态,R:右键状态”。
  6. 保存当前的鼠标位置和按键状态,用于下一次循环时比较是否发生了变化。
// 录制脚本
void Recording(char *script)
{int static_x = 0, static_y = 0;bool static_lbutton = 0, static_rbutton = 0;while (1){POINT Position;GetCursorPos(&Position);int x = Position.x;int y = Position.y;bool lbutton = GetAsyncKeyState(VK_LBUTTON);bool rbutton = GetAsyncKeyState(VK_RBUTTON);if (x != static_x || y != static_y || lbutton != static_lbutton || rbutton != static_rbutton){char szBuf[1024] = { 0 };std::cout << "X轴 = " << x << " Y轴 = " << y << " 鼠标左键 = " << lbutton << " 鼠标右键 = " << rbutton << std::endl;sprintf(szBuf, "X:%d,Y:%d,L:%d,R:%d\n", x, y, lbutton, rbutton);Write_File((char*)script, szBuf);static_x = x;static_y = y;static_lbutton = lbutton;static_rbutton = rbutton;}}
}

接着我们继续封装Play()回放功能,该功能的实现原理与录制保持一致,通过逐条读取传入文件中的参数,并调用SetCursorPos实现鼠标位置的移动操作,该函数与获取参数传递保持一致,这里我们需要注意mouse_event函数,该函数用于模拟鼠标的各种事件,如鼠标移动、鼠标按键的点击和释放等,其函数原型如下所示;

void mouse_event(DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, ULONG_PTR dwExtraInfo);

其中dwFlags指定要模拟的鼠标事件类型和选项。可以是以下常量的组合;

  • MOUSEEVENTF_ABSOLUTE:指定鼠标位置是绝对坐标。如果不设置此标志,则坐标是相对于当前鼠标位置的增量。
  • MOUSEEVENTF_MOVE:模拟鼠标移动事件。
  • MOUSEEVENTF_LEFTDOWN:模拟鼠标左键按下事件。
  • MOUSEEVENTF_LEFTUP:模拟鼠标左键释放事件。
  • MOUSEEVENTF_RIGHTDOWN:模拟鼠标右键按下事件。
  • MOUSEEVENTF_RIGHTUP:模拟鼠标右键释放事件。

其他常量可根据需要自行查阅相关文档。

  • dx:鼠标事件发生时的横坐标(绝对坐标或增量坐标,根据 dwFlags 决定)。
  • dy:鼠标事件发生时的纵坐标(绝对坐标或增量坐标,根据 dwFlags 决定)。
  • dwData:鼠标事件的一些数据。对于滚轮事件,它表示滚动的数量。对于其他事件,通常设为 0。
  • dwExtraInfo:额外的信息。通常设为 0。

mouse_event 函数允许模拟鼠标事件,通过设置 dwFlags 参数来指定需要模拟的事件类型,设置 dxdy 参数来指定事件发生时的鼠标位置。通过调用这个函数,可以实现自动化鼠标操作,如模拟鼠标点击、拖动等。

如下代码段实现了鼠标动作脚本的回放功能,它从之前录制保存的脚本文件中读取鼠标动作信息,并按照脚本中记录的顺序模拟鼠标动作,实现鼠标动作的回放。

代码的主要功能如下:

  1. Play 函数中,打开之前保存的脚本文件,并使用 fgets 函数每次读取一行数据,保存在 buf 字符数组中。
  2. 使用 split 函数切割每行数据,将每行数据切割成以逗号分隔的四个字符串,并将这四个字符串转换为整数类型保存在 key_item 数组中。
  3. 根据 key_item 数组中的数据,判断是否需要进行鼠标点击动作,并调用 mouse_event 函数模拟鼠标点击。
  4. 调用 SetCursorPos 函数设置鼠标的位置,并使用 Sleep 函数模拟鼠标移动的延时,实现鼠标动作的回放。
  5. 循环执行以上步骤,直到脚本文件中的所有动作都被回放完毕。
// 回放脚本
void Play(char *script)
{FILE* fp = fopen(script, "r");char buf[1024];while (feof(fp) == 0){// 每次读入一行memset(buf, 0, 1024);fgets(buf, 1024, fp);// 以逗号切割char split_comma[4][32] = { 0 };int comma_count = split(split_comma, buf, ",");int key_item[4] = { 0 };// std::cout << "长度: " << comma_count << std::endl;for (int x = 0; x < comma_count; x++){// 继续切割冒号char split_colon[2][32] = { 0 };split(split_colon, split_comma[x], ":");// std::cout << "字典键 = " << split_colon[0] << " 字典值 = " << split_colon[1] << std::endl;key_item[x] = atoi(split_colon[1]);}if (key_item[3] != 0){mouse_event(MOUSEEVENTF_LEFTUP | MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);}if (key_item[4] != 0){mouse_event(MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);}// 得到数据后开始回放SetCursorPos(key_item[0], key_item[1]);Sleep(70);}
}

最后是主函数部分,我们通过RegisterHotKey函数注册两个全局热键,通过F1实现鼠标录制部分,通过F2则实现鼠标回放,最后通过GetMessage函数接收全局消息事件,当出现WM_HOTKEY消息则依次判断是否启用录制回放等功能,代码如下所示;

int main(int argc, char* argv[])
{// 注册热键 F1 , F2if (0 == RegisterHotKey(NULL, 1,0, VK_F1)){cout << GetLastError() << endl;}if (0 == RegisterHotKey(NULL, 2,0, VK_F2)){cout << GetLastError() << endl;}if (0 == RegisterHotKey(NULL, 3, 0, VK_F3)){cout << GetLastError() << endl;}// 消息循环MSG msg = { 0 };while (GetMessage(&msg, NULL, 0, 0)){switch (msg.message){case WM_HOTKEY:{if (1 == msg.wParam){std::cout << "录制脚本" << std::endl;Recording((char *)"d://script.txt");}else if (2 == msg.wParam){std::cout << "回放脚本" << std::endl;Play((char *)"d://script.txt");}else if (3 == msg.wParam){exit(0);return 0;}break;}default:break;}}return 0;
}

读者可自行编译并运行这段代码,通过录制一段鼠标功能并回放,输出效果图如下所示;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/d3a88993.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章:

12.3 实现模拟鼠标录制回放

本节将向读者介绍如何使用键盘鼠标操控模拟技术&#xff0c;键盘鼠标操控模拟技术是一种非常实用的技术&#xff0c;可以自动化执行一些重复性的任务&#xff0c;提高工作效率&#xff0c;在Windows系统下&#xff0c;通过使用各种键盘鼠标控制函数实现动态捕捉和模拟特定功能的…...

【计算机网络-自顶向下方法】应用层(SMTP、POP3、DNS)

目录 1. Electronic Mail电子邮件应用画像1.1 电子邮件系统1.2 邮件报文格式1.3 邮件访问 2. DNS&#xff08;Domain Name System&#xff09;2.1 DNS提供的服务2.2 DNS工作机理2.3 DNS资源记录2.4 DNS协议&#xff0c;报文2.5 小结 1. Electronic Mail 电子邮件应用画像 应用…...

【Pm4py第八讲】关于Statistics

本节用于介绍pm4py中的统计函数&#xff0c;包括统计轨迹变体、案例持续时间、案例到达时间等。 1.函数概述 本次主要介绍Pm4py中一些常见的统计函数&#xff0c;总览如下表&#xff1a; 函数名说明pm4py.stats.get_start_activities()从事件日志中获取开始活动。pm4py.stats.…...

【Azure 架构师学习笔记】-Azure Data Factory (5) --Data Flow

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Data Factory】系列。 接上文【Azure 架构师学习笔记】-Azure Data Factory (4)-触发器详解-事件触发器 前言 Azure Data Factory&#xff0c; ADF 是微软Azure 的ETL 首选服务之一&#xff0c; 是Azure data platfor…...

uniapp之ios开发及支付整体流程爬坑记录

前言 在写这篇记录的时候&#xff0c;关于ios的支付已经对接的差不多了&#xff0c;下一步就是测试好了直接发版&#xff0c;总共花了好几周的时间&#xff0c;从0到1对于首次做ios支付来说&#xff0c;确实很多坑。 其实业务层面很简单&#xff0c;甚至比安卓支付还简单&…...

AutoDL百川大模型体验

文章目录 镜像克隆模型下载测试效果AutoDL自定义服务 感谢AutoDL和CodeWithGPU这两个平台&#xff0c;让我们能低成本&#xff0c;低门槛地部署体验这些大模型 镜像克隆 我是在CodeWithGPU上克隆的这个镜像 模型下载 codewithgpu有介绍 注意这三个文件都需要下载 把那个&quo…...

蓝桥杯每日一题2023.10.8

题目描述 七段码 - 蓝桥云课 (lanqiao.cn) 题目分析 所有的情况我们可以分析出来一共有2的7次方-1种&#xff0c;因为每一个二极管都有选择和不选择两种情况&#xff0c;有7个二极管&#xff0c;但是还有一种都不选的情况需要排除&#xff0c;故-1 枚举每个方案看是否符合要…...

jmeter,性能测试,Locust

一。性能测试的概念 1.性能&#xff1a;就是软件质量属性中的 “ 效率 ” 特性 2.效率特性&#xff1a; 时间特性&#xff1a;指系统处理用户请求的响应时间 资源特性&#xff1a;指系统在运行过程中&#xff0c;系统资源的消耗情况 CPU 内存 磁盘IO&#xff08;磁盘的写…...

opencv图像的直方图,二维直方图,直方图均衡化

文章目录 opencv图像的直方图&#xff0c;二维直方图&#xff0c;直方图均衡化一、图像的直方图1、什么是图像的直方图&#xff1a;2、直方图的作用&#xff1a;3、如何绘制图像的直方图&#xff1a;&#xff08;1&#xff09;cv::calcHist()函数原型&#xff1a;英文单词 calc…...

c++中的map和set

文章目录 1. 关联式容器2. 键值对3. 树形结构的关联式容器3.1 set3.1.1 set的介绍3.1.2 set的使用 3.2 map3.2.1 map的介绍3.2.2 map的使用 3.3 multiset3.3.1 multiset的介绍3.3.2 multiset的使用 3.4 multimap3.4.1 multimap的介绍3.4.2 multimap的使用 1. 关联式容器 在初阶…...

Swagger使用详解

目录 一、简介 二、SwaggerTest项目搭建 1. pom.xml 2. entity类 3. controller层 三、基本使用 1. 导入相关依赖 2. 编写配置文件 2.1 配置基本信息 2.2 配置接口信息 2.3 配置分组信息 2.3.1 分组名修改 2.3.2 设置多个分组 四、常用注解使用 1. ApiModel 2.A…...

ToBeWritten之车联网安全中常见的TOP 10漏洞

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…...

软考-密码学概述

本文为作者学习文章&#xff0c;按作者习惯写成&#xff0c;如有错误或需要追加内容请留言&#xff08;不喜勿喷&#xff09; 本文为追加文章&#xff0c;后期慢慢追加 by 2023年10月 密码学基本概念 密码学的主要目的是保持明文的秘密以防止攻击者获知&#xff0c;而密码分…...

windows 2003、2008远程直接关闭远程后设置自动注销会话

1、2003系统&#xff1a; 按开始—运行—输入“tscc.msc”&#xff0c;打开“终端服务配置”。 单击左边窗口的“连接”项&#xff0c;右边窗口中右击“RDP-TCP”&#xff0c;选择“属性”。 单击“会话”项&#xff0c;勾选“替代用户设置”&#xff0c;在“结束已断开的会话”…...

iOS BUG UIView转UIImage模糊失真

iOS BUG UIView转UIImage模糊失真 ##UIView转成Image - (UIImage *)capture {UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);[self.layer renderInContext:UIGraphicsGetCurrentContext()];UIImage *img UIGraphicsGetImageFromCurrentImageContext(…...

如何在10分钟内让Android应用大小减少 60%?

一个APP的包之所以大&#xff0c;主要包括一下文件 代码libso本地库资源文件&#xff08;图片&#xff0c;音频&#xff0c;字体等&#xff09; 瘦身就主要瘦这些。 一、打包的時候刪除不用的代码 buildTypes {debug {...shrinkResources true // 是否去除无效的资源文件(如…...

网络代理技术:保障隐私与增强安全

在当今数字化的世界中&#xff0c;网络代理技术的重要性日益凸显。无论您是普通用户还是网络工程师&#xff0c;了解如何使用代理技术来保护隐私和增强网络安全都是至关重要的。本文将深入探讨Socks5代理、IP代理以及它们在网络安全和隐私保护中的关键作用。 1. Socks5代理&am…...

数据结构 | (二) List

什么是 List 在集合框架中&#xff0c; List 是一个接口&#xff0c;继承自 Collection 。 Collection 也是一个接口 &#xff0c;该接口中规范了后序容器中常用的一些方法&#xff0c;具体如下所示&#xff1a; Iterable 也是一个接口&#xff0c;表示实现该接口的类是可以逐个…...

[NewStarCTF 2023 公开赛道] week1 Crypto

brainfuck 题目描述&#xff1a; [>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<-]>>>>>>>.>----.<-----.>-----.>-----.<<<-.>>..…...

C语言中文网 - Shell脚本 - 0

教程目录如下&#xff1a; 第1章 Shell基础&#xff08;开胃菜&#xff09; 1. Shell是什么&#xff1f;1分钟理解Shell的概念&#xff01; 2. Shell是运维人员必须掌握的技能 3. 常用的Shell有哪些&#xff1f; 4. 进入Shell的两种方式 5. Linux Shell命令的基本格式 6.…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

VisualXML全新升级 | 新增数据库编辑功能

VisualXML是一个功能强大的网络总线设计工具&#xff0c;专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑&#xff08;如DBC、LDF、ARXML、HEX等&#xff09;&#xff0c;并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...