# 热字串

## 目录

- 入门和简单示例
- 终止符
- 选项
- 超长替换
- 上下文相关的热字串
- 自动更正
- 备注
- 函数热字串 [v1.1.28+]
- 热字串助手

## 入门和简单示例

尽管热字串主要用于在您输入缩写时进行扩展(自动替换), 但是它们也可以用来运行任何脚本动作. 从这个角度看, 它们类似于热键, 只是它们通常由多个字符组成(即字符串).

要定义热字串, 请用两个双冒号包围用来触发的缩写, 例如:

    ::btw::by the way

在上面的例子中, 每当您输入缩写 btw 时会被自动替换为 "by the way"(不过, 默认情况下您必须在输入 btw 后输入终止符, 例如 `Space`, `.` 或 `Enter`).

上面的 "by the way" 示例被称为自动替换热字串, 因为输入的文本被自动替换为第二个双冒号后指定的字符串. 与之相比, 热字串还可以定义用来执行任何自定义动作, 例如. 注意命令必须放在热字串的 下面.

    ::btw::
    MsgBox You typed "btw".
    return

    :*:]d::  ; 此热字串通过后面的命令把 "]d" 替换成当前日期和时间.
    FormatTime, CurrentDateTime,, M/d/yyyy h:mm tt  ; 看起来会像 9/1/2005 3:53 PM 这样
    SendInput %CurrentDateTime%
    return

尽管上面的两个例子不是自动替换的热字串, 但默认情况下您输入的缩写也会被擦除. 这是通过自动退格来实现的, 此特性可以通过 b0 选项禁用.

## 终止符

除非使用了星号选项, 否则您必须在热字串的缩写后输入 终止符 才能触发它. 终止符最开始由以下内容组成: -()[]{}':;"/\,.?!`n `t(注意 `n 是 `Enter`, `t 是 `Tab`, 且在它们之间还有一个原义的空格). 可以通过编辑下列的示例来更改这个字符集合, 这个例子中为 所有的 热字串设置新的终止符, 而不仅是在它下面的那些.

    #Hotstring EndChars -()[]{}:;'"/\,.?!`n `t

[v1.1.28+]: 当脚本运行时通过调用 Hotstring() 函数, 可以更改结束字符, 正如下面文档所述:

    Hotstring("EndChars", "-()[]{}:;")

## 选项

可以使用下面的两种方式改变热字串的默认行为:

1. #Hotstring 指令, 它会影响脚本中实际在它后面的所有热字串. 下列示例会让 C 和 R 选项生效: `#Hotstring c r`.
2. 把选项放在热字串的第一个双冒号之间. 下列示例会让 C 和 * 选项(区分大小写且 "不需要终止符") 对当前热字串生效:
   `:c*:j@::john@somedomain.com`.

下面列表中对每个选项进行说明. 当使用上面的方法指定多个选项时, 可以在选项间包含空格.

*(星号): 不需要终止符(即空格, 句点或回车) 来触发热字串. 例如:

    :*:j@::jsmith@somedomain.com

上面的示例会在您输入 @ 字符时立即进行替换. 如果在 #Hotstring 指令中含有此选项, 那么可以使用 *0 来关闭它.

?(问号): 即使此热字串在另一个单词中也会被触发; 即, 在字符串被混排前立即输入字符. 例如, 如果 `:?:al::airline` 为热字串, 那么输入 "practical " 会得到 "practicairline ". 使用 ?0 来关闭此选项.

B0(B 后跟着零): 不 进行自动退格来擦除您输入的缩写. 关闭此选项后可以使用 B 来启用. 脚本还可以通过 {bs 5} 实现自己的退格, 这里发送 5 次 `Backspace`. 同样地, 可以通过 {left 5} 发送 5 次 `←` 的键击. 例如, 下面的热字串产生 "<em></em>" 并把光标向左移动 5 个位置(这样它就在标签之间了):

    :*b0:<em>::</em>{left 5}

C: 区分大小写: 当您输入缩写时, 它必须准确匹配脚本中定义的大小写形式. 使用 C0 可以关闭区分大小写的特性.

