# Send, SendText, SendInput, SendPlay, SendEvent

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

    Send Keys
    SendText Keys
    SendInput Keys
    SendPlay Keys
    SendEvent Keys

## 参数

Keys

  类型: 字符串

  要发送的按键序列.

  默认情况下(也就是说, 如果既不使用 SendText, 也不使用原始模式或文本模式), 字符 `^+!#{}` 具有特殊含义. 字符 `^+!#` 分别代表修饰符键 `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`, 而 `{!}` 是原义的感叹号.

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

## Send 的变体

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

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

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

SendEvent: SendEvent 使用 Windows keybd_event 函数发送键击(有关详情, 请搜索 MSDN). 发送击键的速率由 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}` 必须是字符串中的第一个项目. 它具有以下效果:

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

单词 "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}. 要按住左边或右边的键, 请使用 {RCtrl down} 和 {RCtrl up}.
{Alt} | `Alt`(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)
{LAlt} | 左 `Alt`(技术信息: 发送左边键的虚拟键码而不是中性键)
{RAlt} | 右 `Alt`(或 `AltGr`, 取决于键盘布局)
{Alt down} | 按住 `Alt` 直到发送 {Alt up}. 要按住左边或右边的键, 请使用 {RAlt down} 或 {RAlt up}.
{Shift} | `Shift`(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)
{LShift} | 左 `Shift`(技术信息: 发送左边键的虚拟键码而不是中性键)
{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} | 发送 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.

按住或释放按键: 用大括号括起按键名称和单词 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 可以用来覆盖这种行为. DownTemp 和 DownR 与 Down 具有同样的效果, 除了修饰键(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. 按键: 默认情况下, 先将字符转换为按键来发送字符. 如果这种转换是不可能的(即, 如果当前的键盘布局不包含产生该字符的键或键组合), 则通过以下回退方法之一来发送字符:

- SendEvent 和 SendInput 使用带有 KEYEVENTF_UNICODE 标志的 SendInput().
- SendPlay 使用 Alt+nnnnn 方法, 只有在目标应用程序支持的情况下才会产生 Unicode 字符.
- ControlSend 发布 WM_CHAR 消息.

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

对于 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`) 来阻止开始菜单或窗口菜单的出现. 有关详情, 请参阅 A_MenuMaskKey.

BlockInput 对比 SendInput/SendPlay: 尽管 BlockInput 函数可以用来防止用户物理输入的任何按键破坏模拟按键的流, 但通常最好使用 SendInput 或 SendPlay 这样按键和鼠标点击就不会中断. 这是因为与 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 会自动恢复为 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 不使用 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, 转义序列(例 `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."

dftg