AutoHotkey鼠标轨迹记录工具:实现精确操作回放

AutoHotkey鼠标轨迹记录工具:实现精确操作回放

【免费下载链接】AutoHotkey 【免费下载链接】AutoHotkey 项目地址: https://gitcode.com/gh_mirrors/autohotke/AutoHotkey

在日常办公和游戏中,你是否遇到过需要重复执行一系列精确鼠标操作的场景?比如复杂的软件测试步骤、重复性的图像处理任务,或者游戏中的连招释放。手动操作不仅耗时易错,还可能因疲劳导致精度下降。本文将介绍如何使用AutoHotkey(AHK)构建一个鼠标轨迹记录工具,轻松实现鼠标操作的录制与回放,让你的工作流程自动化、精准化。

读完本文后,你将能够:

  • 理解鼠标轨迹记录的基本原理
  • 使用AutoHotkey编写简单的轨迹记录与回放脚本
  • 掌握轨迹数据的存储与读取方法
  • 优化回放精度和流畅度

工具原理与核心组件

鼠标轨迹记录本质上是通过定期捕获鼠标位置坐标,并在回放时按顺序复现这些坐标点。AutoHotkey提供了丰富的鼠标操作函数,使得实现这一功能变得简单高效。

核心函数解析

AutoHotkey的鼠标操作主要依赖于source/keyboard_mouse.cpp中实现的函数:

  • MouseGetPos:获取当前鼠标位置坐标
  • SendInput:发送鼠标移动和点击事件,具有较高的优先级和准确性
  • SetTimer:设置定时器,用于定期捕获鼠标位置

这些函数协同工作,实现了鼠标轨迹的记录与精确回放。其中,SendInput函数通过发送INPUT事件来模拟鼠标操作,相比其他方法具有更高的执行速度和系统兼容性。

数据存储格式

记录的鼠标轨迹数据需要包含以下关键信息:

  • 时间戳:记录每个坐标点的捕获时间
  • X/Y坐标:鼠标在屏幕上的位置
  • 鼠标状态:按键按下/释放状态

典型的数据格式可以是逗号分隔的文本文件,每行代表一个轨迹点:

timestamp,x,y,button_state
1620000000,500,300,0
1620000001,510,305,0
1620000002,520,310,1  ; 左键按下

实现步骤

1. 基础轨迹记录脚本

以下是一个简单的鼠标轨迹记录脚本,使用AutoHotkey的基本函数实现:

#Persistent
#SingleInstance Force

; 记录数据存储数组
global轨迹点 := []
global记录中 := false
global定时器ID := 0

; F8键开始/停止记录
F8::
    记录中 := !记录中
    if (记录中) {
        轨迹点 := []  ; 清空之前的记录
        ; 设置定时器,每10毫秒记录一次鼠标位置
        定时器ID := SetTimer, 记录鼠标位置, 10
        ToolTip, 正在记录轨迹...
    } else {
        SetTimer, 记录鼠标位置, Delete  ; 停止定时器
        保存轨迹数据("trajectory.txt")
        ToolTip, 轨迹已保存到trajectory.txt
        Sleep, 1500
        ToolTip
    }
return

; 记录鼠标位置的定时器回调函数
记录鼠标位置:
    MouseGetPos, x, y
    ; 获取鼠标按键状态
    左键状态 := GetKeyState("LButton", "P") ? 1 : 0
    右键状态 := GetKeyState("RButton", "P") ? 2 : 0
    按键状态 := 左键状态 | 右键状态
    
    ; 添加时间戳和坐标到轨迹数组
    轨迹点.Push({时间: A_TickCount, x: x, y: y, 按键: 按键状态})
return

; 保存轨迹数据到文件
保存轨迹数据(文件名) {
    文件 := FileOpen(文件名, "w", "UTF-8")
    for index, 点 in 轨迹点 {
        文件.WriteLine(点.时间 "," 点.x "," 点.y "," 点.按键)
    }
    文件.Close()
}

2. 轨迹回放实现

回放功能需要读取之前保存的轨迹数据,并按照时间间隔依次移动鼠标到记录的位置:

; F9键开始回放
F9::
    if (记录中) {
        ToolTip, 请先停止记录
        Sleep, 1000
        ToolTip
        return
    }
    
    轨迹点 := 加载轨迹数据("trajectory.txt")
    if (!轨迹点) {
        ToolTip, 未找到轨迹文件
        Sleep, 1000
        ToolTip
        return
    }
    
    ToolTip, 正在回放轨迹...
    上一个时间 := 轨迹点[1].时间
    
    for index, 点 in 轨迹点 {
        ; 计算与上一个点的时间差
        延迟 := 点.时间 - 上一个时间
        if (延迟 > 0) {
            Sleep, 延迟  ; 等待相应的时间
        }
        
        ; 移动鼠标到记录的位置
        MouseMove, 点.x, 点.y, 0  ; 0表示立即移动,无平滑效果
        
        ; 处理鼠标按键状态
        当前按键 := 点.按键
        上一个按键 := (index > 1) ? 轨迹点[index-1].按键 : 0
        
        ; 左键状态变化
        if ((当前按键 & 1) && !(上一个按键 & 1)) {
            MouseClick, left, , , 1, 0, D  ; 按下左键
        } else if (!(当前按键 & 1) && (上一个按键 & 1)) {
            MouseClick, left, , , 1, 0, U  ; 释放左键
        }
        
        ; 右键状态变化
        if ((当前按键 & 2) && !(上一个按键 & 2)) {
            MouseClick, right, , , 1, 0, D  ; 按下右键
        } else if (!(当前按键 & 2) && (上一个按键 & 2)) {
            MouseClick, right, , , 1, 0, U  ; 释放右键
        }
        
        上一个时间 := 点.时间
    }
    
    ToolTip, 轨迹回放完成
    Sleep, 1500
    ToolTip
return