C1: 不遵循输入的大小写形式. 使用此选项可以让自动替换热字串不区分大小写且阻止它们遵循您实际输入字符的大小写形式. 遵循大小写形式的热字串(这是默认状态) 会在您输入的缩写都为大写时产生大写形式的的替换文本. 如果您的输入的首字母为大写, 那么替换的首字母也会为标题格式(大写, 如果首个字符是字母). 您按其他任何大小写形式输入时, 替换会准确按照定义进行发送. 如果在 #Hotstring 指令中含有此选项, 那么可以使用 C0 来关闭它, 这样可以让热字串重新遵循大小写.

Kn: 按键延迟: 这个非常少用的选项设置在自动退格或自动替换产生的键击之间的延迟. 给 n 指定新的延迟; 例如, 指定 k10 来设置 10 ms 的延迟而 k-1 则取消延迟. 此选项的实际效果取决于当前生效的发送模式:

- SI(SendInput): 由于此模式是没有延迟的, 所以按键延迟会被忽略. 例外是当 SendInput 不可用时, 此时热字串会恢复到下面的 SendPlay 模式(它会遵循按键延迟).
- SP(SendPlay): 默认延迟为零, 这对于 SendPlay 相当于 -1(没有延迟). 此模式中, 这个延迟实际是按住时长而不是键击之间的延迟.
- SE(SendEvent): 默认延迟为零. 在大多情况下建议使用零的延迟, 因为这样快速且与其他进程配合比较好(由于会内部执行 Sleep 0). 指定 k-1 则不使用延迟, 这样可以在您 CPU 经常高负荷运行时让自动替换更快速地进行. 设置为 -1 时, 脚本的进程优先级会成为键击发送速度的重要因素. 要提升脚本的优先级, 请使用 `Process, Priority,, High`.

O: 进行替换时忽略自动替换热字串的终止符. 它可以用于当您希望使用终止符让热字串保持清晰, 却不希望终止符显示在屏幕上的时候. 例如, 如果 `:o:ar::aristocrat` 为热字串, 那么输入 "ar" 后跟着空格键会产生不含尾随空格的 "aristocrat", 这样可以让您在不需要 `Backspace` 的情况下补上单词的复数或所有格形式. 使用 O0(字母 O 后跟着零) 来关闭此选项.

Pn: 字符串的优先级(例如 P1). 这个非常少用的选项对自动替换热字串没有效果.

R: 发送替换文本的原始文本; 即准确地按照原样发送, 而不把 {Enter} 转换成 `Enter`, 把 ^c 转换成 `Ctrl`+`C`, 等等. 此选项在含延续片段热字串中自动生效. 使用 R0 来关闭此选项.

注意: Text 模式可能更可靠. R 选项和 T 选项是相互排斥的.

SI, SP 或 SE [v1.0.43+]: 设置自动替换热字串发送键击的方法. 这些选项是互相排斥的: 每次只会有一个生效. 下面对每个选项进行说明:

- SI 表示 SendInput, 它通常比其他模式拥有较好的速度和可靠性. 另一个好处是和下面的 SendPlay 一样, SendInput 会在热字串自动替换文本时会延迟您输入的内容. 这样避免了您的键击穿插到替换的内容中. 当 SendInput 不可用时, 热字串会自动使用 SendPlay.
- SP 表示 SendPlay, 它可以让热字串运行在更大范围的游戏中.
- SE 表示 SendEvent, 在比 [1.0.43] 早的版本中这是默认选项.

如果未使用上面的任何一个选项, 则在 v1.0.43 及更高的版本中默认模式为 SendInput. 然而, 与 SI 选项不同的是, 在 SendInput 不可用时会使用 SendEvent 而不是 SendPlay.

T [v1.1.27+]: 发送替换文本的原始文本, 不需要将每个字符转换成按键. 有关详情, 请参阅 Text 模式. 使用 T0 或 R0 关闭此选项, 或使用 R 覆盖它.

X [v1.1.28+]: 执行. 取代替换文本, 热字串接受一个命令或表达式来执行. 例如, `:X:~mb::MsgBox` 会在用户输入 "~mb" 时显示一个消息框, 而不是用 "MsgBox" 自动替换. 在定义大量热字串调用函数时, 这是最有用的, 否则每一个热字串就需要三行.

