AutoHotkey 脚本和宏

AutoHotkey

脚本

目录

简介

每个脚本都是纯文本文件, 其中包含了可由程序 (AutoHotkey.exe) 执行的文本行. 脚本中还可以包含 热键热字串 或者甚至完全由它们组成. 不过, 在不包含热键和热字串时, 脚本会在启动后从上往下按顺序执行其中的命令.

程序会把脚本逐行加载到内存中, 每行最多可以包含 16,383 个字符. 在加载过程中, 脚本会被 优化 和检查. 将列出所有的语法错误, 更正它们后脚本才能运行.

脚本顶部 (自动执行段)

脚本加载完成后,它会从顶行开始执行,直到遇到 ReturnExit热键/热字串标签 或脚本的底部(无论最先遇到哪个)。脚本的这个顶端部分被称为 自动执行 段.

如果脚本不是 持续运行的 且不含有 热键, 热字串, OnMessageGUI, 那么它会在自动执行段结束后终止. 否则, 它会以空闲状态继续运行, 从而对例如热键, 热字串, GUI 事件, 自定义菜单项计时器 这些事件进行响应.

每个由 热键, 热字串, 菜单项, GUI 事件计时器 启动的 线程 都以在自动执行段设置的下列属性值作为默认值开始. 如果没有设置,则使用标准的默认值(与下面每个页面中注明的一样):DetectHiddenWindowsDetectHiddenTextSetTitleMatchModeSetBatchLinesSendModeSetKeyDelaySetMouseDelaySetWinDelaySetControlDelaySetDefaultMouseSpeedCoordModeSetStoreCapslockModeAutoTrimSetFormatStringCaseSenseThreadCritical

如果自动执行段执行了很长时间才结束 (或从未结束), 上面这些设置的默认值将在 100 毫秒后自动生效. 当自动执行段最终结束 (如果可能) 时, 在自动执行段末尾生效的那些设置才更新为默认值. 因此, 通常最好在包含 热键, 热字串, 计时器自定义菜单项 的脚本顶部设置自己想要的默认值. 还要注意, 每个 线程 会保存它自己的上述设置的集合. 在一个线程中对这些设置的改变不会影响其他 线程.

转义序列

AutoHotkey 中默认的 转义符 为重音符/反引号 (`), 它位于大多数英文键盘的左上角. 使用这个字符而不是反斜线可以避免在文件路径中使用双反斜线.

由于在 AutoHotkey 中逗号和百分号具有特殊含义,因此需要使用 `, 来指定原义的逗号,使用 `% 来指定原义的百分号。其中的一个例外是 MsgBox,它里面的逗号不需要进行转义。另一个例外是在任意命令最后一个参数中的逗号: 它们不需要进行转义. 请参阅 #EscapeChar 了解转义序列的完整列表。

某些特殊的字符也需要使用转义序列的方法生成. 最常见的有 `t(tab)、`n(换行)和 `r(回车)。

提示: 任何命令中的首个逗号可以省略 (除非首个参数为空或以 := 或 = 开始, 或命令单独处于 延续片段 的顶部). 例如:

MsgBox This is ok.
MsgBox, This is ok too (it has an explicit comma).

在脚本中添加注释

在行首使用分号可以注释当前行脚本. 例如:

; 这整行是注释.

也可以在命令的末尾添加注释, 此时分号左侧必须至少有一个空格或 tab. 例如:

Run Notepad  ; 这是和命令在同一行的注释.

此外, 可以使用 /* 和 */ 符号注释整块代码, 但仅当它们出现在行首时才有效, 例如:

/*
MsgBox, This line is commented out (disabled).
MsgBox, This one too. 
*/

由于脚本运行时会忽略注释, 所以它们不会影响脚本性能或占用内存.

使用 #CommentFlag 可以把默认的注释符 (分号) 改为其他字符或字符串.

把过长的行分割成一系列短行

可以把过长的行分割成一系列较短的行来提高可读性和可维护性. 这样不会降低脚本的执行速度, 因为在脚本启动时这些短行会在内存中合并起来.

方法 #1: 以 "and", "or", ||, &&, 逗号或 句点 开始的行会自动合并到其前一行 (在 v1.0.46+, 以除了 ++ 和 -- 外其他所有的 表达式运算符 开头的行也会如此). 在下面的例子中, 第二行会自动附加到首行, 因为它以逗号开始:

FileAppend, This is the text to append.`n   ; 这里可以使用注释.
    , %A_ProgramFiles%\SomeApplication\LogFile.txt  ; 注释.

同样地, 下列几行会合并成单行, 因为最后两行以 "and" 或 "or" 开始:

if (Color = "Red" or Color = "Green"  or Color = "Blue"   ; 注释.
    or Color = "Black" or Color = "Gray" or Color = "White")   ; 注释.
    and ProductIsAvailableInColor(Product, Color)   ; 注释.

三元运算符 也是个不错的选择:

ProductIsAvailable := (Color = "Red")
    ? false  ; 我们没有任何红色产品, 所以不用那么麻烦去调用函数.
    : ProductIsAvailableInColor(Product, Color)

尽管在上面的例子中缩进不是必须的, 但它可以显示出哪些行属于上一行从而提高代码清晰度. 并且, 可以不必在单词 "AND" 和 "OR" 开始的行加上额外的空格; 程序会自动处理这些. 最后, 可以在上面例子中任意行的末尾或行与行之间添加空行或 注释.

方法 #2: 这种方法可以合并大量的行或不适合方法 #1 处理的行. 尽管此方法对 自动替换热字串 特别有用, 但它也可以用于任意命令或 表达式. 例如:

; 示例 #1:
Var =
(
Line 1 of the text.
Line 2 of the text. By default, a linefeed (`n) is present between lines.
)

