Send / SendText / SendInput / SendPlay / SendEvent

发送模拟键击和鼠标点击到活动窗口.

Send Keys
SendText Keys
SendInput Keys
SendPlay Keys
SendEvent Keys

参数

Keys

类型: 字符串

要发送的按键序列.

默认情况下(也就是说, 如果既不使用 SendText, 也不使用原始模式文本模式), 字符 ^+!#{} 具有特殊含义. 字符 ^+!# 分别代表修饰符键 Ctrl, Shift, AltWin. 他们仅影响紧跟着的下一个键. 若要发送修饰符本身对应的键, 将按键名称括在大括号中. 若要按下(按住) 或松开按键, 下面所示的单词 "down" 或 "up" 跟在按键名称的后面.

符号 按键 按下 松开 示例
^ {Ctrl} {Ctrl down} {Ctrl up} Send "^{Home}" 按下 Ctrl+Home
+ {Shift} {Shift down} {Shift up} Send "+abC" 发送文本 "AbC"
Send "!+a" 按下 Alt+Shift+A
! {Alt} {Alt down} {Alt up} Send "!a" 按下 Alt+A
# {LWin}
{RWin}
{LWin down}
{RWin down}
{LWin up}
{RWin up}
Send "#e" 按住 Win 键时, 按下字母 E

注意: 由于大写字母是通过发送 Shift 产生的, 因此在某些程序中 Aa 会产生不同的效果. 例如, !A 按下 Alt+Shift+A, 而 !a 按下 Alt+A. 如果不确定, 请使用小写字母.

字符 {} 用于括起键名和其他选项, 并发送特殊的原义字符. 例如, {Tab}Tab, 而 {!} 是原义的感叹号.

将一个纯 ASCII 字母(a-z 或 A-Z) 括在大括号中强制它作为相应的虚拟键码发送, 即使该字符在当前键盘布局上不存在. 换句话说, Send a 产生字母 "a", 而 Send {a} 根据键盘布局, 可能产生也可能不产生 "a". 有关详情, 请参阅下面的注释.

Send 的变体

Send: 默认情况下, Send 等同于 SendInput; 但是可以通过 SendMode 使其等同于 SendEvent 或 SendPlay.

SendText: 类似于 Send, 除了 Keys 中的所有字符都按原义解释. 有关详情, 请参阅文本模式.

SendInputSendPlay: SendInput 和 SendPlay 使用与 SendEvent 相同的语法, 但通常更快更可靠. 此外, 它们在发送过程中缓冲任何物理键盘或鼠标活动, 这可以防止用户的击键与发送的击键穿插在一起. 通过 SendMode 可以使 Send 等同于 SendInput 或 SendPlay. 有关每种模式的更多信息, 请参阅下面的 SendInputSendPlay.

SendEvent: SendEvent 使用 Windows keybd_event 函数发送键击(有关详情, 请在 Microsoft Docs 搜索). 发送击键的速率由 SetKeyDelay 决定. 通过 SendMode 可以使 Send 等同于 SendEvent 或 SendPlay.

特殊模式

以下模式影响 Keys 中字符的解释, 或键发送函数(例如 Send, SendInput, SendPlay, SendEvent 和 ControlSend) 的行为. 这些模式必须在 Keys 中指定 {x}, 其中 x 可以是 Raw, Text 或 Blind. 例如, {Raw}.

原始模式

可以使用 {Raw} 启用原始模式, 这会导致所有后续字符, 包括特殊字符 ^+!#{}, 都按原义进行解释, 如 {Enter} 不会转换为 Enter, ^c 不会转换为 Ctrl+C, 等等. 例如, Send "{Raw}{Tab}" 发送 {Tab}, 而不是 Tab.