当使用热字串函数时, X 选项会导致 替换 参数被解释为标签或函数名, 而不是替换文本. 但是, X 选项只有在每次调用函数时才有这种效果.

Z: 这个非常少用的选项会在每次热字串触发后重置热字串识别器. 换句话说, 脚本将开始等待全新的热字串, 而不考虑您之前输入的任何内容. 这可以避免意外地触发字符串. 为了进行说明, 请思考下面的字符串:

    :b0*?:11::
    SendInput xx
    return

由于上面没有使用 Z 选项, 所以输入 111(三个连续的 1) 会触发热字串两次, 因为中间的 1 既是首次触发的 末尾 字符, 又是第二次触发的 起始 字符. 在 b0 前面加上字母 Z 后, 您必须输入四个 1 而不是三个才能触发热键两次. 使用 Z0 来关闭此选项.

## 超长替换

使用延续片段的方法可以让产生大量替换文本的热字串变得更具可读性和可维护性. 例如:

    ::text1::
    (
    括号(顶部和底部) 之间的任何文本都按原义处理, 包括逗号和百分号.
    默认情况下, 前一行与此行之间的硬回车(Enter) 也会保留.
        默认情况下, 保留此行左侧的缩进(制表符).
    )

有关如何更改这些默认行为的信息, 请参阅延续片段. 使用延续片段后也会使热字串默认为原始模式. 覆盖此特性的唯一方法是在每个含延续片段的热字串中指定 r0 选项(例如 `:r0:text1::`).

## 上下文相关的热字串

使用 #IfWinActive/Exist 指令可以让选择的热字串产生上下文相关性. 这样的热字串会根据窗口是否活动或存在的不同情况发送不同的替换, 执行不同的动作或什么都不做. 例如:

    #IfWinActive ahk_class Notepad
    ::btw::This replacement text will appear only in Notepad.
    #IfWinActive
    ::btw::This replacement text appears in windows other than Notepad.

## 自动更正

后面的脚本使用热字串即时更正大约 4700 常见的英文拼写错误. 它还包含了 `Win`+`H` 热键来方便地添加更多拼写错误:

下载: AutoCorrect.ahk(127 KB)

作者: Jim Biancolo 和 维基百科的常见拼写错误列表

## 备注

替换文本中当前不支持例如 `%MyVar%` 这样的变量引用. 要解决此问题, 请不要让这样的热字串自动替换. 而是在缩写的下面使用 SendInput 命令, 后跟着仅包含单词 Return 的行.

要在替换文本后发送额外的空格或 tab, 可以把它们加在替换文本后, 但需要在末尾加上重音符/反引号(`). 例如:

    :*:btw::By the way `

默认情况下, 鼠标左键或右键的任何点击都会重置热字串识别器. 换句话说, 脚本将开始等待全新的热字串, 而不考虑您之前输入的任何内容(如果您不希望这样, 请在脚本的任意位置指定 `#Hotstring NoMouse` 这行). 在 "鼠标点击时重置" 的行为是默认的, 因为每次点击通常会移动插入点(光标) 或设置键盘焦点到新的控件/区域. 在这种情况下, 通常希望: 1) 即使没有问号选项也触发热键; 2) 防止您在点击鼠标后输入的一些内容与之前输入的内容意外形成有效的缩写从而触发热字串.

每次输入字符时, 热字串识别器会检查当前活动窗口, 并且如果活动窗口不同于之前, 则会重置. 如果活动窗口发生变化, 但在键入任何字符之前返回, 则不会检测到更改(但可能会由于其他原因重置热字串识别器). 热字串识别器也可以通过调用 `Hotstring("Reset")` 来重置.

内置变量 A_EndChar 包含了触发最近的非自动替换热字串时的终止符. 如果不需要终止符(使用了 * 选项), 那么它会被置空. A_EndChar 可以用于使用 Send 命令的热字串或根据您输入的不同终止符改变行为的那些热字串. 要发送终止符自身, 请使用 `SendRaw %A_EndChar%`(使用 SendRaw 是因为普通的 Send 命令无法正确发送类似 !{} 这样的字符).