; 示例 #2:
FileAppend,  ; 此时逗号是不能缺少的.
(
A line of text.
By default, the hard carriage return (Enter) between the previous line and this one will be written to the file as a linefeed (`n).
    By default, the tab to the left of this line will also be written to the file (the same is true for spaces).
By default, variable references such as %Var% are resolved to the variable's contents.
), C:\My File.txt

在上面的例子中, 一系列行被头尾的一对括号包围起来. 这被称为 延续片段. 注意在底行的闭括号后面包含了 FileAppend 的最后一个参数. 这种做法是可选的; 这样做是为了在这种情况下把逗号视为参数分隔符而不是原义的逗号.

通过在延续片段的开括号右侧包含一个或多个下列选项, 可以覆盖它的默认特性. 如果含有多个选项, 那么选项之间使用空格分隔. 例如:( LTrim Join| %

Join: 指定行与行之间连接的方式. 如果省略此选项, 那么除最后一行外的其他行后面都会跟一个换行符 (`n). 如果指定单词 Join 自身, 则行与行之间直接连接而不添加任何字符. 或者在单词 Join 后可以紧跟着多达 15 个字符。例如,Join`s 会在除最后一行外的每行末尾插入一个空格(“`s”表示原义的空格,这是一个只能被 Join 识别的特殊转义序列)。另一个例子是 Join`r`n,它会在行与行之间插入 CR+LF。同样地,Join| 会在行之间插入管道符。要让延续片段的最后一行也以连接字符串结尾, 需要在它的闭括号上一行添加一个空行.

LTrim: 删除每行开头的空格和 tab. 主要用来允许延续片段使用缩进. 此外,通过在一行中指定 #LTrim 自身可以为多个延续片段打开此选项。#LTrim 是与位置有关的::会影响它下面的所有延续片段。通过 #LTrim Off 可以关闭此设置。

RTrim0 (RTrim 后跟着零): 关闭自动删除每行末尾的空格和 tab 的设置.

Comments(或 CommentComC) [v1.0.45.03+]:允许在延续片段中使用分号注释(但不支持 /*..*/)。这样的注释 (以及它们左边的任何空格和 tab) 会在连接时完全被忽略而不是当成原义文本处理. 每个注释可以放在一行的右侧或单独一行.

