OnMessage 是 AHK 里连接“脚本”和“Windows 消息”的入口。它不负责直接点按钮、发按键,而是在某个窗口收到指定消息时,调用你写好的函数。新手可以先把它理解成:窗口发生了某类事件,脚本就被通知一次。
它适合做窗口内部事件监听、GUI 交互增强、接收部分系统通知,以及把一些原本只能轮询检查的事情改成事件触发。但它不是全局钩子,也不是所有软件都能拦截;用它之前,要先分清“监听自己的 GUI”和“监听别人的窗口”是两件事。
完整的消息对照表 WM_Messages值解释详见:https://www.ahk66.com/638
最小示例:鼠标在 GUI 内移动
#Requires AutoHotkey v1.1
#NoEnv
#SingleInstance Force
Gui, Add, Text, w320 h80 vInfo, 把鼠标移到这个窗口里
Gui, Show,, OnMessage 示例
OnMessage(0x200, "WM_MOUSEMOVE")
return
WM_MOUSEMOVE(wParam, lParam, msg, hwnd) {
GuiControl,, Info, 鼠标正在窗口内移动
}
GuiClose:
ExitApp
这里的 0x200 是鼠标移动消息。窗口收到这类消息时,AHK 就会调用 WM_MOUSEMOVE 函数。函数名可以自己取,但 OnMessage 里的名字要和函数定义一致。
回调函数的 4 个参数
OnMessage 回调常见参数是 wParam、lParam、msg、hwnd。初学者不需要一开始就背 Windows API,只要知道:msg 是消息编号,hwnd 是收到消息的窗口句柄,wParam 和 lParam 是这条消息附带的数据。
WM_MOUSEMOVE(wParam, lParam, msg, hwnd) {
x := lParam & 0xFFFF
y := lParam >> 16
ToolTip, 鼠标位置:%x%, %y%
}
不同消息里,wParam 和 lParam 的含义不同。写 OnMessage 代码时,真正重要的不是“参数名字”,而是查清楚你监听的那条消息把数据放在哪里。
常见用途
OnMessage 最适合下面几类场景:
- 监听自己写的 AHK GUI,例如鼠标进入、按下、窗口大小变化。
- 处理窗口关闭、移动、激活等事件,让界面行为更自然。
- 接收某些系统或控件发来的通知,减少死循环轮询。
- 在多个脚本配合时,作为一种轻量的事件入口。
但如果你的目标是控制网页、Excel、普通软件按钮,通常应该先考虑 COM、控件命令、UIA、Acc、浏览器接口等更直接的方法。OnMessage 更像底层事件监听,不是自动化的第一选择。
高频消息要节流
鼠标移动、窗口尺寸变化这类消息触发非常频繁。如果回调里写了耗时操作,脚本就容易卡顿。比较稳的做法是先做时间间隔判断,把真正的处理频率降下来。
WM_MOUSEMOVE(wParam, lParam, msg, hwnd) {
static lastTick := 0
if (A_TickCount - lastTick < 100)
return
lastTick := A_TickCount
ToolTip, 已处理一次鼠标移动消息
}
这段代码的意思是:100 毫秒内只处理一次。对于日志、界面刷新、文件写入等操作,这个习惯尤其重要。
临时关闭监听
OnMessage 不是写上就必须一直开着。某些窗口关闭后、调试结束后,或者你只想在特定阶段监听时,可以把对应消息取消掉。
OnMessage(0x200, "WM_MOUSEMOVE") ; 开启监听 ; 不再需要时关闭 OnMessage(0x200, "")
如果一个脚本里有多个 GUI,要注意 hwnd 参数。不要只看消息编号,还要判断这条消息来自哪个窗口,否则容易把 A 窗口的动作误处理到 B 窗口上。
新手最容易踩的坑
- 把 OnMessage 当成全局监听:它通常监听的是脚本相关窗口收到的消息,不等于全系统按键鼠标钩子。
- 回调函数里写太重的任务:高频消息会把脚本拖慢。
- 没有判断 hwnd:多个窗口共用一个回调时很容易误判来源。
- 照抄消息编号却不查参数含义:同样是 wParam、lParam,在不同消息里意思可能完全不同。
- 忘记关闭监听:临时调试代码留下来,后面排查问题会很绕。
结语
OnMessage 的价值在于“事件驱动”。能用窗口消息解决的问题,就不必一直 SetTimer 或 Loop 去查。初学时建议先从自己的 GUI 开始练:监听鼠标移动、点击、窗口关闭,再逐步理解 msg、hwnd、wParam、lParam 的关系。这样学起来更稳,也更容易判断它什么时候该用、什么时候不该用。

评论(0)