以下是一些检测鼠标移动的方法。我通常的首选是选项 2 或 1;如果只需要来自 AHK GUI 的信息,则 4;如果需要来自多个鼠标/设备的信息,则 2 或 6;如果需要阻止/拦截移动,则为 3、6 或 5;如果只需要在一个窗口中拦截移动,那么 5.
1) SetTimer:使用此方法,您可以定期轮询鼠标位置,如果检测到移动(与上次轮询相比位置发生变化),则调用事件处理程序。这种方法的优点是实现起来非常简单。缺点是即使没有移动,鼠标位置也会被轮询,从而浪费资源,如果移动足够快并在下一次轮询之前返回到原始位置,那么就会错过移动。例如,如果每 100 毫秒轮询一次位置,但移动 (0;0)->(0;1)->(0;0) 在 50 毫秒内发生,则错过了移动。
以下所有方法都是真正的事件驱动方法,这意味着如果不发生移动,则不会浪费资源。
2) RawInput:该方法接收鼠标的相对移动数据,即鼠标是否上/下/左/右移动以及移动了多少像素。要获取绝对鼠标位置,请使用鼠标GetPos功能。理论上,RawInput 也可以用于从笔输入、操纵杆等获取信息,但我还没有测试过它。
3) SetWindowHookEx 低级鼠标钩子:此方法的缺点是所有鼠标移动和点击都必须由内部 LowLevelMouseProc 回调处理才能实际发生。这意味着,如果回调或脚本由于某种原因出现故障,鼠标几乎会完全冻结(尽管仍然可以使用 Ctrl+Alt+Delete)。回调需要非常短的时间,但由于 AHK 是一种相当慢的语言,因此它还可能会给鼠标移动带来轻微的延迟。此外,如果 AHK 还使用鼠标钩子(例如,定义了任何鼠标热键),则所有鼠标事件在实际发生之前都会被处理两次,因此延迟可能会累积。此外,由于 AHK 是单线程的,因此如果使用了任何 DllCalls/ComCalls,则在该调用完成之前无法处理任何鼠标事件。此外,由于鼠标变得非常滞后,因此无法使用调试器断点。
一个潜在的好处是,此方法可用于有条件地阻止鼠标移动。
注意:在 AHK 中实现回调时,大多数缺点都适用。如果用 C、C++ 或其他高性能语言实现,那么滞后就不是问题。(见下面的示例)
4) WM_MOUSEMOVE:当鼠标在 GUI 工作区内移动时,所有 GUI 都会收到WM_MOUSEMOVE窗口消息。我们可以侦听发送到脚本创建的 GUI 的消息,但不能侦听外部窗口,这意味着此方法仅限于我们的 GUI 工作区。
5) SetWindowsHookEx 鼠标钩子:使用此方法,可以读取、阻止和修改发送到一个或所有窗口的鼠标消息。如果程序从窗口消息的其他来源读取鼠标信息(例如,游戏可能从 RawInput 读取),则它不会干扰这些鼠标事件。这种方法的缺点是它需要用另一种语言(通常是 C 或 C++)编写 DLL 文件。
6) AutoHotInterception:AutoHotInterception 包装了 Interception 驱动程序,该驱动程序在非常低的级别实现,需要管理员访问权限才能安装。与 RawInput 一样,此方法也可用于侦听鼠标事件并区分不同的输入源,这意味着它可以将移动与两个或多个生成鼠标输入的设备(操纵杆、笔输入等)分开。此外,它可以阻止输入(例如,只允许来自一个设备的输入),还可以生成新的鼠标输入。同样,由于 AHK 是一种相当慢的语言,因此最好使用一些更快的语言,否则鼠标移动会变得滞后。
选项 1-4 的示例。在所有示例中,F1 键用于切换捕获的开与关(脚本以 off 开头),Esc 键终止脚本。
1) 设置计时器