% (百分号): 把百分号视为原义字符而不是变量引用. 这样避免了需要把每个百分号 转义 成原义字符. 在百分号已经为原义的地方不需要使用此选项, 例如 自动替换热字串.

, (逗号): 把逗号作为分隔符而不是原义逗号. 这个非常少用的选项只有在命令参数之间才需要, 因为在 函数调用 中逗号的类型没有影响. 并且, 此选项只会转换那些真正的分隔参数的逗号. 换句话说, 一旦到达命令的最后一个参数 (或者命令没有参数), 那么会忽略此选项而把后续的逗号当成原义逗号.

` (重音符): 把每个反引号视为原义字符而不是 转义符. 此选项同时也避免了需要分别对逗号和百分号进行明确地转义. 此外, 它还阻止对任何特定的转义序列例如 `r 和 `t 进行转义.

) [v1.1.01+]: 如果在延续片段的选项中使用闭括号 (不是作为 Join 选项的参数), 那么此行被重新解释为表达式而不是延续片段的开始. 这样可以让像 (x.y)[z]() 这样的表达式可以在不需要对开括号进行转义的情况下也有效.

备注

当没有指定 重音符 (`) 选项 时, 支持在延续片段中使用 转义序列, 例如 `n (换行) 和 `t (tab).

没有使用 注释选项 时, 不支持在延续片段中使用分号和 /*..*/ 添加注释, 因为它们会被视为原义文本. 不过, 可以在片段的底行和顶行添加注释. 例如:

FileAppend,   ; 注释.
; 注释.
( LTrim Join    ; 注释.
     ; This is not a comment; it is literal. Include the word Comments in the line above to make it a comment.
), C:\File.txt   ; 注释.

由上面可知, 延续片段中的分号不需要进行 转义.

使用延续片段无法生成总长度超过 16,383 字符的行 (如果尝试这么做, 那么程序在启动时会弹出警告). 解决此问题的一种方法是把一系列内容连接到变量中. 例如:

Var =
(
...
)
Var = %Var%`n  ; 通过另一个延续片段添加更多文本到此变量中.
(
...
)
FileAppend, %Var%, C:\My File.txt

因为闭括号表示延续片段的结束,所以要让某一行以原义的闭括号开头,需要在其前面加上重音符/反引号:`)

一个延续片段后面可以紧跟着包含另一个延续片段的开括号的一行. 这样使得上面提到的选项可以在创建单行的过程中进行改变.

不支持通过 #Include 的方法把延续片段各部分连接起来.

把脚本转换成 EXE (ahk2exe)

在程序中包含了脚本编译器 (承蒙 fincs 提供).

脚本编译完成后,成为了独立的可执行文件;即它甚至可以在没有安装 AutoHotkey 的机器上运行(并且这样的可执行文件可以无限制地发布或出售)。编译过程中会创建包含后面这些文件的可执行文件: AutoHotkey 解释器, 脚本, 脚本 加载 的任何文件以及通过 FileInstall 命令合并的任何文件.

使用 Ahk2Exe 有下列几种方式:

  1. GUI 界面: 运行菜单菜单中的 "Convert .ahk to .exe" 菜单项.
  2. 右键点击: 在资源管理器中, 您可以在任何一个 .ahk 上右键点击并选择 "Compile Script" (只有在安装 AutoHotkey 时选择了脚本编译器时时才可用). 这样创建了与脚本具有相同的主文件名的 EXE 文件, 它会在稍后出现在相同目录中. 注: 这样生成的 EXE 文件会使用与前面的方法 #1 最后一次使用时相同的自定义图标, .bin 文件以及 MPRESS 设置.
  3. 命令行: 编译器可以使用下列参数在命令行中运行:
    Ahk2Exe.exe /in MyScript.ahk [/out MyScript.exe] [/icon MyIcon.ico] [/bin AutoHotkeySC.bin] [/mpress 0or1]
    例如:
    Ahk2Exe.exe /in "MyScript.ahk" /icon "MyIcon.ico"
    用法:
    • 含有空格的参数应该包围在双引号中.
    • 如果省略了 "out" 文件, 则使用脚本的主文件名作为 EXE 的主文件名.

