# Send, SendRaw, SendInput, SendPlay, SendEvent

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

    Send Keys
    SendRaw Keys
    SendInput Keys
    SendPlay Keys
    SendEvent Keys

## 参数

Keys

  要发送的按键序列. 和其他命令一样, 首个参数前的逗号是可选的.

  默认情况下(也就是说, 如果不使用 SendRaw, 原始模式或文本模式), 字符 `^+!#{}` 具有特殊含义. 字符 `^+!#` 分别代表修饰符键 `Ctrl`, `Shift`, `Alt` 和 `Win`. 他们仅影响紧跟着的下一个键. 若要发送修饰符本身对应的键, 将按键名称括在大括号中. 若要按下(按住) 或松开按键, 下面所示的单词 "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` 产生的, 因此在某些程序中 `A` 和 `a` 会产生不同的效果. 例如, `!A` 按下 `Alt`+`Shift`+`A`, 而 `!a` 按下 `Alt`+`A`. 如果不确定, 请使用小写字母.

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

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

## Send 的变体

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

SendRaw: 类似于 Send, 除了 Keys 中的所有字符都按原义解释和发送之外. 有关详情, 请参阅原始模式.

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

SendEvent [v1.0.43+]: SendEvent 使用与 1.0.43 之前的 Send 命令相同的方法发送击键. 发送击键的速率由 SetKeyDelay 决定.

## 特殊模式

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

### 原始模式

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