原始模式不影响转义序列表达式的解释. 例如, Send "{Raw}``100`%" 发送字符 `100%.

文本模式

可以使用 {Text}, SendText 或 ControlSendText 来启用文本模式, 与原始模式类似, 不同之处在于不会尝试将字符(`r, `n, `t`b 除外) 转换为键码; 作为代替, 后备方法适用于所有剩余的字符. 对于 SendEvent, SendInput 和 ControlSend, 这提高了可靠性, 因为字符对正确的修饰符状态的依赖性要小得多. 文本模式可以与盲从模式结合使用, 以避免释放任何修饰键: Send "{Blind}{Text}your text". 但是, 一些应用程序会要求修饰键被释放.

`n, `r`r`n 都被转换为一次单独的 Enter, 不像普通模式和原始模式, 转换 `r`n 为两次 Enter. `t 转换为 Tab, 而 `b 转换为 Backspace, 但所有其他字符都是不经转换直接发送的.

与盲从模式类似, 文本模式忽略 SetStoreCapsLockMode(也就是说, 不会改变 CapsLock 的状态), 并且不等待 Win 被释放. 这是因为文本模式通常不依赖于 CapsLock 的状态, 并且不能触发系统 Win+L 热键. 但是, 这仅适用于当 Keys{Text}{Blind}{Text} 开头时.

盲从模式

可以使用 {Blind} 启用盲从模式, 该模式通过禁用通常自动执行的许多操作来使脚本按预期运行, 从而赋予脚本更多控制权. 要启用盲从模式, {Blind} 必须是字符串中的第一个项目. 它具有以下效果:

单词 "Blind" 后面可以用一个或多个修饰符号(!#^+) 以便在需要时自动释放这些修饰符. 例如, *^a::Send "{Blind^}b" 在按下 Ctrl+Shift+A 时, 将发送 Shift+B 而不是 Ctrl+Shift+B. {Blind!#^+} 可以在需要的时候释放所有的修饰符, 但是会启用盲从模式的其他效果.

重映射按键时, 盲从模式可以在其内部使用. 例如, 重映射 a::b 会发生这样的情况: 1) 输入 "a" 时会映射为 "b"; 2) 输入大写字母 "A" 时映射为大写字母 "B"; 并且 3) 按下 Ctrl+A 时映射为按下 Ctrl+B. 如果任何修饰符指定为源按键(包括 Shift 如果源按键是大写字母), 则如上所述, 这些修饰符被排除在外. 例如 ^a::b 产生的是正常的 B, 而不是 Ctrl+B.

SendText 或 ControlSendText 不支持 {Blind}; 请使用 {Blind}{Text} 代替.

SendPlay 不完全支持盲从模式, 尤其是在处理修饰键时(Ctrl, Alt, Shift 和 Win).

Key 名称

下表中列出了可以发送的特殊按键(每个按键名称必须用大括号括起来):

按键名称 描述
{F1} - {F24} 功能键. 例如: {F12} 表示 F12.
{!} !
{#} #
{+} +
{^} ^
{{} {
{}} }
{Enter} 主键盘上的 Enter
{Escape} 或 {Esc} Esc
{Space} Space(这只适用于出现在要发送的字符串的开头或结尾的空格 -- 而在中间的空格是原义的)
{Tab} Tab
{Backspace} 或 {BS} Backspace
{Delete} 或 {Del} Del
{Insert} 或 {Ins} Ins
{Up} (主键盘上的向上键)
{Down} (主键盘上的向下键)
{Left} (主键盘上的向左键)
{Right} (主键盘上的向右键)
{Home} Home(主键盘)
{End} End(主键盘)
{PgUp} PgUp(主键盘)
{PgDn} PgDn(主键盘)
{CapsLock} CapsLock(使用 SetCapsLockState 更可靠). 发送 {CapsLock} 之前可能要求 SetStoreCapsLockMode False.
{ScrollLock} ScrollLock(另请参阅: SetScrollLockState)
{NumLock} NumLock(另请参阅: SetNumLockState)
{Control} 或 {Ctrl} Ctrl(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)
{LControl} 或 {LCtrl} Ctrl(技术信息: 发送左边键的虚拟键码而不是中性键)
{RControl} 或 {RCtrl} Ctrl
{Control down} 或 {Ctrl down} 按住 Ctrl 键直到发送 {Ctrl up}. 要按住左边或右边的键, 请使用 LCtrl 或 RCtrl 替换 Ctrl.
{Alt} Alt(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)
{LAlt} Alt(技术信息: 发送左边键的虚拟键码而不是中性键)
{RAlt} Alt(或 AltGr, 取决于键盘布局)
{Alt down} 按住 Alt 直到发送 {Alt up}. 要按住左边或右边的键, 请使用 LAlt 或 RAlt 替换 Alt.
{Shift} Shift(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)
{LShift} Shift(技术信息: 发送左边键的虚拟键码而不是中性键)
{RShift} Shift
{Shift down} 按住 Shift 直到发送 {Shift up}. 要按住左边或右边的键, 请使用 LShift 或 RShift 替换 Shift.
{LWin} Win
{RWin} Win
{LWin down} 按住左 Win 直到发送 {LWin up}
{RWin down} 按住右 Win 直到发送 {RWin up}
{AppsKey} Menu (调用右键点击或上下文菜单)
{Sleep} Sleep
{ASC nnnnn}

发送 Alt+nnnnn 小键盘上的按键组合, 可以用来生成键盘上不存在的特殊字符. 若要从代码页 437 生成可打印的 ASCII 字符或其他字符, , 请指定一个介于 1 和 255 之间的数字. 要生成 ANSI 字符(在大多数语言中的标准), 请指定一个介于 128 和 255 之间的数字, 但需要在数字前加上一个前导零, 例如 {Asc 0133}..

要生成 Unicode 字符, 请指定一个介于 256 和 65535 之间的数字(不带前导零). 但是, 有些应用程序不支持这种方法. 对于替代方法, 请参阅下面的部分.

{U+nnnn}

发送 Unicode 字符, 其中 nnnn 为字符的不包括 0x 前缀的十六进制值. 通常不需要这么做, 因为 Send 和 ControlSend 自动支持 Unicode 文本.

会使用 SendInput()WM_CHAR 来发送字符, 并且当前的发送模式没有效果. 以这种方式发送的字符通常不会触发快捷键或热键.

{vkXX}
{scYYY}
{vkXXscYYY}

发送虚拟键为 XX 和扫描码为 YYY 的按键. 例如: Send "{vkFFsc159}". 如果省略 sc 或 vk 部分, 则发送最合适的值.

XX 和 YYY 的值是十六进制的, 通常可以从主窗口的 View->Key history 菜单项中确定. 另请参阅: 特殊按键

警告: 以这种方式组合 vk 和 sc 仅在 Send 有效.

{Numpad0} - {Numpad9} 小键盘上的数字键(与 NumLock 打开时输入的一样). 例如: {Numpad5} 为数字 5.
{NumpadDot} .(小键盘上的点)(与 NumLock 打开时输入的一样).
{NumpadEnter} 小键盘上的 Enter
{NumpadMult} *(小键盘上的乘号)
{NumpadDiv} /(小键盘上的除号)
{NumpadAdd} +(小键盘上的加号)
{NumpadSub} -(小键盘上的减号)
{NumpadDel} 小键盘上的 Del(当 NumLock 为 OFF 时, 此键和以下的小键盘按键将被使用)
{NumpadIns} 小键盘上的 Ins
{NumpadClear} 小键盘上的 Clear 键(在 NumLock 关闭时, 通常为 5).
{NumpadUp} 小键盘上的 (向上)
{NumpadDown} 小键盘上的 (向下)
{NumpadLeft} 小键盘上的 (向左)
{NumpadRight} 小键盘上的 (向右)
{NumpadHome} 小键盘上的 Home
{NumpadEnd} 小键盘上的 End
{NumpadPgUp} 小键盘上的 PgUp
{NumpadPgDn} 小键盘上的 PgDn
{Browser_Back} 浏览器 "后退" 按钮
{Browser_Forward} 浏览器 "前进" 按钮
{Browser_Refresh} 浏览器 "刷新" 按钮
{Browser_Stop} 浏览器 "停止" 按钮
{Browser_Search} 浏览器 "搜索" 按钮
{Browser_Favorites} 浏览器 "收藏" 按钮
{Browser_Home} 启动浏览器并打开主页
{Volume_Mute} 主音量静音/取消静音. 通常相当于 SoundSetMute -1.
{Volume_Down} 减小主音量. 通常相当于 SoundSetVolume -5.
{Volume_Up} 增加主音量. 通常相当于 SoundSetVolume "+5".
{Media_Next} 在媒体播放器中播放下一曲目
{Media_Prev} 在媒体播放器中播放前一曲目
{Media_Stop} 停止媒体播放器
{Media_Play_Pause} 播放/暂停媒体播放器
{Launch_Mail} 启动电子邮件程序
{Launch_Media} 启动媒体播放器
{Launch_App1} 启动用户程序 1
{Launch_App2} 启动用户程序 2
{PrintScreen} PrtScr
{CtrlBreak} Ctrl+Pause
{Pause} Pause
{Click [Options]} Send 鼠标点击使用的选项与 Click 函数中的一样. 例如, Send "{Click}" 会在鼠标光标当前位置点击一次鼠标左键, 而 Send "{Click 100 200}" 则在坐标 100, 200 处点击(这里的坐标模式取决于 CoordMode). 要移动鼠标而不点击, 请在坐标后指定 0; 例如: Send "{Click 100 200 0}". 鼠标点击之间的延迟由 SetMouseDelay 决定(而不是 SetKeyDelay).
{WheelDown}, {WheelUp}, {WheelLeft}, {WheelRight}, {LButton}, {RButton}, {MButton}, {XButton1}, {XButton2}

在光标的当前位置发送一个鼠标按钮事件(要控制位置和其他选项, 请使用上面的 {Click}). 鼠标点击之间的延迟由 SetMouseDelay 决定.

LButton 和 RButton 分别对应鼠标的主按钮和次按钮. 通常鼠标的主按钮(LButton) 在左边, 但是用户可以通过系统设置来交换按钮.

{Blind} 启用盲从模式, 通过禁用一些通常会自动完成的事情, 让脚本有了更多的控制权, 从而使事情一般都能正常工作. {Blind} 必须出现在字符串的开头.
{Raw} 启用原始模式, 这将导致以下字符按原义解释: ^+!#{}. 虽然 {Raw} 不需要出现在字符串的开头, 但一旦指定, 它将在字符串的其余部分保持有效.
{Text} 启用文本模式, 它发送的是字符流而不是按键. 与原始模式一样, 文本模式会使以下字符按原义解释: ^+!#{}. 虽然 {Text} 不需要出现在字符串的开头, 但一旦指定, 它将在字符串的其余部分保持有效.

重复或按住按键

重复键击: 用大括号括起按键名称和重复次数. 例如:

Send "{DEL 4}"  ; 按 4 次 Delete 键.
Send "{S 30}"   ; 发送 30 次大写字母 S.
Send "+{TAB 4}"  ; 按 4 次 Shift-Tab.

按住或释放按键: 用大括号括起按键名称和单词 DownUp. 例如:

Send "{b down}{b up}"
Send "{TAB down}{TAB up}"
Send "{Up down}"  ; 按下向上键.
Sleep 1000  ; 按住 1 秒.
Send "{Up up}"  ; 释放向上键.

使用上面的方法按住一个按键后, 这个期间它不会像您实际按住这个按键一样自动重复(这是由于自动重复是一个驱动/硬件的特性). 不过, 可以使用 Loop 来模拟自动重复. 下面的例子中发送 20 次 tab 键击:

Loop 20
{
    Send "{Tab down}"  ; 自动重复由连续的按下事件组成(没有弹起事件).
    Sleep 30  ; 在两次键击之间的毫秒数(或使用 SetKeyDelay 设置).
}
Send "{Tab up}"  ; 松开按键.

默认情况下, 如果一个修饰键在发送时被 "按下", 则 Send 不会自动释放该修饰键(Control, Shift, Alt 和 Win) . 例如, 如果用户物理按下 Ctrl 时, Send "a" 的行为类似于 Send "{Blind}{Ctrl up}a{Ctrl down}", 但 Send "{Ctrl Down}" 后面接着 Send "a" 将产生 Ctrl+A. DownTempDownR 可以用来覆盖这种行为. DownTempDownRDown 具有同样的效果, 除了修饰键(Control, Shift, Alt 和 Win).

DownTemp 告诉后续的发送, 该键不是永久按下的, 只要有按键需要就可以释放. 例如, 在发送 Send "{Control DownTemp}" 之后, 再 Send "a" 将产生一个正常的 A, 而不是 Ctrl+A. 任何使用 Send 的方法都有可能永久地释放修饰键, 所以 DownTemp 并不是重映射修饰键的理想选择.

DownR(其中 "R" 表示重映射, 这是它的主要用途) 告诉后续的发送, 如果该键被自动释放, 则应在发送结束后再次按下. 例如, Send "{Control DownR}" 后面跟着 Send "a" 会产生一个正常的 A, 而不是 Ctrl+A, 但会让 Ctrl 处于被按下的状态, 以便用于键盘快捷键. 换句话说, DownR 有类似于物理按下按键的效果.

如果某个字符与当前键盘布局上的虚拟键不一致, 则不能 "按下" 或 "释放". 例如, Send "{μ up}" 对大多数键盘布局没有效果, 而 Send "{μ down}" 等同于 Send "μ".

备注

字符 vs. 按键: 默认情况下, 先将字符转换为按键来发送字符. 如果这种转换是不可能的(即, 如果当前的键盘布局不包含产生该字符的键或键组合), 则通过以下回退方法之一来发送字符:

注意: 使用上述方法发送字符通常不会触发键盘快捷键或热键.

对于 a-z 或 A-Z(纯 ASCII 字母) 范围内的字符, 每个当前键盘布局中不存在的字符可以作为字符或相应的虚拟键码(vk41-vk5A) 发送:

如果字母存在于当前的键盘布局中, 那么它总是以布局与该字母相关联的键码发送(除非使用了文本模式, 在这种情况下, 该字符将通过其他方式发送). 换句话说, 上面的部分只适用于非拉丁语系的布局, 如俄语.

修饰键状态: 当 Send 需要改变 WinAlt 修饰键的状态时(比如用户按住其中一个键), 它可能会注入额外的按键(默认为 Ctrl) 来阻止开始菜单或窗口菜单的出现. 有关详情, 请参阅 A_MenuMaskKey.

BlockInput 对比 SendInput/SendPlay: 尽管 BlockInput 函数可以用来防止用户物理输入的任何按键破坏模拟按键的流, 但通常最好使用 SendInputSendPlay 这样按键和鼠标点击就不会中断. 这是因为与 BlockInput 不同的是, SendInput/Play 不会在发送过程中丢弃用户输入的内容; 相反, 这样的按键会被缓冲并在之后发送.

当发送大量的按键时, 可以使用延续片段来提高可读性和可维护性.

由于操作系统不允许模拟 Ctrl+Alt+Del 组合, 所以类似 Send "^!{Delete}" 这样的操作是没有效果的.

当活动窗口以管理身份运行而当前脚本不是时, Send 可能没有效果. 这是由于一种叫做用户界面特权隔离的安全机制造成的.

SendInput

一般情况下, SendInput 是发送按键和鼠标点击的首选方法, 因为它的速度和可靠性都很高. 在大多数情况下, SendInput 几乎是瞬间完成的, 即使是发送长字符串时也是如此. 由于 SendInput 的速度如此之快, 它的可靠性也更高, 因为这样其他一些窗口更没有机会出乎意料地弹出并打断按键. 用户在 SendInput 过程中输入的任何东西都会被推迟到之后再进行, 从而进一步提高了可靠性.

与其他发送模式不同, 操作系统限制 SendInput 每次只能发送大约 5000 个字符(此限制可能因操作系统版本和性能设置而有所不同). 超过此限制的字符和事件不会被发送.

注意: SendInput 会忽略 SetKeyDelay, 因为在这种发送模式中操作系统不支持延迟. 但是, 在后面描述的情况中, 当 SendInput 恢复到 SendEvent 时, 它会使用 SetKeyDelay -1, 0(但如果 SendEvent 的按键延迟为 -1,-1 时, 则使用 -1,-1). 当 SendInput 恢复为 SendPlay 时, 它使用 SendPlay 的按键延迟.

如果脚本安装了底层键盘钩子, SendInput 会在执行之前自动卸载它, 并在执行后重新安装. 因此, SendInput 通常不能触发脚本自己的钩子热键或 InputHooks. 之所以暂时卸载钩子, 是因为它的存在会使 SendInput 的所有优势失效, 使其不如 SendPlay 和 SendEvent. 然而, 这只能对脚本自己的钩子执行, 如果检测到外部钩子, 则不会执行, 如下所述.

如果执行 SendInput 的脚本 以外的 脚本安装了低级键盘钩子, 则 SendInput 会自动恢复为 SendEvent(或当 SendMode "InputThenPlay" 生效时为 SendPlay). 这是由于外部钩子的存在让 SendInput 失去了所有的优势, 使它不如 SendPlay 和 SendEvent 两者. 然而, 由于 SendInput 无法检测到除 AutoHotkey v1.0.43+ 以外的程序中的低级钩子, 所以在这些情况下它不会还原, 使得它的可靠性不如 SendPlay/Event.

当 SendInput 使用像 {Click} 这样的方法发送鼠标点击, 并且 CoordMode "Mouse", "Window"CoordMode "Mouse", "Client" 有效时(默认的), 则每次点击都会相对于发送开始时的那个活动窗口. 因此, 如果 SendInput 有意地激活另一个窗口(通过类似 alt-tab 的方法), 那么这个命令中后续点击的坐标将变成错误的, 因为它们仍然相对于原来的活动窗口而不是新的.

SendPlay

警告: 如果启用了 UAC, 即使脚本以管理员身份运行, SendPlay 也可能没有效果. 有关详情, 请参阅 FAQ.

SendPlay 最大的优势在于它能在更多的游戏中 "回放" 按键和鼠标点击. 例如, 某款游戏只有在有 SendPlay 选项的情况下才能接受热字串.

在这三种发送模式中, SendPlay 是最特别的, 因为它本身并不模拟按键和鼠标点击. 相反, 它创建了一系列的事件(消息), 直接流向活动窗口(类似于 ControlSend, 但级别较低). 因此, 不会触发热键或热字串.

SendInput 一样, SendPlay 的按键与用户键入的按键互不干扰. 因此, 如果用户在 SendPlay 期间碰巧输入了一些东西, 这些键程会被推迟到之后.

虽然 SendPlay 比 SendInput 要慢很多, 但它通常比传统的 SendEvent 模式要快(即使 KeyDelay 为 -1 时, 也是如此).

如果安装了键盘钩子, 则在 SendPlay 发送期间会自动屏蔽 Win(LWin 和 RWin). 这样避免了在发送期间当用户无意按了 Win 键时显示开始菜单. 与之相比, LWin 和 RWin 之外的其他按键不需要屏蔽, 因为操作系统会自动把它们延迟到 SendPlay 执行完后(通过缓冲).

SendPlay 不使用 SetKeyDelaySetMouseDelay 的标准设置. 相反, 它默认为无延迟, 可以按照下面的例子来改变:

SetKeyDelay 0, 10, "Play"  ; 注意 0 和 -1 在 SendPlay 模式中是一样的.
SetMouseDelay 10, "Play"

SendPlay 无法打开或关闭 CapsLock, NumLockScrollLock. 同样, 它也无法改变 GetKeyState 所看到的键的状态, 除非按键被发送到脚本自己的一个窗口. 即使如此, 任何对左/右修饰键(例如 RControl) 的改变也只能通过它们的中性对应键(例如 Control) 来检测. 此外, SendPlay 还有其他限制, 在 SendMode 页面上有描述.

SendInputSendEvent 不同, 用户可以通过按下 Ctrl+Alt+DelCtrl+Esc 来中断 SendPlay. 当这种情况发生时, 剩余的按键不会被发送, 但是脚本会继续执行, 就像 SendPlay 已经正常完成一样.

虽然 SendPlay 可以发送 LWin 和 RWin 事件, 但是它们会直接发送到活动窗口, 而不是执行它们的在操作系统中的原生功能. 要解决这个问题, 请使用 SendEvent. 例如, SendEvent "#r" 将显示开始菜单的运行对话框.

SendMode, SetKeyDelay, SetStoreCapsLockMode, 转义序列(例 `n), ControlSend, BlockInput, 热字串, WinActivate

示例

输入两行签名.

Send "Sincerely,{enter}John Smith"

选择 File->Save 菜单(Alt+F 后面跟着 S).

Send "!fs"

到文本的末尾然后发送四次 shift 和左方向键组合的键击.

Send "{End}+{Left 4}"

通过最快的方法发送一长串原始字符.

SendInput "{Raw}A long series of raw characters sent via the fastest method."