SendInput 是 AHK v1 里常用的高速发送方式。很多人写脚本时会直接加一句 SendMode Input,然后默认所有发送都会更快。但实际使用中你可能会遇到一个奇怪现象:同样的脚本,有时很快,有时突然变慢,甚至还会漏按键。
这个问题经常和键盘钩子有关。AHK 为了实现热字符串、条件热键、自定义组合键、通配热键等功能,会安装低级键盘钩子。钩子一旦参与输入流程,SendInput 的行为就可能发生变化。
一、SendInput 快在哪里
SendInput 的优势是批量、快速、通常不容易和用户真实输入交织。录入文本、发送宏命令、执行一串快捷键时,它一般比默认的 SendEvent 更快。
#Requires AutoHotkey v1.1 SendMode, Input SetKeyDelay, -1, -1 F1:: Send, 这是一段快速发送的文本 return
但要注意,SetKeyDelay 主要影响 SendEvent,对 SendInput 的影响很有限。很多人以为 SetKeyDelay, -1, -1 是让 SendInput 更快,其实真正切换发送方式的是 SendMode, Input。
二、哪些功能会用到键盘钩子
AHK v1 中这些写法都可能让脚本安装键盘钩子:
- 热字符串,例如
::btw::by the way。 #If条件热键。- 带
*、$、~修饰的热键。 Up热键。- 自定义组合键,例如
a & b::。 Input命令或需要监听物理按键状态的脚本。
这些功能本身没有问题,问题在于它们会改变输入流的处理方式。脚本越多、热键越复杂,越容易出现“为什么 SendInput 没以前快”的疑问。
三、为什么有钩子时 SendInput 会变慢
当另一个 AHK 脚本安装了键盘钩子时,AHK 可能会把 SendInput 退化成类似 SendEvent 的方式,避免发送出来的按键被其他 AHK 钩子吞掉或乱序。这样一来,SendInput 的速度优势就没了。
如果只有当前脚本自己的钩子,AHK 可能会在调用 SendInput 时临时卸载自身钩子,发送完再装回去。这通常能恢复速度,但也会带来另一个边缘问题:在钩子短暂卸载期间,原本应该被热键拦截的物理按键可能漏到目标程序里。
四、有钩子时,SendEvent 反而更可控
如果脚本依赖热字符串、条件热键或物理按键状态,稳定性往往比极限速度更重要。此时可以显式使用 SendEvent,并把延迟调低。
SetKeyDelay, -1, 0
$z::
while GetKeyState("z", "P")
{
SendEvent, {n down}
Sleep, 200
SendEvent, {n up}
}
return
这里的 $z 会强制使用键盘钩子,避免 Send 自己触发自己。既然这个场景本来就依赖钩子,显式使用 SendEvent 反而更容易控制。
五、SendInput 不一定能触发另一个热键
有些人会写一个脚本发送按键,希望触发另一个脚本里的热键。这个思路不一定可靠。简单热键可能通过 Windows 的 RegisterHotkey 机制触发,但带 *、~、$、#If、Up 或热字符串的规则通常依赖钩子,不应该假设 SendInput 一定能触发它们。
如果确实需要脚本之间互相触发,优先考虑这几种方式:
- 把热键里的逻辑抽成函数,直接调用函数。
- 用
PostMessage/SendMessage通知另一个脚本。 - 用
WM_COPYDATA传递短命令或字符串。 - 必要时再测试
SendLevel/#InputLevel。
六、排查 SendInput 变慢的顺序
- 先关掉其他常驻 AHK 脚本,只留当前脚本测试。
- 检查当前脚本有没有热字符串、
#If、*、$、~、Up热键。 - 把
Send分别改成SendInput、SendEvent、SendPlay测试。 - 如果是游戏、远程桌面、虚拟机或管理员权限窗口,单独测试权限和兼容性。
- 不要只看速度,也要看是否漏键、乱序、夹入用户输入。
我的建议是:普通文本录入优先试 SendInput;依赖热键状态、物理按键、游戏宏时,不要迷信 SendInput,稳定比极限速度更重要。
相关专题
参考来源
- AutoHotkey 文档:Send / SendInput / SendEvent
- AutoHotkey 文档:#InstallKeybdHook
- AutoHotkey 论坛讨论:Understanding SendInput and keyboard hooks

评论(0)