原始模式不影响转义序列, 变量引用和表达式的解释. 例如, `SendRaw, ``100`%` 为发送字符 ``100%`. 当使用 ControlSend 时, 也需要转义原义的逗号(``,`).

### 文本模式[v1.1.27+]

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

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

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

### 盲从模式

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

- 如果修饰符(Alt, Ctrl, Shift 和 Win) 在发送开始时为按下的状态, 则盲从模式不会释放这些按键. 例如, 热键 `+s::Send {Blind}abc` 将发送 ABC 而不是 abc, 因为用户按住了 `Shift`.
- 修饰键有不同的恢复方式, 允许 Send 能关闭热键的修饰键, 即使用户在物理上仍然是按下的. 例如, `^space::Send {Ctrl up}` 如果用户仍然物理按住 `Ctrl`, 则自动推送 `Ctrl` 按下, 而 `^space::Send {Blind}{Ctrl up}` 允许 `Ctrl` 逻辑松开, 即使它物理上是按下的.
- SetStoreCapsLockMode 会被忽略; 也就是说, `CapsLock` 的状态不会改变.
- 菜单掩饰是禁用的. 也就是说, Send 忽略额外的击键, 这些键原本会被发送, 以防止: 1) 在按下 Win 键(LWin/RWin) 时, 出现开始菜单; 2) 在按下 Alt 键时, 菜单栏的激活. 然而, 盲从模式不会阻止在钩子热键激活后由键盘钩子进行的掩饰.
- 即使文本包含一个 `L` 按键, Send 也不会等待 `Win` 按键被释放. 一般情况下会等待 `Win` 释放, 以防止 Send 触发系统 "锁定工作站" 的热键(`Win`+`L`). 有关详细信息, 请参阅热键.

在按键的重映射时, 盲从模式可以在其内部使用. 例如, 重映射 `a::b` 会发生这样的情况: 1) 输入 "a" 时会映射为 "b"; 2) 输入大写字母 "A" 时映射为大写字母 "B"; 并且 3) 按下 `Ctrl`+`A` 时映射为按下 `Ctrl`+`B`.

SendRaw 或 ControlSendRaw 不支持 `{Blind}` ; 请使用 `{Blind}{Raw}` 代替.

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`(在 2k/XP 中使用 SetCapsLockState 更可靠). 发送 {CapsLock} 之前可能要求 `SetStoreCapsLockMode Off`.
{ScrollLock} | `ScrollLock`(另请参阅: SetScrollLockState)
{NumLock} | `NumLock`(另请参阅: SetNumLockState)
{Control} 或 {Ctrl} | `Ctrl`(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)(译者注: 中性 Ctrl 键 VK 11, SC 01D)
{LControl} 或 {LCtrl} | 左 `Ctrl` (技术信息: 发送左边键的虚拟键码而不是中性键)(译者注: 左 Ctrl 键 VK A2, SC 01D)
{RControl} 或 {RCtrl} | 右 `Ctrl`(译者注: 右 Ctrl 键 VK A3, SC 11D)
{Control down} 或 {Ctrl down} | 按住 `Ctrl` 直到发送 {Ctrl up}. 要按住左边或右边的键, 请使用 {RCtrl down} 和 {RCtrl up}.
{Alt} | `Alt`(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)(译者注: 中性 Alt 键 VK 12, SC 038)
{LAlt} | 左 `Alt`(技术信息: 发送左边键的虚拟键码而不是中性键)(译者注: 左 Alt 键 VK A4, SC 038)
{RAlt} | 右 `Alt`(或 `AltGr`, 取决于键盘布局)
{Alt Down} | 按住 `Alt` 直到发送 {Alt up}. 要按住左边或右边的键, 请使用 {RAlt down} 和 {RAlt up}.
{Shift} | `Shift`(技术信息: 发送中性键的虚拟键码和左边键的扫描码)(译者注: 中性 Shift 键 VK 10, SC 02A)
{LShift} | 左 `Shift`(技术信息: 发送左边键的虚拟键码而不是中性键)(译者注: 左 Shift 键 VK A0, SC 02A)
{RShift} | 右 `Shift`
{Shift down} | 按住 `Shift`直到发送 {Shift up}. 要按住左边或右边的键, 请使用 {RShift down} 和 {RShift up}.
{LWin} | 左 `Win`
{RWin} | 右 `Win`
{LWin down} | 按住左 `Win` 直到发送 {LWin up}
{RWin down} | 按住右 `Win` 直到发送 {RWin up}
{AppsKey} | `Menu`(调用右键点击或上下文菜单)
{Sleep} | `Sleep`.
{ASC nnnnn} | 发送 `Alt`+nnnnn 小键盘上的按键组合, 可以用来生成键盘上不存在的特殊字符. 要生成 ASCII 字符, 请指定一个介于 1 和 255 之间的数字. 要生成 ANSI 字符(在大多数语言中的标准), 请指定一个介于 128 和 255 之间的数字, 但需要在数字前加上一个前导零, 例如 {Asc 0133}. 要生成 Unicode 字符, 请指定一个介于 256 和 65535 之间的数字(不带前导零). 但是, 有些应用程序不支持这种方法. 对于替代方法, 请参阅下面的部分.
{U+nnnn} | [AHK_L 24+]: 发送 Unicode 字符, 其中 nnnn 为不包括 0x 前缀的字符的十六进制值. 在 AutoHotkey 的 Unicode 版本中通常不需要这么做, 因为它包含的 Send 和 ControlSend 自动支持 Unicode 文本. 使用 SendInput() 或 WM_CHAR 发送这个字符而当前的发送模式无效. 以这种方式发送的字符通常不会触发快捷键或热键.
{vkXX} {scYYY} {vkXXscYYY} | 发送一个虚拟按键为 XX 且扫描码为 YYY 的键击. 例如: `Send {vkFFsc159}`. 如果省略了 sc 或 vk 部分, 则会发送最适当的值. XX 和 YYY 是十六进制值, 通常可以在主窗口的 View->Key history 菜单项找到. 另请参阅: 特殊按键 警告: 以这种方式组合 vk 和 sc, 仅在 Send 命令中有效. 在 [v1.1.27] 之前, 热键也允许使用, 但忽略 XX 后的任何非十六进制字符.
{Numpad0} - {Numpad9} | 小键盘上的数字键(与 `NumLock` 打开时输入的一样). 例如: {Numpad5} 为数字 `5`.
{NumpadDot} | `.`(小键盘上的点)(与 `NumLock` 打开时输入的一样).
{NumpadEnter} | 小键盘上的 `Enter`
{NumpadMult} | 小键盘上的 `*`(乘)
{NumpadDiv} | 小键盘上的 `/`(除)
{NumpadAdd} | 小键盘上的`+`(加)
{NumpadSub} | 小键盘上的 `-`(减)
{NumpadDel} | 小键盘上的 `Del`(此键和后面的小键盘按键是在 `NumLock` 关闭时输入的)
{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} | 主音量静音/取消静音. 通常相当于 `SoundSet, +1, , mute`.
{Volume_Down} | 减小主音量. 通常相当于 `SoundSet -5`.
{Volume_Up} | 增加主音量. 通常相当于 `SoundSet +5`.
{Media_Next} | 在媒体播放器中播放下一曲目
{Media_Prev} | 在媒体播放器中播放前一曲目
{Media_Stop} | 停止媒体播放器
{Media_Play_Pause} | 播放/暂停媒体播放器
{Launch_Mail} | 启动电子邮件程序
{Launch_Media} | 启动媒体播放器
{Launch_App1} | 启动用户程序 1
{Launch_App2} | 启动用户程序 2
{PrintScreen} | `PrtScr`
{CtrlBreak} | `Ctrl`+`Break`
{Pause} | `Pause`
{Click [选项]} [v1.0.43+] | 使用与 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 决定. WheelLeft/Right 需要 [v1.0.48+], 并且在 Windows Vista 之前的操作系统中没有效果. LButton 和 RButton 在 Send 中对应的是 "物理的" 左键和右键, 而在热键中对应的是 "逻辑" 左键和右键. 换句话说, 如果用户通过系统设置调换了按钮, `{LButton}` 会执行逻辑右键, 但物理左键会激活 `RButton::` 热键. `{RButton}` 和 `LButton::` 也是如此. 要始终执行逻辑点击, 请使用 {Click} 来代替.
{Blind} | 启用盲从模式, 通过禁用一些通常自动完成的任务, 从而使脚本更容易控制, 使事情按预期工作. 字符串 `{Blind}` 必须出现在字符串的开头.
{Raw} [v1.0.43+] | 启用原始模式, 这将导致以下字符被原义解释: `^+!#{}`. `{Raw}` 可以不放在按键序列的开始处, 在按键序列中出现时, 它会影响它后面的剩余部分.
{Text} [v1.1.27+] | 启用文本模式, 发送字符流而不是按键. 像原始模式一样, 文本模式导致以下字符被解释为原义: `^+!#{}`. 尽管字符串 `{Text}` 不需要在字符串的开始处出现, 但是一旦指定, 它将对字符串的其余部分生效.

## 重复或按住按键

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

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

按住或释放按键: 把按键名称和单词 Down 或 Up 写入到大括号中. 例如:

    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` 的击键. DownTemp 和 DownR 可以用来覆盖这种行为. 除了修饰键(Control, Shift, Alt 和 Win) DownTemp 和 DownR 与 Down 相同.

DownTemp 告诉随后的 Send, 按键不是永久按下的, 并且可以在按键调用时被释放. 例如, `Send {Control DownTemp}` 后面跟着 `Send a` 会产生一个 `A`, 而不是 `Ctrl`+`A`. 任何 Send 的使用都可能会永久释放修饰符, 所以 DownTemp 对于重映射修饰键是不理想的.

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

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

## 一般说明

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

- SendEvent 和 SendInput 带有 KEYEVENTF_UNICODE flag 的 SendInput(). [v1.1.27+]: 在发送之前, ANSI 版本的 AutoHotkey 将字符转换为 Unicode. 在 v1.1.27 之前, ANSI 版本使用了 Alt+nnnnn 方法.
- SendPlay 使用 Alt+nnnnn 方法, 仅在目标应用程序支持的情况下才生成 Unicode.
- ControlSend 发布 WM_CHAR 消息.

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

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

- 如果只是发送字母(即没有修饰符或大括号), 或如果原始模式生效中, 则将其作为字符发送. 例如, `Send {Raw}Regards` 发送预期的文本, 即使按住 `R`(vk52) 产生其他一些字符(例如 `к` 在俄语键盘). 在这种情况下, `{Raw}` 可以省略, 除非一个修饰键被前一个 Send 所实现.
- 如果一个或多个修饰键已经通过 Send 命令生效, 或者如果该字母包裹在大括号中, 它将作为键码发送(如果字母为大写则用 `Shift` 修饰). 这使脚本可以更容易地激活标准键盘快捷键. 例如, `^c` 和 `{Ctrl down}c{Ctrl up}` 激活标准的 `Ctrl`+`C` 快捷键, 而 `{c}` 等同于 `{vk43}`.

如果字母存在于当前的键盘布局中, 则始终以键盘布局与该字母关联的任何键码(除非使用文本模式, 在这种情况下该字符以其他方式发送) 的形式发送. 换句话说, 上面的部分只适用于非拉丁语的布局, 如俄语.

修饰键状态: 当 Send 需要更改 `Win` 或 `Alt` 修饰键的状态时(例如, 如果用户正在按住其中一个键), 它可能会注入更多击键(默认情况下为 `Ctrl`), 以防止出现开始菜单或窗口菜单, 有关详细信息, 请参阅 #MenuMaskKey.

BlockInput 与 SendInput/SendPlay 的比较: 尽管可以使用 BlockInput 命令防止用户输入的任何键击扰乱模拟键击流, 但使用 SendInput 或 SendPlay 通常更好, 这样键击和鼠标点击会保持连续. 这是由于与 BlockInput 不同, SendInput/Play 不会丢弃发送期间用户输入的内容; 作为替代, 这些键击被缓冲起来在之后发送.

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

由于操作系统不允许程序模拟 `Ctrl`+`Alt`+`Del` 组合键, 所以执行像 `Send ^!{Delete}` 的命令不会产生效果.

当活动窗口以管理权限运行而当前脚本不是时, Send 在 Windows Vista 或更高版本中可能没有效果. 这是由于用户接口和特权分离的安全机制.

## SendInput [v1.0.43+]

由于 SendInput 突出的速度和可靠性, 通常为发送键击和鼠标点击的首选方法. 在大多数情况下, SendInput 是近乎瞬时发送的, 即使在发送长字符串也是如此. 由于 SendInput 如此快速, 所以也更可靠, 因为这样其他一些窗口更没有机会出乎意料地弹出并打断正发送的键击. 可靠性进一步提升是通过把用户在 SendInput 发送期间输入的内容推迟的情况而言.

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

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

如果执行 SendInput 脚本外的 其他 脚本安装了低级键盘钩子, 则 SendInput 会自动恢复为 SendEvent(或 SendPlay, 当 `SendMode InputThenPlay` 有效的时候). 这是由于外部钩子的存在让 SendInput 失去了所有的优势, 使它不如 SendPlay 和 SendEvent 两者. 然而, 在 [AutoHotkey v1.0.43+] 之前的版本中 SendInput 无法检测到底层键盘钩子, 在这种情况下将不会自动恢复使得比 SendPlay/Event 更不可靠.

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

## SendPlay [v1.0.43+]

警告: SendPlay 在 UAC 启用时完全失效, 即使是使用管理员权限运行脚本. 详情参见 FAQ.

比起其他模式 SendPlay 最大的优势是具有在相当多种游戏中 "play back" 键击和鼠标点击能力. 例如, 某种特殊的游戏可能仅接受 SendPlay 选项的热字串. 但是, SendPlay 在启用了用户账户控制的 Windows Vista 或更高版本中则可能没有效果, 即使以管理员运行脚本. 下面的脚本提供了此问题的变通解决方法: https://www.autohotkey.com/forum/topic75595.html.

在三种发送模式中, SendPlay 是最不常用的, 因为它本身并不模拟键击和鼠标点击. 作为替代, 它制造一系列事件(消息) 直接流向活动窗口(类似于 ControlSend, 但在更低的层面). 因此 SendPlay 不会触发热键或热字串.

和 SendInput 一样, SendPlay 的键击不会夹杂用户输入的内容. 因此, 如果用户碰巧在 SendPlay 发送期间输入了一些内容, 则它们会被延迟到发送完后.

尽管 SendPlay 明显比 SendInput 慢, 但它通常比传统的 SendEvent 模式更快(即使在 KeyDelay 为 -1 时).

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

SendPlay 不使用 SetKeyDelay 和 SetMouseDelay 的标准设置. 作为替代, 它默认没有延迟, 这可以像下面例子演示的那样改变:

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

SendPlay 不能切换 `CapsLock`, `NumLock` 或 `ScrollLock` 按键的状态. 同样地, 如果键击发送到脚本自身的窗口时, 则它才能改变由 GetKeyState() 获取的按键状态. 即使在此时, 对左/右修饰键的任何改变(例如 RControl) 只能通过它们的中性副本检测到(例如 Control). 并且, SendPlay 还有在 SendMode 页面描述的其他限制.

与 SendInput 和 SendEvent 不同, 用户通过按下 `Ctrl`+`Alt`+`Del` 或 `Ctrl`+`Esc` 打断 SendPlay 的发送. 这种情况发生时, 剩余的键击不会被发送, 不过脚本会像 SendPlay 正常结束一样继续执行.

尽管 SendPlay 能发送 LWin 和 RWin 事件, 但它们被直接发送到活动窗口而不执行它们原本的操作系统功能. 要变通解决此问题, 请使用 SendEvent. 例如, `SendEvent #r` 会显示开始菜单的运行对话框.

## 相关

SendMode, SetKeyDelay, SetStoreCapsLockMode, 转义序列(例如 `%), 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.

dftg