; 从文件加载轨迹数据
加载轨迹数据(文件名) {
    if !FileExist(文件名) {
        return false
    }
    
    轨迹点 := []
    文件 := FileOpen(文件名, "r", "UTF-8")
    while (!文件.AtEOF) {
        行 := 文件.ReadLine()
        if (行 = "") {
            continue
        }
        StringSplit, 数据, 行, `,
        轨迹点.Push({时间: 数据1, x: 数据2, y: 数据3, 按键: 数据4})
    }
    文件.Close()
    return 轨迹点
}

3. 优化与高级功能

平滑轨迹回放

默认的立即移动鼠标可能显得生硬,可以通过插值算法实现平滑移动:

; 平滑移动鼠标到目标位置
平滑移动(x1, y1, x2, y2, 持续时间=20) {
    ; 计算两点之间的距离
    dx := x2 - x1
    dy := y2 - y1
    距离 := sqrt(dx*dx + dy*dy)
    
    ; 如果距离很小,直接移动
    if (距离 < 5) {
        MouseMove, x2, y2, 0
        return
    }
    
    ; 计算每步移动的像素和时间间隔
    步数 := 距离 / 2  ; 每步移动2像素
    步长时间 := 持续时间 / 步数
    
    ; 线性插值移动
    for (i := 0; i <= 步数; i++) {
        t := i / 步数
        x := x1 + dx * t
        y := y1 + dy * t
        MouseMove, x, y, 0
        Sleep, 步长时间
    }
}
轨迹编辑与优化

对于长时间记录的轨迹,可能需要进行优化,去除冗余点:

; 使用Douglas-Peucker算法简化轨迹
简化轨迹(原始轨迹, 阈值=2) {
    if (原始轨迹.Length() <= 2) {
        return 原始轨迹
    }
    
    ; 找到距离最长的点
    起点 := 原始轨迹[1]
    终点 := 原始轨迹[原始轨迹.Length()]
    最大距离 := 0
    最大索引 := 0
    
    for i := 2; i < 原始轨迹.Length(); i++ {
        d := 点到线段距离(原始轨迹[i], 起点, 终点)
        if (d > 最大距离) {
            最大距离 := d
            最大索引 := i
        }
    }
    
    ; 如果最大距离大于阈值,则递归简化
    结果 := []
    if (最大距离 > 阈值) {
        ; 递归处理前后两段
        前段 := 原始轨迹.Clone()
        前段.Length(最大索引)
        后段 := 原始轨迹.Clone()
        后段.RemoveAt(1, 最大索引-1)
        
        简化前段 := 简化轨迹(前段, 阈值)
        简化后段 := 简化轨迹(后段, 阈值)
        
        ; 合并结果,去除重复的点
        简化后段.RemoveAt(1)
        结果 := 简化前段.Concat(简化后段)
    } else {
        ; 直接保留起点和终点
        结果.Push(起点)
        结果.Push(终点)
    }
    
    return 结果
}

; 计算点到线段的垂直距离
点到线段距离(点, 线段起点, 线段终点) {
    ; 线段向量
    dx := 线段终点.x - 线段起点.x
    dy := 线段终点.y - 线段起点.y
    
    ; 如果线段长度为0,直接返回点到起点的距离
    if (dx == 0 && dy == 0) {
        return sqrt((点.x - 线段起点.x)^2 + (点.y - 线段起点.y)^2)
    }
    
    ; 计算投影比例
    t := ((点.x - 线段起点.x) * dx + (点.y - 线段起点.y) * dy) / (dx*dx + dy*dy)
    
    ; 限制t在[0,1]范围内
    t := (t < 0) ? 0 : (t > 1) ? 1 : t
    
    ; 计算投影点
    投影x := 线段起点.x + t * dx
    投影y := 线段起点.y + t * dy
    
    ; 计算点到投影点的距离
    return sqrt((点.x - 投影x)^2 + (点.y - 投影y)^2)
}

应用场景与扩展

软件测试自动化

鼠标轨迹记录工具非常适合自动化重复的软件测试步骤。例如,你可以录制一套测试流程,然后在软件更新后自动回放,检查是否有异常行为。

结合AutoHotkey的窗口控制功能,可以实现更复杂的测试场景:

; 激活指定窗口并移动到指定位置
激活窗口并定位(窗口标题, x=0, y=0, 宽度=800, 高度=600) {
    WinActivate, %窗口标题%
    WinMove, %窗口标题%,, x, y, 宽度, 高度
    Sleep, 500  ; 等待窗口激活
}

游戏辅助应用

在游戏中,某些复杂的操作可以通过轨迹记录来实现一键释放。例如MOBA游戏中的连招、FPS游戏中的压枪宏等。

; 游戏连招示例 - 记录的轨迹点
global 连招轨迹 := [
    {x: 650, y: 450, 按键: 1, 延迟: 100},  ; 左键点击
    {x: 700, y: 500, 按键: 0, 延迟: 50},   ; 移动鼠标
    {x: 750, y: 550, 按键: 1, 延迟: 100},  ; 左键点击
    {x: 700, y: 500, 按键: 0, 延迟: 50}    ; 移动回原位
]

; F10键释放连招
F10::
    激活窗口并定位("游戏窗口标题")
    for index, 点 in 连招轨迹 {
        MouseMove, 点.x, 点.y, 0
        if (点.按键 & 1) {
            MouseClick, left, , , 1, 0, D
            Sleep, 20
            MouseClick, left, , , 1, 0, U
        }
        Sleep, 点.延迟
    }
return

注意事项与优化建议

  1. 权限问题:某些应用程序(如游戏、管理员权限运行的软件)可能会阻止AutoHotkey模拟鼠标输入。此时需要以管理员身份运行脚本,或在目标程序中添加例外。

  2. 性能优化:对于长时间记录,建议降低采样频率(如每20-50毫秒记录一次),或使用轨迹简化算法减少数据量。

  3. 多显示器支持:在多显示器系统中,鼠标坐标可能为负数(相对于主显示器),需要在记录和回放时进行坐标转换。

  4. 抗干扰措施:记录和回放时应避免其他操作干扰,可以使用BlockInput命令临时阻止用户输入:

; 开始回放前阻止用户输入
BlockInput, On
; 回放代码...
; 回放结束后恢复输入
BlockInput, Off

总结与展望

AutoHotkey提供了强大的鼠标操作能力,使得实现鼠标轨迹记录与回放工具变得简单高效。通过本文介绍的方法,你可以构建一个功能完善的轨迹工具,应用于自动化测试、游戏辅助、重复性办公等多个场景。

未来可以进一步扩展的功能:

  • 图形化轨迹编辑界面
  • 轨迹数据的云同步与共享
  • AI辅助的轨迹优化与生成
  • 多设备间的轨迹共享与协同

希望本文能够帮助你更好地利用AutoHotkey提高工作效率,实现自动化操作。如有任何问题或改进建议,欢迎在评论区留言讨论。

如果你觉得本文有用,请点赞、收藏并关注,以便获取更多AutoHotkey实用技巧和脚本示例。下期我们将介绍如何实现键盘快捷键与鼠标轨迹的组合宏,敬请期待!

【免费下载链接】AutoHotkey 【免费下载链接】AutoHotkey 项目地址: https://gitcode.com/gh_mirrors/autohotke/AutoHotkey

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值