注意:

  • 进行编译通常并不会提升脚本的性能.
  • 截至 v1.1.01, 还不支持密码保护和 /NoDecompile 选项.
  • 如果在 AutoHotkey 安装目录的 "Compiler" 子文件夹中含有 mpress.exe, 则会使用它压缩脚本的可执行文件, 除非通过 /mpress 0 或 GUI 设置把它禁用了. 这样同时压缩了脚本的源代码 (删除了所有注释), 其中的源码可以使用 PE 资源编辑器从可执行文件中提取.
  • 命令 #NoTrayIcon 和 "Menu, Tray, ShowMainWindow" 会影响已编译脚本的行为.
  • 使用类似 Resource Hacker (免费软件) 的工具编辑 "AutoHotkeySC.bin" 文件可以给已编译脚本添加自定义版本信息 (和在资源管理器的文件属性对话框中看到的那些). 此文件包含在 AutoHotkey 安装目录的 "Compiler" 子文件夹中. 可以使用 Compile_AHK II 简化这个过程. 截至 v1.1.01, 可以直接编辑已编译脚本而不是 AutoHotkeySC.bin.
  • 还可以使用上面的方法改变所有已编译脚本现有的图标或为它们添加新图标.
  • 如果脚本以编译的形式运行, 则内置变量 A_IsCompiled 的值为 1. 否则为空.
  • 传递参数到 Ahk2Exe 后, 它会在标准输出中写入表示编译过程成功与否的消息. 尽管此消息不会显示在命令提示符中, 但可以通过像重定向到文件的方法 "捕获". [v1.0.43+]

编译器的源码和新版本可以在 GitHub 找到.

向脚本传递命令行参数

脚本支持命令行参数. 格式为:

AutoHotkey.exe [Switches] [Script Filename] [Script Parameters]

对于已编译脚本, 格式为:

CompiledScript.exe [Switches] [Script Parameters]

Switches: 零个或多个下列开关:
/f 或 /force -- 无条件运行, 跳过任何警告对话框.
/r 或 /restart -- 表示正在重新加载脚本 (内部的 Reload 命令也使用这种方法).
/ErrorStdOut -- 把阻止脚本运行的语法错误发送到标准输出而不显示在对话框中. 请参阅 #ErrorStdOut 了解详情.
/Debug -- [AHK_L 11+]: 连接到调试客户端. 想了解更多细节, 请参阅 交互调试.
/CPn -- [AHK_L 51+]: 指定用来读取脚本文件的代码页. 想了解更多信息, 请参阅 脚本文件代码页.

Script Filename: 如果不含 Script Parameters, 那么此参数可以省略. 省略时, 它会运行 (或提示您创建) 下列默认位置的其中一个文件:

[AHK_L 51+]: %AhkExeDir%\%AhkExeName%.ahk%A_MyDocuments%\%AhkExeName%.ahk, 此处 %AhkExeDir%%AhkExeName% 需要使用运行当前脚本的可执行文件的目录和文件名替换, 不包括 ".exe" 扩展名.

[早期版本]: AutoHotkey.ini (在当前工作目录) 或 %A_MyDocuments%\AutoHotkey.ahk.

Script Parameters: 您想传递给脚本的字符串, 字符串之间使用空格分隔. 任何含有空格的参数应该包围在一对双引号之间. 要传递原义的引号, 需要在其前面加上反斜线 (\"). 因此, 任何引号包围的参数中末尾的反斜线 (例如 "C:\My Documents\") 会让紧跟着的引号被当作原义的引号进行处理 (即脚本会接收到字符串 C:\My Documents"). 要移除这样的引号,请使用 StringReplace, 1, 1, ",, All

脚本把传入的参数视为 变量 %1%, %2% 等. 还有, %0% 包含了传入参数的数目 (没有则为 0). 但是, 无法直接在表达式中引用这些变量, 因为表达式会把它们视为数字而不是变量. 在下面的例子中, 如果传入参数过少则脚本会退出:

if 0 < 3  ; 非表达式 if 语句 的左侧总是变量名.
{
    MsgBox This script requires at least 3 incoming parameters but it only received %0%.
    ExitApp
}