尽管在热字串定义中的逗号, 百分号和单冒号不需要进行转义, 但反引号和那些在空格或 tab 右边的分号则需要. 请参阅转义序列了解完整的列表.

尽管在自动替换文本(在没有使用原始选项时) 中支持 Send 命令的特殊字符例如 {Enter}, 但热字串自身却不使用这种方式. 而是使用 `n 表示 `Enter`, `t(或原义的 tab) 表示 `Tab`(请参阅转义序列了解完整的列表). 例如, 当您输入 "ab" 后跟着 tab 时会触发热字串 `:*:ab`t::`.

热字串会原义地处理在它的定义中的空格和 tab. 例如后面的热字串会产生两种不同的效果: `::btw::by the way` 和 `::btw:: by the way`.

每个热字串缩写的长度不能超过 40 个字符. 超出此长度后程序会向您提出警告. 与之相比, 当发送模式为默认的 SendInput 时热字串的替换文本的长度限制约为 5000 个字符. 通过切换到其他发送模式可以把此限制增加到 16,383 字符. 此外, 在热字串的替换文本部分使用 `SendPlay %MyVariable%` 可以发送不限数量的文本.

热字串的定义顺序决定了它们的相对优先级. 换句话说, 如果多个热字串匹配您输入的内容, 那么只有脚本中首先列出的那个会生效. 相关主题: 上下文相关热字串.

为了识别热字串, 您输入的所有退格都会被计算进来. 然而, 使用`↑`, `→`, `↓`, `←`, `PgUp`, `PgDn`, `Home` 和 `End` 在编辑器中导航会重置热字串识别过程. 换句话说, 它会开始等待全新的热字串.

即使当前活动窗口忽略您的键击时也可以输入热字串. 换句话说, 即使触发的缩略词不可见时热字串仍会被触发. 此外, 您还可以使用 `Backspace` 键撤销最近输入的键击(尽管您无法看到效果).

可以 Gosub 或 Goto 到热字串标签, 只需在热字串的标签名称前包含第一个双冒号(以及所有选项符号). 例如: `Gosub ::xyz`. 然而, 跳转到单行(自动替换) 热字串会除了执行 return 外什么都不做.

尽管不会监视热字串且在不可见的 Input 命令执行时也不会触发它们, 但是可见的 Input 却能触发它们.

默认情况下, 由任何 AutoHotkey 脚本生成的键击永远不会触发热字串. 这避免了热字串彼此反复地触发而形成的无限循环的可能性. 在 [v1.1.06] 及更高版本中, 此行为可以使用 #InputLevel 和 SendLevel 进行控制. 然而, 自动替换型热字串的发送级别总为 0, 因此永远不会触发钩子热键或热字串.

[v1.1.28+]: 热字串可以通过热字串函数动态创建, 它还可以单独修改, 禁用, 或启用脚本的现有的热字串.

在某些时候 Input 命令比热字串更灵活. 例如, 它可以对活动窗口(例如游戏) 隐藏您的键击. 它还支持非字符型的终止键, 例如 `Esc`.

任何包含热字串的脚本会自动使用键盘钩子.

在下面的情况中热字串与热键具有相同的特性:

- 它们都受 Suspend 命令影响.
- 它们都遵循 #MaxThreads 和 #MaxThreadsPerHotkey 的设置(但不遵循 #MaxThreadsBuffer).
- 包含热字串的脚本会自动变成持续运行的.
- 非自动替换热字串在运行时会创建新的线程. 此外, 它们会更新内置热键变量, 例如 A_ThisHotkey.

已知限制: 在某些系统上的 Java 应用程序中, 热字串可能会干扰用户输入变音符字母(附加符号, 例如 á, à, è, ü 通过 dead 键). 为了解决此问题, 可以临时打开 Suspend(这样禁用了所有热字串).

## 函数热字串 [v1.1.28+]

紧跟在热字串标签后面的函数, 通过简单的定义, 一个或多个热字串可以关联到此函数, 如下例所示:

    ; 这个示例还演示了在脚本中实现大小写一致性的一种方法.
    :C:BTW::  ; 输入所有大写字母.
    :C:Btw::  ; 只有第一个字母输入大写字母.
    : :btw::  ; 输入任何其他组合.
        case_conform_btw() {
            hs := A_ThisHotkey  ; 为了方便, 以防被打断.
            if (hs == ":C:BTW")
                Send BY THE WAY
            else if (hs == ":C:Btw")
                Send By the way
            else
                Send by the way
        }

有关其他细节, 请参阅函数热键.

还可以使用热字串函数将热字串关联到函数或函数对象.

## 热字串助手

Andreas Borutta 推荐了下面的脚本, 如果您是深度的热字串用户, 那么它会很有用. 使用 `Win`+`H`(或您选择的其他热键), 可以把当前选择的文本转变成热字串. 例如, 如果您在文字处理软件中选择了 "by the way", 按下 `Win`+`H` 会提示您输入其缩写(例如 btw), 然后把新热字串添加到脚本中. 之后会重新载入脚本来激活热字串.

注意: 可以使用热字串函数创建新的热字串而不需要重新加载. 查看函数页面示例部分中的示例 1, 看看如何实现它.

    #h::  ; Win+H 热键
    ; 获取当前选择的文本. 使用剪贴板代替
    ; "ControlGet Selected", 是因为它可以工作于更大范围的编辑器
    ; (即文字处理软件). 保存剪贴板当前的内容
    ; 以便在后面恢复. 尽管这里只能处理纯文本,
    ; 但总比没有好:
    AutoTrim Off  ; 保留剪贴板中任何前导和尾随空白字符.
    ClipboardOld := ClipboardAll
    Clipboard := ""  ; 必须清空, 才能检测是否有效.
    Send ^c
    ClipWait 1
    if ErrorLevel  ; ClipWait 超时.
        return
    ; 替换 CRLF 和/或 LF 为 `n 以便用于 "发送原始模式的" 热字串:
    ; 对其他任何在原始模式下可能出现问题
    ; 的字符进行相同的处理:
    StringReplace, Hotstring, Clipboard, ``, ````, All  ; 首先进行此替换以避免和后面的操作冲突.
    StringReplace, Hotstring, Hotstring, `r`n, ``r, All  ; 在 MS Word 等软件中中使用 `r 会比 `n 工作的更好.
    StringReplace, Hotstring, Hotstring, `n, ``r, All
    StringReplace, Hotstring, Hotstring, %A_Tab%, ``t, All
    StringReplace, Hotstring, Hotstring, `;, ```;, All
    Clipboard := ClipboardOld  ; 恢复剪贴板之前的内容.
    ; 这里会移动输入框的光标到更人性化的位置:
    SetTimer, MoveCaret, 10
    ; 显示输入框, 提供默认的热字串:
    InputBox, Hotstring, New Hotstring, Type your abreviation at the indicated insertion point. You can also edit the replacement text if you wish.`n`nExample entry: :R:btw`::by the way,,,,,,,, :R:`::%Hotstring%
    if ErrorLevel  ; 用户选择了取消.
        return
    if InStr(Hotstring, ":R`:::")
    {
        MsgBox You didn't provide an abbreviation. The hotstring has not been added.
        return
    }
    ; 否则添加热字串并重新加载脚本:
    FileAppend, `n%Hotstring%, %A_ScriptFullPath%  ; 在开始处放置 `n 以防文件末尾没有空行.
    Reload
    Sleep 200 ; 如果加载成功, reload 会在 Sleep 期间关闭当前实例, 所以永远不会执行到下面的语句.
    MsgBox, 4,, The hotstring just added appears to be improperly formatted. Would you like to open the script for editing? Note that the bad hotstring is at the bottom of the script.
    IfMsgBox, Yes, Edit
    return

    MoveCaret:
    if not WinActive("New Hotstring")
        return
    ; 否则移动输入框中的光标到用户输入缩写的位置.
    Send {Home}{Right 3}
    SetTimer, MoveCaret, Off
    return

dftg