当前位置: 首页 > 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.…...

STM32F1/F4外部SRAM(IS62WV51216)FSMC配置避坑指南:从硬件连接到时序计算

STM32F1/F4外部SRAM&#xff08;IS62WV51216&#xff09;FSMC配置避坑指南&#xff1a;从硬件连接到时序计算 在嵌入式系统开发中&#xff0c;当STM32的内部SRAM容量不足以满足需求时&#xff0c;扩展外部SRAM成为提升系统性能的有效方案。IS62WV51216作为一款常见的16位宽512K…...

构建多模型对比评测工具时集成Taotoken的统一接口

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 构建多模型对比评测工具时集成Taotoken的统一接口 在模型选型、效果验证或学术研究过程中&#xff0c;开发者或研究者常常需要并行…...

技术团队的“1对1沟通”:别等员工提离职了才聊真心话

在软件测试领域&#xff0c;我们习惯于用脚本验证系统的稳定性&#xff0c;用压测工具探测性能的边界&#xff0c;却常常忽略了对团队中最重要的“系统”——人——进行定期的健康检查。许多技术管理者&#xff0c;尤其是从资深测试工程师晋升上来的团队负责人&#xff0c;往往…...

大厂光环褪去后,技术人该如何评估一份工作的价值?

当“进入大厂”不再是职业发展的唯一解&#xff0c;当“稳定”成为一种奢求&#xff0c;软件测试从业者需要一套更内核的价值评估体系。这套体系不应依赖于公司的名头或短期的薪资涨幅&#xff0c;而应聚焦于那些能够被你带走、并持续产生复利的核心资产。我们可以从以下四个维…...

跨境直播里,为什么很多团队设备很强,画面却依旧不稳定?

做跨境直播的人&#xff0c;基本都会经历一个阶段&#xff1a;疯狂升级设备。更贵的相机更强的显卡更高规格的采集卡更多灯光但实际开播后&#xff1a;直播依旧掉帧OBS 占用异常推流延迟增加画面偶发模糊音视频不同步很多时候&#xff0c;问题并不是设备性能不够。而是&#xf…...

3分钟搞定Word参考文献:APA第7版免费安装终极指南

3分钟搞定Word参考文献&#xff1a;APA第7版免费安装终极指南 【免费下载链接】APA-7th-Edition Microsoft Word XSD for generating APA 7th edition references 项目地址: https://gitcode.com/gh_mirrors/ap/APA-7th-Edition 还在为学术论文的APA格式烦恼吗&#xff…...

5G FR1与FR2频段下,SSB的Kssb子载波偏移配置实战与避坑指南

5G FR1与FR2频段下SSB的Kssb子载波偏移配置实战与避坑指南 在5G网络部署中&#xff0c;同步信号块&#xff08;SSB&#xff09;的配置直接关系到终端设备能否成功接入网络。其中&#xff0c;Kssb子载波偏移参数在不同频段&#xff08;FR1与FR2&#xff09;下的取值范围和单位存…...

从“能用”到“可靠”:基于SonarQube与Jenkins的Java代码质量防线构建实战

当测试覆盖率不再只是一串数字&#xff0c;而是合并代码前的“一票否决权” 1. 为什么你的“质量门禁”只是个摆设&#xff1f; 在很多团队的CI/CD流水线中&#xff0c;SonarQube的集成往往停留在“能跑就行”的阶段。流水线里确实有代码扫描这一步&#xff0c;日志里也打印出…...

Armv8/v9架构中的A64系统指令与预测限制机制详解

1. A64系统指令概述在Armv8/v9架构中&#xff0c;A64系统指令(System Instructions)是处理器特权级别操作的核心机制。这些指令运行在EL1及以上异常级别&#xff0c;用于控制系统寄存器、内存管理单元、虚拟化扩展和安全状态等关键功能。与常规数据处理指令不同&#xff0c;系统…...

别再搞混了!Web地图开发必懂的EPSG:4326和EPSG:3857(附JavaScript转换代码)

Web地图开发中的坐标系解密&#xff1a;从原理到实战 第一次在Leaflet地图上叠加GPS轨迹数据时&#xff0c;我盯着那个偏离了三条街的路径百思不得其解——经纬度坐标明明正确&#xff0c;为什么显示位置完全不对&#xff1f;这个困扰无数Web开发者的经典问题&#xff0c;根源在…...