如果传递给脚本的参数数目不确定 (可能由于用户拖放一组文件到脚本上), 可以使用下面的示例逐个提取这些参数:

Loop, %0%  ; 对每个参数进行循环:
{
    param := %A_Index%  ; 取得名称为 A_Index 的值的变量中的内容.
    MsgBox, 4,, Parameter number %A_Index% is %param%.  Continue?
    IfMsgBox, No
        break
}

如果这些参数是文件名,那么可以使用下列的例子把它们转换到大小写正确的长名称(与文件系统中存储的一致),其中包含完整/绝对的路径。

Loop %0%  ; 对每个参数 (或放到脚本上的文件) 进行循环:
{
    GivenPath := %A_Index%  ; 取得名称为 A_Index 的值的变量中的内容.
    Loop %GivenPath%, 1
        LongPath = %A_LoopFileLongPath%
    MsgBox The case-corrected long path name of file`n%GivenPath%`nis:`n%LongPath%
}

已知限制: 如果 NTFS 文件系统中关闭了 8.3 (短) 文件名, 那么拖拉文件到 .ahk 脚本上可能无法正常工作. 一种解决方法是 编译 脚本, 然后拖拉文件到生成的 EXE 文件上.

脚本文件代码页 [AHK_L 51+]

用来加载脚本的代码页决定了脚本中可以使用的字符.

  • 如果文件以 UTF-8 或 UTF-16 (LE) 字节顺序标记开头, 则会忽略 /CPn 开关并为其使用适合的代码页.
  • 如果在命令行中传递了 /CPn 开关, 则使用代码页 n. 想了解有效的数值代码页标识符, 请参阅 MSDN.
  • 在其他所有情况中使用系统默认的 ANSI 代码页。

注意这仅适用于 AutoHotkey 加载脚本的时候, 而不包括脚本自身的文件 I/O. FileEncoding 决定了脚本读取或写入文件时使用的默认编码, 然而 IniReadIniWrite 总是使用 UTF-16 或 ANSI.

由于所有的文本都被转换 (必要时) 为 原生的字符串格式, 所以无效的或不存在于原生代码页中的字符会被替换为占位符: ANSI '?' 或 Unicode '�'. 在 Unicode 版本中, 这种情况只可能在脚本文件编码错误或用于保存和读取脚本的代码页不一致时发生.

可以使用 RegWrite 为资源管理器中运行的脚本设置默认代码页 (例如双击脚本文件时):

; 取消对下面适当的行的注释或让它们都保留注释
;   以重新设置为当前版本的默认代码页.  需要时进行修改:
; codepage = 0        ; 系统默认的 ANSI 代码页
; codepage = 65001    ; UTF-8
; codepage = 1200     ; UTF-16
; codepage = 1252     ; ANSI Latin 1; 西欧 (Windows)
if (codepage != "")
    codepage := " /CP" . codepage
cmd="%A_AhkPath%"%codepage% "`%1" `%*
key=AutoHotkeyScript\Shell\Open\Command
if A_IsAdmin    ; 为所有用户进行设置.
    RegWrite, REG_SZ, HKCR, %key%,, %cmd%
else            ; 仅为当前用户进行设置.
    RegWrite, REG_SZ, HKCU, Software\Classes\%key%,, %cmd%

这里假定已经安装了 AutoHotkey。如果没有, 则结果可能不理想.

调试脚本

ListVarsPause 等命令可以帮助您调试脚本. 例如, 把下面这两行临时插入精心选择的位置时, 可以在脚本中创建 "断点":

ListVars
暂停

当脚本执行到这两行时, 会显示所有变量当前包含的内容供您检查. 当您准备恢复时, 可以通过 File 或托盘菜单取消暂停. 然后脚本会继续执行,直到遇到下一个“断点”(如果有)。

通常最好把这些 "断点" 插入到活动窗口对当前脚本没有影响的位置, 例如 WinActivate 命令的前一行. 这样当您取消暂停时脚本才可以正确恢复操作.

下列命令也可以用于调试: ListLines, KeyHistoryOutputDebug.

一些常见错误, 例如拼写错误或忘记 "global" 声明, 可以使用 启用警告 检测到.

交互调试 [AHK_L 11+]

通过受支持的 DBGp 客户端 可以进行交互调试. 一般支持下列操作:

  • 设置和移除断点 - 遇到 断点 时暂停执行.
  • 单步调试代码 - 逐语句, 逐过程或跳出函数和子程序.
  • 检查所有变量或特殊变量.
  • 查看正在运行的子程序和函数的堆栈.

注意在已编译脚本中没有提供此功能.

要启用交互调试, 首先要运行受支持的调试器客户端, 然后使用命令开关 /Debug 运行脚本.

AutoHotkey.exe /Debug[=SERVER:PORT] ...

SERVERPORT 可以省略. 例如, 下面的方式是等同的:

AutoHotkey /Debug "myscript.ahk"
AutoHotkey /Debug=localhost:9000 "myscript.ahk"

[AHK_L 59+]: 要向已经在运行的脚本附加调试器, 请向脚本发送消息, 如下所示:

ScriptPath = ; 设置此变量为脚本的完整路径
DetectHiddenWindows On
ifWinExist %ScriptPath% ahk_class AutoHotkey
    ; 可选参数:
    ;   wParam  = 调试器客户端的 IPv4 地址, 相当于 32 位整数.
    ;   lParam  = 调试器客户端的监听端口.
    PostMessage DllCall("RegisterWindowMessage", "str", "AHK_ATTACH_DEBUGGER")

当调试器连接后, 通过发送 "detach" DBGp 命令可以在不终止脚本的情况下分离调试器.

AutoHotkey.exe 的可移植性

运行任何的 .ahk 脚本的所有需要只是 AutoHotkey.exe 文件.

[AHK_L 51+]: 重命名 AutoHotkey.exe 会同时改变它 默认 运行的脚本, 这是在没有安装 AutoHotkey 的计算机上运行脚本的一种可选方法. 例如, 没有指定文件名执行 MyScript.exe 时会自动运行 MyScript.ahk , 但也能运行其他脚本.

安装程序选项

要静默安装 AutoHotkey 到默认目录(这与手动安装时显示的目录相同),需要向安装程序传递 /S 参数。例如:

AutoHotkey110800_Install.exe /S

使用参数 /D 可以指定默认目录外的其他目录作为安装目录 (如果没有使用 /S, 那么这样可以改变在安装程序中显示的默认目录). 例如:

AutoHotkey110800_Install.exe /S /D=C:\Program Files\AutoHotkey

如果之前已经安装了 AutoHotkey, 则安装程序会自动检测 AutoHotkey.exe 的构建并设置为默认构建。否则,根据操作系统是否为 64 位设置默认构建为 Unicode 32 位或 Unicode 64 位。要覆盖 AutoHotkey.exe 的默认构建设置,请使用下列的其中一个开关:

  • /A32/ANSI:ANSI 32 位。
  • /U64/x64:Unicode 64 位(仅在 64 位系统中有效)。
  • /U32:Unicode 32 位。

例如,下面的命令会静默安装并设置 ANSI 32 位为默认的构建:

AutoHotkey110800_Install.exe /S /A32

要静默卸载 AutoHotkey,需要向 Installer.ahk 传递 /Uninstall 参数。例如:

"C:\Program Files\AutoHotkey\AutoHotkey.exe" "C:\Program Files\AutoHotkey\Installer.ahk" /Uninstall

对于 1.1.08.00 以前的 AutoHotkey 版本,请使用 uninst.exe /S。例如:

"C:\Program Files\AutoHotkey\uninst.exe" /S

注:Installer.ahk 需要管理员权限才能正常运行。

以后版本的安装包在右下角包含了用来提取安装文件而不进行安装的链接。如果存在这个功能,则可以在命令行中使用 /E 开关来调用它。例如:

AutoHotkey110903_Install.exe /D=F:\AutoHotkey /E

脚本展示

请参阅 此页面 了解一些有用的脚本.