AutoHotkey

版本 v1.1.15.01

本中文帮助翻译自 http://ahkscript.org/docs/（请参阅此处了解详情）。

©2003-2014 Chris Mallett，部分属于©AutoIt 团队和 AHK 社区

软件许可：GNU 通用公共许可证

重要事项

由于 AutoHotkey 1.0 和 AutoHotkey 1.1 的一些基本差异（尤其是 Unicode 和 x64 的可执行文件），为 AutoHotkey 1.0 编写的脚本可能无法正常运行在 AutoHotkey 1.1 上。关于已知的兼容性问题和解决方法的细节，请参阅下面：

  • 脚本兼容性——Unicode 和 ANSI 的比较，DllCall、NumPut/Get 以及其他变化
  • 脚本文件代码页——把您的文件保存为 UTF-8 编码！

快速参考

基础：

  • 初学者向导
  • 带有 AutoHotkey 支持的文本编辑器
  • 常见问题
  • 脚本
    • 命令
    • 变量和表达式
    • 函数
    • 对象
    • 交互式调试

键盘和鼠标：

  • 热键（鼠标、操纵杆和键盘快捷键）
  • 热字串和自动替换
  • 重映射按键和鼠标按钮
  • 按键、鼠标按钮和操纵杆控制器列表

其他：

  • DllCall
  • 正则表达式快速参考
  • AutoHotkey_L（AutoHotkey 1.1）功能

致谢

特别感谢 Jonathan Bennett，他于 1999 年把 AutoIt v2 作为自由软件慷慨地发布出来，使其成为我以及世界上其他许多人节省时间的工具。此外，AutoHotkey 中许多针对 AutoIt v2 命令集的增强功能以及 Window Spy 和旧的脚本编译器都是直接改写自 AutoIt v3 源代码。所以为此同样感谢 Jon 和 AutoIt 的其他开发人员。

最后，AutoHotkey 离开了这些人也不会有今天。

~ Chris Mallett


AutoHotkey 向导：创建宏和热键

指南和概述

这个简短的介绍将帮助您马上开始编写您自己的宏和热键脚本.

指南目录

  • 创建脚本
  • 启动程序或文档
  • 发送键击和鼠标点击
  • 激活和操作窗口
  • 利用 MsgBox, InputBox 等从用户中获取输入.
  • 使用变量和剪贴板
  • 反复重复一系列动作
  • 操作文件和文件夹
  • 其他功能概述

创建脚本

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

创建新脚本:

  1. 下载 并安装 AutoHotkey.
  2. 在桌面或您选择的文件夹中右键点击空白处.
  3. 在菜单中, 选择 新建-> AutoHotkey 脚本.
  4. 输入文件名, 确保它以 .ahk 结尾. 例如：Test.ahk。
  5. 右键点击此文件并选择 Edit Script.
  6. 在新的空行中，输入下列内容：#space::Run www.google.com。

在上面的语句行中, 首个字符 "#" 表示 Windows 键; 所以 #space 表示按住 Windows 键然后按下空格键来激活热键. 双冒号 :: 表示每次按下此热键时会执行其后续命令, 这里是转到 Google 网站. 要试用此脚本, 请继续下列操作:

  1. 保存并关闭此文件.
  2. 双击此文件来运行. 在任务栏通知区域会出现新的图标.
  3. 按住 Windows 键并按下空格键. 在默认浏览器中会打开网页.
  4. 要退出或编辑此脚本, 则在任务栏通知区域的绿色 "H" 图标上点击右键.

注意:

  • 多个脚本可以同时运行, 其中的每个脚本在任务栏通知区域使用自己的图标.
  • 每个脚本可以包含多个 热键 和 热字串.
  • 要让您的脚本在启动计算机时自动运行, 请在开始菜单的启动文件夹中给您的脚本创建快捷方式.

启动程序或文档

可以使用 Run 命令来其中程序, 文档, URL 或快捷方式. 这里有一些常见示例:

Run Notepad
Run C:\My Documents\Address List.doc
Run C:\My Documents\My Shortcut.lnk
Run www.yahoo.com
Run mailto:someone@somedomain.com

通过加上 热键标签 可以把上面例子的任何一个设置为热键. 在下面的首个例子中, 设置的热键为 Win+N, 而在第二个中为 Control+Alt+C:

#n::Run Notepad
^!c::Run calc.exe

上面的例子被称为单行热键, 因为它们只包含单个命令. 要在一个热键中执行多个命令，请把首行放在热键定义的下面，且在最后行命令的下一行添加 return。例如：

#n::
Run http://www.google.com
Run Notepad.exe
return

如果要运行的程序或文档没有在环境变量中, 那么需要指定它的完整路径才能运行:

Run %A_ProgramFiles%\Winamp\Winamp.exe

在上面的例子中, %A_ProgramFiles% 是 内置变量. 使用它而不使用像 C:\Program Files 这样的, 脚本可以有更好的移植性, 这表示它在其他电脑上能执行的可能性更大. 注意: 命令和变量的名称是不区分大小写的. 例如, "Run" 等同于 "run", 而 "A_ProgramFiles" 等同于 "a_programfiles".

要让脚本等到程序或文档关闭后才继续执行, 请使用 RunWait 代替 Run. 在下面的例子中, 一直到用户关闭记事本后 MsgBox 命令才会继续执行.

RunWait Notepad
MsgBox The user has finished (Notepad has been closed).

要学习关于启动程序的更多内容, 例如传递参数, 指定工作目录和找到程序的退出代码, 请点击 此处.

发送键击和鼠标点击

使用 Send 命令可以发送键击到活动的 (最前面的) 窗口. 在下面的例子中，Control+Alt+S被设置为输入签名的热键（在按下此热键前必须确保编辑器或电子邮件这样的窗口是活动的）：

^!s::
Send Sincerely,{Enter}John Smith
return

在上面的例子中, 除 {Enter} 外的所有字符都按原义发送, 而它则模拟按下了 Enter 键. 下一个例子演示了其他一些常用的特殊字符:

Send ^c!{tab}pasted:^v

上面这行发送 Control+C 跟着 Alt+Tab 跟着字符串 "pasted:" 和 Control+V. 要了解特殊字符和按键的完整列表, 请参阅 Send.

最后, 可以用您输入的缩写来触发发送键击的动作, 这被称为 热字串. 例如，每当您输入“Btw”跟着空格或逗号时，下面这行会把它替换为“By the way”：

::btw::by the way

鼠标点击：要发送鼠标点击到窗口，首先必须确定要点击的 X 和 Y 坐标。这个可以用 Window Spy 来完成, 它包含在 AutoHotkey 中. 下列步骤说明了使用 Window Spy 的方法:

  1. 在脚本托盘图标菜单或开始菜单中运行 Window Spy.
  2. 通过点击感兴趣的标题栏, alt-tab 切换或其他方法激活窗口 (Window Spy 被设计为保持 "置顶").
  3. 移动鼠标光标到目标窗口中想要的位置并记下 Window Spy 中显示的鼠标坐标 (或在 Windows XP 和早期版本中, 按下 Shift-Alt-Tab 来激活 Window Spy, 这样可以复制和粘贴 "冻结的" 坐标).
  4. 在 Click 命令中使用上面找到的坐标. 下面的例子点击鼠标左键：Click 112, 223。

要移动鼠标而不进行点击, 请使用 MouseMove. 要拖拉鼠标, 请使用MouseClickDrag.

激活和操作窗口

要激活窗口 (使它最前面), 请使用 WinActivate. 要判断窗口是否存在, 请使用 IfWinExist 或 WinWait. 下面的例子演示了这些命令:

IfWinExist Untitled - Notepad
{
    WinActivate
}
else
{
    Run Notepad
    WinWait Untitled - Notepad
    WinActivate
}

上面的例子会首先搜索标题以 "无标题 - 记事本" (区分大小写) 开始的任何现有的窗口. 如果找到这样的窗口, 则激活它. 否则, 启动记事本并等待无标题窗口的出现, 出现后激活它. 上面的例子还利用了 最近找到的窗口, 这样可以不需要在每个 WinActivate 中指定窗口标题.

其他一些常用的窗口命令是:

  • IfWinActive: 检查指定的窗口当前是否活动.
  • WinWaitActive: 等待指定窗口变为活动窗口 (通常用在激活窗口的键击后面, 例如按下 Control-F 来打开 "查找" 窗口).
  • WinClose: 关闭指定的窗口.
  • WinMove: 改变指定窗口的位置和/或大小.
  • WinMinimize, WinMaximize, WinRestore: 分别最小化, 最大化或还原指定窗口.

利用 MsgBox, InputBox 等从用户中获取输入.

下面的例子显示带两个按钮的对话框 (是 和 否):

MsgBox, 4, , Would you like to continue?
IfMsgBox, No
    return
; 否则, 用户选择了是.
MsgBox You pressed YES.

使用 InputBox 命令来提示用户输入字符串. 使用 FileSelectFile 或 FileSelectFolder 来让用户选择文件或文件夹. 对于更高级的任务, 请使用 Gui 命令来创建自定义数据输入窗体和用户界面.

提示: 您也许已经从其他例子中注意到任何命令中的首个逗号可以省略 (除非首个参数为空或以 := 或 = 开始, 或命令单独处于 延续片段 的顶部). 例如：

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

使用变量和剪贴板

变量 是脚本用来存储文本或数字的内存块. 只包含数字的变量 (可以含小数点) 在数学运算或比较时会被自动转换为数字.

除了 函数 中的局部变量外, 所有的变量都是全局的; 即可以在脚本的任意位置读取或改变它们的内容. 此外, 变量不需要声明; 简单地使用它们就可以让它们存在 (且每个变量都以空或空白开始).

要把字符串赋值给变量, 请参照这些例子:

MyVar1 = 123
MyVar2 = my string
要把变量的内容和数字或字符串进行比较, 请参照这些例子:
if MyVar2 = my string
{
    MsgBox MyVar2 contains the string "my string".
}
if MyVar1 >= 100
{
    MsgBox MyVar1 contains %MyVar1%, which is a number greater than or equal to 100.
}

在上面的 MsgBox 行中, 注意第二个出现的 MyVar1 被括在百分号内. 这样在那里显示了 MyVar1 的内容. 使用相同的手法能用来复制一个变量的内容给另一个变量. 例如：

MyVarConcatenated = %MyVar1% %MyVar2%

上面这行把字符串 "123 my string" (不含引号) 保存到变量 MyVarConcatenated.

要比较两个变量的内容, 请参照此例:

if (ItemCount > ItemLimit)
{
    MsgBox The value in ItemCount, which is %ItemCount%, is greater than %ItemLimit%.
}

注意上面例子的首行包含小括号. 小括号表示这个 if 语句包含 表达式. 如果没有它们, 那行将被视为 "非表达式 if 语句", 并且因此需要使用百分号括住 ItemLimit (这样的 if 语句被限制为只能包含简单的比较运算符, 而不能包含数学运算符或像 "AND" 和 "OR" 这样的联合运算符).

数学：要执行数学运算，请使用冒号-等号运算符（:=）来把表达式的结果赋值给变量，例如：

NetPrice := Price * (1 - Discount/100)

请参阅 表达式 来了解数学运算符的完整列表.

剪贴板: Clipboard 变量是特殊变量, 因为它包含了 Windows 剪贴板中当前的文本. 即使如此, 它的用法也和普通变量一样. 例如, 下面这行将显示剪贴板当前的内容:

MsgBox %clipboard%

要改变剪贴板的内容, 请参考下面的例子, 它用新文本替换了剪贴板的当前内容:

clipboard = A line of text.`r`nA second line of text.`r`n

在上面, `r 和 `n (重音符后跟着字母 "r" 或 "n") 用来表示两个特殊字符: 回车和换行. 这两个字符在文本中开始新行, 就像用户按下了 Enter 键.

要追加文本到剪贴板 (或其他任何变量), 请参照此例:

clipboard = %clipboard% And here is the text to append.

请参阅 剪贴板 和 变量 章节了解详情.

反复重复一系列动作

要多次连续地重复执行一些操作, 请使用 循环. 下面的循环会显示三次 MsgBox:

Loop 3
{
    MsgBox This window will be displayed three times.
}

您还可以在单词 Loop 后指定变量, 这可以用于循环次数在脚本某个位置定义的时候:

Loop %RunCount%
{
    Run C:\Check Server Status.exe
    Sleep 60000  ; 暂停 60 秒.
}

在上面的例子中, 循环会执行指定的次数, 但是如果 RunCount 的值为 0, 则会完全跳过循环.

当一个或多个条件改变时循环还可以终止它自己. 下面的例子中当用户按住 F1 键时会重复点击鼠标左键:

$F1::  ; 把 F1 键设置为热键 ($ 符号会有助于下面 GetKeyState 的 "P" 模式).
Loop  ; 由于没有指定数字, 所以这是个无限循环, 直到遇到内部的 "break" 或 "return".
{
    if not GetKeyState("F1", "P")  ; 如果此状态为 true, 那么用户实际已经释放了 F1 键.
        break  ; 中断循环.
    ; 否则 (由于上面没有 "中断"), 继续点击鼠标.
    Click  ; 在当前指针位置点击鼠标左键.
}
return

在上面的例子中, 当用户按下 F1 键时, 循环会检测到并通过 break 命令停止它自己. Break 会使得执行跳转到循环闭括号后的行.

另一种实现此目的的方法是使用 "while" 循环:

$F1::
while GetKeyState("F1", "P")  ; 当 F1 键实际被按住时.
{
    Click
}
return

上面的示例演示了一般用途的循环. 对于更多特殊的需要, 请考虑下面这些循环:

文件读取/写入循环: 逐行读取文本文件的内容, 每次一行. 这可以用来一行接一行地把文件转换成不同的格式. 它还可以用来搜索匹配条件的行.

文件和文件夹循环: 获取指定的文件或文件夹, 每次一个. 这可以用来对符合条件的文件或文件夹进行操作.

解析循环: 从一个字符串中获取子字符串, 每次一个. 这可以用来很容易的分解像 "Red,Green,Blue" 这样的字符串为三个子片段.

注册表循环: 获取指定的注册表子键的内容, 每次一个项目.

操作文件和文件夹

要添加文本到文件的末尾 (或创建新文件), 请使用 FileAppend, 如下面的例子所示. 注意它使用 `n (换行符) 来开始新的文本行:

FileAppend, A line of text to append.`n, C:\My Documents\My Text File.txt

要覆盖现有的文件, 请在 FileAppend 之前使用 FileDelete. 例如：

FileDelete, C:\My Documents\My Text File.txt

其他一些常用的文件和文件夹命令是:

  • FileRead: 读取整个文件的内容到变量.
  • 文件读取循环: 逐行读取文本文件的内容.
  • IfExist: 检查文件或文件夹是否存在.
  • FileSelectFile 和 FileSelectFolder: 显示可以让用户选取文件或文件夹的对话框.
  • FileDelete/FileRecycle: 删除/回收一个或多个文件. 使用 FileRemoveDir 来删除整个文件夹.
  • FileCopy/FileMove: 复制/移动一个或多个文件. 使用 FileCopyDir/FileMoveDir 来复制/移动整个文件夹.
  • 文件和文件夹循环: 获取文件夹中包含的子文件夹和文件, 每次一个.
  • FileSetAttrib 和 FileSetTime: 改变一个或多个文件的属性或时间戳.
  • IniRead, IniWrite 和 IniDelete: 创建, 访问和操作标准格式的 INI 文件.
  • RegRead, RegWrite, RegDelete 和 注册表循环: 操作 Windows 注册表.

其他功能概述

请参阅 命令列表 了解每个命令的概述.


AutoHotkey FAQ

常见问题（FAQ）

如果您的问题没有在后面列出，请查看社区维护的 autoHotkey.net 上的 FAQ。

语言语法

  • 什么时候需要在命令和它们的参数中使用引号?
  • 什么时候需要将变量名括在百分号中？
  • 什么时候应该对百分号和逗号进行转义?

常见任务

  • 我可以在哪里找到官方构建或更旧的版本？
  • 为什么我脚本中的某些行总是无法执行?
  • 为什么我的脚本在 XP 运行良好却无法工作于 Windows 7 或 8？
  • 我想通过托盘图标编辑脚本，但它只显示一个错误。能在其他位置找到我的脚本吗？
  • 如何查找代码中的错误并修改呢？
  • 可以在 USB 驱动器中运行 AHK 代码吗？
  • 为什么 Run 命令不能启动我的游戏或程序?
  • 如何获取命令行操作的输出?
  • 如何让一个脚本关闭, 暂停或挂起其他的脚本?
  • 如何在不退出脚本的情况下停止重复的动作?
  • 如何在玩游戏或平时 CPU 高负荷运行时改善性能?
  • 如何在任意编辑器中使用上下文相关的 AutoHotkey 命令帮助?
  • 如何检测一个网页何时加载完毕?
  • 如何比较或操作日期与时间?
  • 如何发送当前的日期和时间？
  • 如何发送文本到不活跃或隐藏的窗口？
  • 为什么在某些游戏中热字串, Send 和 MouseClick 不起作用?
  • 如何控制 Winamp, 即使在它未激活时?
  • 如何改变 MsgBox 的按钮名称?
  • 如何改变默认编辑器，即通过上下文菜单或托盘图标打开的那个？
  • 如何保存 GUI 关联变量的内容？
  • 如何用 AHK 描绘？
  • 如何在窗口出现、关闭或变成（不）活跃时执行操作？
  • 我的杀毒软件把 AHK 归为恶意软件。它真的含病毒吗？

热键, 热字串和重映射

  • 如何让我的热键和热字串在 PC 启动时自动生效?
  • 我在把鼠标按钮作为热键使用时遇到问题. 能提供一些建议吗?
  • 如何将 tab 和空格设置为热键?
  • 如何将按键或鼠标按钮重映射成其他键?
  • 如何检测按键或按钮的双击？
  • 如何让热键或热字串只在特定的程序中有效? 换句话说, 在特定的窗口不活动时我想让特定的按键执行它原来的功能.
  • 如何让前缀按键执行它原来的功能, 而不是什么都不做?
  • 如何改变或禁用 Windows 内置的快捷键, 例如 Win+U (辅助工具管理器) 和 Win+R (运行)?
  • 如何在热字串中使用通配符或正则表达式？
  • 如何使用不存在于我键盘布局中的热键？
  • 我的小键盘上有个特殊的 000 键. 可以把它设成热键吗?

语言语法

什么时候需要在命令和它们的参数中使用引号?

双引号 (") 仅在 表达式 中具有特殊的含义. 在其他的所有地方, 它们像普通字符一样被原义对待. 不过，当脚本启动程序或文档时，操作系统通常要求要用引号把含空格的命令行参数括起来，例如：Run, Notepad.exe "C:\My Documents\Address List.txt"。

什么时候需要将变量名括在百分号中？

除了下面用 粗体 表示的情况外, 变量名总是要括在百分号中:

1) 在参数中的输入或输出变量: StringLen, OutputVar, InputVar
2) 在赋值表达式的左侧: Var = 123abc
3) 在 传统 (非表达式) if 语句 的左侧: If Var1 < %Var2%
4) 在 表达式 中的任意位置. 例如：

If (Var1 <> Var2)
    Var1 := Var2 + 100

什么时候应该对百分号和逗号进行 转义?

原义的百分号必须在它们前面加重音符/反引号进行 转义. 例如: MsgBox The current percentage is 25`%. 原义的逗号也必须进行转义 (`,), 除非在 MsgBox 或任何命令的最后一个参数 (在这种情况下可以使用重音符但不是必须的) 使用时.

在 表达式 中逗号或百分号括在引号中时, 可以使用这样重音符但不是必须的. 例如：Var := "15%"。

常见任务

我可以在哪里找到官方构建或更旧的版本？

请参阅 AutoHotkey 的下载页面。

为什么我脚本中的某些行总是无法执行?

任何想在脚本启动时立即执行的行都应该出现在脚本的顶部, 要在首个 热键, 热字串 或 Return 之前. 更多细节请参阅自动执行部分。

还有, 含有多行执行语句的 热键 必须把它的首行写在热键的 下面 而不能在同一行. 例如：

#space::  ; Win+空格键
Run Notepad
WinWaitActive Untitled - Notepad
WinMaximize
return

为什么我的脚本在 XP 运行良好却无法工作于 Windows 7 或 8？

因为您已经换了操作系统，很可能某些影响脚本的东西也改变了。例如，当您换了新电脑，那么它和旧电脑有些地方是不一样的。如果您同时更新了 AutoHotkey 的版本，那么请看看新版本的更新日志和兼容性提示以找出新旧版本的区别。

从 XP 迁移到 Vista 或更高版本的 Windows 的常见问题是热键操作需要较高的权限或拒绝被自动化。至少有三种变通解决方法：

  • 修改 AutoHotkey.exe 以启用与管理程序的交互。这样会带来一些坏处。更多信息请参阅 http://www.autohotkey.com/board/topic/70449-enable-interaction-with-administrative-programs/
  • 以管理员权限运行脚本。注意这样的脚本中运行的任何程序也具有管理员权限。
  • 关闭用户账户控制（不推荐），在 Windows 8 或之后的版本您还必须禁用“以管理员核准模式运行所有管理员（Run all administrators in Admin Approval Mode）”安全设置（也不推荐）。

SoundGet、SoundSet、SoundGetWaveVolume 和 SoundSetWaveVolume 的功能在 Vista 及更高版本的 Windows 中比起以前的系统有变化。尤其是设备号不一样了，一些组件也无法使用。具体行为决定于音频驱动，它肯定与 XP 中使用的不同。该声卡分析脚本可用于找到正确的设备号。

我想通过托盘图标编辑脚本，但它只显示一个错误。能在其他位置找到我的脚本吗？

试试找到下面的某个文件并编辑（如用记事本）：

  • My Documents/AutoHotkey.ahk
  • My Documents/AutoHotkey.ini
  • Program Files/AutoHotkey/AutoHotkey.ahk
  • Program Files/AutoHotkey/AutoHotkey.ini

AHK 的不同版本默认会创建不同的文件，因此请检查所有这些位置，应该只能找到其中某个文件名。

AHK 不是“普通”程序，所以不要期望像其他程序一样从开始菜单运行。从开始菜单运行或直接运行 AutoHotkey.exe 时会读取上面的某个文件并将其作为脚本运行。您应该创建扩展名为 .ahk 的文件并双击它们来运行。

另请参阅命令行参数“Script Filename”和 AutoHotkey.exe 的可移植性。

如何查找代码中的错误并修改呢？

对于简单的脚本，请参阅调试脚本。要查看变量的内容，请使用 MsgBox 或 ToolTip。对于复杂的脚本，请参阅交互式调试。

可以在 USB 驱动器中运行 AHK 代码吗？

请参阅AutoHotkey.exe 的可移植性。需要注意，如果您使用自动包含的函数库，AutoHotkey.exe 和 Lib 文件夹必须在 Ahk2Exe.exe 的上一级目录（例如分别为 \AutoHotkey.exe 和 \Compiler\Ahk2Exe.exe）。还需注意 Ahk2Exe 保存设置到注册表的下列位置： HKEY_CURRENT_USER\Software\AutoHotkey\Ahk2ExeCommand。

为什么 Run 命令不能启动我的游戏或程序?

有些程序需要在它们自己的目录下运行 (不能确定时, 通常最好这样做). 例如：

Run, %A_ProgramFiles%\Some Application\App.exe, %A_ProgramFiles%\Some Application

如何获取命令行操作的输出?

测试显示, 由于文件缓存的原因, 对于较少量的输出, 使用临时文件获取会非常快. 事实上, 如果在使用后立即删除文件, 通常它并没有被真正地写到磁盘上. 例如：

RunWait %comspec% /c dir > C:\My Temp File.txt
FileRead, VarToContainContents, C:\My Temp File.txt
FileDelete, C:\My Temp File.txt

要避免使用临时文件 (特别是对于大量输出时), 可以考虑使用 CmdRet 或 StdoutToVar.

如何让一个脚本关闭, 暂停或挂起其他的脚本?

首先, 这里有个关闭另一个脚本的例子:

DetectHiddenWindows On  ; 才可以检测到脚本的隐藏主窗口.
SetTitleMatchMode 2  ; 避免为下面的文件指定完整的路径.
WinClose Script's File Name.ahk - AutoHotkey  ; 根据脚本的名称 (区分大小写) 更新此语句.

要 挂起 或 暂停 另一个脚本, 请把上面脚本的最后一行替换为下列语句中的一个:

PostMessage, 0x111, 65305,,, Script's File Name.ahk - AutoHotkey  ; 挂起.
PostMessage, 0x111, 65306,,, Script's File Name.ahk - AutoHotkey  ; 暂停.

如何在不退出脚本的情况下停止重复的动作?

要通过按键来暂停或恢复整个脚本, 需要给 Pause 命令指定热键, 例如:

^!p::Pause  ; 按 Ctrl+Alt+P 暂停. 再按一次则恢复.

要停止在 循环 中重复的动作, 请参考下面这个可运行示例, 这是一个可以启用和停止它自身重复动作的热键. 换句话说, 按一次这个热键将开始循环. 再按同样的热键将停止循环.

#MaxThreadsPerHotkey 3
#z::  ; Win+Z 热键 (可根据您的喜好改变此热键).
#MaxThreadsPerHotkey 1
if KeepWinZRunning  ; 这说明一个潜在的 线程 正在下面的循环中运行.
{
    KeepWinZRunning := false  ; 向那个线程的循环发出停止的信号.
    return  ; 结束此线程, 这样才可以让下面的线程恢复并得知上一行所做的更改.
}
; 否则:
KeepWinZRunning := true
Loop
{
    ; 以下四行是您要重复的动作 (可根据您的需要修改它们):
    ToolTip, 再次按下 Win-Z 来停止此提示闪动.
    Sleep 1000
    ToolTip
    Sleep 1000
    ; 但请不要修改下面剩下的内容.
    if not KeepWinZRunning  ; 用户再次按下 Win-Z 来向循环发出停止的信号.
        break  ; 跳出此循环.
}
KeepWinZRunning := false  ; 复位, 为下一次使用热键做准备.
return

如何在玩游戏或平时 CPU 高负荷运行时改善性能?

当 CPU 高负荷运行时, 如果脚本里的 热键, 点击 或 发送 明显比平时慢, 那么提高脚本的进程优先级可能会有所帮助. 要做到这点, 请在脚本的顶部附近包含下面这行语句:

Process, Priority, , High

如何在任意编辑器中使用上下文相关的 AutoHotkey 命令帮助?

为此 Rajat 创建了 此脚本.

如何检测一个网页何时加载完毕?

对于 Internet Explorer, 可能最可靠的方法是使用 DllCall 和 COM, 正如 www.autohotkey.com/forum/topic19256.html 所演示的. 相关提示, 通过 www.autohotkey.com/forum/topic19255.html 演示的方法可以获取地址栏和状态栏的内容.

旧的、较不可靠的方法：下面示例中的技术对使用 MS Internet Explorer 打开大部分页面时都有效。类似的技术对于其他的浏览器可能也有效:

Run, www.yahoo.com
MouseMove, 0, 0  ; 防止状态栏显示鼠标悬停处的链接而不显示 "完毕".
WinWait, Yahoo!-
WinActivate
StatusBarWait, Done, 30
if ErrorLevel
   MsgBox The wait timed out or the window was closed.
else
   MsgBox The page is done loading.

如何比较或操作日期与时间?

EnvAdd 命令可以对 YYYYMMDDHH24MISS 格式的时间字符串加上或减去一些天数, 小时数, 分钟数或秒数. 后面的例子从指定的时间中减去 7 天：EnvAdd, VarContainingTimestamp, -7, days。

要计算两个日期或时间之间的间隔, 请参阅 EnvSub, 其中给出了一个示例. 此外, 内置变量 A_Now 包含了当前的本地时间. 最后, 还有许多内置的 日期/时间变量, 以及用来创建自定义日期/时间字符串的 FormatTime 命令.

如何发送当前的日期和时间？

使用 FormatTime 或内置的日期和时间变量。

如何发送文本到不活跃或隐藏的窗口？

使用 ControlSend。

为什么在某些游戏中 热字串, Send 和 Click 不起作用?

一些游戏禁止 AHK 发送键击和点击或获取像素颜色。

有一些替代方法，请试试下面提及的方案。如果这些都无效，那么 AHK 可能不适用于您的游戏。一些游戏含有防止反破解和作弊的措施，如 GameGuard 和 Hackshield。如果是，则 AutoHotkey 很可能无法用于该游戏。

  • 通过 SendPlay 命令、SendMode Play 或 热字串选项 SP 使用 SendPlay。

    SendPlay, abc
    SendMode, Play
Send, abc
    :SP:btw::by the way

; or

#Hotstring SP
::btw::by the way

    注：SendPlay 在启用了用户账户控制的 Windows Vista 或更高版本中可能没有效果，即使以管理员运行脚本。

  • 使用 SetKeyDelay 增加延迟. 例如：

    SetKeyDelay, 0, 50
SetKeyDelay, 0, 50, Play

  • 试试 ControlSend，在其他 Send 模式无效时它可能行：

    ControlSend,, abc, game_title

  • 试试在多种发送方式中使用按键的按下和弹起事件。

    Send {KEY down}{KEY up}

  • 试试在按键的按下事件和弹起事件之间使用 Sleep：

    Send {KEY down}
Sleep 10 ; 试试不同的毫秒数
Send {KEY Up}

如何控制 Winamp, 即使在它未激活时?

请参阅 让 Winamp 自动化.

如何改变 MsgBox 的按钮名称?

这里有个 例子.

如何改变默认编辑器，即通过上下文菜单或托盘图标打开的那个？

在 Edit 的示例部分可以找到能让您改变默认编辑器的脚本。

如何保存 GUI 关联变量的内容？

请使用 Gui Submit。例如：

Gui, Add, Text,, Enter some Text and press Submit:
Gui, Add, Edit, vAssociatedVar
Gui, Add, Button,, Submit
Gui, Show
Return

ButtonSubmit:
Gui, Submit, NoHide
MsgBox, Content of the edit control: %AssociatedVar%
Return

如何用 AHK 描绘？

请参阅 tic 写的 GDI+ 标准库。还可以通过一些基本方法但受限的方法使用 Gui。

如何在窗口出现、关闭或变成（不）活跃时执行操作？

使用 WinWait、WinWaitClose 或 WinWait[Not]Active。请参阅社区驱动的常见问题（窗口部分）了解更多。

我的杀毒软件把 AHK 归为恶意软件。它真的含病毒吗？

当然不是。杀毒软件可能把 AHK 误识别为恶意软件（称为假阳性（false positive）），原因是脚本在编译时使用了压缩工具，如 UPX（AHK 1.0 的默认设置，在 AHK 1.1 中被移除）或 MPRESS（在 AHK 1.1 中是可选的）。这种压缩工具可以减小编译后可执行文件的大小。如果您不想要压缩，则应该在编译时不使用压缩工具，这样您和其他潜在用户的反病毒程序就不会误报了。

热键, 热字串和重映射

如何让我的热键和热字串在 PC 启动时自动生效?

在开始菜单中有一个“启动”文件夹。把脚本的快捷方式放到该文件夹，则对应的脚本会在每次启动电脑时自动运行。要创建快捷方式：

  1. 找到脚本文件后选中它, 接着按下 Control-C.
  2. 右键点击开始按钮 (通常在屏幕的左下角) 并选择 "浏览所有用户".
  3. 定位到程序文件夹中的启动文件夹.
  4. 在菜单栏中选择编辑->粘贴快捷方式。现在启动文件夹中应该出现了该脚本的快捷方式。

我在把鼠标按钮作为热键使用时遇到问题. 能提供一些建议吗?

鼠标左键和右键应该可以正常设置为热键（例如，#LButton:: 为 Win+LeftButton 热键）。同样地，鼠标中键和鼠标滚轮的转动应该可以正常地设置为热键，除非对于驱动直接控制这些按钮的鼠标。

第四个按钮 (XButton1) 和第五个按钮 (XButton2) 也可以设置为热键, 如果您的鼠标驱动让系统可以 看到 这些按键的点击时. 如果它们不可见或您的鼠标除了您使用的五个按钮外还有更多的按钮, 您可以尝试配置鼠标附带的软件 (有时需要通过控制面板或开始菜单访问) 来实现当您按下其中的按钮时发送键击. 然后可以在脚本中把这样的键击设置为热键. 例如, 如果您配置第四个按钮来发送 Control+F1, 然后在脚本中通过使用 ^F1:: 您可以把这个按钮间接的设置为热键.

如果您有五键鼠标, 其中的第四和第五个按钮不 可见, 您可以尝试把鼠标驱动改变为 OS 自带的默认驱动. 这里假设您特殊的鼠标使用自己的驱动并且您不使用鼠标自带软件提供的功能.

如何将 Tab 和空格设置为热键?

使用它们的按键名称 (Tab 和 Space) 而不用它们的字符. 例如, #Space 为 Win+Space 而 ^!Tab 为 Control+Alt+Tab.

如何将按键或鼠标按钮重映射成其他键?

解决的方法在 重映射 页面说明了.

如何检测按键或按钮的双击？

像下面那样使用可用于热键的内置变量：

~Ctrl::
    if (A_ThisHotkey = A_PriorHotkey && A_TimeSincePriorHotkey < 200)
        MsgBox double-press
return

如何让 热键 或 热字串 只在特定的程序中有效? 换句话说, 在特定的窗口不活动时我想让特定的按键执行它原来的功能.

首选的方法是使用 #IfWinActive. 例如：

#IfWinActive, ahk_class Notepad
^a::MsgBox You pressed Control-A while Notepad is active.

如何让前缀按键执行它原来的功能, 而不是什么都不做?

请参考下面的例子, 其中把 Numpad0 作为前缀键:

Numpad0 & Numpad1::MsgBox, You pressed Numpad1 while holding down Numpad0.

现在, 要让 Numpad0 在没有像上面那样用来触发热键时发送真正的 Numpad0 键击, 需要添加下面的热键:

 $Numpad0::Send, {Numpad0}

使用前缀 $ 是为避免产生关于无效循环的警告对话框 (因为此热键 "发送了它自己"). 此外, 上述动作在 释放 此按键的时候发生.

如何改变或禁用 Windows 内置的快捷键, 例如 Win+U (辅助工具管理器) 和 Win+R (运行)?

这里有一些 例子.

如何在热字串中使用通配符或正则表达式？

使用 polyethene 写的脚本（含示例）。

如何使用不存在于我键盘布局中的热键？

请参阅特殊按键。

我的小键盘上有个特殊的 000 键. 可以把它设成热键吗?

是的。这个 示例脚本 把 000 键设成等号键. 您可以用您想要的语句替换 Send, = 来改变动作。


按字母排序的命令和函数索引

点击命令或函数名称了解详情。大字体显示 的条目是最常用的。

条目 | 说明
{ ... }（区块） | 一对大括号组成的区域表示一个区块。区块通常与函数、Else、Loop、While 循环和 IF 命令一起使用。
{ ... } / Object() | 创建脚本化关联数组。
[ ... ] / Array() | 创建含整数键的脚本化关联数组。
Abs() | 返回 Number 的绝对值。
AutoTrim | 设置在 Var1 = %Var2% 这样的语句中进行赋值时是否忽略 Var2 的前导和尾随空格和 tab。
ASin() | 返回弧度表示的反正弦值（其正弦值为 Number）。
ACos() | 返回弧度表示的反余弦值（其余弦值为 Number）。
ATan() | 返回弧度表示的反正切值（其正切值为 Number）。
BlockInput | 禁用或启用用户通过键盘和鼠标与计算机交互的能力。
中断 | 退出（终止）循环。在各种循环中都是有效的。
Catch | 指定在执行 try 语句发生异常时执行的代码。
Ceil() | 返回由 Number 向上取整到最近的整数（不带任何 .00 后缀）。
点击 | 在指定坐标处点击鼠标按钮。它还可以按下鼠标按钮，转动鼠标滚轮或移动鼠标。
ClipWait | 等待，一直到剪贴板包含数据。
ComObjActive() | 获取注册的 COM 对象。
ComObjArray() | 创建用于 COM 的 SAFEARRAY。
ComObjConnect() | 连接 COM 对象的事件源到带有给定前缀的函数。
ComObjCreate() | 创建 COM 对象。
ComObjEnwrap() / ComObjUnwrap() | 包装/解开 COM 对象。
ComObjError() | 启用或禁用 COM 错误通告。
ComObjFlags() | 获取或改变控制 COM 包装器对象行为的标志。
ComObjGet() | 返回由 COM 组件提供的对象引用。
ComObjMissing() | 创建传递给 COM 方法的“遗漏参数”对象。
ComObjParameter() | 把值和类型包装成参数传递给 COM 方法。
ComObjQuery() | 查询 COM 对象的接口或服务。
ComObjType() | 从 COM 对象获取类型信息。
ComObjValue() | 获取存储在 COM 包装器对象中的值或指针。
继续 | 跳过当前循环的剩余部分并继续下一次循环。在各种循环中都是有效的。
控件 | 对控件进行各种改变。
ControlClick | 发送鼠标按钮或鼠标滚轮事件到控件。
ControlFocus | 设置输入焦点到窗口的指定控件上。
ControlGet | 获取控件的各种类型的信息。
ControlGetFocus | 如果有，则获取目标窗口中含输入焦点的控件。
ControlGetPos | 获取控件的位置和大小。
ControlGetText | 获取控件的文本。
ControlMove | 移动控件或调整其大小。
ControlSend / ControlSendRaw | 发送模拟键击到窗口或控件。
ControlSetText | 改变控件的文本。
CoordMode | 为多个命令设置坐标模式，相对于活动窗口还是屏幕。
Cos() | 返回 Number 的余弦三角函数值。
Critical | 防止当前线程被其他线程中断。
DetectHiddenText | 设置在探测窗口时窗口中隐藏的文本是否“可见”。此设置影响例如 IfWinExist 和 WinActivate 的这些命令。
DetectHiddenWindows | 设置脚本是否可以“看见”隐藏的窗口。
DllCall() | 调用 DLL 文件中的函数，例如标准的 Windows API 函数。
Drive | 弹出/收进 CD 或 DVD 驱动器托盘，或设置驱动器的卷标。
DriveGet | 获取计算机驱动器的各种类型的信息。
DriveSpaceFree | 获取驱动器的可用磁盘空间，单位为 MB。
Edit | 在关联编辑器中打开当前脚本进行编辑。
Else | 指定当 IF 语句计算结果为 FALSE 时执行的命令。包含多个命令时，需要把它们括在区块（大括号）中。
EnvAdd | 设置变量的值为它自身加上给定的值的和（还可以从日期-时间值中增加或减去时间）。同义于：Var += Value。
EnvDiv | 设置变量的值为它自身除以给定的值。同义于：Var /= Value。
EnvGet | 获取环境变量的内容。
EnvMult | 设置变量的值为它自身乘以给定的值。同义于：Var *= Value。
EnvSet | 向系统环境中的变量写入值。
EnvSub | 设置变量的值为它自身减去给定的值（还可以比较日期-时间值）。同义于：Var -= Value。
EnvUpdate | 通知操作系统和所有正在运行的程序环境变量已经改变。
Exit | 退出当前线程或（如果脚本不是持续运行的且不包含热键时）整个脚本。
ExitApp | 无条件终止脚本。
Exp() | 返回 e（其近似值为 2.71828182845905）的 N 次幂。
FileAppend | 在文件末尾处追加文本（如果有必要，首先创建文本）。
FileCopy | 复制一个或多个文件。
FileCopyDir | 复制文件夹及其所有子文件夹和文件（类似于 xcopy）。
FileCreateDir | 创建文件夹。
FileCreateShortcut | 创建快捷方式（.lnk）文件。
FileDelete | 删除一个或多个文件。
FileEncoding 为 FileRead、FileReadLine、Loop Read、FileAppend 和 FileOpen 设置默认编码。
另请参阅： 文本编码
FileInstall | 封装指定的文件到脚本的已编译版本中。
FileGetAttrib | 报告文件或文件夹是否为只读、隐藏等。
FileGetShortcut | 获取快捷方式（.lnk）文件的信息，例如其目标文件。
FileGetSize | 获取文件的大小。
FileGetTime | 获取文件或文件夹的时间戳。
FileGetVersion | 获取文件的版本。
FileMove | 移动或重命名一个或多个文件。
FileMoveDir | 移动文件夹及其所有子文件夹和文件。它还可以重命名文件夹。
FileOpen | 提供面向对象的文件 I/O。
FileRead | 读取文件的内容到变量。
FileReadLine | 读取文件指定行的文本并保存到变量。
FileRecycle | 发送文件或目录到回收站，如果可行。
FileRecycleEmpty | 清空回收站。
FileRemoveDir | 删除文件夹。
FileSelectFile | 显示可以让用户打开或保存文件的标准对话框。
FileSelectFolder

显示可以让用户选择文件夹的标准对话框。
FileSetAttrib | 改变一个或多个文件或文件夹的属性。支持通配符。
FileSetTime | 改变一个或多个文件或文件夹的时间戳。支持通配符。
Finally | 确保在Try语句结束后总是会执行的代码块。
Floor() | 返回由 Number 向下取整到最近的整数（不带任何 .00 后缀）。
For | 对对象中的每对键值对重复执行一系列命令。
FormatTime | 转换 YYYYMMDDHH24MISS 时间戳到指定的日期/时间格式。
Func() | 获取函数的引用。
GetKeyName()
GetKeyVK()
GetKeySC() 		获取按键的名称、文本、虚拟按键码或扫描码。
GetKeyState | 检查键盘按键或鼠标/操纵杆按钮是否按下或放开。也可以获取操纵杆的状态。
Gosub | 跳转到指定的标签继续执行，直到遇到 Return。
Goto | 跳转到指定的标签并继续执行。
GroupActivate | 激活由 GroupAdd 定义的窗口组中的下一个窗口。
GroupAdd | 增加窗口规格到窗口组，必要时创建组。
GroupClose | 关闭刚刚由 GroupActivate 或 GroupDeactivate 激活的活动窗口。接着激活系列中的下一个窗口。它还可以关闭组中所有窗口。
GroupDeactivate | 类似于 GroupActivate，不同的是它激活不在组中的下一个窗口。
Gui | 创建和管理窗口和控件。这种窗口可以用作数据输入窗体或自定义用户界面。
GuiControl | 对 GUI 窗口中的控件进行各种设置。
GuiControlGet | 获取 GUI 窗口中控件的各种类型的信息。
Hotkey | 在脚本运行时创建、修改、启用或禁用热键。
if | 指定在变量与值比较结果为 TRUE 时执行的命令。包含多个命令时，需要把它们括在区块（大括号）中。
if（表达式） | 指定在表达式计算结果为 TRUE 时执行的命令。
If var [not] between | 根据数值或字母顺序检查变量的内容是否在两个值之间（包含边界）。
If var [not] in/contains MatchList | 检查变量的内容是否匹配列表中的某项。
If var is [not] type | 检查变量的内容是否为数值、大写字母或其他。
IfEqual / IfNotEqual | 比较变量和值判断它们是否相等。同义于：if Var = Value | if Var <> Value。
IfExist / FileExist() | 检查文件或文件夹是否存在。
IfGreater / IfGreaterOrEqual | 比较变量和某个值。同义于：if Var > Value | if Var >= Value。
IfInString / InStr() | 检查变量是否包含指定的字符串。
IfLess / IfLessOrEqual | 比较变量和某个值。同义于：if Var < Value | if Var <= Value。
IfMsgBox | 检查用户在最近的 MsgBox 命令中点击了哪个按钮。
IfWinActive / IfWinNotActive
 检查指定的窗口是否存在且当前是否活动（在最前面）。
IfWinExist / IfWinNotExist
 检查指定的窗口是否存在。
ImageSearch | 在屏幕的某个区域中搜索图像。
IniDelete | 删除标准格式的 .ini 文件中的值。
IniRead | 读取标准格式的 .ini 文件中的值。
IniWrite | 写入值到标准格式的 .ini 文件。
Input | 等待用户输入字符串。
InputBox | 显示输入框让用户输入字符串。
InStr() | 搜索字符串的出现位置，从左边或右边开始。
IsByRef() | 判断变量是否是 ByRef 参数。
IsFunc() | 判断函数是否可以动态调用。
IsLabel() | 检查是否存在指定的标签。
IsObject() | 判断某个值是否为对象。
KeyHistory | 显示脚本信息和最近键击和鼠标点击的历史。
KeyWait | 等待按键或鼠标/操纵杆按钮被松开或按下。
ListHotkeys | 显示当前脚本包含的热键，不论它们的子程序当前是否运行，也不论它们是否使用键盘或鼠标钩子。
ListLines | 显示最近执行的脚本行。
ListVars | 显示脚本的变量：它们的名称和当前的内容。
Log() | 返回 Number 的对数（底数为 10）。
Ln() | 返回 Number 的自然对数（底数为 e）。
Loop（普通） | 重复执行一系列命令：可以指定表示重复次数的数字或直到遇到 break。
Loop（文件和文件夹） | 获取指定的文件或文件夹，每次一个。
Loop（解析字符串） | 从一个字符串中获取子字符串（片段），每次一个。
Loop（读取文件内容） | 逐行读取文本文件的内容，每次一行（比 FileReadLine 执行的更好）。
Loop（注册表） | 获取指定的注册表子键的内容，每次一个项目。
Menu | 创建、删除、修改和显示菜单和菜单项。改变托盘图标和它的提示。控制是否可以打开已编译脚本的主窗口。
Mod() | 求模。返回被除数 Dividend 除以除数 Divisor 后得到的余数。
MouseClick | 点击或按住鼠标按钮，或滚动鼠标滚轮。注意：Click 命令通常更灵活和易于使用。
MouseClickDrag | 点击并按住指定的鼠标按钮，接着移动鼠标到目标坐标，然后松开按钮。
MouseGetPos | 获取鼠标光标的当前位置以及鼠标当前悬停的窗口和控件（可选的）。
MouseMove | 移动鼠标光标。
MsgBox | 在含有一个或多个按钮（例如“是”和“否”）的小窗口中显示指定的文本 。
NumGet() | 返回在指定地址+偏移的位置存储的二进制数。
NumPut() | 以二进制格式把数字存储到指定地址+偏移的位置。
OnExit | 指定在脚本退出时自动运行的子程序。
OnMessage() | 指定当脚本接收到特定消息时自动调用的函数。
OutputDebug | 发送字符串到调试器（如果有）显示出来。
暂停 | 暂停脚本的当前线程。
PixelGetColor | 获取指定的 x, y 坐标处像素的颜色。
PixelSearch | 在屏幕某个区域中搜索指定颜色所在的像素。
PostMessage | 放置消息到窗口或控件的消息队列。
Process | 对进程执行下列的其中一个操作：检查进程是否存在；改变进程的优先级；关闭进程；等待进程关闭。
Progress | 创建或更新包含进度条的窗口。
Random | 生成伪随机数。
RegExMatch() | 判断字符串是否包含某个匹配模式（正则表达式）。
RegExReplace() | 替换字符串中匹配模式（正则表达式）出现的地方。
RegDelete | 从注册表中删除子键或值。
RegRead | 从注册表读取值。
RegWrite | 写入值到注册表。
RegisterCallback() | 创建机器码地址，当它被调用时会重定向到脚本中的函数。
Reload | 使用新的脚本实例替换当前正在运行的实例。
Return | 从子程序返回到之前通过函数调用、Gosub、激活 Hotkey、GroupActivate 或其他方式执行跳转的地方。
Round() | 如果 N 省略或为 0，则 Number 被取整到最近的整数。如果 N 为正数，则 Number 被取整到 N 个小数位。如果 N 为负数，则 Number 被取整到十进制小数点左边 N 位。
运行 | 运行外部程序。
RunAs | 指定在后续所有的 Run 和 RunWait 中使用的一组用户凭据。
RunWait | 运行外部程序并等待其结束。
Send / SendRaw / SendInput / SendPlay | 发送模拟键击和鼠标点击到活动窗口。
SendLevel | 控制热键和热字串是否忽略模拟的键盘和鼠标事件。
SendMessage | 发送消息到窗口或控件并等待确认。
SendMode | 让 Send 和 SendInput 或 SendPlay 具有相同的功能而不是默认的（SendEvent）。也使 Click 和 MouseMove/Click/Drag 使用指定的方法。
SetBatchLines | 设置脚本的执行速度（影响 CPU 使用率）。
SetCapslockState | 设置 Capslock 键的状态。还可以强制此键保持打开或关闭状态。
SetControlDelay | 设置在每次控件修改命令执行后自动的延时。
SetDefaultMouseSpeed | 设置在 Click 和 MouseMove/Click/Drag 中没有指定鼠标速度时使用的速度。
SetEnv (Var = Value) | 把指定的值赋给变量。
SetFormat | 设置数学运算得到的整数和浮点数的格式。
SetKeyDelay | 设置每次 Send 或 ControlSend 发送键击后自动的延时。
SetMouseDelay | 设置每次鼠标移动或点击后自动的延时。
SetNumlockState | 设置 Numlock 键的状态。还可以强制此键保持打开或关闭状态。
SetScrollLockState | 设置 Scrolllock 键的状态。还可以强制此键保持打开或关闭状态。
SetRegView | 允许 32 位脚本中的注册表命令访问 64 位注册表视图，反之亦然。
SetStoreCapslockMode | 设置在 Send 后是否恢复 CapsLock 的状态。
SetTimer | 以指定的时间间隔自动并重复运行子程序。
SetTitleMatchMode | 设置在类似 WinWait 命令中 WinTitle 参数的匹配模式。
SetWinDelay | 设置在每次执行窗口命令（例如 WinActivate）后自动的延时。
SetWorkingDir | 改变脚本的当前工作目录。
Shutdown | 关闭、重启或注销系统。
Sin() | 返回 Number 的正弦三角函数值。
Sleep | 在继续前等待指定的时间量。
Sort | 以字母、数字或随机顺序排列变量的内容（可以选择是否移除重复项）。
SoundBeep | 让 PC 扬声器发出蜂鸣音。
SoundGet | 从音频设备中获取各种设置（主静音、主音量等）。
SoundGetWaveVolume | 获取音频设备的波形输出音量。
SoundPlay | 播放音频、视频或其他支持的文件类型。
SoundSet | 改变音频设备的各种设置（主静音、主音量等）。
SoundSetWaveVolume | 改变音频设备的波形输出音量。
SplashImage | 创建或更新含 JPG、GIF 或 BMP 图像的窗口。
SplashTextOn | 创建自定义文本的弹出窗口。
SplashTextOff | 关闭上面的窗口。
SplitPath | 把文件名或 URL 分解成它的名称、目录、扩展名和驱动器。
Sqrt() | 返回 Number 的平方根。
StatusBarGetText | 获取标准状态栏控件的文本。
StatusBarWait | 等待窗口的状态栏包含指定的字符串。
StrPut() / StrGet() | 复制字符串到内存地址或来自内存地址，并可选地对其在不同代码页间进行转换。
StringCaseSense | 设置在字符串比较中是否区分大小写（默认为“不区分大小写”）。
StringGetPos / InStr() | 获取指定的子字符串在某个字符串中的位置。
StringLeft | 从字符串的左边提取一些字符。
StringLen / StrLen() | 获取字符串中包含的字符数量。
StringLower | 把字符串中的英文字母转换成小写。
StringMid / SubStr() | 从字符串的指定位置提取一个或多个字符。
StringReplace | 用新字符串替换指定的子字符串。
StringRight | 从字符串的右边提取一些字符。
StringSplit | 使用指定的分隔符把一个字符串分解成多个子字符串并保存到数组中。
StringTrimLeft | 从字符串的左边移除一些字符。
StringTrimRight | 从字符串的右边移除一些字符。
StringUpper | 把字符串中的英文字母转换成大写。
Suspend | 禁用或启用所有的或选择的热键和热字串。
SysGet | 获取屏幕分辨率、多显示器信息、系统对象的尺寸和其他系统属性。
Tan() | 返回 Number 的正切三角函数值。
Thread | 设置线程的优先级或是否可以被中断。它也可以临时禁用所有的计时器。
Throw | 发出错误发生的信号。此信号可以被 try-catch 语句捕获。
ToolTip | 在屏幕的任意位置创建总是置顶的窗口。
Transform | 执行各种数学计算、按位运算以及类似 ASCII/Unicode 转换的任务。
TrayTip | 在托盘图标附近创建气球提示窗口。
Trim | 移除字符串的开始和/或末尾的某些字符。
Try | 守护一个或多个语句（命令或表达式）以防备由 throw 命令抛出的运行时错误和异常。
Until | 根据条件判断是否继续执行 Loop 或 For 循环。
UrlDownloadToFile | 从互联网下载文件。
Var = value | 把指定的值赋给变量。
Var := expression | 计算表达式并把结果保存到变量。
VarSetCapacity() | 增加或清空变量占用的内存。通常只有在特殊情况下才需要，例如 DllCall。
While 循环 | 重复执行一系列命令，一直到指定的表达式计算结果为假。
WinActivate | 激活指定的窗口（让它置于最前面）。
WinActivateBottom | 和 WinActivate 一样，只是此命令激活最下面的（最早激活的）匹配窗口而不是最上面的。
WinActive() | 返回匹配指定条件的活动窗口的 唯一 ID（HWND）。
WinClose | 关闭指定的窗口。
WinExist() | 返回首个匹配窗口的唯一 ID（HWND）。
WinGetActiveStats | 组合了 WinGetActiveTitle 和 WinGetPos 两个命令的功能。
WinGetActiveTitle | 获取活动窗口的标题。
WinGetClass | 获取指定窗口的类名。
WinGet | 获取指定窗口的唯一 ID、进程 ID、进程名或控件列表。它还可以获取匹配指定条件的所有窗口的列表。
WinGetPos | 获取指定窗口的位置和大小。
WinGetText | 获取指定窗口的文本。
WinGetTitle | 获取指定窗口的标题。
WinHide | 隐藏指定的窗口。
WinKill | 强制关闭指定的窗口。
WinMaximize | 最大化指定的窗口。
WinMenuSelectItem | 调用指定窗口菜单栏中的菜单项。
WinMinimize | 缩小指定窗口为任务栏上的按钮。
WinMinimizeAll | 最小化所有窗口。
WinMinimizeAllUndo | 反转前面 WinMinimizeAll 的效果。
WinMove | 改变指定窗口的位置和/或大小。
WinRestore | 如果指定的窗口处于最小化或最大化状态，则还原它。
WinSet | 对指定的窗口进行各种设置，例如“总在最前面”和透明度。
WinSetTitle | 改变指定窗口的标题。
WinShow | 显示指定的窗口。
WinWait | 等到指定的窗口出现。
WinWaitActive | 等到指定的窗口处于活动状态。
WinWaitClose | 等到指定的窗口消失。
WinWaitNotActive | 等到指定的窗口处于不活动状态。
#ClipboardTimeout | 改变当首次访问剪贴板失败后脚本会继续尝试访问剪贴板的持续时间。
#CommentFlag | 把脚本的注释符号从分号改为其他字符串。
#ErrorStdOut | 把阻止脚本运行的任何语法错误发送到标准输出而不显示在对话框中。
#EscapeChar | 改变脚本的转义符（例如：反斜线与重音符）。
#HotkeyInterval | 与 #MaxHotkeysPerInterval 一起指定热键激活的速率，超过此速率会显示警告对话框。
#HotkeyModifierTimeout | 影响热键修饰符的行为：CTRL、ALT、WIN 和 SHIFT。
#Hotstring | 改变热字串选项或终止符。
#If | 类似于 #IfWinActive，但可以是任意类型的表达式。
#IfTimeout | 设置计算单个 #If 表达式可以使用的最大时间。
#IfWinActive / #IfWinExist | 创建上下文相关的热键和热字串。这样的热键会根据窗口是否活动或存在的不同情况执行不同的动作（或什么都不做）。
#Include | 让脚本认为指定文件的内容会出现在这个准确的位置。
#InputLevel | 控制热键和热字串是否忽略模拟的键盘和鼠标事件。
#InstallKeybdHook | 强制无条件安装键盘钩子。
#InstallMouseHook | 强制无条件安装鼠标钩子。
#KeyHistory | 设置在 KeyHistory 窗口中显示的键盘和鼠标事件的最大数目。您可以将其设置为 0 来禁用按键历史。
#LTrim | 启用或禁用延续片段中缩进的去除。
#MaxHotkeysPerInterval | 与 #HotkeyInterval 一起指定热键激活的速率，超过此速率会显示警告对话框。
#MaxMem | 设置每个变量可使用的最大内存兆数。
#MaxThreads | 设置可同时存在的线程的最大数目。
#MaxThreadsBuffer | 当某些或所有的热键达到 #MaxThreadsPerHotkey 限制时，这个指令让它们缓冲而不是忽略键击。
#MaxThreadsPerHotkey | 设置每个热键或热字串可同时存在的最大线程数。
#MenuMaskKey | 改变用来屏蔽 Win 或 Alt keyup 事件的按键。
#NoEnv | 不检查空变量是否为环境变量（建议所有新脚本使用）。
#NoTrayIcon | 不显示托盘图标。
#Persistent | 让脚本持久运行（即直到用户关闭或遇到 ExitApp）。
#SingleInstance | 决定当脚本已经运行时是否允许它再次运行。
#UseHook | 强制使用钩子实现全部或部分键盘热键。
#Warn | 启用或禁用为选择的情况提示开发者错误的警告。
#WinActivateForce | 跳过温和的方法而直接使用强制的方法激活窗口。


AutoHotkey 脚本展示

NiftyWindows (美妙的窗口)-- 作者: Enovatic-Solutions: 此脚本让您轻松地控制所有基本的窗口操作, 例如拖动, 调整大小, 最大化, 最小化和关闭. 它最强大的功能是通过拖动鼠标右键来激发. 想象将每个窗口分成一个虚拟的三行三列的 9 个单元组成的网格. 中心的单元是其中最大的: 通过点击并按住鼠标右键您可以抓取窗口并到处移动. 通过同样的方法使用其他八个单元来调整窗口的大小. NiftyWindows 还提供了对齐到网格, "保持窗口高宽比", 卷起窗口到它的标题栏, 透明度控制以及其他有用的快捷功能.

Screen Magnifier (屏幕放大镜) -- 作者: Holomind: 这个屏幕放大镜比操作系统自带的那个有好多优点, 包括: 可自定义的刷新间隔和放大倍数 (包括缩小/反放大); 抗锯齿从而提供更高质的输出; 并且它是开源的 (因此, 有很多变体可供选择, 或者您可以自己对脚本进行调整).

LiveWindows (实况窗口): 通过缩略图观察对话框 -- 作者: Holomind: 此脚本通过显示每个对话框和它的进度条的小型副本 (会自动检测对话框, 即使它们在其他窗口后面) 来让您监视下载进度, 文件复制以及其他对话框. 预览窗口置顶显示, 不过只使用了非常小的屏幕空间 (还可以拖动它的边缘来调整大小). 您也能监视任意窗口, 只需在感兴趣的区域拖拉出一个矩形选框 (拖拉时需按住 control 和 shift 键), 然后按下 Win+W 来在预览窗口中实时显示选区.

Mouse Gestures (鼠标手势) -- 作者: deguix: 此脚本在您按住鼠标右键时会监视鼠标移动的轨迹. 如果它看到您 "画" 出一个能识别的形状或符号, 那么它会启动程序或执行由您选择的自定义动作 (就像热键那样). 请参阅内含的 README 文件了解如何定义手势.

Context Sensitive Help in Any Editor (任意编辑器中的上下文相关帮助) -- 作者: Rajat: 此脚本设置 Ctrl+2 (或您选择的其他热键) 来显示选择的 AutoHotkey 命令或关键字的帮助文件页面. 如果没有选择任何内容, 那么会提取当前行开始处的命令名.

Easy Window Dragging (轻松拖曳窗口) (需要 XP/2k/NT): 一般情况下只能通过点击标题栏来拖动窗口. 这个脚本扩展到可以在窗口中任何一点拖动窗口. 要激活这种模式, 请在点击时按住 CapsLock 或鼠标中键, 然后拖动窗口到新的位置.

Easy Window Dragging (轻松拖曳窗口) -- KDE 风格 (需要 XP/2k/NT) -- 作者: Jonny: 使用此脚本可以轻松移动窗口或改变它的大小: 1) 按住 ALT 键并在窗口内的任意位置点击左键来拖动窗口到新的位置; 2) 按住 ALT 并在窗口内任意位置点击右键后拖动来轻松调整它的大小; 3) 按下 ALT 两次, 但在第二次松开前, 点击左键来最小化鼠标光标下的窗口, 点击右键进行最大化或点击中键进行关闭.

Easy Access to Favorite Folders (轻松访问收藏夹) -- 作者: Savage: 当您在某些类型的窗口活动时点击鼠标中键, 脚本会显示您的收藏夹菜单. 选择收藏夹中的文件夹后, 脚本会让活动窗口立即切换到那个文件夹. 支持下列窗口类型: 1) 标准的文件打开或文件保存对话框; 2) 资源管理器窗口; 3) 控制台 (命令提示符) 窗口. 对于不支持的窗口类型也可以显示此菜单, 此时选择的收藏夹中的文件夹会在新的资源管理器窗口中打开.

IntelliSense (智能感应) -- 作者: Rajat (需要 XP/2k/NT): 此脚本会在您编辑 AutoHotkey 脚本时进行监视. 当它看到您输入命令后跟着逗号或空格后, 会显示此命令的参数列表以给您提示. 此外, 您可以按下 Ctrl+F1 (或您选择的其他热键) 来显示帮助文件中此命令的页面. 要取消参数列表, 请按 Escape 或 Enter.

Using a Joystick as a Mouse (把操纵杆映射为鼠标): 此脚本把操纵杆转换为三键的鼠标. 它允许每个按钮像鼠标按钮那样拖动, 且它几乎不消耗 CPU 时间. 还有, 您将操纵杆推离中央越远, 它会让光标移动的越快. 您可以在脚本的顶部个性化各种设置.

Joystick Test Script (操纵杆测试脚本): 此脚本帮助您判断操纵杆的按钮数目和其他属性. 它还可能显示您的操纵杆是否需要校准; 即它的每个轴向的活动范围是否在百分之零到百分之百的范围内, 这是它应该处于的范围. 如果需要校准, 请使用操作系统控制面板或操纵杆的自带软件.

On-Screen Keyboard (屏幕键盘) (需要 XP/2k/NT) -- 作者: Jon: 此脚本会在屏幕的底部创建一个模拟键盘来实时显示您按下的按键. 我写这个是为了帮我学习盲打 (来适应不去看键盘). 在脚本的顶部可以自定义屏幕键盘的大小. 还有, 您可以双击托盘图标来显示或隐藏键盘.

Minimize Window to Tray Menu (最小化窗口到托盘菜单): 此脚本会设置您选择的热键来隐藏任意的窗口, 让这些窗口成为脚本托盘菜单底部的条目. 通过在菜单上选择相应的项目可以显示个别隐藏的窗口或全部显示. 如果由于任何原因脚本退出了, 那么它隐藏的所有窗口都会自动显示.

Changing MsgBox's Button Names (改变 MsgBox 的按钮名称): 这是个可运行示例脚本, 它使用计时器来改变 MsgBox 对话框中按钮的名称. 尽管改变了按钮名称, 但 IfMsgBox 命令中仍需要引用它们原始的按钮名称表示的按钮.

Numpad 000 Key (小键盘上的 000 键): 此示例脚本把某些小键盘上特殊的 000 键设置为等号键. 您可以用您想要的语句替换 Send, = 来改变动作。

Using Keyboard Numpad as a Mouse (把小键盘作为鼠标使用) -- 作者: deguix: 此脚本用您的键盘来实现鼠标操作, 几乎相当于真正的鼠标 (在一些任务中甚至更方便). 它支持多达五个鼠标按钮和鼠标滚轮的转动. 它还具有能自定义移动速度, 加速和 "轴反转" 的特点.

Seek (搜索) -- 作者: Phi: 浏览开始菜单可能是件麻烦事, 尤其在您安装了很多程序的时候. 'Seek' 能让您指定不区分大小写的关键词/短语, 用它从开始菜单里筛选出匹配的程序和目录, 以便您可以轻松地从少数匹配的项目中打开目标程序. 这样就不用在开始菜单中做查找和穿越的苦力活了.

ToolTip Mouse Menu (鼠标菜单型的工具提示) (需要 XP/2k/NT) -- 作者: Rajat: 此脚本显示弹出菜单来响应短暂地按住鼠标中键的动作. 左键点击来选择菜单项. 在菜单外点击来取消菜单. 最近的改进是可以根据活动的窗口类型来改变菜单的内容 (这里使用了记事本和 Word 作为例子).

Volume On-Screen-Display (OSD) (屏显音量) -- 作者: Rajat: 此脚本把您选择的热键设置为增加和降低总音量和/或波形音量. 这两种音量以不同的颜色条图形显示.

Window Shading (卷起窗口到标题栏) (窗口遮蔽) -- 作者: Rajat: 此脚本通过单个热键实现裁减窗口到它的标题栏, 再次使用热键后恢复为原始大小. 这种方式可以裁减任意数目的窗口 (脚本会记住每个窗口原来的大小). 如果脚本由于任何原因退出了, 那么所有 "卷起" 的窗口会自动恢复为它们原来的高度.

WinLIRC Client (WinLIRC 客户端): 每当您在遥控器上按下按钮时此脚本会接收到来自 WinLIRC 的通知. 它可以用来自动操作 Winamp, Windows Media Player, 等等. 它配置起来很简单. 例如，如果 WinLIRC 能识别您遥控器上名称为“VolUp”的按钮，那么创建名为 VolUp 的标签并在它后面使用命令 SoundSet +5 来增加声卡 5% 的音量。

1 Hour Software (1 小时软件) -- 作者: skrommel: 这是大量有用的脚本集合, 带有简短的说明和截图地专业呈现出来.

Titan 的脚本: 这个集合包含许多有用的脚本, 例如:
1) XML 阅读器/写入器: 通过简单的界面来获取和写入 XML 文件中的值, 就像 JavaScript.
2) 锚: 让 GUI 控件紧贴可调整大小的 GUI 窗口的右边或底部的边缘.
3) 函数: 包装函数的集合, 其中的每个函数是从含有 OutputVar 的 AutoHotkey 命令包装而成.
4) 天气: 在托盘菜单中显示当前天气状况或在富 GUI 中显示预报.

Toralf 的脚本: 这个集合包含了有用的脚本, 例如:
1) AHK Window Info: 显示窗口, 控件等等的信息.
2) 电子节目指南: 浏览您当地的电视节目/时间表 (支持多个国家).
3) 自动语法整理器: 改变脚本中命令的缩进和大小写形式以使它使用一致的格式/风格.

Sean 的脚本: 包含有用的脚本, 例如:
1) 网络下载/上传流量计: 在小且置顶的进度条中显示网络下载/上传的流量 (单位为 KB).
2) StdoutToVar: 重定向命令或应用程序的输入到脚本的变量中.
3) 截取屏幕的矩形区域: 用来截取部分屏幕并保存为文件 (BMP/JPG/PNG/GIF/TIF) 的函数. 它也能截取透明窗口和鼠标指针.
4) 颜色放大器/选取器: 放大光标周围的区域, 允许选取单个像素并识别它的颜色.
5) 嵌入 Internet Explorer 控件: 嵌入 MSIE 控件到脚本的 GUI 窗口. 此控件能进行网页显示或其他兼容于浏览器的功能.

SKAN 的 N 个技巧提示：包含实实用效果和常用功能的示例代码和技术。

论坛的 Scripts & Functions 版块: 这是一个近 1000 个可运行脚本和函数的可搜索集合. 由 AutoHotkey 用户建立和维护, 这个存档每天都在增长和改进.

-- 主页 --


变更和新功能

下面列出了 AutoHotkey 当前开发分支（也称为 AutoHotkey_L）新增的功能。

对于较旧的变更，请参阅存档变更。

1.1.15.01 - 2014 年 6 月 30

改变内置的错误和警告对话框为置顶。

修正 Until 不会从递归的文件和注册表循环中中断的错误。

1.1.15.00 - 2014 年 5 月 4 日

添加 A_OSVersion 值 WIN_8.1。

改变 Hotkey 命令根据是否存在颚化符（~）前缀应用或移除热键已有变体的穿透行为。

改变 exe manifest 以允许 GetVersion/GetVersionEx 检测到 Windows 8.1。

1.1.14.04 - 2014 年 4 月 25 日

修正当 Function 为纯整数 0 时 DllCall() 会让脚本崩溃的问题。

修正 IsFunc("ComObj(") 返回错误而不抛出异常的问题。

修正 ControlClick 发送 XButton1/XButton2 时存在的问题。

1.1.14.03 - 2014 年 2 月 14 日

修正当 X.__Init 中止线程时 new X 中内存泄漏的问题。

修正当断点散布在方法定义中时会转移到类变量初始化位置的问题。

1.1.14.02 - 2014 年 1 月 30 日

修正 x:: 和 x up::，当 x 作为修饰键被阻止在按下触发时则让它们都在弹起时才触发。在 v1.1.14 中的预期行为是当 x 还用于自定义组合键（如 x & y::）的时候，则 x 的单独热键和组合键都会在弹起时触发。

1.1.14.01 - 2014 年 1 月 15 日

修正不带 Catch/Finally 的 Try 过程中无异常抛出时崩溃的错误。

1.1.14.00 - 2014 年 1 月 15 日

增加 Finally 语句用于 try/catch 后的清理操作。[fincs]

改变自定义组合键中 ~ 前缀的行为，使之更直观。

修正 x & y:: 热键中，在释放x时会触发 x:: 和 x up:: 热键的问题。

修正 ImageSearch，当 GDI 调用失败时设置 ErrorLevel=2（而非0）。

修正 EnvGet，当变量超过 32767 个字符时致使程序崩溃的问题。

修正在 StatusBarWait 的 ErrorLevel 中一个小的错误处理缺陷。

修正 ANSI 版本中 FileRead *c 存在的堆损坏。

修正递归调用中传递局部变量到可变参数函数。

修正脚本第一行为小括号括住的表达式时，脚本加载失败的问题。

修正 PixelSearch 快速模式，使其仅在成功时才设置 OutputVarX/Y。

1.1.13.01 - October 11, 2013

Fixed variadic function calls with named values for required parameters.

1.1.13.00 - August 27, 2013

Ported StrSplit() from v2 alpha.

1.1.12.00 - August 14, 2013

Optional parameters can be omitted by writing two consecutive commas, as in InStr(a, b,, 2). Unlike previous versions, this now works for objects (including COM objects) and built-in functions. [a,,b] can be used to create a sparse array.

Object properties can now be set using variadic syntax, as in x[y*]:=z, where y contains an array of keys/indices or parameters.

1.1.11.02 - July 28, 2013

Fixed GuiControl/Get to accept the ClassNN of a ComboBox's child Edit. Specifying the HWND of a ComboBox's child Edit was already supported as a means of identifying the ComboBox.

1.1.11.01 - June 25, 2013

Fixed InputBox default width/height (broken by v1.1.11.00 - commit 7373cc6443).

Fixed DllCall arg type validation to handle SYM_OBJECT safely, and to respect #Warn UseUnset (when var name is not a valid type).

Changed VarSetCapacity(var) to never warn about uninitialized vars.

1.1.11.00 - June 21, 2013

Added support for %A_LineFile% in #Include.

Reduced the file size of AutoHotkeySC.bin by reducing the resolution of the (rarely used) filetype icon.

Fixed class X extends Y to allow Y to be defined after X.

Developed by fincs: AutoHotkey is now DPI-aware. The Gui commands automatically compensate when DPI is not 96. See Gui -DPIScale.

1.1.10.01 - May 17, 2013

Improved RegRead to support REG_BINARY values larger than 64K.

Improved RegWrite to support REG_BINARY/REG_MULTI_SZ values larger than 64K.

Fixed Process Close (and possibly other things) on Windows XP.

1.1.10.00 - May 11, 2013

Added basic support for custom Gui control types.

Revised SoundSet, SoundGet and 'WaveVolume commands to better support Windows Vista and later.

Fixed Run "<file>" <args> to not pass the space as part of the args.

Fixed some issues with reading from console input (CONIN$).

1.1.09.04 - March 14, 2013

Fixed Gui menu accelerator keys not working when the Gui itself (not a control) has focus.

1.1.09.03 - February 9, 2013

Fixed two bugs which affected certain assignments where the target variable contains an unflushed binary number but has zero capacity.

Fixed GuiControl and GuiControlGet acting on the wrong control when given a HWND which does not belong to the current Gui. Instead, the condition is treated as an error.

Fixed OnMessage functions to set A_Gui and A_GuiControl correctly when the target Gui is a child window.

1.1.09.02 - December 24, 2012

Fixed MsgBox to show an error message when given invalid Options, instead of silently exiting the thread.

Fixed syntax errors in class var initializers causing the program to crash without the proper error message.

1.1.09.01 - December 15, 2012

Fixed AND/OR following a multi-statement comma, like ((x, y) and z).

Fixed RegExReplace to support duplicate subpattern names correctly.

Fixed Object.Remove() not freeing string keys.

Fixed base.Invoke() to not depend on dynamic variable resolution.

1.1.09.00 - November 7, 2012

Breaking changes:

Removed .aut file compatibility and #AllowSameLineComments.

Removed undocumented AutoIt v2 commands.

Backward-compatible changes:

Allow optional parameters to be declared with := instead of =, for consistency with variable declarations and expressions.

Allow non-ASCII characters in unquoted keys ({key: x} and obj.key).

Changed name in version info from "AutoHotkey_L" to "AutoHotkey".

Bug-fixes:

Fixed instability caused by warning dialogs appearing part-way through evaluation of a command's args.

Fixed PixelSearch Fast mode treating "not found" as an error.

Fixed ahk_exe to allow other ahk_ criteria after it.

Fixed else continue 2 and similar requiring braces around the loop.

Fixed RegRead indicating failure after successfully reading binary data.

Fixed File.Length to compensate for or flush any buffered data.

Fixed Gui sizing to account for scrollbars when present.

Debugger:

Added support for asynchronous commands.

Improved handling of breakpoints on lines like else foo() or { bar() so that the debugger will actually break when appropriate.

Optimized code size, fixed several bugs and made the debugger generally more robust.

1.1.08.01 - August 3, 2012

Debugger: Fixed max_depth being either half the intended limit or unlimited.

1.1.08.00 - July 14, 2012

Breaking changes:

Changed the default script codepage to ANSI, as the previous behaviour was a common source of confusion. UTF-8 files must now have a byte order mark (BOM) to be recognized correctly. Notepad adds a BOM to any file saved as UTF-8.

Changed return x to preserve formatting of numeric strings; it is now equivalent to return (x).

Changed Gui, Name: New to set the new GUI as the default.

Other changes:

Changed ClipboardAll to prefer CF_UNICODETEXT over other text formats.

Changed Gui Show to allow floating-point numbers.

Changed A_OSVersion to return WIN_8 on Windows 8.

Changed AutoHotkey.exe file description to include "ANSI/Unicode 32/64-bit".

Changed the parser to allow lines like new MyObject() with no assignment.

Upgraded PCRE to 8.30.

Improved wording of some warnings and added a pointer to the documentation at the bottom of the warning dialog.

Improvements to the debugger:

  • Added basic support for inspecting Func, ComObject and RegExMatchObject objects.
  • Fixed the "attach debugger" message being ignored in some situations. See commit 83f0a0e.

New features:

Added support for the PCRE construct (*MARK:NAME) via RegExMatchObject.Mark.

Added support for classvar.x := y assignments in class definitions (after declaring classvar).

Added A_Is64bitOS.

Added SetRegView and A_RegView.

Fixes:

Fixed Func.() to merely skip the function call if mandatory parameters were omitted instead of causing the thread to silently exit.

Fixed Object.Remove() not releasing object keys.

Fixed key-down/key-up hotkey pairs to suppress input correctly when only one hotkey in the pair is enabled.

Fixed #Include <Lib> to not affect the working directory used by subsequent #include directives.

Fixed objaddref() acting like ObjRelease() when called with a lower-case 'a'.

Fixed A_AhkPath in 32-bit compiled scripts to detect 64-bit AutoHotkey installations and vice versa.

Fixed TreeView controls with -Background option rendering incorrectly on older OSes.

Fixed error messages shown during execution of While/Until to identify the appropriate line.

1.1.07.03 - March 25, 2012

Fixed Ctrl/Alt/Shift key-down hotkey breaking any corresponding key-up hotkey defined before it.

Fixed key-down hotkeys to always use the hook if defined after a key-up hotkey of the same key. If the key-down hotkey used the "reg" method, the hook would block the key-down event and trigger only the key-up hotkey.

Fixed load-time checks interpreting expressions with no derefs as raw text. For example, gosub % "foo" resolved to "foo": at load-time. Similarly, % "" was seen as invalid in various cases even if an empty string should be allowed.

1.1.07.02 - March 22, 2012

Fixed a rare crash which can occur when GetClipboardData() fails.

Fixed ComObjArray() to return an empty string on failure instead of an arbitrary integer.

Fixed Object.Remove(i, "") affecting integer keys when !Object.HasKey(i).

1.1.07.01 - March 2, 2012

Fixed FileRead to ignore #MaxMem when reading UTF-16 on Unicode builds.

Fixed dynamic function calls with built-in vars such as %A_ThisLabel%().

1.1.07.00 - February 27, 2012

Enhanced %var%() to support function references, objects imitating functions and the default __Call meta-function.

Fixed ControlGet List to work for ListViews where the script and the target process aren't both 32-bit or both 64-bit.

Fixed SendEvent with a key delay of 0; a change introduced by v1.1.05.04 caused it to be slower than intended.

Fixed Object.Remove(i) not adjusting keys if Object[i] doesn't exist.

Fixed an error in ComObjType() which may have caused unpredictable behaviour when it is called via an alternative name.

Fixed ExitApp to exit the thread if an OnExit subroutine prevents the script from terminating, instead of resuming execution after the block which contained ExitApp.

Calling a function via an object no longer acts as a barrier to exiting the thread. Consequently, if Exit is used or a runtime error occurs within a class method, the entire thread exits instead of just the function.

Calling a base-class method using base.Method() or similar inside a class definition no longer causes a UseUnset warning if the method doesn't exist. Consequently, instantiating an object which has instance variables no longer causes a warning about the internal base.__Init method if the base class has no instance variables.

1.1.06.02 - February 13, 2012

Fixed IniRead crashing when Section is omitted but Key isn't.

Fixed accuracy of FileGetSize with files which are 4GB or larger.

1.1.06.01 - February 12, 2012

Fixed MsgBox smart comma handling to require numeric Options, not Title.

1.1.06.00 - February 12, 2012

New features:

Integrated #InputLevel directive and SendLevel command by Russell Davis.

Integrated support for Link controls by ChrisS85.

Breaking changes:

Changed command parser to avoid trimming escaped characters such as `t or `  at the beginning or end of an arg.

Changed MsgBox's smart comma handling to improve flexibility and consistency.

  • % can now be used to make Options or Timeout an expression.
  • If the first arg is an expression, any unescaped comma which is not enclosed in quote marks or parentheses/brackets/braces will cause multi-arg mode to be used. These commas were formerly interpreted as multi-statement operators within the first-and-only arg (Text).
  • When Title is an expression, unescaped commas contained within the expression no longer interfere with smart comma handling.
  • If there are exactly two args and the first is empty or an integer, multi-arg mode is used. The former behaviour was to combine both into a single arg (Text).
  • Timeout can be a literal number or a single deref (and optionally part of a number; for example, %Timeout%.500). Contrary to the documentation, the former behaviour interpreted most other cases beginning with % as expressions (containing a double-deref).
  • Title can be an expression even if Text and Options are omitted.

Changed A_IsUnicode/A_IsCompiled to be defined as an empty string in ANSI versions/uncompiled scripts instead of being left undefined. This allows them to be checked without triggering #Warn warnings. Side effects include:

  • Attempting to assign directly to A_IsCompiled or A_IsUnicode always causes a load-time error. Dynamic assignments always fail, either silently or with an error dialog as appropriate. Previously assignments were allowed in uncompiled/non-Unicode scripts.
  • Attempting to take the address of A_IsCompiled or A_IsUnicode always fails.
  • A_IsCompiled and A_IsUnicode no longer appear in ListVars when referenced by a script which is not compiled/Unicode.

Changed Send and related commands to respect #MenuMaskKey when changing modifier keystates.

Other changes:

Changed GuiControl Choose to remove the ListBox/ComboBox/DDL's current selection when N=0.

Changed RegisterCallback to allow a Func object in place of a name.

Changed ListLines to show filenames (except when compiled).

Improved Run to output a process ID if possible when ShellExecuteEx is used.

Fixes:

Fixed handle leaks in RegRead.

Fixed x.y++ and similar to assign an empty string if x.y is non-numeric.

Fixed SendInput Win+L workaround causing Win key to "stick down".

Fixed Ahk2Exe auto-including the wrong file if an auto-include used #Include <Lib>.

1.1.05.06 - December 31, 2011

Fixed inc (++) and dec (--) having no effect when used on an object field containing a string.

Fixed inc (++) and dec (--) to cause a warning when used on an uninitialized variable.

1.1.05.05 - December 17, 2011

Fixed continue n misbehaving when an inner loop has no braces.

Fixed RegExMatchObject[Name] to work correctly with duplicate names.

1.1.05.04 - December 5, 2011

Fixed: Selected sub-command of ControlGet was unreliable on x64.

Fixed: CPU was maxed out while waiting if an underlying thread displayed a dialog (and possibly in other cases).

1.1.05.03 - November 30, 2011

Fixed Loop ... Until VarContainingObject.

1.1.05.02 - November 20, 2011

Fixed false detection of end-of-file when loading a compiled script in some cases.

Fixed SendInput to automatically release modifier keys when sending special characters or {U+xxxx} (which was broken by v1.1.00.01).

Fixed ComObjConnect to filter out non-dispatch interfaces instead of allowing the script to crash.

Fixed new %VarContainingClassName%().

1.1.05.01 - October 16, 2011

Fixed class declarations to allow directives such as #Include.

1.1.05.00 - October 8, 2011

Added Client coordinate mode.

Added object output mode for RegExMatch and RegEx callouts.

Added super-global declarations, which avoid the need to repeat global declarations.

Breaking change: Class declarations such as Class c now create a super-global variable instead of an ordinary global.

Added more detail to unhandled exception error dialogs.

Changed Gui +Owner to work even after the GUI is created.

Changed instance var declarations in class definitions to avoid leaving empty key-value pairs in the class object.

Changed #Include to use standard error message formatting when it fails (more detail; also respects ErrorStdOut).

Changed Throw to throw an Exception object by default when its parameter is omitted.

Changed format of runtime error messages slightly to improve consistency and code size.

Modified PCRE to use UTF-16 for input on Unicode builds, for performance.

Upgraded PCRE to 8.13.

Fixed thread not exiting as intended when an assignment in an expression fails.

Fixed #MaxMem preventing assignments to variables which don't require expansion.

Fixed inability of Try/Catch to catch COM errors.

Fixed GuiControlGet incorrectly treating parameter #2 as invalid in some cases.

Fixed input vars being resolved too soon, allowing them to be invalidated by an expression later on the same line.

Fixed RegEx callouts not causing matching to abort when an exception is thrown.

Fixed DllCall setting ErrorLevel to -4 when it should be -3.

Fixed While appearing twice in ListLines for its first iteration.

Fixed Try/Catch to allow If/Loop/For/While with no enclosing block.

Fixed enumerator object not being released when Until is used to break a For-loop.

1.1.04.01 - September 15, 2011

Fixed FileRemoveDir setting ErrorLevel incorrectly.

1.1.04.00 - September 11, 2011

This release contains a number of potentially script-breaking changes.

Added exception handling support: try/catch/throw and Exception().

Added StdOut mode for #Warn.

Added Gui +HwndVARNAME option.

Added Gui, New [, Options, Title].

Added automatic support for keyboard accelerators such as Ctrl+O in Gui menus.

Changed handling of #Include <Lib> when the /iLib command-line switch is present to resolve a problem with Ahk2Exe.

Changed GuiControl to retain the Progress control's current value when its style is changed.

Changed GuiControl and GuiControlGet to allow a HWND to be passed in the ControlID parameter.

Removed the 1GB limit from FileRead.

Improved error detection:

  • Hotkey, If, Expression, where Expression does not match an existing #If expression, is caught at load-time when possible.
  • Hotkey, IfSomething, where Something is invalid, is caught at load-time.
  • Class definitions with missing braces are detected as errors.
  • If a function call is used on the first line of a class definition, it is now correctly treated as an error.
  • GroupAdd now shows an error message when the group name is blank, instead of silently exiting the thread.
  • Removed some redundant "unset var" warnings which appeared when using the OutputDebug or StdOut warning modes.
  • If an unrecognized option is used with Gui, Gui Show, Gui New or GuiControl, an error message is shown and the thread exits unless try is used. This validation is not done at load-time due to complexity (it is common for the option parameters to contain variable references).
  • RegRead, RegWrite and RegDelete now set A_LastError to the result of the operating system's GetLastError() function.
  • +LastFoundExist is now treated as an error if it is combined with another option (+LastFound should be used in that case).

Fixed a bug affecting recursive variadic functions.

1.1.03.00 - August 28, 2011

Added support for GUI names.

Added support for identifying a GUI by its HWND.

Added +Parent%ParentGui% Gui option.

Added support for external windows as Gui owners via +Owner%HWND%.

Added Name sub-command for GuiControlGet.

Added support for ActiveX controls via the Gui command.

Fixed: Empty hotkey control returned "vk00".

Fixed: Crashes and memory leaks related to COM events/ComObjConnect.

Fixed: GuiControlGet OutputVar, Subcmd, %OutputVar% always failed.

Changed "Missing (/[/{" error messages to "Unexpected )/]/}" for greater clarity.

Changed ListLines to display While and Until lines which are executed each iteration.

Changed ~= to have higher precedence than =/!=/</>/<=/>= but lower than concat, and added it to the documentation.

1.1.02.03 - August 21, 2011

Fixed (Debugger): numchildren attribute did not include Object.Base.

1.1.02.02 - August 20, 2011

Fixed: Variable capacity was capped at 2GB on x64 builds.

Fixed: Last Found Window not set by #if WinExist(T).

1.1.02.01 - August 13, 2011

Changed A_PriorKey to exclude key-up events.

Fixed process name/path retrieval in certain cases, including:

  • Retrieving name/path of a 64-bit process from a 32-bit script.
  • Retrieving name/path of an elevated process from a non-elevated process (UAC).

1.1.02.00 - August 6, 2011

Added TV_SetImageList().

Characters which require non-standard shift states 16 and 32 now use a fallback method instead of producing the wrong keystrokes.

Revised handling of dead keys to solve problems which occur when multiple scripts with hotstrings are active.

1.1.01.00 - July 30, 2011

Added support for instance variables in class definitions, using simple assignment syntax.

Removed var keyword used in class definitions; use static instead.

Added new built-in variables: A_ScriptHwnd and A_PriorKey.

Added new built-in functions: GetKeyName(), GetKeyVK(), GetKeySC() and IsByRef().

Added new sub-command: WinGet, OutputVar, ProcessPath.

Added the capability to specify a window by process name or path: ahk_exe %Name%.exe or ahk_exe %FullPath%.

Optimized ProcessName sub-command of WinGet.

Changed SetTimer to use A_ThisLabel if Label is omitted.

Updated ComObjConnect() to support using an object in place of a function name prefix.

Improved ComObjConnect() to allow the prefix/object to be updated without first disconnecting.

Improved parsing of continuation sections to allow expressions like (x.y)[z]() without escaping "(".

Replaced the method used to store script text in 32-bit compiled scripts; now consistent with 64-bit.

Fixed detection of AltGr in the active window's keyboard layout (on Unicode builds).

Fixed SendInput applying a redundant LCtrl-up some time after AltGr-up.

1.1.00.01 - July 17, 2011

Fixed: Modifier keys weren't auto-released when sending special chars.

Fixed: Scancode/modifier-key mapping conflicts such as sc1xx vs ^sc0xx.

Fixed: $ and #UseHook had no effect if used only on the second or subsequent instance(s) of a hotkey.

Fixed: Potential crash when returning a value from a __Delete meta-function.

Fixed: "Uninitialized variable" warnings were triggered by the debugger.

Changed: base.Method() no longer triggers a default meta-function or a warning.

Changed: Gui +(Ex)Style no longer hides/shows the Gui.

Changed the debugger to report type="undefined" for uninitialized variables.

Added check to avoid incorrectly sending keystrokes for characters which actually require the "hankaku" key.

Added support for integers as class variable names.

Added "Static" keyword for declaring class variables.

1.1.00.00 - May 1, 2011

New features:

Implemented basic class definition syntax.

Implemented the new keyword for creating a derived object.

Added Func() for retrieving a reference to an existing function and improved IsFunc to recognize function references.

Added support for ++ and -- with object fields, such as x.y[z]++.

改变:

Changed __Delete to not trigger __Call.

Changed OnClipboardChange to use AddClipboardFormatListener when available (i.e. on Windows Vista and later) to improve reliability.

Auto-concat with ( is more selective, so some invalid expressions like 12(34) will no longer work.

Fixes:

Fixed SetTimer Label, -0 to be treated as "run-once, very soon".

Fixed A_MyDocuments etc. to use SHGetFolderPath instead of undocumented registry keys.

Fixed non-empty ExcludeText causing windows with no text to be excluded.

1.0.97.02 - April 14, 2011

Fixed misinterpretation of comma as an arg delimiter when enclosed in {} in an expression.

Fixed For-loop to set A_Index only after the Expression arg is evaluated, so that the outer loop's value can be used.

Fixed default script location to be based on the directory containing the EXE (as documented), not the working directory.

Improved load-time validation to detect invalid attempts to jump out of a function with Goto.

1.0.97.01 - April 2, 2011

Fixed the 64-bit build to not truncate HWNDs or SendMessage/PostMessage params to 32 bits.

Fixed */:: being treated as an invalid hotkey (broken since L54).

Fixed the icons.

1.0.97.00 - March 28, 2011

Added {key: value} as syntax sugar for Object("key", value).

Added [x, y, z] as syntax sugar for Array(x, y, z), which is a new function equivalent to Object(1, x, 2, y, 3, z).

Added slight optimization: resolve any reference to True, False, A_PtrSize or A_IsUnicode in expressions at load-time.

Fixed hotkey parser to treat x & ^y as an error instead of ignoring ^.

1.0.96.00 - March 21, 2011

New features:

ComObjQuery: Queries a COM object for an interface or service.

ComObjFlags: Retrieves or changes flags which control a COM wrapper object's behaviour.

ComObjCreate allows non-dispatch objects to be created if an interface identifier (IID) is given.

COM arrays support for-loops and the Clone() method.

ListVars shows the inner variant type and value of each COM wrapper object, in addition to the wrapper's address.

改变:

When a literal integer or variable containing both a numeric string and cached binary integer is assigned to a field of an object, an integer is stored instead of a string. This particularly benefits scripts calling COM methods which accept integers but not strings, or have different behaviour depending on the type of value.

NULL values are now allowed with ComObjParameter for the VT_UNKNOWN and VT_DISPATCH types.

Improved support for Common Language Runtime (.NET) objects via COM.

FileRecycle should now warn before deleting a file which is too large to recycle.

When a SafeArray created with ComObjArray is assigned to an element of another SafeArray, a separate copy is created. This prevents the script from crashing due to a second attempt at "destroying" the array. ComObjFlags allows this behaviour to be avoided.

Fixes:

Assigning to a COM array of VT_DISPATCH or VT_UNKNOWN crashed the script.

Break and Continue were tolerated outside of loops in some cases.

Standalone carriage-return (`r) was not correctly interpreted as end-of-line.

MouseMove miscalculated negative coordinates with the Input and Event send modes.

Selecting Edit This Script from the tray menu or using the Edit command crashed the script (broken by v1.0.95).

Error dialogs pointed at irrelevant lines of code in some cases.

1.0.95.00 - March 12, 2011

All file I/O has been heavily optimized.

Added #Warn to assist with debugging; initial design by ac.

By default, if name_var contains a function name, name_var.() calls the function. This can be overidden via the default base object, as before.

Run supports verbs with parameters, such as Run *RunAs %A_ScriptFullPath% /Param.

If an operator which can accept either one operand (&x) or two numeric operands (x & y) follows a quoted literal string, auto-concat occurs and the operator is applied only to the right-hand operand. This is because quoted literal strings are always considered non-numeric and are therefore not valid input for numeric operators. For example, expressions like "x" &y and "x" ++y now work.

Fixed:

  • Wildcard hotkeys were not respecting modifiers such as ^!+ in specific cases.
  • File.Pos returned garbage for non-seeking file types; now it returns -1.
  • File.AtEOF was incorrectly true in some cases.
  • COM wrapper objects left A_LastError unset in some cases.
  • Gui submenu icons did not work on Windows 2000/XP/Server 2003.
  • SplashImage clipped the image if height > width.
  • ComObjConnect did not alert when the first parameter is invalid.
  • SplashImage now uses GDI+ only when the other methods fail, for compatibility.
  • Tilde in ~x:: now affects x & y:: in the same way that ~x & z:: would, instead of having no effect.
  • A_PriorHotkey and A_TimeSincePriorHotkey now have the expected values when used with #If.
  • RegExReplace did not advance through the string correctly after a match failure if the string contained non-ASCII characters.

1.0.92.02 - January 19, 2011

Fixed a memory leak which occurred when the return value of an object invocation or built-in function was not used, such as file.ReadLine() or SubStr(x,y,z) alone on a line.

Replaced the fix from v1.0.92.01 with a better fix, which also fixes k::MsgBox(),x:=y and doesn't break if().

1.0.92.01 - January 18, 2011

Changed: FileCreateDir now sets A_LastError.

Fixed: GuiControl() or similar was sometimes misinterpreted as a command.

1.0.92.00 - January 13, 2011

Added support for compound assignments with objects, such as x.y += z.

Improved IniWrite in Unicode builds to prevent an empty line from appearing at the top of each new file.

Improved the parser to be more permissive about what can follow {/}/Else, especially when combined.

1.0.91.05 - January 1, 2011

Fixed: Cleanup code in COM method calls was freeing the wrong parameters.

Fixed (ANSI): DllCall set incorrect length for wstr parameters on output.

Fixed: Variadic function calls were unstable when param object was empty.

1.0.91.04 - December 29, 2010

Fixed (Unicode): RegExReplace omitted all text up to StartingPosition (broken by v1.0.90.00).

1.0.91.03 - December 27, 2010

Fixed: RegEx callout subpattern vars - broken by v1.0.90.00.

1.0.91.02 - December 26, 2010

COM: Added protection against NULL IDispatch/IUnknown pointers.

COM: Skip QueryInterface for IDispatch if VT_DISPATCH is passed explicitly.

Minor fix for maintainability: obj.field := var now correctly yields SYM_STRING, not SYM_OPERAND.

1.0.91.01 - December 24, 2010

Fixed: Unexpected results with File.Write(Str) after text-reading.

Fixed: UTF BOM check caused unexpected results in files without a BOM.

Fixed (ANSI): Parsing loops and File.ReadLine() treated Chr(255) as EOF.

Fixed (Unicode): RegExReplace errors where the UTF-8 and UTF-16 lengths differed.

Fixed: Disabling the last hook hotkey breaks Input.

Added: Simple optimization for RegExMatch/Replace.

1.0.91.00 - December 21, 2010

All changes in this release are COM-related.

Added: ComObjError now returns the previous setting.

Added: ComObjType(co) and ComObjValue(co).

Added: ComObjMissing().

Added: ComObjArray() and basic SAFEARRAY support.

Added: "Take ownership" parameter for ComObjParameter().

Changed: Values passed to COM functions via ComObjParameter are no longer freed in the process of calling the function.

Changed: ComObj.x() now falls back to PROPERTYGET if member 'x' is not found. This fixes for-loops for some objects.

Changed: Wrap unhandled variant types in an object rather than returning integer value.

Changed: Manage VT_UNKNOWN/VT_ARRAY lifetime automatically, by default.

1.0.90.00 - November 27, 2010

Fixed: UrlDownloadToFile in Unicode builds on Windows < 7.

Fixed: Upper-ANSI characters were sent as Alt+0 in ANSI build.

Fixed: File.Pos was incorrect after attempting to read past EOF.

Fixed: Escape sequences in #If expressions and static initializers.

Fixed: ClipboardAll sometimes crashed the script with certain formats.

Fixed: Transform HTML calculated length incorrectly for &#NNN; entities.

Fixed: VarSetCapacity now correctly ignores #MaxMem for ByRef variables.

Fixed: FileAppend,,file.txt set ErrorLevel=1 even on success.

Fixed: Match length was miscalculated for RegEx callouts with the P) option.

Integrated Sean's improvements to number handling in COM interop.

Optimized RegExReplace and RegExMatch in Unicode builds.

Revision 61 - October 3, 2010

Added: ObjClone(Object), forgotten when Object.Clone() was implemented.

Added: Support for RegEx Unicode properties in Unicode builds. Also upgraded PCRE to 8.10.

Added: Object.Remove(int, "") removes Object[int] without affecting other keys.

Changed: ComObj.xyz() is now always treated as a method-call.

Changed: Var := 123 is now left as an expression, for consistency. This makes Var := 123 and Var := (123) equivalent, whereas previously the former assigned only a string and the latter assigned both a string and a cached binary integer. In particular, this avoids some confusing type mismatch errors with COM objects.

Fixed: Dynamic variadic calls to functions with mandatory parameters.

Fixed: The final parameter of an assume-global variadic function had to be explicitly declared local.

Fixed: Static initializers interfering with setting of breakpoints.

Fixed: More pointer size-related errors with PCRE callouts on x64 builds.

Fixed: Input with 'M' option treated Ctrl-M (`r) as Ctrl-J (`n).

Fixed: Object.Remove(n) returned 0 (not "") if Object[n] didn't exist.

Revision 60 - September 24, 2010

Added: File.Encoding for changing or retrieving the codepage in use by a File object.

Added: Variadic functions and function-calls and indirect mode for callbacks.

Added: Object.Clone()

Changed: ByRef parameters no longer require the caller to supply a variable.

Changed: Obj.foo := "" now frees foo's contents as originally intended (but still doesn't remove the field).

Changed: OnMessage functions now tolerate optional and ByRef parameters.

Changed: RegisterCallback now enables execute access on callbacks in 32-bit builds (already did in 64-bit builds).

Changed: RegisterCallback now treats explicit ParamCount="" as omitted.

Fixed: For-loop was treating non-expression "0" as true for scripted enumerators.

Fixed: ComEvent (ComObjConnect) not working on the ANSI build.

Fixed: ComEvent (ComObjConnect) not correctly backing up/restoring local vars when calling a function which is already running.

Fixed: Buffer overflow in A_EndChar when there is no end char.

Fixed: Func->mNextFunc not inititialized to NULL (used only by LowLevel scripts).

Debugger: Added the capability to retrieve an object's contents (with a supported debugger client).

Debugger: Fixed a few bugs.

Revision 59 - September 12, 2010

Fixed: #If expression should now evaluate each expression at most once per keypress in all cases.

Changed: SplashImage uses common image-loading routines; now supports PNG and similar, but results may differ from before for icon files.

Added: For x,y in z.

Added: Loop .. Until expression, usable with any Loop or For-loop.

Added: Named loops; continue outer_loop, break 2, etc.

Debugger: Encode stdout and stderr packets as UTF-8.

Debugger: Allow user to Abort, Retry or Ignore when the initial connection fails.

Debugger: Allow attaching a debugger client by sending the script a registered window message.

Debugger: Allow detaching debugger client by sending the "detach" DBGp command.

Revision 58 - September 5, 2010

Added: static var := expression.

Revision 57 - September 4, 2010

Fixed Str*, WStr* and AStr* DllCall return types on x64.

Added functionality to InStr to bring it in line with StringGetPos:

  • If StartingPos is negative, the search is conducted right-to-left beginning at that offset from the end.
  • An additional parameter is available to specify which occurrence of the string to find.

Added #include <LibName> for explicitly including a script from a function library folder.

Added functionality to IniRead and IniWrite allowing an entire section to be read or written.

Added functionality to IniRead allowing a list of section names to be retrieved.

Added support for custom verbs to Run/RunWait: Run *verb file.

Made improvements to the way Run/RunWait extracts the action and its parameters from the Target parameter.

Changed NumGet/NumPut to allow Offset to be omitted entirely since Type is always non-numeric.

Removed the restriction that a label can't point to the end of a block.

Revision 56 - August 29, 2010

Added support for x64 compiled scripts. Requires Ahk2Exe_L and x64 AutoHotkeySC.bin.

Fixed: Deref operator (*addr) rejected addresses outside 32-bit range.

Fixed: #If expression memory allocation error on x64.

Fixed: Custom hotstring end chars with code points greater than U+00FF.

Fixed: Special characters being sent out of sequence by SendInput/Play.

Fixed: */ being discarded in continuation sections (see L54).

Revision 55 - August 19, 2010

Fixed: GroupActivate not setting ErrorLevel=1 if no Label was specified.

Fixed: Tab controls in x64 build.

Fixed: String-copy mode of StrPut when length is omitted; broken by L53.

Fixed: Data-alignment issues in x64 builds.

Changed: Set A_LastError for more File* commands to assist debugging.

Includes FileAppend, FileRead, FileReadLine, FileDelete, FileCopy, FileMove, FileGetAttrib/Time/Size/Version and FileSetAttrib/Time.

Excludes FileCopyDir, FileRecycle, FileMoveDir, FileRemoveDir, FileRecycleEmpty, FileCreateDir and FileInstall as the APIs used do not consistently set or return a Win32 error code.

Revision 54 - August 15, 2010

Fixed: RunAs in Unicode build. [jackieku]

Fixed: RegisterCallback in x64 build. [fincs]

Fixed: Executables failing to run on Win2k and WinXP prior to SP2. Win2k requires SP4 and updates (probably KB 816542). XP not tested.

Fixed: Dialogs such as MsgBox became unresponsive when interrupted by another script thread. Message filter/workaround added in L45 had to be removed. [Bug report]

Fixed: Multi-byte characters in default ANSI codepage; this was also causing a memory leak. [Bug report]

Fixed: ComObject now allows purely numeric property/method names. [Bug report]

Enhanced usability and capabilities of FileOpen/File object.

  • FileOpen's Flags parameter accepts a human-readable string of flags.
  • FileOpen's "update" mode has been renamed "read/write" and now creates the file if it didn't already exist.
  • FileOpen sets A_LastError as appropriate.
  • File := FileOpen(handle,"h") wraps an existing file handle in an object.
  • File.Seek(n) defaults to SEEK_END when n is negative.
  • File.Pos (or File.Position) can be used in place of Tell and Seek.
  • File.Pos, File.Length, File.AtEOF and File.__Handle can be used without empty parentheses().
  • File.Length can be set, as in File.Length:=n.
  • File.ReadNum() and File.WriteNum(n) read or write a number, where Num is a NumGet-compatible type name.
  • File.WriteLine(s) is equivalent to File.Write(s "`n"), for symmetry with File.ReadLine().
  • File.Read() reads and returns the remainder of the file when used without parameters.
  • File object now returns "" for unrecognized methods and invalid syntax rather than the numeric address of "".

Changed: GroupAdd's Label parameter now applies to the whole group. [Discussion]

Changed: GroupActivate sets ErrorLevel on success/failure. (Same thread as above.)

Changed: */ at the beginning of a line is ignored if there was no /*. [Discussion]

Removed ToCodePage and FromCodePage subcommands of Transform.

Revision 53 - August 8, 2010

Merged AutoHotkey64 - COM support and x64 compatibility.

x64 (changes since AutoHotkey64):

  • Fixed floating-point return values and exception handling for DllCall.
  • Fixed RegEx callouts.
  • Re-enabled GetProcAddress optimisation for DllCall.
  • NumPut and NumGet default to "Int64" in x64 builds.

COM (changes since AutoHotkey64):

  • Allow ComObjParameter to wrap 64-bit values in 32-bit builds.
  • Implemented more standard ref counting conventions in ComObjActive.
  • Prevent extraneous AddRef for new ComObjects in certain cases.
  • Don't treat pdispVal==NULL return value from Invoke as an error.
  • Fail more predictably when given wrong type of object.
  • Require explicit second param in ComObjType, don't assume "IID".
  • Free local vars after ComEvent calls a function.
  • Remove pVarResult param from ComEvent; use return value instead.
  • Pass the original wrapper ComObject in each ComEvent call.
  • Add context to ComError dialog; let the buttons make more sense.

Implemented common syntax validation code for enumerators. Enum[] and Enum.Next() are now supported with or without parameters. Enum[]:=val and similar obscure forms which worked in AutoHotkey_COM/AutoHotkey64 are not allowed.

"Ptr" type is still signed (unlike AutoHotkey64), for maximum flexibility and consistency.

Other changes:

Added: Object.HasKey(key).

Added: Object(obj) increments obj's reference count and returns its address.

Added: ObjAddRef() and ObjRelease().

Fixed: A_ThisHotkey now has the expected value when used with #If.

Fixed: RunAs in Unicode build (fixed by jackieku).

Changed: Default script codepage for ANSI builds is now CP0 (ANSI).

Changed: x.y[] is now equivalent to (x.y)[] rather than x["y"].

Changed: Built-in methods can now be called with or without the underscore prefix (e.g. obj.MaxIndex() or obj._MaxIndex()).

Revision 52 (again) - July 10, 2010

Added support for built-in and environment variables in double-derefs.

Improved support for multi-byte characters in certain codepages (previously only 932, 936, 949, 950 and 1361 were supported).

Fixed: StrPut failed for codepages which don't support WC_NO_BEST_FIT_CHARS, such as UTF-7.

Fixed: Double-deref as object - literal%var%.literal.

Fixed: StrPut("", Encoding) null-terminated an invalid address.

Revision 52 - June 12, 2010

Fixed: ObjRemove's Key parameter is now optional, as with Object._Remove.

Fixed: Files were improperly locked while reading, unlike in older versions.

Fixed: Uppercase Hex format caused negative integers to become unsigned.

Fixed: RegExMatch was corrupting output array items when specific conditions were met. See bug report.

Revision 51 - April 11, 2010

Changed: Use <EXENAME>.ahk instead of AutoHotkey.ini or AutoHotkey.ahk.

Changed: Default to UTF-8 for script files; override with /CPnnn.

Fixed: Unpause when the script exits so that object __Delete meta-functions can run.

Revision 50 - March 27, 2010

Improved flexibility of Object._Insert.

  • Object._Insert(x) - inserts x at _MaxIndex()="" ? 1 : _MaxIndex() + 1.
  • Object._Insert(i,x,y,z) - inserts x,y,z at i,i+1,i+2.

Improved flexibility of Object._Remove.

  • Object._Remove(k) - removes and returns the value associated with k.
  • Object._Remove() - removes and returns the value at _MaxIndex().

Added file share mode flags to FileOpen [by jackieku].

Fixed: 'P' option of RegExMatch incorrectly output 1 for subpatterns which did not match anything.

Fixed: Object._SetCapacity(key,n) was not null-terminating in some cases.

Fixed: StatusBarGetText returned only half of the text in Unicode builds.

Revision 49 - March 14, 2010

Added obj._NewEnum().

Added ObjMethod(obj) for each built-in obj._Method().

Changed: ObjSet/Get/Call can no longer be called/overridden by script.

Fixed: Potential crash caused by VK_PACKET check added in L48.

Fixed: Character codes in VK_PACKET events were potentially misinterpreted as scancodes.

Fixed: ExcludeText was ineffective after the first matching control.

Revision 48 - February 21, 2010

Fixed: Standalone obj.() was not recognized as a valid expression.

ControlSend now uses WM_CHAR to support characters which have no associated keycode. For instance, this applies to "…" (en-US), "∞" in a Unicode build and {U+221e} in either build.

KeyHistory now shows the full 16-bit character code for VK_PACKET (VK=E7) events. Send may indirectly cause these to be generated for Unicode characters.

Revision 47 - February 13, 2010

Fixed (Unicode): ControlGet,List with ListView controls.

Revision 46 - February 11, 2010

Added A_FileEncoding, which returns the current default file encoding.

Added StrPut and extended StrGet with additional features.

Revision 45 - February 8, 2010

Added _GetAddress; _SetCapacity/_GetCapacity may now operate on a given field. [more info]

Added workaround for WM_PAINT infinite loop often caused by subclassing.

Allow obj.() as a means to call the default method of an object; equivalent to obj[""]().

Dev: Added solution and project files for MSBuild 4.0 & VS2010. [more info]

Fixed (Unicode): 'Running' column in ListHotkeys.

Revision 44 - February 7, 2010

Fixed: Attempting to set "nothing" crashed the script. For instance, x[]:=z.

Fixed (Unicode): Unable to find default script (Documents\AutoHotkey.ahk).

Fixed (Unicode): A_Desktop, A_ProgramFiles and several other built-in variables which read their value from the registry caused strings to be incorrectly terminated.

Fixed (ANSI): Characters in the range 0x80-0xFF couldn't be found by InStr or StringReplace.

Changed (ANSI): Treat ToCodePage/FromCodePage like other unsupported/invalid subcommands.

Revision 43 - January 29, 2010

Fixed: obj.Func() resulting in a random integer when it should be an empty string.

Revision 42 - January 28, 2010

Merged with AutoHotkeyU.

Numerous bug-fixes and improvements, some relating to the merge.

Revision 41 - December 20, 2009

Fixed: Floating-point numbers were equivalent to an empty string when used as keys in objects. They are now converted to numeric strings in the current float format, as originally intended.

Revision 40 - December 13, 2009

Changed meta-functions and multi-param behaviour to improve flexibility. Meta-functions are now invoked *before* searching for an appropriate field in each base object; however, values in x.base will override meta-functions defined in x.base.base. Chaining meta-functions (inheritence) is now possible by avoiding "Return"

Improved Default Base functionality to be more consistent with real objects.

Changed (Debugger): While stepping through code, skip all braces except those which end a function.

Changed (Debugger): When stepping onto the hidden "Exit" at end of the script, consider it to be *below* the last physical line to avoid confusion.

Revision 39 - December 2, 2009

Fixed (Debugger): Error in Base64 decoding used by property_set.

Revision 38 - November 17, 2009

Added: #MenuMaskKey directive to change which key is used to mask Alt/Win keyup events. See this thread for background information.

Changed: If x[1,2]:=3 creates an object for x[1], it's base is no longer automatically set to x.base. See the documentation for a method of controlling this behaviour.

Revision 37 - November 7, 2009

Added: Support for obj[method_name](params) object-call syntax.

Revision 36 - November 4, 2009

Changed: If x.y or similar is immediately followed by an open-bracket ([), the right-most identifier preceding the bracket is treated as the first parameter of the operation. For instance, a.b.c[d] is equivalent to ObjGet(a.b,"c",d) and x.y[z]:=v is equivalent to ObjSet(x,"y",z,v). Previously each sub-expression preceding a bracket was evaluated separately.

Changed: If a method-call such as x.y() is followed immediately by an assignment, the parentheses are treated as brackets. For instance, x.y(z):=v is now equivalent to ObjSet(x,"y",z,v).

Fixed: If(expr) and While(expr) with no delimiting space or comma.

Revision 35 - October 25, 2009

Fixed: Standalone expressions beginning with two or more "dots", such as x.y.z(). (Broken by L34.) Note that '(' or '[' or ':=' is still required.

Revision 34 - October 24, 2009

Changed: Setting a value within an object to an empty string now stores the empty string rather than removing the key-value pair from the object. _Remove can still be used to completely remove key-value pairs.

Changed: Command names must be terminated with a space, tab or comma. The following characters no longer bypass this requirement: <>:+-*/!~&|^[]. For instance, syntax errors such as MsgBox< foo and If!foo are now caught at load-time.

Fixed: Return now properly handles expressions which result in a variable containing an object. For instance, Return x:=y, Return (x), Return x,... and similar should work now (Return x already worked).

Fixed: Multi-parameter get/set did not correctly support meta-functions for multiple objects (such as for x and x[y] in the expression x[y,z]).

Fixed: Cascading object-assignments such as the x[y]:=z in r:=x[y]:=z could not yield numbers or objects - broken by L33.

Fixed: x._Remove(y) crashed the script or removed the wrong item if x did not contain y.

Fixed: x.=y, if x.y=... and similar. May affect other expressions.

Fixed: Standalone ternary expressions no longer requires spaces. For instance, x? F(1) : F(2) is now allowed.

Debugger: On script exit, disconnect debugger *after* releasing objects to allow debugging of __Delete handlers.

Revision 33 - October 3, 2009

Fixed: Local variables were not automatically freed for functions which return objects or pure numbers.

Fixed: Two separate reference-counting errors related to ternary operator and Object().

Fixed: If a string returned by a scripted object function was assigned directly to a variable, the variable's length was set incorrectly.

Fixed: If the last operation in an expression retrieved a string from a temporary object, the object and string were freed prematurely.

Fixed: Numeric strings with special formatting were not preserved when returned from a function via a variable or passed to a recursive function.

Fixed: If the final result of an expression (other than for Return) is an object, correctly yield an empty string instead of silently aborting the thread.

Fixed: __Delete meta-functions sometimes overwrote temporary values in the deref buffer.

Added: An address retrieved via &object may be cast back into an object reference by using Object(address).

Revision 32 - September 26, 2009

Fixed: Send/PostMessage crash when less than three parameters were specified.

Revision 31 - September 26, 2009

Added: Object/array support and numerous minor changes to make this possible.

Added: Support for While(expression) with no delimiting space.

Added: Trim, LTrim, RTrim.

Added: A ~= B; equivalent to RegExMatch(A, B). May be removed in a future revision.

Fixed: An incompatibility with LowLevel.

Changed: Characters [, ] and ? are no longer valid in variable names. Consequently, ? (ternary) no longer requires a space on either side.

Changed: Optional parameters may now be omitted at any position in the parameter list of a non-dynamic function call. Since this works by automatically inserting the parameter's default value at load-time, it is not supported or allowed for dynamic function-calls.

Debugger: Various minor changes to make program flow easier to follow while stepping through code.

Optimization: If DllCall's first parameter is a literal string which identifies a function already present in memory, it is replaced with the actual address of the function.

Updated from v1.0.48.03 to v1.0.48.04.

Revision 30 - May 31, 2009

Updated from v1.0.48.02 to v1.0.48.03.

Revision 29 - May 2, 2009

All supported image formats may now be used as menu icons. 当前在 Windows Vista 和更高版本中如果需要被设置的图标保留透明度时, 则必须指定 "真实的大小". 例如：

Menu, Icon, MenuItemName, Filename.png,, 0

Revision 28 - May 2, 2009

Improved average-case performance of dynamic function calls by implementing binary search for function name look-ups. This change also applies to other areas, such as load-time resolution of function references in expressions and run-time resolution by OnMessage, RegisterCallback, etc.

Revision 27 - April 26, 2009

Updated from v1.0.48.00 to v1.0.48.02.

Revision 26 - April 11, 2009

Fixed: Menu icons were not drawn on items which have sub-menus if owner-drawing was in use.

Fixed: Menu icons were not freed if all menu items were deleted at once.

Changed (Source): Renamed AutoHotkey.sln to AutoHotkey_L.sln to allow VS window to be identified more easily.

Revision 25 - March 30, 2009

Fixed: Send {U+xxxx} correctly sets modifier key-state as with any normal key.

Fixed: Send {U+..xx} no longer triggers hotkey SCxx.

Revision 24 - March 30, 2009

Added: Support for Send {U+xxxx}. SendInput() is used where available for proper unicode support, otherwise falls back to Alt+Numpad.

Revision 23 - March 30, 2009

Fixed: GuiControl, Enable/Disable now only resets focus if the focused control was disabled.

Revision 22 - March 26, 2009

Optimized If var [not] in/contains MatchList, especially for long lists containing shorter fields.

Revision 21 - March 16, 2009

Minor optimizations to While. [thanks Chris]

Fixed (Debugger): Revisions 19 and 20 omitted timer threads from the call stack.

Fixed (Debugger): XML-reserved characters were not escaped in most situations.

Fixed (Debugger): Incorrect command and transaction_id were used in the final response before exiting the script.

Revision 20 - February 27, 2009

Changed: If an icon cannot be loaded with the new method, fall back to the old method.

Revision 19 - February 26, 2009

Added: Gui, Font, qN option to set font quality/control anti-aliasing, where N is between 0 and 5.

Fixed: IL_Add now loads icons at the most appropriate size when multiple sizes exist.

Merged with AutoHotkey v1.0.48, introducing bug fixes, optimizations and other changes by Chris. Some AutoHotkey_L features were integrated into the mainstream release; changes to these features since previous revisions are as follows:

  • Legacy behaviour is no longer applied to While - e.g. "While %x%" is correctly interpreted as a double-deref rather than as "While x".
  • One-True-Brace style is now supported for While.
  • Static vars may now be declared and initialized in assume-static functions.
  • Passing too few parameters in a dynamic function call is no longer allowed, as it allows the function's caller to second-guess the function's designer, reduces the ability to detect script bugs at runtime, and may cause the application to crash if calling a built-in function.

Revision 18 - February 21, 2009

Fixed: Incomplete bug-fix in previous revision causing concat followed by assignment to skip the rest of the expression in some cases.

Revision 17 - February 20, 2009

Added: Menu icons via Icon and NoIcon sub-commands of the Menu command.

Changed: Negative icon numbers can now be used to indicate a resource ID within an executable.

Changed: Set default style of menus to include MNS_CHECKORBMP.

Changed: Load both small and large versions of custom tray icons to allow the correct icons to be shown in the appropriate places.

Fixed: Loading of icons from executable files at sizes other than the system small/large.

Revision 16 - February 4, 2009

Fixed: Deleting a menu item partially deleted its associated sub-menu.

Revision 15 - February 1, 2009

Fixed: SetFormat's presence in a *compiled* script was not disabling binary number write-caching. SetFormat should now work correctly in compiled scripts.

Revision 14 - February 1, 2009

Numerous bug-fixes and optimizations by Chris (pre-v1.0.48 beta).

Added: Support for regex callouts and the auto-callout option 'C'.

Changed: A_AhkVersion now includes the revision number. For instance, this is 1.0.47.07.L14.

Fixed: HWND's/window ID's were sign-extended to 64-bit. For instance, 0xb482057e became 0xffffffffb482057e.

Revision 13 - November 29, 2008

Fixed: Invalid DllCall types were treated as INT in some build environments.

Added: Workaround for GuiEscape issue when disabling focused control.

Changed version info: InternalName, ProductName and FileDescription are now "AutoHotkey_L" instead of "AutoHotkey".

Revision 12 - September 6, 2008

Fixed: Potential access violation when using property_get on a built-in variable. -- DBGP

Revision 11 - September 5, 2008

Fixed: Remove checksum from AutoHotkeySC.bin via post-build script (AutoHotkey must be installed).

Added: .L suffix to A_AhkVersion.

Added: Preliminary support for DBGp (interactive debugging).

Revision 10 - August 2, 2008

Fixed: WheelLeft/WheelRight support, which was broken in revision 9.

Revision 9 - July 29, 2008

Fixed: Allow Break/Continue in While.

Fixed: TrayTip in non-English Windows and possibly other side-effects of using Vista headers.

Revision 8 - July 27, 2008

Added: #IfTimeout directive to set the timeout for evaluation of #If expressions, in milliseconds. Default is 1000.

Added: Assume-static mode for functions. "Static" must precede any local/global variable declarations.

Added: One-true-brace support for While.

Changed: While now sets A_Index to the iteration about to begin.

Revision 7 - July 26, 2008

Added: IsFunc(FuncName) - Returns a non-zero number if FuncName exists in the script or as a built-in function.

Revision 5 - July 19, 2008

Cleaned up obsolete references to test scripts.

Added basic default test script.

Revision 4 - July 18, 2008

Added: #if (expression) - Similar to #IfWinActive, but for arbitrary expressions.

Added: WheelLeft, WheelRight - Support for WM_MOUSEHWHEEL, which was introduced with Windows Vista. (Requires Vista.)

Added: While, expression - Loop while a condition is true.

Added: A_IsPaused - True if the underlying thread is paused.

Added: A_IsCritical - True if the current thread has been marked uninterruptible by the "Critical" command.

Changed: Allow any number of parameters to be passed in dynamic function calls.

Fixed: Access Violation caused by WinGetClass and subclassed windows.

Fixed: Access Violation caused by empty dynamic function references.


热键（鼠标、操纵杆和键盘快捷键）

目录

  • 入门和简单示例
  • 热键前缀符号表 (修饰符)
  • 上下文相关的热键
  • 自定义组合键及其他特性
  • 鼠标滚轮热键
  • 热键技巧和备注

入门和简单示例

热键有时也称为快捷键, 因为它们能简便地触发动作 (例如运行程序或 键盘宏). 在下面的例子中, Win+N 被设置为启动记事本. 磅的符号 [#] 表示 Windows 键, 它被称为 修饰符:

#n::
Run Notepad
return

在前面的最后一行中，return 用来结束此热键。不过, 如果热键只需要执行单行语句, 那么此行可以直接放在双冒号的右边. 换句话说，return 可以省略：

#n::Run Notepad

要在热键中使用多个修饰键, 那么需要把它们连续地列出来 (顺序无关紧要). 下面的例子中使用 ^!s 来表示 Control+Alt+S：

^!s::
Send Sincerely,{enter}John Smith  ; 此行发送键击到活动 (最前面的) 窗口.
return

在定义热键时您可以使用下列修饰符:

符号 说明
# Win (Windows 徽标键). 在 v1.0.48.01+, 对于 Windows Vista 及以上版本, 包含 Windows 键的热键 (例如 #a) 会等待 Windows 键被释放后才发送任何包含 "L" 键击的文本. 这样避免了这种热键中的 Send 锁定 PC。这种行为适用于除 SendPlay (这里不需要) 和 盲从模式 外的所有发送模式.
! Alt
^ 控件
+ Shift
& 和符号可以用来组合任意两个按键或鼠标按钮, 让它们成为自定义热键. 请参阅 后面 了解详情.
< 使用成对按键中左边的那个. 例如 <!a 相当于 !a, 只是使用左边的 Alt 键才可以触发.
> 使用成对按键中右边的那个.
<^>!

AltGr (alternate graving). 如果您键盘布局中含 AltGr 键而非右 Alt 键，那么这一系列符号一般可用于表示 AltGr。例如：

<^>!m::MsgBox You pressed AltGr+m.
<^<!m::MsgBox You pressed LeftControl+LeftAlt+m.

或者, 让 AltGr 自己成为热键, 请使用下面的热键 (不像上面出现的任何热键):

LControl & RAlt::MsgBox You pressed AltGr itself.
*

通配符: 即使附加的修饰键被按住也能激发热键. 这常与 重映射 按键或按钮组合使用. 例如：

*#c::Run Calc.exe  ; Win+C、Shift+Win+C、Ctrl+Win+C 等都会触发此热键。
*ScrollLock::Run Notepad  ; 即使在按住其他修饰键时按下 ScrollLock 也会触发此热键。
~

激发热键时，不会屏蔽（被操作系统隐藏）热键中按键原有的功能。在下面的两个例子中, 用户的鼠标按钮点击会被发送到活动窗口:

~RButton::MsgBox You clicked the right mouse button.
~RButton & C::MsgBox You pressed C while holding down the right mouse button.

注意：1) 与其他前缀符号不同，可以在某些热键的变体中使用颚化符前缀而其他的不使用；2) 代替 alt-tab 的特殊热键总是忽略颚化符前缀。

[v1.1.14+]：如果把颚化符前缀用在自定义修饰键中且此修饰键自身也作为热键，则在按下此修饰键时会触发热键而不会被延迟到按键释放的时候。例如，上文中~RButton热键在按下此按键时就会触发。对于v1.1.14之前的版本（或未使用颚化符前缀）， 则会在按键释放时触发其自身的热键，不过仅在未触发RButton & C组合键的时候。
$

通常只在脚本使用 Send 命令发送包含了热键自身的按键时才需要使用此符号, 此时可以避免触发它自己. $ 前缀强制使用 键盘钩子 来实现此热键, 作为一个副作用这样避免了 Send 命令触发它自己. $ 前缀相当于在此热键定义之前的某个位置指定了 #UseHook。

[v1.1.06+]: #InputLevel 和 SendLevel 对 Send 命令是否触发热键和热字串提供了额外的控制功能.
UP

单词 UP 可以跟在热键名后面使得在释放按键时触发热键, 而不是按下时. 下面的例子把 LWin 重映射 为 LControl:

*LWin::Send {LControl Down}
*LWin Up::Send {LControl Up}

“Up”也可以用于普通热键中，例如：^!r Up::MsgBox You pressed and released Ctrl+Alt+R。它还可以用在组合键（例如 F1 & e Up::）

限制：1) “Up”不能和游戏杆按钮一起使用；2) 在没有普通/按下热键副本的“Up”热键会完全接管那个按键以防被卡住。避免这种情况的一种方法是添加颚化符前缀（例如 ~LControl up::）

相关提示, 类似于上面的一种技术是让热键成为前缀键. 好处是尽管热键会在按键松开时激发, 但仅在您之前按住此前缀键时没有按其他任何键的情况下才会如此. 例如：

LControl & F1::return  ; 通过把左 control 键放在 "&" 前面至少一次来让它成为前缀键.
LControl::MsgBox You released LControl without having used it to modify any other key.

(请参阅 按键列表 来了解键盘按键和鼠标/操纵杆按钮的完整列表)

多个热键可以垂直地叠放来让它们执行相同的动作. 例如：

^Numpad0::
^Numpad1::
MsgBox Pressing either Control+Numpad0 or Control+Numpad1 will display this message.
return

通过不为按键或按键组合的热键指定任何操作可以在整个系统中完全禁用它们. 下面的例子中禁用了右 Windows 键:

RWin::return

上下文相关的热键

#IfWinActive/Exist 和 #If 指令可以用来让热键根据不同的条件执行不同的动作 (或什么都不做). 例如：

#IfWinActive, ahk_class Notepad
^a::MsgBox You pressed Ctrl-A while Notepad is active. Pressing Ctrl-A in any other window will pass the Ctrl-A keystroke to that window.
#c::MsgBox You pressed Win-C while Notepad is active.

#IfWinActive
#c::MsgBox You pressed Win-C while any window except Notepad is active.

#If MouseIsOver("ahk_class Shell_TrayWnd")
WheelUp::Send {Volume_Up}     ; 在任务栏上滚动滚轮：增加/减小音量。
WheelDown::Send {Volume_Down} ;

自定义组合键及其他特性

通过在两个按键 (不包括操纵杆按钮) 间使用 "&" 可以定义定制的组合键. 在下面的例子中, 您在按住 Numpad0 接着按下第二个按键时会触发此热键:

Numpad0 & Numpad1::MsgBox You pressed Numpad1 while holding down Numpad0.
Numpad0 & Numpad2::Run Notepad

在上面的例子中, Numpad0 成为 前缀键; 但是这也让 Numpad0 在被按下时失去了它原有的功能. 为了避免此问题, 脚本中可以配置 Numpad0 执行新的动作, 例如下列热键的其中一个:

Numpad0::WinMaximize A   ; 最大化活动/前端窗口.
Numpad0::Send {Numpad0}  ; 让 Numpad0 释放 时产生 Numpad0 键击. 请参阅下面的注释.

使用上面的其中一个自定义组合热键可以在释放Numpad0时执行指定的动作，但仅在您之前按住Numpad0时没有按其他任何按键的情况下。在v1.1.14+中，可以在其中某个热键使用颚化符前缀来避免这种行为。

Numlock, Capslock 和 Scrolllock: 这些键可以被强制设置为 "AlwaysOn" 或 "AlwaysOff". 例如：SetNumlockState AlwaysOn。

覆盖资源管理器热键: 在脚本中可以为 Windows 内置的热键例如 Win-E (#e) 和 Win-R (#r) 指定一个动作来个别的替换. 请参阅 覆盖页面 了解详情.

替换 Alt-Tab: 热键可以提供 Alt-Tab 切换窗口的可选方法. 例如, 下面的两个热键可以让您用右手进行 alt-tab:

RControl & RShift::AltTab  ; 按住右 control 后接着反复下右 shift 来向前移动.
RControl & Enter::ShiftAltTab  ; 甚至不需要释放右 control, 直接按 Enter 来反向移动.

想了解更多细节, 请参阅 Alt-Tab.

鼠标滚轮热键

通过键名 WheelDown 和 WheelUp 可以支持转动滚轮来激发热键. 在 v1.0.48+ 中还支持 WheelLeft 和 WheelRight，但在早于 Windows Vista 的操作系统上没有效果。这里是一些鼠标滚轮热键的例子:

MButton & WheelDown::MsgBox You turned the mouse wheel down while holding down the middle button.
^!WheelUp::MsgBox You rotated the wheel up while holding down Control+Alt.

在 v1.0.43.03+, 内置变量 A_EventInfo 包含了滚轮转动的格数, 通常为 1. 然而在后面的情况中, A_EventInfo 可能大于或小于 1:

  • 如果鼠标硬件报告小于一格的距离, 那么 A_EventInfo 可能为 0;
  • 如果快速滚动滚轮 (取决于鼠标类型), 那么 A_EventInfo 可能大于 1. 像后面这样的热键可以帮助您分析鼠标：~WheelDown::ToolTip %A_EventInfo%。

鼠标滚轮最有用的一些热键包括滚动窗口文本的可选方法. 例如, 使用下面的一对热键可以在您按住左 Control 键并转动滚轮时进行水平滚动而不是垂直滚动:

~LControl & WheelUp::  ; 向左滚动.
ControlGetFocus, fcontrol, A
Loop 2  ; <-- 增加这个值来加快滚动速度.
    SendMessage, 0x114, 0, 0, %fcontrol%, A  ; 0x114 是 WM_HSCROLL, 它后面的 0 是 SB_LINELEFT.
return

~LControl & WheelDown::  ; 向右滚动.
ControlGetFocus, fcontrol, A
Loop 2  ; <-- 增加这个值来加快滚动速度.
    SendMessage, 0x114, 1, 0, %fcontrol%, A  ; 0x114 是 WM_HSCROLL, 它后面的 1 是 SB_LINERIGHT.
return

最后, 由于鼠标滚轮热键只产生按下事件 (从没有弹起事件), 所以它们无法用作 弹起的按键热键.

热键技巧和备注

根据 Numlock的状态, 每个小键盘上的按键可以运行两个不同的热键子程序. 可选的, 可以让小键盘上的按键不论 Numlock 的状态如何都运行相同的子程序. 例如：

NumpadEnd::
Numpad1::
MsgBox, This hotkey is launched regardless of whether Numlock is on.
return

如果颚化符 (~) 和 前缀键 一起使用, 即使只是一次, 那么其中的前缀键总是会被发送到活动窗口. 例如, 在下面的两个热键中, 活动窗口都会接收到右键点击, 尽管只是其中一个热键使用了颚化符:

~RButton & LButton::MsgBox You pressed the left mouse button while holding down the right.
RButton & WheelUp::MsgBox You turned the mouse wheel up while holding down the right button.

Suspend 命令可以临时禁用所有的热键, 但不包括您要排除的那些. 要得到更大的选择性, 请使用 #IfWinActive/Exist.

通过使用 Hotkey 命令, 可以在脚本运行时动态创建热键. Hotkey 命令还能单独地修改, 禁用或启用脚本现有的热键.

操纵杆热键当前不支持修饰符前缀, 例如 ^ (Control) 和 # (Win). 不过, 您可以使用 GetKeyState 来模仿这种效果, 如下所示:

Joy2::
if not GetKeyState("Control")  ; 左边和右边的 Control 键都没有按下.
    return  ; 即什么都不做.
MsgBox You pressed the first joystick's second button while holding down the Control key.
return

如果热键应该在继续执行前等待其修饰键被释放, 这可能需要一些时间. 请参考下面的例子:

^!s::Send {Delete}

按下 Control-Alt-S 会让系统以为您按下了 Control-Alt-Delete (由于系统对 Ctrl-Alt-Delete 的侵略性检测). 要变通解决此问题, 请使用 KeyWait 来等待按键释放; 例如:

^!s::
KeyWait Control
KeyWait Alt
Send {Delete}
return

如果像 #z:: 这样的热键标签产生了类似“无效热键”的错误，那么您的系统键盘布局/语言可能不包含特殊字符（此时为“Z”）。尝试使用您键盘布局中您知道的其他字符.

热键标签可以作为 Gosub 或 Goto 的目标. 例如：Gosub ^!s。

热键的一个常见用途是启动和停止重复的动作, 例如一系列的键击或鼠标点击. 关于这方面的例子, 请参阅 这个 FAQ 主题.

最后, 每个脚本都是 准多线程的, 这样可以在之前的热键子程序还在运行时启动新的热键. 例如, 即使在当前热键显示 MsgBox 时也能启动新热键.

Alt-Tab 热键

每个 Alt-Tab 热键必须是两个键的组合, 通常通过和符号 (&) 实现. 在下面的例子中, 按住右 Alt 键并按下 J 或 K 可以导航 alt-tab 菜单:

RAlt & j::AltTab
RAlt & k::ShiftAltTab

AltTab 和 ShiftAltTab 是两个特殊的命令, 它们仅在与热键在同一行时才能被识别. 这里是完整的列表:

AltTab: 如果 alt-tab 菜单可见, 那么在菜单中前移. 否则, 显示菜单 (仅当热键为由 "&" 连接的两个按键时; 否则, 它什么都不做).

ShiftAltTab: 与上面相同, 不过这里在菜单中后移.

AltTabAndMenu：如果 alt-tab 菜单可见，那么在菜单中前移。否则, 显示菜单.

AltTabMenuDismiss: 关闭 Alt-tab 菜单.

为了举例说明上述命令, 可以用鼠标滚轮完全代替 Alt-tab. 当下面的热键生效时, 点击鼠标中键显示菜单, 转动滚轮在菜单中导航:

MButton::AltTabMenu
WheelDown::AltTab
WheelUp::ShiftAltTab

要取消热键调用的 Alt-tab 菜单而不激活选择的窗口, 请使用类似下面这样的热键:它可能需要根据后面的这些进行调整: 1) 最初显示 alt-tab 菜单的方法; 和 2) 脚本是否安装了 键盘钩子.

LCtrl & CapsLock::AltTab
!MButton::  ; 鼠标中键. ! 前缀让它在按住 Alt 键时激发 (当 alt-tab 菜单可见时, alt 键是按住的).
IfWinExist ahk_class #32771  ; 表示 alt-tab 菜单出现在屏幕上.
    Send !{Escape}{Alt up}
return

当前, 所有特殊的 Alt-tab 动作必须像上面的例子那样直接指定到热键上 (即它们无法像命令那样使用). 它们 不受 #IfWin 或 #If 的影响.

自定义的 alt-tab 动作还可以通过热键创建. 在下面的例子中, 按下 F1 来显示菜单并预先向前移动. 然后可以按下 F2 来激活选择的窗口 (或按下 Escape 取消):

*F1::Send {Alt down}{tab} ; 这里需要星号.
!F2::Send {Alt up}  ; 释放 Alt 键激活选择的窗口.
~*Escape::
IfWinExist ahk_class #32771
    Send {Escape}{Alt up}  ; 取消菜单而不激活选择的窗口.
return


热字串和自动替换（类似于自动图文集和自动更正）

热字串和自动替换

入门和简单示例

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

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

::btw::by the way

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

上面的 "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 是回车，`t 是 Tab，且在它们之间还有一个原义的空格）。通过编辑下列示例可以改变这个字符集合，这个例子中为 所有的 热字串设置新的终止符，而不仅是在它下面的那些。

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

选项

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

  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 次退格. 同样地, 可以通过 {left 5} 发送左方向键的键击. 例如，下面的热字串产生“<em></em>”并把光标向左移动 5 个位置（这样它就在标签之间了）：

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

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

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

Kn: 按键延迟: 这个非常少用的选项设置在自动退格或 自动替换 产生的键击之间的延迟. 给 n 指定新的延迟; 例如, 指定 k10 来设置 10ms 的延迟而 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”，这样可以让您在不需要退格的情况下补上单词的复数或所有格形式。使用 O0 (字母 O 后跟着零) 来关闭此选项.

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

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

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.

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

:b0*?:11::
SendInput xx
return

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

超长替换

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

::text1::
(
Any text between the top and bottom parentheses is treated literally, including commas and percent signs.
By default, the hard carriage return (Enter) between the previous line and this one is also preserved.
    By default, the indentation (tab) to the left of this line is preserved.

See continuation section for how to change these default behaviors.
)

使用延续片段后也会使热字串默认为 原始模式. 覆盖此特性的唯一方法是在每个含延续片段的热字串中指定 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) 防止您在点击鼠标后输入的一些内容与之前输入的内容意外形成有效的缩写从而触发热字串.

内置变量 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% 可以发送不限数量的文本。

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

为了识别热字串, 您输入的所有退格都会被计算进来. 然而, 使用方向键, PageUp, PageDown, Home 以及 End 在编辑器中导航会重置热字串识别过程. 换句话说, 它会开始等待全新的热字串.

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

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

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

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

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

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

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

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

已知限制: 在 Java 应用程序的某些系统中, 热字串可能会干扰用户输入 diacritical 字母 (通过 dead 键). 为了解决此问题, 可以临时打开 Suspend (这样禁用了所有热字串).

热字串助手

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

#h::  ; Win+H hotkey
; 获取当前选择的文本. 使用剪贴板代替
; "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%  ; 恢复剪贴板之前的内容.
; 这里会移动 InputBox 的光标到更人性化的位置:
SetTimer, MoveCaret, 10
; 显示 InputBox, 提供默认的热字串:
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
IfInString, 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:
IfWinNotActive, New Hotstring
    return
; 否则移动 InputBox 中的光标到用户输入缩写的位置.
Send {Home}{Right 3}
SetTimer, MoveCaret, Off
return


重映射按键和鼠标按钮

简介

限制: 下面描述的 AutoHotkey 重映射功能通常不如直接通过 Windows 注册表进行映射那么直接有效. 对于每种方法的优点和缺点, 请参阅 注册表重映射.

重映射键盘和鼠标

内置重映射功能的语法为 OriginKey::DestinationKey。例如, 只包含下面这行内容的 脚本 会将 "a" 键重映射成 "b" 键:

a::b

上面的例子没有改变 "b" 键自身的功能. "b" 键会继续发送 "b" 的键击, 除非把它重映射成其他功能, 就像下面例子中演示的那样:

a::b
b::a

上述例子中使用小写字母, 在大多数情况下建议这么做, 因为它也会映射相应的大写字母 (即在 Capslock 打开或 Shift 键被按住时会发送大写形式). 与之相比, 在右边使用大写字母会强制发送大写形式. 例如, 下面的代码行在您输入 "a" 或 "A" 时都会产生大写字母 B (只要 Capslock 是关闭的):

a::B

鼠标重映射: 要映射鼠标, 请使用和映射键盘相同的方法. 例如：

MButton::Shift | 把鼠标中键映射成 Shift 键.
XButton1::LButton | 把第四个鼠标按钮映射成鼠标左键.
RAlt::RButton | 把右 Alt 映射成鼠标右键.

其他有用的映射:

Capslock::Ctrl | 把 Capslock 映射成 Control 键. 要保留打开和关闭 Capslock 的功能，还需添加重映射 +Capslock::Capslock（这样，当您按住 shift 键并按下 Capslock 后就可以切换 Capslock 的状态了）。
XButton2::^LButton | 把第五个鼠标按钮 (XButton2) 映射成 Control-LeftClick.
RAlt::AppsKey | 把右 Alt 键映射成 Apps 键 (这是打开上下文菜单的按键).
RCtrl::RWin | 把右 Control 键映射成右 Windows 键.
Ctrl::Alt | 把左右 Control 键映射成 Alt 键. 但是, 请参阅 alt-tab 的问题.
^x::^c | 把 Control-X 映射成 Control-C. 它也会让 Control-Alt-X 产生 Control-Alt-C, 等等.
RWin::Return | 让右 Windows 键简单地执行 return 来禁用它.

您可以尝试执行这里的每个例子: 把它们复制到新文本文件 (例如 "Remap.ahk"), 然后运行这个文件.

请参阅 按键列表 来了解按键和鼠标按钮名称的完整列表.

备注

使用 #IfWinActive/Exist 指令可以让重映射仅在指定的窗口中有效. 例如：

#IfWinActive ahk_class Notepad
a::b  ; 让 'a' 键到 'b' 键的映射仅在记事本中有效.
#IfWinActive  ; 这里让后续的重映射和热键对所有窗口生效.

重映射按键和鼠标按钮在下面的关系中是 "完整的":

  • 按住修饰符 (例如 Control 或 Shift) 后按下原始键, 会让那个修饰符对目标键生效. 例如，b::a 会在您按下 Control-B 时产生 Control-A 的效果。
  • Capslock 通常会像普通键那样影响重映射的按键.
  • 按住目标键或按钮的时间和您持续按住原始键的时间一样长. 但是, 一些游戏不支持重映射; 此时, 键盘和鼠标的重映射没有效果.
  • 按住被重映射的按键时, 它们的目标键会自动重复 (除非是把按键重映射为鼠标按钮).

尽管被重映射的按键可以触发普通热键, 但默认情况下它不能触发鼠标热键或 钩子热键 (请使用 ListHotkeys 来找出哪些热键使用了钩子). 例如，如果重映射 a::b 有效，那么按下 Ctrl-Alt-A 会触发 ^!b 热键，但仅在 ^!b 不是钩子热键的时候。如果 ^!b 是钩子热键，而且您希望使用 Ctrl-Alt-A 来执行和 Ctrl-Alt-B 相同的动作，那么您可以把 ^!a 定义为热键。例如：

a::b
^!a::
^!b::
ToolTip You pressed %A_ThisHotkey%.
return

在 v1.1.06 及更高版本中, 还可使用 #InputLevel 来覆盖此默认行为. 例如：

#InputLevel 1
a::b

#InputLevel 0
^!b::
ToolTip You pressed %A_ThisHotkey%.
return

如果在自动运行段 (脚本的顶部) 使用了 SendMode, 那么它会影响所有的重映射. 但是, 由于重映射使用 Send {Blind} 而 SendPlay 模式 不完全支持 {Blind}, 所以一些映射在 SendPlay 模式中可能无法正常运行 (尤其是 Control, Shift, Alt 和 Win). 要变通解决此问题, 当您脚本中含有重映射时请避免在自动执行段中使用 SendPlay; 而仅在整个脚本的一些需要的地方使用 SendPlay 命令而不是 Send. 或者, 您可以把您的重映射转换为热键 (如下所述), 这样就明确调用 SendEvent 而不是 Send.

加载脚本时, 每个重映射会被转换为一对 热键. 例如，包含重映射 a::b 的脚本实际包含下面的两个热键：

*a::
SetKeyDelay -1   ; 如果目标键是鼠标按钮, 则使用 SetMouseDelay 代替.
Send {Blind}{b DownTemp}  ; DownTemp 和 Down 相似, 不过使用 DownTemp 时脚本中后面的其他 Send 命令则不会假定 "b" 仍然处于按下的状态.
return

*a up::
SetKeyDelay -1  ; 请参阅下面的注意事项来了解在这段代码中两处 SetKeyDelay 都没有指定按键时长的原因.
Send {Blind}{b Up}
return

但是, 上面的两个热键在下列环境中会发生变化:

  1. 当原始键为 LCtrl 而目标键为 Alt 键时，会把 Send {Blind}{LAlt DownTemp} 这行语句替换为 Send {Blind}{LCtrl Up}{LAlt DownTemp}。如果原始键为 RCtrl 也会如此，除非使用了 {RCtrl up}。
  2. 当键盘按键被重映射为鼠标按钮时（例如 RCtrl::RButton），在上面的热键中会使用 SetMouseDelay 代替 SetKeyDelay。而且, 上面的首个热键会被替换为下面的热键, 这样避免了由于键盘的自动重复功能生成的重复的鼠标点击:
    *RCtrl::
SetMouseDelay -1
if not GetKeyState("RButton")  ; 即鼠标右键还没有按下.
    Send {Blind}{RButton DownTemp}
return

请注意在上面的热键中省略了 SetKeyDelay 的第二个参数 (按键时长). 这是因为按键时长不适用于独立的按键按下或按键弹起事件，例如 {b down} 和 {b up}。但是，它适用于 Shift/Ctrl/Alt/Win 按键状态的改变，这会影响像 a::B 或 a::^b 的重映射。因此，脚本中任何在自动执行段生效的按键时长会应用于所有这类重映射。

尽管一对按键不能直接重映射为单个按键（例如 a & c::b 是无效的），不过只需要在前面的示例中添加明确的弹起和按下热键即可实现这种行为：简单地把 *a:: 替换为 a & c::，且把 *a up:: 替换为 a & c up::。

由于重映射会被简单翻译为上面描述的热键, 所以 Suspend 也会影响它们. 同样地, Hotkey 命令可以禁用或修改重映射. 例如，下面的两个命令会禁用重映射 a::b。

Hotkey, *a, off
Hotkey, *a up, off

Alt-tab 的问题: 如果您把一个按键或鼠标按钮映射为 Alt 键, 那么这个键很可能无法正确实现 alt-tab 的功能. 一个可能的变通解决方法是添加热键 *Tab::Send {Blind}{Tab}，但是需要注意这样很可能妨碍使用真正的 Alt 实现 alt-tab 的功能。因此, 这种方法只应当用于在您希望单独使用重映射的按键和/或 alt-tab 热键 实现 alt-tab 功能的时候.

除了 按键列表 页面中的按键和鼠标按钮, 原始键还可以是在 特殊按键 页面描述的虚拟键 (VKnn) 或扫描码 (SCnnn). 对于目标键同样如此, 不过它还可以在虚拟键后指定扫描码. 例如，在大多数键盘布局中 sc01e::vk42sc030 相当于 a::b。

要禁用按键而不进行重映射, 请把它设置为只含有 return 的热键. 例如，F1::return 会禁用 F1 键。

内置的重映射功能不支持下列键:

  • 鼠标滚轮 (WheelUp/Down/Left/Right).
  • Pause 和 Break 不能作为目标键 (因为它们会被作为命令执行).
  • 大括号 {} 不能作为目标键. 作为替代请使用 VK/SC 方法；例如 x::+sc01A 和 y::+sc01B。
  • 百分号 (%) 不能作为目标键. 作为替代请使用 VK/SC 方法.
  • "Return" 不能作为目标键. 作为替代请使用 "Enter".

通过键盘移动鼠标光标

如同在全功能 键盘到鼠标的映射脚本 中演示的那样, 可以使用键盘来移动鼠标光标. 由于这个脚本提供了鼠标平滑移动, 加速和其他功能, 所以如果您想使用键盘实现许多的鼠标操作, 推荐您使用这个脚本. 与之相比, 下面的例子只是简化的演示:

*#up::MouseMove, 0, -10, 0, R  ; Win+UpArrow 热键 => 上移光标
*#Down::MouseMove, 0, 10, 0, R  ; Win+DownArrow => 下移光标
*#Left::MouseMove, -10, 0, 0, R  ; Win+LeftArrow => 左移光标
*#Right::MouseMove, 10, 0, 0, R  ; Win+RightArrow => 右移光标

*<#RCtrl::  ; LeftWin + RightControl => Left-click (按住 Control/Shift 来进行 Control-Click 或 Shift-Click).
SendEvent {Blind}{LButton down}
KeyWait RCtrl  ; 防止键盘自动重复导致的重复鼠标点击.
SendEvent {Blind}{LButton up}
return

*<#AppsKey::  ; LeftWin + AppsKey => Right-click
SendEvent {Blind}{RButton down}
KeyWait AppsKey  ; 防止键盘自动重复导致重复的鼠标点击.
SendEvent {Blind}{RButton up}
return

使用注册表的 "扫描码映射" 功能进行重映射

优点:

  • 注册表的重映射功能通常比 AutoHotkey 的重映射 更加直接有效. 例如, 它能适应于更大范围的游戏, 它不存在 alt-tab 问题, 并且它能触发 AutoHotkey 的钩子热键 (然而 AutoHotkey 的重映射需要 间接的方法 才行).
  • 如果您会手动修改注册表条目 (下面进行阐述), 那么不需要任何外部软件就可以重映射您的键盘. 即使您使用 KeyTweak 来修改注册表条目, 那么完成后 KeyTweak 不需要一直保持运行 (而 AutoHotkey 需要一直运行, 重映射才会生效).

缺点:

  • 注册表重映射比较不灵活: 每次修改映射都必须重启后才会生效.
  • 效果是全局的: 它不能创建针对特定用户, 应用程序或环境的重映射.
  • 它无法发送含修饰键 Shift, Control, Alt 或 AltGr 的组合键. 例如，它不能把小写字符映射为大写字符。
  • 它只支持键盘 (AutoHotkey 还支持 鼠标重映射 和一些 受限的操纵杆重映射).

如何修改注册表: 使用注册表重映射按键至少有两种方法:

  1. 使用像 KeyTweak (免费软件) 这样的程序在可视界面中重映射按键. 它会自动修改注册表.
  2. 手动创建重映射按键的 .reg 文件 (纯文本) 并把它载入注册表. 演示的例子请参阅 www.autohotkey.com/forum/post-56216.html#56216

相关主题

按键和鼠标按钮列表
GetKeyState
重映射操纵杆


用于热键和宏的按键和鼠标/操纵杆按钮的列表

按键, 鼠标按钮和操纵杆控制器的列表

鼠标

概述 |
LButton | 鼠标左键
RButton | 鼠标右键
MButton | 鼠标中键或滚轮
高级 |
XButton1 | 鼠标的第四个按钮。一般和 Browser_Back 执行相同功能。
XButton2 | 鼠标的第五个按钮。一般和 Browser_Forward 执行相同功能。
Wheel |
WheelDown | 向下转动鼠标滚轮（向您的方向）。
WheelUp | 向上转动鼠标滚轮（远离您的方向）。
WheelLeft WheelRight | [v1.0.48+]：向左或向右滚动。 需要 Windows Vista 或更高版本。这可以用在某些（但并非所有）带第二个滚轮或支持左右滚动的鼠标热键。在某些情况下，必须通过鼠标的自带软件包控制这个功能。不论鼠标如何特殊，Send 和 Click 都能在支持它们的程序里水平滚动。

键盘

注意: 字母和数字按键的名称和单个字母或数字相同. 例如: b 表示 "b" 键而 5 表示 "5" 键.

概述
CapsLock | 大小写锁定键
Space | 空格键
Tab | Tab 键
Enter (或 Return) | 回车键
Escape (或 Esc) | 退出键
Backspace (或 BS) | 退格键
光标控制
ScrollLock | 滚动锁定键
Delete (或 Del) | 删除键
Insert (或 Ins) | 插入改写切换键
Home | Home 键
End | End 键
PgUp | 向上翻页键
PgDn | 向下翻页键
Up | 向上方向键
Down | 向下方向键
Left | 向左方向键
Right | 向右方向键
Numpad
NumLock 开启
NumLock 关闭
Numpad0
NumpadIns 0 / 插入改写切换键
Numpad1
NumpadEnd 1 / End 键
Numpad2
NumpadDown 2 / 向下方向键
Numpad3
NumpadPgDn 3 / 向下翻页键
Numpad4
NumpadLeft 4 / 向左方向键
Numpad5
NumpadClear 5 / 通常什么都不做
Numpad6
NumpadRight 6 / 向右方向键
Numpad7
NumpadHome 7 / Home 键
Numpad8
NumpadUp 8 / 向上方向键
Numpad9
NumpadPgUp 9 / 向上翻页键
NumpadDot
NumpadDel 十进制分隔符 / 删除键
NumpadDiv
NumpadDiv 除
NumpadMult
NumpadMult 乘
NumpadAdd
NumpadAdd 加
NumpadSub
NumpadSub 减
NumpadEnter
NumpadEnter 回车键
功能
F1 - F24 | 在大多数键盘顶部的 12 个或更多的功能键。
按键修饰符
LWin | 左边的 Windows 徽标键。对应的热键前缀为 <#。
RWin 右边的 Windows 徽标键。对应的热键前缀为 >#。
注意：与 Control/Alt/Shift 不同，没有一般的/中性的“Win”键，因为操作系统不支持。不过含 # 修饰符的热键可以被任何一个 Win 键触发。
Control (或 Ctrl) | Control 键。单独作为热键（Control::）时它在弹起时触发，不过如果加上颚化符前缀可以改变这种情况。对应的热键前缀为 ^。
Alt | Alt 键。单独作为热键（Alt::）时它在弹起时触发，不过如果加上颚化符前缀可以改变这种情况。对应的热键前缀为 !。
Shift | Shift 键。单独作为热键（Shift::）时它在弹起时触发，不过如果加上颚化符前缀可以改变这种情况。对应的热键前缀为 +。
LControl（或 LCtrl） | 左 Control 键。对应的热键前缀为 <^。
RControl（或 RCtrl） | 右 Control 键。对应的热键前缀为 >^。
LShift | 左 Shift 键。对应的热键前缀为 <+。
RShift | 右 Shift 键。对应的热键前缀为 >+。
LAlt | 左 Alt 键。对应的热键前缀为 <!。
RAlt 右 Alt 键。对应的热键前缀为 >!。
注意：如果您的键盘布局存在 AltGr 而不是 RAlt，那么您完全可以根据这里描述的那样通过 <^>! 把它作为热键前缀使用。此外，LControl & RAlt:: 可以把 AltGr 自身设置成热键。
多媒体
Browser_Back | 后退
Browser_Forward | 前进
Browser_Refresh | 刷新
Browser_Stop | 停止
Browser_Search | 搜索
Browser_Favorites | 收藏夹
Browser_Home | 主页
Volume_Mute | 静音
Volume_Down | 调低音量
Volume_Up | 增加音量
Media_Next | 下一首
Media_Prev | 上一首
Media_Stop | 停止
Media_Play_Pause | Play/Pause
Launch_Mail | 打开默认的电子邮件程序
Launch_Media | 打开默认的媒体播放器
Launch_App1 | 打开我的电脑
Launch_App2 | 打开计算器
注：上面列出的每个按键的功能可以通过修改 Windows 注册表进行替换。这个表格中显示的是在 Windows 系统的大多数版本中每个按键的默认功能。
特别
AppsKey | 菜单键。这是调用右键上下文菜单的按键。
PrintScreen | 捕获屏幕
CtrlBreak
暂停 | 暂停键
中断 | 中断键。由于此键和 Pause 含义相同，所以在热键中请使用 ^CtrlBreak 代替 ^Pause 或 ^Break。
帮助 | 帮助键。此键可能在大多数键盘上不存在。它通常和 F1 不同.
Sleep | 休眠键。注意在一些键盘上的 sleep 键可能不是休眠功能。
SCnnn | 请在 nnn 中指定按键的扫描码。识别上面没有提到的罕见的按键。请参阅特殊按键了解详情。
VKnn 请在 nn 中指定十六进制的虚拟按键码。这种极少用的方法还可以避免某些类型的热键需要安装键盘钩子。例如，后面的热键不使用键盘钩子，但副作用是它会在按下 Home 或 NumpadHome 的其中一个时触发：
^VK24::MsgBox You pressed Home or NumpadHome while holding down Control.
已知限制：强制使用键盘钩子的 VK 热键，例如 *VK24 或 ~VK24，只会触发其中一个热键，而不会触发两者（例如触发 NumpadHome 但不触发 Home）。关于 VKnn 方法的更多细节，请参阅特殊按键。

操纵杆

Joy1 到 Joy32: 操纵杆的按钮. 要辅助判断您操纵杆的按钮编号, 请使用此 测试脚本. 请注意这里不支持 热键前缀符, 例如 ^ (control) 和 + (shift) (尽管可以使用 GetKeyState 作为替代方法). 还必须注意, 如果活动窗口设计对操纵杆按钮进行检测, 那么操纵杆按钮按下时总是会 "传递" 给它.

尽管下列操纵杆控制器的名称不能设为热键, 但它们可以用于 GetKeyState:
JoyX, JoyY 和 JoyZ: 操纵杆的 X (水平), Y (垂直) 和 Z (高度/深度) 轴.
JoyR: 操纵杆的方向舵或第 4 轴.
JoyU 和 JoyV: 操纵杆的第 5 和第 6 轴.
JoyPOV: 视点 (帽) 控制器.
JoyName: 操纵杆或其驱动的名称.
JoyButtons: 操纵杆支持的按钮数 (不总是准确的).
JoyAxes: 操纵杆支持的轴数.
JoyInfo: 提供由零个或多个后面的字母组成的字符串, 这些字母表示操纵杆的功能: Z (有 Z 轴), R (有 R 轴), U (有 U 轴), V (有 V 轴), P (有 POV 控制器), D (POV 控制器有少数离散的/不同的设置), C (POV 控制器是连续的/良好的). 示例字符串: ZRUVPD

多个操纵杆: 如果计算机上有多个操纵杆并且您想使用第一个外的其他操纵杆, 那么请在控制器名称的前面加上操纵杆的编号 (最大为 16). 例如, 2joy1 表示第二个操纵杆的首个按钮.

注意: 如果您在使用脚本识别您的操纵杆时遇到问题, 曾有人报告说尽管只有一个操纵杆却需要指定大于 1 的操纵杆编号. 不清楚这种方法是如何得到的或是否正常, 不过请尝试在 操纵杆测试脚本 中使用操纵杆编号也许可以帮助确定这种方法是否适合您的系统.

另请参阅:
操纵杆重映射: 使用操纵杆发送键击和鼠标点击的方法.
操纵杆到鼠标的映射脚本: 把操纵杆作为鼠标使用.

手持遥控

通过 WinLIRC 客户端脚本 响应手持遥控器的信号.

特殊按键

如果您的键盘或鼠标含有前面没有列出的按键，那么使用下列步骤后您仍可能把它设为热键。

  1. 确保至少有一个使用 键盘钩子 的脚本正在运行. 打开脚本的主窗口并在菜单栏中选择 "View->Key history" 后您可以判断脚本是否使用了键盘钩子.
  2. 双击脚本的托盘图标来打开其主窗口.
  3. 按下您键盘上的其中一个 "神秘按键".
  4. 选择菜单项 "View->Key history"
  5. 向下滚动到页面的底部. 在底部附近的某个地方可以看到您按键的按下和弹起事件. 注: 一些按键不生成事件, 因此这里看不到它们的事件. 如果是这种情况, 那么您不能直接把此特殊按键设为热键, 因为您的键盘驱动或硬件在很低的 AutoHotkey 无法访问的层面处理它. 要得到可能的解决方法, 请参阅较远的后面.
  6. 如果检测到了您的按键, 请记下列表中第二列的 3 位十六进制值 (例如 159).
  7. 要把此键定义为热键, 请参照此例:
    SC159:: ; 把 159 替换为您按键的值.
MsgBox, %A_ThisHotKey% was pressed.
return

反向: 要把其他键重映射 为 "神秘按键", 请参照此例:

; 把 159 替换为上面找到的值. 把FF（如果需要）替换为
; 按键的虚拟键，它可以在按键历史页面的首列找到。
#c::Send {vkFFsc159}

可选的解决方案: 如果您的按键或鼠标按钮没有在按键历史页面检测到, 那么下面的其中一种方法可能有帮助:

  1. 重新配置您鼠标或键盘的附带软件 (有时可以在控制面板或开始菜单中访问) 来让 "神秘按键" 发送其他的键击. 然后可以在脚本中把这样的键击设置为热键. 例如，如果您配置神秘按键来发送 Control+F1，然后在脚本中通过使用 ^F1:: 您可以把这个按键间接的设置为热键。

  2. 试试 DllCall: 对人体学输入设备的支持. 您还可以在 论坛 中搜索类似 RawInput* 的关键字.

  3. 下面是最后的手段, 通常应该在其他所有方法都无效时才去尝试. 这是由于成功的机会很小且可能会引起难以取消的不必要的副作用.
    禁用或移除您键盘或鼠标的附带软件, 或者让它使用更标准的驱动, 例如操作系统内置的那个. 这里假设您特殊的键盘或鼠标使用自己的驱动并且您不使用其自带驱动和软件提供的功能.


AutoHotkey 脚本和宏

脚本

目录

  • 简介
  • 脚本顶部（自动执行段）：当脚本启动时，这部分会自动执行。
  • 转义序列: 什么时候应该使用 `% 和 `, 来表示原义的百分号或逗号.
  • 在脚本中添加注释: 使用分号和 /*...*/ 符号来给脚本添加注释.
  • 把过长的行分割成一系列短行: 这样可以提高脚本的可读性和可维护性.
  • 把脚本转换成 EXE (ahk2exe): 把 .ahk 脚本转换成可以在任何 PC 上运行的 .exe 文件.
  • 向脚本传递命令行参数: %1%, %2% 等变量包含了传入的参数.
  • 脚本文件代码页: 在脚本中可靠地使用非 ASCII 字符.
  • 调试脚本: 如何找出无法正常工作的脚本中的问题.
  • AutoHotkey.exe 的可移植性: 有 AutoHotkey.exe 的副本足以执行任何的 .ahk 文件.
  • 安装程序选项: 如何无人值守/静默的安装或卸载.

简介

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

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

脚本顶部 (自动执行段)

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

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

每个由 热键, 热字串, 菜单项, GUI 事件 或 计时器 启动的 线程 都以在自动执行段设置的下列属性值作为默认值开始. 如果没有设置，则使用标准的默认值（与下面每个页面中注明的一样）：DetectHiddenWindows、DetectHiddenText、SetTitleMatchMode、SetBatchLines、SendMode、SetKeyDelay、SetMouseDelay、SetWinDelay、SetControlDelay、SetDefaultMouseSpeed、CoordMode、SetStoreCapslockMode、AutoTrim、SetFormat、StringCaseSense、Thread 和 Critical。

如果自动执行段执行了很长时间才结束 (或从未结束), 上面这些设置的默认值将在 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（或 Comment 或 Com 或 C) [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 决定了脚本读取或写入文件时使用的默认编码, 然而 IniRead 和 IniWrite 总是使用 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。如果没有, 则结果可能不理想.

调试脚本

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

ListVars
暂停

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

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

下列命令也可以用于调试: ListLines, KeyHistory 和 OutputDebug.

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

交互调试 [AHK_L 11+]

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

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

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

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

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

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

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

脚本展示

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


变量和表达式

目录

  • 变量
  • 表达式
  • 表达式中的运算符
  • 内置变量
  • 环境变量与普通变量
  • 变量的容量和占用内存

变量

变量的类型: AutoHotkey 中没有明确的变量类型. 然而, 只包含数字 (可以含有小数点) 的变量进行数学运算或比较时, 会被自动转换为数值. (为了提高性能, 在内部会对数字进行缓存以避免与字符串之间的转换.)

变量的作用域和声明: 除了函数中的 局部变量, 其他所有变量都是全局的; 即可以在脚本的任意位置读取或修改它们的内容. 除了在函数页面注明的情况，变量都是不需要声明的；使用它们的时候它们就产生了（每个变量初始为空）。

变量的名称: 变量名不区分大小写 (例如, CurrentDate 等同于 currentdate). 变量名可以含有多达 253 个字符, 并且可以由字母, 数字以及后面的标点组成: # _ @ $

考虑到命名的惯例, 通常在命名变量时最好仅使用字母, 数字和下划线 (例如: CursorPosition, Total_Items 和 entry_is_valid). 这样的风格可以让熟悉其他计算机语言的人更容易理解您的脚本. 而且, 如果您在 AutoHotkey 和其他语言中使用相同的风格, 您会发现能更容易重新读懂自己的脚本.

尽管变量名可以完全由数字组成, 但通常这样的名称仅用于 传入的命令行参数. 这样数值名称的变量不能用在 表达式 中, 因为它们会被看成是数字而不是变量.

因为单词 AND, OR 和 NOT 作为表达式的 运算符 使用, 所以通常不应该把它们用作变量名称. 在表达式中使用这样的名称会无法正确计算.

给变量赋值: 要把字符串或数字保存到变量中, 有两种方法: 传统方法和表达式方法. 传统方法使用 等号运算符 (=) 来指定 没有加引号的 原义字符串或包围在百分号中的变量. 例如：

MyNumber = 123
MyString = This is a literal string.
CopyOfVar = %Var%  ; 和 = 运算符一起使用时, 需要使用百分号来获取变量的内容.

与之相比, 表达式方法使用 冒号等号运算符 (:=) 来保存数字, 加引号的 字符串和其他类型的 表达式. 下面的例子在功能上与前面的例子相同:

MyNumber := 123
MyString := "This is a literal string."
CopyOfVar := Var  ; 和前面段落中与其作用相同的语句不同, 百分号不和 := 运算符一起使用.

后一种方法由于其更清晰并且与其他许多语言几乎一致的 表达式语法 成为大多数人的首选方法.

从上面的例子中您可能已经想到了有两种方法来清除变量的内容 (即让变量为空):

MyVar =
MyVar := ""

上面的这对空引号只能和 := 运算符一起使用, 因为和 = 运算符一起使用时, 则会在变量中保存两个原义的引号字符.

获取变量的内容: 如同赋值有两种方法, 获取变量的内容也有两种方法: 传统方法和表达式方法. 传统方法需要将变量名包围在百分号中来获取变量的内容. 例如：

MsgBox The value in the variable named Var is %Var%.
CopyOfVar = %Var%

与之相比, 表达式方法省去了变量名两边的百分号, 但原义的字符串必须包围在双引号中. 所以, 下面的表达式作用等同于上面的例子:

MsgBox % "The value in the variable named Var is " . Var . "."  ; 使用句点连接两个字符串.
CopyOfVar := Var

在上面的 MsgBox 这行, 通过使用百分号和空格把参数从传统模式改变为表达式模式. 因为所有的命令默认情况下使用传统模式 (除了另外注明的那些), 所以这是必须的. 不过, 某些命令的特定参数已注明接受表达式, 此时前导的百分号可以省略. 例如, 下面的所有语句都是等效的, 因为 Sleep 的首个参数可以是表达式:

Sleep MillisecondsToWait
Sleep %MillisecondsToWait%
Sleep % MillisecondsToWait

变量的比较: 请阅读下面表达式部分中关于不同类型变量比较的重要提示, 尤其是关于何时使用小括号的内容.

表达式

表达式用来对一系列变量, 原义字符串和/或原义数字执行一个或多个操作.

表达式中的变量名称不用包围在百分号中（伪数组和其他的双重引用除外）。所以, 为了与变量区别, 原义的字符串必须用双引号包围. 例如：

if (CurrentSetting > 100 or FoundColor <> "Blue")
    MsgBox The setting is too high or the wrong color is present.

在上面的例子中, 因为 "Blue" 是原义字符串, 所以包围在双引号中. 要在原义字符串中包含真实的引号字符，请指定两个连续的引号，如同此例中的两次演示："She said, ""An apple a day."""。

重要说明：含有表达式的 if 语句与传统的 if 语句（例如 If FoundColor <> Blue），可以通过单词“if”后是否有开括号来区分。尽管通常把整个表达式包围在括号中，不过也可以写成这样：if (x > 0) and (y > 0)。此外, 如果单词 "if" 后的第一项为 函数调用 或类似 "not" 或 "!" 这样的运算符时, 开括号可以完全省略.

空字符串: 要在表达式中使用空字符串, 请指定一对空引号. 例如，当 MyVar 非空时语句 if (MyVar <> "") 的结果为真。然而, 在 传统 if 语句 中, 一对空引号会被视为原义的字符串. 例如，当 MyVar 仅包含一对真实的引号时语句 if MyVar = "" 结果为真。因此，要使用传统的 if 语句判断变量是否为空，则需要让 = 或 <> 的右侧为空，例如：if Var =。

相关提示，任何无效的表达式例如 (x +* 3) 会产生空字符串。

保存表达式的结果: 要把结果赋值给变量, 请使用 := 运算符. 例如：

NetPrice := Price * (1 - Discount/100)

布尔值: 要计算表达式结果为真还是假时 (例如 IF 语句), 表达式结果为空或零被视为假, 而其他所有结果都视为真. 例如，仅当 ItemCount 为空或 0 时 if ItemCount 的结果才为假。类似地，表达式 if not ItemCount 将产生相反的结果。

像 NOT/AND/OR/>/=/< 这些运算符的运算会自动产生真值或假值的结果: 真值时结果为 1 而假值时为 0. 例如, 在下面的表达式中, 如果有一个条件为真则变量 Done 被赋值为 1:

Done := A_Index > 5 or FoundIt

如上面提示的那样, 简单地置空变量或为其赋值为 0 可以让它假值. 利用这种特性，可以使用简写语句 if Done 来检查变量 Done 是真还是假。

单词 true 和 false 是值分别为 1 和 0 的内置变量. 使用它们可以增加脚本的可读性, 例如:

CaseSensitive := false
ContinueSearch := true

整数和浮点数: 在表达式中, 含有小数点的数字被视为浮点数; 否则视为整数. 对于大多数运算符（例如加法和乘法），只要其中的一个输入是浮点数，那么结果也将是浮点数。

不论在表达式中还是在表达式外的其他地方, 整数都可以表示成十六进制或十进制. 十六进制数必须以前缀 0x 开头. 例如，Sleep 0xFF 等同于 Sleep 255。在 v1.0.46.11+，可以识别用科学计数法表示的浮点数；但只有在它们含有小数点时才行（例如 1.0e4 和 -2.1E-4）。

强制使用表达式: 通过在表达式前加上百分号和空格或 tab, 能把表达式用在不直接支持表达式的参数中 (除了像 StringLen 的 OutputVar 和 InputVar 的那些参数). 这种技巧常用来访问 数组. 例如：

FileAppend, % MyArray%i%, My File.txt
MsgBox % "The variable MyVar contains " . MyVar . "."
Loop % Iterations + 1
WinSet, Transparent, % X + 100
Control, Choose, % CurrentSelection - 1

表达式中的运算符

优先级相同的运算符例如乘 (*) 和除 (/) 按从左到右的顺序计算, 下面另行注明的除外. 与之相比, 低优先级的运算符例如加 (+) 在更高优先级的运算符例如 (*) 之后 计算. 例如, 3 + 2 * 2 等价于 3 + (2 * 2). 使用括号可以改变优先级, 例如: (3 + 2) * 2

除了下面注明的情况, 其他时候在数学运算中包含的任何空值 (空字符串) 都 不会 被假定为零. 作为替代, 它会被视为错误, 这将导致那部分表达式的计算结果为空字符串. 例如, 如果变量 X 为空, 那么表达式 X+1 会产生空值而不是 1.

表达式运算符 (按优先级降序排列)

%Var%

如果表达式中的变量包围在百分号中 (例如 %Var%), 不管此变量 包含 什么内容都会被假定为另一个变量 (如果不存在这样的变量, 那么 %Var% 会被解析为空字符串) 的名称或部分名称. 这种方法常用来引用 伪数组 元素, 例如:

Var := MyArray%A_Index% + 100

为了向后兼容, 注明了 "可以使用表达式" 的命令参数把百分号中的孤立名称 (例如 %Var%, 但不是 Array%i%) 当作其两边的百分号不存在一样. 通过把引号包围在括号中可以避免这种情况；例如 Sleep (%Var%)。

[AHK_L 52+]: 除了普通变量, %Var% 还可以解析为 环境变量, 剪贴板或任何的 保留/只读的变量. 在修订号 52 之前, 在这些情况中 %Var% 会被当成空字符串.
x.y | [AHK_L 31+]: 对象访问. 从对象 x 中取值或为其存入值或调用其方法, 此处 y 是个原义值. 请参阅 对象语法.
new | [v1.1.00+]：基于其他对象创建新对象。例如，x := new y 通常等价于 x := {base: y}。new 后应该跟着变量或 GlobalClass.NestedClass 形式的简单类名，还可以像 x := new y(z) 那样加上可选参数（其中 y 是变量而非函数名）。更多细节请参阅自定义对象。
++
-- 		前置和后置的自增/自减. 从变量中增加或减去 1 (但在 1.0.46 之前的版本中, 只有把它们放在一行中才能用; 此行中不能使用其他运算符). 运算符可以放在变量名的前面或后面. 如果放在变量名的 前面, 会立即执行运算并把结果用于后面的运算. 例如，Var := ++X 让 X 自增后才把它的值赋给 Var。相反地, 如果运算符放在变量名的 后面, 在后面的运算使用了变量 之后 才对其进行自增运算. 例如，Var := X++ 把 X 的当前值赋给 Var 后才进行自增。由于向后兼容性，仅当空变量在单独一行时运算符 ++ 和 -- 才把它们视为零；例如 y:=1, ++x 和 MsgBox % ++x 当 x 为空时结果都为空。
** 幂. 底数和指数都可以为小数. 如果指数为负数, 即使底数和指数都为整数, 结果也会被格式化为浮点数. 因为 ** 的优先级高于一元负号，所以 -2**2 的计算过程和 -(2**2) 一样且得到结果 -4。因此，要让负号的优先级高于幂运算，需要把它们包围在括号中，例如 (-2)**2。注意：不支持底数为负数且指数为分数的情况，例如 (-2)**0.5；它会产生空字符串。但 (-2)**2 和 (-2)**2.0 都是支持的。
-
!
~
& *

一元负号（-）：尽管它和减运算符使用相同的符号，但一元负号仅应用于单项或子表达式，如此例中的两次演示：-(3 / -x)。相关提示, 表达式中的任何一元正号 (+) 都会被忽略.

逻辑非(!): 如果运算数为空或 0, 那么逻辑非的结果为 1, 这表示 "真". 否则, 结果为 0 (假). 例如：!x or !(y and z)。注意: 单词 NOT 和 ! 含义相同, 但 ! 优先级更高. 在 v1.0.46+，允许使用连续的一元运算符，例如 !!Var，因为它们是按从右到左的顺序计算。

按位非 (~): 此运算符对运算数按位取反. 如果运算数为浮点数, 则在计算前把它截取成整数. 如果运算数介于 0 和 4294967295 (0xffffffff) 之间, 那么它会被视为 无符号的 32 位值. 否则, 它被视为 有符号的 64 位值. 例如，~0xf0f 计算结果为 0xfffff0f0（4294963440）。

取址（&）：&MyVar 获取 MyVar 的内容的内存地址，此地址一般和 DllCall 结构一起使用。同时 &MyVar 也禁用了此变量中的二进制数的缓存，如果它经常用于数学或数值比较，那么这会拖慢其性能。每当变量的地址改变时会重新启用它的缓存 (例如使用 VarSetCapacity()).

解除引用（*）：*Expression 假定 Expression 解析为数值的内存地址；它会获取在一个介于 0 和 255 之间的数字表示的内存地址中一个字节的内容（地址为 0 时获取的结果也总是 0；但应该避免使用其他任何无效地址，因为它可能会让脚本崩溃）。然而, 使用 NumGet() 获取二进制数通常会更好.
*
/
//

乘 (*): 如果两个输入都为整数, 则结果为整数; 否则结果为浮点数.

真除 (/): 与 EnvDiv 不同, 即使两个输入都是整数, 真除的结果也为浮点数. 例如，3/2 结果为 1.5 而不是 1，而 4/2 结果为 2.0 而不是 2。

向下舍除 (//): 如果两个输入都是整数, 那么双斜线运算符使用高效的整数除法. 例如，5//3 结果为 1 而 5//-3 结果为 -1。如果任何一个输入为浮点数, 则执行浮点除法并把结果往下取整到最近的整数. 例如，5//3.0 结果为 1.0 而 5.0//-3 结果为 -2.0。尽管浮点除法的结果为整数, 但它被保存为浮点格式, 以便其他使用者能使用浮点格式. 关于求模运算，请参阅 mod()。

*= 和 /= 运算符是用变量的值乘以或除以另一个值的一种简写形式. 例如，Var*=2 和 Var:=Var*2 会得到相同的结果（不过前者执行的更好）。

除数为零时结果为空 (空字符串).
+
-

加 (+) 和 减 (-). 相关提示, += 和 -= 运算符是从变量中增加或减少值的一种简写形式. 例如，Var+=2 和 Var:=Var+2 会得到相同的结果（不过前者执行的更好）。同样地，使用 Var++、Var--、++Var 或 --Var 可以让变量增加或减小 1。
<<
>> 		按位左移 (<<) 和 右移 (>>). 用法示例：Value1 << Value2。任何浮点数在计算前会被截取成整数. 左移 (<<) 相当于把 Value1 乘以 "2 的 Value2 次幂". 右移（>>）相当于把 Value1 除以“2 的 Value2 次幂”并把结果往下取整到最近的整数；例如，-3>>1 结果为 -2。
&
^
| 		按位与 (&), 按位异或 (^) 和 按位或 (|). 这三个运算符中, & 优先级最高而 | 优先级最低. 任何浮点数在计算前会被截取成整数.
.

连接. 句点运算符用于把两个项目组合成单个字符串 (在句点的两边至少必须有一个空格). 省略句点也可以达到相同的目的（除非表达式中有不明确的关系，例如 x -y，或在右边的项目含有前导的 ++ 或 -- 运算符）。省略句点时, 合并的两个项目间应该至少有一个空格.
示例（表达式方法）：Var := "The color is " . FoundColor
示例（传统方法）：Var = The color is %FoundColor%

还可以用来连接子表达式. 例如：Var := "The net price is " . Price * (1 - Discount/100)。

以句点 (或其他任何运算符) 开始的行会自动 附加到 前一行的末尾.
~= [AHK_L 31+]: RegExMatch 的简写形式. 例如，"abc123" ~= "\d" 会设置 ErrorLevel 为 0 并得到结果 4（首个数字的位置）。在 v1.1.03 之前, 此运算符和 等号 (=) 运算符优先级相同, 却完全没有说明.
> <
>= <= 		大于（>）、小于（<）、大于或等于（>=）和小于或等于（<=）。如果某个输入不是数字, 则按字母顺序比较 (加了引号的原义字符串例如 "55" 在这种情况中总是被当成是非数值的). 仅当 StringCaseSense 打开时, 比较才区分大小写. 另请参阅: Sort
=
==
<> != 		等号（=）、区分大小写等于（==） 和 不等于（<> 或 !=）。运算符 != 和 <> 功能完全相同。当两个输入都是数字时，运算符 == 和 = 是一样的，当某个输入不是数字时，== 总是区分大小写，而 = 总是不区分大小写（不区分大小写的方法由 StringCaseSense 决定）。与之相比，<> 和 != 都遵循 StringCaseSense。注意: 加了引号的字符串例如 "55" 在这种情况下总是被当成非数值的.
NOT | 逻辑非. 除了优先级较低外, 其他的与 ! 运算符相同. 例如，not (x = 3 or y = 3) 等同于 !(x = 3 or y = 3)。
AND
&& 		这两个运算符都是 逻辑与. 例如：x > 3 and x < 10。要提高性能, 则要应用 求值优化. 此外, 以 AND/OR/&&/|| (或其他任何运算符) 开始的行会自动 附加到 前一行的末尾.
OR
|| 		这两个运算符都是 逻辑或. 例如：x <= 3 or x >= 10。要提高性能, 则要应用 求值优化.
?: 三元运算符 [v1.0.46+]. 此运算符是 if-else 语句 的简写形式. 它计算左侧的条件来决定两个分支中哪个作为最终结果. 例如，var := x>y ? 2 : 3，当 x 大于 y 时保存 2 到 Var；否则保存 3。为了提高性能，只计算决定性的分支（请参阅求值优化）。
:=
+=
-=
*=
/=
//=
.=
|=
&=
^=
>>=
<<=

赋值. 对变量的内容进行运算, 然后把结果保存到同一个变量中 (但在 1.0.46 之前的版本中, 这些运算符只能在一行中最左边使用, 且仅支持前五个运算符). 最简单的赋值运算符为 冒号等号 (:=), 它把表达式的结果保存到变量中. 关于其他运算符的功能说明, 请参阅这个表格中它们的相关条目. 例如，Var //= 2 执行向下舍除，把 Var 除以 2，然后把结果保存回 Var。同样地，Var .= "abc" 为 Var := Var . "abc" 的一种简写形式。

与其他大多数运算符不同, 赋值运算是从右往左执行的. 因此，Var1 := Var2 := 0 这个语句中首先把 0 赋值给 Var2，然后把 Var2 赋值给 Var1。

如果使用赋值运算的结果作为其他某些运算符的输出, 那么输入的值是变量自身. 例如，如果变量 Var 新增值后大于 50，那么表达式 (Var+=2) > 50 结果为真。这样还允许赋值被作为 ByRef 传递或获取它的地址，例如：&(x:="abc")。

需要避免语法错误或提供更直观的操作时, 会自动提升赋值运算符的优先级. 例如：not x:=y 等价于 not (x:=y)。同样地，++Var := X 等价于 ++(Var := X)；而 Z>0 ? X:=2 : Y:=2 等价于 Z>0 ? (X:=2) : (Y:=2)。

由向后兼容引起的已知限制（可能会在未来的版本中解决）：1) 当 /= 为表达式中最左边的运算符并且它不是多语句表达式的一部分时，而且输入都不是浮点数时，它会执行向下舍除（在其他所有情况中，/= 会执行真除）；2) 仅当 += 和 -= 为一行中最左边的运算符时，它们才支持日期/时间的计算；3) 运算符 +=, -= 和 *= 仅在空变量在单独一行时才把它们视为零；例如，y:=1, x+=1 和 MsgBox % x-=3 当 x 为空时都得到空的结果。
,

逗号 (多语句) [v1.0.46+]. 逗号可以用来在单行中书写多个子表达式. 最常用于把多个赋值或函数调用聚集在一起. 例如：x:=1, y+=2, ++index, func()。这样的语句按从左到右的顺序执行. 注意: 以逗号 (或其他任何运算符) 开始的行会自动 附加到 前一行的末尾. 另请参阅: 逗号的性能.

在 v1.0.46.01+, 当逗号后紧跟着变量和等号时, 则这个等号会被自动当成赋值 赋值 (:=). 例如，后面所有的都是赋值：x:=1, y=2, a=b=c。

mod()
round()
abs()

 这些和其他内置数学函数在 这里 阐述.
func.()

[AHK_L 48+]: 试图调用对象 func 的命名的空方法. 按照约定, 这是对象的 "默认" 方法. 如果 func 不是对象, 则调用 默认基对象.

[v1.0.95+]: 如果 func 为函数名, 则调用这个命名的函数.
F(p*) | [AHK_L 60+]: 请参阅 可变参数函数.
x[y] | [AHK_L 31+]: 对象访问. 从对象 x 中取值或为其存入值或调用其方法, 这里的 y 是参数列表或计算方法名. 请参阅 数组语法 和 对象语法.

性能：在 v1.0.48+，使用逗号运算符常常比分开写单独的表达式速度更快，尤其是把一个变量的值赋给另一个变量时（例如 x:=y, a:=b）。当越多的表达式联合成单个表达式时, 性能会持续得到提升; 例如, 把五个或十个简单的表达式联合成单个表达式速度可能提升 35%.

内置变量

下列变量内置于程序中, 可以在任何脚本中引用. 除了 Clipboard, ErrorLevel 和 命令行参数, 其他变量都是只读的; 即它们的内容无法在脚本中直接修改.

目录

  • 特殊字符: A_Space, A_Tab
  • 脚本属性: 命令行参数, A_WorkingDir, A_ScriptDir, A_ScriptName, (...更多...)
  • 日期和时间: A_YYYY, A_MM, A_DD, A_Hour, A_Min, A_Sec, (...更多...)
  • 脚本设置: A_IsSuspended, A_BatchLines, A_TitleMatchMode, (...更多...)
  • 用户空闲时间: A_TimeIdle, A_TimeIdlePhysical
  • GUI 窗口和菜单栏: A_Gui, A_GuiControl, A_GuiEvent, A_EventInfo
  • 热键, 热字串和自定义菜单项: A_ThisHotkey, A_EndChar, A_ThisMenuItem, (...更多...)
  • 操作系统和用户信息: A_OSVersion, A_ScreenWidth, A_ScreenHeight, (...更多...)
  • 杂项: A_Cursor, A_CaretX, A_CaretY, Clipboard, ClipboardAll, ErrorLevel
  • 循环: A_Index, (...更多...)

特殊字符

A_Space | 此变量包含单个空格字符. 请参阅 AutoTrim 了解详情.
A_Tab | 此变量包含单个 tab 字符. 请参阅 AutoTrim 了解详情.

脚本属性

1, 2, 3 等 | 每当启动带命令行参数的脚本时, 会自动创建这些变量. 可以像普通变量一样修改和引用它们 (例如: %1%). 变量 %0% 包含了命令行参数的数目 (如果没有则为 0). 需了解详情请参阅 命令行参数.
A_WorkingDir | 脚本当前工作目录, 这是脚本访问文件的默认路径. 除非是根目录, 否则路径末尾不包含反斜线. 两个示例: C:\ 和 C:\My Documents. 使用 SetWorkingDir 可以改变当前工作目录.
A_ScriptDir | 当前脚本所在目录的绝对路径. 不包含最后的反斜线（根目录同样如此）。
A_ScriptName | 当前脚本的文件名称, 不含路径, 例如 MyScript.ahk.
A_ScriptFullPath | 上面两个变量的组合, 包含了当前脚本的完整路径和名称, 例如 C:\My Documents\My Script.ahk
A_ScriptHwnd [v1.1.01+] | 脚本隐藏主窗口的唯一 ID (HWND/句柄).
A_LineNumber | 当前脚本中正在执行的行所在的行号 (或其 #Include 文件 的行号). 这个行号与 ListLines 显示的一致；它可以用在报告错误的时候，例如：MsgBox Could not write to log file (line number %A_LineNumber%)。 由于 已编译脚本 已经把它所有的 #Include 文件 合并成一个大脚本, 所以它的行号可能与它在未编译模式运行时不一样.
A_LineFile | A_LineNumber 所属文件的完整路径和名称, 除非当前行属于未编译脚本的某个 #Include 文件, 否则它将和 A_ScriptFullPath 相同.
A_ThisFunc [v1.0.46.16+] | 当前正在执行的 自定义函数 的名称 (没有则为空); 例如: MyFunction. 另请参阅: IsFunc()
A_ThisLabel [v1.0.46.16+] | 当前正在执行的 标签 (子程序) 的名称 (没有则为空); 例如: MyLabel. 每当脚本执行 Gosub/Return 或 Goto 时会更新此变量的值. 执行自动调用的标签时也会更新此变量的值，例如计时器、GUI 线程、菜单项、热键、热字串、OnClipboardChange 和 OnExit。不过，当执行从前面的语句“进入”一个标签时不会更新 A_ThisLabel 的值，即此时它还是保持原来的值。另请参阅: A_ThisHotkey 和 IsLabel()
A_AhkVersion | 在 1.0.22 之前的版本, 此变量为空. 否则, 它包含了运行当前脚本的 AutoHotkey 主程序的版本号, 例如 1.0.22. 在 已编译脚本 中, 它包含了原来编译时使用的主程序的版本号. 格式化的版本号使得脚本可以使用 > 或 >= 来检查 A_AhkVersion 是否大于某个最小的版本号，例如：if A_AhkVersion >= 1.0.25.07。
A_AhkPath | 对于未编译脚本: 实际运行当前脚本的 EXE 文件的完整路径和名称. 例如: C:\Program Files\AutoHotkey\AutoHotkey.exe 对于 已编译脚本: 除了通过注册表条目 HKEY_LOCAL_MACHINE\SOFTWARE\AutoHotkey\InstallDir 获取 AutoHotkey 目录外, 其他的和上面相同. 如果找不到这个注册表条目, 则 A_AhkPath 为空.
A_IsUnicode | 当字符串为 Unicode (16 位) 时值为 1, 字符串为 ANSI (8 位) 时为空字符串 (这会被视为 false). 字符串的格式取决于用来运行当前脚本的 AutoHotkey.exe, 如果为已编译脚本, 则取决于用来编译它的主程序.
A_IsCompiled | 如果当前运行的脚本为 已编译 EXE 时此变量值为 1, 否则为空字符串 (这会被视为 false).
A_ExitReason | 最近一次要求脚本终止的原因. 除非脚本含有 OnExit 子程序并且此子程序当前正在运行或被退出尝试至少调用过一次, 否则此变量为空. 请参阅 OnExit 了解详情.

日期和时间

A_YYYY | 4 位数表示的当前年份 (例如 2004). 与 A_Year 含义相同. 注意：要获取符合您区域设置和语言的格式化时间或日期，请使用 FormatTime, OutputVar（时间和长日期）或 FormatTime, OutputVar,, LongDate（获取长格式日期）。
A_MM | 2 位数表示的当前月份 (01-12). 与 A_Mon 含义相同.
A_DD | 2 位数表示的当前月份的日期 (01-31). 与 A_MDay 含义相同.
A_MMMM | 使用当前用户语言表示的当前月份的全称, 例如 July
A_MMM | 使用当前用户语言表示的当前月份的简称, 例如 Jul
A_DDDD | 使用当前用户语言表示的当前星期几的全称, 例如 Sunday
A_DDD | 使用当前用户语言表示的当前星期几的 3 个字母的简称, 例如 Sun
A_WDay | 1 位数表示的当前星期经过的天数 (1-7). 在所有区域设置中 1 都表示星期天.
A_YDay | 当前年份中经过的天数 (1-366). 不会使用零对变量的值进行填充, 例如会获取到 9, 而不是 009. 要对变量的值进行零填充，请使用：FormatTime, OutputVar, , YDay0。
A_YWeek | 符合 ISO 8601 标准的当前的年份和周数 (例如 200453). 要分离年份和周数，请使用 StringLeft, Year, A_YWeek, 4 和 StringRight, Week, A_YWeek, 2。A_YWeek 的准确定义为: 如果含有 1 月 1 日的星期有四天以上在新年里, 则它被认为是新年的第一个星期. 否则, 它为前一年的最后一个星期, 而下一星期为新年的第一星期.
A_Hour | 在 24 小时制 (例如, 17 表示 5pm) 中 2 位数表示的当前小时数 (00-23). 要获取带 AM/PM 提示的 12 小时制的时间，请参照此例：FormatTime, OutputVar, , h:mm:ss tt
A_Min

2 位数表示的当前分钟数 (00-59).
A_Sec | 2 位数表示的当前秒数 (00-59).
A_MSec | 3 位数表示的当前毫秒数 (000-999). 要移除前导零，请参照此例：Milliseconds := A_MSec + 0。
A_Now | YYYYMMDDHH24MISS 格式的当前本地时间. 注意: 使用 EnvAdd 和 EnvSub 可以对日期和时间进行计算. 此外, 使用 FormatTime 可以根据您的区域设置或选项来格式化日期和/或时间.
A_NowUTC | YYYYMMDDHH24MISS 格式的当前的协调世界时 (UTC). UTC 本质上和格林威治标准时间 (GMT) 一致.
A_TickCount

计算机重启后经过的毫秒数. 通过把 A_TickCount 保存到变量中, 经过一段时间后从最近的 A_TickCount 值中减去那个变量, 可以计算出所经过的时间. 例如：

StartTime := A_TickCount
Sleep, 1000
ElapsedTime := A_TickCount - StartTime
MsgBox,  %ElapsedTime% milliseconds have elapsed.

如果您需要比 A_TickCount 的10ms 更高的精确度, 请使用 QueryPerformanceCounter().

脚本设置

A_IsSuspended | 当脚本 挂起时 值为 1, 否则为 0.
A_IsPaused [v1.0.48+] | 当紧随当前线程的 线程 被 暂停 时值为 1. 否则为 0.
A_IsCritical [v1.0.48+] | 当前线程 的 Critical 设置关闭时值为 0. 否则它包含大于零的整数, 即 Critical 使用的 消息检查频率. 因为 Critical 0 关闭了当前线程的关键性，所以 Critical 的当前状态可以这样来保存和恢复：Old_IsCritical := A_IsCritical，后来执行 Critical %Old_IsCritical%。
A_BatchLines | (同义于 A_NumBatchLines) 由 SetBatchLines 设置的当前值. 例如: 200 或 10ms (取决于格式).
A_TitleMatchMode | 由 SetTitleMatchMode 设置的当前模式: 1, 2, 3 或 RegEx.
A_TitleMatchModeSpeed | 由 SetTitleMatchMode 设置的当前匹配速度 (fast 或 slow).
A_DetectHiddenWindows | 由 DetectHiddenWindows 设置的当前模式 (On 或 Off).
A_DetectHiddenText | 由 DetectHiddenText 设置的当前模式 (On 或 Off).
A_AutoTrim | 由 AutoTrim 设置的当前模式 (On 或 Off).
A_StringCaseSense | 由 StringCaseSense 设置的当前模式 (On, Off 或 Locale).
A_FileEncoding | [AHK_L 46+] 包含了多个命令使用的默认编码; 请参阅 FileEncoding.
A_FormatInteger | 由 SetFormat 设置的当前整数格式 (H 或 D). [AHK_L 42+]: 此变量还可能为小写字母 h.
A_FormatFloat | 由 SetFormat 设置的当前浮点数格式.
A_KeyDelay | 由 SetKeyDelay 设置的当前延迟 (总是十进制数, 不是十六进制). 此延迟适用于传统的 SendEvent 模式, 不适用于 SendPlay.
A_WinDelay | 由 SetWinDelay 设置的当前延迟 (总是十进制数, 不是十六进制).
A_ControlDelay | 由 SetControlDelay 设置的当前延迟 (总是十进制数, 不是十六进制).
A_MouseDelay | 由 SetMouseDelay 设置的当前延迟 (总是十进制数, 不是十六进制). 此延迟适用于传统的 SendEvent 模式, 不适用于 SendPlay.
A_DefaultMouseSpeed | 由 SetDefaultMouseSpeed 设置的当前速度 (总是十进制数, 不是十六进制).
A_RegView | [v1.1.08+]：由 SetRegView 设置的当前注册表视图。
A_IconHidden | 托盘图标当前隐藏时值为 1, 否则为 0. 此图标可以使用 #NoTrayIcon 或 Menu 命令进行隐藏.
A_IconTip | 如果使用 Menu, Tray, Tip 为托盘图标指定了自定义的工具提示时，变量的值为这个提示的文本，否则为空。
A_IconFile | 如果使用 Menu, tray, icon 指定了自定义的托盘图标时，变量的值为图标文件的完整路径和名称，否则为空。已知限制：如果脚本原来传递相对路径给系统的 DLL，那么此变量中的路径可能不正确；例如 Menu, Tray, Icon, user32.dll, 2。
A_IconNumber | 当 A_IconFile 为空时此变量为空. 否则, 它的值为 A_IconFile 中的图标编号 (通常为 1).

用户空闲时间

A_TimeIdle | 从系统最后一次接收到键盘, 鼠标或其他输入后所经过的毫秒数. 这可以用来判断用户是否离开. 用户的物理输入和由 任何 程序或脚本生成的模拟输入 (例如 Send 或 MouseMove 命令) 会让此变量重置为零. 由于此变量的值趋向于以 10 的增量增加, 所以不应该判断它是否等于另一个值. 相反, 应该检查此变量是否大于或小于另一个值. 例如：IfGreater, A_TimeIdle, 600000, MsgBox, The last keyboard or mouse activity was at least 10 minutes ago。
A_TimeIdlePhysical | 与上面类似, 但在安装了相应的钩子 (键盘 或 鼠标) 后会忽略模拟的键击和/或鼠标点击; 即此变量仅反应物理事件. (这样避免了由于模拟键击和鼠标点击而误以为用户存在.) 如果两种钩子都没有安装, 则此变量等同于 A_TimeIdle. 如果仅安装了一种钩子, 那么仅此类型的物理输入才会对 A_TimeIdlePhysical 起作用 (另一种/未安装钩子的输入, 包括物理的和模拟的, 都会被忽略).

GUI 窗口和菜单栏

A_Gui | 启动了 当前线程 的 GUI 的名称或编号. 除非当前线程是由 Gui 控件, 菜单项或 Gui 事件 (例如 GuiClose/GuiEscape) 启动的, 否则此变量为空.
A_GuiControl | 启动 当前线程 的 GUI 控件的关联变量名. 如果那个控件没有 关联变量, 则 A_GuiControl 包含此控件的文本/标题中前 63 个字符 (这常用来避免给每个按钮分配变量名). 出现后面这些情况时 A_GuiControl 为空: 1) A_Gui 为空; 2) GUI 菜单项或事件 (例如 GuiClose/GuiEscape) 启动了当前线程; 3) 那个控件没有关联变量, 也没有标题; 或 4) 最初启动当前线程的控件已经不存在 (可能由于 Gui Destroy 的原因).
A_GuiWidth
A_GuiHeight 		在 GuiSize 子程序 中引用时, 它们分别包含了 GUI 窗口的宽度和高度. 它们对应于窗口的工作区, 这是窗口中不包括标题栏, 菜单栏和边框的区域. [v1.1.11+]：这些值会受 DPI 缩放的影响。
A_GuiX
A_GuiY 		它们包含了 GuiContextMenu 和 GuiDropFiles 事件中的 X 和 Y 坐标. 这里的坐标相对于窗口的左上角. [v1.1.11+]：这些值会受 DPI 缩放的影响。
A_GuiEvent
或 A_GuiControlEvent

启动当前线程的事件类型。如果当前线程不是由 GUI 动作 启动的，则此变量为空。否则, 它为下列字符串的其中一个:

Normal: 此事件是由左键单击和键击 (方向键, TAB 键, 空格键, 带下划线的快捷键等) 触发的. 此变量的值还可以用于菜单项和特殊的 Gui 事件, 例如 GuiClose 和 GuiEscape.

DoubleClick: 此事件是由双击触发的. 注意: 双击中的首次点击仍会引起 Normal 事件首先被接收到. 换句话说, 双击时子程序会运行两次: 一次在首次点击时, 再次是在第二次点击时.

RightClick: 仅出现在 GuiContextMenu, ListViews 和 TreeViews.

上下文相关值：要了解详情请参阅 GuiContextMenu、GuiDropFiles、Slider、MonthCal、ListView 和 TreeView。
A_EventInfo

包含下列事件的额外信息:

  • OnClipboardChange 标签
  • 鼠标滚轮热键 (WheelDown/Up/Left/Right)
  • RegisterCallback()
  • GUI 事件, 即 GuiContextMenu, GuiDropFiles, ListBox, ListView, TreeView 和 StatusBar. 如果一个事件没有额外的信息, 那么 A_EventInfo 的值为 0.

注意: 与类似 A_ThisHotkey 这样的变量不同, 每个 线程 会为 A_Gui, A_GuiControl, A_GuiX/Y, A_GuiEvent 和 A_EventInfo 保存它自己本身的值. 因此, 如果一个线程被另一个中断, 在这个线程恢复时它仍将看到这些变量的原来/正确的值.

热键, 热字串和自定义菜单项

A_ThisMenuItem | 最近选择的 自定义菜单项 的名称 (没有则为空).
A_ThisMenu | A_ThisMenuItem 所在菜单的名称.
A_ThisMenuItemPos | 表示 A_ThisMenuItem 在 A_ThisMenu 当前 位置的编号. 菜单中首个项目为 1, 第二项为 2, 依此类推. 菜单分隔线也计算在内. 如果 A_ThisMenuItem 为空或已不存在于 A_ThisMenu 中, 则此变量为空. 如果 A_ThisMenu 已不存在, 则此变量也为空.
A_ThisHotkey | 最近执行的 热键 或 非自动替换热字串 的按键名称 (如果没有则为空), 例如 #z. 如果 当前线程 被其他热键中断, 那么此变量的值会变化, 所以如果之后需要在子程序中使用原来的值, 则必须马上把它复制到另一个变量中. 首次创建热键时 (通过 Hotkey 命令 或 双冒号标签 ), 其键名以及修饰符的顺序成为此热键的固定名称. 另请参阅: A_ThisLabel
A_PriorHotkey | 除了保存前一次热键的名称外, 其他的与上面相同. 如果没有它会为空.
A_PriorKey | [v1.1.01+]: 在最近按键按下或按键释放前最后按下的按键名称, 如果在按键历史中没有适用的按键按下则为空. 不包括由 AutoHotkey 脚本生成的所有输入. 要使用此变量, 首先必须安装 键盘 或 鼠标钩子 同时启用 按键历史.
A_TimeSinceThisHotkey | 从 A_ThisHotkey 按下后到现在经过的毫秒数. 如果 A_ThisHotkey 为空, 则此变量的值为 -1.
A_TimeSincePriorHotkey | 从 A_PriorHotkey 按下后到现在经过的毫秒数. 如果 A_PriorHotkey 为空, 则此变量的值为 -1.
A_EndChar | 用户最近按下的触发了 非自动替换热字串 的 终止符. 如果不需要终止符 (由于使用了 * 选项), 那么此变量将为空.

操作系统和用户信息

ComSpec
[v1.0.43.08+] 		此变量的值与系统环境变量 ComSpec 一样 (例如 C:\Windows\system32\cmd.exe). 常与 Run/RunWait 一起使用. 注意: 此变量不带 A_ 前缀.
A_Temp
[v1.0.43.09+] 		存放临时文件的文件夹的完整路径和名称 (例如 C:\DOCUME~1\UserName\LOCALS~1\Temp). 它的值从下列的其中一个位置获取 (按顺序): 1) 环境变量 TMP, TEMP 或 USERPROFILE; 2) Windows 目录.
A_OSType | 正在运行的操作系统类型。由于 AutoHotkey 1.1 仅支持基于 NT 的操作系统，所以此变量总是为 WIN32_NT。旧版本的 AutoHotkey 运行在 Windows 95/98/ME 时会返回 WIN32_WINDOWS。
A_OSVersion

下列字符串的其中一个：WIN_7 [需要 v1.1+ 或 AHK_L]、WIN_8 [需要 v1.1.08+]、WIN_8.1 [需要 v1.1.15+]、WIN_VISTA、WIN_2003、WIN_XP、WIN_2000。

; 这个示例已过时了，里面的这些操作系统都不再受支持。
if A_OSVersion in WIN_NT4,WIN_95,WIN_98,WIN_ME  ; 注：逗号两边没有空格。
{
    MsgBox This script requires Windows 2000/XP or later.
    ExitApp
}
A_Is64bitOS | [v1.1.08+]：当操作系统为 64 位则值为 1（真），为 32 位则为 0（假）。
A_PtrSize | [AHK_L 42+]: 包含指针的大小值, 单位为字节. 值为 4（32 位）或 8（64位），取决于运行当前脚本的执行程序的类型。
A_Language | 当前系统的默认语言, 值为 这些 4- 位数字编码 的其中一个.
A_ComputerName | 在网络上看到的计算机名称.
A_UserName | 运行当前脚本的用户的登录名.
A_WinDir | Windows 目录. 例如: C:\Windows
A_ProgramFiles
或 ProgramFiles 		Program Files 目录 (例如 C:\Program Files). 在 v1.0.43.08+, 前缀 A_ 可以省略, 这样有助于自然过渡到 #NoEnv.
A_AppData
[v1.0.43.09+] 		当前用户的应用程序数据文件夹的完整路径和名称. 例如: C:\Documents and Settings\Username\Application Data
A_AppDataCommon
[v1.0.43.09+] 		所有用户的应用程序数据文件夹的完整路径和名称.
A_Desktop | 当前用户的桌面文件夹的完整路径和名称.
A_DesktopCommon | 所有用户的桌面文件夹的完整路径和名称.
A_StartMenu | 当前用户的开始菜单文件夹的完整路径和名称.
A_StartMenuCommon | 所有用户的开始菜单文件夹的完整路径和名称.
A_Programs | 当前用户的开始菜单中程序文件夹的完整路径和名称.
A_ProgramsCommon | 所有用户的开始菜单中程序文件夹的完整路径和名称.
A_Startup | 当前用户的开始菜单中启动文件夹的完整路径和名称.
A_StartupCommon | 所有用户的开始菜单中启动文件夹的完整路径和名称.
A_MyDocuments | 当前用户 "我的文档" 文件夹的完整路径和名称. 与大多数类似变量不同, 当此文件夹为驱动器的根目录时, 此变量的值不包含最后的反斜线. 例如, 它的值我 M: 而不是 M:\
A_IsAdmin

如果当前用户有管理员权限, 则此变量的值为 1. 否则为 0.

在 Windows Vista 或更高版本中, 一些脚本可能需要管理员权限才能正常运行 (例如与使用管理员权限执行的进程和窗口进行交互的脚本). 要做到这点，请把下列语句添加到脚本的顶部：

if not A_IsAdmin
{
   Run *RunAs "%A_ScriptFullPath%"  ; 需要 v1.0.92.01+
   ExitApp
}

A_ScreenWidth
A_ScreenHeight

主监视器的宽度和高度, 单位为像素 (例如 1024 和 768).

要获取多显示器系统中其他显示器的尺寸, 请使用 SysGet.

要获取整个桌面（即使它横跨多个显示器）的宽度和高度，请使用下面的例子：

SysGet, VirtualWidth, 78
SysGet, VirtualHeight, 79

此外, 使用 SysGet 可以获取显示器的工作区域, 它比显示器的整个区域小, 因为它不包括任务栏和其他注册的桌面工具栏.
A_ScreenDPI [v1.1.11+] | 在屏幕宽度上每逻辑寸的像素数。在多显示器的系统中，这个值对于所有的显示器都是一样的。在大多数系统中该值为 96；它取决于系统文本大小（DPI）设置。另请参阅 Gui -DPIScale。
A_IPAddress1 到 4 | 计算机中前 4 个网卡的 IP 地址.

杂项

A_Cursor

当前显示的鼠标光标类型. 其值为下列单词的其中一个: AppStarting, Arrow, Cross, Help, IBeam, Icon, No, Size, SizeAll, SizeNESW, SizeNS, SizeNWSE, SizeWE, UpArrow, Wait, Unknown. 与 size 指针类型一起的首字母表示方向, 例如 NESW = NorthEast+SouthWest. 手型指针 (点击和抓取) 属于 Unknown 类别.
A_CaretX
A_CaretY

当前光标 (文本插入点) 的 X 和 Y 坐标. 如果没有使用 CoordMode 使得坐标相对于整个屏幕, 默认坐标相对于活动窗口. 如果没有活动窗口或无法确定文本插入点的位置, 则这两个变量为空.

下面这个脚本可以让您在四处移动文本插入点时, 查看显示在自动更新工具提示上的当前位置. 注意在某些窗口 (例如某些版本的 MS Word) 会不管文本插入点的实际位置如何都报告同样的位置.

#Persistent
SetTimer, WatchCaret, 100
return
WatchCaret:
  ToolTip, X%A_CaretX% Y%A_CaretY%, A_CaretX, A_CaretY - 20
return

如果以很高的频率 (即每 500 ms 或更快) 重复获取这些变量的内容, 那么可能会干扰用户双击鼠标. 没有已知的解决方法.
Clipboard | 操作系统剪贴板的内容, 可以从中读取或写入内容. 请参阅 剪贴板 章节.
ClipboardAll | 剪贴板中的完整内容 (包含格式和文本). 请参阅 ClipboardAll.
ErrorLevel | 请参阅 ErrorLevel.
A_LastError | 操作系统 GetLastError() 函数或最近 COM 对象调用返回的结果. 要了解详情, 请参阅 DllCall() 和 Run/RunWait.

循环

A_Index | 当前循环重复的次数 (64 位整数). 例如, 当脚本首次执行此循环体时, 此变量的值为 1. 要了解详情请参阅 Loop 或 While 循环.
A_LoopFileName 等 | 此变量和其他相关变量仅在 文件循环 中有效.
A_LoopRegName 等 | 此变量和其他相关变量仅在 注册表循环 中有效.
A_LoopReadLine | 请参阅 文件读取循环.
A_LoopField | 请参阅 解析循环.

环境变量与 "普通" 变量

环境变量由操作系统维护. 在命令提示符中输入 SET 并回车后, 您可以看到环境变量列表.

脚本中可以使用 EnvSet 创建新的环境变量或改变现有环境变量的内容. 但是, 这样的添加和改变都是私有的; 它们不会被系统的其他部分看到. 一个例外是当脚本使用 Run 或 RunWait 运行程序时 (甚至是另一个脚本): 这样的程序会继承其父脚本的环境变量的副本, 包括私有的那些.

在 v1.0.43.08+, 推荐在所有新脚本中使用以下方式获取环境变量, 例如 Path:

EnvGet, OutputVar, Path  ; 想了解含义, 请参阅 #NoEnv.

变量的容量和占用内存

  • 每个变量最多可以含有64MB的文本（使用#MaxMem可以突破这个限制）。
  • 当赋值给变量比当前更长的内容时, 会自动分配额外的系统内存给这个变量.
  • 通过赋值为空可以释放大变量占用的内存，例如 Var := ""。
  • 脚本可以创建的变量数量没有限制. 程序设计用来支持至少几百万的变量而不会出现明显的性能下降.
  • 接受数值输入的命令, 函数和表达式通常可以支持 15 位的浮点数精度. 对于整数, 可以支持 64 位有符号整数, 其范围从 -9223372036854775808 (-0x8000000000000000) 到 9223372036854775807 (0x7FFFFFFFFFFFFFFF). 此范围外的任何整数不受支持, 并可能产生错误的结果. 与之相比, 整数的算数运算结果超出此范围时会产生溢出 (例如 0x7FFFFFFFFFFFFFFF + 1 = -0x8000000000000000).


函数

目录

  • 入门和简单示例
  • 参数
  • 可选参数
  • 返回值给调用者
  • 可变参数函数
  • 局部变量
  • 动态调用函数
  • 优化布尔求值
  • 在函数中使用子程序
  • Return, Exit 及一般说明
  • 使用 #Include 在多个脚本间共享函数
  • 函数库: 标准库和用户库
  • 内置函数

入门和简单示例

函数类似于子程序 (Gosub), 不过它可以从调用者那里接受参数 (输入). 同时, 函数还可以返回值给其调用者. 思考后面这个接受两个数字并返回它们的和的简单函数:

Add(x, y)
{
    return x + y   ; "Return" 期望 表达式.
}

上面的被称为函数 定义, 因为它创建了一个名称为 "Add" (不区分大小写) 的函数并且确立了调用它时必须准确的提供两个参数 (x 和 y). 要调用此函数, 请把它的结果通过 := 运算符 赋值给变量. 例如：

Var := Add(2, 3)  ; 数字 5 将被保存到 Var.

并且, 调用函数时可以不保存其返回值:

Add(2, 3)

但在这种情况下, 函数返回的任何值会被丢弃; 所以除非函数产生了返回值外的其他效果, 否则这个调用没有意义.

由于函数调用是 表达式, 在其参数列表中的任何变量名称都不应该括在百分号中. 与之相比, 原义的字符串应该括在双引号中. 例如：

if InStr(MyVar, "fox")
    MsgBox The variable MyVar contains the word fox.

最后, 可以在任何命令的参数中调用函数 (除了像 StringLen 的中的那些 OutputVar 和 InputVar 参数). 然而, 不支持 表达式 的参数必须加上 "% " 前缀, 例如:

MsgBox % "The answer is: " . Add(3, 2)

在原生支持表达式的参数中也允许加上 "% " 前缀, 不过它会被简单的忽略了.

参数

定义函数时, 其参数都在其名称后面的括号中列出 (在其名称和开括号之间不能含有空格). 如果函数不接受任何参数，请把括号留空，例如：GetCurrentTimestamp()。

ByRef 参数: 从函数的角度看, 参数本质上是 局部变量, 除非它们被定义为 ByRef, 例如:

Swap(ByRef Left, ByRef Right)
{
    temp := Left
    Left := Right
    Right := temp
}

在上述例子中, ByRef 的使用让每个参数变成从调用者传递进来的变量的一个别名. 换句话说, 参数和调用者的变量都引用内存中相同的内容. 这样使得 Swap 函数可以通过移动 Left 的内容到 Right 中来修改调用者的变量, 反之亦然.

与之相比, 在上述例子中如果没有使用 ByRef, Left 和 Right 将是调用者变量的副本, 因此 Swap 函数不会对外部产生影响.

由于 return 只能送回一个值给函数的调用者, 所以可以使用 ByRef 送回更多的结果. 这是由函数向调用者传递进来的变量 (通常为空) 储存一个值来实现的.

传递大字符串给函数时, 使用 ByRef 提高了性能并且通过避免生成字符串的副本节约了内存. 同样地, 使用 ByRef 送回长字符串给调用者通常比类似 Return HugeString 的方式执行的更好.

[AHK_L 60+]: 如果传递给 ByRef 参数的不是可修改的变量, 那么函数会表现的就像关键字 "ByRef" 没有那样. 例如, Swap(A_Index, i) 保存 A_Index 的值到 i 中, 但是当 Swap 函数返回时赋给 Left 的值会被丢弃.

[v1.1.01+]： IsByRef() 函数可以用来判断调用者是否为指定的 ByRef 参数提供了变量。

已知限制:

  • 对象字段在 ByRef 的目的中不会被视为变量. 例如, 如果 foo.bar 传递给 ByRef 参数, 那么它将表现的就像 ByRef 没有那样.
  • 不能传递 Clipboard, 内置变量 或 环境变量 给函数的 ByRef 参数, 即使脚本中没有 #NoEnv 时.
  • 尽管函数可以递归调用它自己，但是如果它传递它自己的一个局部变量或非 ByRef 参数给自己的 ByRef，那么新一层的 ByRef 参数将引用它自己那个名称的局部变量而不是之前层的。然而, 当函数传递给它自己 全局变量, 静态变量 或 ByRef 参数时不会产生这样的问题.
  • 如果一个参数在函数调用中被解析为一个变量 (例如 Var 或 ++Var 或 Var*=2), 它左边或右边的其他参数可能在它被传递给函数前修改这个变量. 例如, 当 Var 初始为 0 时 func(Var, Var++) 会意外地传递 1 和 0, 即使函数的首个参数不是 ByRef 类型时. 因为这种行为是违反常规的, 所以可能在将来的版本中改变.

可选参数

定义函数时, 可以把它的一个或多个参数标记为可选的. 这可以通过在参数后添加一个等号（在 v1.1.09+ 中还可以为 :=）跟着默认值完成. 后面的函数中其 Z 参数被标记为可选的:

Add(X, Y, Z:=0) {
    return X + Y + Z
}

从 v1.1.09 起，= 和 := 都支持。为了与表达式赋值保持一致且与将来的 AutoHotkey 版本兼容，建议使用后者。

当调用者传递 三个 参数给上面的函数时, Z 的默认值被忽略. 但当调用者仅传递 两个 参数时, Z 自动接受默认值 0.

可选参数不能孤立地放在参数列表的中间. 换句话说, 在首个可选参数右边的所有参数都必须标记为可选的. [AHK_L 31+]：调用函数时可以省略参数列表中间的可选参数，如下所示：对于动态的函数调用和方法调用，版本为 v1.1.12+ 才支持这种特性。

Func(1,, 3)
Func(X, Y:=2, Z:=0) {  ; 请注意此时 Z 必须是可选的。
    MsgBox %X%, %Y%, %Z%
}

在 v1.0.46.13+, ByRef 参数 也支持默认值; 例如: Func(ByRef p1 = ""). 每当调用者省略这样的参数时, 函数会创建一个包含默认值的局部变量; 换句话说, 函数表现的就像关键字 "ByRef" 没有那样.

参数的默认值必须是下列形式的其中一种：true、false、原义的整数、原义的浮点数或引号包围的/原义的字符串例如 "fox" 或 ""（但在 1.0.46.13+ 之前的版本中字符串只支持 ""）。

返回值给调用者

如介绍中所说，函数可以返回值给调用者。

Test := returnTest()
MsgBox % Test

returnTest() {
  return 123
}

如果要从函数中返回额外的结果，可以使用 ByRef：

returnByRef(A,B,C)
MsgBox % A "," B "," C

returnByRef(ByRef val1, ByRef val2, ByRef val3)
{
  val1 := "A"
  val2 := 100
  val3 := 1.1
  return
}

[v1.0.97+]： 可以使用对象和数组返回多值甚至是命名值：

Test1 := returnArray1()
MsgBox % Test1[1] "," Test1[2]

Test2 := returnArray2()
MsgBox % Test2[1] "," Test2[2]

Test3 := returnObject()
MsgBox % Test3.id "," Test3.val

returnArray1() {
  Test := [123,"ABC"]
  return Test
}

returnArray2() {
  x := 456
  y := "EFG"
  return [x, y]
}

returnObject() {
  Test := {id: 789, val: "HIJ"}
  return Test
}

可变参数函数 [AHK_L 60+]

定义函数时, 在最后一个参数后面写一个星号来标记此函数为可变参数的, 这样让它可以接收可变数目的参数:

Join(sep, params*) {
    for index,param in params
        str .= param . sep
    return SubStr(str, 1, -StrLen(sep))
}
MsgBox % Join("`n", "one", "two", "three")

调用可变参数函数时, 通过保存在函数的最后参数中的对象可以访问剩余的参数. 函数的首个剩余参数在 params[1], 第二个在 params[2] 等等. 和所有的标准对象一样, 使用 params.MaxIndex() 可以确定最大的索引值 (这里为参数的数目). 但是如果没有参数, MaxIndex 会返回空字符串.

注意:

  • "可变" 参数只可以出现在形式参数列表的末尾.
  • RegEx 调出函数不是可变参数的，虽然允许使用“可变的”参数但会被留空。
  • 回调函数 通过地址而不是数组传递剩余参数。

可变参数函数调用

虽然可变参数函数可以接受可变数目的参数，不过在函数调用中使用相同的语法可以把数组作为参数传递给任何函数：

substrings := ["one", "two", "three"]
MsgBox % Join("`n", substrings*)

注意:

  • 在源数组中参数的编号从 1 开始.
  • 数组中的可选参数可以完全省略.
  • 调用自定义函数时数组参数可以包含命名项，在其他情况下则不支持命名项。
  • 目标函数也可以是可变的, 此时命名项被复制, 即使它们没有一致的形式参数.
  • 这样的语法还可以用于调用对象的方法或获取对象的属性; 例如, Object.Property[Params*]. 在 v1.1.12+，它还可以用于设置属性。

已知限制:

  • 只有最右边的那个参数才可以这样展开。例如, 支持 Func(x, y*) 但不支持 Func(x*, y).
  • 在星号 (*) 和参数列表中最后的形式参数间不能存在任何的非空白字符.

局部变量和全局变量

局部变量

默认情况下, 在函数中创建或访问的所有变量都是 局部的 (除了 超级全局 变量和内置变量, 例如 Clipboard, ErrorLevel 和 A_TimeIdle). 每个局部变量的内容只在它所在的函数中可见. 因此, 一个局部变量可以和一个全局变量有相同的名称却有着不同的内容. 最后, 所有的局部变量在每次调用函数时都以空值开始.

全局变量

要在函数中引用现有的全局变量 (或创建新的), 需要在使用前声明此变量为全局的. 例如：

LogToFile(TextToLog)
{
    global LogFileName  ; 此全局变量之前已经在函数外的某个地方赋值了.
    FileAppend, %TextToLog%`n, %LogFileName%
}

假设全局模式: 如果函数需要访问或创建大量的全局变量, 通过在函数的首行使用单词 "global" 或声明局部变量可以把函数定义为假设其所有的变量都是全局的 (除了它的参数). 例如：

SetDefaults()
{
    global  ; 如果此函数的首行是类似于 "local MyVar" 这样的, 那么这个单词可以省略.
    MyGlobal := 33  ; 把 33 赋值给全局变量, 必要时首先创建这个变量.
    local x, y:=0, z  ; 在这种模式中局部变量必须进行声明, 否则会假设它们为全局的.
}

函数还可以使用这种假设全局模式来创建全局 数组, 例如赋值给 Array%A_Index% 的循环.

超级全局变量 [v1.1.05+]: 如果全局声明出现在任何函数的外面, 默认情况下它可以对所有函数有效. 这样可以避免在每个函数中重复声明变量的需要. 不过, 如果声明了含有相同名称的函数参数或局部变量, 那么它会优先于全局变量. 由 class 关键字创建的变量也是超级全局的.

静态变量

静态变量总是隐式的局部变量, 但和局部变量的区别是它们的值在多次调用期间是记住的. 例如：

LogToFile(TextToLog)
{
    static LoggedLines = 0
    LoggedLines += 1  ; 保持局部的计数 (它的值在多次调用期间是记住的).
    global LogFileName
    FileAppend, %LoggedLines%: %TextToLog%`n, %LogFileName%
}

静态初始化: 在 1.0.46 以前的版本中, 所有的静态变量都是以空值开始; 所以要检查静态变量首次被使用的唯一方法是检查它是否为空值. 在 v1.0.46+，静态变量可以初始化为 "" 外的其他值，通过在后面跟着 := 或 = 及后面这些形式的其中一种：true、false、原义的整数、原义的浮点数或引号包围的/原义的字符串，如 "fox"。例如：static X:=0, Y:="fox"。每个静态变量只初始化一次 (在脚本开始执行前).

[AHK_L 58+]: 支持 Static var := expression. 根据这些表达式在脚本中出现的顺序对它们进行计算，紧接着才进入脚本的自动执行段。

假设静态模式 [v1.0.48+]: 通过在函数的首行使用单词 "static" 可以把函数定义为假设其所有的变量都是静态的 (除了它的参数). 例如：

GetFromStaticArray(WhichItemNumber)
{
    static
    static FirstCallToUs := true  ; 静态声明初始化仍然只运行一次 (在脚本执行前).
    if FirstCallToUs  ; 在首次调用而不在后续的调用时创建静态数组.
    {
        FirstCallToUs := false
        Loop 10
            StaticArray%A_Index% := "Value #" . A_Index
    }
    return StaticArray%WhichItemNumber%
}

在假设静态模式中, 任何非静态变量都必须声明为局部变量或全局变量.

关于局部和全局的更多信息

通过逗号分隔多个变量这样可以在同一行声明它们, 例如:

global LogFileName, MaxRetries := 5
static TotalAttempts = 0, PrevResult

在 v1.0.46+, 通过后面跟着 := or = 及任意 表达式 局部或全局变量可以在同一行初始化, 如同声明那样 (在声明时 = 运算符和 := 作用相同). 与 静态初始化 不同, 在每次调用函数时都会对局部变量和全局变量进行初始化, 但只在控制流实际达到它们所在的语句时. 换句话说, 像 local x = 0 这样的一行和写成单独的两行有同样的效果: local x 后面跟着 x = 0.

因为单词 local, global 和 static 都是在脚本运行时立即处理的, 所以不能使用 IF 语句 有条件的声明变量. 换句话说, IF 或 ELSE 的 区块 内的声明无条件对声明和函数的闭括号之间的所有行生效. 同时还需注意当前还不支持声明动态变量, 例如 global Array%i%.

对于创建 数组 的命令 (例如 StringSplit), 如果 假设全局模式 没有生效或数组的首个元素已经声明为局部变量时创建的数组是局部的 (如果函数的某个参数被传递时也是如此, 即使此参数为 ByRef 类型, 因为参数类似于局部变量). 相反地, 如果首个元素已经 声明为全局的, 那么创建全局的数组. 不过, 后面 混乱的常见根源 也适用于这些情况. StringSplit 创建的数组首个元素为 ArrayName0. 对于其他创建数组的命令, 例如 WinGet List, 首个元素为 ArrayName (即没有数字).

在函数中, 任何动态变量引用, 例如 Array%i%, 总是解析为局部变量, 仅当这样名称的局部变量不存在而全局变量存在时才解析为全局变量. 如果两者都不存在并且需要创建此变量时, 当 假设全局模式 没有生效时它被创建为局部变量. 因此, 仅当函数被定义为 假设全局 函数时, 函数中才可以手动创建全局 数组 (通过使用类似 Array%i% := A_Index 的方法).

混乱的常见根源: 任何对 非 动态引用都会在脚本运行时创建那个变量. 例如, 在函数外使用时, MsgBox %Array1% 会在脚本运行的时候创建 Array1 为全局变量. 相反地, 在函数中使用 MsgBox %Array1% 会在脚本运行的时候创建 Array1 为函数的一个局部变量 (除非 假设全局模式 生效), 即使 Array 和 Array0 都声明为全局的.

动态调用函数

在 v1.0.47.06+, 通过百分号可以动态调用函数 (包括 内置函数). 例如，%Var%(x, "fox") 将调用名称保存在 Var 中的函数。同样地, Func%A_Index%() 将调用 Func1() 或 Func2() 等, 这取决于 A_Index 的当前值.

在 v1.1.07.00+, 在 %Var%() 中的 Var 可包含函数名, 函数引用 或 模仿函数的对象. 如果此函数不存在, 则调用 默认基对象的 __Call 元函数.

如果由于下面的某个原因无法调用函数, 计算包含调用的表达式时可能会过早静默停止, 这样可能会产生问题.

  • 调用不存在的函数, 这可以通过使用 If IsFunc(VarContainingFuncName) 来避免. 除了 内置函数, 被调用函数的 定义 必须明确存在于脚本中, 通过类似 #Include 或对 库函数 的非动态调用的方法.
  • 传递过少的参数, 这可以通过检查 IsFunc() 的返回值来避免 (这是强制参数的数目加上一的数字). 注意: 在 v1.0.48+, 允许传递过多的参数; 每个额外的参数在被完全计算 (包括任何函数调用) 后丢弃.

最后, 对函数的动态调用比正常调用稍慢, 因为正常的调用在脚本开始运行前解析 (查询).

优化布尔求值

当在 表达式 中使用 AND, OR 和 三元运算符 时, 会对它们进行优化来提高性能 (不管当前是否存在函数调用). 通过不计算表达式中那些不影响最终结果的部分来进行优化运算. 为了说明这个概念, 请看这个例子:

if (ColorName <> "" AND not FindColor(ColorName))
    MsgBox %ColorName% could not be found.

在上面的例子中, 如果 ColorName 变量为空则永远不会调用 FindColor() 函数. 这是由于 AND 的左侧结果将为 false, 因此其右边不可能让最终的结果为 true.

由于此特性, 所以需要注意到, 如果在 AND 或 OR 的右侧调用函数, 那么函数可能永远不会产生副作用 (例如改变全局变量的内容).

还需要注意在嵌套的 AND 和 OR 串联表达式的求值优化. 例如, 在后面的表达式中每当 ColorName 为空时只会进行最左边的比较. 这是因为此时最左边的比较已经足以确定最终的结果:

if (ColorName = "" OR FindColor(ColorName, Region1) OR FindColor(ColorName, Region2))
    break   ; 搜索内容为空或找到了匹配.

从上面的例子可以看出, 任何耗时的函数一般应该在 AND 或 OR 的右侧调用从而提高性能. 这种方法还能避免调用接受了一个不合适的值例如空字符串的函数.

在 v1.0.46+, 三元条件运算符 (?:) 也通过不计算丢弃的分支进行求值优化.

在函数中使用子程序

尽管在一个函数中不能 定义 其他函数, 但它可以含有子程序. 与其他子程序一样使用 Gosub 运行它们且使用 Return 返回 (此时 Return 属于 Gosub 而不是函数).

已知限制: 当前每个子程序 (标签) 的名称在整个脚本中必须是唯一的. 如果存在重复的标签, 在运行前程序会通知您.

如果函数使用 Gosub 跳转到公共子程序 (在函数外部的子程序), 那么所有外面的变量都是全局的而且在子程序返回前无法引用函数自身的 局部变量. 不过, A_ThisFunc 仍将包含正在执行的函数名称.

尽管不能使用 Goto 从函数中跳转到外面, 但可以在函数中使用 Gosub 到外部/公共的子程序, 然后在那里使用 Goto.

尽管一般不鼓励使用 Goto, 但它能用来在同个函数中的一个位置跳转到其他位置. 这样有助于简化包含许多个返回点而所有这些点在返回前需要进行一些清理的复杂函数.

函数可以包含能被外部调用的子程序，例如计时器、GUI g 标签和菜单项。通常把它们封装到一个单独的文件中供 #Include 使用, 这样避免了它们和脚本的 自动执行段 的冲突. 不过, 还存在下面这些限制:

  • 如果它们所在的函数曾经被正常调用, 那么这样的子程序应该只使用 静态 和 全局 变量 (不使用 局部 变量). 这是由于中断函数调用线程的子程序 线程 (反之亦然) 可以改变被中断线程看到的局部变量的值. 此外, 在任何时候函数返回到其调用者时, 它包含的所有局部变量都被置空来释放占用的内存.
  • 这样的子程序应该只使用 全局变量 (不使用 静态变量) 作为 GUI 控件的变量.
  • 当一个子程序 线程 进入函数后, 在此线程中任何对 动态变量 的引用都被视为是 全局 的 (包括创建数组的那些命令).

Return, Exit 及一般说明

如果函数内的执行流在遇到 Return 前到达了函数的闭括号, 那么函数结束并返回空值 (空字符串) 给其调用者. 当函数明确省略 Return 的参数时也返回空值.

当函数使用 Exit 命令终止 当前线程 时, 其调用者不会接收到返回值. 例如，这个语句 Var := Add(2, 3) 中，如果 Add() 退出了那么 Var 会保持不变。如果函数出现了运行时错误, 例如 运行 了一个不存在的文件 (当 UseErrorLevel 选项不存在时), 也会出现同样的情况.

如果要返回一个额外的容易记住的值, 那么函数可以修改 ErrorLevel 的值来实现.

要使用一个或多个空值（空字符串）调用函数，可以使用空的引号对，例如：FindColor(ColorName, "")。

因为调用函数不会开启新 线程, 所以函数对设置例如 SendMode 和 SetTitleMatchMode 做出的任何改变对其调用者同样有效.

函数的调用者可以传递不存在的变量或 数组 元素给它, 当函数期望和 ByRef 一致的参数时这很有用. 例如, 调用 GetNextLine(BlankArray%i%) 会自动地创建 局部 或全局的变量 BlankArray%i% (是局部还是全局取决于调用者是否在函数内并且它的 假设全局模式 是否有效).

在函数中使用 ListVars 时, 它会显示函数的 局部变量 及其内容. 这样可以帮助调试脚本.

风格和命名约定

您也许会发现, 如果给复杂函数中的特定变量加上独特的前缀会让函数更容易阅读和维护. 例如, 使用 "p" 或 "p_" 开头来命名函数中的每个参数可以让它们的性质一目了然, 尤其是当函数中有许多 局部变量 吸引您的注意力的时候. 同样地, 前缀 "r" 或 "r_" 可以用于 ByRef 参数, 而 "s" 或 "s_" 可以用于 静态变量.

在定义函数时可以使用 One True Brace (OTB) 风格. 例如：

Add(x, y) {
    return x + y
}

使用 #Include 在多个脚本间共享函数

可以使用 #Include 指令 (即使在脚本的顶部) 从外部文件中加载函数.

说明: 当脚本的执行流遇到函数定义时, 它会跳过函数 (使用一种瞬时的方法) 并在函数闭括号后恢复执行. 因此, 开始执行时执行流不会陷入函数中, 也不会因为在脚本的最顶部存在一个或多个函数而影响到 自动执行段.

函数库: 标准库和用户库 [v1.0.47+]

脚本中可以不需要通过 #Include 而调用外部文件中的函数. 要达到此目的, 一个和函数相同名称的文件必须存在于下面库目录的其中一个:

%A_ScriptDir%\Lib\  ; 局部库 - 需要 AHK_L 42+.
%A_MyDocuments%\AutoHotkey\Lib\  ; 用户库.
path-to-the-currently-running-AutoHotkey.exe\Lib\  ; 标准库.

例如，当脚本调用不存在的函数 MyFunc() 时，程序会在用户库中搜索名为“MyFunc.ahk”的文件。如果没有找到, 会继续在标准库中搜索此文件. 如果仍然没有找到匹配的文件且函数的名称含有下划线（例如 MyPrefix_MyFunc），那么程序会在两个库中搜索名为 MyPrefix.ahk 的文件，如果找到则加载它。这样使得 MyPrefix.ahk 可以同时包含 MyPrefix_MyFunc 函数和其他名称以 MyPrefix_ 开始的相关函数。

[AHK_L 42+]: 支持局部库且局部库优先于用户库和标准库.

虽然库文件通常只包含和它的文件名称相同的单个函数, 但它还可以包含仅被此函数调用的私有函数和子程序. 然而, 这样的函数应该使用相当特殊的名称, 因为它们仍属于全局命名空间; 也就是说, 可以在脚本的任意位置调用它们.

如果在库文件中使用 #Include, 那么 #Include 的工作目录为库文件自身所在的目录. 利用这个特性可以重定向到较大的库文件, 其中包含此函数及相关内容.

脚本编译器 (ahk2exe) 同样支持库函数. 不过, 它要求在编译器目录的上一级目录中存在 AutoHotkey.exe 的副本 (通常是这样). 如果不存在 AutoHotkey.exe, 编译器仍可以运行但无法自动包含库函数.

包含在库中的函数和其他函数执行的一样好, 因为在脚本开始执行前已经预加载了它们.

内置函数

在内置函数参数列表末尾的任何可选参数可以完全省略. 例如, WinExist("Untitled - Notepad") 是有效的, 因为它的其他三个参数被认为是空的.

如果脚本定义了与内置函数同名的函数, 那么内置函数会被覆盖. 例如, 脚本会调用它自己定义的 WinExist() 函数来代替标准的那个. 然而, 这样脚本将无法调用原来的函数.

在 DLL 文件中的外部函数可以使用 DllCall() 调用.

常用函数

FileExist(FilePattern): 如果 FilePattern 不存在 (如果未指定绝对路径, 则假定 FilePattern 在 A_WorkingDir 中) 则返回空值 (空字符串). 否则, 它返回首个匹配的文件或文件夹的 属性字符串 ("RASHNDOCT" 的子集). 如果文件没有属性 (很少见), 则返回 "X". FilePattern 可以是文件或文件夹的准确名称或包含通配符 (* 或 ?). 由于空字符串被视为 "false", 所以总可以把函数的返回值作为准布尔值来使用. 例如, if FileExist("C:\My File.txt") 语句当文件存在时则为真, 否则为假. 同样地, if InStr(FileExist("C:\My Folder"), "D") 语句仅当文件存在 并且 为目录时才为真. 相关命令: IfExist 和 FileGetAttrib.

GetKeyState(KeyName [, "P" 或 "T"])：与 GetKeyState 命令（它在按下时返回 D 而弹起时返回 U）不同，此函数在按下时返回 true（1）而弹起时返回 false（0）。如果 KeyName 无效, 则返回空字符串. 请参阅 GetKeyState 了解其他返回值和用法.

InStr(Haystack, Needle [, CaseSensitive = false, StartingPos = 1, Occurrence = 1]): 返回字符串 Needle 在字符串 Haystack 中的出现位置. 与 StringGetPos 不同, 首个字符位置为 1; 这是由于 0 相当于 "false", 使其成为直观的 "未找到" 的提示. 如果参数 CaseSensitive 省略或为 false, 搜索不区分大小写 (不区分的模式取决于 StringCaseSense); 否则, 必须准确匹配大小写. 如果 StartingPos 省略, 那么使用默认值 1 (Haystack 的起始处). 否则, 从 Haystack 的第二个字符开始请指定 2, 从第三个开始为 3, 等等. 如果 StartingPos 超过了 Haystack 的长度, 则返回 0. 如果 StartingPos 为 0 或负数, 搜索将从末尾的偏移处开始反向进行 (从右往左). 不论 StartingPos 的值是多少, 返回的位置总是相对于 Haystack 的首个字符. 例如, "abc" 在 "123abc789" 中的位置总为 4. 在 Occurrence 中指定 2 来返回第二个匹配的位置, 3 为第三个, 等等. 相关项: RegExMatch(), IfInString 和 StringGetPos.

RegExMatch(Haystack, NeedleRegEx [, UnquotedOutputVar = "", StartingPos = 1])：判断字符串是否包含某个匹配模式（正则表达式）。请参阅 RegExMatch() 了解详情。

RegExReplace(Haystack, NeedleRegEx [, Replacement = "", OutputVarCount = "", Limit = -1, StartingPos = 1])：替换字符串中匹配模式（正则表达式）出现的地方。请参阅 RegExReplace() 了解详情。

SubStr(String, StartingPos [, Length]) [v1.0.46+]: 在 String 中从 StartingPos 开始向右复制不超过 Length 长度的子字符串 (如果 Length 省略, 则默认为 "所有字符"). 对于 StartingPos, 指定 1 从首个字符开始, 2 从第二个开始等 (如果 StartingPos 超过了 String 长度, 则返回空字符串). 如果 StartingPos 小于 1, 那么它被看成是从字符串末尾开始的偏移. 例如, 0 提取最后一个字符而 -1 提取最后两个字符 (但如果 StartingPos 超过了字符串的左端, 则提取又从首个字符开始). Length 是需提取字符的最大数目 (当字符串剩余部分太短时提取的数目会比最大值少). 指定负的 Length 从而在返回字符串的末尾省略这个数目的字符（如果省略了全部或过多字符则返回空字符串）。相关项: RegExMatch(), StringMid, StringLeft/Right, StringTrimLeft/Right.

StrLen(String): 返回 String 的长度. 请参阅 StrLen() 了解详情。

StrSplit(String [, Delimiters, OmitChars]) [v1.1.13+]：使用指定的分隔符把一个字符串分解成多个子字符串并保存到数组中。请参阅StrSplit()了解详情。

WinActive([WinTitle, WinText, ExcludeTitle, ExcludeText])：如果活动窗口匹配指定的条件，则返回其 唯一 ID （HWND）。请参阅 WinActive() 了解详情。

WinExist([WinTitle, WinText, ExcludeTitle, ExcludeText])：返回首个匹配窗口的唯一 ID（HWND）。请参阅 WinExist() 了解详情。

杂项函数

Asc(String): 返回 String 中首个字符的字符编码 (介于 1 和 255 (在 ANSI 版本中) 或 65535 (在 Unicode 版本中) 的数字). 如果 String 为空, 则返回 0.

Chr(Number): 返回与 Number 表示的字符编码相对应的单个字符. 如果 Number 不在有效的字符编码范围内, 则返回空字符串. 常用的字符编码包括 9 (tab), 10 (换行), 13 (回车), 32 (空格), 48-57 (数字 0-9), 65-90 (大写字母 A-Z) 和 97-122 (小写字母 a-z).

DllCall()：调用 DLL 文件中的函数，例如标准的 Windows API 函数。请参阅 DllCall() 了解详情。

FileOpen(): 提供面向对象的文件 I/O. 请参阅 FileOpen() 了解详情。

Func(FunctionName) [v1.1.00+]: 如果 FunctionName 没有显式出现在脚本中 (通过例如 #Include 或对 库函数 的非动态调用的方法), 则 Func() 返回 0. 否则, 它返回 到函数的引用. 这可以用来调用函数或获取类似参数的最小和最大数目的 信息.

GetKeyName(Key), GetKeyVK(Key), GetKeySC(Key) [v1.1.01+]: 获取按键的名称/文本, 虚拟按键码或扫描码. Key 可以为 VK 或 SC 码, 例如 "vkA2" 或 "sc01D", 以及两者的组合或键名. 例如, GetKeyName("vk1B") 和 GetKeyName("Esc") 都返回 "Escape", 而 GetKeyVK("Esc") 返回 27.

IsByRef(Var) [v1.1.01+]: 当 Var 为 ByRef 参数且调用者提供了变量时返回 1; 否则当 Var 为其他类型的变量时返回 0.

IsFunc(FunctionName) [v1.0.48+]: 如果 FunctionName 不是显式出现在脚本中 (通过例如 #Include 或对 库函数 的非动态调用的方法), 则 IsFunc() 返回 0. 否则它返回函数的强制参数个数加一的数字（例如 1 为函数可以不需要参数，2 为函数需要 1 个参数等等）。例如, 函数存在时 if IsFunc("MyFunc") 和 if IsFunc(VarContainingFunctionName) 语句为真, 否则为假. 在 v1.1.00+, FunctionName 为可以代替函数名的函数引用. 另请参阅: 动态函数调用, A_ThisFunc

IsLabel(LabelName)：如果 LabelName 为脚本中的子程序、热键或热字串（不包括 LabelName 中末尾的冒号），则返回非零数字。例如, 标签存在时 if IsLabel(VarContainingLabelName) 将为真, 否则为假. 在类似 Gosub, Hotkey, Menu 和 Gui 命令中指定动态标签时, 使用此函数可以避免运行时错误. 另请参阅: Labels.

IsObject() [AHK_L 31+]: 判断某个值是否为对象. 另请参阅: 对象.

ListView 和 TreeView 函数：请参阅 ListView 和 TreeView 页面了解详情。

NumGet(VarOrAddress [, Offset = 0][, Type = "UPtr"])：返回在指定地址+偏移的位置存储的二进制数。请参阅 NumGet 了解详情。

NumPut(Number, VarOrAddress [, Offset = 0][, Type = "UPtr"])：以二进制格式把数字存储到指定地址+偏移的位置。请参阅 NumPut 了解详情。

OnMessage(MsgNumber [, "FunctionName"]): 监视消息/事件. 请参阅 OnMessage() 了解详情.

StrGet(Address [, Length] [, Encoding = None ] ) [AHK_L 46+]: 从内存地址复制字符串, 并可以对其在不同代码页间进行转换. 请参阅 StrGet() 了解详情.

StrPut(String, Address [, Length] [, Encoding = None ] ) [AHK_L 46+]: 复制字符串到内存地址, 并可以对其在不同代码页间进行转换. 请参阅 StrPut() 了解详情.

RegisterCallback()：创建机器码地址，当它被调用时会重定向到脚本中的函数。请参阅 RegisterCallback() 了解详情。

Trim() [AHK_L 31+]：移除字符串的开始和/或末尾的某些字符。请参阅 Trim() 了解详情。

VarSetCapacity(UnquotedVarName [, RequestedCapacity, FillByte]): 增加或清空变量占用的内存. 请参阅 VarSetCapacity() 了解详情.

通用数学函数

注意: 如果某个传入参数为非数值时, 那么数学函数通常返回空值 (空字符串).

Abs(Number): 返回 Number 的绝对值. 返回值的类型与 Number 相同 (整数或浮点数).

Ceil(Number)：返回由 Number 向上取整到最近的整数（不带 .00 后缀）。例如，Ceil(1.2) 结果为 2 而 Ceil(-1.2) 结果为 -1。

Exp(N): 返回 e (其近似值为 2.71828182845905) 的 N 次幂. N 可以为负数, 也可以为小数. 要计算 e 以外的其他数的次幂, 请使用 ** 运算符.

Floor(Number): 返回由 Number 向下取整到最近的整数 (不带任何 .00 后缀). 例如, Floor(1.2) 的结果为 1 而 Floor(-1.2) 结果为 -2.

Log(Number): 返回 Number 的对数 (底数为 10). 结果格式化为 浮点数. 如果 Number 为负数, 则返回空字符串.

Ln(Number): 返回 Number 的自然对数 (底数为 e). 结果格式化为 浮点数. 如果 Number 为负数, 则返回空字符串.

Mod(Dividend, Divisor): 求模. 返回被除数 Dividend 除以除数 Divisor 后得到的余数. 结果的正负总是与被除数一致. 例如，mod(5, 3) 和 mod(5, -3) 的结果都为 2，但 mod(-5, 3) 和 mod(-5, -3) 的结果为 -2。如果其中一个参数为浮点数, 那么结果也是浮点数. 例如, mod(5.0, 3) 的结果为 2.0 而 mod(5, 3.5) 的结果为 1.5. 如果除数为零, 则函数返回空值 (空字符串).

Round(Number [, N]): 如果 N 省略或为 0, 则 Number 被取整到最近的整数. 如果 N 为正数, 则 Number 被取整到 N 个小数位. 如果 N 为负数，则 Number 被取整到十进制小数点左边 N 位。例如，Round(345, -1) 的结果为 350 而 Round (345, -2) 的结果为 300。与 Transform Round 不同, 每当 N 省略或小于 1 时结果不带 .000 后缀. 在 v1.0.44.01+，N 值大于零时会准确显示 N 个小数位而不遵循 SetFormat 的设置。要避免这种情况, 需要对 Round() 的返回值再进行一次数学运算; 例如: Round(3.333, 1)+0.

Sqrt(Number): 返回 Number 的平方根. 结果格式化为 浮点数. 如果 Number 为负数, 则函数返回空字值 (空字符串).

三角函数

Sin(Number) | Cos(Number) | Tan(Number)：分别返回 Number 的正弦、余弦或三角函数值。Number 必须用弧度表示.

ASin(Number): 返回弧度表示的反正弦值 (其正弦值为 Number). 如果 Number 小于 -1 或大于 1, 则函数返回空值 (空字符串).

ACos(Number): 返回弧度表示的反余弦值 (其余弦值为 Number). 如果 Number 小于 -1 或大于 1, 则函数返回空值 (空字符串).

ATan(Number)：返回弧度表示的反正切值（其正切值为 Number）。

注意: 要将弧度转换成角度, 请将其乘以 180/pi (约为 57.29578). 要将角度转换成弧度, 请将其乘以 pi/180 (约为 0.01745329252). pi 的值 (约为 3.141592653589793) 为 1 的反正切值的 4 倍.

其他函数

Polyethene 的命令函数：为每个有 OutputVar 的 AutoHotkey 命令提供了可调用的函数。可以通过 #Include 把这个库包含在任何脚本中.


调试功能

调试器客户端

通过 DBGp 可以支持调试功能，DGBp 是一种常见的支持多语言和调试器 UI 通信的调试器协议。请参阅交互式调试了解更多细节。在这个页面中列出了一些与 AutoHotkey 兼容的 UI 或“客户端”。

SciTE4AutoHotkey

SciTE4AutoHotkey 是一个免费的基于 SciTE 的 AutoHotkey 脚本编辑器. 除了 DBGp 支持, 它还为 AutoHotkey 提供了语法高亮, 调用提示, 参数信息和自动完成, 以及其他拥有的编辑特性和辅助工具.

调试功能包括:

  • 断点.
  • 运行, 逐语句/逐过程/跳出.
  • 查看调用堆栈.
  • 列出局部域和全局域中变量的名称和内容.
  • 在变量上悬停时显示其内容。
  • 检查或编辑变量的内容.
  • 查看对象的结构.

http://www.autohotkey.net/~fincs/SciTE4AutoHotkey_3/web/

XDebugClient

XDebugClient 是一个基于 .NET Framework 2.0 的简单开源前端 DBGp 客户端. XDebugClient 一起最初设计用于带 Xdebug 的 PHP，不过下面有一个自定义版本可用于 AutoHotkey 中。

改变:

  • 允许调试器引擎报告 "php" 外的其他语言.
  • 添加 AutoHotkey 语法高亮.
  • 自动监听调试器引擎的连接, 而不需要等待用户点击 开始监听.
  • 截去属性值中首个空字符及其后面的内容，因为当前 AutoHotkey 返回整个变量的内容而 XDebugClient 无法正确显示二进制内容。

下载: 二进制; 源代码 (另请参阅 SharpDevelop, Dockpanel Suite 和 Advanced Treeview.)

用法:

  • 运行 XDebugClient.
  • 运行 AutoHotkey /Debug。XDebugClient 会自动打开脚本文件.
  • 在左边距点击以至少设置一个断点.
  • 在调试菜单中选择运行或按下 F5.
  • 执行到断点时, 使用调试菜单或快捷键进行单步调试或继续执行脚本.

特性:

  • 源码语法高亮只读显示.
  • 断点.
  • 运行, 逐语句/逐过程/跳出.
  • 查看调用堆栈.
  • 检查变量 - 选择变量名, 右键点击, 检查.

已知问题:

  • 当脚本运行时用户界面不响应用户的输入.
  • 没有提供列出变量或设置变量值的结构.

Notepad++ DBGp 插件

一个可作为 Notepad++ 插件使用的 DBGp 客户端. 它设计用于 PHP，不过用于 AutoHotkey 时同样工作地很好。

下载：请参阅 Notepad++ 插件目录。

用法:

  • 运行 Notepad++.
  • 通过 插件, DBGp, 配置... 配置 DBGp 插件

    注意: 必须配置文件映射. 大多数用户不进行远程调试, 因此可以简单地复选 忽略所有映射 (本地 windows 安装).

  • 通过工具栏或 插件, DBGp, 调试器 显示调试器面板.
  • 打开需调试的脚本文件.
  • 至少设置一个断点.
  • 运行 AutoHotkey /Debug。
  • 使用调试器工具栏或快捷键控制调试器.

特性:

  • 根据用户的配置进行语法高亮显示.
  • 断点.
  • 运行, 逐语句/逐过程/跳出, 运行到光标, 停止.
  • 查看局部/全局变量.
  • 监视用户指定的变量.
  • 查看调用堆栈.
  • 悬停在变量上时显示其内容.
  • 可配置的快捷键 - 设置, 快捷映射..., 插件命令.

已知问题:

  • 悬停在单字母的变量名上时不会显示变量内容 - 例如, 悬停在 "a" 将试图获取 " a" 或 "a " 变量的内容.
  • 悬停在文本上将试图把文本作为变量名获取其内容, 即使文本中含有非法字符.
  • 如果属性获取失败 Notepad++ 会变得不稳定, 在上述问题的来源中这是显著的问题. 为了避过此问题，AutoHotkey 接到获取一个不存在或非法变量的请求时发送一个空属性而不是错误码。

基于脚本的客户端

可用于开发中的一个基于脚本的 DBGp 库 和两个基本的客户端:

  • dbgp_console.ahk: 简单的命令行客户端.
  • dbgp_test.ahk: 演示异步调试.

命令行客户端

xdebug.org 上有一个可用的命令行客户端, 然而它不适合大多数用户, 因为需要深入理解 DBGp (协议) 才能使用它.

其他

还有一些可用的其他 DBGp 客户端，不过没有在 AutoHotkey 测试过。关于这些客户端的列表，请参阅 Xdebug：文档。


对象

AutoHotkey 中的 对象 是一种抽象数据结构, 它提供三个基本功能:

  • 取值.
  • 设置值.
  • 调用方法 (即可以对目标对象进行某些操作的函数).

对象 引用 是指向特殊对象的指针或 "句柄". 和字符串和数字一样, 对象引用可以存储到变量中, 传递给函数或从函数返回以及保存到对象中. 在从一个变量复制引用到另一个后, 例如 x := y , 两个变量都引用相同的对象.

IsObject 可以用来确定一个值是否为对象:

Result := IsObject(expression)

对象类型包括:

  • 对象 - 脚本化关联数组.
  • 文件 - 为文件输入/输出提供接口.
  • Func - 函数.
  • ComObject - 打包 IDispatch 接口 (COM 或 "自动化" 对象).

目录

  • 基本用法 - 简单数组, 关联数组, 对象, 释放对象, 备注
  • 扩展用法 - 函数引用, 数组嵌套, 函数数组
  • 自定义对象 - 原型, 类, 创建和销毁, 元函数
  • 默认基对象 - 自动初始化变量, 伪属性, 调试
  • 实现 - 引用计数, 指向对象的指针

基本用法

简单数组

创建数组:

Array := [Item1, Item2, ..., ItemN]
Array := Array(Item1, Item2, ..., ItemN)

获取项:

Value := Array[Index]

对项进行赋值:

Array[Index] := Value

附加项:

Array.Insert(Value)

在指定的索引插入一项或多项:

Array.Insert(Index, Value, Value2, ...)

移除项:

RemovedValue := Array.Remove(Index)

如果数组不是空的, 那么 MinIndex 和 MaxIndex 分别返回数组中当前使用的最小和最大的索引. 由于最小的索引几乎总是 1, 所以 MaxIndex 经常返回项目数. 对数组内容进行依次循环可以通过索引或 For 循环实现. 例如：

array := ["one", "two", "three"]

; 从 1 到项目数进行重复:
Loop % array.MaxIndex()
    MsgBox % array[A_Index]

; 枚举数组内容:
For index, value in array
    MsgBox % "Item " index " is '" value "'"

关联数组

关联数组是包含唯一键集合和值集合的对象, 其中每个键和一个值关联. 键可以为字符串, 整数或对象, 而值可以为任何类型. 关联数组可以用如下方法创建:

Array := {KeyA: ValueA, KeyB: ValueB, ..., KeyZ: ValueZ}
Array := Object("KeyA", ValueA, "KeyB", ValueB, ..., "KeyZ", ValueZ)

使用 {key:value} 表示法时, 对于仅由单词字符组成的键, 其两边的引号标记是可选的. 可以使用任何表达式作为键, 但使用变量作为键时, 它必须包围在小括号中. 例如, {(KeyVar): Value} 和 {GetKey(): Value} 都是合法的.

获取项:

Value := Array[Key]

对项进行赋值:

Array[Key] := Value

移除项:

RemovedValue := Array.Remove(Key)

枚举项:

array := {ten: 10, twenty: 20, thirty: 30}
For key, value in array
    MsgBox %key% = %value%

关联数组可以是稀疏分布的 - 即 {1:"a",1000:"b"} 仅包含两个键值对, 而不是 1000.

到现在, 您也许已经注意到关联数组使用与简单数组非常相似的语法. 事实上, 在 v1.x 中它们是相同的东西. 然而, 把 [] 视为简单线性数组有助于保持其作用清晰, 并且改善您脚本与 AutoHotkey 未来版本的兼容性, 未来版本中可能改变实现方式.

对象

获取属性:

Value := Object.Property

设置属性:

Object.Property := Value

调用方法:

ReturnValue := Object.Method(Parameters)

使用可推算的方法名调用方法:

ReturnValue := Object[MethodName](Parameters)

COM 对象和用户定义对象的一些属性可以接受参数:

Value := Object.Property[Parameters]
Object.Property[Parameters] := Value

相关: 对象, 文件对象, Func 对象, COM 对象

已知限制:

  • 当前 x.y[z]() 会被视为 x["y", z](), 这是不受支持的. 作为一种变通方法, (x.y)[z]() 首先计算 x.y, 然后把结果作为方法调用的目标. 请注意 x.y[z].() 没有这个限制, 因为对它求值的方式和 (x.y[z]).() 一样.

释放对象

脚本不会显式的释放对象。当到对象的最后一个引用被释放时，会自动释放这个对象。当某个保存引用的变量被赋为其他值时，会自动释放它原来保存的引用。例如：

obj := {}  ; 创建对象。
obj := ""  ; 释放最后一个引用，因此释放对象。

同样地，当另一个对象的某个字段被赋为其他值或从对象中移除时，保存在这个字段中的引用会被释放。这同样适用于数组，因为它是真正的对象。

arr := [{}]  ; 创建包含对象的数组。
arr[1] := {}  ; 再创建一个对象，隐式释放第一个对象。
arr.Remove(1)  ; 移除并释放第二个对象。

由于在释放一个对象时，到这个对象的所有引用都必须被释放，所以包含循环引用的对象无法被自动释放。例如，如果 x.child 引用 y 且 y.parent 引用了 x，则清除 x 和 y 是不够的，因为父对象仍然包含到这个子对象的引用，反之亦然。要避免此问题，请首先移除循环引用。

x := {}, y := {}             ; 创建两个对象。
x.child := y, y.parent := x  ; 创建循环引用。

y.parent := ""               ; 在释放对象前必须移除循环引用。
x := "", y := ""             ; 如果没有上一行，则此行无法释放对象。

想了解更多高级用法和细节，请参阅引用计数。

备注

语法

对于所有类型的对象都支持数组语法 (方括号) 和对象语法 (句点).

同时, 对象引用自身也可以用在表达式中:

  • 当对象引用使用 = == != <> 中的一种比较运算符和其他值比较时, 仅在两个值都为指向相同对象的引用时它们才被视为相等的.
  • 进行逻辑运算时对象总是被视为 true, 例如在 if obj, !obj 或 obj ? x : y 中.
  • 使用 & 取址运算符可以获取对象的地址. 它从此对象创建时到此对象的最后一个引用被 释放 期间唯一标识此对象.

如果在不期望对象的地方使用对象, 那么它被视为空字符串. 例如, MsgBox %object% 显示空的 MsgBox 且 object + 1 产生空字符串. 由于这种特性可能会变化, 所以不要依赖它.

当方法调用紧接着赋值运算符, 那么它等同于用参数来设置属性. 例如, 下面的方式是等同的:

obj.item(x) := y
obj.item[x] := y

还支持复合赋值例如 x.y += 1 和 --arr[1].

键

对于哪种值可以在通过 [], {} 或 new 运算符创建的对象中作为键使用的一些限制:

  • 整数键使用本机有符号整数类型存储. AutoHotkey 32 位支持使用从 -2147483648 到 2147483647 范围内的整数作为键. AutoHotkey 支持 64 位整数, 但仅 AutoHotkey 64 位版本才支持完整范围的整数在对象中作为键使用.
  • 由上面这点可知, 整数值的字符串格式不会被保留. 例如, x[0x10], x[16] 和 x[00016] 都是等同的. 这点同样适用于不含小数点的数值型字符串.
  • 用引号括起来的原义字符串在 v1.x 中被视为纯非数值型, 所以 x[1] 和 x["1"] 是 不 等同的. 同时, 如果原义字符串和另一个值串联在一起 (如同在 "0x" x), 结果被视为纯非数值型. 不过, 这不适用于变量, 所以 x[1] 和 x[y:="1"] 是等同的. 此问题将在 v2 中解决, 所以脚本应避免使用用引号括起来的原义字符串作为键.
  • 不支持使用浮点数作为键 - 而是把它们转换成字符串. 在 v1.x 中, 浮点数文字保留它们原始的格式, 而纯浮点数 (例如 0+1.0 或 Sqrt(y) 的结果) 被强制转换成当前的 浮点格式. 考虑到一致和清晰, 脚本中应避免使用浮点文字作为键.
  • 字符串键 "base" 没有和 Insert 一起使用时具有特殊含义.

扩展用法

函数引用 [v1.1.00+]

如果变量 func 包含一个函数名, 此函数可以通过两种方式进行调用: %func%() 或 func.(). 然而，由于前者每次都需要解析函数名，所以多次调用时效率低下。为了改善性能, 脚本可以获取到函数的引用并保存以供后面使用:

Func := Func("MyFunc")

通过引用调用函数时, 必须使用下面的语法:

RetVal := Func.(Params)

有关函数引用的附加属性的详细信息，请参阅 Func 对象。

已知限制:

  • 在 v1.1.07.00 已修复: 如果它所调用的函数或子程序中使用了 Exit, 它表现的如同函数调用创建了新线程. 即它立即返回到函数的调用者而不会终止当前线程. 但是, 如果脚本不是 持续运行的, 那么它仍会使脚本终止.

数组嵌套

在 AutoHotkey 中可以通过透明地把数组存储到其他数组中来支持“多维”数组。例如, 表格可以表示为行数组, 这里每个行自身是一个列数组. 此时, x 行 y 列的内容可以用以下两种方法的其中一个进行设置:

table[x][y] := content  ; A
table[x, y] := content  ; B

如果 table[x] 不存在, A 和 B 在两个方面有区别:

  • A 失败而 B 会自动创建一个对象并把它存储到 table[x] 中.
  • 如果 table 的 base 定义了 元函数, 可以用如下方式调用它们:
    table.base.__Get(table, x)[y] := content   ; A
table.base.__Set(table, x, y, content)     ; B
    因此, B 可以让对象为全面赋值定义定制的行为.

类似 table[a, b, c, d] := value 这样的多维赋值按以下方式处理：

  • 如果仅剩一个键，则执行赋值操作并返回。在其他情况时：
  • 在对象中查找列表中的首个键。
  • 如果找到非对象值，则失败。
  • 如果没有找到对象，则创建一个并保存。
  • 重复调用子对象，从顶部开始把剩下的键和值传递过去。

这种行为仅适用于由脚本创建的对象, 而不适合特殊的对象类型例如 COM 对象或 COM 数组.

函数数组

函数数组是包含函数名或引用的简单数组. 例如：

array := [Func("FirstFunc"), Func("SecondFunc")]

; 调用每个函数, 传递 "foo" 参数:
Loop 2
    array[A_Index].("foo")

; 调用每个函数, 隐式地把数组自己作为参数传递:
Loop 2
    array[A_Index]()

FirstFunc(param) {
    MsgBox % A_ThisFunc ": " (IsObject(param) ? "object" : param)
}
SecondFunc(param) {
    MsgBox % A_ThisFunc ": " (IsObject(param) ? "object" : param)
}

为了向后兼容，如果array[A_Index]含有函数名而非函数引用时，在第二种形式中array将不会作为参数被传递。但是, 如果 array[A_Index] 继承 自 array.base[A_Index], 那么 array 将作为参数被传递.

自定义对象

AutoHotkey 中的对象是基于原型而不是基于类. 即对象可以从其原型或 base 对象中继承属性和方法, 但不需要有预定义结构. 在任何时候, 属性和方法还可以添加到 (或从中移除) 一个对象或它所派生自的任何对象. 不过, AutoHotkey 通过把 类定义 转化为普通对象来模仿类. 有关更多复杂或特殊解决方法, 通过定义 元函数 基对象可以覆盖标准行为.

要从其他对象继承创建对象, 脚本可以赋值 base 或使用 new 关键字:

baseObject := {foo: "bar"}
obj1 := Object(), obj1.base := baseObject
obj2 := {base: baseObject}
obj3 := new baseObject
MsgBox % obj1.foo " " obj2.foo " " obj3.foo

原型

原型或 base 对象和其他任何对象一样创建和操作. 例如, 带有单属性和单方法的普通对象可以这样创建:

; 创建对象.
thing := {}
; 存储值.
thing.foo := "bar"
; 通过存储函数引用创建方法.
thing.test := Func("thing_test")
; 调用方法.
thing.test()

thing_test(this) {
   MsgBox % this.foo
}

调用 thing.test() 时, thing 会自动被插入到参数列表的开始处. 然而, 为了能够向后兼容, 通过名称 (而不是通过引用) 把函数直接保存到对象中 (而不是继承自基对象) 时这种情况不会发生. 按照约定, 通过结合对象 "类型" 和方法名来命名函数.

如果另一个对象继承自某个对象，那么这个对象被称为原型或基：

other := {}
other.base := thing
other.test()

此时, other 从 thing 继承了 foo 和 test. 这种继承是动态的, 所以如果 thing.foo 被改变了, 这改变也会由 other.foo 表现出来. 如果脚本赋值给 other.foo, 值存储到 other 中并且之后对 thing.foo 任何改变都不会影响 other.foo. 调用 other.test() 时, 它 这里的 参数包含到 other 而不是 thing 的引用.

类 [v1.1.00+]

为了简便，可以使用“class”关键字创建基对象。基类定义看起来类似这样：

class ClassName extends BaseClassName
{
    InstanceVar := Expression
    static ClassVar := Expression

    class NestedClass
    {
        ...
    }

    Method()
    {
        ...
    }
}

在加载脚本时, 这里会创建对象并将其存储到全局 (而在 v1.1.05+, 超级全局) 变量 ClassName. 在 v1.1.05 之前, 要在函数中引用这个类, 如果函数不处于 假设全局模式, 那么需要进行声明, 例如 global ClassName. 如果存在 extends BaseClassName，那么 BaseClassName 必须为另一个类的完整名称（从 v1.1.11 开始，对于早期的版本它们所定义的无关紧要）。每个类的完整名称存储在 object.__Class.

类定义可以包含变量声明, 方法定义和内嵌的类定义.

    InstanceVar := Expression

实例变量 声明 [v1.1.01+] 在每次使用 new 关键字创建类的新实例时都进行求值. 在调用 __New() 方法之前对所有这样的声明进行求值，包括在基类中定义的那些。表达式 可以通过 this 访问其他实例变量和方法, 但其他所有的变量引用都假定为全局的. 要访问实例变量, 总是要指定目标对象; 例如, this.InstanceVar.

    static ClassVar := Expression

类变量 声明 [v1.1.00.01+] 仅在 自动执行段 之前根据它们在脚本中出现的顺序被求值一次. 每个声明保存值到类对象中. 如同类对象包含的任何值或方法, 这个值可以被派生对象继承. 表达式 中的任何变量引用都假定为全局的. 要访问类变量, 总是要指定类或或派生对象; 例如, ClassName.ClassVar.

    class NestedClass
    {
        ...
    }

嵌套类 定义允许类对象存储到另一个类对象中而不作为单独的全局变量. 在上面的例子中, class NestedClass 创建了一个对象并把它保存到 ClassName.NestedClass. 因此, NestedClass 可以被派生自 ClassName 的任何类或对象继承.

    Method()
    {
        ...
    }

方法 定义看起来和函数定义相同. 每个方法都有一个名称为 this 的隐藏参数, 它实际上包含了指向继承自此类的对象的引用. 不过, 它也可以包含指向此类自身或派生类的引用, 取决于如何调用这个方法. 方法被 通过引用 存储到类对象中.

除了隐藏参数 this, 方法定义中还可以使用伪关键字 base 以调用包含了此方法定义的类的基类. 例如, 在上面的方法中 base.Method() 相当于 BaseClassName.Method.(this). 注意它与this.base.base.Method()在其他两方面有区别：

  • 它总是调用当前类的基, 即使 this 继承自当前类的 子类.
  • 它自动传递 this, 而不是 this.base.base.

base 仅在后面跟着点 . 或方括号 [] 时才有特殊含义, 所以像 obj := base, obj.Method() 这样的代码将不起作用. 通过把base赋为非空值可以禁用它的特殊行为，但是不建议这样做。因为变量 base 必须为空, 所以如果脚本中不含有 #NoEnv 指令那么性能可能会降低.

创建和销毁

每当使用 new 关键字 [需要 v1.1.00+] 创建派生对象时, 那么调用由其基对象定义的 __New 方法. 此方法可以接受参数, 初始化对象并通过返回值覆盖 new 运算符的结果. 销毁对象时, 则调用 __Delete. 例如：

m1 := new GMem(0, 20)
m2 := {base: GMem}.__New(0, 30)

class GMem
{
    __New(aFlags, aSize)
    {
        this.ptr := DllCall("GlobalAlloc", "uint", aFlags, "ptr", aSize, "ptr")
        if !this.ptr
            return ""
        MsgBox % "New GMem of " aSize " bytes at address " this.ptr "."
        return this  ; 使用“new”运算符时可以省略此行。
    }

    __Delete()
    {
        MsgBox % "Delete GMem at address " this.ptr "."
        DllCall("GlobalFree", "ptr", this.ptr)
    }
}

元函数

方法语法：
class ClassName {
    __Get([Key, Key2, ...])
    __Set([Key, Key2, ...], Value)
    __Call(Name [, Params...])
}

函数语法：
MyGet(this [, Key, Key2, ...])
MySet(this [, Key, Key2, ...], Value)
MyCall(this, Name [, Params...])

ClassName := { __Get: Func("MyGet"), __Set: Func("MySet"), __Call: Func("MyCall") }

元函数是由对象的基定义的方法, 这里可以明确定义在接受未知键的请求时对象应如何处理. 例如, 如果 obj.key 尚未赋值, 那么它会调用 __Get 元函数. 同样地, obj.key := value 调用 __Set 而 obj.key() 调用 __Call.

在这些情况中, 按如下方式调用基对象:

  • 如果此基对象定义了相应的元函数, 那么调用它. 如果元函数明确 return, 那么把返回值作为运算的结果且不进行进一步的处理.

    Set：如果运算成功，__Set应该返回这个字段的新值，这可能与原始的r值不同。这样允许赋值链, 例如 a.x := b.y := z. 如果赋值失败那么应该返回空字符串, 这样脚本可以检测到发生了错误.

  • 如果是 get 或 call 运算, 那么在基对象自身的字段中搜索匹配的键.

    Get: 如果找到, 那么返回这个字段的值.
    Call: 如果找到, 那么 (通过名称或 引用) 调用保存在这个字段中的函数, 并把原始目标对象作为 this 参数传递过去.

  • 递归调用其自己的基对象. 这样就可以从其基对象, 基对象的基等 "继承" 对象的属性.

当 (且仅当) 没有基对象处理运算时, 处理照常进行:

  • Get: 如果此键为 "base", 那么获取对象的基.
  • Set: 如果此键为 "base", 那么设置对象的基; 非对象的值会移除现有的基.

    否则创建一个新键值对并存储到对象中.

  • Call: 调用 内置方法.

已知限制:

  • 使用不带值的 return 等同于 return "". 这种情况可能在未来的版本中改变, 所以可以使用 return 来从元函数 "退出" 而不覆盖默认行为.
  • 请参阅 Exit 限制。

动态属性

__Get 和 __Set 可以用来实现在某些情况下可以计算或限制的值的属性. 例如, 可以用来实现含 R, G, B 和 RGB 属性的 "Color" 对象, 这里只有 RGB 值是实际存储的:

red  := new Color(0xff0000), red.R -= 5
cyan := new Color(0x00ffff)

MsgBox % "red: " red.R "," red.G "," red.B " = " red.RGB
MsgBox % "cyan: " cyan.R "," cyan.G "," cyan.B " = " cyan.RGB

class Color
{
    __New(aRGB)
    {
        this.RGB := aRGB
    }

    __Get(aName)
    {
        if (aName = "R")
            return (this.RGB >> 16) & 255
        if (aName = "G")
            return (this.RGB >> 8) & 255
        if (aName = "B")
            return this.RGB & 255
    }

    __Set(aName, aValue)
    {
        if aName in R,G,B
        {
            aValue &= 255

            if      (aName = "R")
                this.RGB := (aValue << 16) | (this.RGB & ~0xff0000)
            else if (aName = "G")
                this.RGB := (aValue << 8)  | (this.RGB & ~0x00ff00)
            else  ; (aName = "B")
                this.RGB :=  aValue        | (this.RGB & ~0x0000ff)

            ; 必须使用 'Return' 表示不应该创建一个新键值对.
            ; 这里也定义了在 'x := clr[name] := val' 中将要存储到 'x' 中的内容:
            return aValue
        }
    }
}

对象函数化

生成一个调用（例如obj.func(param)）时，obj.func可以包含函数名或对象。如果obj.func包含对象，则可以用obj代替方法名调用此对象，像在(obj.func)[obj]()那样。在大多数情况下obj.func[obj]不存在，作为替代而调用obj.func的__Call 元函数。这可以用来以一种抽象的方式改变函数调用的行为, 如以下示例所示:

; 为函数数组创建原型.
FuncArrayType := {__Call: "FuncType_Call"}
; 创建函数数组.
funcArray := {1: "One", 2: "Two", base: FuncArrayType}
; 把此数组作为方法创建对象.
obj := {func: funcArray}
; 调用方法.
obj.func("foo", "bar")

FuncType_Call(func, obj, params*)
{
    ; 调用函数列表.
    Loop % ObjMaxIndex(func)
        func[A_Index](params*)
}

One(param1, param2) {
    ListVars
    Pause
}
Two(param1, param2) {
    ListVars
    Pause
}

把这种技术和类定义组合在一起为定义类似于前面部分的动态属性提供了便利的方法:

blue := new Color(0x0000ff)
MsgBox % blue.R "," blue.G "," blue.B

class Properties
{
    __Call(aTarget, aName, aParams*)
    {
        ; 如果 this 属性对象包含此半属性的定义, 那么调用它.
        ; 小心别使用 this.HasKey(aName), 因为这样会递归进 __Call.
        if IsObject(aTarget) && ObjHasKey(this, aName)
            return this[aName].(aTarget, aParams*)
    }
}

class Color
{
    __New(aRGB)
    {
        this.RGB := aRGB
    }

    class __Get extends Properties
    {
        R() {
            return (this.RGB >> 16) & 255
        }
        G() {
            return (this.RGB >> 8) & 255
        }
        B() {
            return this.RGB & 255
        }
    }

    ;...
}

子类化数组嵌套

在 多参数赋值 例如 table[x, y] := content 会隐式地创建一个新对象, 这个新对象一般不含基, 因此没有自定义方法或特殊行为. __Set 可以用来初始化这样的对象, 如下所示.

x := {base: {addr: Func("x_Addr"), __Set: Func("x_Setter")}}

; 赋值, 隐式调用 x_Setter 来创建子对象.
x[1,2,3] := "..."

; 获取值并调用示例方法.
MsgBox % x[1,2,3] "`n" x.addr() "`n" x[1].addr() "`n" x[1,2].addr()

x_Setter(x, p1, p2, p3) {
    x[p1] := new x.base
}

x_Addr(x) {
    return &x
}

由于 x_Setter 含有四个必需参数, 所以只有在有两个或更多键参数时才会调用它. 当上面的赋值出现时, 会发生下面的情况:

  • x[1] 不存在, 所以调用 x_Setter(x,1,2,3) (由于参数过少所以 "..." 不会被传递).
    • x[1] 被赋值为与 x 含有相同基的新对象.
    • 不返回任何值 – 赋值继续.
  • x[1][2] 不存在, 所以调用 x_Setter(x[1],2,3,"...").
    • x[1][2] 被赋值为与 x[1] 含有相同基的新对象.
    • 不返回任何值 – 赋值继续.
  • x[1][2][3] 不存在, 但由于 x_Setter 需要四个参数而这里只有三个 (x[1][2], 3, "..."), 所以不会调用它且赋值正常完成.

默认基对象

当非对象值用于对象语法时, 则调用 默认基对象. 这可以用于调试或为字符串, 数字和/或变量定义全局的类对象行为. 默认基可以使用带任何非对象值的 .base 进行访问; 例如, "".base. 尽管默认基无法像 "".base := Object() 这样进行 set, 不过它可以有自己的基如同在 "".base.base := Object() 中那样.

自动初始化变量

当使用空变量作为 set 运算的目标时, 它直接被传递给 __Set 元函数, 这样它就有机会插入新对象到变量中. 为简洁起见, 此示例不支持多个参数; 如果需要, 可以使用 可变参数函数 实现.

"".base.__Set := Func("Default_Set_AutomaticVarInit")

empty_var.foo := "bar"
MsgBox % empty_var.foo

Default_Set_AutomaticVarInit(ByRef var, key, value)
{
    if (var = "")
        var := Object(key, value)
}

伪属性

对象 "语法糖" 可以适用于字符串和数字.

"".base.__Get := Func("Default_Get_PseudoProperty")
"".base.is    := Func("Default_is")

MsgBox % A_AhkPath.length " == " StrLen(A_AhkPath)
MsgBox % A_AhkPath.length.is("integer")

Default_Get_PseudoProperty(nonobj, key)
{
    if (key = "length")
        return StrLen(nonobj)
}

Default_is(nonobj, type)
{
    if nonobj is %type%
        return true
    return false
}

注意也可以使用内置函数, 不过这时不能省略大括号:

"".base.length := Func("StrLen")
MsgBox % A_AhkPath.length() " == " StrLen(A_AhkPath)

调试

如果不希望把一个值视为对象, 每当调用非对象值可以显示警告:

"".base.__Get := "".base.__Set := "".base.__Call := Func("Default__Warn")

empty_var.foo := "bar"
x := (1 + 1).is("integer")

Default__Warn(nonobj, p1="", p2="", p3="", p4="")
{
    ListLines
    MsgBox A non-object value was improperly invoked.`n`nSpecifically: %nonobj%
}

实现

引用计数

当脚本不再引用对象时, AutoHotkey 使用基本引用计数结构来自动释放对象使用的资源. 脚本作者不应该明确调用此结构, 除非在直接处理指向对象的未托管指针时. 想了解更多细节，请参阅 ObjAddRef。

; 增加对象的引用数以 "使其保持活跃":
ObjAddRef(address)
...
; 减少对象的引用数, 这样可以释放它:
ObjRelease(address)

然而, 最初通过 Object(obj) 获取地址时不需要使用 ObjAddRef.

通常每个新的对象地址副本都应被视为对象引用, 除非脚本会负责在适当时调用 ObjAddRef 和/或 ObjRelease. 例如, 每当通过类似 x := address 这样的方式复制地址时, 应调用 ObjAddRef 来增加引用数. 同样地, 每当含对象地址特殊副本的脚本结束时, 它应该调用 ObjRelease. 这样确保了当指向对象的最后一个引用失去时对象被释放 - 而不是在这之前.

要在指向对象的最后一个引用被释放时运行代码, 实现 __Delete 元函数.

已知限制:

  • 在释放对象前必须断开循环引用. 想了解细节和查看示例，请参阅释放对象。
  • 尽管在程序退出时静态和全局变量中的引用会自动释放, 但在非静态局部变量或表达式求值堆栈中的引用则不会. 只有让函数或表达式正常结束这些引用才会释放.

尽管当程序退出时操作系统会回收对象所使用的内存, 但只有在指向对象的所有引用都释放时才会调用 __Delete. 这样释放了不会由操作系统自动回收的其他资源, 例如临时文件, 所以这很重要.

指向对象的指针

在一些罕见的情况中, 可能需要通过 DllCall 传递对象到外部代码或把它存储到二进制数据结构以供以后取回. 通过 x := &obj 可以获取对象的地址; 然而, 如果变量 obj 被清除, 此对象可能被过早释放. 为确保不发生这样的情况, 按上面演示那样使用 ObjAddRef 或按下面演示那样使用 Object():

address := Object(object)

此外, 还可以使用此函数把地址转换回引用:

object := Object(address)

在这两种情况中, 对象的 引用数 都会自动增加, 这样对象不会被过早释放.

注意此函数同样适用于不是由 Object() 创建的对象, 例如 COM 对象包装器 或 文件对象.


对象

所有由 Object() 或 {} 创建的对象的内置方法都可以作为正常的函数或方法访问:

result := obj.Method(params)

这种调用方法方式允许每个对象为此方法实现自身的行为。但是，如果一个对象覆盖了内置方法，那么通常需要一种方式访问原始的功能。可以使用函数形式进行访问:

result := ObjMethod(obj, params)

因为函数名称在加载时解析, 所以直接调用函数会执行地稍快些, 但语法往往不够直观. 对象实现的任何自定义行为都会被忽略, 所以这些函数一般应该仅对象自身使用.

Insert [AHK_L 31+]

插入键值对到对象中, 在合适时自动调整现有的键.

Object.Insert(Index, Value1 [, Value2, ... ValueN ])
Object.Insert(Value)
Object.Insert(Key, Value)
Index | 表示 Value1 插入位置的整数键. 后续的值插入到 Index+1, Index+2, 等等. 如果省略, 默认为 MaxIndex()="" ? 1 : MaxIndex() + 1.
键 | 字符串或目标键. 如果键已经存在, 那么会改写它的值.
值 | 字符串, 数字或对象.
返回值 | 成功时返回 true, 而脚本内存不足时返回空字符串.

备注

注意此方法绕过 __Set 结构和 base 键的特殊行为。例如, Object.Insert("base","") 会使得 Object.base 返回空字符串而不是真正的基础对象, 但这样不会阻止触发对象元函数的其他操作.

Remove [AHK_L 31+]

从对象中移除键值对.

Object.Remove(FirstKey, LastKey)
FirstKey, LastKey | 需移除的整数或字符串键的范围. 如果两个键都是整数, 则任何大于 LastKey 的整数键通过减去 (LastKey - FirstKey + 1) 来模仿典型的基于数值索引的数组. 两个键必须为相同的类型 (整数或字符串).
返回值 | 成功时返回被移除的实际键值对数目, 没有找到键则为零, 而失败时为空字符串.
Object.Remove(Key = MaxIndex())
键 | 任何有效键. 如果省略, 默认为现有的最大整数键; 如果不存在, 则什么都不移除. 调整现有的键就像使用 Remove(Key,Key) 一样.
返回值 | 被移除的值（如果有），否则为空字符串。
Object.Remove(IntKey, "")

[AHK_L 61+]: 移除整数键并返回它的值, 但不影响其他整数键.

MinIndex / MaxIndex [AHK_L 31+]

MinIndex := Object.MinIndex()
MaxIndex := Object.MaxIndex()

如果存在整数键, 则 MinIndex 返回最小的那个而 MaxIndex 返回最大的那个. 否则返回空字符串.

SetCapacity [AHK_L 31+]

调整对象或其一个区域占用的内存空间.

Object.SetCapacity(MaxItems)
Object.SetCapacity(Key, ByteSize)
MaxItems | 对象在必须自动扩展前它可以包含的键值对的最大数目. 如果小于当前键值对的数目, 则缩小对象以匹配.
键 | 任何有效键.
ByteSize | 为目标区域字符串缓存设置的新大小, 不包括空终止符, 单位为字节. 如果区域不存在, 则创建它. 如果 ByteSize 为零, 则清空缓存但不移除空区域. 如果 ByteSize 小于当前大小, 则移除额外的数据; 否则保留所有现有的数据.
返回值 | 成功时返回新设置的内存空间, 否则为空字符串.

GetCapacity [AHK_L 31+]

MaxItems := Object.GetCapacity()
ByteSize := Object.GetCapacity(Key)

返回对象或其一个区域当前占用的内存空间.

GetAddress [AHK_L 31+]

Ptr := Object.GetAddress(Key)

返回区域字符串的缓存的当前地址，如果它含有。

NewEnum [AHK_L 49+]

Enum := Object._NewEnum()

返回枚举此对象的键值对的新的 枚举数.

HasKey [AHK_L 53+]

Object.HasKey(Key)

如果与 Key 关联的值 (即使为 "") 在 Object 中则返回真, 否则为假.

Clone [AHK_L 60+]

Clone := Object.Clone()

返回对象的阴影副本.


枚举数

枚举数对象 [AHK_L 49+]

可以枚举容器中的项目.

Next

检索下一个项目或枚举中的项目.

Enum.Next(OutputVar1 [, OutputVar2, ...])
OutputVar1, OutputVar2 | 接收特定于实现的值.
... | 附加参数, 如果支持.
返回值 | 成功时返回非零整数, 如果没有剩余项目则返回零, 而参数不正确则返回空字符串.

对象

由 ObjNewEnum() 返回的计数器为每个键值对调用一次, 最多允许两个参数:

OutputVar1 | 键值对中的 键.
OutputVar2 | 接收与 OutputVar1 关联的 值。

返回的键值对是以实现定义的顺序. 即, 它们一般不是以在定义时的相同顺序返回. 现有的键值对可以在枚举时修改, 但插入或移除键可能使得一些项目被多次枚举或一次都不枚举.

相关

For 循环, Object.NewEnum()

示例

; 创建一些样本数据.
obj := Object("red", 0xFF0000, "blue", 0x0000FF, "green", 0x00FF00)

; 进行枚举!
enum := obj._NewEnum()
While enum[k, v]
    t .= k "=" v "`n"
MsgBox % t

; AHK_L 59+
For k, v in obj
    s .= k "=" v "`n"
MsgBox % s


File 对象

File对象 [AHK_L 42+]

提供文件输入/输出的接口. FileOpen 返回文件类型的对象.

Read

从文件读取字符串并使文件指针向前移动.

String := File.Read([Characters])
Characters | 需读取的最大字符数. 如果省略, 则读取文件的剩余部分并作为单个字符串返回. 如果 File 对象创建于非搜寻设备（例如控制台缓冲区或管道）的句柄，省略此参数可能引起执行方法失败或仅返回当前可用的数据。
返回值 | 字符串.

Write

写入字符串到文件并使文件指针向前移动.

File.Write(String)
String | 字符串.
返回值 | 写入的字节数 (不是字符数).

ReadLine

从文件中读取一行文本并使文件指针向前移动.

Line := File.ReadLine()
返回值 一行文本. 其中可能包括 `n, `r`n 或 `r, 取决于文件和打开文件时使用的 EOL 标志.

WriteLine

写入字符串后面跟着 `n 或 `r`n, 取决于打开文件时使用的标志. 使文件指针向前移动.

File.WriteLine([String])
String | 可选的字符串.
返回值 | 写入的字节数 (不是字符数).

ReadNum

从文件中读取指定类型的数据并使文件指针向前移动。

Num := File.ReadNumType()
NumType | 指定下列各项的其中一个直接作为函数名称的一部分: UInt, Int, Int64, Short, UShort, Char, UChar, Double 或 Float.
返回值 | 成功时返回数字, 否则返回空字符串.

WriteNum

写入指定类型的数据到文件并使文件指针向前移动。

File.WriteNumType(Num)
NumType | 指定下列各项的其中一个直接作为函数名称的一部分: UInt, Int, Int64, Short, UShort, Char, UChar, Double 或 Float.
Num | 数字.
返回值 | 写入的字节数. 例如, 写入成功时 WriteUInt 返回 4.

RawRead

从文件读取原始的二进制数据到内存. 如果指定了变量, 则必要时会自动扩展.

File.RawRead(VarOrAddress, Bytes)
VarOrAddress | 用来保存复制出来的数据的变量或内存地址。用法类似于 NumGet.
Bytes | 需读取的最大字节数.
返回值 | 读取的字节数.

RawWrite

写入原始的二进制数据到文件.

File.RawWrite(VarOrAddress, Bytes)
VarOrAddress | 包含数据的变量或内存中的数据地址。用法类似于 NumPut.
Bytes | 需写入的字节数.
返回值 | 写入的字节数.

Seek

移动文件指针.

File.Seek(Distance [, Origin = 0])
File.Position := Distance
File.Pos := Distance
Distance | 需移动的距离, 单位为字节. 较小的值更接近文件的开始处.
Origin 文件指针开始移动的起点. 必须为下列值的其中一个:
  • 0 (SEEK_SET): 文件的开始处. Distance 必须为零或更大.
  • 1 (SEEK_CUR): 文件指针的当前位置.
  • 2 (SEEK_END): 文件的末尾. Distance 通常应该为负数.
如果省略, 当 Distance 为负数时 Origin 为 SEEK_END, 而其他情况时为 SEEK_SET.
返回值 | 成功时为非零值, 否则为零.

Tell

Pos := File.Tell()
Pos := File.Position
Pos := File.Pos
返回值 文件指针的当前位置, 文件开始处为 0.

Length

获取或设置文件的大小.

FileSize := File.Length
File.Length := NewSize
NewSize | 文件的新大小, 单位为字节.
返回值 | 文件的大小, 单位为字节.

此属性应该仅用于真实的文件。如果 File 对象创建于管道的句柄，那么它可能返回管道内部缓冲区中当前可能数据的数目，但不能保证一定如此。

AtEOF

IsAtEOF := File.AtEOF
返回值 当文件指针到达文件的末尾时为非零值, 否则为零.

此属性应该仅用于真实的文件。如果 File 对象创建于非搜寻设备（例如控制台缓冲区或管道）的句柄，那么返回的值可能没有意义，因为这些设备逻辑上没有“文件末尾”。

Close

关闭文件, 把缓冲区的数据写入磁盘并释放共享锁定. 尽管当对象释放时文件会自动关闭, 不过建议尽快关闭文件.

File.Close()

没有参数或返回值.

Encoding

获取或设置此文件对象使用的编码.

Encoding := File.Encoding
File.Encoding := Encoding
Encoding FileEncoding 可接受格式的字符串.

__Handle

File.__Handle
返回值 与 DllCall 一起使用的系统文件句柄. 请参阅 CreateFile.

文件对象使用内部缓冲区读取或写入。如果数据已经被写入对象的内部缓冲区，则在返回句柄前会确保把数据写入磁盘。如果缓冲区中包含从文件读取的数据，则会把数据丢弃且文件指针的实际位置被重设为由 File.Pos 表示的逻辑位置。


Func 对象

Func对象[v1.1.00+]

表示可以被脚本调用的自定义或内置的函数.

到 Func 对象的引用也被称为 函数引用. 要获取函数引用, 请使用 Func 函数, 例如:

fn := Func("Func")
MsgBox % fn.Name "() is " (fn.IsBuiltIn ? "built-in." : "user-defined.")

Call

调用函数.

Func.(Parameters)

参数和返回值由函数定义.

如果 Func 是实现了 __Call 的函数名或用户定义对象, 那么此语法也是有效的.

Name

返回函数的名称.

Func.Name

IsBuiltIn

如果函数是内置的则返回 true, 否则返回 false.

Func.IsBuiltIn

IsVariadic

如果函数是 可变参数的 则返回 true, 否则返回 false.

Func.IsVariadic

MinParams

返回必需的参数数目.

Func.MinParams

MaxParams

对于用户定义函数返回正式声明的参数数目, 对于内置函数返回最大的参数数目.

Func.MaxParams

如果函数是 可变参数的, 返回值表示函数在不考虑 "variadic*" 参数时可以接受的最大参数数目.

IsByRef()

确定一个参数是否为 ByRef 类型.

Func.IsByRef(ParamIndex)
ParamIndex | 可选: 基于 1 的参数索引. 如果省略, 那么返回值表示此函数是否含有 ByRef 参数.
返回值 | 如果函数为内置函数或 ParamIndex 无效时返回空字符串; 否则返回布尔值表示此参数是否为 ByRef 类型.

IsOptional()

确定一个参数是否是可选的.

Func.IsOptional(ParamIndex)
ParamIndex | 可选: 基于 1 的参数索引. 如果省略, 返回值表示此函数是否含有可选参数.
返回值 | 如果 ParamIndex 无效则返回空字符串; 否则返回布尔值表示此参数是否可选.

如果此函数是可变参数的, 那么参数可以不进行正式声明. 支持内置函数.


AutoHotkey_L 新特性

这个页面描述了新添加到 AutoHotkey_L 分支的功能，现在简称为“AutoHotkey 1.1”。

流程控制 |
Break LoopLabel | 退出一个循环或任意数目的嵌套循环.
Continue LoopLabel | 继续循环, 即使在任意数目的嵌套循环中.
For x,y in z | 从头到为尾循环对象的内容.
Loop Until | 循环直到条件为真. 可用于任意类型的循环.
Try...Catch...Finally | 提供结构化的异常处理机制.
Throw | 抛出异常.
命令 |
FileEncoding | 为 FileRead、FileReadLine、Loop Read、FileAppend 和 FileOpen 设置默认编码。 另请参阅： 文本编码
Gui | 请参阅后面的 GUI 增强.
IniRead/Write/Delete | 读取, 写入或删除整段, 或获取所有段名称组成的列表.
Menu, Icon | 设置或移除菜单项图标.
运行 | 改进 了参数的解析方式.
SendInput {U+nnnn} | 发送 Unicode 字符. 在 Unicode 版本中可以直接使用 Unicode 字符.
SendLevel | 控制热键和热字串是否忽略模拟的键盘和鼠标事件。
SetFormat, IntegerFast, h|H | 设置小写或大写的十六进制格式.
SetRegView, RegView | 允许 32 位脚本中的注册表命令访问 64 位注册表视图，反之亦然。
Transform, HTML | 执行代码页或 HTML 转换.
WinGet, ..., ProcessPath | 获取拥有指定窗口的进程的完整路径和名称.
指令 |
#If expression | 类似于 #IfWinActive，但可以是任意类型的表达式。
#IfTimeout | 设置计算单个 #If 表达式可以使用的最大时间。
#MenuMaskKey | 改变用来屏蔽 Win 或 Alt keyup 事件的按键。
#Include <Lib> | 包含函数库文件夹中的脚本文件.
#InputLevel | 控制热键和热字串是否忽略模拟的键盘和鼠标事件。
#Warn | 启用或禁用为选择的情况提示开发者错误的警告。
函数 |
ComObj... -- ComObjActive ComObjEnwrap/Unwrap ComObjParameter ComObjType | 获取注册的 COM 对象。 包装/解开 COM 对象。 把值和类型包装成参数传递. 获取 COM 对象的类型信息.
ComObjArray | 创建用于 COM 的 SAFEARRAY。
ComObjConnect | 连接 COM 对象的事件源到带有给定前缀的函数。
ComObjCreate | 创建 COM 对象。
ComObjError | 启用或禁用 COM 错误通告。
ComObjFlags | 获取或改变控制 COM 包装器对象行为的标志。
ComObjGet | 返回由 COM 组件提供的对象引用。
ComObjQuery | 查询 COM 对象的接口或服务。
ComObjType | 从 COM 对象获取类型信息。
ComObjValue | 获取存储在 COM 包装器对象中的值或指针。
Exception | 创建用于 Throw 的异常对象 (同时提供对堆栈的受限访问).
FileOpen | 提供面向对象的文件 I/O。
Func | 获取函数的引用。
GetKeyName/VK/SC | 获取按键的名称、文本、虚拟按键码或扫描码。
InStr | 搜索字符串的出现位置，从左边或右边开始。
IsByRef | 判断变量是否是 ByRef 参数。
IsObject | 判断某个值是否为对象。
StrPut / StrGet | 复制字符串到内存地址或来自内存地址，并可选地对其在不同代码页间进行转换。
Trim | 移除字符串的开始和/或末尾的某些字符。
RegEx (?CNum:Func) | 在正则表达式进行模式匹配期间调用函数.
函数库 | 新的 "本地库" 和 #Include <LibName>.
可变参数函数 | 函数可以通过数组接受可变数目的参数.
静态初始化 | 静态变量现在可以使用任意表达式进行初始化.
对象 |
概述 | 对象的常规行为和用法.
对象 | 可以使用其他功能扩展的关联数组.
枚举数 | 可以枚举容器中的项目.
文件 | 提供访问文件的接口. FileOpen 返回文件类型的对象.
Func | 表示可以被脚本调用的自定义或内置的函数.
ComObject | 请参阅上面的 ComObj 函数。
变量 |
A_Is64bitOS | 当操作系统为 64 位则值为 1（真），为 32 位则为 0（假）。
A_IsUnicode | 在 Unicode 版本中, 此变量值为 1 (true). 在 ANSI 版本中此变量未定义, 所以等同为 false.
A_FileEncoding | 包含用于多种命令的默认编码，请参阅 FileEncoding。
A_OSVersion | 支持 Windows 7 和 Windows 8，请参阅 A_OSVersion。
A_PriorKey | 在最近按键按下或释放前最后按下的按键名称 ... (更多细节)
A_PtrSize | 包含指针的大小, 单位为字节. 此大小为 4 (32 位) 或 8 (64 位).
A_RegView | 由 SetRegView 设置的当前注册表视图。
A_ScriptHwnd | 脚本隐藏主窗口的唯一 ID (HWND/句柄).
数据类型 |
Ptr | 在 32 位版本中等同于 Int 而在 64 位版本中为 Int64. 由 DllCall, NumPut 和 NumGet 所支持.
AStr, WStr | 仅 DllCall 支持，请参阅脚本兼容性。
Unicode |
兼容性 | 在 DllCall 中如何处理 Unicode 等.
脚本文件 | 在脚本文件中使用 Unicode 编码.
SendInput | 在 SendInput 中使用 Unicode.
其他 |
ahk_exe | 窗口可以通过拥有此窗口的进程名称或路径 (EXE 文件) 进行标识.
调试 | 交互式调试功能 (单步执行等).
错误处理 | Try/catch/throw 和增加的 A_LastError 可用性.
GUI 增强 | 对 Gui 命令和相关部分的多方面增强.
图标支持 | 资源标识符和改进的对各种图标大小的支持.
其他变更 | 影响脚本兼容性的改变.
版本历史 | AutoHotkey_L 的修订历史.

错误处理

许多命令支持使用 try/catch 代替 ErrorLevel 进行错误处理. 例如：

try
{
    FileCopy, file1.txt, C:\folder
    FileDelete, C:\folder\old.txt
}
catch
    MsgBox An error occured!

此外, 后面的这些命令现在设置 A_LastError 来辅助调试: FileAppend, FileRead, FileReadLine, FileDelete, FileCopy, FileMove, FileGetAttrib/Time/Size/Version, FileSetAttrib/Time, FileCreateDir, RegRead, RegWrite, RegDelete.

函数库

除了 %A_MyDocuments%\AutoHotkey\Lib 的用户库和在 AutoHotkey 目录的标准库外, 函数还可以从 %A_ScriptDir%\Lib 中的 "本地库" 自动加载. 想了解更多信息, 请参阅 函数库.

#Include <LibName> 可以明确加载函数库中任意一个库文件.

GUI 增强

对 Gui 命令和相关部分进行了一些增强:

  • 引用 GUI 时可以用 名称或 HWND 代替介于 1 和 99 之间的数字.
  • Gui, New 创建新的匿名 GUI.
  • 可以创建任意数目的命名或匿名 GUI.
  • 新 GUI 选项: +HwndOutputVar, +ParentGUI
  • GUI 的拥有者可以为任意窗口: +Owner%HWND%.
  • Gui, Font 可以控制文本的反锯齿效果.
  • 支持像 Internet Explorer WebBrowser 这样的 ActiveX 控件.
  • GuiControlGet, OutputVar, Name 获取与 GUI 控件关联的变量名.
  • 在 Gui menus 中使用像 Ctrl+O 这样的键盘快捷键时会自动得到支持.
  • 字体品质 可以通过 Font 子命令控制.

静态变量

静态变量现在可以使用任意表达式进行初始化. 例如：

Sleep 500
MsgBox % Time() "ms since the script started."
Time() {
    static Tick := A_TickCount
    return A_TickCount - Tick
}

文本编码

FileRead, FileReadLine, Loop Read 和 FileAppend 支持 Windows 所支持的大部分文本编码, 而不限于系统默认的 ANSI 代码页. 可以用 FileEncoding 设置默认编码, 此设置在 FileRead 和 FileAppend 中可以使用如下方法覆盖:

FileRead, OutputVar, *Pnnn Filename
FileAppend [, Text, Filename, Encoding]

此处 nnn 必须是数值的 代码页标识符, 而 Encoding 遵循与 FileEncoding 相同的格式.

另请参阅: 脚本兼容性

可变参数函数和函数调用

可变参数函数 可以通过数组接受可变数目的参数, 而 可变参数的函数调用 可以用来传递可变数目的参数给函数.

图标支持的改进

不常见的大小

可以从可执行文件中提取操作系统支持的任意大小的图标资源. 当图标组中存在多种大小的图标资源时, 则使用其中最合适的大小. 在修订号 17 之前的版本中, 系统先选择任意的图标资源, 接着调整到系统的大图标尺寸, 然后调整回请求的尺寸.

资源标识符

使用负数的图标编号可以标识可执行文件中的一组图标资源. 例如, 下面的语句设置托盘图标为 ahk 文件的默认图标.

Menu, Tray, Icon, %A_AhkPath%, -160


脚本兼容性

尽管为 AutoHotkey 1.0 编写的许多脚本不需要修改就可以运行在 AutoHotkey 1.1 上，然而由于两种版本的根本区别可能使得某些功能运行不正常。因为最主要出现问题的差异只影响高级功能（例如 DllCall），大多数用户不需要担心。

AutoHotkey 1.1 也称为“AutoHotkey_L”，而 AutoHotkey 1.0 则表示“AutoHotkey Basic”。AutoHotkey_L 的一些旧版本使用 1.0.* 版本号，所以为了清晰，这里的帮助中使用名称而不是版本号来区分 AutoHotkey 的两种分支。

注：一些常见的问题是由对 Unicode 文本的支持引起的，可以通过使用 AutoHotkey_L 的 ANSI 版本来避免。

基本

高度影响：

  • 不再允许的一些语法错误
  • FileRead 可能返回损坏的二进制数据
  • 变量和函数名中不允许使用 [、] 或 ?

中度影响：

  • Transform 的 Unicode 子命令在 Unicode 版本中不再可用
  • 运行 AutoHotkey.ahk 来代替 AutoHotkey.ini
  • SetFormat, Integer, H 区分大小写
  • A_LastError 会被更多的命令修改
  • MsgBox 的逗号智能处理更加一致
  • Gui +Owner 替换额外的样式
  • 默认情况下会启用 GUI 的 DPI 缩放。
  • SoundSet 和 SoundGet 在 Vista 及更高版本中表现更佳
  • ~颚化符会影响自定义修饰键的工作方式
  • x & y:: 会使得 x:: 和 x up:: 都会在 x 释放时触发。

低度影响：

  • If var is type 默认忽略系统区域设置
  • GroupActivate 设置 ErrorLevel 和 GroupAdd 的 Label 作用的差异
  • Run 和 RunWait 解释 Target 的差异
  • Control-Z 不会被解释为文件结束
  • 兼容模式可能引起冲突
  • A_IsCompiled 总是只读的
  • 前导和尾随的 `t 序列不再被丢弃

高级

  • Unicode 和 ANSI 的比较
    • VarSetCapacity
    • DllCall
    • NumPut / NumGet
  • 指针大小

基本

语法错误

AutoHotkey_L 中不允许某些在 AutoHotkey Basic 中接受的语法错误。识别出这些错误后，其中大多数都很容易改正。用 AutoHotkey_L 运行脚本时下面的错误会立即被检测出来，必须改正后才能运行脚本：

  • 在每个命令和它的参数之间需要空格、tab 或逗号。例如，MsgBox< foo 和 If!foo 不会被允许。
  • Hotkey, IfSomething，当 Something 无效时不会被允许。

其他一些语法错误会在脚本运行时检测出来。这些情况会导致在退出当前线程前显示错误消息：

  • 常见：无法识别或不良格式的 Gui、Gui Show 或 GuiControl 选项。
  • 带有空的组名称的 GroupAdd。以前这个问题会让当前线程安静地退出。
  • Gui 选项 +LastFoundExist 不能和其他选项组合使用，因为这样会让它的行为与 +LastFound 一样。

当前无法检测但会在 AutoHotkey_L 出现问题的其他语法错误：

  • 通过 ( 进行自动连结具有更多选择性，所以类似 12(34) 这样无效的表达式不再起作用。

FileRead

在某些情况下 FileRead 会在代码页之间转换文本，因此可能输出错误的二进制数据。要避免此问题，请添加 *c 选项或使用 FileOpen 代替。

变量和函数名

字符 [、] 和 ? 被预留用于表达式，所以在变量名中使用时不再合法。因此，?（用于三元运算）的两边不再需要空格。另请参阅对象语法。

可能或不能自动检测的错误：

  • 当脚本在表达式中的变量名使用这些字符时，一般脚本会运行而不显示错误，但这些字符可能被错误解释为运算符而不是变量名的一部分。
  • 如果这些字符用在双重解引（例如 Array%n%，其中 n 包含了上面的某个字符），则当脚本运行到计算双重解引时会显示错误消息。
  • 如果这些字符用在其他环境中（例如赋值的左边、命令的输入、输出变量的名称或在百分号之间），则会显示错误消息并阻止脚本运行。

Transform

在 AutoHotkey_L 的 Unicode 版本中一些 Transform 子命令被修改或不可用：

  • Transform, Unicode 不可用。要赋值 Unicode 文本到剪贴板, 使用正常赋值. 另请参阅: StrPut/StrGet.
  • Transform, HTML 支持附加功能。

默认脚本

未指定脚本运行 AutoHotkey_L 时，默认加载 .ahk 文件而不是 .ini。这个文件的名称取决于当前执行程序的文件名。想了解更多细节, 请参阅 传递命令行参数到脚本.

SetFormat, Integer[Fast], H

使用大写字母 H 时, 十六进制数字中 A-F 也将为大写. AutoHotkey Basic 总是使用小写形式的数字。请参阅 SetFormat。

A_LastError

现在后面的这些命令会设置 A_LastError 来辅助调试：FileAppend、FileRead、FileReadLine、FileDelete、FileCopy、FileMove、FileGetAttrib/Time/Size/Version、FileSetAttrib/Time、FileCreateDir、RegRead、RegWrite、RegDelete。使用这些命令的其中任何一个会覆盖 A_LastError 之前的值。

MsgBox

对 MsgBox 的智能逗号处理进行了改变，提高了灵活性及与其他所有命令的一致性。在大多数情况中，MsgBox 会按预想的方式执行。在某些罕见的情况下，依赖旧有怪癖的脚本可能观察到行为的变化。例如：

; 现在这样会被解释为表达式（选项）跟着文本（标题）
; 而不是含多个子表达式的单个表达式（文本）：
MsgBox % x, y
; 添加小括号来强制使用旧式解释：
MsgBox % (x, y)

; 现在这样会显示空对话框而不是文本“0, Title”：
MsgBox 0, Title
; 这两个在 AutoHotkey_L 和 AutoHotkey Basic 的行为和预期一样：
MsgBox 0, Title, % ""   ; 显示空对话框
MsgBox 0`, Title        ; 显示文本“0, Title”

; 现在这样会显示空对话框而不是文本“, Title”：
MsgBox,, Title

Gui +Owner

对 Gui 应用 +Owner 选项还会移除 WS_CHILD 样式并设置 WS_POPUP 样式。这样会破坏在设置这些样式之后使用 +Owner 设置 Gui 的父窗口的脚本。

DPI 缩放

DPI 缩放 默认会在脚本的 GUI 中启用。当系统 DPI 设置不是 96（100%）时它会影响脚本。要禁用，请使用 Gui -DPIScale。

Windows Vista 及更高版本中的 Sound 命令

SoundSet、SoundGet、SoundSetWaveVolume 和 SoundGetWaveVolume 已经改进了对 Windows Vista 及更高版本的支持。典型的行为改变包括：

  • 脚本会影响整个系统（通常希望如此）而不是仅脚本自身。
  • 设备编号方式的改变——每个输出设备或输入设备被视为独立的。

~颚化符和自定义组合键

从 v1.1.14 起，当一个按键作为修饰符用于组合键时颚化符前缀会影响该热键的工作方式。

自定义组合键和 Down/Up 热键

如果没有使用颚化符前缀，则对于自定义修饰键会同时定义按键按下和弹起热键，它们在该按键释放时都会触发。例如，x & y:: 会使得 x:: 和 x up:: 都会在 x 释放时触发，而以前 x:: 是不会触发。

If var is type

If var is type 只有在使用 StringCaseSense, Locale 时才不会忽略系统区域设置。

窗口组

GroupActivate 在没有找到要激活的窗口时设置 ErrorLevel 为 1，否则为 0。以前 ErrorLevel 会保持不变。

GroupAdd 的 Label 参数应用于作为一个整体的窗口组而不是组中某个特殊的窗口规格。关于这个变更的讨论可以在论坛上找到。然而，不建议使用这个参数；相反地应该在调用 GroupActivate 后检查 ErrorLevel。

Run / RunWait

AutoHotkey_L 包含了一些对 Run 和 RunWait 命令的 Target 参数的增强解释。这样能接受一些之前不起作用的情况，但在罕见的情况下也会影响 AutoHotkey Basic 中能执行的情况。新的行为如下：

  • 如果 Target 以引号开始，则到下一个引号之间的所有内容被视为要执行的操作，一般为可执行文件。
  • 否则首个以空格结束并且为一个现有文件或以 .exe, .bat, .com, .cmd 或 .hta 结尾的子字符串被视为操作. 这样就允许 .ahk、.vbs 或 .lnk 这样的文件类型接受参数，同时也允许像以前的版本那样不需要绝对路径运行“已知”的可执行文件（例如 wordpad.exe）。

Control-Z

Loop Read 和 FileReadLine 不再把字符 Control-Z（0x1A）解释为文件结束标记。任何的 Control-Z，即使某一个恰好出现在文件末尾，都原样加载。FileRead 已经忽略这个字符，所以不受这个问题的影响。

兼容模式

如果用于运行脚本的 EXE 文件属性中设置 兼容模式 为 Windows 95, 98/ME 或 NT4, 脚本可能无法正常运行. 这是由于兼容模式会把特定的 Windows 版本报告给应用程序，但 AutoHotkey_L 不支持这些版本。例如设置兼容模式为 Windows 95 或 98/ME 将使得 MsgBox %A_OSVersion% 报告 WIN_NT4.

A_IsCompiled

A_IsCompiled 当脚本未编译时被定义为空字符串。之前它会被保留为未定义，这意味着当脚本未编译时对它进行赋值（例如 A_IsCompiled := 1）是有效的。现在在所有的情况中它都被视为只读的内置变量。

转义的空白符

不再从每个参数的开始和末尾移除转义的空白字符（例如 `t 和 `）。例如，StringReplace s, s, `t 现在是有效的，并会移除 s 中的所有 tab 字符。

Unicode 和 ANSI 的比较

脚本处理的每个文本值会被保存为一序列或一串字符。每个字符的数值和大小取决于所使用的AutoHotkey构建：Unicode或ANSI。这些细节对于进行下列操作的脚本通常很重要：

  • 通过 DllCall 传递字符串到外部函数。
  • 通过 PostMessage/SendMessage 传递字符串。
  • 通过 NumPut/NumGet 直接操作字符串。
  • 使用 VarSetCapacity 来确保变量中能存储一定数目的字符。

为一种特殊格式设计的脚本使用错误的 AutoHotkey 版本运行时常常会遇到问题。例如，一些为 AutoHotkey Basic 编写的脚本能正常运行在 AutoHotkey_L 的 ANSI 版本中，但在 Unicode 版本中会失败。如果您不确定正在使用的版本，请运行下面的脚本：

MsgBox % A_IsUnicode ? "Unicode" : "ANSI"

ANSI：每个字符占用一个字节（8 位）。大于 127 的字符代码取决于系统的语言设置。

Unicode：每个字符占用两个字节（16 位）。字符代码在 UTF-16 格式中定义。

语义注：技术上，一些 Unicode 字符表示为两个 16 位代码单元，一起被称为“代理项对”。同样地，一些 ANSI 代码页（通常称为双字节字符集）含有一些双字节字符。然而，由于特殊的原因它们几乎都被视为两个单独的单元（为了简化而称为“字符”）。

VarSetCapacity

VarSetCapacity 设置一个变量占用的空间, 单位为字节. 要根据字符数设置变量的容量，必须同时考虑字符的大小。例如：

VarSetCapacity(ansi_var,    capacity_in_chars)
VarSetCapacity(unicode_var, capacity_in_chars * 2)
VarSetCapacity(native_var,  capacity_in_chars * (A_IsUnicode ? 2 : 1))
VarSetCapacity(native_var,  t_size(capacity_in_chars))  ; 请参阅下面

VarSetCapacity 的两种主要用途：

  1. 在通过逐步连接构造字符串时扩展变量以存储估计的字符数和提升性能。例如，VarSetCapacity(var, 1000) 允许使用 1000 字节，这样的容量在 AutoHotkey_L 的 Unicode 版本中只能保存 500 个字符。这样会影响性能，不过脚本应该能正常执行。
  2. 重设变量的大小来存储二进制结构。如果结构直接包含文本，则必须考虑文本的格式。这取决于结构自身，有时即使在 AutoHotkey_L 的 Unicode 版本中也会使用 ANSI 文本。如果变量太小，则脚本可能会崩溃或行为异常（取决于使用结构的方式）。

DllCall

使用 "Str" 类型时, 表示字符串使用当前版本原生的编码格式. 由于一些函数可能需要或返回特殊格式的字符串, 所以有时还需要使用下列的字符串格式:

 | 字符大小 | C / Win32 类型 | Encoding
WStr | 16-位 | wchar_t*, WCHAR*, LPWSTR, LPCWSTR | UTF-16
AStr | 8-位 | char*, CHAR*, LPSTR, LPCSTR | ANSI (系统默认 ANSI 代码页)
Str | -- | TCHAR*, LPTSTR, LPCTSTR | 相当于 Unicode 构建中的 WStr 或 ANSI 构建中的 AStr。

如果 "Str" 或在当前版本中的等价类型用于参数中, 那么字符串或变量的地址被传递给函数, 否则创建一个期望格式的字符串临时副本进行传递. 一般地，“AStr”和“WStr”不应该用于函数会写入值的参数中。

注意: "AStr" 和 "WStr" 用于参数和函数的返回值同样是有效的.

一般而言, 如果脚本通过 DllCall 调用接受字符串参数的函数, 那么必须采取以下其中一种方式:

  1. 如果函数的 Unicode (W) 和 ANSI (A) 都可用, 那么为当前版本调用匹配的那个. 在下面的例子中, "DeleteFile" 在内部被称为 "DeleteFileA" 或 "DeleteFileW". 由于 "DeleteFile" 自身实际并不存在, DllCall 自动根据当前版本尝试适合的 "A" 或 "W".
    DllCall("DeleteFile", "Ptr", &filename)
DllCall("DeleteFile", "Str", filename)

    在这个例子中, &filename 准确按原样传递字符串地址, 所以函数必须期望接受和 "Str" 类型相同编码格式的字符串. 注意在 AutoHotkey Basic 中 "UInt" 必须使用 "Ptr" 代替, 但得到的代码可能不兼容 64 位.

    注意: 如果无法根据名称准确找到指定的函数, 在 AutoHotkey_L 中不管指定哪个 DLL 都会在函数名称后添加 "A" 或 "W" 后缀查找. 然而, AutoHotkey Basic 则仅为 User32.dll, Kernel32.dll, ComCtl32.dll 或 Gdi32.dll 中的函数添加 "A" 后缀.

  2. 如果函数仅接受特殊类型的字符串作为输入, 那么脚本可能必须使用相应的字符串类型:
    DllCall("DeleteFileA", "AStr", filename)
DllCall("DeleteFileW", "WStr", filename)
  3. 如果函数必须修改字符串 (非原生格式), 那么脚本必须如 上面 描述的那样分配缓存并且把缓存的地址传递给函数. 如果参数接受输入, 脚本还必须把输入字符串转换为适当的格式; 这可以用 StrPut 实现.

NumPut / NumGet

当使用 NumPut 或 NumGet 操作字符串时, 对于给定类型的字符串其偏移和类型都必须正确. 可以参考下面的代码:

;  8 位/ANSI   字符串:  size_of_char=1  type_of_char="Char"
; 16 位/UTF-16 字符串:  size_of_char=2  type_of_char="UShort"
nth_char := NumGet(var, (n-1)*size_of_char, type_of_char)
NumPut(nth_char, var, (n-1)*size_of_char, type_of_char)

如果 var 含有原生格式的字符串, 那么根据 A_IsUnicode 的值可以确定变量的值.

nth_char := NumGet(var, t_size(n-1), t_char())
NumPut(nth_char, var, t_size(n-1), t_char())

; 为了方便和清晰定义的函数:
t_char() {
    return A_IsUnicode ? "UShort" : "Char"
}
t_size(char_count=1) {
    return A_IsUnicode ? char_count*2 : char_count
}

指针大小

指针在 32 位版本 (包括 AutoHotkey Basic) 中是 4 个字节大小而在 64 位版本中是 8 个字节. 使用结构或 DllCall 的脚本可能需要为在两种平台上正常运行进行考虑. 受影响的特殊地方包括:

  • 含有一个或多个指针的结构字段的偏移计算.
  • 含有一个或多个指针的结构大小计算.
  • 在 DllCall, NumPut 或 NumGet 中使用的类型名称.

对于大小和偏移计算, 使用 A_PtrSize. 对于 DllCall, NumPut 和 NumGet, 使用适当的 Ptr 类型.

记住一个字段的偏移常常是在它之前所有字段的总大小. 同时注意句柄 (包括类似 HWND 和 HBITMAP 的类型) 实际上是指针类型.

/*
  typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;    // Ptr
    HANDLE hThread;
    DWORD  dwProcessId; // UInt (4 字节)
    DWORD  dwThreadId;
  } PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
*/
VarSetCapacity(pi, A_PtrSize*2 + 8) ; Ptr + Ptr + UInt + UInt
DllCall("CreateProcess", <为简短而省略>, "Ptr", &pi, <omitted>)
hProcess    := NumGet(pi, 0)         ; 默认为“Ptr”。
hThread     := NumGet(pi, A_PtrSize) ;
dwProcessId := NumGet(pi, A_PtrSize*2,     "UInt")
dwProcessId := NumGet(pi, A_PtrSize*2 + 4, "UInt")


ClipWait

等待，一直到剪贴板包含数据。

ClipWait [, SecondsToWait, 1]

参数

SecondsToWait

如果省略, 此命令将无限期等待. 否则, 它将等待不超过这个秒数的时间 (可以包含小数点或为 表达式). 指定 0 等同于指定 0.5.

1

如果省略此参数, 此命令会更有选择性, 明确地等待剪贴板中出现文本或文件 ("文本" 包含任何当您粘贴到记事本时会产生文本的内容). 如果此参数为 1 (可以为 表达式), 此命令会等待剪贴板中出现任何类型的数据.

ErrorLevel

如果到达等待期限, ErrorLevel 将被置为 1. 否则 (即剪贴板包含数据), ErrorLevel 被置为 0.

备注

使用此命令比您在一个循环中检查剪贴板是否为空要好. 这是由于此命令从不打开剪贴板, 因此执行地更好并且避免了对可能使用剪贴板的其他程序的干扰.

此命令把任何可转换成文本的内容 (例如 HTML) 视为文本. 它也把文件, 例如从资源管理器窗口中通过 Control-C 复制的那些, 视为文本. 每当在脚本中引用剪贴板变量 (%clipboard%) 时, 这些文件被自动转换成它们的文件名 (包含完整路径). 详情见 剪贴板.

当最后一个参数为 1 时, 剪贴板中出现任何数据都将符合此命令. 这种特性可以和 ClipboardAll 结合使用来保存像图片这样的非文本数据.

当此命令处于等待状态时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

相关

Clipboard, WinWait, KeyWait

示例

clipboard = ; 清空剪贴板
Send, ^c
ClipWait, 2
if ErrorLevel
{
    MsgBox, The attempt to copy text onto the clipboard failed.
    return
}
MsgBox, clipboard = %clipboard%
return


EnvGet

EnvGet [v1.0.43.08+]

获取环境变量的内容。

EnvGet, OutputVar, EnvVarName

参数

OutputVar

用来存储字符串的变量名.

EnvVarName

要获取的 环境变量 的名称. 例如：EnvGet, OutputVar, Path。

备注

如果指定的环境变量为空或不存在, 那么 OutputVar 被置空.

操作系统限制每个环境变量的文本最多为 32 KB.

相关

EnvSet, #NoEnv, 环境变量, EnvUpdate, SetEnv, Run, RunWait

示例

EnvGet, OutputVar, LogonServer


EnvSet

向系统环境中的变量写入值。

EnvSet, EnvVar, Value

参数

EnvVar
要使用的 环境变量 的名称, 例如 "COMSPEC" 或 "PATH".
值

要设置到目标 环境变量 的值.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

操作系统限制每个环境变量的文本最多为 32 KB.

此命令创建或改变的环境变量只有由此脚本通过 Run 或 RunWait 运行的程序才可以读取. 请参阅环境变量了解更多细节。

此命令与 SetEnv 分别存在, 因为 普通脚本变量 没有存储在系统环境中. 这是由于性能会变差且操作系统限制环境变量大小在 32 KB 之内.

相关

EnvGet, #NoEnv, 环境变量, EnvUpdate, SetEnv, Run, RunWait

示例

EnvSet, AutGUI, Some text to put in the variable.


EnvUpdate

通知操作系统和所有正在运行的程序环境变量已经改变。

EnvUpdate

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

刷新操作系统环境. 效果类似于注销系统后再登录.

例如，修改了后面的注册表键后，可以用 EnvUpdate 来广播这个变化：HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session

相关

EnvSet, RegWrite

示例

EnvUpdate


DllCall()

调用 DLL 文件中的函数，例如标准的 Windows API 函数。

Result := DllCall("[DllFile\]Function" [, Type1, Arg1, Type2, Arg2, "Cdecl ReturnType"])

参数

Result

DllCall 返回由被调用函数所返回的实际值. 如果函数没有返回值, 那么结果为未定义整数. 如果函数在被调用时发生了 错误, 那么返回值为空 (一个空字符串).

[DllFile\]Function

DLL 或 EXE 文件名, 后面跟着一个反斜杠和函数名. 例如：MyDLL\MyFunction（省略时文件扩展名默认为 ".dll"）。如果未指定绝对路径，则假定 DllFile 在系统的 PATH 指定的路径或 A_WorkingDir 中。

调用 User32.dll, Kernel32.dll, ComCtl32.dll 或 Gdi32.dll 中的函数时可以省略 DllFile. 例如，使用 "User32\IsWindowVisible" 和 "IsWindowVisible" 得到相同的结果。

如果使用指定的名称无法找到函数, 则会根据当前运行脚本的 AutoHotkey 版本自动附加 A (ANSI) 或 W (Unicode) 后缀. 例如，"MessageBox" 在 ANSI 版本中等同于 "MessageBoxA" 而在 Unicode 版本中等同于 "MessageBoxW"。

当 重复 调用 DLL 通过 预先加载此 DLL 文件 可以显著改善执行效率.

在 1.0.46.08+ 版本中, 此参数也可以是表示需调用函数的内存地址的单独的整数. 如 COM 和 RegisterCallback() 提供的地址.

Type1, Arg1

这样的每对数据表示需传递给函数的单个参数. 参数的个数没有限制. 关于 Type，请参阅下面的类型表。关于 Arg, 指定传递给函数的值.

Cdecl ReturnType

通常省略单词 Cdecl 因为大多数函数使用标准调用约定而不是 "C" 调用约定 (像 wsprintf 这样接受可变数目参数的函数在这点上是个例外). 如果您省略了 Cdecl 但调用时产生 ErrorLevel An (这里 n 是您传递的参数的总大小), 此时可能需要加上 Cdecl. 注意大多数面向对象的 C++ 函数使用的 thiscall 约定是不受支持的.

如果使用了，那么单词Cdecl应该在返回值类型前列出（如果有）。在单词间使用空格或 tab 分隔. 例如："Cdecl Str"。

[AHK_L 53+]：因为在 64 位代码中不存在“C”调用约定，所以在 AutoHotkey 的 64 位版本中可以使用 Cdecl 但没有效果。

ReturnType: 如果函数返回 32 位的有符号整型 (Int), BOOL 或没有返回值, 则 ReturnType 可以省略. 否则, 需要指定下面 类型表 中参数类型的其中一个. 还支持 星号后缀.

参数和返回值类型

Str

例如“Blue”或 MyVar 这样的字符串型。如果被调用函数修改了字符串且此参数是个裸变量, 那么其内容将被更新. 例如，后面的调用将把 MyVar 的内容转换成大写：DllCall("CharUpper", "Str", MyVar)。

然而, 如果函数需要保存超过变量当前容量的字符串, 则在调用前必须确保此变量的容量足够大. 这可以通过调用 VarSetCapacity(MyVar, 123) 来实现，其中 123 是为 MyVar 保留的容量。

Str 参数不能是计算结果为数字 (例如 i+1) 的 表达式. 如果这样, 则不会调用函数并设置 ErrorLevel 的值为 -2.

支持 星号变量 "Str*" 但极少使用. 它可以用在期望如 "TCHAR **" 或 "LPTSTR *" 类型参数的函数中.

注意: 传递字符串给函数时, 应该注意函数期望什么 类型 的字符串.
AStr
WStr 		[AHK_L 42+]: ANSI 或 Unicode (宽 字符) 字符串型. 请参阅 脚本兼容性 了解等同的 Win32 类型和其他细节.
Int64 | 64 位整型, 其范围为 -9223372036854775808 (-0x8000000000000000) 到 9223372036854775807 (0x7FFFFFFFFFFFFFFF).
Int

32 位整型 (最常用的整数类型), 其范围为 -2147483648 (-0x80000000) 到 2147483647 (0x7FFFFFFF). Int 有时也写成 "Long".

在函数期望 BOOL 类型的参数中也应该使用 Int (BOOL 值应该为 1 或 0).

无符号 整型 (UInt) 也是频繁使用的类型, 例如用于 DWORD.
Short | 16 位整型, 其范围为 -32768 (-0x8000) 到 32767 (0x7FFF). 无符号 短整型 (UShort) 可用于函数参数的 WORD 类型.
Char | 8 位整型, 其范围为 -128 (-0x80) 到 127 (0x7F). 无符号 字符型 (UChar) 可用于函数参数的 BYTE 类型.
Float | 32 位浮点型, 具有 6 位精确度.
Double | 64 位浮点型, 具有 15 位精确度.
Ptr

[AHK_L 42+]: 指针大小的 整型, 根据当前运行的脚本是 32 位还是 64 位分别相当于 Int 或 Int64. Ptr 应该用于数组或结构中的指针 (例如 RECT* 或 LPPOINT) 和几乎所有句柄 (例如 HWND, HBRUSH 或 HBITMAP). 如果参数是指向简单的数值的指针 (例如 LPDWORD 或 int*), 通常应该使用 * 或 P 后缀代替 "Ptr".

Ptr 也可以和 * 或 P 后缀一起使用; 此时它应该用在通过 LPVOID* 或类似类型输出指针的函数中.

UPtr 也是有效的, 但仅适用于 32 位版本中的无符号整型, 因为 AutoHotkey 不支持无符号的 64 位整型.

如果需要和旧版本的 AutoHotkey 兼容, 请使用如下所示的变量类型:

Ptr := A_PtrSize ? "Ptr" : "UInt" ; 若 A_PtrSize 没有定义, 则使用 UInt.
DllCall("DeleteFile", Ptr, &filename) ; 省略 Ptr 两边的引号.

注意: 要传递 NULL 句柄或指针, 请传递整数 0.
* 或 P
(后缀)

在上述任一类型后附加星号 (星号前可以含有空格) 表示传递参数的地址而不是参数的值 (被调用函数必须接受地址). 由于这时函数可能修改参数的值, 所以每当不受保护的变量作为参数传递时, 变量的内容都会被更新. 例如，后面的调用将通过地址传递 MyVar 的内容给 MyFunction，但也会更新 MyVar 来反映 MyFunction 对它作出的改变：DllCall("MyDll\MyFunction", "Int*", MyVar)。

一般说来, 星号可用于函数中以 "LP" 开始的参数类型或返回值类型. 最常见的例子是 LPDWORD, 这是指向 DWORD 的指针. 因为 DWORD 是无符号 32 位整型, 所以用 "UInt*" 或 "UintP" 来表示 LPDWORD. 星号不应该用于字符串类型 (例如 LPTSTR), 指向结构的指针 (如 LPRECT) 或数组; 对于这些, 根据您需要传递的是变量还是其地址应该使用 "Str" 或 "Ptr".

注：“Char*”与“Str”类型是不同的，因为“Char*”传递 8 位数的地址，而“Str”传递一系列字符的地址，根据 AutoHotkey 版本的不同它可能是 8 位（ANSI）或 16 位（Unicode）的。同样地，“UInt*”会传递 32 位数的地址，所以不应该使用在函数期望大于 32 位的结构或值的数组的时候。

由于AutoHotkey 中的变量没有固定的类型，所以传递给函数的地址指向临时内存而不是变量自身。不需要对这样的变量调用 VarSetCapacity，因为在函数返回后 DllCall 会正确的更新变量。
U (前缀)

在上述任一整型前加上字符 U 表示无符号整型 (UInt64, UInt, UShort 和 UChar). 严格说来, 这仅对于返回值或 星号变量 才是必要的, 因为它不影响值传递的参数是无符号的还是有符号的 (Int64 除外).

如果在无符号参数中指定负整数, 那么它会被转换到无符号范围中. 例如, 把 -1 作为 UInt 类型传递, 则它会被转换成 0xFFFFFFFF.

不支持由函数产生的 无符号 64 位整型. 因此, 要让大于或等于 0x8000000000000000 的数字有效, 请省略 U 前缀并且把任何从函数接收到的负值转换成很大的正数. 例如, 如果设计返回值为 UInt64 类型的函数在返回 Int64 类型的值 -1 时, 实际的返回值是 0xFFFFFFFFFFFFFFFF.

注意: 当指定不包含空格或星号的参数类型或返回值类型时, 包含的引号可以省略. 例如，可以使用 Str 代替 "Str" 而 CDecl 代替 "CDecl"。此外, 用字母 P 代替星号时也可以省略引号. 例如：UIntP。

ErrorLevel

[v1.1.04+] 此函数失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

ErrorLevel 会被设置为下列值的其中一个来表示调用成功或失败.

0: 成功.

-1 (负 1): [DllFile\]Function 参数是浮点数. 要求参数为字符串或正整数.

-2: 返回值类型 或某个指定的 参数类型 无效. 此错误的原因也可能是传递计算结果为数字的表达式给字符串（str）参数。

-3：无法访问或加载指定的 DllFile。如果没有明确指明 DllFile 的路径, 则文件必须在系统 PATH 变量的路径或 A_WorkingDir 中. 此错误的原因可能是用户缺少访问此文件的权限，或者 AutoHotkey 为 32 位而 DLL 是 64 位，反之亦然。

-4: 在 DLL 中没有找到指定的函数.

N (任意正数): 函数被调用后异常终止了, 致命异常号为 N (例如, 0xC0000005 表示 "访问违例"). 此时函数返回空值 (空字符串), 但仍会更新所有的 星号变量. 致命异常的一个例子是间接引用了无效的指针, 如 NULL. 因为 Cdecl 函数决不会产生下一段描述中的 "An" 错误, 所以当传递给它的参数太少时可能会产生异常.

An (字母 A 后面跟着整数 n): 调用了函数, 但传递给它的参数太多或太少了. "n" 是错误参数列表超过正确参数列表的字节数. 如果 n 为正数, 表示传递的参数过多 (或参数太大), 或函数调用要求 CDecl 的返回值类型. 如果 n 为负数, 表示传递的参数过少. 应该改正这种情况来让函数可靠运行. 此错误的出现也可能表示出现了异常, 此时函数返回空字符串. 请注意由于 x64 调用约定, 64 位版本不会设置 ErrorLevel 为 An.

异常和 A_LastError

尽管有内置的异常处理机制, 但 DllCall 仍有可能让脚本崩溃. 当函数不直接生成异常而输出一些不适当的数据 (例如无效的指针或没有结束符的字符串) 时, 这种情况可能会发生. 这可能不是函数的问题，而是脚本传递给它不适合的值，例如无效的指针或内存空间不足的 “str”。当脚本指定不适当的参数类型或返回值类型 (例如要求由函数生成的整数是 星号变量 或 str) 时, 它也可能崩溃.

内置变量 A_LastError 包含了操作系统 GetLastError() 函数最近调用返回的结果, 在调用函数后会立即执行此函数 (对效率的影响未知). A_LastError 是一个介于 0 和 4294967295 之间的数字 (总是为十进制而非十六进制). 像 ErrorLevel 一样, A_LastError 是与每个线程关联的设置; 即由其他 线程 产生的中断不会改变它. 不过, Run/RunWait 也会设置 A_LastError 的值.

性能

当需要重复调用一个 DLL 时, 预先明确装载它可以显著提高执行效率 (对于 标准的 DLL 文件如 User32 可以不需要, 因为它是常驻的). 这样的实现避免了 DllCall 内部每次调用 LoadLibrary 和 FreeLibrary 的需要. 例如：

hModule := DllCall("LoadLibrary", "Str", "MyFunctions.dll", "Ptr")  ; 避免了在循环中每次都需要使用 DllCall() 装载库.
Loop, C:\My Documents\*.*, , 1
    result := DllCall("MyFunctions\BackupFile", "Str", A_LoopFileFullPath)
DllCall("FreeLibrary", "Ptr", hModule)  ; 为了释放内存, 在使用 DLL 后需要进行卸载.

在 v1.0.46.08+, 通过预先查找函数的地址甚至可以获得更快的性能. 例如：

; 在下面的地址中, 如果 DLL 还没有装载, 则请使用 LoadLibrary 代替 GetModuleHandle.
MulDivProc := DllCall("GetProcAddress", Ptr, DllCall("GetModuleHandle", Str, "kernel32", "Ptr"), AStr, "MulDiv", "Ptr")
Loop 500
    DllCall(MulDivProc, Int, 3, Int, 4, Int, 3)

[AHK_L 31+]: 如果 DllCall 的首个参数是原义的字符串如 "MulDiv" 并且包含了函数的 DLL 在脚本开始前已正常装载了, 那么此字符串会自动被解析为函数地址. 这种内置的最优化比上述演示的例子执行地更高效.

同时, 在脚本的任意位置添加 #NoEnv 这行可以改善在使用了没有加引号的参数类型 (例如 Int 与 "Int") 时 DllCall 的性能.

最后, 当传递字符串变量给不会改变它长度的函数时, 传递变量的 地址 (例如 &MyVar) 而不是作为 "str" 类型可以提升性能 (尤其是当字符串很长的时候). 后面的例子把字符串转换成大写：DllCall("CharUpper", Ptr, &MyVar, Ptr)。

结构和数组

结构是内存中连续的 成员 (空间) 的集合. 大多数成员变量类型是整型.

调用接受结构地址 (或内存块数组) 的函数可以把结构中的原始二进制数据保存到普通变量中. 一般步骤如下:

1) 调用 VarSetCapacity(MyStruct, 123, 0) 来确保目标变量足够大以便保存结构数据. 把 123 替换为至少和结构一样大小的数字. 最后一个参数零是可选的; 它会初始化所有成员变量为二进制零, 这样通常可以避免在下一步中频繁调用 NumPut().

2) 如果目标函数需要初始化结构, 则调用 NumPut(123, MyStruct, 4, "UInt") 来初始化任意成员为非零数据. 把 123 替换为需要向目标成员存入的整数 (或指定 &Var 来存入变量的 地址). 把 4 替换为目标成员的偏移 (关于 "偏移" 的说明请参阅步骤 #4). 把 "UInt" 替换为合适的类型, 或当成员是指针或句柄时省略.

3) 调用目标函数, 把 MyStruct 的 地址 作为 UInt (或 Ptr 在 AHK_L 42+ 时) 的参数传递过去. 例如, DllCall("MyDll\MyFunc", Ptr, &MyStruct). 函数将检查和/或改变其中的某些成员变量.

4) 使用 MyInteger := NumGet(MyStruct, 4, "UInt") 从结构中获取任何想要的成员变量. 把 4 替换为结构中目标成员的偏移. 首个成员变量的偏移总为 0. 第二个成员的偏移为 0 加上首个成员的大小 (一般为 4 字节). 后面成员的偏移等于它前一个成员的偏移加上前一个成员的大小. 大多数成员 (例如 DWORD, Int 和 其他的 32 位整型) 大小为 4 个字节. 把 "UInt" 替换为合适的类型, 或当成员是指针或句柄时省略.

请参阅 结构示例 了解实际用法.

已知限制

当把变量的地址（例如 &MyVar）传递给函数而此函数修改了变量内容的长度，那么后面使用这个变量可能出现错误。要解决此问题，有下面几种方法：1) 把 MyVar 作为 "Str" 参数而不是作为 Ptr/地址传递；1) 在 v1.0.44.03+，在调用 DllCall 后使用 VarSetCapacity(MyVar, -2) 来更新变量的内部容量。

由函数保存到变量中的任何二进制零会隐藏这个零右边的所有数据; 即这样的数据无法被大多数命令和函数访问或修改. 但是, 这样的数据可以使用 地址运算符 和 NumPut/NumGet 以及 DllCall 自己进行操作.

当一个字符串传递给一个返回此字符串地址的函数后, 此函数可能会出乎意料地返回一个地址不同内容相同的字符串. 例如在编程语言中调用 CharLower(CharUpper(MyVar)) 将把 MyVar 的内容转换成小写形式。但当使用 DllCall() 进行相同操作时，在后面的调用操作后 MyVar 将是小写的，因为 CharLower 对一个内容与 MyVar 相同而地址不同的临时字符串进行操作：

MyVar = ABC
result := DllCall("CharLower", str, DllCall("CharUpper", Str, MyVar, Str), Str)

要变通解决此问题, 请把上面两个带下划线的 "Str" 修改成 Ptr. 这种情况说明了 CharUpper 的返回值为纯地址并作为整型传递给 CharLower.

处理字符串时可能遇到某些限制. 更多细节请参阅 脚本兼容性。

组件对象模型 (COM)

在 VBScript 和其他类似语言中可访问的 COM 对象在 AutoHotkey 中一般可以通过 ComObjCreate、ComObjGet 或 ComObjActive 以及内置的对象语法进行访问。

不支持 IDispatch 的 COM 对象可以通过从对象接口的虚函数表中获取函数的地址用于 DllCall 中. 想了解更多细节, 请参阅较远后面的 这个例子.

许多 .NET Framework 也可以使用 COM 和 DllCall 进行访问. 请参阅 http://www.autohotkey.com/forum/topic26191.html.

相关

脚本兼容性, PostMessage, OnMessage(), RegisterCallback(), Run, VarSetCapacity, 函数, SysGet, MSDN Library

示例

; 例子: 调用 Windows API 函数 "MessageBox" 并报告用户按下了哪个按钮.

WhichButton := DllCall("MessageBox", "Int", "0", "Str", "Press Yes or No", "Str", "Title of box", "Int", 4)
MsgBox You pressed button #%WhichButton%.
; 例子: 改变壁纸为指定的位图 (.bmp) 文件.

DllCall("SystemParametersInfo", UInt, 0x14, UInt, 0, Str, A_WinDir . "\winnt.bmp", UInt, 2)
; 例子: 调用 API 函数 "IsWindowVisible" 来判断记事本窗口是否可见.

DetectHiddenWindows On
if not DllCall("IsWindowVisible", "Ptr", WinExist("Untitled - Notepad"))  ; WinExist() 返回 HWND.
    MsgBox The window is not visible.
; 例子: 调用 API 的 wsprintf() 来给数字 432 加上前导零以填充到 10 个字符的长度 (0000000432).

VarSetCapacity(ZeroPaddedNumber, 20)  ; 确保变量的容量足够大以便容纳新的字符串.
DllCall("wsprintf", "Str", ZeroPaddedNumber, "Str", "%010d", "Int", 432, "Cdecl")  ; 需要 Cdecl 调用约定.
MsgBox %ZeroPaddedNumber%
; 例子: 演示 QueryPerformanceCounter(), 它提供了比 A_TickCount 的 10ms 更高的精确度.

DllCall("QueryPerformanceCounter", "Int64*", CounterBefore)
Sleep 1000
DllCall("QueryPerformanceCounter", "Int64*", CounterAfter)
MsgBox % "Elapsed QPC time is " . CounterAfter - CounterBefore
; 例子: 这是个临时减慢鼠标移动速度的热键, 这样有助于准确定位.
; 按住 F1 来降低鼠标速度. 释放后则恢复原来的速度.

F1::
SPI_GETMOUSESPEED = 0x70
SPI_SETMOUSESPEED = 0x71
; 获取鼠标当前的速度以便稍后恢复:
DllCall("SystemParametersInfo", UInt, SPI_GETMOUSESPEED, UInt, 0, UIntP, OrigMouseSpeed, UInt, 0)
; 现在在倒数第二个参数中设置较低的速度 (范围为 1-20, 10 是默认值):
DllCall("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, Ptr, 3, UInt, 0)
KeyWait F1  ; 这里避免了由于键盘的重复特性导致再次执行 DllCall.
return

F1 up::DllCall("SystemParametersInfo", UInt, 0x71, UInt, 0, Ptr, OrigMouseSpeed, UInt, 0)  ; 恢复原来的速度.
; 例子: 当传递窗口的唯一 ID 和其中某个控件的文本或 ClassNN,
; 下面的函数会返回此控件的 HWND (唯一 ID).
; v1.0.43.06+: 此函数已经被下面的命令取代, 这个命令执行地更准确.

ControlGet, OutputVar, Hwnd,, ClassNN, WinTitle
; 例子: 监视活动窗口并显示在它的焦点控件中垂直滚动条
; 的位置 (并实时更新). 此脚本需要 v1.0.43.06+，因为其中使用了 ControlGet Hwnd。

#Persistent
SetTimer, WatchScrollBar, 100
return

WatchScrollBar:
ActiveWindow := WinExist("A")
if not ActiveWindow  ; 没有活动窗口。
    return
ControlGetFocus, FocusedControl, ahk_id %ActiveWindow%
if not FocusedControl  ; 没有焦点控件.
    return
; 在工具提示中显示垂直或水平滚动条的位置:
ControlGet, ChildHWND, Hwnd,, %FocusedControl%, ahk_id %ActiveWindow%
ToolTip % DllCall("GetScrollPos", "Ptr", ChildHWND, "Int", 1)  ;  最后一个参数 1 表示 SB_VERT, 而 0 表示 SB_HORZ.
return
; 示例: 这是个可运行脚本, 它写入一些文本到文件, 然后从文件读取回内存 (需要 v1.0.34+).
; 在同时读取或写入多个文件时使用这种方法可以改善性能.
; 在 AHK_L 42+, 使用 FileOpen 可以实现同样的目的.

FileSelectFile, FileName, S16,, Create a new file:
if FileName =
    return
GENERIC_WRITE = 0x40000000  ; 以写入而不是读取的方式打开文件.
CREATE_ALWAYS = 2  ; 创建新文件 (覆盖任何现有的文件).
hFile := DllCall("CreateFile", Str, FileName, UInt, GENERIC_WRITE, UInt, 0, Ptr, 0, UInt, CREATE_ALWAYS, UInt, 0, Ptr, 0, Ptr)
if not hFile
{
    MsgBox Can't open "%FileName%" for writing.
    return
}
TestString = This is a test string.`r`n  ; 通过这种方式写入内容到文件时, 要使用 `r`n 而不是 `n 来开始新行.
DllCall("WriteFile", Ptr, hFile, Str, TestString, UInt, StrLen(TestString), UIntP, BytesActuallyWritten, Ptr, 0)
DllCall("CloseHandle", Ptr, hFile)  ; 关闭文件.

; 现在已经把内容写入文件了, 重新把它们读取回内存中.
GENERIC_READ = 0x80000000  ; 以读取而不是写入的方式来打开文件.
OPEN_EXISTING = 3  ; 此标志表示要打开的文件必须已经存在.
FILE_SHARE_READ = 0x1 ; 这个和下一个标志表示其他进程是否可以打开我们已经打开的文件.
FILE_SHARE_WRITE = 0x2
hFile := DllCall("CreateFile", Str, FileName, UInt, GENERIC_READ, UInt, FILE_SHARE_READ|FILE_SHARE_WRITE, Ptr, 0, UInt, OPEN_EXISTING, UInt, 0, Ptr, 0)
if not hFile
{
    MsgBox Can't open "%FileName%" for reading.
    return
}
; 清空变量以便进行测试, 但需要确保它含有足够的容量:
BytesToRead := VarSetCapacity(TestString, StrLen(TestString))
DllCall("ReadFile", Ptr, hFile, Str, TestString, UInt, BytesToRead, UIntP, BytesActuallyRead, Ptr, 0)
DllCall("CloseHandle", Ptr, hFile)  ; 关闭文件.
MsgBox The following string was read from the file: %TestString%
; 例子: 当您按下 Win+C 时隐藏鼠标光标. 再次按下 Win+C 显示.
; 此脚本来自 www.autohotkey.com/forum/topic6107.html

OnExit, ShowCursor  ; 确保到脚本退出时鼠标光标是显示的.
return

ShowCursor:
SystemCursor("On")
ExitApp

#c::SystemCursor("Toggle")  ; Win+C 热键用来切换鼠标光标的显示和隐藏.

SystemCursor(OnOff=1)   ; 初始化 = "I","Init"; 隐藏 = 0,"Off"; 切换 = -1,"T","Toggle"; 显示 = 其他
{
    static AndMask, XorMask, $, h_cursor
        ,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13 ; 系统指针
        , b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13   ; 空白指针
        , h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13   ; 默认指针的句柄
    if (OnOff = "Init" or OnOff = "I" or $ = "")       ; 在请求或首此调用时进行初始化
    {
        $ = h                                          ; 活动的默认指针
        VarSetCapacity( h_cursor,4444, 1 )
        VarSetCapacity( AndMask, 32*4, 0xFF )
        VarSetCapacity( XorMask, 32*4, 0 )
        system_cursors = 32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650
        StringSplit c, system_cursors, `,
        Loop %c0%
        {
            h_cursor   := DllCall( "LoadCursor", "Ptr",0, "Ptr",c%A_Index% )
            h%A_Index% := DllCall( "CopyImage", "Ptr",h_cursor, "UInt",2, "Int",0, "Int",0, "UInt",0 )
            b%A_Index% := DllCall( "CreateCursor", "Ptr",0, "Int",0, "Int",0
                , "Int",32, "Int",32, "Ptr",&AndMask, "Ptr",&XorMask )
        }
    }
    if (OnOff = 0 or OnOff = "Off" or $ = "h" and (OnOff < 0 or OnOff = "Toggle" or OnOff = "T"))
        $ = b  ; 使用空白指针
    else
        $ = h  ; 使用保存的指针

    Loop %c0%
    {
        h_cursor := DllCall( "CopyImage", "Ptr",%$%%A_Index%, "UInt",2, "Int",0, "Int",0, "UInt",0 )
        DllCall( "SetSystemCursor", "Ptr",h_cursor, "UInt",c%A_Index% )
    }
}
; 结构的例子: 把 RECT 结构的地址传递给 GetWindowRect(), 它会把
; 窗口的左, 上, 右和下边的位置 (相对于屏幕) 存入结构的成员中.

Run Notepad
WinWait Untitled - Notepad  ; 这里同时设置了 "上次找到的窗口" 以用于下面的 WinExist().
VarSetCapacity(Rect, 16)  ; RECT 结构由四个 32 位整数组成 (即 4*4=16).
DllCall("GetWindowRect", Ptr, WinExist(), Ptr, &Rect)  ; WinExist() 返回 HWND.
MsgBox % "Left " . NumGet(Rect, 0, "Int") . " Top " . NumGet(Rect, 4, "Int")
    . " Right " . NumGet(Rect, 8, "Int") . " Bottom " . NumGet(Rect, 12, "Int")
; 结构的例子: 把 RECT 结构的地址传递给 FillRect(), 这个
; 结构表示需要临时描绘为红色的屏幕区域.

VarSetCapacity(Rect, 16, 0)  ; 设置容量为 4 个的 4 字节整型并把它们都初始化为零.
NumPut(A_ScreenWidth//2, Rect, 8, "Int")  ; 结构中的第三个整数是 "rect.right".
NumPut(A_ScreenHeight//2, Rect, 12, "Int") ; 结构中的第四个整数是 "rect.bottom".
hDC := DllCall("GetDC", "Ptr", 0, "Ptr")  ; 传递零来获取桌面的设备上下文.
hBrush := DllCall("CreateSolidBrush", "UInt", 0x0000FF, "Ptr")  ; 创建红色画刷 (0x0000FF 是 BGR 格式).
DllCall("FillRect", "Ptr", hDC, "Ptr", &Rect, "Ptr", hBrush)  ;  使用上面的画刷填充指定的矩形.
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)  ; 清理.
DllCall("DeleteObject", "Ptr", hBrush)  ; 清理.
; 结构的例子: 改变系统的时钟为指定的日期和时间. 请注意
; 改变时间为将来的日期可能会导致计划任务提早运行!

SetSystemTime("20051008142211")  ; 传递 时间戳 (本地的, 非 UTC).

SetSystemTime(YYYYMMDDHHMISS)
; 设置系统时钟为指定的日期和时间.
; 调用者必须确保传入的参数是有效的日期时间戳
; (本地时间, 非 UTC). 成功时返回非零值, 否则返回零.
{
    ; 把参数从本地时间转换为 UTC 以便用于 SetSystemTime().
    UTC_Delta -= A_NowUTC, Seconds  ; 取整后秒数会更精确.
    UTC_Delta := Round(-UTC_Delta/60)  ; 取整到最近的分钟数以确保精度.
    YYYYMMDDHHMISS += UTC_Delta, Minutes  ; 对本地时间应用偏移来转换到 UTC.

    VarSetCapacity(SystemTime, 16, 0)  ; 此结构由 8 个 UShort 组成 (即 8*2=16).

    StringLeft, Int, YYYYMMDDHHMISS, 4    ; YYYY (年份)
    NumPut(Int, SystemTime, 0, "UShort")
    StringMid, Int, YYYYMMDDHHMISS, 5, 2  ; MM (年中的月数, 1-12)
    NumPut(Int, SystemTime, 2, "UShort")
    StringMid, Int, YYYYMMDDHHMISS, 7, 2  ; DD (月中的天数)
    NumPut(Int, SystemTime, 6, "UShort")
    StringMid, Int, YYYYMMDDHHMISS, 9, 2  ; HH (24 小时制的小时数)
    NumPut(Int, SystemTime, 8, "UShort")
    StringMid, Int, YYYYMMDDHHMISS, 11, 2 ; MI (分钟数)
    NumPut(Int, SystemTime, 10, "UShort")
    StringMid, Int, YYYYMMDDHHMISS, 13, 2 ; SS (秒数)
    NumPut(Int, SystemTime, 12, "UShort")

    return DllCall("SetSystemTime", Ptr, &SystemTime)
}
/* 更多结构的例子:

1) 请参阅 WinLIRC 客户端脚本 演示来学习如何使用 DllCall() 来创建
到 TCP/IP 服务器的连接并从那里接收数据.

2) 操作系统提供了标准的对话框让用户选取字体和/或颜色或图标.
这些对话框使用了结构, 并可以在这里找到演示的例子: www.autohotkey.com/forum/topic17230.html.

*/
/*
  例子: 使用 COM 从任务栏暂时地移除活动窗口.

  ITaskbarList 的 VTable 中的方法:
    IUnknown:
      0 QueryInterface  -- 使用 ComObjQuery 代替
      1 AddRef          -- 使用 ObjAddRef 代替
      2 Release         -- 使用 ObjRelease 代替
    ITaskbarList:
      3 HrInit
      4 AddTab
      5 DeleteTab
      6 ActivateTab
      7 SetActiveAlt
*/
IID_ITaskbarList  := "{56FDF342-FD6D-11d0-958A-006097C9A090}"
CLSID_TaskbarList := "{56FDF344-FD6D-11d0-958A-006097C9A090}"

; 创建 TaskbarList 对象并把它的地址保存到 tbl。
tbl := ComObjCreate(CLSID_TaskbarList, IID_ITaskbarList)

activeHwnd := WinExist("A")

DllCall(vtable(tbl,3), "ptr", tbl)                     ; tbl.HrInit()
DllCall(vtable(tbl,5), "ptr", tbl, "ptr", activeHwnd)  ; tbl.DeleteTab(activeHwnd)
Sleep 3000
DllCall(vtable(tbl,4), "ptr", tbl, "ptr", activeHwnd)  ; tbl.AddTab(activeHwnd)

; 非 dispatch 对象总是需要手动释放。
ObjRelease(tbl)

vtable(ptr, n) {
    ; NumGet(ptr+0) 返回对象的虚函数表
    ; (简称为 vtable) 的地址. 表达式的其余部分从
    ; vtable 中获取第 n 个函数的地址.
    return NumGet(NumGet(ptr+0), n*A_PtrSize)
}


NumGet

返回在指定地址+偏移的位置存储的二进制数。

Number := NumGet(VarOrAddress [, Offset = 0][, Type = "UPtr"])

参数

VarOrAddress

内存地址或变量。如果 VarOrAddress 是类似 MyVar 的变量且它的值不是纯数字或对象，则相当于传递 &MyVar。然而，省略“&”可以执行的更好并确保目标地址+偏移是有效的。

Offset

偏移（单位为字节），添加到 VarOrAddress 以确定目标地址。

类型

下列字符串的其中一个（省略时默认为 UPtr）：
UInt、Int、Int64、Short、UShort、Char、UChar、Double、Float、Ptr 或 UPtr

与 DllCall 不同的是，作为原义字符串使用时必须括在引号中。

更多细节请参阅 DllCall 类型。

返回值

如果目标地址无效，则返回空字符串。然而，某些无效地址这里无法检测出来并可能导致不可预知的行为。

其他情况下返回指定地址+偏移的数字。

一般说明

如果只使用了三个参数，则第三个参数可以为 Offset 或 Type。例如，NumPut(x, var, "int") 是有效的。

相关

NumPut, DllCall, VarSetCapacity


NumPut

以二进制格式把数字存储到指定地址+偏移的位置。

NumPut(Number, VarOrAddress [, Offset = 0][, Type = "UPtr"])

参数

数字

要保存的数字。

VarOrAddress

内存地址或变量。如果 VarOrAddress 是类似 MyVar 的变量且它的值不是纯数字或对象，则相当于传递 &MyVar。然而，省略“&”可以执行的更好并确保目标地址+偏移是有效的。

Offset

偏移（单位为字节），添加到 VarOrAddress 以确定目标地址。

类型

下列字符串的其中一个（省略时默认为 UPtr）：
UInt、Int、Int64、Short、UShort、Char、UChar、Double、Float、Ptr 或 UPtr

与 DllCall 不同的是，作为原义字符串使用时必须括在引号中。

更多细节请参阅 DllCall 类型。

返回值

如果目标地址无效，则返回空字符串。然而，某些无效地址这里无法检测出来并可能导致不可预知的行为。

其他情况下则返回刚写入项右边的地址。常用于写入不同类型的一序列数字，例如在 DllCall 中使用的结构。

一般说明

如果整数太大而无法用指定的 Type 存储，那么它的高位会被忽略：例如 NumPut(257, var, 0, "Char") 将存储数字 1。

如果只使用了三个参数，则第三个参数可以为 Offset 或 Type。例如，NumPut(x, var, "int") 是有效的。

相关

NumGet, DllCall, VarSetCapacity


RegisterCallback

RegisterCallback() [v1.0.47+]

创建机器码地址，当它被调用时会重定向到脚本中的函数。

Address := RegisterCallback("FunctionName" [, Options = "", ParamCount = FormalCount, EventInfo = Address])

参数

Address

成功时，RegisterCallback() 返回一个数值地址，它可以被 DllCall() 或其他能调用机器码函数的东西调用。失败时, 它返回空字符串. 当 FunctionName 出现下列情况时会引起失败：1) 不存在；2) 接收到比 ParamCount 过多或过少的参数；或 3) 接收到任何一个 ByRef 参数。

FunctionName

函数 名, 如果是原义的字符串, 则必须包围在双引号中. 每当调用 Address 时会自动调用此函数. 此函数同时会接收到传递给 Address 的参数.

[v1.1.06+]: 可以传递 函数引用 来代替函数名.

选项

指定零个或多个下列单词. 在选项间使用空格分隔（例如C Fast）。

Fast 或 F: 避免每次调用 FunctionName 时都启动新 线程. 尽管这样执行的更好, 但必须避免调用 Address 的线程发生变化 (例如当回调函数被传入的消息触发时). 这是因为 FunctionName 能改变在它被调用时刚好在运行的线程的全局设置 (例如 ErrorLevel, A_LastError 和 上次找到的窗口). 想了解更多细节, 请参阅 备注.

CDecl 或 C：让 Address 遵循“C”调用约定。此选项通常省略, 因为在回调函数中标准调用约定更常用.

ParamCount

Address 的调用者会传递给它的参数数目. 如果完全省略, 则它默认为 FunctionName 的 定义 中强制参数的数目. 在这两种情况中, 必须确保调用者准确传递此数目的参数.

EventInfo

每当通过此 Address 调用 FunctionName 时, 它将在 A_EventInfo 中看到这个整数. 这可用于一个 FunctionName 同时被多个 Address 调用时. 如果省略, 则它默认为 Address. 注: 与其他全局设置不同, 当前线程 的 A_EventInfo 不会受到 快速模式 的干扰.

如果运行当前脚本的主程序为 32 位, 那么此参数必须介于 0 和 4294967295 之间. 如果主程序为 64 位, 那么此参数可以为 64 位整数. 尽管 A_EventInfo 通常返回无符号整数, 但由于 AutoHotkey 不完全支持 64 位无符号整数, 因此对这个值进行某些操作可能让它溢出从而进入有符号整数的范围.

回调函数的参数

分配了回调地址的 函数 可以接受多达 31 个参数. 允许有 可选参数, 这可用于函数被多个调用者调用时.

32 位: 所有传入参数都是 32 位无符号整数. 如果某个传入参数应该为有符号整数, 则可以参照下面的其中一个例子得到负数:

; 方法 #1
if wParam > 0x7FFFFFFF
    wParam := -(~wParam) - 1

; 方法 #2: 依赖于 AutoHotkey 原生使用 64 位有符号整数的事实.
wParam := wParam << 32 >> 32

64 位: 所有传入参数都是 64 位有符号整数. AutoHotkey 没有对 64 位无符号整数的原生支持.

如果某个传入参数应该为字符串, 那么它实际接收的是这个字符串的地址. 要获取这样的字符串, 请使用 StrGet:

MyString := StrGet(MyParameter)  ; AHK_L 46+

如果某个传入参数为结构的地址, 则可以参照 DllCall 结构 中描述的步骤提取其中的各个成员.

[AHK_L 60+]: 如果函数声明为 可变参数的, 那么它的最后一个参数被赋值为首个没有赋值给脚本参数的回调参数 地址. 例如：

callback := RegisterCallback("Func", "F", 1)  ; 不必指定参数数目.
Func("Func was called directly.")  ; 直接调用 Func.
DllCall(callback, float, 10.5)  ; 通过回调调用 Func.
Func(params*) {
    if IsObject(params)
        MsgBox % params[1]
    else
        MsgBox % NumGet(params+0, 0, "float")
}

大部分回调使用 stdcall 调用约定, 这种方式需要固定的参数数目. 在大多数情况中, 在创建回调时必须指定 ParamCount. 在 64 位版本或 32 位版本的 Cdecl 回调中, ParamCount 可以省略, 此时所有可选参数接收它们的默认值且在计算保存在 params 中的地址时被忽略.

函数应该 返回 什么

如果函数使用不带任何参数的 Return, 或指定空值如 "" (甚至从不使用 Return), 则返回 0 给 Address 的调用者. 否则, 函数应该返回一个介于 -2147483648 和 4294967295 之间的整数, 它会被返回给 Address 的调用者.

快速与慢速

默认/慢速的模式会让函数以设置的默认值启动, 例如 SendMode 和 DetectHiddenWindows. 这些默认值可以在 自动执行段 改变.

与之相比, 快速模式 会继承在调用函数时刚好在运行的 线程 的全局设置. 而且, 函数对全局设置的任何修改 (包括 ErrorLevel 和 上次找到的窗口) 都会在 当前线程 生效. 因此, 快速模式应该只在确切知道函数会被哪个线程调用时才使用.

要避免被自己 (或其他任何线程) 中断, 回调函数可以在它的首行使用 Critical. 然而, 通过小于 0x312 消息达到的间接调用函数时, 这并不是完全有效的 (增加 Critical 的 间隔 也许有帮助). 而且, Critical 不会阻止执行一些可能导致间接调用它自己的动作, 例如调用 SendMessage 或 DllCall.

内存

每次使用 RegisterCallback() 都会分配少量的内存 (32 字节加上系统开销). 由于当脚本退出时操作系统会自动释放这些内存, 所以任何分配少量 固定 数目的回调的脚本不需要明确地释放内存. 与之相比, 调用 RegisterCallback() 不确定/无限制次数的脚本应明确对任何不使用的回调执行下列操作:

DllCall("GlobalFree", "Ptr", Address, "Ptr")

相关

DllCall(), OnMessage(), OnExit, OnClipboardChange, Sort 的回调, Critical, Post/SendMessage, 函数, Windows 消息列表, 线程

示例

; 示例: 下面是个可运行脚本, 它显示了所有顶层窗口的摘要.

; 考虑到性能和内存的保持, 只为指定的回调调用一次 RegisterCallback():
if not EnumAddress  ; 由于只能从这个线程调用, 所以可以使用快速模式:
    EnumAddress := RegisterCallback("EnumWindowsProc", "Fast")

DetectHiddenWindows On  ; 由于是快速模式, 所以此设置也会在回调中生效.

; 把控制传给 EnumWindows(), 它会重复调用回调:
DllCall("EnumWindows", Ptr, EnumAddress, Ptr, 0)
MsgBox %Output%  ; 显示由回调收集的信息.

EnumWindowsProc(hwnd, lParam)
{
    global Output
    WinGetTitle, title, ahk_id %hwnd%
    WinGetClass, class, ahk_id %hwnd%
    if title
        Output .= "HWND: " . hwnd . "`tTitle: " . title . "`tClass: " . class . "`n"
    return true  ; 告知 EnumWindows() 继续执行, 一直到枚举完所有的窗口.
}

; 示例: 下面是个可运行脚本, 它演示了如何在脚本中通过把 GUI 窗口的
; WindowProc 重定向到新的 WindowProc 来子类化窗口. 此时, 文本控件的
; 背景颜色被改变为自定义颜色.

TextBackgroundColor := 0xFFBBBB  ; BGR 格式的自定义颜色.
TextBackgroundBrush := DllCall("CreateSolidBrush", UInt, TextBackgroundColor)

Gui, Add, Text, HwndMyTextHwnd, Here is some text that is given`na custom background color.
Gui +LastFound
GuiHwnd := WinExist()

; 64 位脚本必须调用 SetWindowLongPtr 代替 SetWindowLong:
SetWindowLong := A_PtrSize=8 ? "SetWindowLongPtr" : "SetWindowLong"

WindowProcNew := RegisterCallback("WindowProc", ""  ; 指定 "" 来避免子类化中使用快速模式.
    , 4, MyTextHwnd)  ; 使用了 EventInfo 参数时必须明确指定 ParamCount.
WindowProcOld := DllCall(SetWindowLong, Ptr, GuiHwnd, Int, -4  ; -4 是 GWL_WNDPROC
    , Ptr, WindowProcNew, Ptr) ; 返回值必须设置为 Ptr 或 UPtr 而不是 Int.

Gui Show
return

WindowProc(hwnd, uMsg, wParam, lParam)
{
    Critical
    global TextBackgroundColor, TextBackgroundBrush, WindowProcOld
    if (uMsg = 0x138 && lParam = A_EventInfo)  ; 0x138 为 WM_CTLCOLORSTATIC.
    {
        DllCall("SetBkColor", Ptr, wParam, UInt, TextBackgroundColor)
        return TextBackgroundBrush  ; 返回 HBRUSH 来通知操作系统我们改变了 HDC.
    }
    ; 否则 (如果上面没有返回), 传递所有的未处理事件到原来的 WindowProc.
    return DllCall("CallWindowProc", Ptr, WindowProcOld, Ptr, hwnd, UInt, uMsg, Ptr, wParam, Ptr, lParam)
}

GuiClose:
ExitApp


StrPut / StrGet

StrPut() / StrGet() [AHK_L 46+]

复制字符串到内存地址或来自内存地址, 并可以对其在指定代码页间进行转换.

StrPut(String [, Encoding = None ] )
StrPut(String, Address [, Length] [, Encoding = None ] )
StrGet(Address [, Length] [, Encoding = None ] )

参数

String

任何字符串. 也可以接受数字.

Address

字符串将被写入或读取的地址.

Length

需读取/写入的字符的最大数目, 需要时包含空终止符. 请参阅返回值。

Encoding

用于 StrGet 的源编码或用于 StrPut 的目标编码; 例如, "UTF-8", "UTF-16" 或 "CP936". 如果 Address 和 Length 都没有指定, 那么数值标识符必须加上 "CP" 前缀. 指定空字符串或 "CP0" 则使用系统默认 ANSI 代码页.

返回值

对每个函数, 无效的参数会让它们返回空字符串.

StrPut 返回写入的字符数, 如果没有指定 Address 则返回以字符数表示的必须的缓冲区大小, 如果遇到错误则返回 0. 如果 Length 小于源字符串的长度, 那么函数失败且返回 0. 如果 Length 准确等于源字符串的长度, 那么字符串不包含空终止符; 否则返回的数目包含空终止符.

StrGet 返回所请求的进行必要转换后的字符串.

备注

注意 StrPut 的 String 参数或 StrGet 的返回值总是为当前可执行程序的 原生编码, 而 Encoding 则指定写入的或从指定 Address 读取的字符串编码. 如果未指定 Encoding, 则对字符串进行简单长度计算或复制而不进行转换.

如果需要在代码页之间转换, 那么需要的缓存大小可能不同于源 String 的大小.

需要兼容于 AutoHotkey Basic 的脚本仍可以使用 StrPut 和 StrGet, 此时它们是由安装在 函数库 中的 相应的脚本文件 提供的. 这些脚本可以在 AutoHotkey 社区论坛 中找到.

相关

脚本兼容性, FileEncoding, VarSetCapacity()

示例

Length 或 Encoding 都可以在 Address 后直接指定, 不过此时 Encoding 必须用非数值表示:

strA := StrGet(addressA, "cp0")     ; OK
strA := StrGet(addressA, length, 0) ; OK
strA := StrGet(addressA, 0)         ; 错误

可以调用一次 StrPut 来计算字符串在特殊编码时需要的缓冲区大小, 然后再进行编码并把字符串写入缓冲区. 如果您常用 StrPut 操作变量, 那么考虑把此函数添加到您 库 中:

StrPutVar(string, ByRef var, encoding)
{
    ; 确定容量.
    VarSetCapacity( var, StrPut(string, encoding)
        ; StrPut 返回字符数, 但 VarSetCapacity 需要字节数.
        * ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
    ; 复制或转换字符串.
    return StrPut(string, &var, encoding)
}


ComObjActive()

ComObjActive() [AHK_L 53+]

检索已注册到 OLE 的正在运行的对象.

ComObject := ComObjActive(CLSID)

创建表示作为参数或返回值传递的类型化值的对象.

ParamObj := ComObjParameter(VarType, Value [, Flags])

创建在调用 COM 对象的方法时可以用来代替可选参数默认值的对象.

ParamObj := ComObjMissing()

高级

包装或解开可用对象中的原始 IDispatch 指针.

ComObject := ComObjEnwrap(DispPtr)
DispPtr := ComObjUnwrap(ComObject)

参数

CLSID

要检索的 COM 对象的 CLSID 或可读 Prog ID.

ComObject

可以使用 对象语法 的 COM 对象.

VarType

表示值类型的整数. 请参阅 ComObjType() 了解类型列表.

值

要包装的值. 当前仅支持整数值和指针值.

Flags

影响此函数和包装器对象行为的标志，请参阅后面。

DispPtr

原始的 IDispatch 指针.

Flags

0 | 默认行为. 为 IUnknown 和 IDispatch 指针自动调用 AddRef, 所以调用者应该在适当时使用 ObjRelease 释放这些指针副本.
1 | 取得 IUnknown, IDispatch 或 SAFEARRAY 指针的所有权. 不调用 AddRef. 如果包装器对象包含 SAFEARRAY (VT_BYREF 除外), 那么当包装器对象被释放时会自动调用 SafeArrayDestroy.

一般说明

ComObjActive 是 多态的; 即任何名称以 "ComObj" 开始且不匹配其他某个 COM 函数的函数调用实际在调用 ComObjActive. 例如, ComObj(9, DispPtr) 和 ComObjActive(DispPtr) 都等同于 ComObjEnwrap(DispPtr). 然而, 在未来的版本中此特性可能发生变化 (或实现了新的函数), 所以最好仅显示此页面中演示的形式, 此外 "ComObject" 可以用来代替 ComObjEnwrap 或 ComObjParameter.

当使用此函数包装或检索 IDispatch 或 IUnknown 接口指针时, 默认的行为会增加 COM 对象的引用数. 一般而言, 脚本中指针的原始副本被视为独立的引用, 当不再需要时必须在脚本中对其进行 手动释放. 释放包装器对象时, 也会同时释放其到 COM 对象的引用.

已知限制: 每次包装 COM 对象时, 都会创建新的包装器对象. 比较和赋值运算中, 例如 obj1 == obj2 和 array[obj1] := value, 会把两个包装器对象视为唯一的, 即使它们包含相同的 COM 对象.

相关

ComObjCreate, ComObjGet, ComObjConnect, ComObjError, ComObjFlags, ObjAddRef/ObjRelease, ComObjQuery, GetActiveObject (MSDN)

示例

ComObjUnwrap: 请参阅 ComObjConnect.

; 示例: 传递 VARIANT ByRef 到 COM 函数.

code =
(
Sub Example(Var)
    MsgBox Var
    Var = "out value!"
End Sub
)
sc := ComObjCreate("ScriptControl"), sc.Language := "VBScript", sc.AddCode(code)

var := ComVar()
var[] := "in value"
sc.Run("Example", var.ref)
MsgBox % var[]

; ComVar: 创建用来传递 ByRef 值的对象.
;   ComVar[] 检索值.
;   ComVar[] := Val 设置值.
;   ComVar.ref 检索 ByRef 对象用于传递到 COM 函数.
ComVar(Type=0xC)
{
    static base := { __Get: "ComVarGet", __Set: "ComVarSet", __Delete: "ComVarDel" }
    ; 创建含 1 个 VARIANT 类型变量的数组.  此方法可以让内部代码处理
    ; 在 VARIANT 和 AutoHotkey 内部类型之间的所有转换.
    arr := ComObjArray(Type, 1)
    ; 锁定数组并检索到 VARIANT 的指针.
    DllCall("oleaut32\SafeArrayAccessData", "ptr", ComObjValue(arr), "ptr*", arr_data)
    ; 保存可用于传递 VARIANT ByRef 的数组和对象.
    return { ref: ComObjParameter(0x4000|Type, arr_data), _: arr, base: base }
}
ComVarGet(cv, p*) { ; 当脚本访问未知字段时调用.
    if p.MaxIndex() = "" ; 没有名称/参数, 即 cv[]
        return cv._[0]
}
ComVarSet(cv, v, p*) { ; 当脚本设置未知字段时调用.
    if p.MaxIndex() = "" ; 没有名称/参数, 即 cv[]:=v
        return cv._[0] := v
}
ComVarDel(cv) { ; 当对象被释放时调用.
    ; 必须进行这样的处理以释放内部数组.
    DllCall("oleaut32\SafeArrayUnaccessData", "ptr", ComObjValue(cv._))
}


ComObjArray()

ComObjArray() [v1.0.91+]

创建用于 COM 的 SafeArray.

ArrayObj := ComObjArray(VarType, Count1 [, Count2, ... Count8])

参数

VarType
数组的基类型 (数组中每个元素的 VARTYPE). VARTYPE 被限制为变量类型的子集. 不能设置为 VT_ARRAY 和 VT_BYREF. 对于数组的基类型 VT_EMPTY 和 VT_NULL 都是无效的. 其他所有类型都是合法的.

请参阅 ComObjType 了解允许值的列表.

CountN

每个维度的大小。可以支持多达 8 维的数组.

ArrayObj

包含 SafeArray 的包装器对象.

方法

数组包装器对象支持下列方法:

Array.MaxIndex(n): 返回第 n 维的上界. 如果 n 省略, 默认为 1.

Array.MinIndex(n): 返回第 n 维的下界. 如果 n 省略, 默认为 1.

Array.Clone() [v1.0.96.00+]: 返回数组的副本.

Array._NewEnum() [v1.0.96.00+]: 通常不是由脚本调用; 允许 for 循环 和 SafeArray 一起使用.

一般说明

COM 方法和 ComObjActive 也可以返回数组包装器对象. 脚本中可以使用如下方法判断一个值是否为数组:

if ComObjType(obj) & 0x2000
    MsgBox % "Array subtype: " . ComObjType(obj) & 0xfff
else
    MsgBox Not an array.

可以支持多达 8 维的数组.

[v1.0.96.00+]: 由于 SafeArray 没有设计用以支持多种引用, 当一个 SafeArray 被赋值为另一个 SafeArray 的元素时, 会创建一个独立的副本. 不过, 只有当包装器对象含有 F_OWNVALUE 标志时才会发生这种情况, 这个标志表示它负责销毁此数组. 此标志可以使用 ComObjFlags 进行移除.

相关

ComObjType, ComObjValue, ComObjActive, ComObjFlags, 数组操作函数 (MSDN)

示例

; 示例 #1：简单用法。

arr := ComObjArray(VT_VARIANT:=12, 3)
arr[0] := "Auto"
arr[1] := "Hot"
arr[2] := "key"
Loop % arr.MaxIndex() + 1
   t .= arr[A_Index-1]
MsgBox % t

; 示例 #2：多维数组。

arr := ComObjArray(VT_VARIANT:=12, 3, 4)

; 获取数组的维数个数:
dim := DllCall("oleaut32\SafeArrayGetDim", "ptr", ComObjValue(arr))

; 获取每个维数的边界:
Loop %dim%
    dims .= arr.MinIndex(A_Index) " .. " arr.MaxIndex(A_Index) "`n"
MsgBox %dims%

; 简单用法:
Loop 3 {
    x := A_Index-1
    Loop 4 {
        y := A_Index-1
        arr[x, y] := x * y
    }
}
MsgBox % arr[2, 3]


ComObjConnect()

ComObjConnect() [AHK_L 53+]

连接对象的事件源到带有给定前缀的函数.

ComObjConnect(ComObject [, Prefix])

参数

ComObject

产生事件的对象.

Prefix

用于确定当事件发生时应调用哪个函数的的事件名称前缀的字符串.

如果省略, 那么对象为 "未连接的"; 即脚本将不再接收其事件通告.

[v1.1.01+]: 此参数可以为脚本定义的对象. 事件发生时, 会调用相应的方法. 首个参数, 通常为隐藏的 this 参数, 引用脚本定义的对象, 而不是 COM 对象. 要不为每个事件定义方法而捕获所有事件, 请定义 __Call 元函数.

用法

要让 ComObjConnect 有意义, 首先您必须在脚本中编写处理任何感兴趣事件的函数. 这类函数或 "事件处理程序" 具有下列结构:

PrefixEventName([Params..., ComObject])
{
    ... 处理事件的代码 ...
    return returnValue
}

Prefix 为您选择的前缀, 而 EventName 为函数需要处理的每种事件的名称.

Params 对应于事件包含的所有参数. 如果事件不含有参数, Params 应该完全省略. ComObject 是可选的, 并且可以在定义的 Params 数目正确时才使用; 它包含了到传递给 ComObjConnect 的原始包装器对象的引用. "ComObject" 应该替换为与您脚本上下文相关的更有意义的名称.

注意事件处理程序可以产生返回值. 要返回特定的 COM 类型的值, 请使用 ComObjParameter, 它也可以写成 ComObjRetVal(type, value) 或简化成 ComObj(type, value).

调用 ComObjConnect(yourObject, "Prefix") 来启用事件处理.

调用 ComObjConnect(yourObject) 来断开到对象的连接 (停止处理事件).

如果参数的数目未知, 那么可以使用 可变参数函数.

相关

ComObjCreate, ComObjGet, ComObjActive, ComObjConnect, ComObjError, WScript.ConnectObject (MSDN)

示例

ie := ComObjCreate("InternetExplorer.Application")

; 把事件连接到带“IE_”前缀的脚本函数。
ComObjConnect(ie, "IE_")

ie.Visible := true  ; 已知此语句在IE7上无法正常执行。
ie.Navigate("http://ahkscript.org/")
#Persistent

IE_DocumentComplete(ieEventParam, url, ieFinalParam) {
    global ie
    if (ie != ieEventParam)
        s .= "First parameter is a new wrapper object.`n"
    if (ie == ieFinalParam)
        s .= "Final parameter is the original wrapper object.`n"
    if ((disp1:=ComObjUnwrap(ieEventParam)) == (disp2:=ComObjUnwrap(ieFinalParam)))
        s .= "Both wrapper objects refer to the same IDispatch instance.`n"
    ObjRelease(disp1), ObjRelease(disp2)
    MsgBox % s . "Finished loading " ie.Document.title " @ " url
    ie.Quit()
    ExitApp
}


ComObjCreate()

ComObjCreate() [AHK_L 53+]

创建 COM 对象。

ComObject := ComObjCreate(CLSID [, IID])

参数

CLSID

要创建的 COM 对象的 CLSID 或可读 Prog ID。

IID

[v1.0.96.00+]: 对象支持的接口标识符.

返回值

如果发生了错误, 则返回空字符串.

如果指定了 IID, 则返回接口指针. 不再使用指针时通常脚本必须调用 ObjRelease.

否则, 返回脚本可以使用的包装器对象. 请参阅 对象语法.

相关

ComObjGet, ComObjActive, ComObjConnect, ComObjArray, ComObjError, ComObjQuery, CreateObject (MSDN)

示例

参阅后面的论坛主题可以看到不断增长的示例列表: http://www.autohotkey.com/forum/topic61509.html.

ie := ComObjCreate("InternetExplorer.Application")
ie.Visible := true  ; 已知此语句在IE7上无法正常执行。
ie.Navigate("http://ahkscript.org/")


ComObjGet()

ComObjGet() [AHK_L 53+]

返回由 COM 组件提供的对象引用。

ComObject := ComObjGet(Name)

参数

Name

需要获取的对象的显示名称. 请参阅 MkParseDisplayName (MSDN) 了解更多信息.

相关

ComObjCreate, ComObjActive, ComObjConnect, ComObjError, ComObjQuery, CoGetObject (MSDN)

示例

; 示例: 使用 Shift+Escape 来显示活动窗口
;   进程的命令行.  需要 XP 或更高版本.
+Esc::
    WinGet pid, PID, A
    ; 获取 WMI 服务对象.
    wmi := ComObjGet("winmgmts:")
    ; 执行查询以获取匹配进程.
    queryEnum := wmi.ExecQuery(""
        . "Select * from Win32_Process where ProcessId=" . pid)
        ._NewEnum()
    ; 获取首个匹配进程.
    if queryEnum[process]
        MsgBox 0, Command line, % process.CommandLine
    else
        MsgBox Process not found!    ; 释放所有全局对象 (使用局部变量时不需要这么做).
    wmi := queryEnum := process := ""
return
; Win32_Process: http://msdn.microsoft.com/en-us/library/aa394372.aspx


ComObjError()

ComObjError() [AHK_L 53+]

启用或禁用 COM 错误通告。

Enabled := ComObjError([Enable])

参数

Enable

布尔值 (真或假). 此参数是可选的.

Enabled

[v1.0.91+]: 保存调用函数前的实际设置.

一般说明

使用 COM 对象后, A_LastError 包含了由 COM 对象的 IDispatch::Invoke 函数返回的 HRESULT 码. 通过调用 ComObjError(false) 来禁用错误通知并检查 A_LastError 的值, 脚本可以实现自己的错误处理.

相关

ComObjCreate, ComObjGet, ComObjActive, ComObjConnect


ComObjFlags()

ComObjFlags() [v1.0.96.00+]

获取或改变控制 COM 包装器对象行为的标志。

Flags := ComObjFlags(ComObject [, NewFlags, Mask])

参数

ComObject

COM 对象包装器.

NewFlags

由 Mask 标识的或要添加或移除的新标志值.

Mask

需要改变的标志位掩码.

Flags

ComObject 的所有标志 (如果指定了 NewFlags, 则为应用后的新标志).

Flags

F_OWNVALUE
1 		当前仅对 SafeArray 有效. 如果设置了此标志, 则当包装器对象释放时销毁 SafeArray. 由于 SafeArray 没有引用计数结构, 所以当含有此标志的 SafeArray 被赋值到另一个 SafeArray 的元素时, 会创建一个独立的副本.

一般说明

如果省略 Mask, 则在 NewFlags 指定需要添加 (为正数时) 或移除 (为负数时) 的标志. 例如, ComObjFlags(obj, -1) 会移除 F_OWNVALUE 标志. 不要在 Mask 中使用 0 或 1 外的其他值, 其他所有位保留供将来使用.

相关

ComObjActive, ComObjArray

示例

; 示例: 检查是否存在 F_OWNVALUE 标志.

arr := ComObjArray(0xC, 1)
if ComObjFlags(arr) & 1
    MsgBox arr will be automatically destroyed.
else
    MsgBox arr will not be automatically destroyed.

; 示例: 改变内嵌在其他数组中的数组的行为.

arr1 := ComObjArray(0xC, 3)
arr2 := ComObjArray(0xC, 1)
arr2[0] := "original value"
arr1[0] := arr2         ; 赋值隐式副本.
ComObjFlags(arr2, -1)   ; 移除 F_OWNVALUE.
arr1[1] := arr2         ; 赋值为原始数组.
arr1[2] := arr2.Clone() ; 赋值显式副本.
arr2[0] := "new value"
for arr in arr1
    MsgBox % arr[0]

arr1 := ""
; 由于 arr2 == arr1[1], 所以后面这句无效, 它已经被销毁了:
;  arr2[0] := "foo"


ComObjQuery()

ComObjQuery() [v1.0.96.00+]

查询 COM 对象的接口或服务。

InterfacePointer := ComObjQuery(ComObject, [SID,] IID)

参数

ComObject

COM 包装器对象或原始接口指针.

IID

格式为"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" 的接口标识符 (GUID).

SID

与 IID 格式相同的服务标识符. 省略此参数时, 必须同时省略后面跟着的逗号.

一般说明

在此函数使用两个参数时, 它相当于 IUnknown::QueryInterface. 如果同时指定了 SID 和 IID, 那么它会内部查询 IServiceProvider 接口, 然后调用 IServiceProvider::QueryService. 在两种形式中, 返回值为零或到被请求接口的指针. 通常在脚本结束时必须 释放 这种指针.

相关

ObjRelease, ComObjCreate, ComObjGet, ComObjActive, ComObjError

示例

; 示例: 确定对象的类名.

obj := ComObjCreate("Scripting.Dictionary")

MsgBox % "Interface name: " ComObjType(obj, "name")

IID_IProvideClassInfo := "{B196B283-BAB4-101A-B69C-00AA00341D07}"

; 请求到对象的 IProvideClassInfo 接口的指针.
if !(pci := ComObjQuery(obj, IID_IProvideClassInfo))
{
    MsgBox IProvideClassInfo interface not supported.
    return
}

; 调用 GetClassInfo 来获取到 ITypeInfo 接口的指针.
DllCall(vtable(pci, 3), "ptr", pci, "ptr*", ti)

; 调用 GetDocumentation 来获取对象的完整类型名称.
DllCall(vtable(ti, 12), "ptr", ti, "int", -1, "ptr*", name, "ptr", 0, "ptr", 0, "ptr", 0)

; 转换 BSTR 指针为可用的字符串.
name := StrGet(name, "UTF-16")

; 释放原始接口指针.
ObjRelease(ti)
ObjRelease(pci)

; 显示类型名称!
MsgBox % "Class name: " name

vtable(ptr, n) {
    ; NumGet(ptr+0) 返回对象的虚函数表
    ; (简称为 vtable) 的地址. 表达式的其余部分从
    ; vtable 获取第 n 个函数的地址.
    return NumGet(NumGet(ptr+0), n*A_PtrSize)
}

; 示例：自动化已有的Internet Explorer窗口。

sURL := "http://ahkscript.org/boards/"
if webBrowser := GetWebBrowser()
   webBrowser.Navigate(sURL)
return

GetWebBrowser()
{
    ; 获取到顶级 IE 窗口文档对象的原始指针.
    static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
    SendMessage msg, 0, 0, Internet Explorer_Server1, ahk_class IEFrame
    if ErrorLevel = FAIL
        return  ; 未找到 IE.
    lResult := ErrorLevel
    DllCall("oleacc\ObjectFromLresult", "ptr", lResult
        , "ptr", GUID(IID_IHTMLDocument2,"{332C4425-26CB-11D0-B483-00C04FD90119}")
        , "ptr", 0, "ptr*", pdoc)

    ; 查询 WebBrowserApp 服务. 在这种特殊情况中,
    ; SID 和 IID 相同, 但不总是如此.
    static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}"
    static SID_SWebBrowserApp := IID_IWebBrowserApp
    pweb := ComObjQuery(pdoc, SID_SWebBrowserApp, IID_IWebBrowserApp)

    ; 释放文档对象指针.
    ObjRelease(pdoc)

    ; 返回包装过的可用的 WebBrowser 对象:
    static VT_DISPATCH := 9, F_OWNVALUE := 1
    return ComObject(VT_DISPATCH, pweb, F_OWNVALUE)
}

GUID(ByRef GUID, sGUID) ; 转换字符串为二进制的 GUID 并返回其地址.
{
    VarSetCapacity(GUID, 16, 0)
    return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : ""
}


ComObjType()

ComObjType() [v1.0.91+]

从 COM 对象获取类型信息。

VarType := ComObjType(ComObject)
Name    := ComObjType(ComObject, "Name")
IID     := ComObjType(ComObject, "IID")

参数

ComObject

包含 COM 对象或类型化值的包装器对象.

VarType

表示值类型的整数. 请参阅下面.

Name

接口类型名.

IID

表示接口类型的全局唯一标识符 (GUID).

返回值

如果省略第二个参数, 则返回包装器对象包含的值的变量类型.

如果第二个参数为 "Name" 或 "IID" 并且包装器对象包含 COM 对象 (变量类型 VT_DISPATCH), 则返回 COM 对象的类型名或其主接口的标识符.

如果参数无效或发生了错误, 则返回空字符串.

变量类型的常量值

VT_EMPTY     =      0  ; 没有值
VT_NULL      =      1  ; SQL 风格的空值
VT_I2        =      2  ; 16 位有符号整数
VT_I4        =      3  ; 32 位有符号整数
VT_R4        =      4  ; 32 位浮点数
VT_R8        =      5  ; 64 位浮点数
VT_CY        =      6  ; 通用
VT_DATE      =      7  ; 日期
VT_BSTR      =      8  ; COM 字符串（带长度前缀的 Unicode 字符串）
VT_DISPATCH  =      9  ; COM 对象
VT_ERROR     =    0xA  ; Error 码（32 位整数）
VT_BOOL      =    0xB  ; 布尔值真（-1）或假（0）
VT_VARIANT   =    0xC  ; VARIANT（必须与 VT_ARRAY 或 VT_BYREF 组合使用）
VT_UNKNOWN   =    0xD  ; IUnknown 接口指针
VT_DECIMAL   =    0xE  ; （不支持）
VT_I1        =   0x10  ; 8 位有符号整数
VT_UI1       =   0x11  ; 8 位无符号整数
VT_UI2       =   0x12  ; 16 位无符号整数
VT_UI4       =   0x13  ; 32 位无符号整数
VT_I8        =   0x14  ; 64 位有符号整数
VT_UI8       =   0x15  ; 64 位无符号整数
VT_INT       =   0x16  ; 有符号机器整数
VT_UINT      =   0x17  ; 无符号机器整数
VT_RECORD    =   0x24  ; 用户定义类型
VT_ARRAY     = 0x2000  ; SAFEARRAY
VT_BYREF     = 0x4000  ; 到另一种值的指针
/*
 VT_ARRAY 和 VT_BYREF 与另一个值组合在一起 (使用按位 "或")
 来指定准确的类型. 例如, 0x2003 表示 32 位有符号整数的 SAFEARRAY
 而 0x400C 表示到 VARIANT 的指针.
*/

一般说明

在通常情况下, COM 对象的方法或属性的返回值会被转换成 AutoHotkey 支持的适合的数据类型. 没有明确处理的类型通过 VariantChangeType 强制转换成字符串; 如果转换失败或变量类型包含 VT_ARRAY 或 VT_BYREF 标志, 则返回包含值和其类型的对象代替.

对于任意变量 x, 如果 ComObjType(x) 返回整数, 则 x 包含 COM 对象包装器.

相关

ComObjValue, ComObjCreate, ComObjGet, ComObjActive

示例

d := ComObjCreate("Scripting.Dictionary")
VarType := ComObjType(d)          ; 对于可脚本化对象总为 9.
Name    := ComObjType(d, "Name")  ; 仅对于可脚本化对象有效.
IID     := ComObjType(d, "IID")   ; 同上.
MsgBox Variant type:`t%VarType%`nType name:`t%Name%`nInterface ID:`t%IID%


ComObjValue()

ComObjValue() [v1.0.91+]

获取存储在 COM 包装器对象中的值或指针。

Value := ComObjValue(ComObject)

参数

值

64 位有符号整数.

ComObject

包含 COM 对象或类型化值的包装器对象.

一般说明

此函数并非计划用于一般用途.

调用 ComObjValue 等价于 variant.llVal, 这里 ComObject 被视为 VARIANT 结构. 使用此函数的脚本必须注意到包装器对象包含的 值类型 以及对它应该如何处理. 例如, 如果返回接口指针, 则不应该调用 Release, 不过根据脚本对指针进行的操作可能需要 AddRef.

相关

ComObjType, ComObjCreate, ComObjGet, ComObjActive


ObjAddRef() / ObjRelease()

ObjAddRef() / ObjRelease() [AHK_L 53+]

增加或减少对象的引用数.

ObjAddRef(Ptr)
ObjRelease(Ptr)

参数

Ptr

非托管对象指针或 COM 接口指针.

返回值

这两个函数返回新的引用数. 这个值应该 仅 用于调试的目的.

相关

尽管后面的文章讨论了适用于 COM 的引用计数, 但其中也包含了通常也适用于 AutoHotkey 对象的重要概念和规则: IUnknown::AddRef, IUnknown::Release, 引用计数规则.

示例

请参阅 ComObjConnect.

obj := Object()

; 下面的两行是等同的:
ptr1 := Object(obj)
ptr2 := ObjectToPointer(obj)

ObjectToPointer(obj) {
    if !IsObject(obj)
        return ""
    ptr := &obj
    ObjAddRef(ptr)
    return ptr
}

; 由 Object() 或 ObjectToPointer() 返回的指针必须进行手动释放,
; 这样才能最终释放对象并回收它占用的内存.
ObjRelease(ptr2)
ObjRelease(ptr1)


Drive

弹出/收进 CD 或 DVD 驱动器托盘，或设置驱动器的卷标。

Drive, Sub-command [, Drive , Value]

sub-command, drive 和 value 参数互相依赖, 它们的用法描述如下.

Label, Drive [, NewLabel]: 改变 Drive 的卷标为 NewLabel (如果省略 NewLabel, 则设置驱动器卷标为空). Drive 由驱动器字母, 跟着冒号和可选的反斜线组成 (也许对 UNC 和映射的驱动器也有效). 例如：Drive, Label, C:, Seagate200。

要获取当前卷标，请参照此例：DriveGet, OutputVar, Label, C:。

Lock, Drive: 禁用驱动器的弹出功能。例如：Drive, Lock, D:。大多数驱动器不能 "在锁定之后打开". 然而, 在驱动器打开时进行锁定可能会导致驱动器在关闭后立即进入锁定状态. 对于不支持锁定的驱动器（例如大多数只读驱动器），此命令没有效果。如果使用脚本锁定驱动器后这个脚本退出了, 那么那个驱动器会保持锁定状态, 直到另一个脚本或程序对它进行解锁, 或系统重新启动. 如果指定的驱动器不存在或不支持锁定功能, 则 ErrorLevel 被置为 1. 否则被置为 0.

Unlock, Drive: 反转上面的功能. 如果对同一驱动器锁定了多次，则需使用 Unlock 多次才能解锁（至少适用于一些驱动器）。例如，如果执行了 Drive, Lock, D: 三次，那么需要执行 Drive, Unlock, D: 三次才能解锁。由于这种情况以及并没有方法判断某个驱动器当前是否锁定的事实，所以通常需要使用变量来记录它的锁定状态。

Eject [, Drive, 1]：弹出或收回 CD 或 DVD 驱动器的托盘（要弹出其他类型的媒体或设备，请参阅在此页面底部的 DllCall 示例）。

如果省略 Drive，则默认使用 CD/DVD。要弹出托盘, 请省略最后一个参数. 要收回/关闭托盘，请在最后一个参数中指定 1；例如：Drive, Eject, D:, 1。

Drive Eject 会等待弹出或收回完成，然后才继续执行脚本。如果托盘已经处于指定的状态 (打开或关闭), 则 ErrorLevel 被置为 0 (例 "没有错误").

Drive Eject 可能对网络驱动器或非 CD/DVD 驱动器无效。如果因为这种或其他原因失败了, 则 ErrorLevel 被置为 1.

通过检测命令消耗的时间, 可以判断托盘之前的状态. 例如, 下面的热键切换托盘到相反的状态 (打开或关闭):

#c::
Drive, Eject
; 如果命令快速完成, 则托盘已经处于弹出状态.
; 在那样的情况下, 收回托盘:
if A_TimeSinceThisHotkey < 1000  ; 需要时调整这个时间值.
    Drive, Eject,, 1
return

要判断 CD 或 DVD 驱动器的媒体状态 (正在播放, 停止, 打开, 等等), 请参阅 DriveGet.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

下面的例子是另一种弹出方法, 它对除了 CD/DVD 外的其他类型的媒体/设备也有效:

; 使用期望的驱动器字母更新下面的第一行 (您可以忽略后面的其他所有行).
Driveletter = I:  ; 设置为您想弹出的驱动器字母.

hVolume := DllCall("CreateFile"
    , Str, "\\.\" . Driveletter
    , UInt, 0x80000000 | 0x40000000  ; GENERIC_READ | GENERIC_WRITE
    , UInt, 0x1 | 0x2  ; FILE_SHARE_READ | FILE_SHARE_WRITE
    , UInt, 0
    , UInt, 0x3  ; OPEN_EXISTING
    , UInt, 0, UInt, 0)
if hVolume <> -1
{
    DllCall("DeviceIoControl"
        , UInt, hVolume
        , UInt, 0x2D4808   ; IOCTL_STORAGE_EJECT_MEDIA
        , UInt, 0, UInt, 0, UInt, 0, UInt, 0
        , UIntP, dwBytesReturned  ; 不使用.
        , UInt, 0)
    DllCall("CloseHandle", UInt, hVolume)
}

相关

DriveGet, DriveSpaceFree

示例

Drive, Label, D:, BackupDrive
Drive, Eject,, 1 ; 收回 (关闭) 默认的 CD 或 DVD 驱动器的托盘.


DriveGet

获取计算机驱动器的各种类型的信息。

DriveGet, OutputVar, Cmd [, Value]

参数

OutputVar

用来保存 Cmd 结果的变量名.

Cmd, Value
请参阅后面的列表.

Cmd, Value

Cmd 和 Value 参数互相依赖, 它们的用法描述如下. 如果遇到问题, 则 OutputVar 被置空且 ErrorLevel 被置为 1.

List [, Type]：设置 OutputVar 为一串字母，其中每个字母表示系统中的一个驱动器。例如: ACDEZ. 如果省略 Type, 则获取所有类型的驱动器. 否则, 指定 Type 为下列单词的其中一个来获取该特定类型的驱动器: CDROM, REMOVABLE, FIXED, NETWORK, RAMDISK, UNKNOWN.

Capacity (or Cap), Path: 获取 Path (e.g. C:\) 的总容量, 单位为 MB. 使用 DriveSpaceFree 来获取可用空间.

Filesystem（或 FS）, Drive ：获取 Drive 的文件系统类型，其中 Drive 由驱动器字母、跟着一个冒号和可选的反斜线组成，或为 UNC 名称（例如 \\server1\share1）。OutputVar 将被设为下列单词的其中一个: FAT, FAT32, NTFS, CDFS (一般指 CD), UDF (一般指 DVD). 如果驱动器中不包含格式化的媒体, 则 OutputVar 被置空且 ErrorLevel 被置为 1.

Label, Drive: 获取 Drive 的卷标, 其中 Drive 由驱动器字母, 跟着冒号和可选的反斜线组成, 或为 UNC 名称 (例如 \\server1\share1). 要改变卷标，请参照此例：Drive, Label, C:, MyLabel。

Serial, Drive：获取以十进制数表示的 Drive 的卷序列号，其中 Drive 由驱动器字母、跟着冒号和可选的反斜线组成，或为 UNC 名称（例如 \\server1\share1）。请参阅 SetFormat 了解如何把它转换成十六进制.

Type, Path: 获取 Path 的驱动器类型, 它为下列单词的其中一个: Unknown, Removable, Fixed, Network, CDROM, RAMDisk.

Status, Path: 获取 Path 的状态, 它为下列单词的其中一个: Unknown (可能表示未格式化/RAW), Ready, NotReady (通常表示不含媒体的可移动驱动器), Invalid (Path 不存在或为当前无法访问的网络驱动器, 等等).

StatusCD [, Drive]: 获取 CD 或 DVD 驱动器的媒体状态, 其中 Drive 由驱动器字母跟着冒号组成 (如果省略 Drive, 则使用默认的 CD/DVD 驱动器). 如果无法确定它的状态, 则 OutputVar 被置空. 否则, 它被设置为下列字符串的其中一个:

not ready | 驱动器未准备好被访问, 可能因为正忙于写入操作. 已知限制: 当驱动器里是 DVD 而不是 CD 时, 也会出现 "未准备好" 的情况.
open | 驱动器里没有光盘, 或者托盘已弹出.
playing | 驱动器正在播放光盘.
paused | 之前播放的音频或视频现在已暂停.
seeking | 驱动器正在寻道.
stopped | 驱动器里有 CD 但当前没有进行访问.

此命令对网络驱动器或非 CD/DVD 驱动器不起作用; 如果因为这种或其他原因失败了, 则 OutputVar 被置空且 ErrorLevel 被置为 1.

如果托盘刚才被关闭, 则此命令可能需要一些时间才能完成.

要弹出或收回托盘, 请参阅 Drive 命令.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

此命令的一些子命令参数 Path 中可以接受网络共享名, 例如 \\MyServer\MyShare\

相关

Drive, DriveSpaceFree

示例

; 这是个可运行示例脚本.
FileSelectFolder, folder, , 3, Pick a drive to analyze:
if folder =
    return
DriveGet, list, list
DriveGet, cap, capacity, %folder%
DrivespaceFree, free, %folder%
DriveGet, fs, fs, %folder%
DriveGet, label, label, %folder%
DriveGet, serial, serial, %folder%
DriveGet, type, type, %folder%
DriveGet, status, status, %folder%
MsgBox All Drives: %list%`nSelected Drive: %folder%`nDrive Type: %type%`nStatus: %status%`nCapacity: %cap% M`nFree Space: %free% M`nFilesystem: %fs%`nVolume Label: %label%`nSerial Number: %serial%


DriveSpaceFree

获取驱动器的可用磁盘空间，单位为 MB。

DriveSpaceFree, OutputVar, Path

参数

OutputVar

用来保存结果的变量, 结果向下取整到最近的整数.

path

要获取信息的驱动器路径. 由于 NTFS 支持装载卷和目录连接, 所以在某些情况下在相同 "驱动器" 上不同文件夹的可用空间可能不同.

备注

OutputVar 被设置为可用的磁盘空间数, 单位为 MB (向下取整到最近的兆字节).

相关

Drive, DriveGet

示例

DriveSpaceFree, FreeSpace, c:\


FileAppend

在文件末尾处追加文本（如果有必要，首先创建文本）。

FileAppend [, Text, Filename, Encoding]

参数

文本

要追加到文件的文本. 此文本可以包含换行符 (`n) 来开始新行. 此外, 一个长行可以使用 延续片段 的方法分成较短的几行.

如果 Text 为空, 则创建一个文件名为 Filename 的空白文件 (但如果文件已经存在, 则更新其修改时间).

如果 Text 为 %ClipboardAll% 或之前接受了 ClipboardAll 赋值的变量, 则用剪贴板的全部内容无条件覆盖 Filename (即不需要 FileDelete).

Filename

要追加内容的文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

二进制模式: 要以二进制模式而不是文本模式追加数据, 在文件名前面加上星号. 这使得每个换行符 (`n) 作为单个换行符 (LF) 而不是 Windows 标准的 CR+LF 写入. 例如：*C:\My Unix File.txt。

如果文件还没有打开 (由于在 文件读取循环 中), 且 Text 包含任意的回车和换行符对 (`r`n), 则自动以二进制模式打开文件. 换句话说, 前面段落中描述的星号选项自动生效. 不过, 当 Text 包含 `r`n 如果指定星号可以改善性能, 因为程序不需要扫描 Text 检查其中是否包含 `r`n.

标准输出 (stdout): 在 Filename 指定星号 (*) 可以把 Text 发送到标准输出 (stdout). 这样文本可以重定向到文件, 指向另一个 EXE 的管道或被 高级文本编辑器 捕获. 例如, 在命令提示符中输入后面的例子是有效的:

"%ProgramFiles%\AutoHotkey\AutoHotkey.exe" "My Script.ahk" >"Error Log.txt"

然而, 发送到标准输出的文本将不会出现在运行它的命令提示符中. 解决此问题的方法是把脚本的输出通过管道传递给另一个命令或程序. 例如：

"%ProgramFiles%\AutoHotkey\AutoHotkey.exe" "My Script.ahk" |more
For /F "tokens=*" %L in ('""%ProgramFiles%\AutoHotkey\AutoHotkey.exe" "My Script .ahk""') do @Echo %L
Encoding

[AHK_L 42+]: 覆盖 FileEncoding 的默认设置, 其中 Encoding 遵循相同的格式.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

要覆盖现有的文件, 请在使用 FileAppend 前用 FileDelete 删除它.

追加文本后目标文件会自动关闭 (除非在 文件读取/写入循环 中以单参数模式使用 FileAppend 时).

[AHK_L 42+]: 追加模式的 FileOpen() 比 FileAppend 提供了更多的控制性并且允许文件保持打开状态而不是每次打开关闭文件. 一旦以追加模式打开文件后, 请使用 file.Write(string) 来追加字符串. 文件对象通过 RawWrite/RawRead 或 WriteNum/ReadNum 还支持二进制 I/O, 然而 FileAppend 仅支持文本.

相关

FileOpen/文件对象, FileRead, 文件读取循环, FileReadLine, IniWrite, FileDelete, OutputDebug, 延续片段

示例

FileAppend, Another line.`n, C:\My Documents\Test.txt

; 下面的例子使用 延续片段 来提高可读性和可维护性:
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.
    This line is indented with a tab; by default, that tab will also be written to the file.
Variable references such as %Var% are expanded by default.
), C:\My File.txt

; 下面的例子演示了如何使用操作系统内置的 FTP 功能
; 自动进行 FTP 上传. 此脚本已经在 Windows XP 中测试通过。

FTPCommandFile = %A_ScriptDir%\FTPCommands.txt
FTPLogFile = %A_ScriptDir%\FTPLog.txt
FileDelete %FTPCommandFile%  ; 避免之前运行意外中止带来的问题。

FileAppend,  ; 这里需要逗号。
(
open host.domain.com
username
password
binary
cd htdocs
put %VarContainingNameOfTargetFile%
delete SomeOtherFile.htm
rename OldFileName.htm NewFileName.htm
ls -l
quit
), %FTPCommandFile%

RunWait %comspec% /c ftp.exe -s:"%FTPCommandFile%" >"%FTPLogFile%"
FileDelete %FTPCommandFile%  ; 删除以避免安全问题。
Run %FTPLogFile%  ; 显示日志进行复查。


FileCopy

复制一个或多个文件。

FileCopy, SourcePattern, DestPattern [, Flag]

参数

SourcePattern

单个文件或文件夹的名称或者通配符模式, 例如 C:\Temp\*.tmp. 如果未指定绝对路径则假定 SourcePattern 在 %A_WorkingDir% 中。

DestPattern
目标的名称或模式, 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 要执行简单地复制 (保留原来的文件名), 那么只需要指定文件夹名, 如下面这些功能相同的例子所演示的那样:
FileCopy, C:\*.txt, C:\My Folder
FileCopy, C:\*.txt, C:\My Folder\*.*
Flag

(可选参数) 此标志决定了是否覆盖现有的文件:

0 = (默认) 不覆盖现有的文件
1 = 覆盖现有的文件

此参数可以为 表达式, 甚至是计算结果为真或假的表达式 (因为真和假内部分别保存为 1 和 0).

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

ErrorLevel 被设置为由于错误而无法复制的文件数, 否则为 0.

在这两种情况中, 如果源文件为单个文件 (没有通配符) 且此文件不存在, 则 ErrorLevel 被置为 0. 要判断这种情况, 请在复制前对源文件使用 IfExist 或 FileExist().

与 FileMove 不同, 复制一个文件来覆盖它自己总是会导致错误, 即使在改写模式生效的情况下.

如果找到了文件, 则 A_LastError 会被设置为 0 (零) 或最近一次操作失败时调用操作系统 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

备注

FileCopy 只复制文件. 要复制整个文件夹的内容 (它的所有文件和子文件夹), 请参照下面的示例部分. 要复制单个文件夹 (及其子文件夹), 请使用 FileCopyDir.

在遇到错误后操作仍会继续进行.

相关

FileMove, FileCopyDir, FileMoveDir, FileDelete

示例

FileCopy, C:\My Documents\List1.txt, D:\Main Backup\  ; 复制文件并保留原来的文件名. file name.
FileCopy, C:\My File.txt, C:\My File New.txt  ; 复制文件到同一个文件夹并改变文件名.
FileCopy, C:\Folder1\*.txt, D:\New Folder\*.bkp  ; 复制到新位置并改变扩展名.

; 下面的例子复制一个文件夹中所有文件和文件夹到另一个文件夹中:
ErrorCount := CopyFilesAndFolders("C:\My Folder\*.*", "D:\Folder to receive all files & folders")
if ErrorCount <> 0
    MsgBox %ErrorCount% files/folders could not be copied.

CopyFilesAndFolders(SourcePattern, DestinationFolder, DoOverwrite = false)
; 复制匹配 SourcePattern 的所有文件和文件夹到 DestinationFolder 文件夹中且
; 返回无法复制的文件/文件夹的数目.
{
    ; 首先复制所有文件 (不是文件夹):
    FileCopy, %SourcePattern%, %DestinationFolder%, %DoOverwrite%
    ErrorCount := ErrorLevel
    ; 现在复制所有文件夹:
    Loop, %SourcePattern%, 2  ; 2 表示 "只获取文件夹".
    {
        FileCopyDir, %A_LoopFileFullPath%, %DestinationFolder%\%A_LoopFileName%, %DoOverwrite%
        ErrorCount += ErrorLevel
        if ErrorLevel  ; 报告每个出现问题的文件夹名称.
            MsgBox Could not copy %A_LoopFileFullPath% into %DestinationFolder%.
    }
    return ErrorCount
}


FileCopyDir

复制文件夹及其所有子文件夹和文件（类似于 xcopy）。

FileCopyDir, Source, Dest [, Flag]

参数

Source

源目录的名称 (不含末尾的反斜线), 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 例如: C:\My Folder

Dest

目标目录的名称 (不含末尾的反斜线), 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 例如: C:\Copy of My Folder

Flag

(可选参数) 此标志决定了是否覆盖现有的文件:

0 (默认): 不覆盖现有的文件. 如果存在 Dest 名称的文件或目录, 则操作会失败而且不会产生效果.

1: 覆盖现在的文件. 但是，不会删除在 Dest 中没有被 Source 目录中文件覆盖的其他子目录或文件。

此参数可以为 表达式, 甚至是计算结果为真或假的表达式 (因为真和假内部分别保存为 1 和 0).

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0. 但是, 如果源目录包含任何由 PageName.htm 文件和名称为 PageName_files 的相应目录组成的网页, 那么即使复制成功也可能提示错误.

备注

如果目标目录结构不存在, 则可行时会进行创建.

由于操作会递归复制文件夹及其所有子文件夹和文件, 所以复制某个文件夹到目标内部的什么位置是不确定的. 要变通解决此问题, 首先把它复制到目标外面, 然后使用 FileMoveDir 把这个副本移动到目标位置.

FileCopyDir 只复制单个文件夹. 要复制整个文件夹的内容 (它的所有文件和子文件夹), 请参照 FileCopy 的示例部分.

相关

FileMoveDir, FileCopy, FileMove, FileDelete, 文件循环, FileSelectFolder, SplitPath

示例

FileCopyDir, C:\My Folder, C:\Copy of My Folder

; 示例 #2: 提示您复制文件夹的可运行脚本.
FileSelectFolder, SourceFolder, , 3, Select the folder to copy
if SourceFolder =
    return
; 否则继续.
FileSelectFolder, TargetFolder, , 3, Select the folder IN WHICH to create the duplicate folder.
if TargetFolder =
    return
; 否则继续。
MsgBox, 4, , A copy of the folder "%SourceFolder%" will be put into "%TargetFolder%".  Continue?
IfMsgBox, No
    return
SplitPath, SourceFolder, SourceFolderName  ; 仅从它的完整路径中提取文件夹名称.
FileCopyDir, %SourceFolder%, %TargetFolder%\%SourceFolderName%
if ErrorLevel
    MsgBox The folder could not be copied, perhaps because a folder of that name already exists in "%TargetFolder%".
return


FileCreateDir

创建目录/文件夹.

FileCreateDir, DirName

参数

DirName

要创建的目录名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

如果 DirName 中给出的父目录还不存在, 则此命令也会创建它们.

相关

FileRemoveDir

示例

FileCreateDir, C:\Test1\My Images\Folder2


FileCreateShortcut

创建快捷方式（.lnk）文件。

FileCreateShortcut, Target, LinkFile [, WorkingDir, Args, Description, IconFile, ShortcutKey, IconNumber, RunState]

参数

Target

快捷方式引用的文件名, 其中应该包含绝对路径, 除非文件集成到了系统中 (如 Notepad.exe). 创建快捷方式时它指向的文件不需要一定存在; 换句话说, 可以创建指向无效目标的快捷方式.

LinkFile

要创建的快捷方式文件名, 如果未指定绝对路径则假定在 %A_WorkingDir%. 必须确保扩展名为 .lnk. 如果文件已经存在, 则它会被覆盖.

WorkingDir

启动快捷方式时 Target 的当前工作目录. 如果为空或省略, 则快捷方式的 "起始位置" 字段为空, 而当快捷方式启动时系统会提供默认的工作目录.

Args

启动快捷方式时传递给 Target 的参数. 参数之间使用空格分隔. 如果某个参数包含空格, 则要把它括在双引号中.

说明

描述快捷方式的注释 (操作系统显示在工具提示中, 等等.)

IconFile

显示在 LinkFile 中图标的完整路径和名称. 它必须为必须为 ico 文件或者 EXE 或 DLL 中的首个图标.

ShortcutKey

单个字母, 数字或在 按键列表 中的单个按键的名称 (可能不支持鼠标按钮或其他非标准的按键). 不要 包含修饰符. 目前, 所有创建的快捷键都使用 CTRL+ALT 作为修饰键. 例如, 如果在此参数中指定字母 B, 则快捷键将为 CTRL-ALT-B.

IconNumber

要使用 IconFile 首个外的其他图标, 请在这里指定编号 (可以为 表达式). 例如, 2 表示第二个图标.

RunState

要最小化或最大化运行 Target, 请指定下列数字的其中一个:

1 - 正常 (这是默认的)
3 - 最大化
7 - 最小化

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

如果 Target 在系统 PATH 环境变量包含的某个文件夹中, 则其中可以不包含路径.

只有把快捷方式文件放在桌面或开始菜单的某个位置, 这样新建快捷方式的 ShortcutKey 才会生效. 如果您选择的 ShortcutKey 已经在使用中, 那么您新建的快捷方式具有优先权.

创建到 URL 的快捷方式的另一种方法是下面这个例子, 其中创建了特殊的 URL 快捷方式. 根据您的需要改变前两个参数:
IniWrite, http://www.google.com, C:\My Shortcut.url, InternetShortcut, URL.

使用下面的语句可以给上面的快捷方式添加图标:

IniWrite, <IconFile>, C:\My Shortcut.url, InternetShortcut, IconFile
IniWrite, 0, C:\My Shortcut.url, InternetShortcut, IconIndex

在上面的语句中, 请把 0 替换为图标的索引 (0 表示首个图标) 并把 <IconFile> 替换为 URL, EXE, DLL 或 ICO 文件. 例如: C:\Icons.dll, C:\App.exe, http://www.somedomain.com/ShortcutIcon.ico

操作系统会被上面创建的 .URL 文件视为真正的快捷方式, 尽管它只是纯文本文件而不是 .LNK 文件.

相关

FileGetShortcut, FileAppend

示例

; 最后一个参数中的字母 "i" 将快捷键设成 Ctrl-Alt-I:
FileCreateShortcut, Notepad.exe, %A_Desktop%\My Shortcut.lnk, C:\, "%A_ScriptFullPath%", My Description, C:\My Icon.ico, i


FileDelete

删除一个或多个文件。

FileDelete, FilePattern

参数

FilePattern

单个文件的名称或通配符模式，例如 C:\Temp\*.tmp。如果未指定绝对路径则假定 FilePattern 在 %A_WorkingDir%。

要删除整个文件夹及其所有子文件夹和文件, 请使用 FileRemoveDir.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

ErrorLevel 被设置为删除失败的文件数, 否则为 0. 删除像 *.tmp 这样的通配符模式即使它不匹配任何文件也被视为是成功的；因此 ErrorLevel 被置为 0。

如果找到了文件, 则 A_LastError 会被设置为 0 (零) 或最近一次操作失败时调用操作系统 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

备注

要删除只读文件, 请首先移除它的只读属性. 例如：FileSetAttrib, -R, C:\My File.txt。

相关

FileRecycle, FileRemoveDir, FileCopy, FileMove

示例

FileDelete, C:\temp files\*.tmp


FileEncoding

FileEncoding [AHK_L 42+]

为 FileRead、FileReadLine、Loop Read、FileAppend 和 FileOpen 设置默认编码。

FileEncoding [, Encoding]

编码可以为下列值的其中一个:

  • UTF-8: Unicode UTF-8, 相当于 CP65001.
  • UTF-16: Unicode UTF-16, 小端字节顺序. 相当于 CP1200.
  • UTF-8-RAW 或 UTF-16-RAW: 像上面一样, 但创建新文件时不写入字节顺序标记.
  • CPnnn: 带数值标识符 nnn 的代码页. 请参阅 代码页标识符.
  • 空或省略: 系统默认的 ANSI 代码页, 这也是默认设置.

备注

A_FileEncoding 包含了当前的默认编码设置.

相关

FileOpen, StrPut/StrGet, 脚本兼容性


FileGetAttrib

报告文件或文件夹是否为只读、隐藏等。

FileGetAttrib, OutputVar [, Filename]
AttributeString := FileExist(FilePattern)

参数

OutputVar

用来存储获取的文本的变量名.

Filename

目标文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 如果省略, 则使用最内层 文件循环 的当前文件.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

返回的字符串为字符串 "RASHNDOCT" 中部分字母组成的子集:

R = 只读
A = 存档
S = 系统
H = 隐藏
N = 普通
D = 目录
O = 离线
C = 压缩
T = 临时

要判断在获取的字符串中是否含有指定的属性, 请参照此例:

FileGetAttrib, Attributes, C:\My File.txt
IfInString, Attributes, H
    MsgBox The file is hidden.

相关提示, 要获取 8.3 格式的短文件名, 请参照此例:

Loop, C:\My Documents\Address List.txt
    ShortPathName = %A_LoopFileShortPath%  ; 将产生类似于 C:\MYDOCU~1\ADDRES~1.txt 的路径

用类似的方法可以获取与8.3短名称对应的长名称。

相关

FileExist(), FileSetAttrib, FileGetTime, FileSetTime, FileGetSize, FileGetVersion, 文件循环

示例

FileGetAttrib, OutputVar, C:\New Folder


FileGetShortcut

获取快捷方式（.lnk）文件的信息，例如其目标文件。

FileGetShortcut, LinkFile [, OutTarget, OutDir, OutArgs, OutDescription, OutIcon, OutIconNum, OutRunState]

参数

LinkFile

要分析的快捷方式文件名, 如果未指定绝对路径则假定在 %A_WorkingDir%. 必须确保扩展名为 .lnk.

OutTarget

用来存储快捷方式目标的变量名 (不包含它可能含有的任何参数). 例如: C:\WINDOWS\system32\notepad.exe

OutDir

用来保存快捷方式工作目录的变量名. 例如: C:\My Documents. 如果在字符串中存在像 %WinDir% 这样的环境变量, 那么解决它们的一种方法是使用 StringReplace. 例如：StringReplace, OutDir, OutDir, `%WinDir`%, %A_WinDir%。

OutArgs

用来保存快捷方式参数的变量名 (如果没有则为空).

OutDescription

用来保存快捷方式注释的变量名 (如果没有则为空).

OutIcon

用来保存快捷方式图标文件名的变量名 (如果没有则为空).

OutIconNum

用来保存快捷方式图标在图标文件中编号的变量名 (如果没有则为空). 这个值通常为 1, 表示首个图标.

OutRunState

用来存储快捷方式初始运行方式的变量名, 其值为下列数字的其中一个:

1: 普通
3: 最大化
7: 最小化

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题 (例如 LinkFile 不存在), 则所有的输出变量被置空且 ErrorLevel 被置为 1. 否则, ErrorLevel 被置为 0.

备注

如果不需要相应的信息, 则可以省略相应的输出变量.

相关

FileCreateShortcut, SplitPath

示例

FileSelectFile, file, 32,, Pick a shortcut to analyze., Shortcuts (*.lnk)
if file =
    return
FileGetShortcut, %file%, OutTarget, OutDir, OutArgs, OutDesc, OutIcon, OutIconNum, OutRunState
MsgBox %OutTarget%`n%OutDir%`n%OutArgs%`n%OutDesc%`n%OutIcon%`n%OutIconNum%`n%OutRunState%


FileGetSize

获取文件的大小。

FileGetSize, OutputVar [, Filename, Units]

参数

OutputVar

用来保存获取的文件大小的变量名 (文件大小向下取整到最近的整数).

Filename

目标文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 如果省略, 则使用最内层 文件循环 的当前文件.

Units

如果使用此参数, 那么它会让返回结果使用的字节外的其他单位:
K = 千字节
M = 兆字节

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

支持任意的文件大小 (包括超过 4 GB 的文件), 对任意大小的文件都支持 Units 为字节.

如果目标文件为目录, 则报告操作系统看到的它的大小 (在所有情况中可能都是零).

要计算文件夹及其所有文件的大小, 请参照此例:

SetBatchLines, -1  ; 让操作以最快速度运行.
FolderSize = 0
FileSelectFolder, WhichFolder  ; 提示用户选择文件夹.
Loop, %WhichFolder%\*.*, , 1
    FolderSize += %A_LoopFileSize%
MsgBox Size of %WhichFolder% is %FolderSize% bytes.

相关

FileGetAttrib, FileSetAttrib, FileGetTime, FileSetTime, FileGetVersion, 文件循环

示例

FileGetSize, OutputVar, C:\My Documents\test.doc  ; 获取以字节为单位的文件大小.
FileGetSize, OutputVar, C:\My Documents\test.doc, K  ; 获取以千字节为单位的文件大小.


FileGetTime

获取文件或文件夹的时间戳。

FileGetTime, OutputVar [, Filename, WhichTime]

参数

OutputVar

用来保存获取的 YYYYMMDDHH24MISS 格式的日期时间的变量名. 这个时间是您本地时间, 不是 UTC/GMT.

Filename

目标文件或文件夹的名称, 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 如果省略, 则使用最内层 文件循环 的当前文件.

WhichTime
要获取的时间戳类别:
M = 修改时间 (此参数省略时这是默认的)
C = 创建时间
A = 上次访问时间

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

请参阅 YYYYMMDDHH24MISS 了解日期和时间的说明.

相关

FileSetTime, FormatTime, If var is [not] type, FileGetAttrib, FileSetAttrib, FileGetSize, FileGetVersion, 文件循环, EnvAdd, EnvSub

示例

FileGetTime, OutputVar, C:\My Documents\test.doc  ; 默认获取修改时间.
FileGetTime, OutputVar, C:\My Documents\test.doc, C  ; 获取创建时间.


FileGetVersion

获取文件的版本。

FileGetVersion, OutputVar [, Filename]

参数

OutputVar

用来保存表示版本的数字/字符串的变量名.

Filename

目标文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 如果省略, 则使用最内层 文件循环 的当前文件.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

大多数非可执行文件 (甚至是某些可执行文件) 没有版本, 因此此时 OutputVar 将是空的.

相关

FileGetAttrib, FileSetAttrib, FileGetTime, FileSetTime, FileGetSize, 文件循环

示例

FileGetVersion, version, C:\My Application.exe
FileGetVersion, version, %A_ProgramFiles%\AutoHotkey\AutoHotkey.exe


FileInstall

封装指定的文件到脚本的已编译版本中。

FileInstall, Source, Dest [, Flag]

参数

Source

要添加到已编译可执行文件中的文件名. 如果未指定绝对路径, 则假定文件在相对于脚本的目录中.

文件名 不能 包含双引号, 变量引用 (例如 %A_ProgramFiles%) 或通配符. 此外, 任何特殊字符 (例如原义的百分号和逗号) 必须 进行转义 (如同在其他所有命令的参数中一样). 最后, 此参数必须放在 FileInstall 的右边而不能在下面 (即不能在命令的下面使用 延续行).

Dest

从可执行文件中释放 Source 时使用的文件名. 如果未指定绝对路径则假定在 %A_WorkingDir%. 目标目录必须已经存在. 与 Source 不同, 这里可以使用变量引用.

Flag

(可选参数) 此标志决定了是否覆盖现有的文件:

0 = (默认) 不覆盖现有的文件
1 = 覆盖现有的文件

此参数可以为 表达式, 甚至是计算结果为真或假的表达式 (因为真和假内部分别保存为 1 和 0).

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

此命令是为 Ahk2Exe 编译器 提供的指令, 允许您添加额外的文件到最终的已编译脚本. 随后, 当已编译脚本运行时, 文件会被释放到磁盘中.

该文件会在脚本编译时添加进去。已编译脚本执行到同一个“FileInstall”命令时，该文件会被释放到 Dest。

添加文件到脚本时会进行压缩和加密.

如果在普通 (未编译) 脚本中使用此命令, 则会简单地复制一个副本, 这样可以帮助测试最终会进行编译的脚本.

相关

FileCopy, #Include

示例

FileInstall, C:\My Documents\My File.txt, %A_ProgramFiles%\My Application\Readme.txt, 1


FileMove

移动或重命名一个或多个文件。

FileMove, SourcePattern, DestPattern [, Flag]

参数

SourcePattern

单个文件的名称或通配符模式, 例如 C:\Temp\*.tmp. 如果未指定绝对路径则假定 SourcePattern 在 %A_WorkingDir% 中。

DestPattern

目标的名称或模式, 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 要执行简单地移动 (保留原来的文件名), 那么只需要指定文件夹名, 如下面这些功能相同的例子所演示的那样:

FileMove, C:\*.txt, C:\My Folder
FileMove, C:\*.txt, C:\My Folder\*.*
Flag

(可选参数) 此标志决定了是否覆盖现有的文件:

0 = (默认) 不覆盖现有的文件
1 = 覆盖现有的文件

此参数可以为 表达式, 甚至是计算结果为真或假的表达式 (因为真和假内部分别保存为 1 和 0).

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

ErrorLevel 被设置为由于错误而无法移动的文件数, 否则为 0. 但是, 如果源文件为单个文件 (没有通配符) 且此文件不存在, 则 ErrorLevel 被置为 0. 要判断这种情况, 请在移动前对源文件使用 IfExist 或 FileExist().

与 FileCopy 不同, 移动一个文件来覆盖它自己总被认为是成功的, 即使在改写模式没有生效的情况下.

如果找到了文件, 则 A_LastError 会被设置为 0 (零) 或最近一次操作失败时调用操作系统 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

备注

FileMove 只移动文件. 要移动整个文件夹的内容 (它的所有文件和子文件夹), 请参照下面的示例部分. 要移动或重命名单个文件夹, 请使用 FileMoveDir.

在遇到错误后操作仍会继续进行.

尽管此命令可以移动文件到不同的卷, 但这样的操作会比在相同卷上消耗更多的时间. 这是由于在相同卷上类似于重命名, 因此快速得多.

相关

FileCopy, FileCopyDir, FileMoveDir, FileDelete

示例

FileMove, C:\My Documents\List1.txt, D:\Main Backup\  ; 移动文件而不进行重命名.
FileMove, C:\File Before.txt, C:\File After.txt  ; 重命名单个文件.
FileMove, C:\Folder1\*.txt, D:\New Folder\*.bkp  ; 移动并使用新的扩展名重命名文件.

; 下面的例子移动一个文件夹中所有文件和文件夹到另一个文件夹中:
ErrorCount := MoveFilesAndFolders("C:\My Folder\*.*", "D:\Folder to receive all files & folders")
if ErrorCount <> 0
    MsgBox %ErrorCount% files/folders could not be moved.

MoveFilesAndFolders(SourcePattern, DestinationFolder, DoOverwrite = false)
; 移动匹配 SourcePattern 的所有文件和文件夹到 DestinationFolder 文件夹中且
; 返回无法移动的文件/文件夹的数目. 此函数需要 v1.0.38+
; 因为它使用了 FileMoveDir 的模式 2.
{
    if DoOverwrite = 1
        DoOverwrite = 2  ; 请参阅 FileMoveDir 了解模式 2 与模式 1 的区别.
    ; 首先移动所有文件 (不是文件夹):
    FileMove, %SourcePattern%, %DestinationFolder%, %DoOverwrite%
    ErrorCount := ErrorLevel
    ; 现在移动所有文件夹:
    Loop, %SourcePattern%, 2  ; 2 表示 "只获取文件夹".
    {
        FileMoveDir, %A_LoopFileFullPath%, %DestinationFolder%\%A_LoopFileName%, %DoOverwrite%
        ErrorCount += ErrorLevel
        if ErrorLevel  ; 报告每个出现问题的文件夹名称.
            MsgBox Could not move %A_LoopFileFullPath% into %DestinationFolder%.
    }
    return ErrorCount
}


FileMoveDir

移动文件夹及其所有子文件夹和文件。它还可以重命名文件夹。

FileMoveDir, Source, Dest [, Flag]

参数

Source

源目录的名称 (不含末尾的反斜线), 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 例如: C:\My Folder

Dest

目录的新路径和名称 (不含末尾的反斜线), 如果未指定绝对路径则假定在 %A_WorkingDir%. 例如: D:\My Folder. 注: Dest 是目录在移动后使用的实际路径和名称; 它 不是 Source 移动后保存的目录 (不过存在下面提到的已知限制).

Flag

(可选) 指定下列单个字符的其中一个:

0 (默认): 不覆盖现有的文件. 如果存在 Dest 名称的文件或目录, 则操作会失败.

1: 覆盖现在的文件. 但是，不会删除在 Dest 中没有被 Source 目录中文件覆盖的其他子目录或文件。已知限制：如果在同一个卷上存在和 Source 相同的 Dest 文件夹，则 Source 会被移入到这个文件夹中而不覆盖它。要避免此问题, 请参阅下一个选项.

2: 与上面的模式 1 相同, 不过不存在那个限制.

R: 重命名目录而不移动它. 尽管普通的重命名和移动具有相同的效果, 但如果您想要 "完全成功或完全失败" 的结果时它就会有用; 即您不希望由于 Source 或其中的某个文件被锁定 (在使用中) 而只是部分移动成功. 尽管这种方法不能移动 Source 到另一个卷中, 但它可以移动到同一个卷中的其他任何目录. 如果已经存在 Dest 名称的文件或目录时, 则操作失败.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

FileMoveDir 移动单个文件夹到新位置. 要移动整个文件夹的内容 (它的所有文件和子文件夹), 请参照 FileMove 的示例部分.

如果源和目标在不同的卷或 UNC 路径中, 则会执行复制/删除操作而不进行移动.

相关

FileCopyDir, FileCopy, FileMove, FileDelete, 文件循环, FileSelectFolder, SplitPath

示例

FileMoveDir, C:\My Folder, D:\My Folder  ; 移动到新驱动器。
FileMoveDir, C:\My Folder, C:\My Folder (renamed), R  ; 简单地重命名。
FileMoveDir, C:\My Folder, C:\New Location\My Folder, R  ; 只有在同一个卷上，文件夹可以被“重命名到”另一个位置。


FileOpen

FileOpen [AHK_L 42+]

打开文件.

file := FileOpen(Filename, Flags [, Encoding])

参数

Filename

要打开文件的路径, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

Flags

[在 AHK_L 54+] 表示希望使用的访问模式的字符串, 后面跟着其他选项 (中间可以含有空格或 tab); 或 [在 AHK_L 42+] 数值标志的组合 (总和). 下表中描述了支持的值.

Encoding

当文件没有包含 UTF-8 或 UTF-16 字节顺序标记时文件 I/O 使用的代码页.
如果省略, 则使用 A_FileEncoding 的当前值.

Flags

 |  | 访问模式 (互斥的)
r | 0 | 读取: 当文件不存在时失败.
w | 1 | 写入：创建新文件，若文件已存在则覆盖它们。
a | 2 | 追加: 如果文件不存在则创建新文件, 否则移动文件指针到文件末尾.
rw | 3 | 读取/写入: 当文件不存在时创建新文件.
h |  | 表示 Filename 是包装在对象中的文件句柄. 忽略共享模式标志. 当文件对象销毁时, 文件句柄 不会 自动关闭并且调用 Close 没有效果. 注意当 Filename 是到非搜寻设备 (例如管道或通信设备) 的句柄时不应该使用 Seek, Tell 和 Length.
 |  | 共享模式标志
-rwd |  | 为读取, 写入和/或删除访问进行文件锁定. 可以使用 r, w 和 d 的任意组合. 指定 - 相当于指定 -rwd. 如果完全省略, 默认为共享所有访问.
 | 0 | 如果 Flags 是数值的, 缺少共享模式标志会让文本被锁定.
 | 0x100 | 共享 读取 访问.
 | 0x200 | 共享 写入 访问.
 | 0x400 | 共享 删除 访问.
 |  | 行结束符 (EOL) 选项
`n | 4 | 读取时把 `r`n 替换为 `n 而写入时把 `n 替换为 `r`n.
`r | 8 | 读取时把单独的 `r 替换为 `n.

返回值

如果成功打开文件, 则返回值为 文件对象.

如果函数失败, 则返回值为 0 且 [in AHK_L 54+] A_LastError 包含错误码.

使用 if file 或 IsObject(file) 可以判断函数是否成功执行.

备注

当创建 UTF-8 或 UTF-16 文件时, 会写入字节顺序标记到文件中, 除非 Encoding (或 A_FileEncoding, 当 Encoding 省略时) 包含 "UTF-8-RAW" 或 "UTF-16-RAW".

以读取方式打开含有 UTF-8 或 UTF-16 字节顺序标记（BOM）的文件时，会把文件指针放置到这个标志后来从输出中排除 BOM。因此，在刚刚打开这样的文件时 File.Position 可能为 3 或 2。

相关

FileEncoding, 文件对象, FileRead

示例

; 示例: 这是个可运行脚本, 它写入一些文本到文件, 然后从文件读取回内存.
; 它提供了与 此 DllCall 示例 同样的功能.

FileSelectFile, FileName, S16,, Create a new file:
if (FileName = "")
    return
file := FileOpen(FileName, "w")
if !IsObject(file)
{
    MsgBox Can't open "%FileName%" for writing.
    return
}
TestString := "This is a test string.`r`n"  ; 通过这种方式写入内容到文件时, 要使用 `r`n 而不是 `n 来开始新行.
file.Write(TestString)
file.Close()

; 现在已经把内容写入文件了, 重新把它们读取回内存中.
file := FileOpen(FileName, "r-d") ; 读取文件 ("r"), 共享除删除 ("-d") 外的所有访问权限
if !IsObject(file)
{
    MsgBox Can't open "%FileName%" for reading.
    return
}
CharsToRead := StrLen(TestString)
TestString := file.Read(CharsToRead)
file.Close()
MsgBox The following string was read from the file: %TestString%
; 以只读模式打开脚本并读取它的首行:
file := FileOpen(A_ScriptFullPath, "r")
MsgBox % file.ReadLine()

; 打开控制台窗口以进行此次演示:
DllCall("AllocConsole")
; 在新行符转换模式中打开应用程序的 stdin/stdout 句柄.
stdin  := FileOpen(DllCall("GetStdHandle", "int", -10, "ptr"), "h `n")
stdout := FileOpen(DllCall("GetStdHandle", "int", -11, "ptr"), "h `n")
stdout.Write("Enter your query.`n\> ")
stdout.Read(0) ; 刷新写入缓冲区.
query := RTrim(stdin.ReadLine(), "`n")
stdout.WriteLine("Your query was '" query "'. Have a nice day.")
stdout.Read(0) ; 刷新写入缓冲区.
Sleep 5000


FileReadLine

读取文件指定行的文本并保存到变量。

FileReadLine, OutputVar, Filename, LineNum

参数

OutputVar

用来存储获取的文本的 变量 名.

Filename

要访问的文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 支持 Windows 和 Unix 格式; 即文件的行结束符可以是回车和换行符 (`r`n) 或只是换行符 (`n).

LineNum

要读取的行号 (首行为 1, 第二行为 2, 依此类推). 可以为 表达式.

如果指定的行号大于文件的行数, 则 ErrorLevel 被设置为 1 且 OutputVar 不会发生变化. 当指定的行号为文件的最后一行且此行为空, 同时不是以新行/CRLF 结束时, 也会发生这种情况.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

成功时 ErrorLevel 被置为 0. 否则它被设置为 1 且 OutputVar 的原始内容不会发生变化.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

强烈建议仅对于小文件或只需要单行文本的情况时使用此命令. 要扫描并处理大量的文本行 (一行接一行), 请使用 文件读取循环 来获取最好的性能. 要读取整个文件到变量中, 请使用 FileRead.

虽然一行中任何前导和尾随的 tab 和空格都会被写入 OutputVar, 但是行末的换行符 (`n) 则不会. 当 AutoTrim 设置打开 (默认的) 时, 任何变量都可以通过赋值给自己来移除变量两端的 tab 和空格. 例如：MyLine = %MyLine%。

最大可以读取包含 65,534 字符的长行. 如果行的超度超过这个极限, 则此命令无法读取剩余的字符 (此时应使用 FileRead 或 文件读取循环 代替).

相关

FileOpen/File.ReadLine(), FileRead, FileAppend, 文件读取循环, IniRead

示例

Loop
{
    FileReadLine, line, C:\My Documents\ContactList.txt, %A_Index%
    if ErrorLevel
        break
    MsgBox, 4, , Line #%A_Index% is "%line%".  Continue?
    IfMsgBox, No
        return
}
MsgBox, The end of the file has been reached or there was a problem.
return


FileRead

读取文件的内容到变量。

FileRead, OutputVar, Filename

参数

OutputVar

用来存储获取的数据的 变量 名. 如果遇到问题 (例如文件 "在使用中") 或不存在), 则 OutputVar 被置空 (此时 ErrorLevel 被设置为 1). 如果 Filename 是个空文件, 则输出变量也被置空 (此时 ErrorLevel 被置为 0).

Filename

要读取的文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

选项: 在文件名前面可以直接添加零个或多个下列字符串. 在选项间使用单个空格或 tab 分隔. 例如：*t *m5000 C:\Log Files\200601.txt。

*c: 读取保存了 ClipboardAll 内容的文件或其他二进制数据. 使用了 *c 选项时其他所有选项会被忽略.

*m1024: 如果省略此选项, 则读取整个文件, 不过如果内存不足, 则显示错误消息并退出线程 (使用 Try 可以避免这种情况). 否则, 请把 1024 替换为十进制或十六进制表示的字节数. 如果文件大于此字节数, 那么只读取其前面部分. 注: 此选项可能导致最后一行以单独的回车符 (`r) 而不是 `r`n 结束.

*t: 把所有的回车换行符 (`r`n) 替换为换行符 (`n). 不过, 这种转换会降低性能而且往往不必要. 例如, 包含 `r`n 的文本已经是添加到 Gui 编辑控件 的正确格式. 同样地, FileAppend 打开新文件时会检测是否含有 `r`n; 它知道按原样写入每对 `r`n 而不是把它转换成 `r`r`n. 最后，不论每行的结束符是 `r`n 或只是 `n，后面的解析循环都可以正确执行：Loop, parse, MyFileContents, `n, `r。

*Pnnn: [AHK_L 42+]: 覆盖 FileEncoding 包含的默认编码设置, 其中 nnn 必须是数值的 代码页标识符.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

读取成功时 ErrorLevel 被置为 0. 如果遇到问题, 它被设置为 1, 例如: 1) 文件不存在; 2) 文件被锁定或无法访问; 3) 系统没有足够的内存加载文件.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

读取二进制数据

根据文件, 参数和默认设置, FileRead 可能把文件数据解释为文本并且把它转换成脚本使用的 原生编码. 如果文件包含二进制数据, 那么这样的操作很可能引起问题, 不过在下列情况中则可以避免:

  • 如果存在 *C 选项, 则无条件忽略所有代码页和行结束符的转换.
  • 如果存在 *Pnnn 选项且 nnn 符合原生的字符串编码, 则不会进行代码页转换.
  • 如果当前 文件编码 设置符合原生字符串编码, 则不会进行代码页转换.

注意一旦把数据读取到 OutputVar, 那么只有首个二进制零 (如果存在) 才能被大多数 AutoHotkey 命令和函数 "看到". 然而, 所有的内容仍然存在并且可以使用高级的方法进行访问 (例如 NumGet()).

最后, 使用 FileOpen() 和 File.RawRead() 或 File.ReadNum() 可以在无需首先读取整个文件到内存中的情况下读取二进制数据.

备注

当需要读取文件的全部或大部分内容到内存时, 使用 FileRead 比 文件读取循环 执行地更好.

大于 1 GB 的文件会导致 ErrorLevel 被设置为 1 并且 OutputVar 被置为空, 此时可以使用 *m 选项来避免并读取文件的前面部分.

FileRead 不遵循 #MaxMem 的设置. 如果担心使用太多的内存, 可以预先用 FileGetSize 检查文件的大小.

FileOpen() 比 FileRead 提供了更高级的功能, 例如在文件的指定位置读取或写入数据时无需把整个文件读取到内存中. 请参阅 文件对象 了解函数列表.

相关

FileEncoding, FileOpen/File Object, 文件读取循环, FileReadLine, FileGetSize, FileAppend, IniRead, Sort, UrlDownloadToFile

示例

; 示例 #1: 读取文本文件到 OutputVar.
FileRead, OutputVar, C:\My Documents\My File.txt
; 示例 #2：快速对文件的内容进行排序。
FileRead, Contents, C:\Address List.txt
if not ErrorLevel  ; 加载成功
{
    Sort, Contents
    FileDelete, C:\Address List (alphabetical).txt
    FileAppend, %Contents%, C:\Address List (alphabetical).txt
    Contents =  ; 清空占用的内存.
}


FileRecycle

发送文件或目录到回收站，如果可行。

FileRecycle, FilePattern

参数

FilePattern

单个文件的名称或通配符模式, 例如 C:\Temp\*.tmp. 如果未指定绝对路径则假定 FilePattern 在 %A_WorkingDir% 中.

要回收整个目录, 请指定不包含末尾反斜线的目录名.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

实际使用 SHFileOperation 进行操作. 如果由于文件过大而无法存放到回收站, 那么此功能还会永久地删除文件; 截至 v1.0.96, 在遇到这种情况时会显示警告.

相关

FileRecycleEmpty, FileDelete, FileCopy, FileMove

示例

FileRecycle, C:\temp files\*.tmp


FileRecycleEmpty

清空回收站。

FileRecycleEmpty [, DriveLetter]

参数

DriveLetter

如果省略, 则清空所有驱动器的回收站. 否则, 请指定驱动器字母, 例如 C:\

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

此命令要求安装 MS Internet Explorer 4 或更高版本.

相关

FileRecycle, FileDelete, FileCopy, FileMove

示例

FileRecycleEmpty, C:\


FileRemoveDir

删除文件夹。

FileRemoveDir, DirName [, Recurse?]

参数

DirName

要删除的目录名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

递归？

0（默认）：不移除 DirName 中包含的文件和子目录。此时如果 DirName 不是空的，则不进行操作并且将 ErrorLevel 设置为 1。

1：移除所有文件和子目录（类似于 Windows 命令“rmdir /S”）。

此参数可以为 表达式, 甚至是计算结果为真或假的表达式 (因为真和假内部分别保存为 1 和 0).

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

无

相关

FileCreateDir, FileDelete

示例

FileRemoveDir, C:\Download Temp
FileRemoveDir, C:\Download Temp, 1


FileSelectFile

显示可以让用户打开或保存文件的标准对话框。

FileSelectFile, OutputVar [, Options, RootDir\Filename, Prompt, Filter]

参数

OutputVar

用来保存用户选择的文件名的变量名称. 如果用户取消了对话框 (即不想选择文件), 则此变量被置空.

选项

如果省略, 则它默认为零, 相当于下面的任意选项都没有指定.

M: 多选. 指定字母 M 让用户可以使用 shift-click, control-click 或其他方法来选择多个文件. M 后面可以跟着下面描述的数字 (例如, M 和 M1 都是有效的). 要逐个提取文件, 请参阅此页面底部的例子.

S: 保存按钮. 指定字母 S 让对话框显示保存按钮代替打开按钮. S 后面可以跟着下面描述的数字 (或几个数的和) (例如, S 和 S24 都是有效的).

即使同时省略 M 和 S, 仍然可以使用下面的数字. 要让多个数字同时生效, 请把它们加在一起. 例如, 要使用 8 和 16, 请指定数字 24.

1: 文件必须存在
2: 路径必须存在
8: 提示创建新文件
16: 提示覆盖文件
32 [v1.0.43.09+]: 按原样选择快捷方式 (.lnk 文件) 而不把它们解析为它们的目标. 此选项也避免了通过文件夹快捷方式跳转到那个文件夹的情况.

如果使用 "提示覆盖" 选项而没有使用 "提示创建" 选项, 则对话框会包含保存按钮而不是打开按钮. 此行为是因为 Windows 的怪癖.

RootDir\Filename

如果存在, 则此参数包含下列的其中一个或两个:

RootDir: 根 (起始) 目录, 如果未指定绝对路径则假定为 %A_WorkingDir% 中的子文件夹. 如果省略或为空，则起始目录将为默认值，这可能操作系统版本有关（它很可能是之前使用 FileSelectFile 时用户最近选择的目录）。v1.0.43.10+ 在 Windows XP/2003 或早期系统中，还可以指定 CLSID 例如 ::{20d04fe0-3aea-1069-a2d8-08002b30309d}（即我的电脑），此时在 CLSID 后任何子目录都应该以反斜线结尾（否则在最后一个反斜线后的字符串会被解释为默认文件名，这点在下面说明）。

Filename: 初始显示对话框时在编辑区域的默认文件名. 只显示单独的文件名 (不带路径). 要让对话框正确显示, 请确保不包含非法字符 (例如 /<|:").

示例:

C:\My Pictures\Default Image Name.gif  ; 同时使用了 RootDir 和 Filename.
C:\My Pictures  ; 只使用了 RootDir.
My Pictures  ; 只使用了 RootDir, 且它相对于当前工作目录.
My File  ; 只使用了 Filename (但如果已存在 "My File" 的文件夹, 则它会被认为是 RootDir).
Prompt

显示在窗口中用来提示用户操作的文本. 如果省略或为空, 则它默认为 "Select File - %A_SCRIPTNAME%" (即当前脚本的名称).

Filter

表示希望对话框显示的文件类型.

例如: Documents (*.txt)
例如: Audio (*.wav; *.mp2; *.mp3)

如果省略, 则过滤器默认为 所有文件 (*.*). 在对话框 "文件类型" 菜单中, 文本文档 (*.txt) 选项还是可用的.

否则, 过滤器使用指示的字符串, 不过在对话框的 "文件类型" 下拉列表中仍然提供了 所有文件 (*.*) 选项. 要在过滤器中包含多个文件扩展名, 请使用分号分隔它们, 如上所示.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果用户没有选择文件却解除了对话框 (例如按下了取消按钮), 则 ErrorLevel 被置为 1. 如果系统拒绝显示对话框 (罕见), 那么它也被设置为 1. 否则被置为 0.

备注

如果用户什么都没选 (例如点击了取消), 则 OutputVar 被置空.

如果没有启用多选, 则 OutputVar 被设置为用户选择的单个文件的完整路径和名称.

如果使用了 M 选项 (多选), 则 OutputVar 被设置为项目列表, 除了最后一个项目外的每个项目后都跟着换行符 (`n). 列表中的首个项目是包含所有选择文件的路径 (此路径仅在为根目录时才以反斜线结尾, 例如 C:\). 其他项为选择的文件名 (不带路径). 例如：

C:\My Documents\New Folder [这是下面所有文件所在的路径]
test1.txt [这些是不含路径的文件名]
test2.txt
... 等等。

(此页面底部的例子演示了如何逐个提取这些文件.)

如果启用了多选, 则所有选择文件名的总长度被限制为 64 KB. 不过这通常足够容纳几千个文件, 如果超出此限制则 OutputVar 会被置空.

GUI 窗口可以使用 Gui +OwnDialogs 的方法显示模态的文件选择对话框. 模态对话框在其消失之前会阻止用户与 GUI 窗口进行交互.

已知限制: 在显示 FileSelectFile 对话框时运行的 计时器 会延迟用户在对话框中点击的效果到计时器结束之后. 要变通解决此问题, 请避免使用子程序需要很长时间来完成的计时器, 或在显示对话框期间禁用所有计时器:

Thread, NoTimers
FileSelectFile, OutputVar
Thread, NoTimers, false

过时选项: 在 v1.0.25.06+, 多选选项 "4" 已过时. 然而, 考虑到和旧脚本的兼容, 这个选项仍然可用. 具体是, 如果用户只选择了一个文件, 则 OutputVar 会包含这个文件的完整路径和名称跟着换行符 (`n). 如果用户选择了多个文件, 则格式和上面描述的 M 选项相同, 不过最后一项也会以换行符 (`n) 结束.

相关

FileSelectFolder, MsgBox, InputBox, ToolTip, GUI, CLSID 列表, 解析循环, SplitPath

此外, 操作系统提供了标准的对话框让用户选取字体, 颜色或图标. 使用 DllCall() 可以显示这些对话框, 演示的例子请参阅 www.autohotkey.com/forum/topic17230.html.

示例

FileSelectFile, SelectedFile, 3, , Open a file, Text Documents (*.txt; *.doc)
if SelectedFile =
    MsgBox, The user didn't select anything.
else
    MsgBox, The user selected the following:`n%SelectedFile%

; CLSID 的例子（XP/2003 或早期系统中）：
FileSelectFile, OutputVar,, ::{645ff040-5081-101b-9f08-00aa002f954e}  ; 回收站。

; 多选的例子：
FileSelectFile, files, M3  ; M3 = 选择多个现有文件。
if files =
{
    MsgBox, The user pressed cancel.
    return
}
Loop, parse, files, `n
{
    if a_index = 1
        MsgBox, The selected files are all contained in %A_LoopField%.
    else
    {
        MsgBox, 4, , The next file is %A_LoopField%.  Continue?
        IfMsgBox, No, break
    }
}
return


FileSelectFolder

显示可以让用户选择文件夹的标准对话框。

FileSelectFolder, OutputVar [, StartingFolder, Options, Prompt]

参数

OutputVar

用来保存用户选择的文件夹的变量名. 如果用户取消了对话框 (即不想选择文件夹), 则此变量被置空. 如果用户选择了根目录 (例如 C:\), 则 OutputVar 会包含末尾的反斜线. 如果不希望这样, 则使用如下方法移除它:

FileSelectFolder, Folder
Folder := RegExReplace(Folder, "\\$")  ; 移除默认的反斜线，如果存在。
StartingFolder

如果为空或省略, 则对话框的初始选择对象为用户的我的文档文件夹 (或可能是我的电脑). 可以指定 CLSID 文件夹 例如 ::{20d04fe0-3aea-1069-a2d8-08002b30309d}（即我的电脑）来从特定的专用文件夹开始导航。

否则, 此参数最常见的用法是星号后面紧跟着初始选择的驱动器或文件夹的绝对路径. 例如，*C:\ 会初始选择 C 驱动器。同样地，*C:\My Folder 会初始选择这个特殊的文件夹。

星号表示允许用户从起始文件夹向上导航 (接近根目录). 如果没有星号，则强制用户在 StartingFolder 中选择文件夹（或 StartingFolder 自身）。省略星号的一个好处是最初 StartingFolder 会显示为树形展开状态, 这样可以节省用户点击前面加号的时间.

如果使用星号, 则向上导航可以被限制到桌面外的其他文件夹. 在星号前加上最上级文件夹的绝对路径跟着一个空格或 tab 即可实现. 在下面的例子中, 将不允许用户导航到比 C:\My Folder 更上级的文件夹 (不过初始选择对象为 C:\My Folder\Projects):
C:\My Folder *C:\My Folder\Projects

选项

下列数字的其中一个:

0: 禁用下面所有选项 (不包括 Windows 2000, 这里可能总是会显示 "新建文件夹" 按钮).

1 (默认): 提供允许用户新建文件夹的按钮.

增加 2 到上面的数字来提供允许用户输入文件夹名称的编辑区域. 例如, 此参数使用数值 3 表示同时提供编辑区域和 "新建文件夹" 按钮.

增加 4 到上面的数字来忽略 BIF_NEWDIALOGSTYLE 属性. 增加 4 确保了 FileSelectFolder 即使在像 WinPE 或 BartPE 这样的预安装环境中也能正常工作. 然而, 这样阻止了 "新建文件夹" 按钮的出现, 至少在 Windows XP 上是这样. ["4" 需要 v1.0.48+]

如果用户在编辑区域中输入了无效的文件夹名称, 则 OutputVar 会被设置为在导航树中选择的文件夹而不是用户输入的内容, 至少在 Windows XP 上是这样.

此参数可以为 表达式.

Prompt

显示在窗口中用来提示用户操作的文本. 如果省略或为空, 则它默认为 "Select Folder - %A_SCRIPTNAME%" (即当前脚本的名称).

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果用户没有选择文件却解除了对话框（例如按下了取消按钮），则 ErrorLevel 被置为 1。如果系统拒绝显示对话框 (罕见), 那么它也被设置为 1. 否则被置为 0.

备注

GUI 窗口可以使用 Gui +OwnDialogs 的方法显示模态的文件夹选择对话框. 模态对话框在其消失之前会阻止用户与 GUI 窗口进行交互.

已知限制: 在显示 FileSelectFolder 对话框时运行的 计时器 会延迟用户在对话框中点击的效果到计时器结束之后. 要变通解决此问题, 请避免使用子程序需要很长时间来完成的计时器, 或在显示对话框期间禁用所有计时器:

Thread, NoTimers
FileSelectFolder, OutputVar,, 3
Thread, NoTimers, false

相关

FileSelectFile, MsgBox, InputBox, ToolTip, GUI, CLSID 列表, FileCopyDir, FileMoveDir, SplitPath

此外, 操作系统提供了标准的对话框让用户选取字体, 颜色或图标. 使用 DllCall() 可以显示这些对话框, 演示的例子请参阅 www.autohotkey.com/forum/topic17230.html.

示例

FileSelectFolder, OutputVar, , 3
if OutputVar =
    MsgBox, You didn't select a folder.
else
    MsgBox, You selected folder "%OutputVar%".

CLSID 的例子:
FileSelectFolder, OutputVar, ::{20d04fe0-3aea-1069-a2d8-08002b30309d}  ; 我的电脑.


FileSetAttrib

改变一个或多个文件或文件夹的属性。支持通配符。

FileSetAttrib, Attributes [, FilePattern, OperateOnFolders?, Recurse?]

参数

Attributes

要改变的属性 (请参阅备注).

FilePattern
单个文件或文件夹的名称或者通配符模式，例如 C:\Temp\*.tmp。如果未指定绝对路径则假定 FilePattern 在 %A_WorkingDir%。

如果省略, 则使用最内层 文件循环 的当前文件.

OperateOnFolders?

0 (默认) 不对文件夹进行操作 (仅文件).
1对匹配通配符模式的所有文件和文件夹进行操作.
2仅对文件夹进行操作 (不操作文件).

注: 如果 FilePattern 是单个文件夹而不是通配符模式, 那么总是忽略此设置.

此参数可以为 表达式.

递归？

0 (默认) 不对子文件夹进行递归.
1递归子文件夹, 以便对包含在其中的匹配 FilePattern 的所有文件和文件夹进行操作. 将递归所有子文件夹, 而不仅是名称匹配 FilePattern 的那些. 但是, 文件和文件夹的完整路径和名称超过 259 个字符时, 这些文件和文件夹会被跳过, 就像它们不存在一样. 这样的文件很罕见, 因为操作系统一般不允许创建它们.

此参数可以为 表达式.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

ErrorLevel 被设置为改变属性 失败 的文件数, 否则为 0.

如果找到了文件, 则 A_LastError 会被设置为 0 (零) 或最近一次操作失败时调用操作系统 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

备注

Attributes 参数由运算符和属性字母的集合组成.

运算符:

+ | 启用属性
- | 取消属性
^ | 切换属性 (设置为与现在相反的值)

属性字母:
R = 只读
A = 存档
S = 系统
H = 隐藏
N = 普通 (仅在单独使用此属性时才有效)
O = 离线
T = 临时

注: 当前, 此命令无法改变文件的压缩状态.

相关

FileGetAttrib, FileGetTime, FileSetTime, FileGetSize, FileGetVersion, 文件循环

示例

FileSetAttrib, +RH, C:\MyFiles\*.*, 1  ; +RH 等同于 +R+H
FileSetAttrib, ^H, C:\MyFiles  ; 切换文件夹的 "隐藏" 属性.
FileSetAttrib, -R+A, C:\New Text File.txt
FileSetAttrib, +A, C:\*.ini, , 1  ; 递归 C 驱动器上的所有 .ini 文件.


FileSetTime

改变一个或多个文件或文件夹的时间戳。支持通配符。

FileSetTime [, YYYYMMDDHH24MISS, FilePattern, WhichTime, OperateOnFolders?, Recurse?]

参数

YYYYMMDDHH24MISS

如果为空或省略, 则它默认为当前时间. 否则, 指定操作使用的时间 (请参阅备注了解时间的格式). 不支持 1601 以前的年份.

此参数可以为 表达式. 因此, 如果需要连接多个变量来形成单个时间戳, 则应该使用 点运算符 代替百分号. 例如：FileSetTime, Year . Month . Day, C:\My File.txt。

FilePattern

单个文件或文件夹的名称或者通配符模式, 例如 C:\Temp\*.tmp. 如果未指定绝对路径则假定 FilePattern 在 %A_WorkingDir% 中.

如果省略, 则使用最内层 文件循环 的当前文件.

WhichTime
要设置的时间戳:
M = 修改时间 (如果此参数为空或省略, 这是默认的)
C = 创建时间
A = 上次访问时间
OperateOnFolders?

0 (默认) 不对文件夹进行操作 (仅文件).
1对匹配通配符模式的所有文件和文件夹进行操作.
2仅对文件夹进行操作 (不操作文件).

注: 如果 FilePattern 是单个文件夹而不是通配符模式, 那么总是忽略此设置.

此参数可以为 表达式.

递归？

0 (默认) 不对子文件夹进行递归.
1递归子文件夹, 以便对包含在其中的匹配 FilePattern 的所有文件和文件夹进行操作. 将递归所有子文件夹, 而不仅是名称匹配 FilePattern 的那些. 但是, 文件和文件夹的完整路径和名称超过 259 个字符时, 这些文件和文件夹会被跳过, 就像它们不存在一样. 这样的文件很罕见, 因为操作系统一般不允许创建它们.

此参数可以为 表达式.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

ErrorLevel 被设置为改变属性 失败 的文件数, 否则为 0. 如果指定的时间戳无效或 FilePattern 解析结果为空值, 则 ErrorLevel 被置为 1.

如果找到了文件, 则 A_LastError 会被设置为 0 (零) 或最近一次操作失败时调用操作系统 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

备注

在 FAT16 & FAT32 卷上的文件上次访问时间可能不如在 NTFS 卷上那么精确.

YYYYMMDDHH24MISS 格式中元素表示的含义分别为:

YYYY | 4 位数的年份
MM | 2 位数的月份 (01-12)
DD | 月的 2 位数的天数 (01-31)
HH24 | 24 小时格式的 2 位小时数 (00-23). 例如, 09 是 9am 而 21 是 9pm.
MI | 2 位数的分钟数 (00-59)
SS | 2 位数的秒数 (00-59)

如果只给出了 YYYYMMDDHH24MISS 中的部分字符串 (例如 200403), 则任何省略的元素将使用下面的默认值:

MM: 月份 01
DD: 日期 01
HH24: 小时 00
MI: 分钟 00
SS: 秒 00

内置变量 A_Now 包含了上述格式的当前本地时间. 同样地, A_NowUTC 包含了当前的协调世界时.

注: 使用 EnvAdd 和 EnvSub 可以对日期时间值进行比较和加减. 此外, 最后不要使用大于或小于来比较时间, 除非它们的字符串长度相同. 这是因为此时它们被视为数字进行比较; 例如, 20040201 数值上总是小于 (但时间顺序上较后) 200401010533. 所以应该使用 EnvSub 来计算出它们之间的时间差是正数还是负数.

相关

FileGetTime, FileGetAttrib, FileSetAttrib, FileGetSize, FileGetVersion, FormatTime, 文件循环, EnvAdd, EnvSub

示例

; 设置所有匹配文件的修改时间为当前时间:
FileSetTime, , C:\temp\*.txt

; 设置修改日期 (时间将为午夜):
FileSetTime, 20040122, C:\My Documents\test.doc

; 设置创建日期. 把时间设置为 4:55pm:
FileSetTime, 200401221655, C:\My Documents\test.doc, C

; 改变匹配一种模式的所有文件的修改时间.
; 由于最后一个参数的作用, 所以也会改变所有匹配的文件夹.:
FileSetTime, 20040122165500, C:\Temp\*.*, M, 1


IfExist / IfNotExist

检查文件或文件夹是否存在。

IfExist, FilePattern
IfNotExist, FilePattern
AttributeString := FileExist(FilePattern)

参数

FilePattern

需检查的路径, 文件名或文件模式. 如果未指定绝对路径则假定 FilePattern 在 %A_WorkingDir% 中.

相关

FileExist(), 区块, Else, 文件循环

示例

IfExist, D:\
    MsgBox, The drive exists.
IfExist, D:\Docs\*.txt
    MsgBox, At least one .txt file exists.
IfNotExist, C:\Temp\FlagFile.txt
    MsgBox, The target file does not exist.


IniDelete

删除标准格式的 .ini 文件中的值。

IniDelete, Filename, Section [, Key]

参数

Filename

.ini 文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

Section

.ini 文件中的段名, 它是包含在方括号中的标题短语 (在此参数中不需要加方括号).

键

.ini 文件中的键名. 如果省略, 将删除整个 Section.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

标准的 ini 文件看起来类似下面这样:

[SectionName]
Key=Value

相关

IniRead, IniWrite, RegDelete

示例

IniDelete, C:\Temp\myfile.ini, section2, key


IniRead

读取标准格式的 .ini 文件中的值。

IniRead, OutputVar, Filename [, Section, Key, Default]

参数

OutputVar

用来存储获取值的变量名. 如果无法获取到这个值, 此变量会被设置为由 Default 参数提供的值 (如下所述).

[AHK_L 57+]: 如果省略 Key 参数, 那么会获取去除任何注释的指定 Section 的内容. 如果也省略 Section 参数, 那么 OutputVar 中会存储段名列表, 其中每个名称都用换行符 (`n) 隔开.

Filename

.ini 文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

Section

.ini 文件中的段名, 它是包含在方括号中的标题短语 (在此参数中不需要加方括号).

键

.ini 文件中的键名.

Default

当没有找到请求的键时保存到 OutputVar 中的值. 如果省略, 此参数默认为单词 ERROR. 要存储空值 (空字符串), 请指定 %A_Space%.

[AHK_L 57+]: 省略 Key 时不使用此参数.

ErrorLevel

此命令 不会 改变 ErrorLevel. 如果遇到问题, OutputVar 将被设置为如上所述的 Default 值.

备注

操作系统会自动忽略获取字符串中前导和尾随空格/tab.

超过 65,535 字符的值很可能被截短。

标准的 ini 文件看起来类似下面这样:

[SectionName]
Key=Value

Unicode: IniRead 和 IniWrite 依靠外部函数 GetPrivateProfileString 和 WritePrivateProfileString 来读取和写入值. 这些函数仅支持 UTF-16 编码的 Unicode 文件; 其他所有文件都被认为使用系统默认 ANSI 代码页.

相关

IniDelete, IniWrite, RegRead, 文件读取循环, FileRead

示例

IniRead, OutputVar, C:\Temp\myfile.ini, section2, key
MsgBox, The value is %OutputVar%.


IniWrite

写入值到标准格式的 .ini 文件。

IniWrite, Value, Filename, Section [, Key]

参数

值

将被写入到 Key 的等号 (=) 右边的字符串或数字. 如果文本较长, 可以通过 延续片段 的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

[AHK_L 57+]: 如果省略 Key, 那么此参数应该包含要写入到 .ini 文件的全部的段内容, 不包括 [SectionName] 标题.

Filename

.ini 文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

Section

.ini 文件中的段名, 它是包含在方括号中的标题短语 (在此参数中不需要加方括号).

键

.ini 文件中的键名.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

超过 65,535 字符的值很可能被截短。

标准的 ini 文件看起来类似下面这样:

[SectionName]
Key=Value

Unicode: IniRead 和 IniWrite 依靠外部函数 GetPrivateProfileString 和 WritePrivateProfileString 来读取和写入值. 这些函数仅支持 UTF-16 编码的 Unicode 文件; 其他所有文件都被认为使用系统默认 ANSI 代码页. 在 Unicode 脚本 中, IniWrite 为每个新文件使用 UTF-16 编码. 如果不希望这样, 那么请确保在执行 IniWrite 前目标文件已经存在. 例如：

FileAppend,, NonUnicode.ini, CP0 ; 在大多数情况下最后一个参数是可选的.

相关

IniDelete, IniRead, RegWrite

示例

IniWrite, this is a new value, C:\Temp\myfile.ini, section2, key


Loop（文件和文件夹）

获取指定的文件或文件夹，每次一个。

Loop, FilePattern [, IncludeFolders?, Recurse?]

参数

FilePattern

单个文件或文件夹的名称或者通配符模式，例如 C:\Temp\*.tmp。如果未指定绝对路径则假定 FilePattern 在 %A_WorkingDir%。

支持星号和问号作为通配符使用. 当模式出现在文件的长/普通名称或其 8.3 短名称 时出现匹配.

如果此参数为单个文件或文件夹 (即不含通配符) 且 Recurse 为 1, 同时指定的文件名出现在多个被搜索的文件夹中, 那么将找到多个匹配.

IncludeFolders?

使用下列的其中一个数字, 或留空以使用默认值:
0 (默认) 不获取文件夹 (仅文件).
1获取所有匹配通配符模式的文件和文件夹.
2仅获取文件夹 (不获取文件).

递归？
使用下列的其中一个数字, 或留空以使用默认值:
0 (默认) 不对子文件夹进行递归.
1递归子文件夹, 以便获取包含在其中的匹配 FilePattern 的文件和文件夹. 将递归所有子文件夹, 而不仅是名称匹配 FilePattern 的那些.

可在文件循环中使用的特殊变量

下列变量存在于任何文件循环中。如果一个内层文件循环包含在一个外层文件循环中，那么最内层循环的文件将具有优先权：

A_LoopFileName | 当前获取的文件或文件夹的名称 (不含路径).
A_LoopFileExt | 当前文件的扩展名 (例如 TXT, DOC 或 EXE). 不含句点 (.).
A_LoopFileFullPath | 当前获取的文件/文件夹的路径和名称. 如果 FilePattern 包含相对路径而不是绝对路径，那么这里的路径也是相对路径。此外，FilePattern 中的任何短（8.3）文件夹名称仍将为短名称（请参阅下一项来获取长名称）。
A_LoopFileLongPath | 此变量与 A_LoopFileFullPath 有以下不同之处: 1) 不论 FilePattern 包含的是否为相对路径, 它总是包含文件的绝对/完整路径; 2) 在 FilePattern 中的任何短 (8.3) 文件夹名称被转换成它们的长名称; 3) 在 FilePattern 中的字符被转换成与文件系统中存储的名称一致的大小写形式. 把文件名转换为资源管理器中显示的准确路径名称时这很有用, 例如作为命令行参数传递给脚本的那些.
A_LoopFileShortPath

当前获取的文件/文件夹的 8.3 短路径和名称. 例如: C:\MYDOCU~1\ADDRES~1.txt. 如果 FilePattern 包含相对路径而不是绝对路径，那么这里的路径也是相对路径。

要获取单个文件或文件夹的完整的 8.3 路径和名称, 像这个例子那样在 FilePattern 中指定其名称:

Loop, C:\My Documents\Address List.txt
    ShortPathName = %A_LoopFileShortPath%

注意: 如果文件没有短名称, 那么此变量将为 空, 这种情况会发生在注册表中设置了 NtfsDisable8dot3NameCreation 的系统上. 如果 FilePattern 包含相对路径且循环体中使用 SetWorkingDir 从当前循环的有效的工作目录中切换出来, 那么它也将为空.
A_LoopFileShortName | 8.3 短名称或文件的备用名称. 如果文件没有此名称 (由于长名称比 8.3 形式更短或也许因为在 NTFS 文件系统上禁止生成短名称), 将获取 A_LoopFileName 作为代替.
A_LoopFileDir | A_LoopFileName 所在目录的路径。如果 FilePattern 包含相对路径而不是绝对路径，那么这里的路径也是相对路径。根目录将不包含末尾的反斜线. 例如: C:
A_LoopFileTimeModified | 文件的上次修改时间. 格式为 YYYYMMDDHH24MISS.
A_LoopFileTimeCreated | 文件的创建时间. 格式为 YYYYMMDDHH24MISS.
A_LoopFileTimeAccessed | 文件的上次访问时间. 格式为 YYYYMMDDHH24MISS.
A_LoopFileAttrib | 当前获取的文件的 属性.
A_LoopFileSize | 以字节为单位的当前获取的文件的大小. 同样支持大于 4 GB 的文件.
A_LoopFileSizeKB | 以 KB 为单位的当前获取的文件的大小, 向下取整到最近的整数.
A_LoopFileSizeMB | 以 MB 为单位的当前获取的文件的大小, 向下取整到最近的整数.

备注

当您想对文件和/或文件夹集合中的项逐个进行操作时, 文件循环很有用.

所有匹配的文件都被获取, 包括隐藏文件. 相比之下, 诸如 DIR 命令的 OS 特性默认忽略隐藏文件. 要避免处理隐藏, 系统和/或只读文件, 在循环中使用类似下面的方法:

if A_LoopFileAttrib contains H,R,S  ; 跳过具有 H (隐藏), R (只读) 或 S (系统) 属性的任何文件. 注意: 在 "H,R,S" 中不含空格.
    continue  ; 跳过这个文件并前进到下一个.

要在递归搜索中获取文件的相对路径而不是绝对路径，在循环之前使用 SetWorkingDir 来改变工作目录为基文件夹，且在接着的 Loop 中省略路径（例如 Loop, *.*, 0, 1）。这样将使得 A_LoopFileFullPath 包含相对于基文件夹的文件路径。

如果文件循环在其范围中创建或重命名文件或文件夹, 那么会扰乱它自己. 例如, 如果它通过 FileMove 或其他方法重命名文件, 每个这样的文件可能被找到两次: 一次是作为其旧名称, 再一次则作为其新名称. 要变通解决此问题, 创建需重命名文件的列表后才重命名这些文件. 例如：

FileList =
Loop *.jpg
   FileList = %FileList%%A_LoopFileName%`n
Loop, parse, FileList, `n
   FileMove, %A_LoopField%, renamed_%A_LoopField%

在 NTFS 文件系统中的文件可能总是按字母顺序来获取. 在其他文件系统中的文件则没有特殊的获取顺序. 要使用特殊的获取顺序, 使用 Sort 命令, 如同下文示例部分演示的那样.

文件和文件夹的完整路径和名称超过 259 个字符时, 这些文件和文件夹会被跳过, 就像它们不存在一样. 这样的文件很罕见, 因为操作系统一般不允许创建它们.

请参阅 Loop 了解关于区块、Break、Continue 和 A_Index 变量（其存在于各种类型的循环中）的相关信息。

相关

Loop, Break, Continue, 区块, SplitPath, FileSetAttrib, FileSetTime

示例

; 示例 #1:
Loop, %A_ProgramFiles%\*.txt, , 1  ; 递归子文件夹.
{
    MsgBox, 4, , Filename = %A_LoopFileFullPath%`n`nContinue?
    IfMsgBox, No
        break
}

; 示例 #2: 计算文件夹的大小, 包括其所有子文件夹中的文件:
SetBatchLines, -1  ; 让操作以最快速度进行.
FolderSizeKB = 0
FileSelectFolder, WhichFolder  ; 让用户选取文件夹.
Loop, %WhichFolder%\*.*, , 1
    FolderSizeKB += %A_LoopFileSizeKB%
MsgBox Size of %WhichFolder% is %FolderSizeKB% KB.

; 示例 #3: 获取根据名称排序的文件名（要以日期排序请参阅后一个例子）：
FileList =  ; 初始为空.
Loop, C:\*.*
    FileList = %FileList%%A_LoopFileName%`n
Sort, FileList, R  ; R 选项使得以逆序排列. 请参阅 Sort 了解其他选项。
Loop, parse, FileList, `n
{
    if A_LoopField =  ; 忽略列表末尾的空项.
        continue
    MsgBox, 4,, File number %A_Index% is %A_LoopField%.  Continue?
    IfMsgBox, No
        break
}

; 示例 #4: 获取根据修改日期排序的文件名:
FileList =
Loop, %A_MyDocuments%\Photos\*.*, 1
    FileList = %FileList%%A_LoopFileTimeModified%`t%A_LoopFileName%`n
Sort, FileList  ; 根据日期排序.
Loop, parse, FileList, `n
{
    if A_LoopField =  ; 忽略列表末尾的最后一个换行符 (空项).
        continue
    StringSplit, FileItem, A_LoopField, %A_Tab%  ; 用 tab 作为分隔符将其分为两部分.
    MsgBox, 4,, The next file (modified at %FileItem1%) is:`n%FileItem2%`n`nContinue?
    IfMsgBox, No
        break
}

; 示例 #5: 仅复制比目标位置中
; 它们的副本更新的源文件:
CopyIfNewer:
; 调用者已经为我们赋值了变量 CopySourcePattern 和 CopyDest.
Loop, %CopySourcePattern%
{
    copy_it = n
    IfNotExist, %CopyDest%\%A_LoopFileName%  ; 如果目标文件还不存在, 那么总是复制.
        copy_it = y
    else
    {
        FileGetTime, time, %CopyDest%\%A_LoopFileName%
        EnvSub, time, %A_LoopFileTimeModified%, seconds  ; 从目的时间中减去源文件的时间.
        if time < 0  ; 源文件比目的文件更新.
            copy_it = y
    }
    if copy_it = y
    {
        FileCopy, %A_LoopFileFullPath%, %CopyDest%\%A_LoopFileName%, 1   ; 以覆盖形式复制
        if ErrorLevel
            MsgBox, Could not copy "%A_LoopFileFullPath%" to "%CopyDest%\%A_LoopFileName%".
    }
}
Return

; 示例 #6: 把通过命令行参数传递的文件名转换为长名称,
; 完整路径和在文件系统中存储的正确的大写/小写字符形式.
Loop %0%  ; 对于拖放到脚本上 (或作为参数传递) 的每个文件.
{
    GivenPath := %A_Index%  ; 获取下一个命令行参数.
    Loop %GivenPath%, 1
        LongPath = %A_LoopFileLongPath%
    MsgBox The case-corrected long path name of file`n%GivenPath%`nis:`n%LongPath%
}


Loop（读取文件内容）

逐行读取文本文件的内容，每次一行（比 FileReadLine 执行的更好）。

Loop, Read, InputFile [, OutputFile]

参数

Read

此参数必须为单词 READ.

InputFile

需要在循环中读取内容的文本文件的名称, 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 支持 Windows 和 Unix 格式; 即文件的行结束符可以是回车和换行符 (`r`n) 或只是换行符 (`n).

OutputFile

(可选的) 在循环期间保持打开的文件的名称, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

在循环体内, 使用仅带一个参数 (写入的文本) 的 FileAppend 命令来追加文本到此指定的文件. 以这种方式追加文本到文件比使用 2 个参数模式的 FileAppend 执行地更好, 因为每次操作时不需要关闭文件再重新打开. 如果需要, 记得在写入的文本后加上换行符 (`n).

如果没有写入内容到此文件, 那么它不会被打开. 当 Loop 的循环次数为零或其循环体中没有使用 FileAppend 命令时会发生这种情况.

二进制模式: 要以二进制模式而不是文本模式追加数据, 在文件名前面加上星号. 这使得每个换行符 (`n) 作为单个换行符 (LF) 而不是 Windows 标准的 CR+LF 写入. 例如：*C:\My Unix File.txt。即使没有星号，如果 Loop 中首次使用 FileAppend 时写入任何回车和换行符对（`r`n），这时二进制模式也会自动生效。

标准输出 (stdout): 指定 OutputFile 为星号 (*) 可以把 FileAppend 写入的任何文本发送到标准输出 (stdout). 尽管这样的输出可以重定向到文件, 指向另一个 EXE 的管道或被 高级文本编辑器 捕获, 然而它不会出现在运行它的命令提示符中. 请参阅 FileAppend 了解详细信息。

逗号转义: 与其他大多数命令的最后一个参数不同, 在 OutputFile 中的逗号必须进行转义 (`,).

备注

当您想对包含在文本文件中的内容逐行进行操作时, 文件读取循环很有用. 它比 FileReadLine 执行的更好, 因为: 1) 在整个操作过程中文件一直保持打开状态; 2) 不需要每次都重新扫描文件来查找请求的行内容.

内置变量 A_LoopReadLine 存在于任何文件读取循环中。它包含了已去除行尾的回车换行符 (`r`n) 的当前行内容. 如果一个内层文件读取循环包含在一个外层文件读取循环中，则最内层循环的文件行将具有优先权。

最大可以读取包含 65,534 字符的长行. 如果某行超出这个长度, 此行的剩余字符将在下一次循环中读取.

经常在文件读取循环中使用 StringSplit 或 解析循环 解析从 InputFile 读取的每行内容. 例如, 如果 InputFile 文件中的各行是由 tab 分隔的片段, 那么可以单独获取这些片段, 例如:

Loop, read, C:\Database Export.txt
{
    Loop, parse, A_LoopReadLine, %A_Tab%
    {
        MsgBox, Field number %A_Index% is %A_LoopField%.
    }
}

要加载整个文件内容到变量中, 使用 FileRead, 因为它比循环执行的更好 (尤其对于大文件).

要同时打开多个文件, 请参考 此例 使用 DllCall().

请参阅 Loop 了解关于区块、Break、Continue 和 A_Index 变量（其存在于各种类型的循环中）的相关信息。

在不存在字节顺序标记时要控制如何解码文件, 使用 FileEncoding.

相关

FileEncoding, FileOpen/文件对象, FileRead, FileReadLine, FileAppend, Sort, Loop, Break, Continue, 区块, FileSetAttrib, FileSetTime

示例

; 示例 #1: 在首个文件中只有包含单词 FAMILY 的那些行才会写入第二个文件中.
; 取消注释首行可以覆盖而不追加到任何现有的文件.
;FileDelete, C:\Docs\Family Addresses.txt

Loop, read, C:\Docs\Address List.txt, C:\Docs\Family Addresses.txt
{
    IfInString, A_LoopReadLine, family, FileAppend, %A_LoopReadLine%`n
}

; 示例 #2: 获取文本文件的最后一行.
Loop, read, C:\Log File.txt
    last_line := A_LoopReadLine  ; 当循环结束时, 这里会保持最后一行的内容.

; 示例 #3: 尝试从文本或 HTML 文件中提取
; 所有 FTP 和 HTTP URL 的有效脚本:
FileSelectFile, SourceFile, 3,, Pick a text or HTML file to analyze.
if SourceFile =
    return  ; 此时将退出.

SplitPath, SourceFile,, SourceFilePath,, SourceFileNoExt
DestFile = %SourceFilePath%\%SourceFileNoExt% Extracted Links.txt

IfExist, %DestFile%
{
    MsgBox, 4,, Overwrite the existing links file? Press No to append to it.`n`nFILE: %DestFile%
    IfMsgBox, Yes
        FileDelete, %DestFile%
}

LinkCount = 0
Loop, read, %SourceFile%, %DestFile%
{
    URLSearchString = %A_LoopReadLine%
    Gosub, URLSearch
}
MsgBox %LinkCount% links were found and written to "%DestFile%".
return

URLSearch:
; 由于在一些 URL 中内嵌有其他的 URL, 所以用这种特殊的方法进行处理:
StringGetPos, URLStart1, URLSearchString, http://
StringGetPos, URLStart2, URLSearchString, ftp://
StringGetPos, URLStart3, URLSearchString, www.

; 查找最左边的起始位置:
URLStart = %URLStart1%  ; 设置默认的起始处.
Loop
{
    ; 仅解析 "URLStart%A_Index%" 一次有助于
    ; 改善性能 (尤其在含有许多变量的脚本中):
    ArrayElement := URLStart%A_Index%
    if ArrayElement =  ; 到达伪数组的末尾。
        break
    if ArrayElement = -1  ; 此元素无效。
        continue
    if URLStart = -1
        URLStart = %ArrayElement%
    else ; URLStart 中含有有效位置，所以把它与 ArrayElement 进行比较。
    {
        if ArrayElement <> -1
            if ArrayElement < %URLStart%
                URLStart = %ArrayElement%
    }
}

if URLStart = -1  ; 在 URLSearchString 中不存在网址。
    return

; 否则，提取该网址：
StringTrimLeft, URL, URLSearchString, %URLStart%  ; 忽略开始/无效部分。
Loop, parse, URL, %A_Tab%%A_Space%<>  ; 找到首个空格、tab 或尖括号（如果有）。
{
    URL = %A_LoopField%
    break  ; 即仅执行一次循环来获取首个“片段”。
}
; 如果没有找到结束字符而在上面的循环中没有执行循环体，
; 那么保持网址变量的内容不变。

; 如果网址以双引号结束，那么移除它。暂时使用 StringReplace，不过注意
; 双引号似乎可以合法存在于网址中，所以这样做
; 可能破坏它们：
StringReplace, URLCleansed, URL, ",, All
FileAppend, %URLCleansed%`n
LinkCount += 1

; 看看当前行中是否含有其他网址：
StringLen, CharactersToOmit, URL
CharactersToOmit += %URLStart%
StringTrimLeft, URLSearchString, URLSearchString, %CharactersToOmit%
Gosub, URLSearch  ; 到自身的递归调用。
return


SetWorkingDir

改变脚本的当前工作目录。

SetWorkingDir, DirName

参数

DirName

新工作目录的名称, 如果未指定绝对路径则假定在当前 %A_WorkingDir% 的子目录中.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

脚本的工作目录是用来访问未指定绝对路径的文件和文件夹的默认目录. 在下面的例子中，将假定文件 My Filename.txt 在 %A_WorkingDir% 中：FileAppend, A Line of Text, My Filename.txt。

脚本的初始工作目录取决于它的启动方式. 例如, 如果是通过开始菜单中的快捷方式启动的, 则它的工作目录由快捷方式属性中的 "起始位置" 字段决定.

要让脚本无条件使用它所在的文件夹作为工作目录, 请在脚本首行中使用下列语句:

SetWorkingDir %A_ScriptDir%

一旦改变后, 新的工作目录会立即生效并对整个脚本起作用. 所有被中断的, 暂停的 和新启动的 线程 都会受影响, 包括 计时器.

相关

%A_WorkingDir%, %A_ScriptDir%, FileSelectFolder

示例

SetWorkingDir %A_ScriptDir%
SetWorkingDir, D:\My Folder\Temp


SplitPath

把文件名或 URL 分解成它的名称、目录、扩展名和驱动器。

SplitPath, InputVar [, OutFileName, OutDir, OutExtension, OutNameNoExt, OutDrive]

参数

InputVar

包含要分解的文件名的变量名.

OutFileName

用来保存不带路径的文件名的变量名. 包含文件的扩展名.

OutDir

用来保存文件目录的变量名，包含驱动器字母或共享名（如果有）。即使文件在驱动器的根目录中也不包含最后的反斜线.

OutExtension

用来保存文件扩展名 (例如 TXT, DOC 或 EXE) 的变量名. 不包含句点.

OutNameNoExt

用来保存不带路径, 句点和扩展名的变量名.

OutDrive

用来保存文件的驱动器字母或共享名的变量名. 如果文件在本地或映射的驱动器中, 则此变量会被设为驱动器字母后跟着冒号 (没有反斜线). 如果文件在网络路径中 (UNC), 则变量会被设为共享名, 例如 \\Workstation01

备注

如果不需要相应的信息, 则可以省略相应的输出变量.

如果 InputVar 包含不带驱动器字母的文件名 (即没有路径或只是相对路径), 则 OutDrive 会被赋值为空, 但其他变量会被设置正确. 同样地, 如果没有路径, 则 OutDir 会被赋值为空; 而如果有路径但没有文件名, 则 OutFileName 和 OutNameNoExt 都会被置空.

此命令不会检查文件系统中真实的文件和目录. 它只是简单地分析 InputVar 中的字符串.

文件名中的通配符 (* 和 ?) 及其他非法字符被视为等同于合法字符, 除了冒号, 反斜线和句点, 对它们处理时会根据它们在文件的驱动器字母, 目录和扩展名中的性质进行.

对 URL 的支持: 如果 InputVar 包含一个冒号后跟两个斜线, 例如 http://domain.com 或 ftp://domain.com, 则 OutDir 会被设置为协议前缀加域名加目录 (例如 http://domain.com/images) 而 OutDrive 被设置为协议前缀加域名 (例如 http://domain.com). 其他所有变量会根据上面的定义对它们进行设置.

相关

A_LoopFileExt, StringSplit, StringGetPos, StringMid, StringTrimLeft, StringLeft, FileSelectFile, FileSelectFolder

示例

FullFileName = C:\My Documents\Address List.txt

; 只获取上面的单独的文件名:
SplitPath, FullFileName, name

; 只获取目录:
SplitPath, FullFileName,, dir

; 获取所有信息:
SplitPath, FullFileName, name, dir, ext, name_no_ext, drive

; 上面这行会对变量进行如下设置:
; name = Address List.txt
; dir = C:\My Documents
; ext = txt
; name_no_ext = Address List
; drive = C:


#Include

#Include / #IncludeAgain

让脚本认为指定文件的内容会出现在这个准确的位置。

#Include FileOrDirName
#Include <LibName>
#IncludeAgain FileOrDirName

参数

FileOrDirName

文件或目录的路径，接着会详细说明。这里不能包含双引号、通配符和除 %A_ScriptDir%、%A_AppData%、%A_AppDataCommon% 及（在 v1.1.11+）%A_LineFile% 外的变量引用。不能使用除分号（`;）外的其他转义序列，也不需要使用它们，因为像百分号这样的字符会被当成原义处理。

File: 要包含的文件名, 如果未指定绝对路径, 则假定在启动/工作目录 (除了 ahk2exe, 它会假定文件在脚本自身目录). 注意：SetWorkingDir 对 #Include 没有效果，因为在脚本开始执行前已经处理了 #Include。

Directory: 指定目录而不是文件来改变后续所有的 #Include 和 FileInstall 使用的工作目录. 注意：用这种方式改变工作目录不会影响脚本启动时的初始工作目录 （A_WorkingDir）。要改变初始工作目录，请在脚本的顶部使用 SetWorkingDir。

LibName

[AHK_L 57+]: 库文件或函数的名称. 例如, #include <lib> 和 #include <lib_func> 都会包含某个 函数库文件夹 中的 lib.ahk.

备注

脚本认为包含文件的内容实际会出现在 #Include 指令的准确位置 (就好像从包含的文件中复制粘贴过来一样). 因此, 它通常不能把两个孤立的脚本合并成一个可运行的脚本 (要实现这样的效果, 请参阅 www.autohotkey.com/forum/topic18545.html).

#Include 确保仅包含 FileName 一次, 即使它遇到多次重复的包含. 与之相比, #IncludeAgain 允许多次包含同一文件, 其他方面则和 #Include 一样.

可以在 FileName 参数前加上 *i 和单个空格，这样会使程序忽略读取包含文件时出现的任何问题。例如：#Include *i SpecialOptions.ahk。此选项应该仅在包含文件的内容对主脚本的操作可有可无的情况下才使用.

通过 ListLines 或菜单 View->Lines 显示在主窗口的那些行总是按照它们在文件内的物理顺序编号的. 换句话说, 包含新文件只会改变主脚本文件的一行编号, 即 #Include 所在行 (除了 已编译脚本, 它会在编译时把它们包含的文件合并成一个大的脚本).

#Include 常用来加载在外部文件中定义的 函数. 和子程序标签不同, 可以在脚本的顶部包含 函数 而不影响 自动执行段.

与其他 # 指令类似, 不能根据条件执行 #Include. 换句话说, 这个例子不起作用:

if x = 1
    #Include SomeFile.ahk  ; 不管 x 的值是什么此行都会执行.
    y = 2  ; 而此行属于上面的 IF, 因为 # 指令不属于 IF.

通过调用 库函数 中的函数名称可以自动将文件包含进来 (即不需要使用 #Include).

[v1.1.11+]：使用%A_LineFile%\.. 可以引用包含当前文件的目录，即使当前文件不是主脚本文件也有效。例如，#Include %A_LineFile%\..\other.ahk。

相关

函数库, 函数, FileInstall

示例

#Include C:\My Documents\Scripts\Utility Subroutines.ahk
#Include %A_ScriptDir%  ; 为后续的 #Include 和 FileInstall 改变工作目录.
#Include C:\My Scripts  ; 和上面相同, 不过这里指定明确的命名目录.


{...} (区块)

一对大括号组成的区域表示一个区块。区块通常与函数、Else、Loop、While 循环和 IF 命令一起使用。

{
零行或多行命令
}

备注

使用区块可以绑定两行或多行命令. 还可以用它改变 IF 与 ELSE 从属关系, 例如在此例中, 区块强制 ELSE 从属于首个 IF 而不是第二个:

if var1 = 1
{
    if var2 = abc
        sleep, 1
}
else
    return

尽管区块可以用在脚本中的任何位置, 不过目前它们仅在与 函数, Else, Loop 或 IF 类型的命令例如 IfEqual 或 IfWinExist 一起使用时才有意义.

如果 IF, ELSE, Loop, While 循环 或 For 循环 中仅含单行命令, 那么此命令可以不需要括在区块中. 不过, 这样做也许可以提高脚本的可读性和可维护性.

区块中可以为空 (不含任何命令), 当您想注释区块中的内容而不移除区块时这很有用.

One True Brace（OTB，K&R风格）：在后面这些位置中可以使用OTB风格：表达式型if语句、else关键字、while循环、For循环、普通循环、函数定义、Try、Catch和Finally。这种风格中区块的开括号与区块的控制语句在同一行, 而不是在其下一行. 例如：

if (x < y) {
    ...
} else {
    ...
}
While x < y {
    ...
}
For k,v in obj {
    ...
}
Loop %RepeatCount% {
    ...
}
MyFunction(x, y) {
    ...
}
Try {
    ...
} Catch e {
    ...
} Finally {
    ....
}

同样地, 命令或其他操作可以放在大括号的后面 (但不包括 One True Brace 风格的开括号). 例如：

if x = 1
{ MsgBox This line appears to the right of an opening brace. It executes whenever the IF-statement is true.
    MsgBox This is the next line.
} MsgBox This line appears to the right of a closing brace. It executes unconditionally.

相关

函数, While 循环, Loop, Else, If, If(Expression)

示例

if x = 1
{
    MsgBox, test1
    Sleep, 5
}
else
    MsgBox, test2


中断

退出（终止）循环。在各种循环中都是有效的。

Break [, LoopLabel]

[AHK_L 59+]：如果指定了 LoopLabel，它确定了此语句应该应用于哪层循环；使用标签名或嵌套层级的数值表示。如果省略或为 1，此语句应用于它所在的最内层循环。LoopLabel 必须为常量，不支持变量和表达式。如果指定标签，则它必须直接指向循环命令。

鼓励使用 Break 和 Continue 代替 goto 因为它们通常让脚本更容易阅读和维护.

相关

Continue、Loop、While 循环、For 循环、区块、标签

示例

Loop
{
    ...
    if var > 25
        break
    ...
    if var <= 5
        continue
}
; 从内嵌循环内部退出到外层循环.
outer:
Loop 3
{
    x := A_Index
    Loop 3
    {
        if (x*A_Index = 6)
            break outer  ; 等同于 break 2 或 goto break_outer.
        MsgBox %x%,%A_Index%
    }
}
break_outer: ; 用于 goto 命令.


Catch

Catch [v1.1.04+]

指定在执行 try 语句发生异常时执行的代码。

Catch [, OutputVar]
    Statement
Catch [, OutputVar]
{
    Statements
}

参数

OutputVar

(可选) 用来存储异常值的变量名称.

Statement(s)

发生异常时执行的命令或表达式.

备注

每次使用 catch 都必须附属于 (与之关联) 它上面的 try 语句. catch总是附属于在它上面且离它最近的无主try语句，不过可以使用区块改变这种行为。

可以使用 One True Brace (OTB) 风格. 例如：

try {
    ...
} catch e {
    ...
}

运行时错误

try-catch 语句同样可以用来处理运行时错误. 有两类的运行时错误：设置 ErrorLevel 的那些和在显示错误消息后会让当前线程退出的那些。无法处理加载时错误，因为它们在 try 执行前已经发生了。为了能够向后兼容（及在一些时候的方便），在执行 try 区块产生运行时错误时才会抛出异常。大部分命令支持 try-catch；不过当命令执行成功时 ErrorLevel 仍然被置为 0。

存储在OutputVar（如果存在）中的值是包含下列字段的异常对象：

What: 错误发生时正在或即将执行的命令或函数的名称.

File: 包含发生错误的语句的脚本文件的完整路径.

Line: 发生错误的语句行号.

Message：错误消息或 ErrorLevel 值。

Extra: 可用时包含错误的额外信息.

注意: 这些细节应该仅用于调试, 因为它们可以在将来的版本中改变.

相关

Try, Throw, Finally, Blocks

示例

请参阅 Try.


继续

跳过当前循环的剩余部分并继续下一次循环。在各种循环中都是有效的。

Continue [, LoopLabel]

[AHK_L 59+]：如果指定了，则 LoopLabel 表示此语句所应用的循环；通过标签名或嵌套层级的数值。如果省略或为 1，此语句应用于它所在的最内层循环。LoopLabel 必须为常量，不支持变量和表达式。如果指定标签，则它必须直接指向循环命令。

Continue 的行为如同直接到达了循环的闭括号:

  1. 它让 A_Index 加 1.
  2. 它跳过了循环体的剩余部分.
  3. 检查循环条件（如果有）判断是否满足。如果满足, 开始新的循环; 否则循环结束.

鼓励使用 Break 和 Continue 代替 goto 因为它们通常让脚本更容易阅读和维护.

相关

Break、Loop、Until、While 循环、For 循环、区块、标签

示例

; 此例显示 5 此MsgBox 消息框, 为从 6 到 10 的每个数字显示一次.
; 注意 Loop 的前 5 次循环, "continue" 命令
; 会使得循环在到达 MsgBox 前重新开始.
Loop, 10
{
    if A_Index <= 5
        continue
    MsgBox %A_Index%
}
; 从内嵌循环内部直接继续新的外层循环.
outer:
Loop 3
{
    x := A_Index
    Loop 3
    {
        if (x*A_Index = 4)
            continue outer  ; 等同于 continue 2 或 goto continue_outer.
        MsgBox %x%,%A_Index%
    }
    continue_outer: ; 用于 goto 命令.
    ErrorLevel:=ErrorLevel ; 在修订号 57 之前, 标签不能指向区块的末尾.
}


Critical

防止当前线程被其他线程中断。

Critical [, Off]
Critical 50 ; 请参阅备注底部。

如果首个参数省略 (或为单词 On), 则设置 当前线程 为关键的, 这意味着它不会被其他线程中断. 如果首个参数为 Off（或在 v1.0.48+ 为数字 0），则当前线程会不论 Thread Interrupt 设置如何都会变成可中断状态。

与 高优先级 线程不同, 在关键线程中产生的事件不会被丢弃. 例如, 在当前线程为关键线程时用户按下了 热键, 那么此热键会被缓冲到当前线程结束或成为非关键线程时才作为新的线程启动.

关键线程也会被紧急事件中断. 紧急事件包括: 1) OnExit 子程序; 2) 监听消息号小于 0x312 的任何 OnMessage() 函数 (或被这些消息触发的 回调); 和 3) 由紧急线程自身间接触发的任何 回调 (例如通过 SendMessage 或 DllCall). 要避免被这些事件中断, 可以临时禁用这些函数.

当被缓冲的事件等待启动新线程时, 使用 "Critical Off" 不会立即中断当前线程. 相反, 需要经过平均 5 毫秒的时间才会进行中断. 这样在中断前, 有 99.999% 的可能性至少执行了 "Critical Off" 后的一行代码. 您可以通过延迟（例如 Sleep -1 或使用 WinWait 等待不存在的窗口），这样可以强制立即产生中断。

关键线程在显示 MsgBox 或其他对话框时, 会变成可中断的. 但是，与 Thread Interrupt 不同，在用户解除对话框后这个线程会再恢复为关键的。

请参阅 A_IsCritical 了解如何保存和恢复 Critical 的当前设置. 然而，由于Critical是特定于线程的设置，所以当关键线程结束后，在它后面的/待恢复的线程（如果有）会自动成为非关键的。因此, 不需要在关键线程结束前执行 "Critical Off".

如果在自动执行段（脚本的顶部）没有使用 Critical，那么所有线程初始都为非关键的（然而还是会应用 Thread Interrupt 的设置）。与之相比, 如果在自动执行段中打开了 Critical 且从没有关闭过, 那么每个新启动的 线程 (例如 热键, 自定义菜单项 或 计时 子程序) 初始都为关键的.

Thread NoTimers 命令类似于 Critical，不过它只防止被计时器中断。

在 v1.0.47+，打开 Critical 的同时也会让 SetBatchLines -1 对当前线程生效。

在 v1.0.47+，在首个参数中使用正数（例如 Critical 30）会打开 Critical，但同时也改变了检查内部消息队列的间隔时间。如果没有指定数字, 则当 Critical 设置为 On 时会每隔 16 毫秒检查消息, 而 Critical 为 Off 时会每隔 5 ms 检查消息. 增加这个间隔可以延迟消息/事件的达到, 这样给 当前线程 更多的时间来结束. 这样降低了由于 "线程已经运行" 而丢失某些 OnMessage() 和 GUI 事件 的可能性. 然而，等待的命令（例如 Sleep 和 WinWait）会不论此设置如何都使用默认间隔检查消息（一种解决方法是 DllCall("Sleep", Uint, 500)）。注意: 增加消息检查间隔太多可能会降低各种事件的实时响应性, 例如 GUI 窗口重绘.

相关

Thread（命令）, 线程, #MaxThreadsPerHotkey, #MaxThreadsBuffer, OnMessage(), RegisterCallback(), Hotkey, Menu, SetTimer

示例

#space::  ; Win+Space 热键.
Critical
ToolTip No new threads will launch until after this ToolTip disappears.
Sleep 3000
ToolTip  ; 关闭提示.
return  ; 从热键子程序中返回, 这样结束了当前线程. 后面的线程会按设置恢复为非关键的.


Else

指定当 IF 语句计算结果为 FALSE 时执行的命令。包含多个命令时，需要把它们括在区块（大括号）中。

Else

备注

每次使用 ELSE 都必须附属于 (与之关联) 它上面的 IF 语句. ELSE总是附属于在它上面且离它最近的无主IF语句，不过可以使用区块改变这种行为。

ELSE的同一行中可以紧跟着其他任何的单个命令。这种形式最常使用于 "else if" 梯形结构 (请参阅底部的例子).

当 IF 或 ELSE 结构中含有多行命令时, 这些命令必须括在大括号中. 不过, 如果只有一行命令从属于 IF 或 ELSE, 那么可以不用大括号. 例如：

if count > 0  ; 下一行可以不需要使用大括号括住, 因为它只有一行.
    MsgBox Press OK to begin the process.
else  ; 下面这部分必须使用大括号括住, 因为它含有多行.
{
    WinClose Untitled - Notepad
    MsgBox There are no items present.
}

One True Brace (OTB) 风格 可以用于 "else" 前后. 例如：

if IsDone {
    ...
} else if (x < y) {
    ...
} else {
    ...
}

相关

请参阅 区块. 还有, 每种 IF 命令都可以使用 ELSE, 包括 IfWinActive, IfWinExist, IfMsgBox, IfInString, IfBetween, IfIn, IF 和 IF (表达式).

示例

IfWinExist, Untitled - Notepad
{
    WinActivate
    Send This is a test.{Enter}
}
else
{
    WinActivate, Some Other Window
    MouseClick, left, 100, 200
}

if x = 1
    Gosub, a1
else if x = 2 ; "else if" 类型
    Gosub, a2
else IfEqual, x, 3 ; 可选类型
{
    Gosub, a3
    Sleep, 1
}
else Gosub, a4  ; 即任何单个命令都可以和 ELSE 放在同一行.

; 这样也行:
IfEqual, y, 1, Gosub, b1
else {
    Sleep, 1
    Gosub, b2
}


Exit

退出当前线程或（如果脚本不是持续运行的且不包含热键时）整个脚本。

Exit [, ExitCode]

参数

ExitCode

一个介于 -2147483648 和 2147483647 之间的整数 (可以为 表达式), 在脚本退出时返回给它的调用者. 此代码可以被任何调用脚本的程序访问, 例如另一个脚本 (使用 RunWait) 或批处理 (.bat) 文件. 如果省略，则 ExitCode 默认为零。零一般用来表示成功.

备注

如果脚本中不含热键, 也不是 持续运行的 且没有让 Num/Scroll/CapsLock 键一直保持 AlwaysOn 或 AlwaysOff, 那么遇到 Exit 时它会立即终止 (除非它含有 OnExit 子程序).

在其他情况下, Exit 命令会终止 当前线程. 换句话说, 由 menu, 计时器 或 热键 直接或间接调用的子程序堆栈全部都会像遇到 Return 那样立即被返回. 如果直接用在这样的子程序内部而不是由它间接调用的某个子程序中, 那么此时 Exit 效果等同于 Return.

使用 ExitApp 来完全终止 持久运行的 或包含热键的脚本.

相关

ExitApp, OnExit, 函数, Gosub, Return, 线程, #Persistent

示例

#z::
Gosub, Sub2
MsgBox, This msgbox will never happen because of the EXIT.
return

Sub2:
Exit  ; 终止当前子程序以及调用它的子程序.


ExitApp

无条件终止脚本。

ExitApp [, ExitCode]

参数

ExitCode

一个介于 -2147483648 和 2147483647 之间的整数 (在 v1.0.48.01+ 中还可以为 表达式), 在脚本退出时返回给它的调用者. 此代码可以被任何调用脚本的程序访问, 例如另一个脚本 (使用 RunWait) 或批处理 (.bat) 文件. 如果省略，则 ExitCode 默认为零。零一般用来表示成功.

备注

如果脚本不含有 OnExit 子程序, 则它会被立即终止. 这等同于从脚本的托盘菜单或主菜单中选择了 "Exit".

如果脚本中不含热键, 也不是 持续运行的 且没有让 Num/Scroll/Capslock 键一直保持 AlwaysOn 或 AlwaysOff, 那么 Exit 和 ExitApp 的效果相同.

如果脚本含有 OnExit 子程序, 则在执行 ExitApp 后它将会运行.

相关

Exit, OnExit, #Persistent

示例

#x::ExitApp  ; 设定热键来终止当前脚本.


Finally

Finally [v1.1.14+]

确保在try语句后总是会执行的一个或多个语句（命令或表达式）。

Finally Statement
Finally
{
    Statements
}

备注

每次使用finally都必须附属于（与之关联）它上面的try（或catch）语句。finally总是附属于它上面且离它最近的无主try语句，不过可以使用区块改变这种行为。

如果finally语句使用在不含catch块的try语句中，则以后无法清除这里出现的异常且在finally语句执行后异常传播仍会继续。

不允许使用goto/break/continue退出finally语句，因为这样会中断异常传播（不过可以在区块中正常使用以确保持续执行）。在加载时会检测到这种错误（以及运行时的动态goto语句）。

One True Brace (OTB)风格可以用于finally命令中。例如：

try {
    ...
} finally {
    ...
}

try {
    ...
} catch e {
    ...
} finally {
    ...
}

相关

Try, Catch, Throw, 区块

示例

try
{
    ToolTip, Working...
    Example1()
}
catch e
{
    ; 关于e对象的更多细节，请参阅Catch。
    MsgBox, 16,, % "Exception thrown!`n`nwhat: " e.what "`nfile: " e.file
        . "`nline: " e.line "`nmessage: " e.message "`nextra: " e.extra
}
finally
{
    ToolTip ; 隐藏工具提示
}

MsgBox, Done!; 此函数包含了清理代码的Finally区块
Example1()
{
    try
        Example2()
    finally
        MsgBox, This is always executed regardless of exceptions
}

; 分钟数为奇数时此函数执行时出错
Example2()
{
    if Mod(A_Min, 2)
        throw Exception("Test exception")
    MsgBox, Example2 did not fail
}


For 循环

For 循环 [AHK_L 59+]

对对象中的每对键值对重复执行一系列命令。

For Key [, Value] in Expression

参数

键

在每次重复开始时用来保存键的变量名称.

值

保存与当前键关联的值的变量名.

Expression

结果为对象的 表达式 或包含对象的变量.

备注

只在循环开始前计算一次 表达式. 如果其结果不是对象, 则立即跳转到循环体后面的语句执行; 否则, 调用对象的 _NewEnum() 来获取 枚举数 对象. 每次重复开始时, 使用枚举数的 Next() 方法获取下一个键值对. 如果 Next() 返回零或空字符串, 则循环终止.

尽管不完全等同于 for 循环, 不过下面演示了近似于它的循环过程:

_enum := (Expression)._NewEnum()
if IsObject(_enum)
    while _enum.Next(Key, Value)
    {
        ...
    }

现有的键值对可以在循环中修改, 但插入或移除键可能导致一些项目被跳过或枚举多次. 一种解决方法是建立待移除的键列表, 在首个循环结束后使用第二个循环来移除这些键. 请注意使用 Object.Remove(first, last) 可以直接移除键的范围而不需要循环.

for 循环后通常跟着 区块, 这是构成循环 体 的语句的集合. 不过, 在单语句的循环中可以不使用区块 (用于此目的时 "if" 与其相匹配的 "else" 一起被视为单语句). 可以使用 One True Brace (OTB) 风格, 这样允许左大括号与 while 在同一行而不是在其下面. 例如：for x, y in z {。

和所有的循环一样, 循环中可以使用 Break, Continue 和 A_Index.

COM 对象

因为 Key 和 Value 被直接传递给枚举数的 Next() 方法, 所以它们的值取决于被枚举的对象类型. 对于 COM 对象, Key 包含由 IEnumVARIANT::Next() 返回的值, 而 Value 包含了表示其 变量类型 的数字. 例如, 用于 Scripting.Dictionary 对象时, 每个 Key 包含字典中的键而 Value 通常为 8 (对于字符串) 和 3 (对于整数). 请参阅 ComObjType 了解类型代码表.

[v1.0.96.00+]: 枚举 SafeArray 时, Key 包含了当前元素而 Value 包含其变量类型.

相关

枚举数对象, Object.NewEnum(), While 循环, Loop, Until, Break, Continue, 区块

示例

; 列出对象中的键值对：
colours := Object("red", 0xFF0000, "blue", 0x0000FF, "green", 0x00FF00)
; 上面的表达式可以直接代替下面的“colours”：
for k, v in colours
    s .= k "=" v "`n"
MsgBox % s

; 列出所有的资源管理器和 Internet Explorer 窗口:
for window in ComObjCreate("Shell.Application").Windows
    windows .= window.LocationName " :: " window.LocationURL "`n"
MsgBox % windows
/*
Class: CEnumerator

能用来循环数值键的通用枚举器对象。在循环中不能修改数组，否则循环的区间可能出错。可以定义自己的 MaxIndex() 函数来表示数组边界。如果在 1 和最大索引间有缺失的数组成员，仍会循环到它们但值为空。这是说这个枚举器被设计为不支持真正的数组解析。要在对象能使用这种循环，请在它的类定义中插入这个函数：

    _NewEnum()
    {
        return new CEnumerator(this)
    }

来源：http://www.autohotkey.com/board/topic/2667-suggestions-on-documentation-improvements/?p=531509
*/

; 对枚举器进行循环
For k, v in Test
    MsgBox %k%=%v%

; 用于演示的测试类
class Test
{
    static Data := ["abc", "def", "ghi"]

    _NewEnum()
    {
        return new CEnumerator(this.Data)
    }
}

class CEnumerator
{
    __New(Object)
    {
        this.Object := Object
        this.first := true
        ; 加速的缓存。当 MaxIndex() 函数性能差时用得上。
        ; 副作用是在循环时不能插入键值对，否则区间是错误的。
        this.ObjMaxIndex := Object.MaxIndex()
    }

    Next(ByRef key, ByRef value)
    {
        if (this.first)
        {
            this.Remove("first")
            key := 1
        }
        else
            key ++
        if (key <= this.ObjMaxIndex)
            value := this.Object[key]
        else
            key := ""
        return key != ""
    }
}


Gosub

跳转到指定的标签继续执行，直到遇到 Return。

Gosub, Label

参数

标签

跳转的目标 标签, 热键标签 或 热字串标签, 这样会执行 Label 下的命令, 直到遇到 Return 或 Exit. "Return" 会让脚本返回到 Gosub 后的首个命令恢复执行. "Exit" 终止 当前线程.

备注

和几乎其他所有命令的参数一样, Label 可以为 变量 引用 (例如 %MyLabel%), 此时将使用变量中的名称作为跳转的目标. 然而, 性能会稍微降低, 因为每次都必须 "查找" 目标标签名而不是只在脚本首次加载时查找一次.

使用动态标签时 (例如 %MyLabel%), 如果目标标签不存在则会显示错误对话框. 要避免此问题, 请预先调用 IsLabel(). 例如：

if IsLabel(VarContainingLabelName)
    Gosub %VarContainingLabelName%

尽管 Gosub 可用于简单, 普通用途的子程序, 不过对于更复杂的情况请考虑使用 函数.

相关

Return, 函数, IsLabel(), 区块, Loop, Goto

示例

Gosub, Label1
MsgBox, The Label1 subroutine has returned (it is finished).
return

Label1:
MsgBox, The Label1 subroutine is now running.
return


Goto

跳转到指定的标签并继续执行。

Goto, Label

参数

标签

跳转目标的 标签 名.

备注

使用动态标签时 (例如 %MyLabel%), 如果目标标签不存在则会显示错误对话框. 要避免此问题, 请预先调用 IsLabel(). 例如：

if IsLabel(VarContainingLabelName)
    Goto %VarContainingLabelName%

不鼓励使用 Goto, 因为它通常让脚本不容易阅读且难以维护. 考虑使用 Else, 区块, Break 和 Continue 来代替 Goto.

相关

Gosub, Return, IsLabel(), Else, 区块, Break, Continue

示例

Goto, MyLabel
...
MyLabel:
Sleep, 100
...


if（表达式）

指定在表达式计算结果为 TRUE 时执行的命令。

if（表达式）

备注

包含表达式的 if 语句与像 If FoundColor <> Blue 这样的传统 if 语句的区别是，它在单词“if”后的字符为左大括号。尽管通常把整个表达式包围在括号中，不过也可以写成这样：if (x > 0) and (y > 0)。此外, 如果单词 "if" 后是 函数调用 或者类似 "not" 或 "!" 的运算符, 那么左大括号可以完全省略.

如果 if 语句中表达式的计算结果为 true (即除空字符串和数值 0 以外的任何结果), 那么执行 if 语句下的行或 区块. 否则如果有相应的 ELSE, 则会跳到 else 下的行或区块执行.

当 IF 或 ELSE 结构中含有多行命令时, 这些命令必须括在 大括号 中. 不过, 如果只有一行命令从属于 IF 或 ELSE, 那么可以不用大括号. 请参阅此页面底部的例子。

One True Brace (OTB) 风格可用于表达式形式的 if 语句中 (但不能用于 传统的 if 语句). 例如：

if (x < y) {
    ...
}
if WinExist("Untitled - Notepad") {
    WinActivate
}
if IsDone {
    ...
} else {
    ...
}

与 "else" 语句支持任何类型的语句紧跟在其右边不同, if 语句仅支持 "{" 在其右边.

相关提示，if var [not] between LowerBound and UpperBound 命令判断变量是否在两个值之间，而 if var [not] in value1,value2 可以用来判断变量内容是否存在于值列表中。

相关

表达式, 赋值表达式 (:=), if var in/contains MatchList, if var between, IfInString, 区块, Else, While 循环

示例

if (A_Index > 100 or Done)
    return

if (A_TickCount - StartTime > 2*MaxTime + 100)
{
    MsgBox Too much time has passed.
    ExitApp
}

if (Color = "Blue" or Color = "White")
{
    MsgBox The color is one of the allowed values.
    ExitApp
}
else if (Color = "Silver")
{
    MsgBox Silver is not an allowed color.
    return
}
else
{
    MsgBox This color is not recognized.
    ExitApp
}


If/IfEqual/IfNotEqual/IfLess/IfLessOrEqual/IfGreater/IfGreaterOrEqual

指定在变量与值比较结果为 TRUE 时执行的命令。包含多个命令时，需要把它们括在区块（大括号）中。

IfEqual, var, value (等同于: if var = value)
IfNotEqual, var, value (等同于: if var <> value) (可以使用 != 代替 <>)
IfGreater, var, value (等同于: if var > value)
IfGreaterOrEqual, var, value (等同于: if var >= value)
IfLess, var, value (等同于: if var < value)
IfLessOrEqual, var, value (等同于: if var <= value)
If var ; 如果变量的内容为空或 0 时, 它被视为 false. 否则它被视为 true.

请参阅: IfInString

参数

var

变量 名.

value

文字字符串, 数字或变量引用 (例如 %var2%). 如果您希望将 var 与空字符串 (空白) 进行比较, 那么可以省略 Value.

备注

如果 var 和 value 都为纯数值, 那么它们将被作为数字而不是字符串进行比较. 其他情况下, 它们将被作为字符串按字母顺序进行比较 (即字母次序将决定 var 是大于, 等于或小于 value).

当 IF 或 ELSE 结构中含有多行命令时, 这些命令必须括在大括号中. 例如：

if count <= 0
{
    WinClose Untitled - Notepad
    MsgBox There are no items present.
}

不过, 如果只有一行命令从属于 IF 或 ELSE, 那么可以不用大括号.

如果您使用命令名称风格, 那么另一个命令只能与 IF 语句在同一行. 换句话说, 这些语句都是有效的:

IfEqual, x, 1, Sleep, 1
IfGreater, x, 1, EnvAdd, x, 2

但这些是无效的:

if x = 1 Sleep 1
IfGreater, x, 1, x += 2

One True Brace (OTB) 风格 不 能用在 if 语句的这些类型中. 它只能和表达式类型的 if 语句一起使用.

相关提示，if var [not] between LowerBound and UpperBound 命令判断变量是否在两个值之间，而 if var [not] in value1,value2 可以用来判断变量内容是否存在于值列表中。

相关

IF (表达式), StringCaseSense, 赋值表达式 (:=), if var in/contains MatchList, if var between, IfInString, 区块, Else

示例

if counter >= 1
    Sleep, 10

if counter >=1   ; 如果 IF 结构中含有多行命令, 那么这些命令必须括在大括号中:
{
    WinClose, Untitled - Notepad
    Sleep 10
}

if MyVar = %MyVar2%
    MsgBox The contents of MyVar and MyVar2 are identical.
else if MyVar =
{
    MsgBox, 4,, MyVar is empty/blank. Continue?
    IfMsgBox, No
        Return
}
else if MyVar <> ,
    MsgBox The value in MyVar is not a comma.
else
    MsgBox The value in MyVar is a comma.

if Done
    MsgBox The variable Done is neither empty nor zero.


If var [not] between LowerBound and UpperBound

根据数值或字母顺序检查变量的内容是否在两个值之间（包含边界）。

if Var between LowerBound and UpperBound
if Var not between LowerBound and UpperBound

参数

Var

需要被检查的 变量 名称.

LowerBound

指定范围的下限, Var 必须大于或等于此字符串, 数字或变量引用.

UpperBound

指定范围的上限, Var 必须小于或等于此字符串, 数字或变量引用.

备注

如果这三个参数都为纯数值，那么它们将被作为数字而不是字符串进行比较。其他情况下, 它们将被作为字符串按字母顺序进行比较 (即字母次序将决定 Var 是否在指定范围内). 此时，可以使用 StringCaseSense On 来设置在比较时区分大小写。

运算符 "between", "is", "in" 和 "contains" 不支持用于 表达式 中.

相关

IfEqual/Greater/Less, if var in/contains MatchList, if var is type, IfInString, StringCaseSense, EnvAdd , 区块, Else

示例

if var between 1 and 5
    MsgBox, %var% is in the range 1 to 5, inclusive.

if var not between 0.0 and 1.0
    MsgBox %var% is not in the range 0.0 to 1.0, inclusive.

if var between %VarLow% and %VarHigh%
    MsgBox %var% is between %VarLow% and %VarHigh%.

if var between blue and red
    MsgBox %var% is alphabetically between the words blue and red.

LowerLimit = 1
UpperLimit = 10
InputBox, UserInput, Enter a number between %LowerLimit% and %UpperLimit%
if UserInput not between %LowerLimit% and %UpperLimit%
    MsgBox Your input is not within the valid range.


If var is [not] type

检查变量的内容是否为数值、大写字母或其他。

if var is type
if var is not type

参数

var

变量 名.

type

请参阅下面的备注.

备注

受支持的 Type:

integer | 当 var 非空且包含不带小数点的纯数值字符串 (十进制或十六进制) 时为 true. 允许含有前导和尾随空格和 tab. 字符串可以以加号或减号开始.
float | 当 var 非空且包含浮点数; 即含有小数点的纯数值字符串时为 true. 允许含有前导和尾随空格和 tab. 字符串可以以加号, 减号或小数点开始.
number | 当 var 包含整数或浮点数 (上文描述的每种数字) 时为 true.
digit | 当 var 为空或仅包含由 0 到 9 字符组成的数字时为 true. 不允许出现其他字符, 例如后面这些: 空格, tab, 加号, 减号, 小数点, 十六进制数以及 0x 前缀.
xdigit | 十六进制数: 除了还允许 A 到 F (大写和小写形式) 字符外, 其他与 digit 相同. 在 v1.0.44.09+, 允许使用 0x 前缀.
alpha | 当 var 为空或仅包含字母时为 true. 如果字符串中含有任何数字, 空格, tab, 标点或其他非字母的字符时则为 false. 例如, 如果 var 包含一个空格后跟一个字母, 那么它 不会 被看成是 alpha.
upper | 当 var 为空或仅包含大写字母时为 true. 如果字符串中含有任何数字, 空格, tab, 标点或其他非大写字母的字符时则为 false.
lower | 当 var 为空或仅包含小写字母时为 true. 如果字符串中含有任何数字, 空格, tab, 标点或其他非小写字母的字符时则为 false.
alnum | 除了还允许 0 到 9 的数字外, 其他与 alpha 相同.
space | 当 var 为空或仅包含空白字符时为 true, 其中空白字符包括后面这些字符: 空格 (%A_Space%), tab (%A_Tab% or `t), 换行符 (`n), 回车符 (`r), 垂直 tab (`v) 和进纸符 (`f).
time | 当 var 包含有效的日期时间戳时为 true, 其中日期时间戳可以是 YYYYMMDDHH24MISS 格式的全部或开始部分. 例如, 类似 2004 这样的 4 位字符串被视为有效的. 使用 StringLen 可以判断是否存在额外的时间部分. 小于 1601 的年份会被视为无效的, 因为操作系统通常不支持它们. 被视为有效的最大年份为 9999. 可以使用单词 DATE 代替 TIME, 效果相同.

注意: 运算符 "between", "is", "in" 和 "contains" 不支持 用于 表达式 中.

[AHK_L 42+]: 如果没有使用 StringCaseSense Locale, 那么会忽略系统区域设置.

相关

%A_YYYY%, SetFormat, FileGetTime, IfEqual, if var in/contains MatchList, if var between, StringLen, IfInString, StringUpper, EnvAdd , 区块, Else

示例

if var is float
    MsgBox, %var% is a floating point number.
else if var is integer
    MsgBox, %var% is an integer.
if var is time
    MsgBox, %var% is also a valid date-time.


If var [not] in/contains value1,value2,...

检查变量的内容是否匹配列表中的某项。

if Var in MatchList
if Var not in MatchList

if Var contains MatchList
if Var not contains MatchList

参数

Var

需要被检查的 变量 名称. 对于 "in" 运算符, 需要准确匹配列表中的某项. 对于 "contains" 运算符, 会更容易形成匹配: 只要列表中的某项作为子字符串包含于 Var 中.

MatchList

逗号分隔的字符串列表, 其中的每个字符串都将与 Var 的内容进行比较以寻找匹配. 在分隔逗号周围的任何空格或 tab 都是有意义的, 这表示它们也是匹配字符串的一部分. 例如，如果 MatchList 被设置为 ABC , XYZ，这时 Var 必须包含带有尾随空格的 ABC 或带有前导空格的 XYZ 才形成匹配。

在匹配列表中两个连续的逗号产生单个原义逗号. 例如，后面的匹配列表会在 string1 的末尾产生单个原义逗号：If Var In string1,,,string2。同样地，后面的匹配列表仅包含其中含有一个原义逗号的单个项目：If Var In single,,item。要在列表中包含空的项目，那么像这个例子那样把逗号作为首个字符：If Var In ,string1,string2（用于“contains”运算符时，由于在所有字符串中都可以找到空项，所以空项将总是会形成匹配）。

因为 MatchList 中的每一项并不是作为独立的参数, 所以此列表可以完整的包含在一个变量中. 事实上, 如果此列表的长度超过 16383, 那么列表的全部或部分必须包含在变量中以变量表示, 因为这个长度是任何脚本行的最大长度. 例如，MatchList 可以由 %List1%,%List2%,%List3% 组成，其中的每个子列表包含了用来匹配词组的一个大的列表。

列表中任何长度超过 16384 字符的单个项目, 超出长度的那些字符将被视为一个新列表项. 因此, 通常最好避免包含这样的项目.

备注

比较总是按字母顺序进行, 而不是作为数字. 例如, 字符串 "11" 不会匹配列表项 "11.0".

除了支持搜索多个字符串 (其中任何一个都将形成匹配) 外, "contains" 运算符的作用与 IfInString/IfNotInString 相同.

可以使用 StringCaseSense On 来设置在比较时区分大小写。

如果 MatchList 较长, 可以通过 延续片段 的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

运算符 "between", "is", "in" 和 "contains" 不支持用于 表达式 中.

相关

if var between, IfEqual/Greater/Less, IfInString, StringCaseSense, 区块, Else

示例

if var in exe,bat,com
    MsgBox The file extension is an executable type.

if var in 1,2,3,5,7,11 ; 避免在列表中添加了空格.
    MsgBox %var% is a small prime number.

if var contains 1,3  ; 注意这里把值作为字符串而不是数字进行比较.
    MsgBox Var contains the digit 1 or 3 (Var could be 1, 3, 10, 21, 23, etc.)

if var in %MyItemList%
    MsgBox %var% is in the list.

InputBox, UserInput, Enter YES or NO
if UserInput not in yes,no
    MsgBox Your input is not valid.

WinGetTitle, active_title, A
if active_title contains Address List.txt,Customer List.txt
    MsgBox One of the desired windows is active.
if active_title not contains metapad,Notepad
    MsgBox But the file is not open in either Metapad or Notepad.


IfInString / IfNotInString

检查变量是否包含指定的字符串。

IfInString, var, SearchString
IfNotInString, var, SearchString
Position := InStr(Haystack, Needle [, CaseSensitive?, StartingPos]]) ; 请参阅 InStr() 函数了解详细信息。

参数

var

为寻找匹配而被搜索的 变量 名称.

SearchString

要搜索的字符串. 如果没有启用 StringCaseSense, 那么匹配过程不区分大小写.

备注

内置变量 %A_Space% 和 %A_Tab% 分别包含单个空格和单个 tab 字符, 单独搜索这些字符时它们可能很有用.

另一个命令可以和此命令在同一行. 换句话说, 这两个语句是等同的:

IfInString, MyVar, abc, Gosub, Process1
IfInString, MyVar, abc
    Gosub, Process1

不过, 除命名命令外的其他项不支持与此命令在相同行. 例如：

IfInString, MyVar, abc, found := true  ; 无效的.

相关

InStr(), RegExMatch(), StringGetPos, StringCaseSense, IfEqual, if var in/contains MatchList, if var between, if var is type, 区块, Else

示例

Haystack = abcdefghijklmnopqrs
Needle = abc
IfInString, Haystack, %Needle%
{
    MsgBox, The string was found.
    return
}
else
    Sleep, 1


IfMsgBox

检查用户在最近的 MsgBox 命令中点击了哪个按钮。

IfMsgBox, ButtonName

参数

ButtonName

下列字符串之一表示用户在最近的 MsgBox 命令中所点击的按钮:

是
No
OK
Cancel
Abort
Ignore
Retry
Continue [v1.0.44.08+]
TryAgain [v1.0.44.08+]
Timeout (即单词 "timeout" 表示 MsgBox 命令 超时)

相关

MsgBox

示例

MsgBox, 4, , Would you like to continue?, 5  ; 5 秒的超时时间.
IfMsgBox, No
    Return  ; 用户点击了 "No" 按钮.
IfMsgBox, Timeout
    Return ; 即在超时时假设点击了 "No".
; 否则, 继续:
...


IfWinActive / IfWinNotActive / WinActive

检查指定的窗口是否存在且当前是否活动（在最前面）。若存在，则 WinActive() 返回其唯一 ID（HWND）。

IfWinActive [, WinTitle, WinText,  ExcludeTitle, ExcludeText]
IfWinNotActive [, WinTitle, WinText, ExcludeTitle, ExcludeText]
UniqueID := WinActive("WinTitle", "WinText", "ExcludeTitle", "ExcludeText")

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除. 注：由于向后兼容性，所以如果此参数准确匹配某个命令名，那么 IfWinActive 和 IfWinNotActive 会将其作为命令解释。要变通解决此问题，请使用 WinActive() 函数代替。

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

如果省略所有参数, 那么将使用 上次找到的窗口.

如果这些命令的其中一个确定了某个活动窗口为符合的匹配, 那么 上次找到的窗口 将更新为这个活动窗口. 换句话说, 如果 IfWinActive 匹配结果为 "true" 或 IfWinNotActive 匹配结果为 "false", 那么将更新 上次找到的窗口.

WinActive() 函数返回匹配指定条件的活动窗口的 唯一 ID (HWND). 如果不匹配, 则函数返回 0. 由于所有的非零数字被视为“true”，所以每当 WinTitle 为活动时，if WinActive("WinTitle") 语句为真。

获取活动窗口的唯一 ID 的简便方法是使用 ActiveHwnd := WinExist("A")。

SetWinDelay 不适用于 IfWinExist/IfWinActive.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

IfWinExist, SetTitleMatchMode, DetectHiddenWindows, 上次找到的窗口, WinActivate, WinWaitActive, WinWait, WinWaitClose, #IfWinActive/Exist

示例

IfWinActive, Untitled - Notepad
{
    WinMaximize  ; 最大化前面 IfWinActive 找到的记事本窗口.
    Send, Some text.{Enter}
    return
}

if WinActive("ahk_class Notepad") or WinActive("ahk_class" . ClassName)  ; "ahk_class" 后不需要空格.
    WinClose  ; 这里使用 上次找到的窗口.


IfWinExist / IfWinNotExist / WinExist

检查是否存在匹配的窗口。WinExist() 返回首个匹配窗口的唯一 ID（HWND）。

IfWinExist [, WinTitle, WinText,  ExcludeTitle, ExcludeText]
IfWinNotExist [, WinTitle, WinText, ExcludeTitle, ExcludeText]
UniqueID := WinExist("WinTitle", "WinText", "ExcludeTitle", "ExcludeText")

参数

UniqueID

首个匹配指定条件窗口的唯一 ID（HWND）（作为十六进制整型）。

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除. 注：由于向后兼容性，所以如果此参数准确匹配某个命令名，那么 IfWinExist 和 IfWinNotExist 会将其作为命令解释。要变通解决此问题，请使用 WinExist() 函数代替。

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

如果省略所有参数，那么将检查上次找到的窗口看它是否仍然存在（如果是 IfWinNotExist 则检查其是否不存在）。

如果这些命令的其中一个确定了某个符合的窗口存在, 那么 上次找到的窗口 将更新为此窗口. 换句话说，如果 IfWinExist 匹配结果为真或 IfWinNotExist 匹配结果为假，那么将更新上次找到的窗口。

WinExist() 返回首个匹配窗口的 唯一 ID （HWND）（没有找到匹配时则为 0）。由于所有非零值都被视为“true”，所以每当 WinTitle 存在时 if WinExist("WinTitle") 语句为真。

要获取控件的 HWND (用于 Post/SendMessage 或 DllCall 中), 请使用 ControlGet Hwnd 或 MouseGetPos.

SetWinDelay 不适用于 IfWinExist、IfWinActive。

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

IfWinActive, SetTitleMatchMode, DetectHiddenWindows, 上次找到的窗口, Process, WinActivate, WinWaitActive, WinWait, WinWaitClose, #IfWinActive/Exist

示例

; 例 1
IfWinExist, Untitled - Notepad
{
    WinActivate  ; 自动使用上面找到的窗口.
    WinMaximize  ; 同上
    Send, Some text.{Enter}
    return
}

; 例 2
IfWinNotExist, Calculator
    return
else
{
    WinActivate  ; 前面的“IfWinNotExist”也设置了上次找到的窗口。
    WinMove, 40, 40  ; 把它移动到新位置。
    return
}

; 例 3
if WinExist("ahk_class Notepad") or WinExist("ahk_class" . ClassName)
    WinActivate  ; 使用最近找到的窗口。

MsgBox % "The active window's ID is " . WinExist("A")

; 例 4: 等同于 IfWinNotExist, Calculator
If !WinExist("Calculator")
    return


循环

Loop（普通）

重复执行一系列命令：可以指定表示重复次数的数字或直到遇到 break。

Loop [, Count]

参数

Count

执行循环体 (重复) 的次数. 如果省略, Loop 会无期限继续, 直到遇到 break 或 return.

如果 Count 是一个变量引用例如 %ItemCount%, 每当此变量为空或包含小于 1 的数字时, 循环会被完全跳过.

由于必须支持 文件模式循环, Count 不可以为表达式. 不过, 和所有的非表达式参数一样, 通过在表达式之前加上 % 和空格可以强制使用它. 例如：Loop % Count + 1。此时, 表达式仅在循环开始之前被求值一次.

备注

循环命令后通常跟着 区块, 这是组成循环 体 的语句的集合. 不过, 在单语句的循环中可以不使用区块 (用于此目的时 "if" 与其相匹配的 "else" 一起被视为单语句).

此命令的常见用途是无限循环, 在循环 体 中某个地方使用 break 命令来决定何时停止循环.

在循环中鼓励使用 break 和 continue 代替 goto, 因为它们通常可以让脚本更容易理解和维护. 要创建 "Do...While" 循环, 在循环 体 的最后一个语句中使用 IF 语句, 在其中根据条件执行 break 命令. 可以使用相同的方法创建 "While" 循环, 但是应该使用 While 命令代替.

内置变量 A_Index 包含当前循环重复的次数。首次执行循环体时其值为 1。第二次时其值为 2；依此类推。如果一个内层循环包含在一个外层循环中，那么内层循环具有优先权。A_Index 在所有类型的循环中都有效, 包括 文件循环 和 注册表循环; 但是在循环外部时 A_Index 值为 0.

在普通循环中可以使用 One True Brace (OTB) 风格 (但不适用于专用循环例如 文件模式 和 解析). 例如：

Loop {
    ...
}
Loop %RepeatCount% {
    ...
}

专用循环: 循环可以用来自动获取文件, 文件夹或注册表项 (每次一个). 请参阅文件循环和注册表循环了解详细信息。此外, 文件读取循环 可以对整个文件的内容进行操作, 每次一行. 最后, 解析循环 可以对包含在可分隔的字符串中的单独片段进行操作.

相关

Until, While 循环, For 循环, 文件和文件夹循环, 注册表循环, 文件读取循环, 解析循环, Break, Continue, 区块

示例

Loop, 3
{
    MsgBox, Iteration number is %A_Index%.  ; A_Index 将为 1, 2, 接着 3
    Sleep, 100
}

Loop
{
    if a_index > 25
        break  ; 终止循环
    if a_index < 20
        continue ; 跳过后面并开始下一次重复
    MsgBox, a_index = %a_index% ; 这里将仅显示数字 20 到 25
}


Loop（解析字符串）

从一个字符串中获取子字符串（片段），每次一个。

Loop, Parse, InputVar [, Delimiters, OmitChars]

参数

Parse

此参数必须为单词 PARSE, 且与其他类型的循环不同, 它不能为包含单词 PARSE 的变量引用.

InputVar

需要被分解的变量名称. 不要把名称括在百分号中, 除非您希望使用变量的 内容 作为被解析的变量名.

分隔符

如果此参数为空或省略, 那么将把 InputVar 中的每个字符解析为单独的子字符串.

如果此参数为 CSV, 那么将把 InputVar 按逗号分隔值格式标准进行解析. 这个是 MS Excel 生成的 CSV 文件行的示例：

"first field",SecondField,"the word ""special"" is quoted literally",,"last field, has literal comma"

其他情况下, Delimiters 中可以包含一个或多个字符 (区分大小写), 其中的每个都被用来确定 InputVar 中子字符串之间的边界.

分隔符不会被视为子字符串自身的一部分. 此外, 在 InputVar 中如果一对分隔符之间没有任何字符, 那么相应的子字符串将为空.

例如：`,（转义的逗号）将根据逗号每次出现的位置分割字符串。同样地，使用 %A_Tab%%A_Space% 作为分隔符将在 InputVar 中每次遇到空格或 tab 时开始一个新的子字符串。

要使用字符串而不是字符作为分隔符, 首先使用 StringReplace 把这个字符串在所有出现的地方替换为文本中从未使用的单个字符, 例如这些特殊字符的其中一个: ¢¤¥¦§©ª«®µ¶. 参考这个例子, 其中使用字符串 <br> 作为分隔符:

StringReplace, NewHTML, HTMLString, <br>, ¢, All
Loop, parse, NewHTML, ¢ ; 使用 ¢ 解析字符串.
{
...
}
OmitChars

可选的字符列表（区分大小写），用来从每个子字符串的开始和结尾部分移除这些字符。例如, 如果在 OmitChars 使用 %A_Space%%A_Tab%, 那么每个解析出来的子字符串中开始和结尾部分 (但中间的不会) 的空格和 tab 会被移除.

如果 Delimiters 为空, 那么 OmitChars 表示应该考虑移除哪些字符 (它们将不会出现在循环中).

与其他大多数命令的最后一个参数不同, 在 OmitChars 中的逗号必须进行转义 (`,).

备注

当您想对包含在字符串中的片段逐个进行操作时, 字符串解析循环很有用. 解析循环比 StringSplit 使用更少的内存（因为 StringSplit 创建了持久的伪数组）且在大多数情况下更容易使用。

内置变量 A_LoopField 存在于任何解析循环中。它包含了 InputVar 中当前子字符串 (片段) 的内容. 如果一个内层解析循环包含在一个外层解析循环中，则最内层循环的片段将具有优先权。

尽管不存在内置变量 "A_LoopDelimiter", 不过在此页面最底部的例子演示了如何检测在分割每个片段时是由于遇到哪个分隔符.

InputVar 或其片段没有大小限制. 此外, 如果 InputVar 的内容在循环执行期间改变了, 循环将 "无视" 这些变化, 因为它正在操作的是原始内容的临时副本.

要在解析前按不同的顺序排列字段, 请使用 Sort 命令.

请参阅 Loop 了解关于区块、Break、Continue 和 A_Index 变量（其存在于各种类型的循环中）的相关信息。

相关

StringSplit, 文件读取循环, Loop, Break, Continue, 区块, Sort, FileSetAttrib, FileSetTime

示例

; 示例 #1:
Colors = red,green,blue
Loop, parse, Colors, `,
{
    MsgBox, Color number %A_Index% is %A_LoopField%.
}

; 示例 #2: 按行读取变量的内容, 一行接一行 (类似于 文件读取 循环).
; 通过 FileRead 可以把文件加载到变量中:
Loop, parse, FileContents, `n, `r  ; 在 `r 之前指定 `n, 这样可以同时支持对 Windows 和 Unix 文件的解析.
{
    MsgBox, 4, , Line number %A_Index% is %A_LoopField%.`n`nContinue?
    IfMsgBox, No, break
}

; 示例 #3: 除了用于剪贴板外, 这个例子和上一个一样.
; 每当剪贴板包含文件时这个例子很有用, 例如从打开的资源管理器窗口
; 复制的那些 (程序自动把这些文件转换为它们的文件名):
Loop, parse, clipboard, `n, `r
{
    MsgBox, 4, , File number %A_Index% is %A_LoopField%.`n`nContinue?
    IfMsgBox, No, break
}

; 示例 #4: 解析逗号分隔值 (CSV) 文件:
Loop, read, C:\Database Export.csv
{
    LineNumber = %A_Index%
    Loop, parse, A_LoopReadLine, CSV
    {
        MsgBox, 4, , Field %LineNumber%-%A_Index% is:`n%A_LoopField%`n`nContinue?
        IfMsgBox, No
            return
    }
}

; 示例 #5: 判断遇到了哪个分隔符.

; 初始化要搜索的字符串.
Colors = red,green|blue;yellow|cyan,magenta
; 初始化计数器来跟踪字符串中我们的位置.
Position := 0

Loop, Parse, Colors, `,|;
{
    ; 计算在这个字段末尾分隔符的位置.
    Position += StrLen(A_LoopField) + 1
    ; 获取解析循环中找到的分隔符.
    Delimiter := SubStr(Colors, Position, 1)

    MsgBox Field: %A_LoopField%`nDelimiter: %Delimiter%
}


Loop（注册表）

获取指定的注册表子键的内容，每次一个项目。

Loop, RootKey [, Key, IncludeSubkeys?, Recurse?]

参数

RootKey

必须为 HKEY_LOCAL_MACHINE（或 HKLM）、HKEY_USERS（或 HKU）、HKEY_CURRENT_USER（或 HKCU）、HKEY_CLASSES_ROOT（或 HKCR）或 HKEY_CURRENT_CONFIG（或 HKCC）的其中一个。

要访问远程注册表, 请在前面加上计算机名和冒号, 例如: \\workstation01:HKEY_LOCAL_MACHINE

键

键名（例如 Software\SomeApplication）。如果为空或省略, 将获取 根键 的内容.

IncludeSubkeys?

0 (默认值) 不获取 Key 中包含的子键 (仅获取值).
1获取所有的值和子键.
2仅获取子键 (不获取值).

递归？
0 (默认值) 不对子键进行递归.
1对子键进行递归, 以便获取包含在其中的所有值和子键.

备注

当您想对注册表值或子键集合中的项逐个进行操作时, 注册表循环很有用. 值和子键以逆序获取 (自下而上), 这样在循环中使用 RegDelete 不会扰乱循环自身.

下列变量存在于任何注册表循环中。如果一个内层注册表循环包含在一个外层注册表循环中，那么最内层循环的注册表项将具有优先权：

A_LoopRegName | 当前获取项的名称, 可以是值名或子键名. 在 Windows 注册表编辑器中, 值名为 "(默认)" 的项如果分配了值, 那么也会获取它的值, 不过此时相应的 A_LoopRegName 将是空的.
A_LoopRegType | 当前获取项的类型, 可以是下列单词的其中一个: KEY (即当前获取项为子键而不是值), REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ, REG_DWORD, REG_QWORD, REG_BINARY, REG_LINK, REG_RESOURCE_LIST, REG_FULL_RESOURCE_DESCRIPTOR, REG_RESOURCE_REQUIREMENTS_LIST, REG_DWORD_BIG_ENDIAN (在大多数 Windows 硬件上相当罕见). 如果当前获取项为未知类型, 那么此变量将为空.
A_LoopRegKey | 正在访问的根键名 (HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_USER, HKEY_CLASSES_ROOT 或 HKEY_CURRENT_CONFIG). 访问远程注册表时，此变量的值将不包含计算机名。
A_LoopRegSubKey | 当前子键名. 如果没有使用 Recurse 参数以递归查询其他子键时, 此变量的值与 Key 参数相同. 在递归查询时, 此变量的值将为当前获取项的完整路径, 其中不包含根键. 例如: Software\SomeApplication\My SubKey
A_LoopRegTimeModified | 当前子键或其中任何一个值的上次修改时间. 格式为 YYYYMMDDHH24MISS. 当前获取项不是子键（即 A_LoopRegType 不是单词 KEY）时，此变量将为空。

在注册表循环中使用下列命令时, 可以以一种简化的方式来操作当前获取项:

RegRead, OutputVar | 读取当前项. 如果当前项为键, ErrorLevel 将被置为 1 且 OutputVar 将被置空.
RegWrite [, Value] | 写入到当前项. 如果省略 Value, 根据不同的类型当前项可能被置为 0 或空. 如果当前项为键, ErrorLevel 将被置为 1 且没有其他效果.
RegDelete | 删除当前项. 如果当前项为键, 它以及它所包含的所有子键和值都将被删除.

访问远程注册表时 (通过上面描述的 RootKey 参数), 需要注意以下事项:

  • 目标机器上必须正在运行远程注册表服务。
  • 如果您和目标计算机不在相同的域或者本地或远程用户名缺乏足够的权限（然而，请参阅下文了解可能的解决方法）时，访问远程注册表可能失败。
  • 在尝试访问远程注册表之前, 根据您的用户名所在的域, 工作组和/或权限, 您可能必须连接到共享设备, 例如通过映射驱动器. 建立这样的连接 -- 使用拥有访问或编辑注册表权限的远程用户名和密码 -- 也许可以顺带启用远程注册表访问.
  • 如果您已经作为另一个用户连接到目标计算机 (例如, 通过 Guest 用户映射驱动器), 您可能必须终止这个连接, 以允许远程注册表功能使用您当前登录的用户名重新连接和认证.
  • 对于 Windows Server 2003 和 Windows XP 专业版, MSDN 中声明: "如果 [注册表服务器] 所在的计算机加入了工作组且启用了 强制以本地账户的来宾身份进行网络登录验证 策略, 此功能无效. 请注意如果计算机加入了工作组, 那么这项策略默认是启用的."
  • 对于 Windows XP 家庭版, MSDN 中声明 "此功能总是无效". 家庭版没有注册表服务器和客户端, 尽管客户端可以从操作系统的某个 cab 压缩包提取.

请参阅 Loop 了解关于区块、Break、Continue 和 A_Index 变量（其存在于各种类型的循环中）的相关信息。

相关

Loop、Break、Continue、区块、RegRead、RegWrite、RegDelete、SetRegView

示例

; 示例: 删除用户输入的 Internet Explorer URL 历史:
Loop, HKEY_CURRENT_USER, Software\Microsoft\Internet Explorer\TypedURLs
    RegDelete

; 示例: 有效的测试脚本:
Loop, HKEY_CURRENT_USER, Software\Microsoft\Windows, 1, 1
{
    if a_LoopRegType = key
        value =
    else
    {
        RegRead, value
        if ErrorLevel
            value = *error*
    }
    MsgBox, 4, , %a_LoopRegName% = %value% (%a_LoopRegType%)`n`nContinue?
    IfMsgBox, NO, break
}

; 示例: 用于在整个注册表中
; 递归搜索特殊值的可运行示例.
SetBatchLines -1  ; 让搜索以最快速度进行.
RegSearchTarget = Notepad  ; 告知子程序搜索的目标.
Gosub, RegSearch
return

RegSearch:
ContinueRegSearch = y
Loop, HKEY_LOCAL_MACHINE, , 1, 1
{
    Gosub, CheckThisRegItem
    if ContinueRegSearch = n ; 这里告知我们要停止搜索.
        return
}
Loop, HKEY_USERS, , 1, 1
{
    Gosub, CheckThisRegItem
    if ContinueRegSearch = n ; 这里告知我们要停止搜索.
        return
}
Loop, HKEY_CURRENT_CONFIG, , 1, 1
{
    Gosub, CheckThisRegItem
    if ContinueRegSearch = n ; 这里告知我们要停止搜索.
        return
}
; 请注意: 我认为如果已经搜索了 HKEY_USERS, 那么可以不必搜索
; HKEY_CURRENT_USER.  同样地, 如果搜索了 HKEY_LOCAL_MACHINE,
; 那么可以不必搜索 HKEY_CLASSES_ROOT.
return

CheckThisRegItem:
if A_LoopRegType = KEY  ; 如果您也想检查键名, 那么移除这两行.
    return
RegRead, RegValue
if ErrorLevel
    return
IfInString, RegValue, %RegSearchTarget%
{
    MsgBox, 4, , The following match was found:`n%A_LoopRegKey%\%A_LoopRegSubKey%\%A_LoopRegName%`nValue = %RegValue%`n`nContinue?
    IfMsgBox, No
        ContinueRegSearch = n  ; 告知我们的调用者停止搜索.
}
return


OnExit

指定在脚本退出时自动运行的子程序。

OnExit [, Label]

参数

标签

如果省略, 则脚本会返回到正常的退出行为. 否则, 请指定 标签 的名称, 当脚本由于任意原因退出时将执行标签中的内容 (作为新 线程).

重要提示: 由于调用这个指定的子程序而没有终止脚本, 所以想要终止脚本时必须在这个子程序中使用 ExitApp 命令. 可选的 (如同下面的示例部分那样), OnExit 子程序可以显示一个 MsgBox 来提示用户确认, 只有当用户按下 YES 时才会执行 ExitApp 退出脚本.

备注

当脚本由于任意原因退出时会调用 OnExit 子程序 (除非脚本是被像结束任务这样杀掉). 每当 #SingleInstance 和 Reload 命令要求终止前一个实例时, 也会调用这个子程序.

脚本可以通过 OnMessage(0x11, "WM_QUERYENDSESSION") 检测并且可以终止系统关闭或注销操作。

OnExit 线程 不遵循 #MaxThreads (需要时它总是会运行). 此外, 当它运行的时候, 它不会被任何 线程 中断, 包括 热键, 自定义菜单项 以及 定时子程序. 然而, 如果用户在托盘菜单或主菜单中选择 Exit, 或者通过 Reload 或 #SingleInstance 命令要求终止脚本时, 它将会终止执行 (同时脚本将退出). 因此, OnExit 子程序应该设计成快速结束, 除非用户明白自己正在做什么.

如果 OnExit 线程 遇到诸如运行时错误的失败状况, 则脚本会终止. 这样避免了有问题的 OnExit 子程序使得脚本无法终止的情况出现.

如果 OnExit 子程序是由指定退出码的 Exit 或 ExitApp 命令运行的, 则会忽略退出码. OnExit 子程序中可以使用 ExitApp 指定新的退出码.

每当脚本退出尝试调用 OnExit 子程序时, 这时会使用设置 (例如 SendMode) 的默认值开始. 这些默认值可以在 自动执行段 改变.

内置变量 A_ExitReason 为空，除非 OnExit 子程序正在运行或者在之前的退出中至少调用过一次。如果不是空的, 则它为下列单词的其中一个:

logoff | 用户正在注销.
Shutdown | 正在关闭或重启系统, 例如使用 Shutdown 命令.
Close | 脚本接收到 WM_CLOSE 或 WM_QUIT 消息, 出现致命错误或者正被以其他方式关闭. 尽管这些情况都是很少见的, 然而 WM_CLOSE 可能是由脚本主窗口使用 WinClose 命令发出的. 要避免这种情况，请使用 Send, !{F4} 关闭主窗口。
错误 | 在没有热键且不是 持续运行的 脚本中发生了运行时错误. 运行时错误的一个例子是 Run/RunWait 命令无法启动指定的程序或打开指定的文档.
Menu | 用户在主窗口的菜单或标准托盘菜单中选择了退出.
Exit | 使用了 Exit 或 ExitApp 命令 (包括 自定义菜单项).
Reload | 正通过 Reload 命令或菜单项重载脚本.
Single | 由于 #SingleInstance 的结果, 脚本正被它自身的新实例代替.

相关

OnMessage(), RegisterCallback(), OnClipboardChange, ExitApp, Shutdown, #Persistent, 线程, Gosub, Return, Menu

示例

#Persistent  ; 为了进行演示, 当用户选择 "No" 时让脚本持续运行.
OnExit, ExitSub
return

ExitSub:
if A_ExitReason not in Logoff,Shutdown  ; 在这行语句中, 注意不要在逗号周围含有空格.
{
    MsgBox, 4, , Are you sure you want to exit?
    IfMsgBox, No
        return
}
ExitApp  ; 含 OnExit 脚本终止自身的唯一方法是在 OnExit 子程序中使用 ExitApp.


暂停

暂停脚本的当前线程。

#p::Pause ; 按一次 Win+P 会暂停脚本. 再按一次则取消暂停.
Pause [, On|Off|Toggle, OperateOnUnderlyingThread?]

参数

On|Off|Toggle

如果为空或省略, 则它默认为 Toggle. 否则, 请指定下列单词的其中一个:

Toggle：如果在当前线程下的潜在线程处于运行状态，则暂停当前线程，否则让潜在的线程恢复运行。

On：暂停当前线程。

Off：如果在当前线程下的线程已经处于暂停状态，则把它恢复到取消暂停状态。在其他情况下, 此命令没有效果.

OperateOnUnderlyingThread?

对于 Pause Off 会忽略此参数，因为它总是对潜在的线程进行操作。在打开或切换的两种情况时, 只有在打开 Pause 时才不会忽略此设置 (包含使用 Toggle 打开的情况).

请指定下面的其中一个数字:

0 (或省略): 此命令会暂停当前线程; 即正在运行 Pause 命令的这个线程.

1：此命令会标记在当前线程下面的线程为暂停，这样当那个线程恢复时它会结束它之前运行的命令（如果有）然后进入暂停状态。如果当前线程下面没有线程, 则暂停脚本自身, 这样阻止 计时器 的运行 (这样的效果和当脚本没有线程时使用了菜单项 "Pause Script" 一样).

注: A_IsPaused 包含了潜在线程的暂停状态.

备注

与 Suspend 禁用 热键 和 热字串 不同, 打开暂停状态会冻结 当前线程. 副作用是, 在它下面的任何被中断线程也将处于潜伏状态.

暂停任意线程后, 计时器 不会运行. 与之相比, 明确地启动的线程 (例如 热键 和 菜单项) 仍然可以运行; 但当它们的 线程 结束时, 潜在的线程仍会被暂停. 换句话说, 每个线程都能独立于其他线程被暂停.

每当脚本的 当前线程 处于暂停状态时, 托盘图标的颜色会从绿色变成红色. 通过冻结图标可以阻止这个图标颜色的改变, 这是使用最后一个参数为 1 的 Menu 命令实现的. 例如：

Menu, Tray, Icon, C:\My Icon.ico, , 1

要禁用计时器而不暂停脚本，请使用 Thread, NoTimers。

Pause 命令的功能和内置的菜单项 "Pause Script" 类似.

当脚本显示任意类型的 菜单 (托盘菜单, 菜单栏, GUI 上下文菜单, 等等) 时脚本总是处于停住状态 (虽然不是正式地暂停).

相关

Suspend, Menu, ExitApp, 线程, SetTimer

示例

Pause::Pause  ; 设置 "pause" 键为切换暂停功能的热键...
#p::Pause  ; ... 或者设置 Win+p 或其他热键.
; 发送 Pause 命令到另一个脚本。
DetectHiddenWindows, On
WM_COMMAND := 0x111
ID_FILE_PAUSE := 65403
PostMessage, WM_COMMAND, ID_FILE_PAUSE,,, C:\YourScript.ahk ahk_class AutoHotkey


Reload

使用新的脚本实例替换当前正在运行的实例。

Reload

此命令可用于需要频繁改变的脚本. 通过给此命令设置热键, 您可以在编辑器中保存修改后轻松地重启脚本.

传递给原始脚本的 命令行参数 不会被传递给新的实例. 要传递这些参数, 请不要使用 Reload. 相反地, 把 Run 配合 A_AhkPath 和 A_ScriptFullPath 使用 (如果会以编译后的形式运行脚本, 还包括 A_IsCompiled). 此外，使用 /restart 作为首个参数（即在可执行文件名后），这样告诉程序要使用和 Reload 相同的动作。另请参阅: 命令行开关和语法.

当脚本重启时, 会从它原来的工作目录启动 (当它首次启动时生效的那个). 换句话说, SetWorkingDir 不会改变新实例的初始工作目录.

如果脚本无法重载 (可能由于语法错误), 那么原来的实例会继续运行. 因此, reload 命令后应跟着在重载失败时您想执行的动作 (例如使用 return 来退出当前子程序). 要在原来的实例中检测到失败, 请参照此例:

Reload
Sleep 1000 ; 如果成功, 则 reload 会在 Sleep 期间关闭这个实例, 所以下面这行语句永远不会执行.
MsgBox, 4,, The script could not be reloaded. Would you like to open it for editing?
IfMsgBox, Yes, Edit
return

相关

Edit

示例

^!r::Reload  ; 设定 Ctrl-Alt-R 热键来重启脚本.


Return

从子程序返回到之前通过函数调用、Gosub、激活 Hotkey、GroupActivate 或其他方式执行跳转的地方。

Return [, Expression]

参数

Expression

当 return 不在 函数 内时应该省略此参数。

由于此参数为 表达式, 所以下面所有的都是有效的例子:

return 3
return "literal string"
return MyVar
return i + 1
return true  ; 返回数字 1 表示 "true".
return ItemCount < MaxItems  ; 返回真值或假值.
return FindColor(TargetColor)

已知限制: 为了向后兼容和方便使用, 下面两个例子功能是等同的:

return MyVar
return %MyVar%

换句话说, 包围在百分号中的单变量会被视为非表达式. 要变通解决此问题，请通过把它放到括号中来让它明确为表达式；例如：return (%MyVar%)。

备注

如果没有调用者可返回, 则 Return 将执行 Exit 代替.

在返回值给调用者中包含了多种从函数中返回多值给调用者的各种方法。

相关

函数, Gosub, Exit, ExitApp, GroupActivate

示例

#z::
MsgBox The Win-Z hotkey was pressed.
Gosub MySubroutine
return

MySubroutine:
Sleep 1000
return


SetBatchLines

设置脚本的执行速度（影响 CPU 使用率）。

SetBatchLines, 20ms
SetBatchLines, LineCount

参数

20ms

(这里的 20ms 只是个例子.) 如果这个值以 ms 结尾, 那么它表示脚本两次休眠之间的时间间隔 (每次休眠 10 ms). 在下面的例子中，脚本会在每次运行 20ms 之后休眠 10ms：SetBatchLines, 20ms。

LineCount

两次休眠之间执行脚本的行数. 这个值可以高达 9223372036854775807. 此外, 此模式与前面段落中介绍的 20ms 是互斥的; 即每次只会有其中一个生效.

备注

使用 SetBatchLines -1 让脚本无休眠运行（即让脚本以全速运行）。

默认设置为 10ms，不过在 v1.0.16 之前的版本中默认为 10 （行）。

不论希望脚本快速执行还是希望脚本减少 CPU 占用都推荐使用 "ms" 方法. 例如, 在大多数系统中 10ms 的设置会避免脚本使用超过 50% 的 CPU 时间. 这样既可以让脚本快速运行, 同时也保留了充分的 CPU 资源供其他任务使用, 例如游戏或视频捕获/回放.

内置变量 A_BatchLines 包含了当前的设置.

根据脚本的内容, 脚本的速度还可能会受到下列命令的影响: SetWinDelay, SetControlDelay, SendMode, SetKeyDelay, SetMouseDelay 和 SetDefaultMouseSpeed.

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

SetWinDelay, SetControlDelay, SendMode, SetKeyDelay, SetMouseDelay, SetDefaultMouseSpeed, Critical

示例

SetBatchLines, 10ms
SetBatchLines, 1000


SetTimer

以指定的时间间隔自动并重复运行子程序。

SetTimer [, Label, Period|On|Off, Priority]

参数

标签

跳转的目标 标签 或 热键标签 的名称, 这样会执行 Label 下的命令, 直到遇到 Return 或 Exit. 和几乎其他所有命令的参数一样, Label 可以为 变量 引用 (例如 %MyLabel%), 此时将使用变量中的名称作为跳转的目标.

[v1.1.01+]: 如果省略 Label, 则使用 A_ThisLabel. 例如, SetTimer,, Off 可以用来在定时子程序中关闭计时器.

Period|On|Off

On: 以原来的 周期 重新启用之前禁用的计时器. 如果计时器不存在, 则进行创建 (使用默认的周期 250). 如果计时器存在但之前被设为 单次运行模式, 那么它仍然只运行一次.

Off: 禁用现有的计时器.

周期: 把此参数作为上次 Label 子程序启动后必须经过的 近似 的毫秒数来创建或更新计时器. 经过了这个指定的时间值后, 会再次运行 Label (除非自上次启动后仍在运行中). 会自动启用计时器. 要避免这种情况, 紧接着再次使用此命令, 指定此参数为 OFF.

如果此参数为空并且:
1) 计时器不存在: 则使用 250 的周期进行创建.
2) 计时器已经存在: 则启用计时器并 重设 为它原来的 周期 (除非指定了 Priority).

单次运行 [v1.0.46.16+]: 使用负的 周期 来表示计时器只运行一次. 例如，指定 -100 将会从现在开始的 100 ms 后运行计时器，然后就像使用 SetTimer, Label, Off 那样禁用计时器。

Priority

这个可选参数是一个介于 -2147483648 和 2147483647 之间的整数 (或为 表达式) 来表示计时器的优先级. 如果省略, 则使用 0. 请参阅 线程 了解详情.

要改变现有计时器的优先级而不影响其他方面, 请留空前一个参数.

备注

计时器很有用, 因为它们是异步运行的, 这意味着它们会以指定的频率 (间隔) 运行, 即使脚本正等待窗口, 显示对话框或忙于其他任务的时候. 它们的许多应用实例包括了当用户空闲时 (如 A_TimeIdle 反映的那样) 执行一些动作或在不需要的窗口出现时关闭它们.

尽管计时器给人一种脚本同时执行多个任务的错觉, 实际并非如此. 相反地, 定时子程序只是被当作其他线程来处理: 它们可以中断另一个线程或被另一个线程中断, 例如 热键子程序. 请参阅 线程 了解详情.

每当创建或重新启用计时器或用新的周期更新计时器时，它的子程序都不会立即运行，必须先经过它的周期 时间。如果您希望立即开始计时器的首次执行, 请使用 Gosub 来执行计时器的子程序 (但是, 这种方式不会像计时器那样启动新线程; 所以诸如 SendMode 的设置不会以它们的默认值开始).

如果 SetTimer 用于现有的计时器且第二个参数为数字或单词 ON (或省略), 则计时器内部的 "上次运行的时间" 会被重置为当前时间; 换句话说, 在经过它的整个周期后子程序才会再次运行.

计时器精度: 由于操作系统中计时系统的精确度, 周期 通常会被向上取整到最近的 10 或 15.6 毫秒的倍数 (取决于所安装的硬件和驱动的类型). 例如，在 Windows NT/2000/XP 中介于 1 和 10（含边界）的周期通常相当于 10 或 15.6。使用 Loop+Sleep 可以实现更短的延时, 请参阅演示: DllCall+timeBeginPeriod+Sleep.

计时器在下列情况中可能无法按指定频率运行:

  1. 其他程序让 CPU 负载较大.
  2. 定时子程序运行的时间超过它自己的周期, 或者有太多竞争计时器 (改变 SetBatchLines 可能有帮助).
  3. 计时器已经被另一个 线程 中断, 即另一个定时子程序, 热键子程序 或 自定义菜单项 (这可以使用 Critical 避免). 如果这种情况发生了并且中断的线程花费了很长的时间才结束, 则被中断的计时器在这段时间里会被禁用. 不过, 其他任何计时器会对这个中断首个计时器的 线程 进行中断来继续运行.
  4. 使用 Critical 或 Thread Interrupt/Priority 后脚本会变成不可中断的. 在这样的时期, 计时器不会运行. 之后, 当脚本恢复可中断时, 任何过时的计时器会尽快运行一次然后恢复到正常的调度.

尽管计时器在脚本 挂起 时仍会运行, 但是如果 当前线程 的 "Thread NoTimers" 正在起作用或者任意线程 被暂停 时则不会. 此外, 当用户通过脚本的菜单 (例如托盘图标菜单或菜单栏) 进行导航时它们也不会运行.

因为计时器是通过临时中断脚本当前线程来运行的, 所以它们的子程序应该保持简短 (以便很快地结束), 无论何时很长的中断都是不好的.

要在脚本运行期间保持有效的计时器一般应在 自动执行段 中进行创建. 与之相比, 临时的计时器经常可以在它自己的子程序中禁用 (请参阅此页面底部的示例).

每当计时子程序运行时，它会使用设置（例如 SendMode）的默认值开始。这些默认值可以在 自动执行段 改变.

如果 热键 的响应时间非常重要 (例如在游戏中) 且脚本包含了子程序执行时间超过 5 ms 的计时器, 那么请使用下列命令来避免 15 ms 的延迟. 如果在热键按下时恰好处于计时器线程的不可中断期间, 那么这样的延迟还是会发生.

Thread, interrupt, 0  ; 让所有的线程总是不可中断的.

如果计时器在它的子程序正运行时被禁用, 那么该子程序会继续运行直到完成.

KeyHistory 功能会显示存在的计时器数目以及当前启用的数目.

计时器的周期不能大于 4294967295 毫秒 (49.7 天).

要让脚本持续运行 (例如只包含计时器的脚本), 请使用 #Persistent.

相关

Gosub, Return, 线程, Thread (命令), Critical, IsLabel(), Menu, #Persistent

示例

; 示例 #1: 当不想要的窗口出现时关闭它们:
#Persistent
SetTimer, CloseMailWarnings, 250
return

CloseMailWarnings:
WinClose, Microsoft Outlook, A timeout occured while communicating
WinClose, Microsoft Outlook, A connection to the server could not be established
return

; 示例 #2: 等待特定的窗口出现, 然后通知用户:
#Persistent
SetTimer, Alert1, 500
return

Alert1:
IfWinNotExist, Video Conversion, Process Complete
    return
; Otherwise:
SetTimer, Alert1, Off  ; 即此处计时器关闭自己.
SplashTextOn, , , The video conversion is finished.
Sleep, 3000
SplashTextOff
return

; 示例 #3: 检测热键的单次, 两次和三次按下. 这样
; 允许热键根据您按下次数的多少
; 执行不同的操作：
#c::
if winc_presses > 0 ; SetTimer 已经启动, 所以我们记录键击.
{
    winc_presses += 1
    return
}
; 否则, 这是新开始系列中的首次按下. 把次数设为 1 并启动
; 计时器：
winc_presses = 1
SetTimer, KeyWinC, 400 ; 在 400 毫秒内等待更多的键击.
return

KeyWinC:
SetTimer, KeyWinC, off
if winc_presses = 1 ; 此键按下了一次.
{
    Run, m:\  ; 打开文件夹.
}
else if winc_presses = 2 ; 此键按下了两次.
{
    Run, m:\multimedia  ; 打开不同的文件夹.
}
else if winc_presses > 2
{
    MsgBox, Three or more clicks detected.
}
; 不论触发了上面的哪个动作, 都对 count 进行重置
; 为下一个系列的按下做准备:
winc_presses = 0
return


Sleep

在继续前等待指定的时间量。

Sleep, DelayInMilliseconds

参数

Delay

要暂停的时间量 (单位为毫秒), 介于 0 和 2147483647 (24 天) 之间, 可以为 表达式.

备注

由于操作系统中计时系统的精确度, Delay 通常会被向上取整到最近的 10 或 15.6 毫秒的倍数 (取决于所安装的硬件和驱动的类型). 例如，在大部分 Windows 2000/XP 系统上介于 1 和 10（含边界）的延时都相当于 10 或 15.6。要实现更短的延时, 请参阅 示例.

如果 CPU 在负载时, 那么实际的延时可能超过请求的时间. 这是因为在给脚本另一个时间片之前, 会给每个有需要的进程一个 CPU 时间片 (一般为 20 毫秒).

延时为 0 会将脚本当前时间片的剩余部分分配给其他需要的进程 (只要它们的 优先级 不是显著比脚本低). 因此, 延时为 0 实际会产生在 0 和 20ms (或更多) 之间的延时, 取决于有需要的进程的数目 (如果没有这样的进程, 则完全没有延时). 然而, 0 的 Delay 应该比任何更长的 Delay 会更早结束.

当脚本休眠时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

Sleep -1：-1 的 delay 不会休眠，相反地它让脚本立即检查消息队列。这可用来强制任何迫近的中断在指定的位置发生，而不是在更随机的位置。请参阅 Critical 了解更多细节。

相关

SetKeyDelay, SetMouseDelay, SetControlDelay, SetWinDelay, SetBatchLines

示例

Sleep, 1000  ; 1 秒

; 下面是个可运行示例, 它演示了如何休眠比一般的 10 或 15.6 毫秒
; 更短的时间.
; 注：像这样的脚本运行时，整个操作系统和所有的应用程序
; 都会受到下面的 timeBeginPeriod 的影响。

SetBatchLines -1  ; 确保此方法最高的效率。

SleepDuration = 1  ; 这里有时可以根据下面的值进行细微调整（例如 2 与 3 的区别）。
TimePeriod = 3 ; 尝试 7 或 3。请参阅下面的注释.
; 在休眠持续时间一般向上取整到 15.6 ms 的个人电脑中，尝试 TimePeriod=7 来允许
; 稍短一点的休眠，而尝试 TimePeriod=3 或更小的值来允许最小可能的休眠。

DllCall("Winmm\timeBeginPeriod", uint, TimePeriod)  ; 作用于所有的应用程序，而不只是脚本的 DllCall("Sleep"...)，但不影响 SetTimer。Iterations = 50
StartTime := A_TickCount

Loop %Iterations%
    DllCall("Sleep", UInt, SleepDuration)  ; 必须使用 DllCall 而不是 Sleep 命令。

DllCall("Winmm\timeEndPeriod", UInt, TimePeriod)  ; 应该进行调用来让系统恢复正常。
MsgBox % "Sleep duration = " . (A_TickCount - StartTime) / Iterations


Suspend

禁用或启用所有的或选择的热键和热字串。

Suspend [, Mode]

参数

Mode

On：挂起所有的热键和热字串，备注部分说明的除外。

Off：重新启用上面禁用的热键和热字串。

Toggle（默认）：改变为与原来相反的状态（On 或 Off）。

Permit：仅仅把当前的子程序标记为免于挂起。

备注

任何首行为 Suspend（不包括 Suspend On）的热键/热字串会被免于挂起。换句话说, 即使在挂起状态为 ON 时热键仍会保持可用. 这样就允许使用这样的热键关闭挂起状态.

要根据窗口的类型自动禁用选择的热键或热字串, 请使用 #IfWinActive/Exist.

挂起脚本的热键不会停止脚本中已经运行的线程（如果有），请使用Pause来让它停止。

当脚本的热键挂起时, 它的托盘图标会变为字母 S. 这可以通过冻结图标来避免, 这是使用最后一个参数为 1 的 Menu 命令实现的. 例如：

Menu, Tray, Icon, C:\My Icon.ico, , 1

当脚本挂起时内置变量 A_IsSuspended 值为 1, 否则为 0.

相关

#IfWinActive/Exist, Pause, Menu, ExitApp

示例

^!s::Suspend  ; 设置一个切换挂起功能的热键.
; 发送 Suspend 命令到另一个脚本。
DetectHiddenWindows, On
WM_COMMAND := 0x111
ID_FILE_SUSPEND := 65404
PostMessage, WM_COMMAND, ID_FILE_SUSPEND,,, C:\YourScript.ahk ahk_class AutoHotkey


Thread

设置线程的优先级或是否可以被中断。它也可以临时禁用所有的计时器。

Thread, NoTimers [, false]
Thread, Priority, n
Thread, Interrupt [, Duration, LineCount]

Thread, NoTimers [, false]：防止当前线程被任何的计时器中断，直至当前线程结束，或执行 Thread, NoTimers, false，或者被另一个允许计时器的线程中断（这样的情况下计时器在它结束前可以中断正在中断的线程）。

如果在自动执行段（脚本的顶部）没有使用 Thread NoTimers，则所有线程初始都可以被计时器中断（然而后面的 Thread Interrupt 设置仍会生效）。相反地，如果在自动执行段中打开了 NoTimers 却从没有关闭它，则每个新启动的线程（例如热键、自定义菜单项或计时器）初始都不会被计时器中断。

不论默认的设置如何, 当脚本没有其他线程时计时器总能执行 (除非使用了 Pause).

Thread, NoTimers 相当于 Thread, NoTimers, true。此外, 由于 true/false 参数为 表达式, 计算结果为真时表示为 1, 而为假时为 0.

Thread, Priority, n：指定 n 为介于 -2147483648 和 2147483647 之间的整数（或表达式）来表示当前线程的新优先级。此语句不会影响其他线程. 请参阅线程了解详情。

由于其缓冲事件的能力，一般应优先考虑 Critical 而不是 Thread Priority。

相关提示，整个脚本的操作系统优先级可以这样改变，例如：Process, Priority,, High。

Thread, Interrupt [, Duration, LineCount]：应该谨慎使用此命令，因为大多数脚本在默认的设置附近时执行得更一致。

默认情况下, 每个新运行的线程在开始的 15 毫秒的 持续时间 或在开始的 1000 个脚本 行数 (无论首先遇到哪个) 执行时都是不可中断的. 这使得线程有机会结束, 而不是立即被另一个等待运行的线程中断 (例如缓冲的 热键 或一系列即将运行的 计时子程序).

如果持续时间或行数其中一个为 0, 则每个新启动的线程会被立即中断. 如果其中一个为 -1, 那么此参数会使得线程不会被中断. 这两个参数的最大值为 2147483647.

中断设置是全局的, 这意味着所有后续线程都会遵循它, 即使此设置在 自动执行段 外的某个地方被改变了. 然而, 被中断过的线程 则不受影响, 因为它们不可中断的时期已经期满 (说明:Thread, Interrupt 仅设置新线程创建时不可中断的那个时期,而被中断过的线程已经过了这个时期即随时都可能被中断, 所以不受此设置影响). 同样地, 只有在改变 LineCount 时 当前线程 是不可中断的, 它才会受影响, 因为此时新的 LineCount 对当前线程有效.

当 当前线程 不可中断时如果按下了 热键 或选择了 自定义菜单项, 那么这些事件会被缓冲起来. 换句话说, 到当前线程结束或变得可中断时 (无论先遇到哪个) 它才会运行. 例外情况是当当前线程在结束前变得可中断并且它的 优先级 高于被缓冲的事件, 此时被缓冲的事件不再缓冲而丢弃了.

不论此设置如何, 当一个线程显示 MsgBox, InputBox, FileSelectFile 或 FileSelectFolder 对话框时都将变成不可中断的.

两个参数的其中每个都可以留空来保持此设置不变.

备注

由于更大的伸缩性和缓冲事件的能力，命令 Critical 通常比 Thread Interrupt 和 Thread Priority 更有效。

相关

Critical, 线程, Hotkey, Menu, SetTimer, Process

示例

Thread, priority, 1 ; 让当前线程的优先级比平均的稍高一点.
Thread, interrupt, 0  ; 让每个新启动的线程立即变成可中断:
Thread, interrupt, 50, 2000  ; 让每个线程在 50ms 或 2000 行 (无论首先遇到哪个) 之后变成可中断.


Throw

Throw [v1.1.04+]

发出错误发生的信号。此信号可以被 try-catch 语句捕获。

Throw [, Expression]

参数

Expression

要保存到 catch 的 OutputVar 中的值.

由于此参数为 表达式, 所以下面所有的都是有效的例子:

throw 3
throw "literal string"
throw MyVar
throw i + 1
throw { what: "Custom error", file: A_LineFile, line: A_LineNumber } ; 抛出 对象

此参数总是为表达式, 所以变量引用不应该括在 百分号 中, 除非执行 展开双重引用.

[v1.1.05+]：如果省略，则抛出带默认消息的 Exception 对象。

Exception(Message [, What, Extra])

创建 Exception 对象.

如果省略 What, 则它默认为当前函数或子程序的名称. 否则它可以为字符串或到调用堆栈顶部的负偏移. 例如, 使用值 -1 来设置 Exception.What 为当前函数或子线程名称, 且设置 Exception.Line 为调用它的行号.

try
    BadlyCodedFunc()
catch e
    MsgBox % "Error in " e.What ", which was called at line " e.Line

BadlyCodedFunc() {
    throw Exception("Fail", -1)
}

相关

Try, Catch, Finally

示例

请参阅 Try.


Try

Try [v1.1.04+]

守护一个或多个语句（命令或表达式）以防备由 throw 命令抛出的运行时错误和异常。

Try Statement
Try
{
    Statements
}

备注

try 命令后常跟着 区块 - 括在大括号中的一个或多个语句 (命令或表达式). 如果仅需执行单个语句, 那么此语句可以和 try 放在同一行或在其下一行, 并且大括号可以省略. 要指定仅在 try 捕获到错误时执行的代码, 请使用 catch 命令.

throw 命令或程序在运行时遇到错误时会抛出异常。当 try 区块或由其调用的函数抛出异常时，将进行下列操作：

  • 如果该区块有相应的 catch 语句，则继续执行该语句。
  • 如果没有 catch 语句但有 finally 语句，则执行该语句并在结束后自动再次抛出异常。
  • 如果 catch 语句和 finally 语句都没有，则到 try 区块下的一行继续执行。

如果在 try 区块外执行时抛出异常，则显示错误信息并退出当前线程。

One True Brace (OTB) 风格 可以用在 try 命令中. 例如：

try {
    ...
} catch e {
    ...
}

相关

Catch、Throw、Finally、区块

示例

; 示例 #1: try/catch/throw 的基本概念.

try  ; 尝试执行的代码.
{
    HelloWorld()
    MakeToast()
}
catch e  ; 处理由上面区块产生的首个错误/异常.
{
    MsgBox, An exception was thrown!`nSpecifically: %e%
    Exit
}

HelloWorld()  ; 总是成功.
{
    MsgBox, Hello, world!}

MakeToast()  ; 总是失败.
{
    ; 立即跳到 try 区块的错误处理程序:
    throw A_ThisFunc " is not implemented, sorry"
}

; 示例 #2: 使用 try/catch 代替 ErrorLevel.

try
{
    ; 下列语句尝试备份特殊类型的文件:
    FileCopy, %A_MyDocuments%\*.txt, D:\Backup\Text documents
    FileCopy, %A_MyDocuments%\*.doc, D:\Backup\Text documents
    FileCopy, %A_MyDocuments%\*.jpg, D:\Backup\Photos
}
catch
{
    MsgBox, 16,, There was a problem while backing the files up!    ExitApp
}

; 示例 #3: 处理 COM 错误.

try
{
    obj := ComObjCreate("ScriptControl")
    obj.ExecuteStatement("MsgBox ""This is embedded VBScript""")
    obj.InvalidMethod() ; 此行会产生运行时错误.
}
catch e
{
    ; 关于e对象的更多细节，请参阅Catch。
    MsgBox, 16,, % "Exception thrown!`n`nwhat: " e.what "`nfile: " e.file
        . "`nline: " e.line "`nmessage: " e.message "`nextra: " e.extra
}

; 示例 #4: 嵌套的 try-catch 语句.

try Example1() ; 任何单个语句可以和 Try 命令放在同一行.
catch e
    MsgBox, Example1() threw %e%.

Example1()
{
    try Example2()
    catch e
    {
        if e = 1
            throw e ; 重新抛出这个异常, 这样调用者可以捕获它.
        else
            MsgBox, Example2() threw %e%.
    }
}

Example2()
{
    Random, o, 1, 2
    throw o
}


Until

Until [AHK_L 59+]

根据条件判断是否继续执行 Loop 或 For 循环。

Loop {
    ...
} Until Expression

参数

Expression

任何有效的 表达式.

备注

在每次重复执行后都会计算一次表达式, 即使使用了 continue 也会进行计算. 如果表达式计算结果为 false (即为空字符串或数值 0), 循环继续; 否则循环被打破且跳到 Until 之后一行执行.

Loop Until 是下列结构的简写形式:

Loop {
    ...
    if (Expression)
        break
}

不过, Loop Until 通常更容易理解, 且与上面不同的是, 它还可以使用单行动作. 例如：

循环
    x *= 2
Until x > y

Until 可以使用在任何 Loop 或 For 循环中. 例如：

Loop, Read, %A_ScriptFullPath%
    lines .= A_LoopReadLine . "`n"
Until A_Index=5  ; 读取前五行.
MsgBox % lines

如果 A_Index 用在 Expression 中, 那么它的值为刚结束的那次循环的索引.

相关

Loop, While 循环, For 循环, Break, Continue, 区块, 文件和文件夹循环, 注册表循环, 文件读取循环, 解析循环, If (表达式)


While 循环

While 循环 [v1.0.48+]

重复执行一系列命令，一直到指定的表达式计算结果为假。

While Expression

参数

Expression

任何有效的 表达式. 例如：while x < y。

备注

在每次重复执行前都会计算一次表达式. 如果表达式计算结果为 true (即除空字符串和数值 0 以外的任何结果), 那么执行循环体; 否则跳到循环体之后一行执行.

while 循环后通常跟着 区块, 这是组成循环 体 语句的集合. 不过, 在单语句的循环中可以不使用区块 (用于此目的时 "if" 与其相匹配的 "else" 一起被视为单语句).

可以使用 One True Brace (OTB) 风格, 这样允许左大括号与 while 在同一行而不是在其下面. 例如：while x < y {。

内置变量 A_Index 包含当前循环重复的次数。首次计算循环的表达式和执行循环体时其值为 1. 第二次时其值为 2；依此类推。如果一个内层循环包含在一个外层循环中，那么内层循环具有优先权。A_Index 在所有类型的循环中都有效, 但是在循环外部时其值为 0.

和所有的循环一样, 可以使用 Break 提前退出循环. 同样地, 可以使用 Continue 跳过当前循环的剩余部分, 此时 A_Index 增加 1 且重新计算 while 循环的表达式. 如果结果仍为 true, 开始新的循环; 否则循环结束.

专用循环: 循环可以用来自动获取文件, 文件夹或注册表项 (每次一个). 请参阅文件循环和注册表循环了解详细信息。此外, 文件读取循环 可以对整个文件的内容进行操作, 每次一行. 最后, 解析循环 可以对包含在可分隔的字符串中的单独片段进行操作.

相关

Until, Break, Continue, 区块, Loop, For 循环, 文件和文件夹循环, 注册表循环, 文件读取循环, 解析循环, If (表达式)

示例

; 当用户按住鼠标左键拖动时, 在拖动区域中会出现工具提示显示区域的大小.

CoordMode, Mouse, Screen

~LButton::
    MouseGetPos, begin_x, begin_y
    while GetKeyState("LButton")
    {
        MouseGetPos, x, y
        ToolTip, % begin_x ", " begin_y "`n" Abs(begin_x-x) " x " Abs(begin_y-y)
        Sleep, 10
    }
    ToolTip
return


OnMessage()

指定当脚本接收到特定消息时自动调用的函数。

OnMessage(MsgNumber [, "FunctionName", MaxThreads])

参数

MsgNumber

需要监视或查询的消息编号, 应该介于 0 和 4294967295 (0xFFFFFFFF) 之间. 如果您不想监视 系统消息 (即编号小于 0x400 的那些), 那么最好在大于 4096 (0x1000) 的范围中选择一个. 这降低了可能对当前及将来版本的 AutoHotkey 内部所使用的消息的冲突.

FunctionName

函数 名, 如果是原义的字符串, 则必须包围在双引号中. 当脚本接收到 MsgNumber 时会自动调用此函数. 省略该参数可以获取当前正在监视 MsgNumber 的函数名（如果没有则为空）。指定空字符串 ("") 或空变量来关闭对 MsgNumber 的监视.

MaxThreads
[v1.0.47+]

此整数通常省略, 此时表示限制监视函数在同一时刻只能运行一个 线程. 这通常是最佳的, 因为如果不这样, 则每当监视函数中断它自己时脚本将不会按照时间先后顺序来处理消息. 因此，代替 MaxThreads 的一种方法是，请像下面描述的那样使用 Critical。

返回值

如果省略 FunctionName，则返回当前正在监视 MsgNumber 的函数名（如果没有则为空）。

如果明确指定 FunctionName 为空 (例如 ""), 则它返回当前正在监视 MsgNumber 的函数名 (如果没有则为空), 然后关闭对 MsgNumber 的监视.

当 FunctionName 不为空时: 如果 MsgNumber 已经处于被监视状态, 则它返回原来监视的函数名并让新函数开始监视. 否则，它指定 FunctionName 来监视 MsgNumber 然后返回相同的 FunctionName。在两种情况中，失败时都返回空值。当 FunctionName 出现下列情况时会导致失败：1) 不存在（可能由于 FunctionName 两边没有加上双引号）；2) 接受多于四个参数；或 3) 在 v1.0.48.05 或更早的版本中含有 ByRef 或可选参数。如果脚本当前已经在监视 500 个消息时还试图监视新消息, 那么也会失败.

函数的参数

被分配用于监视一个或多个消息的 函数 最多可以接受四个参数:

MyMessageMonitor(wParam, lParam, msg, hwnd)
{
    ... 函数体...
}

尽管您所给出的参数名无关紧要, 不过它们和下面的信息是按顺序一一对应的:

参数 #1：消息的 WPARAM 值。
参数 #2：消息的 LPARAM 值。
参数 #3：消息号，可用在用一个函数监视多个消息时。
参数 #4：发送消息的窗口或控件的 HWND（唯一 ID）。要使用 HWND 则需要加上 ahk_id.

根据运行脚本的 AutoHotkey.exe 是 32 位或 64 位，WPARAM 和 LPARAM 是无符号 32 位整数（从 0 到 232-1）或有符号 64 位整数（从 -263 到 263-1）。在 32 位脚本中，如果传入参数应该为有符号整数，则可以参照这个例子得到负数：

if (A_PtrSize = 4 && wParam > 0x7FFFFFFF)  ; 检查 A_PtrSize 以确保脚本为 32 位。
    wParam := -(~wParam) - 1

如果不需要相应的信息, 那么您可以在列表末尾开始省略一个或多个参数. 例如，定义为 MyMsgMonitor(wParam, lParam) 的函数只会接收到前两个参数，而定义为 MyMsgMonitor() 的函数将不接收任何参数。

函数中可用的附加信息

除了上面接收到的参数外, 函数中还可以使用下面的内置变量:

  • A_Gui: 当消息被发送到 GUI 窗口或控件时 A_Gui 为 Gui 窗口编号 (此窗口同时也被设置为函数的 默认 GUI 窗口); 否则为空.
  • A_GuiControl: 当消息被发送到 GUI 控件时它的值为控件的变量名或在 A_GuiControl 中说明的其他值; 否则为空. 一些控件决不会接收到某些类型的消息. 例如, 当用户点击 文本控件 时, 操作系统会发送 WM_LBUTTONDOWN 到它的父窗口而不是控件本身, 所以此时 A_GuiControl 是空的.
  • A_GuiX 和 A_GuiY: 如果传入的消息是使用 SendMessage 发送的, 则它们的值都为 -2147483648. 如果是使用 PostMessage 发送的, 则它们的值为投递消息时鼠标光标的坐标 (相对于屏幕)
  • A_EventInfo: 如果消息是使用 SendMessage 发送的, 则它的值为 0. 如果是使用 PostMessage 发送的, 则它的值为消息投递的 tick-count time.

监视函数的 上次找到的窗口 初始与消息发送的目标窗口的相同 (即使消息是发送到控件的). 如果这个窗口是隐藏的但非 GUI 窗口 (例如脚本的主窗口), 那么需要在使用前打开 DetectHiddenWindows. 例如：

DetectHiddenWindows On
MsgParentWindow := WinExist()  ; 这里保存了消息发送的目标窗口的唯一 ID.

函数应该 返回 什么

如果监视函数使用不带任何参数的 Return, 或指定空值如 "" (甚至从不使用 Return), 则当此函数结束时将继续正常处理传入的消息. 同样的情况也会出现在函数使用 Exit 或者出现了运行时错误的时候 (例如 运行 不存在的文件). 与之相比，返回一个整数时会被作为回复立即发送；即程序不会再进一步处理此消息。例如, 监视 WM_LBUTTONDOWN (0x201) 的函数可以返回一个整数来阻止目标窗口接收到鼠标点击的通知. 在许多情况下 (例如使用 PostMessage 发送的消息), 它不关心返回了哪个整数; 不过如果不确定, 0 通常是最安全的.

有效返回值的范围与运行脚本的 AutoHotkey.exe 是 32 位还是 64 位有关。对于 32 位脚本（A_PtrSize = 4），非空返回值必须介于 -231 和 232-1 之间，而 64 位脚本 A_PtrSize = 8 则必须介于 -263 和 263-1 之间。

一般说明

与普通的函数调用不同, 被监视消息的到达会启动新 线程 来调用函数. 因此, 函数会以设置的默认值启动, 例如 SendMode 和 DetectHiddenWindows. 这些默认值可以在 自动执行段 改变.

发送 (而不是投递) 到控件的消息不会被监视到, 因为系统在后台直接把它们路由给控件了. 对于系统生成的消息, 这是很少见的情况, 因为它们大部分都是被投递的.

任意调用 OnMessage 的脚本会自动成为 持续运行的. 同时也会单实例运行，不过可以使用 #SingleInstance 覆盖了默认设置。

当一个消息达到时它的监视函数仍由于处理之前同样的消息而在运行, 则不会再次调用函数 (除非 MaxThreads 大于 1); 而这个消息会被视为没有监视的那样进行处理. 如果不希望这样, 那么对于大于或等于 0x312 的消息可以通过在函数的首行中使用 Critical 来在之前运行的函数完成前把消息缓冲起来. 或者, 使用 Thread Interrupt 来实现同样的事情, 只要它持续可以让函数完成的足够长的时间. 与之相比, 无法使用 Critical 或 Thread Interrupt 对小于 0x312 的消息进行缓冲 (然而, 在 v1.0.46+, Critical 可能有所帮助, 因为它会以 更低的频率 检查消息, 这样函数可以有更多的时间来完成). 要确保这类消息不会被丢弃的唯一方法是它的监视函数在 6 毫秒之内结束 (不过这个限制的数值可以使用 Critical 30 增加). 要实现这点的一个方法是通过 投递 一个受监视的大于 0x312 的消息到它所在的脚本来把它放入将来线程的队列中. 那个消息处理函数应该在首行使用 Critical 以确保它的消息被缓冲起来.

如果在小于 0x312 的受监视消息当脚本完全不可中断时到达 (例如在 菜单, 正在进行 按键延时/鼠标延时 或正 打开 剪贴板), 则不会调用此函数而消息会被视为未监视的. 与之相比, 一个等于或大于 0x312 的受监视消息在这些不可中断期间会被缓冲起来; 即当脚本变成可中断时会调用它的处理函数.

如果小于 0x312 的受监视的消息在脚本由于 Thread Interrupt 或 Critical 的设置而不可中断时到达, 则会中断当前线程而调用消息处理函数. 与之相比, 等于或大于 0x312 的受监视消息则会被缓冲到线程结束或变成可中断之后.

OnMessage 的 优先级 总是为 0. 因此, 如果当前线程的优先级大于 0 时将不会监视或缓冲任何消息.

监视系统消息 (小于 0x400 的那些) 时应多加小心. 例如, 如果监视函数不会快速结束, 那么对消息的响应可能超过系统预期的时间, 这样可能会导致一些副作用. 如果监视函数为了阻止对消息的进一步处理而返回整数而系统期望不同的处理或响应时, 可能会发生不想要的行为.

当脚本显示系统对话框时 (例如 MsgBox), 则不会监视到任何投递到控件的消息. 例如, 如果脚本正显示 MsgBox 而用户点击一个 GUI 窗口上的按钮, 则 WM_LBUTTONDOWN 消息会被直接发送到按钮而不会调用监视函数.

尽管外部程序可以使用 PostThreadMessage() 或其他 API 调用直接投递消息给脚本的线程, 但不建议这么做, 因为如果此时脚本正显示系统窗口 (例如 MsgBox) 则消息会丢失. 相反, 通常最好投递或发送消息到脚本的主窗口或其中的某个 GUI 窗口.

相关

RegisterCallback(), OnExit, OnClipboardChange, Post/SendMessage, 函数, Windows 消息列表, 线程, Critical, DllCall()

示例

; 示例: 下面是个可运行脚本, 它监视在 GUI 窗口中的鼠标点击.
; 相关主题: GuiContextMenu

Gui, Add, Text,, Click anywhere in this window.
Gui, Add, Edit, w200 vMyEdit
Gui, Show
OnMessage(0x201, "WM_LBUTTONDOWN")
return

WM_LBUTTONDOWN(wParam, lParam)
{
    X := lParam & 0xFFFF
    Y := lParam >> 16
    if A_GuiControl
        Control := "`n(in control " . A_GuiControl . ")"
    ToolTip You left-clicked in Gui window #%A_Gui% at client coordinates %X%x%Y%.%Control%
}

GuiClose:
ExitApp
; 示例: 下面的脚本检测系统的关机/注销动作并允许您终止它
; 据说在 Windows Vista 或更高版本中不会工作).
; 相关主题：OnExit

; 下面的 DllCall 是可选的：它告诉操作系统要首先关闭此脚本（在其他所有程序之前）。
DllCall("kernel32.dll\SetProcessShutdownParameters", UInt, 0x4FF, UInt, 0)
OnMessage(0x11, "WM_QUERYENDSESSION")
return

WM_QUERYENDSESSION(wParam, lParam)
{
    ENDSESSION_LOGOFF = 0x80000000
    if (lParam & ENDSESSION_LOGOFF)  ; 用户正在注销.
        EventType = Logoff
    else  ; 系统正在关机或重启.
        EventType = Shutdown
    MsgBox, 4,, %EventType% in progress.  Allow it?
    IfMsgBox Yes
        return true  ; 告诉操作系统允许关机/注销操作继续.
    else
        return false  ; 告诉操作系统终止关机/注销操作.
}
; 示例: 此脚本能接收到其他脚本或程序的自定义消息和最多两个数字
; (要发送字符串而不是数字, 请参阅下一个示例).

OnMessage(0x5555, "MsgMonitor")
OnMessage(0x5556, "MsgMonitor")

MsgMonitor(wParam, lParam, msg)
{
    ; 由于尽快返回常常很重要, 所以最好使用 ToolTip 而不是
    ; 类似 MsgBox 的进行显示, 以避免阻止函数结束:
    ToolTip Message %msg% arrived:`nWPARAM: %wParam%`nLPARAM: %lParam%
}

; 下面的代码可用于其他脚本内来激发运行上面脚本中的函数:
SetTitleMatchMode 2
DetectHiddenWindows On
if WinExist("Name of Receiving Script.ahk ahk_class AutoHotkey")
    PostMessage, 0x5555, 11, 22  ; 因为上面的有 WinExist(), 所以消息被发送到 "上次找到的窗口".
DetectHiddenWindows Off  ; 在 PostMessage 时不能是关闭的.
; 示例: 从一个脚本发送任何长度的字符串到另一个脚本.  这是个可运行的示例.
; 要使用它, 请保存并运行下面的脚本, 然后按下 Win+Space 来显示
; InputBox 来让您输入字符串.

; 保存下面的脚本为 "Receiver.ahk", 然后运行它:
#SingleInstance
OnMessage(0x4a, "Receive_WM_COPYDATA")  ; 0x4a 为 WM_COPYDATA
return

Receive_WM_COPYDATA(wParam, lParam)
{
    StringAddress := NumGet(lParam + 2*A_PtrSize)  ; 获取 CopyDataStruct 的 lpData 成员.
    CopyOfData := StrGet(StringAddress)  ; 从结构中复制字符串.
    ; 比起 MsgBox, 应该用 ToolTip 显示, 这样我们可以及时返回:
    ToolTip %A_ScriptName%`nReceived the following string:`n%CopyOfData%
    return true  ; 返回 1 (true) 是回复此消息的传统方式.
}

; 保存下面的脚本为 "Sender.ahk", 接着运行它.  然后, 按下 Win+Space 热键.
TargetScriptTitle = Receiver.ahk ahk_class AutoHotkey

#space::  ; Win+Space 热键. 按下此热键会显示 InputBox 用于输入消息字符串.
InputBox, StringToSend, Send text via WM_COPYDATA, Enter some text to Send:
if ErrorLevel  ; 用户按下了取消按钮.
    return
result := Send_WM_COPYDATA(StringToSend, TargetScriptTitle)
if result = FAIL
    MsgBox SendMessage failed. Does the following WinTitle exist?:`n%TargetScriptTitle%
else if result = 0
    MsgBox Message sent but the target window responded with 0, which may mean it ignored it.
return

Send_WM_COPYDATA(ByRef StringToSend, ByRef TargetScriptTitle)  ; 在这种情况中使用 ByRef 能节约一些内存.
; 此函数发送指定的字符串到指定的窗口然后返回收到的回复.
; 如果目标窗口处理了消息则回复为 1, 而消息被忽略了则为 0.
{
    VarSetCapacity(CopyDataStruct, 3*A_PtrSize, 0)  ; 分配结构的内存区域.
    ; 首先设置结构的 cbData 成员为字符串的大小, 包括它的零终止符:
    SizeInBytes := (StrLen(StringToSend) + 1) * (A_IsUnicode ? 2 : 1)
    NumPut(SizeInBytes, CopyDataStruct, A_PtrSize)  ; 操作系统要求这个需要完成.
    NumPut(&StringToSend, CopyDataStruct, 2*A_PtrSize)  ; 设置 lpData 为到字符串自身的指针.
    Prev_DetectHiddenWindows := A_DetectHiddenWindows
    Prev_TitleMatchMode := A_TitleMatchMode
    DetectHiddenWindows On
    SetTitleMatchMode 2
    SendMessage, 0x4a, 0, &CopyDataStruct,, %TargetScriptTitle%  ; 0x4a 为 WM_COPYDATA. 必须使用发送而不是投递.
    DetectHiddenWindows %Prev_DetectHiddenWindows%  ; 恢复调用者原来的设置.
    SetTitleMatchMode %Prev_TitleMatchMode%         ; 同样.
    return ErrorLevel  ; 返回 SendMessage 的回复给我们的调用者.
}
; 示例: 请参阅 WinLIRC 客户端脚本 演示来学习如何使用 OnMessage() 接收
; 在网络连接的数据到达时的通知.


RegExMatch

RegExMatch() [v1.0.45+]

判断字符串是否包含某个匹配模式（正则表达式）。

FoundPos := RegExMatch(Haystack, NeedleRegEx [, UnquotedOutputVar = "", StartingPosition = 1])

参数

FoundPos

RegExMatch() 返回 NeedleRegEx 在字符串 Haystack 中最左边的出现位置. 首个字符位置为 1. 如果没有找到匹配模式则返回零. 如果遇到错误 (例如 NeedleRegEx 出现语法错误), 则返回空字符串并设置 ErrorLevel 为 下列 值的其中一个而不是 0.

Haystack

源字符串.

NeedleRegEx

要搜索的模式, 它是兼容 Perl 的正则表达式 (PCRE). 模式的选项（如果有）必须放在模式字符串的开始且后面跟着闭括号。例如, 模式 "i)abc.*123" 将匹配不区分大小写的 "abc", 接着零个或多个任意字符, 并以 "123" 结尾的字符串. 如果不含选项, 则可以省略 ")"; 例如, ")abc" 等同于 "abc".

UnquotedOutputVar

模式 1 (默认): OutputVar 是用来保存 Haystack 中匹配整个模式的那部分的变量名. 如果没有找到模式 (即如果函数返回 0), 则此变量和下面的所有数组元素都被置空.

如果在 NeedleRegEx 中包含捕获子模式，那么它们的匹配将被存储在基名称为 OutputVar 的伪数组里。例如, 如果输出变量名是 Match, 则匹配首个子模式的子字符串存储在 Match1, 第二个存储在 Match2, 依此类推. 这种情况的例外是 命名子模式: 它们以名称而不是数字保存. 例如，匹配命名子模式“(?P<Year>\d{4})”的子字符串存储在 MatchYear。如果特定的子模式不匹配任何文本 (或如果函数返回零), 则相应的变量被置空.

在函数中，要创建全局而不是局部的伪数组，则必须在使用前声明伪数组的基名称（例如 Match）为全局变量。对于 假设全局 函数, 反之亦成.

模式 2 (位置和长度): 如果在正则表达式选项中含有 P (例如 "P)abc.*123"), 则整个模式的匹配字符串的 长度 会被存储到 OutputVar (如果没有匹配则为 0). 如果包含捕获子模式，则它们匹配的位置和长度会被存储到两个伪数组：OutputVarPos 和 OutputVarLen。例如，如果变量的基名称为 Match，首个子模式的匹配位置（基于 1）会存储在 MatchPos1，而它的长度存储在 MatchLen1（如果子模式没有匹配或函数返回 0 则它们两者中保存的都为零）。这种情况的例外是命名子模式：它们以名称而不是数字保存（例如 MatchPosYear 和 MatchLenYear）。

模式 3 (匹配对象) [v1.1.05+]: 如果在正则表达式选项中含有大写的 O (例如 "O)abc.*123"), 则 匹配对象 会被存储到 UnquotedOutputVar. 此对象还可以用来获取整个匹配和每个捕获子模式（如果存在）的位置、长度和值。

StartingPosition

如果省略 StartingPosition, 则它默认为 1 (从 Haystack 的首个字符开始). 否则, 从第二个字符开始请指定 2, 第三个开始为 3, 依此类推. 如果 StartingPosition 超过了 Haystack 的长度, 则搜索会从 Haystack 末尾后的空字符串开始 (这通常会导致没有匹配发生).

如果 StartingPosition 小于 1, 则它被视为从 Haystack 末尾开始的偏移. 例如, 0 表示从最后一个字符开始而 -1 则从倒数第二个字符开始. 如果 StartingPosition 超出了 Haystack 最左边的位置, 则会搜索整个 Haystack.

不论 StartingPosition 的值是多少, 返回的值总是相对与 Haystack 的首个字符. 例如, "abc" 在 "123abc789" 中的位置总为 4.

ErrorLevel

[v1.1.04+] 此函数失败时会抛出异常 (这个不会和 "没有找到匹配" 冲突, 失败表示匹配过程中遇到问题, 而 "没有找到匹配" 表示匹配过程成功完成只是没有发现匹配). 想了解更多信息, 请参阅 运行时错误.

ErrorLevel 被设置为下列值的其中一个:

  • 0, 表示没有遇到错误.
  • 一个如下格式的字符串: Compile error N at offset M: description. 在此字符串中, N 是 PCRE 错误值, M 是正则表达式中出现错误的字符的位置, 而 description 是描述这个错误的文本.
  • 一个负数, 表示在正则表达式 执行 时遇到的错误. 尽管这样的错误很罕见, 然而像这些情况就容易出现这种错误, 例如 "太多空字符串匹配" (-22), "递归太深" (-21) 以及 "达到匹配限制" (-8). 如果出现这些情况, 请尝试重新设计更严格的匹配模式, 例如无论是否可行都把每个 * 替换为 ?, + 或像 {0,3} 这样的限制.

选项

请参阅 选项 了解修饰符, 例如 "i)abc", 里面的选项关闭了 "abc" 模式中的区分大小写匹配.

匹配对象 v1.1.05+

如果在正则表达式选项中含有大写的 O, 则匹配对象会被存储到 UnquotedOutputVar. 此对象含有下列属性:

Match.Pos(N): 返回整个匹配或捕获子模式的位置.

Match.Len(N): 返回整个匹配或捕获子模式的长度.

Match.Value(N): 返回整个匹配或捕获子模式.

Match.Name(N)：返回指定的子模式的名称（如果它含有）。

Match.Count(): 返回所有子模式的数目.

Match.Mark()：适用时返回上次遇到 (*MARK:NAME) 的 NAME。

Match[N]: 如果 N 为 0 或有效的子模式编号或名称, 那么它相当于 Match.Value(N). 否则, N 可以为上面其中一个属性的名称. 例如, Match["Pos"] 和 Match.Pos 相当于 Match.Pos(), 不过如果存在名称为 "Pos" 的子模式, 此时它们相当于 Match.Value("Pos").

Match.N: 与上面相同, 不过这里 N 为未引用的名称或编号.

对于上面的所有属性, 其中 N 可以为下列值:

  • 0 表示整个匹配.
  • 子模式的编号, 包括含有名称的子模式.
  • 子模式的名称.

如果指定了 N, 则可以使用方括号 [] 代替其中的圆括号.

性能

要在一个较大的字符串中搜索简单的子字符串, 请使用 InStr(), 因为它比 RegExMatch() 执行地更快.

为了提升性能, 最近使用的 100 个正则表达式会被缓存在内存中 (以已编译的形式).

多次使用一个正则表达式时 (例如在循环中), 使用 研究选项 (S) 可以提高性能.

备注

可以为子模式指定名称，例如模式“(?P<Year>\d{4})”中的 Year。这种名称最多可以由 32 个字母数字和下划线组成. 下面的限制不适用于“O”（匹配对象）模式：尽管命名的子模式在正则表达式运算时还可以使用它们的编号（例如 \1 为到实际匹配首个捕获子模式的字符串的后向引用），然而它们被存储到输出伪数组时只通过名称（而不是编号）。例如，如果“Year”是首个子模式，则 OutputVarYear 会被设置为匹配的子字符串，但 OutputVar1 不会发生变化（如果有则它会保持原来的值）。然而，如果在“Year”后含有未命名子模式，则它会被存储到 OutputVar2，而不是 OutputVar1。

大多数字符 (例如 abc123) 可以直接使用在正则表达式中. 然而, \.*?+[{|()^$ 这些字符则必须在其前面加上反斜线来进行匹配. 例如, \. 表示一个原义的句点而 \\ 表示一个原义的反斜线. 使用 \Q...\E 能避免转义. 例如：\QLiteral Text\E。

在正则表达式中, 特殊字符 (如制表符和新行符) 可以使用一个重音符 (`) 或反斜线 (\) 进行转义. 例如, 不含 x 选项时 `t 等同于 \t.

要了解正则表达式的基础 (或复习正则表达式的语法), 请参阅 正则表达式快速参考.

AutoHotkey 的正则表达式是使用来自 www.pcre.org 的兼容 Perl 的正则表达式 (PCRE) 实现的.

相关

RegExReplace(), 正则表达式快速参考, 正则表达式调出, InStr(), IfInString, StringGetPos, SubStr(), SetTitleMatchMode RegEx, 全局匹配和 Grep (论坛链接)

文本数据的常见来源: FileRead, UrlDownloadToFile, Clipboard, GUI Edit 控件

示例

FoundPos := RegExMatch("xxxabc123xyz", "abc.*xyz")  ; 返回 4, 这是找到匹配的位置.
FoundPos := RegExMatch("abc123123", "123$")  ; 返回 7, 因为 $ 要求在末端进行匹配.
FoundPos := RegExMatch("abc123", "i)^ABC")  ; 返回 1, 因为通过不区分大小写选项实现了匹配.
FoundPos := RegExMatch("abcXYZ123", "abc(.*)123", SubPat)  ; 返回 1, 并把 "XYZ" 保存到 SubPat1.
FoundPos := RegExMatch("abc123abc456", "abc\d+", "", 2)  ; 返回 7 而不是 1, 这是由于 StartingPosition 为 2 而不是 1.

; 关于普通正则表达式的例子, 请参阅 正则表达式快速参考.


RegExReplace

RegExReplace() [v1.0.45+]

替换字符串中匹配模式（正则表达式）出现的地方。

NewStr := RegExReplace(Haystack, NeedleRegEx [, Replacement = "", OutputVarCount = "", Limit = -1, StartingPosition = 1])

参数

NewStr

RegExReplace() 返回内容被替换过的 Haystack 版本. 如果没有发生替换操作, 则返回的 Haystack 保持不变. 如果遇到错误 (例如 NeedleRegEx 出现语法错误), 则返回的 Haystack 保持不变 (不过如果在早于 1.0.46.06 的版本中, 会返回 "") 同时设置 ErrorLevel 为 下面 的其中一个值而不是 0.

Haystack

源字符串.

NeedleRegEx

要搜索的模式, 它是兼容 Perl 的正则表达式 (PCRE). 模式的选项（如果有）必须放在模式字符串的开始且后面跟着闭括号。例如, 模式 "i)abc.*123" 将匹配不区分大小写的 "abc", 接着零个或多个任意字符, 并以 "123" 结尾的字符串. 如果不含选项, 则可以省略 ")"; 例如, ")abc" 等同于 "abc".

Replacement

用来替换每个匹配的字符串, 它是普通文本 (不是正则表达式). 此参数可以包含像 $1 这样的后向引用, 它引用了 Haystack 中匹配首个 子模式 的子字符串. 最简单的后向引用是从 $0 到 $9, 其中 $0 是匹配整个模式的子字符串, $1 是匹配首个子模式的子字符串, $2 是第二个, 依此类推. 对于大于 9 的后向引用 (对于小于等于 9 的那些, 这是可选的), 需要把数字括在大括号中; 例如 ${10}, ${11}, 依此类推. 对于 命名子模式, 需要将名称括在大括号中; 例如 ${SubpatternName}. 要指定原义的 $, 请使用 $$ (这是唯一需要特殊处理的字符; 反斜杠不需要转义).

要转换子模式的大小写, 请在 $ 后跟着下列字符的其中一个: U 或 u (大写), L 或 l (小写), T 或 t (标题格式, 此时每个单词的首字母大写, 而把其他的所有字母改成小写). 例如, $U1 和 $U{1} 都会把首个子模式转换成大写的版本.

不存在的后向引用和不匹配 Haystack 中任何字符串的模式，例如“(abc)|(xyz)”中的一个子模式，会被转译为空字符串。

OutputVarCount

用来保存替换次数 (如果没有则为 0) 的未引用的变量名 (即不需要使用百分号包围).

Limit

如果省略 Limit, 则它默认为 -1, 此时会替换 Haystack 中 所有 发现匹配模式的地方. 否则, 请指定允许替换的最大次数. Haystack 中最后一次替换位置右边的部分将保持不变.

StartingPosition

如果省略 StartingPosition, 则它默认为 1 (从 Haystack 的首个字符开始). 否则, 从第二个字符开始请指定 2, 第三个开始为 3, 依此类推. 如果 StartingPosition 超过了 Haystack 的长度, 则搜索会从 Haystack 末尾后的空字符串开始 (这通常会导致没有替换发生).

如果 StartingPosition 小于 1, 则它被视为从 Haystack 末尾开始的偏移. 例如, 0 表示从最后一个字符开始而 -1 则从倒数第二个字符开始. 如果 StartingPosition 超出了 Haystack 最左边的位置, 则会搜索整个 Haystack.

不论 StartingPosition 的值是什么, 返回值总是 Haystack 的完整副本, 唯一的区别是比起 StartingPosition 为 1 时发生的情况此时源字符串左边可能更多的部分保持不变.

ErrorLevel

[v1.1.04+] 此函数失败时会抛出异常 (这个不会和 "没有找到匹配" 冲突, 失败表示匹配过程中遇到问题, 而 "没有找到匹配" 表示匹配过程成功完成只是没有发现匹配). 想了解更多信息, 请参阅 运行时错误.

ErrorLevel 被设置为下列值的其中一个:

  • 0, 表示没有遇到错误.
  • 一个如下格式的字符串: Compile error N at offset M: description. 在此字符串中, N 是 PCRE 错误值, M 是正则表达式中出现错误的字符的位置, 而 description 是描述这个错误的文本.
  • 一个负数, 表示在正则表达式 执行 时遇到的错误. 尽管这样的错误很罕见, 然而像这些情况就容易出现这种错误, 例如 "太多空字符串匹配" (-22), "递归太深" (-21) 以及 "达到匹配限制" (-8). 如果出现这些情况, 请尝试重新设计更严格的匹配模式, 例如无论是否可行都把每个 * 替换为 ?, + 或像 {0,3} 这样的限制.

选项

请参阅 选项 了解修饰符, 例如 "i)abc", 里面的选项关闭了 "abc" 模式中的区分大小写匹配.

性能

要进行简单的子字符串替换, 请使用 StringReplace, 因为它比 RegExReplace() 执行地更快.

如果您知道替换的最大次数是多少, 请在 Limit 参数中指定来提高性能, 因为这样可以早一些停止搜索 (这样也可能会降低在替换操作过程中占用的系统内存). 例如, 如果您知道在一个大字符串的开始处仅有一个匹配, 请指定最大次数为 1.

为了提升性能, 最近使用的 100 个正则表达式会被缓存在内存中 (以已编译的形式).

多次使用一个正则表达式时 (例如在循环中), 使用 研究选项 (S) 可以提高性能.

备注

大多数字符 (例如 abc123) 可以直接使用在正则表达式中. 然而, \.*?+[{|()^$ 这些字符则必须在其前面加上反斜线来进行匹配. 例如, \. 表示一个原义的句点而 \\ 表示一个原义的反斜线. 使用 \Q...\E 能避免转义. 例如：\QLiteral Text\E。

在正则表达式中, 特殊字符 (如制表符和新行符) 可以使用一个重音符 (`) 或反斜线 (\) 进行转义. 例如, `t 等同于 \t.

要了解正则表达式的基础 (或复习正则表达式的语法), 请参阅 正则表达式快速参考.

相关

RegExMatch(), 正则表达式快速参考, 正则表达式调出, StringReplace, InStr()

文本数据的常见来源: FileRead, UrlDownloadToFile, Clipboard, GUI Edit 控件

示例

NewStr := RegExReplace("abc123123", "123$", "xyz")  ; 返回 "abc123xyz", 因为 $ 使得只能在末尾形成匹配.
NewStr := RegExReplace("abc123", "i)^ABC")  ; 返回 "123", 因为通过不区分大小写选项实现了匹配.
NewStr := RegExReplace("abcXYZ123", "abc(.*)123", "aaa$1zzz")  ; 返回 "aaaXYZzzz", 其中使用了 $1 后向引用.
NewStr := RegExReplace("abc123abc456", "abc\d+", "", ReplacementCount)  ; 返回 "" 并保存 2 到 ReplacementCount.

; 关于普通正则表达式的例子, 请参阅 正则表达式快速参考.


StrLen / StringLen

获取字符串中包含的字符数量。

OutputVar := StrLen(InputVar)
StringLen, OutputVar, InputVar

参数

OutputVar

用来存储字符串长度的变量名.

InputVar

需要统计长度的变量名. 不要把名称括在百分号中, 除非您希望使用变量的 内容 作为被解析的变量名.

备注

如果 InputVar 是由 ClipboardAll 之前所赋值的变量, 那么 StringLen 将报告其总大小.

相关

IfInString, StringGetPos, StringMid, StringTrimLeft, StringTrimRight, StringLeft, StringRight, StringLower, StringUpper, StringReplace

示例

InputVar := "The Quick Brown Fox Jumps Over the Lazy Dog"
MsgBox % "The length of InputVar is " . StrLen(InputVar) ; 结果：43
StringLen, length, InputVar
MsgBox, The length of InputVar is %length%.


StringSplit / StrSplit()

使用指定的分隔符把一个字符串分解成多个子字符串并保存到数组中。

StringSplit, OutputArray, InputVar [, Delimiters, OmitChars]
Array := StrSplit(String [, Delimiters, OmitChars])  ; [v1.1.13+]

参数

StringSplit

OutputArray

用来存储从 InputVar 分解出来的每个子字符串的伪数组名。例如, 如果指定 MyArray, 那么 MyArray0 中会保存分解出来的子字符串的数目 (没有则为 0), 首个子字符串为保存到 MyArray1, 第二个保存到 MyArray2 等.

在函数中，要创建全局而不是局部的伪数组，必须先在函数中声明 MyArray0 为全局变量（对于假设全局函数，反之亦成）。

InputVar

需要被分解的变量名称. 不要把名称括在百分号中, 除非您希望使用变量的 内容 作为被解析的变量名. 注意：InputVar 不能是 OutputArray 中的其中一个变量。

分隔符

如果此参数为空或省略, 那么将把 InputVar 中的每个字符解析为单独的子字符串.

其他情况下, Delimiters 中可以包含一个或多个字符 (区分大小写), 其中的每个都被用来确定 InputVar 中子字符串之间的边界. 由于分隔符不被视为子字符串的一部分, 所以它们不会被保存到 OutputArray. 此外, 如果 InputVar 中一对分隔符之间不存在其他字符, 那么相应的数组元素会被置空.

例如：`,（转义的逗号）将根据逗号每次出现的位置分割字符串。同样地，使用 %A_Tab%%A_Space% 作为分隔符将在 InputVar 中每次遇到空格或 tab 时创建一个新的数组元素。

要使用字符串而不是字符作为分隔符, 首先使用 StringReplace 把这个字符串在所有出现的地方替换为文本中从未使用的单个字符. 参考这个例子, 其中使用字符串 <br> 作为分隔符:

StringReplace, NewHTML, HTMLString, <br>, ``, All  ; 把所有 <br> 替换为重音符.
StringSplit, MyArray, NewHTML, ``  ; 使用重音符分隔字符串.

StrSplit() [v1.1.13+]

Array
（返回值）

字符串数组（对象）。

String

要分割的字符串。

分隔符

如果此参数为空或省略，那么将把输入字符串中的每个字符解析为单独的子字符串。

其他情况下，Delimiters 中可以是单个字符串或字符串数组，其中的每个都被用来确定子字符串之间的边界。由于分隔符不被视为子字符串的一部分，所以它们不会被包含在返回的数组中。此外，如果输入字符串中一对分隔符之间没有其他字符，那么相应的数组元素会被置空。

例如：","将根据逗号每次出现的位置分割字符串。同样地，使用 [A_Tab, A_Space] 作为分隔符将在输入字符串中每次遇到空格或 tab 时创建一个新的数组元素。

两者

OmitChars

可选的字符列表 (区分大小写), 用来从每个数组元素的开始和结尾部分移除这些字符. 例如如果在 OmitChars 中使用 %A_Space%%A_Tab%（StringSplit）或" `t"（StrSplit），那么每个元素中开始和结尾部分（但中间的不会）的空格和 tab 会被移除。

如果 Delimiters 为空, 那么 OmitChars 表示需要从数组中排除的那些字符.

与其他大多数命令的最后一个参数不同，在 StringSplit 参数 OmitChars 中的逗号必须进行转义（`,）。

备注

如果数组元素已经存在，那么 StringSplit 命令只会改变其前面 N 个元素的值，此处 N 为在 InputVar 中的子字符串的数目。原来存在的第 N 个元素之后的其他元素会保持不变. 因此, 最好使用零元素 (MyArray0) 来确定此命令实际分解出了多少项.

会保留例如空格和 tab 这样的空白字符，除非它们被作为分隔符或包含在 OmitChars 中。调用 Trim 函数可以把空格和 tab 从每个变量的两端移除。例如：MyArray1 := Trim(MyArray1)。

要分割标准 CSV (逗号分隔值) 格式的字符串, 请使用 解析循环 内置的 CSV 处理功能.

要在分割前按不同的顺序排列字段, 请使用 Sort 命令.

如果您不需要把子字符串长时间的存储到内存中, 建议使用 解析循环, 尤其在 InputVar 非常巨大时可以节约大量内存. 例如：

Colors = red,green,blue
Loop, parse, Colors, `,
    MsgBox Color number %A_Index% is %A_LoopField%.

相关

解析循环, Arrays, Sort, SplitPath, IfInString, StringGetPos, StringMid, StringTrimLeft, StringTrimRight, StringLen, StringLower, StringUpper, StringReplace

示例

TestString = This is a test.
StringSplit, word_array, TestString, %A_Space%, .  ; 移除句点.
MsgBox, The 4th word is %word_array4%.

Colors = red,green,blue
StringSplit, ColorArray, Colors, `,
Loop, %ColorArray0%
{
    this_color := ColorArray%a_index%
    MsgBox, Color number %a_index% is %this_color%.
}
TestString := "This is a test."
word_array := StrSplit(TestString, A_Space, ".")  ; 忽略句点。
MsgBox % "The 4th word is " word_array[4]

Colors := "red,green,blue"
ColorArray := StrSplit(Colors, ",")
Loop % ColorArray.MaxIndex()
{
    this_color := ColorArray[a_index]
    MsgBox, Color number %a_index% is %this_color%.
}


VarSetCapacity()

增加或清空变量占用的内存。通常只有在特殊情况下才需要，例如 DllCall。

GrantedCapacity := VarSetCapacity(UnquotedVarName [, RequestedCapacity, FillByte])

参数

GrantedCapacity

变量现在占用的字节数, 它会大于或等于 RequestedCapacity. 如果 VarName 不是有效的变量名 (例如原义的字符串或数字), 则返回 0. 如果系统没有足够的内存来进行变更 (很罕见), 则会显示错误对话框并返回当前的容量, 此行为可能在将来的版本中改变.

UnquotedVarName

变量名 (没有括在百分号中). 例如: VarSetCapacity(MyVar, 1000). 这也可以是动态变量, 例如 Array%i% 或 函数的 ByRef 参数.

RequestedCapacity

如果省略, 则返回变量当前的容量且不会改变它的内容. 否则, 会丢失变量中的所有内容 (变量变成空的).

在 RequestedCapacity 中指定字节数, 表示在调整后变量要占用的空间. 对于 Unicode 字符串, 这里应是长度的两倍. RequestedCapacity 不包含内部的零终止符. 例如, 指定 1 会允许变量最多占用一字节的空间加上内部的终止符. 注: 如果后面脚本给变量分配更大的值, 那么它会自动扩展容量.

因此可以经常简单地调用此函数来确保变量占用最小的空间, 考虑到性能原因, 只有在 RequestedCapacity 为 0 时它才会缩小变量的容量. 换句话说, 如果变量的容量已经大于 RequestedCapacity, 则不会减小它的容量 (但为了保持一致, 变量会被置空).

因此, 要明确地缩小变量, 首先请使用 VarSetCapacity(Var, 0) 释放它占用的内存, 然后使用 VarSetCapacity(Var, NewCapacity) 或者简单地让它自动按需从零扩展.

考虑到性能的原因, 要释放一个原来容量小于 64 字节 (在 Unicode 版本中为 128 字节) 的变量可能会没有效果, 因为它的内存是永久性的. 此时, 会返回当前容量而不是 0.

考虑到性能的原因, 容量小于 4096 字节的变量的内存不能通过赋值空字符串的方法来释放 (例如 Var := ""). 然而, VarSetCapacity(Var, 0) 会释放.

在 v1.0.44.03+, 在 RequestedCapacity 指定 -1 来更新变量内部存储的字符串长度为当前内容的长度. 这可用在间接修改变量的时候, 例如通过 DllCall() 传递它的 地址. 在这种模式中, VarSetCapacity() 返回以字节为单位的长度而不是容量.

FillByte

此参数通常省略, 此时不会对目标变量的内存进行初始化 (作为替代, 只是像上面描述的那样简单地把变量置空). 否则, 请指定介于 0 和 255 之间的整数. 目标变量内存区域的每个字节 (它的当前容量, 可能大于 RequestedCapacity) 会被设为这个数字. 零显然是最常用的值, 这可用于要在变量中保存原始的二进制数据时, 例如 DllCall 结构.

备注

除了在 DllCall 中描述的它的用法, 此函数还可以用来在通过逐步连接的方法构造字符串时提升性能. 这是因为当您可以确定字符串的最终长度时可以避免多次自动的容量大小调整. 在这种情况中, RequestedCapacity 不需要太准确: 如果容量太小, 性能仍然会提升, 而当分配的容量用完时变量会开始自动扩展. 如果容量太大, 会浪费一些内存, 不过只是暂时的, 因为在操作完成后使用 VarSetCapacity(Var, 0) 或 Var := "" 后可以释放所有的内存.

#MaxMem 只限制变量自动扩展所占用的容量. 它不会影响 VarSetCapacity.

相关

DllCall, #MaxMem, NumPut, NumGet

示例

; 通过让 MyVar 有足够的空间进行操作来优化性能.
VarSetCapacity(MyVar, 10240000)  ; ~10 MB
Loop
{
    ...
    MyVar = %MyVar%%StringToConcatenate%
    ...
}
; 计算字符串需要的缓冲空间.
bytes_per_char := A_IsUnicode ? 2 : 1
max_chars := 500
max_bytes := max_chars * bytes_per_char

Loop 2
{
    ; 分配用于 DllCall 的空间.
    VarSetCapacity(buf, max_bytes)

    if A_Index = 1
        ; 通过 DllCall 间接修改变量.
        DllCall("wsprintf", "ptr", &buf, "str", "0x%08x", "uint", 4919)
    else
        ; 使用 "str" 来自动更新长度:
        DllCall("wsprintf", "str", buf, "str", "0x%08x", "uint", 4919)

    ; 连接字符串以演示为什么需要更新长度:
    wrong_str := buf . "<end>"
    wrong_len := StrLen(buf)

    ; 更新变量的长度.
    VarSetCapacity(buf, -1)

    right_str := buf . "<end>"
    right_len := StrLen(buf)

    MsgBox,
    (
    Before updating
      String: %wrong_str%
      Length: %wrong_len%

    After updating
      String: %right_str%
      Length: %right_len%
    )
}


GUI

创建和管理窗口和控件。这种窗口可以用作数据输入窗体或自定义用户界面。

Gui, sub-command [, Param2, Param3, Param4]

目录

  • New: 创建新窗口.
  • Add: 创建控件, 例如文本, 按钮或复选框.
  • Show: 显示窗口. 同时可以最小化, 最大化和移动窗口.
  • Submit: 保存用户的输入并可以隐藏窗口.
  • Cancel (或 Hide): 隐藏窗口.
  • Destroy: 销毁窗口.
  • Font: 为后续创建的控件文本设置文字的字体, 大小, 样式和文本颜色.
  • Color: 设置窗口和/或控件的背景颜色.
  • Margin: 设置在没有为控件指定明确的位置时使用的边距/间隔.
  • 窗口的选项和风格: 设置窗口的外观和行为的各种选项.
  • Menu: 添加或移除菜单栏.
  • Minimize / Maximize / Restore: 对窗口执行指示的操作.
  • Flash: 闪烁窗口及其任务栏按钮.
  • Default: 改变当前线程的默认 GUI 窗口编号.
  • 控件的定位和大小设置
  • 保存和响应用户的输入: 变量和 g 标签
  • 控件的选项和样式
  • 窗口事件: GuiClose | GuiEscape | GuiSize | GuiContextMenu | GuiDropFiles
  • 创建多个 GUI 窗口
  • GUI 事件, 线程和子程序
  • 其他: 键盘导航 | 窗口外观 | 一般说明
  • 示例: 包含了演示 GUI 窗口和控件的有效脚本

Gui, New [, Options, Title] [v1.1.04]

创建新窗口.

Gui, New  ; 创建新的未命名 GUI。
Gui, Name:New  ; 创建新 GUI，销毁含有此名称的现有 GUI。

为了方便，会设置新窗口为当前线程的 默认 GUI。

如果没有指定名称，特殊的标签（例如 GuiClose）含有默认的“Gui”前缀，不过可以在选项中使用 +Label前缀进行覆盖。如果启动当前线程的 GUI 是使用这种方法创建的，那么 A_Gui 包含 HWND 而不是名称。相关提示，如果在选项中使用 +HwndOutputVar，那么新窗口的 HWND 会被保存到 OutputVar。

如果指定了名称，则含有此名称的现有 GUI 会被销毁。

Options 可以包含主要 GUI 命令支持的任意 选项.

如果省略 Title, 则使用脚本文件名.

尽管建议使用此命令以让脚本更清晰, 但不是强制的. 如果在使用其他某个 Gui 子命令 (例如 Gui, Add) 时 GUI 不存在, 则会自动创建.

注：在 v1.1.08 之前，在指定名称时此命令不会设置它为默认的 Gui。

Gui, Add, ControlType [, Options, Text]

添加控件到 GUI 窗口 (必要时首先创建 GUI 窗口).

ControlType 为下列的其中一个:

  • Text, Edit, UpDown, Picture
  • Button, Checkbox, Radio
  • DropDownList, ComboBox
  • ListBox, ListView, TreeView
  • Link, Hotkey, DateTime, MonthCal
  • Slider, Progress
  • GroupBox, Tab, StatusBar
  • ActiveX (例如 Internet Explorer Control)
  • 定制

例如：

Gui, Add, Text,, Please enter your name:
Gui, Add, Edit, vName
Gui, Show

Gui, Show [, Options, Title]

如果没有在 Options 中明确指定, 那么此命令会让窗口以可见, 非最小化 (必要时), 激活 并设置它的标题的状态显示. 如果省略了 Title, 则保留原来的标题 (如果没有, 则使用脚本的文件名).

省略后面的 X, Y, W 和 H 选项则让窗口保持原来的大小和位置. 如果之前没有设置过位置, 则在后面提到的 X 和/或 Y 选项没有指明的坐标上窗口将自动居中. 如果之前没有设置过大小, 则窗口会根据它所包含控件的大小和位置自动调整大小.

在 Options 中可以包含零个或多个下列字符串 (规定其中的数字使用十进制, 而不是十六进制):

Wn: 指定 n 为窗口工作区的宽度 (单位为像素), 窗口工作区指除了窗口边框, 标题栏和 菜单栏 的区域.

Hn: 指定 n 为窗口工作区的高度, 单位为像素.

Xn: 指定 n 为窗口在屏幕中的 X 坐标, 单位为像素. 0 表示屏幕最左边首列可见像素的位置.

Yn: 指定 n 为窗口在屏幕中的 Y 坐标, 单位为像素. 0 表示屏幕最上边首行可见像素的位置.

Center: 让窗口在屏幕的水平和垂直方向上居中.

xCenter: 让窗口在屏幕的水平方向上居中. 例如：Gui, Show, xCenter y0。

yCenter: 让窗口在屏幕的垂直方向上居中.

AutoSize: 根据窗口当前包含的可见控件调整窗口的大小. 这常在添加新控件, 调整现有控件的大小或隐藏/显示现有控件后用来调整窗口的大小. 例如：
Gui, Show, AutoSize Center

还可以包含下列参数的其中一个:

Minimize: 最小化当前窗口并激活下一个窗口.

Maximize: 最大化比激活窗口.

Restore: 当窗口处于最小化或最大化状态时, 还原窗口. 当窗口隐藏且不活动时, 则显示并激活窗口.

NoActivate: 当窗口处于最小化或最大化状态时, 还原窗口. 同时让窗口显示但不进行激活.

NA: 显示窗口但不进行激活. 如果窗口处于最小化状态, 那么它仍保持这种状态, 但可能提升它的 z 顺序 (这是在 alt-tab 选择器中看到的顺序). 如果窗口之前是隐藏的, 则此参数可能会让它显示在当前仍处于活动状态的窗口上面.

Hide: 隐藏窗口并激活下一个窗口. 除了允许隐藏窗口被移动, 重设大小或在不显示的情况下设置新的标题外, 此参数与 Gui Cancel 的功能相同. 例如：Gui, Show, Hide x55 y66 w300 h200, New Title。

Gui, Submit [, NoHide]

保存每个控件的内容到其关联变量中（如果有）并且在没有使用NoHide选项时隐藏窗口。对于那些产生多个字段输出的控件, 例如 多选列表框, 输出结果中使用窗口的 当前分隔符 来分隔多个字段的内容. 如果由于之前使用 Gui Destroy 销毁了窗口或其他原因使得窗口不存在, 那么此命令没有效果.

Gui, Cancel

隐藏当前窗口, 并不保存控件的内容到其 关联变量 中. 如果由于之前使用 Gui Destroy 销毁了窗口或其他原因使得窗口不存在, 那么此命令没有效果.

Gui, Destroy

移除当前窗口（如果它存在）及其所有控件，并释放其占用的内存和系统资源。如果脚本之后重新创建窗口, 那么窗口的所有属性 (例如颜色和字体) 初始都为默认值 (如同窗口从没有出现过一样). 如果没有使用 Gui Destroy，则当脚本退出时会自动销毁所有的 GUI 窗口。

Gui, Font [, Options, FontName]

为在此处之后创建的控件设置字体字型, 大小, 样式和/或颜色. 例如：

gui, font, s10, Verdana  ; 设置 10 点大小的 Verdana 字体.

省略最后两个参数可以让字体恢复为系统默认的 GUI 字型, 大小和颜色.

FontName 可以是任意字体的名称, 例如 字体表 的其中一个. 如果省略了 FontName 或此字体在系统中不存在, 则使用之前的字体字型 (如果没有, 则使用系统默认的 GUI 字型). 即使某些系统缺少首选字体, 这种特性也可以让窗口在多个系统上具有类似的字体. 例如, 按顺序执行下列命令, 则 Verdana 字体优先于 Arial, 而 Arial 字体优先于 MS sans serif:

gui, font,, MS sans serif
gui, font,, Arial
gui, font,, Verdana  ; 首选字体.

如果 Options 参数为空, 则使用之前的字体属性. 或者可以在其中指定下列的一个或多个选项字母:

C: 颜色名称 (请参阅 颜色图表) 或 RGB 值, 或指定单词 Default 来恢复到系统默认颜色 (大多数系统的默认颜色为黑色). 例如：cRed、cFFFFAA、cDefault。注意：Buttons 不遵循自定义颜色。此外, 可以通过包含 C 选项创建带有字体颜色的特殊控件不会受到当前选项的影响. 例如：Gui, Add, Text, cRed, My Text。

S: 字体大小 (单位为磅). 例如：s12（规定为十进制，而不是十六进制）

W: 字体粗细, 这是介于 1 和 1000 之间的数字 (400 为标准大小而 700 为粗体). 例如：w600（规定为十进制，而不是十六进制）

还支持使用下列单词: bold, italic, strike, underline, and norm. 指定 Norm 则让字体恢复标准粗细并去除斜体, 删除线和下划线效果 (但保持现有的颜色和大小). 可以使用 norm 去除所有属性然后有选择的设置其他属性. 例如，指定 norm italic 将设置字体为标准然后增加斜体属性。

要指定多个选项, 请在选项间使用空格分隔. 例如：cBlue s12 bold。

如果一个脚本中创建了 多个 GUI 窗口, 那么其中的每个窗口都会记住它自己的 "当前字体" 属性, 可以用于后面创建的控件.

相关提示, 操作系统提供了标准的对话框让用户选取字体, 颜色或图标. 使用 DllCall() 可以显示这些对话框, 演示的例子请参阅 www.autohotkey.com/forum/topic17230.html.

Q: [AHK_L 19+]: 文本呈现质量. 例如：q3。应该在 Q 后跟着下表中的一个数字:

0 = DEFAULT_QUALITY | 保持字体的外观.
1 = DRAFT_QUALITY | 字体外观不如使用 PROOF_QUALITY 值时那么重要.
2 = PROOF_QUALITY | 字体的字符质量比准确符合逻辑字体属性更重要.
3 = NONANTIALIASED_QUALITY | 不对字体修边, 即不进行平滑处理.
4 = ANTIALIASED_QUALITY | 如果字体支持且字体不会太小或太大时, 则对字体进行修边或平滑.
5 = CLEARTYPE_QUALITY | Windows XP 以及更高版本: 如果设置此选项, 则 (尽可能) 使用 ClearType 抗锯齿方法描绘文本.

关于这些值含义的更多细节, 请参阅 MSDN: CreateFont.

由于默认设置通常是最好的品质, 所以这个功能往往用于在特殊情况时禁用抗锯齿效果, 这样可以让文本更清晰.

Gui, Color [, WindowColor, ControlColor]

设置窗口和/或其控件的背景颜色. 设置 WindowColor 为 GUI 窗口自己的背景颜色. ControlColor 应用于窗口中所有现在和将来的控件 (不过某些类型的控件不支持自定义颜色). 尽管 ListViews 和 TreeViews 的初始背景颜色由当前的 ControlColor 决定, 但之后 ControlColor 颜色的改变不会影响它们. 这时，应该使用 GuiControl +BackgroundFF9977, MyListView 来明确改变它们的背景颜色。

让两个参数中的某个留空可以保持当前的颜色设置. 否则, 指定 16 种 HTML 基础颜色 之一或 6 位的 RGB 颜色值 (0x 前缀可以省略), 或指定单词 Default 来恢复到默认颜色. 例如：Silver、FFFFAA、0xFFFFAA、Default。

默认情况下, 窗口的背景颜色为系统按钮的颜色, 而控件的背景颜色为系统默认窗口的颜色 (通常为白色).

菜单栏及其子菜单的颜色可以这样改变，例如：Menu, MyMenuBar, Color, White。

要让窗口的背景透明，请使用 WinSet TransColor。然而，如果在进行这样的操作前没有使用 Gui, Color 为窗口设置自定义的颜色，那么按钮也将变成透明的。要避免此问题, 应首先为窗口设置自定义的颜色, 然后让此颜色透明. 例如：

Gui, Color, EEAA99
Gui +LastFound  ; 让 GUI 窗口成为 上次找到的窗口 以用于下一行的命令.
WinSet, TransColor, EEAA99

此外, 如果要移除背景透明的窗口的边框和标题栏, 请在设置窗口为透明 后 使用下面的命令:

Gui -Caption  ; 如果它不是 默认窗口, 则使用 Gui, GuiName:-Caption.

为了阐明上面的情况, 请参阅此页面底部的屏幕显示 (OSD) 的例子.

Gui, Margin [, X, Y]

此命令用来为窗口上没有明确指定 X 或 Y 坐标 的控件设置在自动排列时距离窗口边界的距离, X 为控件距离窗口左/右边界的距离, Y 为控件距离窗口上/下边界的距离, 它们的单位为像素. 同时使用此边距设置自动排列的控件彼此间在水平和垂直方向上的距离. 最后, 在首次使用 Gui Show 计算窗口的大小时也需要考虑此边距 (在没有明确指定窗口大小的时候).

如果没有使用此命令, 当添加首个控件到窗口时, 窗口会根据当前选择的 字体 的大小按比例计算出默认的边距 (上下边距为字体高度的 0.75 倍, 而左右边距为字体高度的 1.25 倍).

尽管在添加控件的过程中可以改变边距, 但这仅印象后面添加的控件, 而不影响现在的. 最后, X 或 Y 的其中任意一个可以留空来保持相应的边距不变.

Gui, +/-Option1 +/-Option2 ...

在 GUI 命令后可以指定一个或多个选项. 考虑到性能的原因, 最好在创建窗口前 (即在使用任何其他子命令例如 Gui Add 之前) 使用一行语句指定所有的选项.

此命令的效果是累加的; 即它只改变那些明确指定的选项, 而其他所有选项则保持不变.

在选项前指定加号表示增加此选项, 而减号表示移除它. 例如：

Gui +Resize -MaximizeBox  ; 改变 默认 GUI 窗口的设置.
Gui MyGui:+Resize -MaximizeBox  ; 改变名称为 MyGui 的 GUI 窗口的设置.

AlwaysOnTop：让窗口置顶，与 WinSet AlwaysOnTop 的效果相同。

Border: 为窗口增加细边框. 此选项不常用.

Caption (默认具有此选项): 为窗口增加标题栏和粗边框. 如果要移除将要使用 WinSet TransColor 设置透明的窗口的标题栏, 那么在需要在设置 TransColor 后才进行移除.

Delimiter: 指定管道 (|) 外的其他字符作为窗口的字段分隔符, 每当使用 Gui Add 添加, 使用 GuiControl 修改, 使用 Gui Submit 或 GuiControlGet 获取控件的内容时. 在单词 Delimiter 后紧跟着单个字符. 例如，Gui +Delimiter`n 将使用换行符，这可能特别适合于延续片段。同样，使用 Gui +Delimiter| 将恢复为默认的分隔符。要使用空格或 tab，指定 Gui +DelimiterSpace 或 Gui +DelimiterTab。一旦改变数据分隔符, 它会影响作用于这个特殊窗口的所有现在和后续的 线程.

Disabled: 禁用窗口, 阻止用户和窗口中的控件交互. 此选项常用于含有子窗口的窗口 (请参阅 Owner).

DPIScale [v1.1.11+]：使用 Gui -DPIScale 禁用 DPI 缩放，它默认是启用的。如果在使用非标准 DPI 设置的系统上启用 DPI 缩放，则 Gui 命令会自动调整坐标和尺寸来让控件具有大致相同的外观尺寸（不过解析率更高）。例如，对于 144（150%） 的 DPI，Gui Show, w100 会让 Gui 宽度为 150 像素，但 A_GuiWidth 将保持 100。A_ScreenDPI 包含了系统当前 DPI。

Hwnd OutputVar [v1.1.04+]: 此选项保存 GUI 的窗口句柄 (HWND) 到 OutputVar. 例如：Gui +HwndMyGuiHwnd。在函数中使用时, MyGuiHwnd 会被视为 函数动态变量. GUI 的 HWND 常用于 PostMessage, SendMessage 和 DllCall. 它还可以直接作为 ahk_id WinTitle 或代替 GUI 名称来使用，例如 Gui %MyGuiHwnd%:Destroy。

Label [v1.0.44.09+]: 为当前窗口的 特殊标签 指定自定义名称. 例如，Gui MyGui:+LabelMyGui_On 将使用标签 MyGui_OnClose 和 MyGui_OnSize（如果它们存在）分别代替 MyGuiGuiClose 和 MyGuiGuiSize。换句话说, 在所有 特殊标签 的名称中字符串 "MyGuiGui" 被替换为 "MyGui_On". 这可以让多个窗口使用一套相同的标签 (此时脚本可以根据 A_Gui 来确定运行子程序的窗口是哪个).

LastFound: 设置窗口为 上次找到的窗口 (对于 Gui 线程 这是多余的, 因为它自动设置了), 这样允许类似 WinSet 这样的命令对此窗口进行操作, 即使它当前为隐藏状态 (即不需要使用 DetectHiddenWindows). 需要在显示窗口之前改变其属性时, 这是非常有用的. 例如：

Gui +LastFound
WinSet, TransColor, %CustomColor% 150
Gui Show

LastFoundExist [v1.0.43.09+]: 和其他选项不同, LastFoundExist 选项只有在单独使用时才有效. +LastFoundExist 的效果与 +LastFound 相同, 不过如果窗口不存在时不会创建窗口. 此选项的主要用途是判断是否存在某特殊的窗口. 例如：

Gui MyGui:+LastFoundExist
IfWinExist
    MsgBox GUI "MyGui" already exists.

MaximizeBox: 启用标题栏上的最大化按钮. 下面的 Resize 也含有此效果.

MinimizeBox (默认含有此选项): 启用标题栏上的最小化按钮.

MinSize 和 MaxSize [v1.0.44.13+]: 限定窗口的最小尺寸和最大尺寸, 例如当用户拖动窗口边框改变其大小的时候. 指定不带后缀的单词 MinSize 和/或 MaxSize 来使用窗口当前尺寸作为限制大小 (如果没有窗口当前尺寸, 则使用首次 Gui Show 时显示的大小). 还可以在后面加上宽度，跟着 X 和高度，例如：Gui +Resize +MinSize640x480。它们指定了以像素为单位的窗口工作区 (不包括边框, 标题栏和 菜单栏) 的大小. 规定每个数字为十进制, 而不是十六进制.

可以省略高度或宽度以保持不变（例如 +MinSize640x 或 +MinSizex480）。而且, 可以多次指定 Min/MaxSize 以便在一个方向上使用窗口当前的尺寸而另一个则使用指定的大小. 例如，+MinSize +MinSize640x 表示最小高度限制为窗口当前的大小而最小宽度限制为 640。

如果从没有使用 MinSize 和 MaxSize，则使用操作系统的默认值（同样地，可以使用 Gui -MinSize -MaxSize 恢复为此默认值）。注意: 必须含有 +Resize 才能允许用户调节窗口的大小.

OwnDialogs：在每个线程（ 例如 ButtonOK 子线程）中指定 Gui +OwnDialogs，这样所有后续的 MsgBox、InputBox、FileSelectFile 以及 FileSelectFolder 对话框才会成为当前窗口的子窗口。这时这些对话框成为模式对话框, 这意味着用户必须先关闭这些对话框才能和它们的父窗口进行交互. 与之相比, ToolTip, Progress 和 SplashImage 窗口即使成为了其他窗口的子窗口也为非模式的; 它们仅仅是永远显示在其父窗口的上面. 在模式和非模式窗口两种情况中, 当它们的父窗口 销毁 时它们也会被自动销毁.

一般情况下打开这个设置后不需要再切换到关闭, 因为它不影响其他 线程. 但是，如果一个线程需要显示从属和非从属对话框，则可以使用 Gui -OwnDialogs 关闭此设置。

如果在前缀中没有使用窗口名称（例如使用 Gui +OwnDialogs 而不是 Gui MyGui:+OwnDialogs），则当前线程的默认窗口将拥有这些从属对话框。

Owner: 使用 +Owner 可以让当前窗口从属于另一个窗口. 从属的窗口默认不显示在任务栏, 并且它总是显示在其父窗口的上面. 当其父窗口销毁时它也被自动销毁. +Owner 必须在父窗口创建 后 使用, 而在 v1.1.05 及更高版本中可以在从属窗口创建前面或后面使用. +owner 有两种使用方法，如下所示：

Gui, MyGui:+OwnerMyOtherGui  ; 让 MyGui 成为 MyOtherGui 的子窗口.
Gui, MyGui:+Owner  ; 让 MyGui 成为 脚本主窗口 的子窗口, 这样可以阻止任务栏按钮的显示.

[v1.1.03+]：+Owner 后面可以紧跟着现有的 Gui 或任何顶级窗口的 HWND 的名称或编号。

兼容性注意：在 v1.1.03 及更高版本中，+Owner 移除 WS_CHILD 样式并设置 WS_POPUP 样式。要设置某个 Gui 的父窗口，脚本必须使用 +Parent 选项或在 +Owner 选项后覆盖适当的样式。

在某个从属窗口显示时要防止用户与其父窗口交互，请使用 Gui +Disabled 禁用父窗口。之后（当子窗口取消或销毁时），通过 Gui -Disabled 来重新启用父窗口。在取消或销毁子窗口前这样做可以让父窗口自动恢复有效.

Parent [v1.1.03+]：使用 +Parent 后面紧跟着要拥有此窗口的现有 Gui 或任何窗口或控件的 HWND 的名称或编号。要恢复 Gui 为顶级窗口，请使用 -Parent.。在窗口创建后此选项也有效.

Resize: 此选项允许用户重新调整窗口的大小并启用标题栏上的最大化按钮. 要禁用最大化按钮，请指定 +Resize -MaximizeBox。

SysMenu（默认含有此选项）：指定 -SysMenu（负 SysMenu）可以删除点击窗口左上角时弹出的系统菜单和图标。同时也删除标题栏上的最小化, 最大化和关闭按钮.

Theme：指定 -Theme，可以让后续创建的所有控件在 Windows XP 以及更高版本中使用经典主题外观。之后要创建其他使用当前主题的控件时，请使用 +Theme 把设置切换回来。注意: 此选项在比 Windows XP 早的系统上没有效果, 如果 XP 中当前使用经典主题时也没有效果. 最后，对于单独的控件还可以在其创建的选项中指定 +Theme 或 -Theme 来改变此设置。

ToolWindow: 让窗口显示细标题栏, 同时去除任务栏按钮.

(未命名样式): 在十进制或十六进制的 样式编号 前加上加号或减号表示添加或删除此样式.

(未命名扩展样式): 在字母 E 和十进制或十六进制的扩展样式编号前加上加号或减号表示添加或删除此扩展样式. 例如，+E0x40000 表示添加 WS_EX_APPWINDOW 样式，此样式让窗口显示任务栏按钮。尽管这里没有列出其他的扩展样式编号 (因为它们极少使用), 不过可以通过在 www.microsoft.com 中搜索 WS_EX_APPWINDOW 找到它们.

Gui, Menu [, MenuName]

添加菜单栏到窗口. 使用 Menu 命令可以创建普通的菜单. 例如：

Menu, FileMenu, Add, &Open`tCtrl+O, MenuFileOpen  ; 关于 Ctrl+O 请参阅后面的备注.
Menu, FileMenu, Add, E&xit, MenuHandler
Menu, HelpMenu, Add, &About, MenuHandler
Menu, MyMenuBar, Add, &File, :FileMenu  ; 附加上面的两个子菜单.
Menu, MyMenuBar, Add, &Help, :HelpMenu
Gui, Menu, MyMenuBar

注意在上面的首行中，&Open 后面跟着 Ctrl+O（它们之间含 tab）。这表示用户可以按下快捷键代替选择菜单项来执行操作. [v1.1.04+]：如果这样的快捷键中只使用了标准的修饰键名称 Ctrl、Alt 和 Shift，那么它会被自动注册为这个 GUI 的键盘快捷键。不含修饰键的单字母快捷键是区分大小写的, 且可以使用不常见的方法触发, 例如 IME 或 Alt+NNNN.

如果特殊的按键组合没有自动生效, 请使用 上下文相关热键. 然而, 这样的热键一般不能使用 Send 触发, 并且比起标准的键盘快捷键它们更可能和其他脚本产生冲突.

要移除窗口当前的菜单栏，请使用 Gui Menu（即省略最后一个参数）。

一旦菜单被设置为窗口的菜单栏, 它就不能用于弹出菜单或子菜单. 这是因为菜单栏内部使用了不同的格式 (不过, 这只限制菜单栏自身, 而不包括其子菜单). 如果您一定要这样实现, 那么先创建一个菜单用于菜单栏, 再创建另一个相同的菜单用于其他目的.

对当前正用于菜单栏 (在某些情况下包括其子菜单) 使用某些破坏性的 menu 子命令 (例如 Delete 和 DeleteAll) 时, 这些命令会无效并显示错误对话框 (可以使用 UseErrorLevel 来避免). 可以使用下列步骤改变窗口菜单栏中的菜单：1) 使用 Gui Menu（省略 MenuName）从窗口中分离菜单；2) 改变菜单；3) 使用 Gui, Menu, MyMenuBar 重新附加菜单到窗口。

Gui, Hide / Minimize / Maximize / Restore

Gui Hide 相当于 Gui Cancel。其他三个命令则显示窗口, (必要时) 然后分别对窗口进行最小化/最大化/还原操作. 如果由于之前使用 Gui Destroy 销毁了窗口或其他原因使得窗口不存在，那么这些命令没有效果。

Gui, Flash [, Off]

闪烁窗口的任务栏按钮. 这是通过反转窗口的标题栏和/或任务栏按钮（如果有）的颜色实现的。可以加上选项 OFF 让标题栏和任务栏按钮恢复到它们最初的颜色 (但实际效果可能受操作系统版本影响). 在下面的例子中, 窗口将闪烁三次, 因为每对闪烁都会在对它们反转后恢复原来的外观:

Loop 6
{
    Gui Flash
    Sleep 500  ; 这个时间值十分敏感, 改变它可能引起异常.
}

Gui, GuiName:Default

改变 当前线程 的默认 GUI 窗口名称, 这是在没有指定窗口名称时用于 GuiControl, GuiControlGet 和 Gui 命令自身的默认窗口. 在后面的例子中，默认窗口名称被改变为“MyGui”：Gui MyGui:Default。请参阅 线程的默认窗口 了解关于默认窗口的更多细节.

使用 SmartGUI Creator 创建窗口布局

虽然下一段落中描述了简单的布局选项, 但您会发现使用 Rajat 的 SmartGUI Creator 来创建会更简单, 因为它是完全可视化的; 即 "所见即所得". SmartGUI Creator 是免费的, 可以从 www.autohotkey.com/docs/SmartGUI/ 下载

控件的位置和大小

如果在 Options 中省略了某些尺寸和/或坐标, 则会根据前一个控件确定它的位置, 根据控件的类型和内容确定它的大小.

支持下列选项:

R: 指定文本的行数 (可以为浮点数, 如 R2.5). 使用 R 通常比 H (高度) 更合适. 如果同时指定 R 和 H 选项, 则 R 优先考虑. 对于 GroupBox, 此选项设置在框中可以容纳的控件数目. 对于 DropDownLists, ComboBoxes 和 ListBoxes, 此选项设置在控件的列表部分一次可以看到的项目数 (但在 Windows XP 或更高版本中, 对于 DropDownList 和 ComboBox 控件常常同时省略 R 和 H 选项, 这样可以让弹出的列表自动设置为用户桌面的可用高度). 对于其他类型的控件, R 表示控件内可见的文本行数.

W: 宽度, 单位为像素. 如果省略, 对于某些控件则根据其内容自动计算宽度. 其他类型的控件具有下列默认的宽度值:
选项卡控件: 30 倍的当前字体大小加上 3 倍的 X 边距 (行边距).
垂直滚动条: 两倍的当前字体大小.
水平进度条, 水平滑动条, DropDownList, ComboBox, ListBox, GroupBox, Edit 和 Hotkey: 15 倍的当前字体大小 (GroupBox 例外, 其默认宽度为 18 倍, 这样可以显示内部的边距).

H: 高度, 单位为像素. 如果 H 和 R 选项同时省略, 则 DropDownList, ComboBox, ListBox 和初始内容为空的多行 Edit 控件默认为 3 行; GroupBox 默认为 2 行; 垂直滑动条和进度条默认为 5 行; 水平滑动条默认为 30 像素 (在没有指定其厚度时); 水平进度条默认为 2 倍的当前字体大小; Hotkey 控件默认为 1 行; 而 Tab 控件默认为 10 行. 对于其他类型的控件, 根据它们的内容自动计算高度. 请注意对于 DropDownList 和 ComboBox, H 为控件总是可见的部分 (大概指列表上面的框) 和其列表部分相加的高度 (但即使高度设置很小, 也至少会在下拉列表中显示一个项目). 同时对于所有类型的控件, 通过 R 选项指定行数比使用 H 更可取, 因为这样可以避免在控件中显示部分/不完整的文本行.

wp+n, hp+n, wp-n, hp-n (其中 n 可以为任意数字) 用来设置控件的宽度和/或高度等于前一个添加控件的宽度或高度, 可以使用加号或减号进行调整. 例如，wp 将设置控件的宽度等于之前的控件，而 wp-50 则设置宽度为之前的控件宽度减去 50 像素。

X: 控件的 X 坐标. 例如，指定 x0 y0 则把控件放置到窗口工作区的左上角，窗口工作区是在标题栏和菜单栏（如果有）下面的区域。如果省略了 X 但指定了 Y，则控件将被放置在之前所有控件的右边（即其 X 坐标为前一个控件的 X 坐标加上前一个控件的宽度，即前一个坐标右边的位置），可以理解为开始了一个新“列”。

Y: 控件的 Y 坐标. 如果省略了 Y 但指定了 X, 则控件将被放置在之前所有控件的下面, 可以理解为开始了一个新 "行".

X、Y 的其中一个或同时省略时，可以在您对控件的大小或字体进行改变时自动调整 GUI 布局。与之相比, 如果为每个控件指定了绝对位置, 则当一个控件放大或缩小时需要为在此控件下面和/或右边的所有控件手动调整位置.

如果同时省略 X 和 Y, 则控件会放置在之前控件的下面, 中间加上标准的填充间距.

对于 X 和 Y, 还可以在后面加上加号来确定控件相对于前一个添加控件的右边或底部边缘 (分别地) 的位置. 例如，指定 Y+10 将把控件放置在前一个控件底部下面 10 个像素的位置，而不使用标准的填充间距。同样地，指定 X+10 将把控件放置在前一个控件右边缘的右边 10 个像素的位置。由于负数如 X-10 表示绝对的位置，因此要使用负的位置偏移，需要在前面加上一个加号。例如：X+-10。

xp+n, yp+n, xp-n, yp-n (其中 n 可以为任意数字) 可以用来指定控件相对于前一个控件左上角的位置, 此选项常用于 GroupBox 中的封装控件.

xm 和 ym 分别可以把控件放置在窗口最左边和最上边的 边缘 (它们后面还可以跟着加号/减号和数字). 指定 ym 而省略 x 坐标, 将把控件放置在窗口的最上面但在之前所有控件的右边, 可以理解为开始了一个新 "列". 反之亦然.

xs 和 ys：它们类似于 xm 和 ym，区别在于它们是相对于前一个使用 Section 选项添加的控件坐标（在窗口中创建首个控件时总是开始一个新列，即使没有指定此选项）。指定 ys 而省略 x 坐标, 将把控件放置在之前保存的 y 坐标 (即最近一次使用 Section 选项添加的控件的 y 坐标) 但在最近一次使用 Section 后添加的所有控件右边; 这可以理解为在同一个控件段中开始一个新列. 例如：

gui, add, edit, w600  ; 在窗口的顶部添加一个非常宽的编辑控件.
gui, add, text, section, First Name:  ; 保存此控件位置并定义一个新控件段.
gui, add, text,, Last Name:
gui, add, edit, ys  ; 在此控件段中开始一个新列.
gui, add, edit
gui, show

反过来 (指定 xs 但省略 y 坐标) 也是一样的.

xs 和 ys 后面可以跟着一个加号/减号和一个数字. 并且, 还可以在控件的选项中同时指定单词 Section 和 xs/ys; 这样可以让当前控件使用之前的控件段, 但为后续控件定义一个新段.

存储和响应用户的输入

V: 变量. 为控件分配关联变量. 在字母 V 后指定一个变量名, 此变量将为全局变量 (或指向全局变量的 ByRef 局部变量, 在 v1.0.46.01+ 还可能为 静态变量). 例如，指定 vMyEdit 后，每当执行 Gui Submit 命令时将把控件的内容保存到变量 MyEdit。如果控件是不可输入型（例如 Text 控件或 GroupBox），那么为其分配的关联变量作为控件的唯一标识符仍可用于 GuiControl、GuiControlGet 和 A_GuiControl。注意: Gui Submit 不会改变不可输入型控件 (例如 Text 和 GroupBox) 关联变量的内容, 也不会改变其他某些控件的内容 (例如 ListView 和 TreeView).

G: Gosub (g 标签). 当用户点击或改变控件内容时会自动运行的子程序. 在字母 G 后指定需要执行的 标签 名称. 指定 gCancel 暗示执行 Gui Cancel（但如果在脚本中存在名称为“Cancel”的标签，则会执行此标签）。在子程序中可以引用下列内置变量：A_Gui、A_GuiControl、A_GuiEvent 以及 A_EventInfo。

控件: 常用样式和其他选项

注意：选项前的符号省略时，默认为加号，例如Wrap 等同于 +Wrap。相反地，-Wrap 将去除自动换行属性。

AltSubmit: 使用备用的提交方法. 对于 DropDownList, ComboBox 和 ListBox 此选项会让 Gui Submit 命令保存选项项目的位置而不是其文本. 如果没有选择项目, 则对于 ComboBox 会保存其编辑区域的文本; 同样地, 对于 DropDownList 或 ListBox 则把它们的关联 输出变量 设置为空. 注意: AltSubmit 还会影响 GuiControlGet 获取这些控件内容时的行为.

C: 文本颜色 (对 按钮 控件无效). 指定字母 C 后面紧跟着颜色名称 (请参阅 颜色图表) 或 RGB 值 (0x 前缀可以省略). 例如：cRed、cFF2211、c0xFF2211、cDefault。

Disabled: 让可输入型控件变为灰色禁用状态, 这样可以防止取得焦点或用户改变其内容. 以后可以使用 GuiControl Enable 来启用控件。注意：要让编辑控件为只读状态，请指定 ReadOnly 选项代替。并且, 还可以在单词 Disabled 后紧跟着 0 或 1 来表示控件的初始状态 (0 为启用而 1 为禁用). 换句话说，Disabled 和 Disabled%VarContainingOne% 是一样的。

Hidden: 让控件初始为隐藏状态. 以后可以使用 GuiControl Show 来让它显示。可以在单词 Hidden 后跟着 0 或 1 来表示初始状态 (0 为可见而 1 为隐藏). 换句话说，Hidden 和 Hidden%VarContainingOne% 是一样的。

Left: 在控件的可用宽度内左对齐控件的文本.

Right: 在控件的可用宽度内右对齐控件的文本. 对于复选框和单选按钮, 此选项也同时把框放置在控件的右边而不是左边.

Center: 在控件的可用宽度内居中对齐控件的文本.

Section：定义一个新的控件段并保存当前控件的位置以便在之后创建含有 xs 和 ys 选项的控件时使用，请参阅上文的描述。

Tabstop：使用 -Tabstop（即负 Tabstop）可以让用户按 TAB 键导航时跳过输入型控件。

Wrap: 让控件的文本自动换行. 因为几乎所有类型的控件初始状态都启用了自动换行，所以需要通过-Wrap禁用它。

VScroll: 当控件支持时为其提供一个垂直滚动条.

HScroll: 当控件支持时为其提供一个水平滚动条. 这个段落的剩余部分仅适用于 ListBox. 可水平滚动的宽度默认为 ListBox 宽度的 3 倍. 要使用其他的滚动宽度, 请在单词 HScroll 后紧跟着一个数字表示. 例如，HScroll500 将在 ListBox 中使用 500 像素的滚动栏宽度。但是，如果指定的滚动宽度小于 ListBox 的宽度，则不显示滚动条（不过在这种含有 HScroll 的情况下，可以在之后使用 GuiControl, +HScroll500, MyScrollBar 来添加水平滚动条，否则是无法添加的）。

控件: 不常用样式和选项

BackgroundTrans: 使用透明的背景, 这样可以让任何一个在 Text, Picture 或 GroupBox 后面的控件显示出来. 例如, 在 Picture 控件上显示一个透明背景的 Text 可以让文字看起来就像图片的一部分. 以后可以使用 GuiControl +background 移除此选项。请参阅 Picture 控件的 AltSubmit 部分来了解关于透明图像的更多细节。已知限制：对包含了 ListView 的 Tab 控件中的其他控件，BackgroundTrans 可能无法正确应用。

-Background（即负 Background）：使用标准的背景颜色代替 Gui Color 命令设置的那个颜色。此选项常用于让 Tab 控件使用其标准颜色代替窗口颜色. 以后可以使用 GuiControl +background 移除此选项。

Border: 为控件增加一个细边框. 对于大多数控件不需要使用此选项, 因为它们已经含有特定于类型的边框. 添加一个边框到 现有 控件时, 可能需要给控件的宽度和高度增加 1 个像素.

Hwnd OutputVar [v1.0.46.01+]: 在 Gui Add 中使用时, 此选项保存新建控件的窗口句柄 (HWND) 到 OutputVar. 例如：Gui, Add, Edit, vMyEdit HwndMyEditHwnd。如果在函数中使用, MyEditHwnd 会被视为 函数动态变量. 控件的 HWND 常用于 PostMessage, SendMessage 和 DllCall. 它还可以直接用在 ahk_id WinTitle (即使 DetectHiddenWindows 设置关闭时, 这样对于隐藏控件也是有效的) 或 [in v1.1.04+] GuiControl 和 GuiControlGet 的ControlID 参数. 相关提示，父窗口的 HWND 可以使用 Gui MyGui:+HwndOutputVar 获取。

Theme: 使用此选项可以让新建的控件忽略窗口当前的主题设置. 它对于现有控件没有效果; 不过, 这种情况可能在将来的版本中改变. 请参阅 Gui +/-Theme 了解详情.

(未命名样式): 在十进制或十六进制的 样式编号 前加上加号或减号表示添加或删除此样式. 如果省略了符号, 则默认为加号.

(未命名扩展样式): 在字母 E 和十进制或十六进制的扩展样式编号前加上加号或减号表示添加或删除此扩展样式. 如果省略了符号, 则默认为加号. 例如，E0x200 表示添加 WS_EX_CLIENTEDGE 样式，它可以为图片和其他控件增加一个下沉的边框样式。尽管这里没有列出其他的扩展样式编号（因为它们极少使用），不过可以通过在 www.microsoft.com 中搜索 WS_EX_CLIENTEDGE 找到它们。

窗口事件

如果在脚本中存在下列的标签 (子程序) 时, 它们会自动和 GUI 窗口关联:

GuiClose: 使用下列其中一种方法关闭窗口时自动运行此子程序: 点击标题栏上的关闭按钮, 从标题栏中的系统菜单中选择 "关闭" 或使用 WinClose 关闭. 如果此标签不存在, 则关闭窗口只是简单地隐藏窗口, 与 Gui Cancel 的效果一样. 在 GuiClose 中一个最常用的动作是 ExitApp; 例如:

GuiClose:
ExitApp

GuiEscape: 用户在 GUI 窗口活动时按下 Escape 后自动运行此子程序. 如果此标签不存在, 则按下 Escape 没有效果. 已知限制: 如果窗口中首个控件是禁用的 (可能与控件类型有关), 则按下 Escape 时 GuiEscape 子程序不会运行. 产生这样的效果可能是受其他一些事件的影响.

GuiSize: 对窗口调整大小, 最小化, 最大化或还原时自动运行此子程序. 内置变量 A_GuiWidth 和 A_GuiHeight 分别包含了窗口工作区调整后的宽度和高度，窗口工作区不包括标题栏、菜单栏和边框。此外，A_EventInfo 和 ErrorLevel 将同时包含下列数字的其中一个：

0: 窗口被还原或通过拖拉窗口边缘这样正常调节过大小时.
1: 窗口被最小化了.
2: 窗口被最大化了.

脚本中可以使用 GuiSize 调整控件的大小和位置来响应用户对窗口大小的改变. 通过 #Include 加载 Titan 的 "Anchor" 脚本 可以让这种处理更容易些.

GuiContextMenu: 当用户在窗口上除标题栏和菜单栏外的其他地方点击右键时自动运行此子程序. 当用户按下 Apps 键或 Shift-F10 时也会运行. 和其他多数 GUI 标签不同, GuiContextMenu 可以含有多个并发 线程. 在 GuiContextMenu 子程序中可以引用下列内置变量:

  1. A_GuiControl, 它包含了接收事件的控件的 文本或变量名 (如果没有则为空).
  2. A_EventInfo: 当右键点击 ListBox, ListView 或 TreeView 时 (可以由上面的 A_GuiControl 确定), A_EventInfo 包含了右键点击的控件项目:
    ListBox 或 ListView: A_EventInfo 包含了当前焦点行的行号 (如果没有则为 0).
    TreeView: 右键点击时, A_EventInfo 包含了右击项目的 ID 编号 (如果用户点击到项目外的其他地方则为 0). 对于 AppsKey 和 Shift-F10, A_EventInfo 包含了选择的项目的 ID 编号.
  3. A_GuiX 和 A_GuiY，包含了菜单显示位置的 X 和 Y 坐标（例如 Menu, MyContext, Show, %A_GuiX%, %A_GuiY%）。这里的坐标相对于窗口的左上角.
  4. A_GuiEvent, 当用户右键点击时包含单词 RightClick, 当用户按下 Apps 键或 Shift-F10 时包含单词 Normal.

注意: 由于 Edit 和 MonthCal 控件有它们自己的右键菜单, 所以右键点击这些控件时不会运行 GuiContextMenu.

GuiDropFiles: 拖放文件/文件夹到窗口上时运行此子程序 (如果此子程序已经在运行中, 则忽略拖放事件). 在 GuiDropFiles 中可以引用下列内置变量:

  1. A_GuiControl, 它包含了接收到释放文件的控件的 文本或变量名 (如果没有则为空).
  2. A_EventInfo 和 ErrorLevel, 包含了释放文件的数目.
  3. A_GuiX 和 A_GuiY, 包含了释放文件时的 X 和 Y 坐标 (相对于窗口的左上角).
  4. A_GuiEvent, 包含了被释放文件的名称, 文件名之间使用换行符 (`n) 分隔.

要逐个提取每个文件, 请使用 解析循环, 如下所示:

; 示例 #1:
Loop, parse, A_GuiEvent, `n
{
    MsgBox, 4,, File number %A_Index% is:`n%A_LoopField%.`n`nContinue?
    IfMsgBox, No, Break
}

; 示例 #2: 只要提取首个文件, 请参照此例:
Loop, parse, A_GuiEvent, `n
{
    FirstFile = %A_LoopField%
    Break
}

; 示例 #3: 要按照文件名的字母顺序处理文件, 请参照此例:
FileList = %A_GuiEvent%
Sort, FileList
Loop, parse, FileList, `n
    MsgBox File number %A_Index% is:`n%A_LoopField%.

要临时禁用窗口的拖放功能，请使用 Gui -E0x10 移除 WS_EX_ACCEPTFILES 样式。后面要重新启用，请使用 Gui +E0x10。

检测和响应其他事件: 其他 GUI 事件可以使用 OnMessage() 来检测和响应. 例如, 当用户把鼠标移动到窗口中特殊的控件时脚本可以通过工具提示显示相关帮助. 请参阅演示 GUI 工具提示示例.

创建多个 GUI 窗口

对于非首个窗口，需要在上面描述的特殊标签前加上窗口的名称或编号（如果有）作为前缀；例如2GuiEscape和2GuiClose为第二个窗口的默认标签，而MyGuiGuiEscape和MyGuiGuiClose为MyGui窗口的默认标签。要使用自定义的标签名称，请参阅 Gui +Label。

要对非 默认 窗口进行操作, 需要在子命令前加上窗口名称或编号 (在 v1.1.03+, 还可以使用 HWND) 和一个冒号, 例如:

Gui, MyGui:Add, Text,, Text for about-box.
Gui, MyGui:Show

使用 Gui MyGui:Default 后可以去除上面使用的“MyGui:”前缀。此外，在由窗口运行的 GUI 线程中对此窗口进行操作时可以不加前缀。

[v1.1.03+]: Gui 名称必须遵循和 变量名 相同的规则. 在 1 到 99 范围外或长于两个字符 (例如 0x01) 的数字必须为现有 Gui 的 HWND, 否则命令执行失败. 可以创建的窗口数仅受系统可用资源的限制.

[v1.1.04+]: 使用 Gui, New 可以创建任何数目的未命名 GUI 窗口.

GUI 事件, 线程和子程序

GUI 线程 是由 GUI 动作启动的. GUI 动作包括从 GUI 窗口的 菜单栏 中选择一个项目或触发其某个 g 标签 (例如按下按钮).

GUI 线程的 默认窗口名称 是运行此线程的窗口名称. 非 GUI 线程的默认窗口编号为 1.

当一个 GUI 线程 启动时, 此线程的 上次找到的窗口 初始为此 GUI 窗口自身. 这样可以让窗口和控件操作命令（例如 WinMove、WinHide、WinSet、WinSetTitle 和 ControlGetFocus）对当前的 GUI 窗口进行操作时省略 WinTitle 和 WinText（即使窗口处于隐藏状态）。

当一个控件的 g 标签 由于之前的点击还在运行时, 点击此控件不会有效果并且此事件被丢弃. 要避免此问题, 请在子程序的首行使用 Critical (不过, 这样也将缓冲/延迟其他 线程, 例如按下的热键).

内置变量 A_Gui 和 A_GuiControl 包含了运行当前线程的窗口编号和控件 ID. 要了解详情请参阅 A_Gui 和 A_GuiControl.

要让多个事件执行相同的子程序, 请在子程序上面连续指定这些标签. 例如：

GuiEscape:
GuiClose:
ButtonCancel:
ExitApp  ; 上面的所有标签都会执行这个语句.

所有的 GUI 线程 都会以设置的默认值启动, 例如 SendMode. 这些默认值可以在 自动执行段 改变.

键盘导航

使用 TAB 可以在 GUI 窗口中导航, 它会移动键盘焦点到下一个可输入型控件中 (跳过移除了 Tabstop 样式的控件). 导航的顺序由控件添加的顺序决定. 当首次显示一个窗口时, 键盘焦点将在首个具有 Tabstop 样式 (默认情况下大多数类型的控件都具有) 的可输入型控件上.

可以在某些控件的名称中包含和符号 (&) 来创建此控件的键盘快捷键, 在控件名称中的快捷键字母会加上下划线显示 (取决于系统设置). 用户可以通过按下 ALT 键和相应的字符来触发这样的快捷键. 对于按钮, 复选框和单选按钮, 按下相应的快捷键等于点击了按钮. 对于 GroupBox 和 Text 控件, 按下相应的快捷键则移动键盘焦点到此控件后 (不是指位置, 是创建顺序) 首个具有 tabstop 样式的可输入型控件中. 然而, 如果多个控件含有相同的快捷键, 则按下此快捷键会让键盘焦点在这些控件中交替.

要在上面提及类型的控件中显示一个原义的和符号，请指定两个连续的和符号，例如：Save && Exit。

窗口外观

GUI 窗口使用它创建时的托盘图标作为其窗口图标. 因此, 如果要使用不同的图标, 需要在创建窗口前改变托盘图标. 例如：Menu, Tray, Icon, MyIcon.ico。还可以让窗口拥有一个不同的大图标而不用这个小图标 (大图标显示在 alt-tab 任务切换器中). 这个功能可以通过 DllCall 和 SendMessage 来实现; 例如:

hIcon32 := DllCall("LoadImage", uint, 0
    , str, "My Icon.ico"  ; 图标文件名 (此文件可以包含多种尺寸的图标).
    , uint, 1  ; 图像类型: IMAGE_ICON
    , int, 32, int, 32  ; 想要的高度和宽度 (可以让 LoadImage 确定哪个是最佳图标).
    , uint, 0x10)  ; 标志: LR_LOADFROMFILE
Gui +LastFound
SendMessage, 0x80, 1, hIcon32  ; 0x80 是 WM_SETICON; 1 表示 ICON_BIG (而0 表示 ICON_SMALL).
Gui Show

由于操作系统的限制, 在 Windows XP 以及更高版本中, Checkbox, Radio button 和 GroupBox 控件中的文本不是使用默认颜色时将显示为经典主题外观.

相关主题: 窗口边距.

一般说明

使用 GuiControl 和 GuiControlGet 可以单独对 GUI 窗口中的控件进行操作.

每个 GUI 窗口最多可以包含 11,000 个控件. 然而, 当控件数量超过 5000 时需要谨慎, 因为此时某些类型的控件可能让系统不稳定.

使用 GUI 命令的任何脚本会自动成为 持续运行的 (即使 GUI 命令实际从未执行过). 同时也会单实例运行, 除非使用 #SingleInstance 覆盖了默认设置.

相关

GuiControl, GuiControlGet, Menu, 控件类型, ListView, TreeView, Control, ControlGet, SplashImage, MsgBox, FileSelectFile, FileSelectFolder

示例

; 示例: 实现类似 SplashTextOn 的效果:

Gui, +AlwaysOnTop +Disabled -SysMenu +Owner  ; +Owner 避免显示任务栏按钮.
Gui, Add, Text,, Some text to display.
Gui, Show, NoActivate, Title of Window  ; NoActivate 让当前活动窗口继续保持活动状态.

; 示例: 要求输入姓名的简单输入框:

Gui, Add, Text,, First name:
Gui, Add, Text,, Last name:
Gui, Add, Edit, vFirstName ym  ; ym 选项开始一个新的控件列。
Gui, Add, Edit, vLastName
Gui, Add, Button, default, OK  ; ButtonOK（如果存在）会在此按钮被按下时运行。
Gui, Show,, Simple Input Example
return  ; 自动运行段结束。在用户进行操作前脚本会一直保持空闲状态.

GuiClose:
ButtonOK:
Gui, Submit  ; 保存用户的输入到每个控件的关联变量中.
MsgBox You entered "%FirstName% %LastName%".
ExitApp

; 示例: 选项卡控件:

Gui, Add, Tab2,, First Tab|Second Tab|Third Tab  ; Tab2 比起 Tab 需要 v1.0.47.05.
Gui, Add, Checkbox, vMyCheckbox, Sample checkbox
Gui, Tab, 2
Gui, Add, Radio, vMyRadio, Sample radio1
Gui, Add, Radio,, Sample radio2
Gui, Tab, 3
Gui, Add, Edit, vMyEdit r5  ; r5 表示 5 行的高度.
Gui, Tab  ; 即后续添加的控件将不属于前面那个选项卡控件.
Gui, Add, Button, default xm, OK  ; xm 把它放置在左下角.
Gui, Show
return

ButtonOK:
GuiClose:
GuiEscape:
Gui, Submit  ; 保存每个控件的内容到其关联变量中.
MsgBox You entered:`n%MyCheckbox%`n%MyRadio%`n%MyEdit%
ExitApp

; 示例: 显示一个目录中的文件的列表框:

Gui, Add, Text,, Pick a file to launch from the list below.`nTo cancel, press ESCAPE or close this window.
Gui, Add, ListBox, vMyListBox gMyListBox w640 r10
Gui, Add, Button, Default, OK
Loop, C:\*.*  ; 根据您的需要改变此文件和通配符模式.
{
    GuiControl,, MyListBox, %A_LoopFileFullPath%
}
Gui, Show
return

MyListBox:
if A_GuiEvent <> DoubleClick
    return
; 否则, 用户双击了列表中的项目, 所以把它和点击 OK 按钮进行相同的处理.
; 所以直接进入下一个标签.
ButtonOK:
GuiControlGet, MyListBox  ; 获取列表框中当前选择的项目.
MsgBox, 4,, Would you you like to launch the file or document below?`n`n%MyListBox%
IfMsgBox, No
    return
; 否则, 运行此文件:
Run, %MyListBox%,, UseErrorLevel
if ErrorLevel = ERROR
    MsgBox Could not launch the specified file.  Perhaps it is not associated with anything.
return

GuiClose:
GuiEscape:
ExitApp

; 示例: 当鼠标移动到特定的控件上时显示相关帮助 (使用工具提示):

Gui, Add, Edit, vMyEdit
MyEdit_TT := "This is a tooltip for the control whose variable is MyEdit."
Gui, Add, DropDownList, vMyDDL, Red|Green|Blue
MyDDL_TT := "Choose a color from the drop-down list."
Gui, Add, Checkbox, vMyCheck, This control has no tooltip.
Gui, Show
OnMessage(0x200, "WM_MOUSEMOVE")
return

WM_MOUSEMOVE()
{
    static CurrControl, PrevControl, _TT  ; _TT 保持为空以便用于下面的 ToolTip 命令.
    CurrControl := A_GuiControl
    If (CurrControl <> PrevControl and not InStr(CurrControl, " "))
    {
        ToolTip  ; 关闭之前的工具提示.
        SetTimer, DisplayToolTip, 1000
        PrevControl := CurrControl
    }
    return

    DisplayToolTip:
    SetTimer, DisplayToolTip, Off
    ToolTip % %CurrControl%_TT  ; 前导的百分号表示要使用表达式.
    SetTimer, RemoveToolTip, 3000
    return

    RemoveToolTip:
    SetTimer, RemoveToolTip, Off
    ToolTip
    return
}

GuiClose:
ExitApp

; 示例: 使用透明窗口进行屏幕显示 (OSD):

CustomColor = EEAA99  ; 可以为任意 RGB 颜色 (在下面会被设置为透明).
Gui +LastFound +AlwaysOnTop -Caption +ToolWindow  ; +ToolWindow 避免显示任务栏按钮和 alt-tab 菜单项.
Gui, Color, %CustomColor%
Gui, Font, s32  ; 设置大字体 (32 磅).
Gui, Add, Text, vMyText cLime, XXXXX YYYYY  ; XX & YY 用来自动调整窗口大小.
; 让此颜色的所有像素透明且让文本显示为半透明 (150):
WinSet, TransColor, %CustomColor% 150
SetTimer, UpdateOSD, 200
Gosub, UpdateOSD  ; 立即进行第一此更新而不等待计时器.
Gui, Show, x0 y400 NoActivate  ; NoActivate 让当前活动窗口继续保持活动状态.
return

UpdateOSD:
MouseGetPos, MouseX, MouseY
GuiControl,, MyText, X%MouseX%, Y%MouseY%
return

; 示例: 在背景图像上移动的进度条.

Gui, Color, White
Gui, Add, Picture, x0 y0 h350 w450, %A_WinDir%\system32\ntimage.gif
Gui, Add, Button, Default xp+20 yp+250, Start the Bar Moving
Gui, Add, Progress, vMyProgress w416
Gui, Add, Text, vMyText wp  ; wp 表示 "使用之前的宽度".
Gui, Show
return

ButtonStartTheBarMoving:
Loop, %A_WinDir%\*.*
{
    if A_Index > 100
        break
    GuiControl,, MyProgress, %A_Index%
    GuiControl,, MyText, %A_LoopFileName%
    Sleep 50
}
GuiControl,, MyText, Bar finished.
return

GuiClose:
ExitApp

; 示例: 简单的图像查看器:

Gui, +Resize
Gui, Add, Button, default, &Load New Image
Gui, Add, Radio, ym+5 x+10 vRadio checked, Load &actual size
Gui, Add, Radio, ym+5 x+10, Load to &fit screen
Gui, Add, Pic, xm vPic
Gui, Show
return

ButtonLoadNewImage:
FileSelectFile, file,,, Select an image:, Images (*.gif; *.jpg; *.bmp; *.png; *.tif; *.ico; *.cur; *.ani; *.exe; *.dll)
if file =
    return
Gui, Submit, NoHide ; 保存单选按钮的值.
if Radio = 1  ; 按实际大小显示图像.
{
    Width = 0
    Height = 0
}
else ; 选择了第二个单选按钮: 按照屏幕的大小显示图像.
{
    Width := A_ScreenWidth - 28  ; 减去的 28 是用来显示边框和内边缘的空间.
    Height = -1  ; "保持高宽比" 应该是最好的.
}
GuiControl,, Pic, *w%width% *h%height% %file%  ; 载入图像.
Gui, Show, xCenter y0 AutoSize, %file%  ; 调整窗口以适合图片尺寸.
return

GuiClose:
ExitApp

; 示例: 含菜单栏的简单文本编辑器.

; 为菜单栏创建子菜单:
Menu, FileMenu, Add, &New, FileNew
Menu, FileMenu, Add, &Open, FileOpen
Menu, FileMenu, Add, &Save, FileSave
Menu, FileMenu, Add, Save &As, FileSaveAs
Menu, FileMenu, Add  ; 分隔线.
Menu, FileMenu, Add, E&xit, FileExit
Menu, HelpMenu, Add, &About, HelpAbout

; 创建用来附加子菜单的菜单栏:
Menu, MyMenuBar, Add, &File, :FileMenu
Menu, MyMenuBar, Add, &Help, :HelpMenu

; 添加菜单栏到窗口:
Gui, Menu, MyMenuBar

; 创建主编辑控件并显示窗口:
Gui, +Resize  ; 让用户可以调整窗口的大小.
Gui, Add, Edit, vMainEdit WantTab W600 R20
Gui, Show,, Untitled
CurrentFileName =  ; 表示当前没有文件.
return

FileNew:
GuiControl,, MainEdit  ; 清空编辑控件.
return

FileOpen:
Gui +OwnDialogs  ; 强制用户响应 FileSelectFile 对话框后才能返回到主窗口.
FileSelectFile, SelectedFileName, 3,, Open File, Text Documents (*.txt)
if SelectedFileName =  ; 没有选择文件.
    return
Gosub FileRead
return

FileRead:  ; 调用者已经设置了 SelectedFileName 变量.
FileRead, MainEdit, %SelectedFileName%  ; 读取文件的内容到变量中.
if ErrorLevel
{
    MsgBox Could not open "%SelectedFileName%".
    return
}
GuiControl,, MainEdit, %MainEdit%  ; 在控件中显示文本.
CurrentFileName = %SelectedFileName%
Gui, Show,, %CurrentFileName%   ; 在标题栏显示文件名.
return

FileSave:
if CurrentFileName =   ; 还没有选择文件, 所以执行另存为操作.
    Goto FileSaveAs
Gosub SaveCurrentFile
return

FileSaveAs:
Gui +OwnDialogs  ; 强制用户响应 FileSelectFile 对话框后才能返回到主窗口..
FileSelectFile, SelectedFileName, S16,, Save File, Text Documents (*.txt)
if SelectedFileName =  ; 没有选择文件.
    return
CurrentFileName = %SelectedFileName%
Gosub SaveCurrentFile
return

SaveCurrentFile:  ; 调用者已经确保了 CurrentFileName 不为空.
IfExist %CurrentFileName%
{
    FileDelete %CurrentFileName%
    if ErrorLevel
    {
        MsgBox The attempt to overwrite "%CurrentFileName%" failed.
        return
    }
}
GuiControlGet, MainEdit  ; 获取编辑控件的内容.
FileAppend, %MainEdit%, %CurrentFileName%  ; 保存内容到文件.
; 成功时在标题栏显示文件名 (以防 FileSaveAs 调用时的情况):
Gui, Show,, %CurrentFileName%
return

HelpAbout:
Gui, About:+owner1  ; 让主窗口 (Gui #1) 成为 "关于对话框" 的父窗口.
Gui +Disabled  ; 禁用主窗口.
Gui, About:Add, Text,, Text for about box.
Gui, About:Add, Button, Default, OK
Gui, About:Show
return

AboutButtonOK:  ; 上面的 "关于对话框" 需要使用这部分.
AboutGuiClose:
AboutGuiEscape:
Gui, 1:-Disabled  ; 重新启用主窗口 (必须在下一步之前进行).
Gui Destroy  ; 销毁关于对话框.
return

GuiDropFiles:  ; 对拖放提供支持.
Loop, Parse, A_GuiEvent, `n
{
    SelectedFileName = %A_LoopField%  ; 仅获取首个文件 (如果有多个文件的时候).
    break
}
Gosub FileRead
return

GuiSize:
if ErrorLevel = 1  ; 窗口被最小化了.  无需进行操作.
    return
; 否则, 窗口的大小被调整过或被最大化了. 调整编辑控件的大小以匹配窗口.
NewWidth := A_GuiWidth - 20
NewHeight := A_GuiHeight - 20
GuiControl, Move, MainEdit, W%NewWidth% H%NewHeight%
return

FileExit:     ; 用户在 File 菜单中选择了 "Exit".
GuiClose:  ; 用户关闭了窗口.
ExitApp


GUI 控件类型

目录

  • Text, Edit, UpDown, Picture
  • Button, Checkbox, Radio
  • DropDownList, ComboBox
  • ListBox, ListView, TreeView
  • Link, Hotkey, DateTime
  • MonthCal, Slider, Progress
  • GroupBox, Tab2, StatusBar
  • ActiveX (例如 Internet Explorer Control)
  • 定制

文本

描述: 包含用户不能编辑的无边界文本的区域. 常用来标识其他控件. 例如：

Gui, Add, Text,, Please enter your name:

此时最后一个参数为要显示的字符串. 它可以包含换行符 (`n) 来开始新行. 此外, 一个长行可以使用 延续片段 的方法分成较短的几行.

如果 Options 中指定了宽度 (W) 而没有指定 行数 (R) 或高度 (H), 那么在需要时文本将自动换行, 同时自动设置控件的高度.

因为控件的内容是 Gui 命令的最后一个参数, 所以可以直接使用逗号而需要转义. 对于其他所有命令的最后一个参数也是如此.

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户点击文本时 MySubroutine 标签会自动运行. 这可以用来模仿带下划线的蓝色超级链接, 如下面的可运行脚本所示:

Gui, Font, underline
Gui, Add, Text, cBlue gLaunchGoogle, Click here to launch Google.

; 或者可以使用 Link 控件：
Gui, Add, Link,, Click <a href="www.google.com">here</a> to launch Google.
Gui, Font, norm
Gui, Show
return

LaunchGoogle:
Run www.google.com
return

通过检查 A_GuiEvent 是否包含单词 DoubleClick 可以检测到双击事件.

在文本中使用和符号 (&) 可以让其中的某个字母带下划线显示. 例如：

Gui, Add, Text,, &First Name:
Gui, Add, Edit

在上述示例中, 字母 F 将被添加下划线, 这允许用户按下 快捷键 Alt+F 将键盘焦点设置到此文本控件后添加的首个可输入型控件中. 要显示一个原义的和符号, 请指定两个连续的和符号 (&&). 要取消控件中和符号的特殊含义, 请在控件的选项中包含 0x80.

请参阅 常规选项 来了解其他选项 (例如 Right, Center 和 Hidden). 另请参阅: 控件的位置和大小.

Edit

描述: 用户可以输入自由格式的文本区域. 例如：

Gui, Add, Edit, r9 vMyEdit, Text to appear inside the edit control (omit this parameter to start off empty).

如果控件中有多行的文本, 则它将为多行的. 例如，在选项中指定 r3 将创建一个拥有后面那些默认属性的 3 行编辑控件：一个垂直滚动条，启用自动换行并且捕获的回车键作为输入的一部分而不触发窗口的默认按钮。

要在多行编辑控件中开始新行, 请在最后一个参数中 (内容) 包含单独的换行符 (`n) 或回车换行符 (`r`n). 这两种方法都会在 Edit 控件中产生原义的 `r`n 对. 然而, 当控件通过 Gui Submit 或 GuiControlGet 把内容保存到其变量时, 文本中的每对 `r`n 总是被转换成单独的换行符 (`n). 要把文本写入到文件中，请参照此例：FileAppend, %MyEdit%, C:\Saved File.txt。

如果控件启用了自动换行 (对于多行编辑控件默认是启用的), 那么用户输入时任何自动换行的地方不会产生换行字符 (仅回车键才会).

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户或脚本改变控件的内容时 MySubroutine 标签会自动运行.

提示: 要加载一个文本文件的内容到编辑控件中, 请使用 FileRead 和 GuiControl. 例如：

Gui, Add, Edit, R20 vMyEdit
FileRead, FileContents, C:\My File.txt
GuiControl,, MyEdit, %FileContents%

Edit 选项

要移除而非添加选项，请在选项前加上负号：

Limit: 限制用户的输入在编辑区域的可见宽度内. 另外, 要限制输入指定数目的字符, 请在选项后跟着数字. 例如，Limit10 将允许输入不超过 10 个字符。

Lowercase: 把用户输入的字符自动转换成小写形式.

Multi: 让控件可以含有多行文本. 然而, 通常没必要指定此选项, 因为它会根据高度 (H), 行数 (R) 或内容 (Text) 自动判断.

Number: 阻止用户输入数字以外的其他字符到编辑区域 (然而, 还是可能粘贴非数字字符到里面). 强制输入数字的另一种方法是添加 UpDown 控件到 Edit 控件.

Password: 通过将用户的输入替代为屏蔽字符来隐藏用户的输入 (例如密码). 如果想使用非默认的屏蔽字符, 请在单词 Password 后加上此符号. 例如，Password* 将使用星号而不是黑色圆（项目符号）作为屏蔽符号，这是 Windows XP 中的默认屏蔽符号。注意: 此选项对于多行编辑控件没有效果.

ReadOnly: 阻止用户改变控件的内容. 不过, 仍然可以滚动, 选择文本或将文本复制到剪贴板.

Tn: 字母 T 可以用来设置 多行编辑控件 的制表位 (因为制表位决定了原义的 TAB 字符跳转的列位置, 所以它们可以把文本格式成列). 如果没有使用字母 T, 则每 32 个对话框单位设置一次制表位 (每个对话框单位的宽度由操作系统决定). 如果仅使用一次字母 T, 则每 n 个单位设置一次横跨整个控件宽度的制表位. 例如，Gui, Add, Edit, vMyEdit r16 t64 将设置制表位之间的距离为默认的两倍。要自定义制表位，请指定字母 T 多次，例如：Gui, Add, Edit, vMyEdit r16 t8 t16 t32 t64 t128。在列表中每个绝对的列位置设置一个制表位, 制表位数目最大可达 50 个. 注: 制表位仅用于多行编辑控件.

Uppercase: 把用户输入的字符自动转换成大写形式.

WantCtrlA [v1.0.44+]: 指定 -WantCtrlA (负 WantCtrlA) 阻止用户使用 Control-A 来选择编辑控件中所有文本.

WantReturn: 指定 -WantReturn (即负后后跟着 WantReturn) 来阻止多行编辑控件捕获回车键. 按下回车键相当于点击了窗口的默认按钮（如果有）。此时用户可以使用 Control-Enter 来开始新行.

WantTab: 使得 tab 键击产生制表符而不是导航到下一个控件. 如果没有这个选项, 则在多行编辑控件中用户可以按下 Control-Tab 来产生制表符. 注: 尽管 WantTab 也可以用于单行编辑控件, 但此时每个制表符显示为一个空框字符 (不过实际保存为真正的 tab).

-Wrap (负 wrap): 关闭多行编辑控件中的自动换行属性. 由于在控件创建后不能改变此样式, 所以需要使用下列方法的其中一个来改变它: 1) 销毁 后重新创建窗口和其中的控件; 或 2) 创建两个重叠的编辑控件, 其中一个启用自动换行而另一个禁用. 当前没有使用的那个可以保持空的和/或隐藏.

请参阅 常规选项 来了解其他选项 (例如 Right, Center 和 Hidden). 另请参阅: 控件的位置和大小.

更强大的编辑控件: HiEdit 是免费, 多选项卡, 支持大文件且消耗很少内存的编辑控件. 它可以编辑文本和二进制文件. 想了解详情和演示, 请参阅 www.autohotkey.com/forum/topic19141.html

UpDown

描述: 一对箭头组成的按钮, 用户点击后会增加或减少值. 默认情况下, UpDown 控件自动依附于前一个添加的控件上. 这里的前一个控件被称为 UpDown 的 伙伴控件. 最常见的例子是 "旋转器", 这里 UpDown 附加到 Edit 控件. 例如：

Gui, Add, Edit
Gui, Add, UpDown, vMyUpDown Range1-10, 5

在上面的例子中, Edit 控件是 UpDown 的伙伴控件. 每当用户按下了增减按钮的其中一个, Edit 控件中的数字会自动增加或减少.

UpDown 的伙伴控件也可以是 Text 控件 或 ListBox. 然而, 由于操作系统的限制, 除了这些以外的其他控件类型 (例如 ComboBox 和 DropDownList) 可能无法和 g 标签 以及其他特性一起正常工作.

在最后一个参数中指定 UpDown 的初始位置 (如果省略, 则初始为 0 或允许的范围中最接近 0 的数字).

使用Gui Submit命令后，控件的关联输出变量（如果有）会接收到UpDown的当前的数字位置。如果 UpDown 依附于编辑控件而且您不想确认用户的输入, 此时最好使用 UpDown 的值而不是编辑控件的. 这是因为 UpDown 总是产生一个允许范围内的数字, 即使用户在编辑控件中输入了非数字或超出范围的内容. 相关提示, 默认情况下超过三位的数字会添加 千位分隔符 (例如逗号). 这些分隔符保存在编辑控件的输出变量中, 但不在 UpDown 的变量中.

如果 UpDown 含有 g 标签, 则当用户点击增减按钮的其中一个或按下了键盘上的方向键时它将会运行. 每次运行g标签还会保存UpDown的位置到其关联输出变量（如果有）。

UpDown 选项

Horz: 使控件的按钮点指向左/右而不是上/下. 默认情况下, Horz 还会让控件变成孤立的 (没有伙伴控件). 通过在控件选项中指定 Horz 16 可以覆盖此特性。

Left: 把 UpDown 放在其伙伴控件的左边而不是右边.

Range: 使用 0 到 100 外的其他范围. 在单词 Range 后指定最小值, 破折号和最大值. 例如, Range1-1000 将允许选择一个介于 1 和 1000 之间的数字; Range-50-50 将允许介于 -50 和 50 之间的数字; 而 Range-10--5 将允许介于 -10 和 -5 之间的数字. 交换最小值和最大值可以让箭头往与正常方向相反的方向移动. 最大的允许范围是 -2147483648-2147483647. 最后, 如果伙伴控件为 ListBox, 那么垂直的默认范围是 32767-0 而水平的则反向 (Horz).

Wrap: 当用户试图超出最小值或最大值时使得控件返回到其范围的另一端. 如果没有 Wrap, 当达到最小值或最大值时控件会停止.

-16 (负 16): 让垂直的 UpDown 成为孤立的; 即让它没有伙伴控件. 这还可以让控件符合任何指定的宽度, 高度和位置而不是适应于其伙伴控件的大小. 此外, 孤立的 UpDown 会内部跟踪它自己的位置. 使用 Gui Submit 可以正常获取此位置.

0x80：在选项中包含 0x80 来省略伙伴控件中正常出现在每三位十进制数间的千位分隔符。然而, 通常不使用此样式, 因为当脚本从 UpDown 控件 (而不是其伙伴控件) 获取的数字中不包含分隔符.

使用 1 以外的其他增量: 在 此脚本 中, NumEric 演示了如何改变 UpDown 增量为 1 以外的其他值 (例如 5 或 0.1).

另请参阅: 控件的位置和大小.

Picture (或 Pic)

描述: 包含图像的区域 (请参阅最后两段来了解支持的文件类型). 最后一个参数是图像的文件名, 如果未指定绝对路径则假定在 A_WorkingDir 中. 例如：

Gui, Add, Picture, w300 h-1, C:\My Pictures\Company Logo.gif

要保持图像的实际宽度和/或高度, 请省略 W 和/或 H 选项. 否则，缩放图像的尺寸到指定的宽度和/或高度（此宽度和高度也决定了从多图标的 .ICO 文件中加载哪个图标）。要保持高宽比来缩放图像, 请在其中一个尺寸中指定 -1 而在另一个中指定正数. 例如，指定 w200 h-1 将缩放图像到 200 像素的宽度同时自动设置其高度。如果图片无法加载或显示 (例如找不到文件), 则控件被留空且设置其宽度和高度为零.

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户点击图片时 MySubroutine 标签会自动运行. 通过检查 A_GuiEvent 是否包含单词 DoubleClick 可以检测到双击事件.

要使用图片作为其他控件的背景, 则应该在其他控件之前正常添加图片. 然而，如果这些控件是可输入型且此图片控件含有 g 标签，那么在其他控件后创建图片控件并在其选项中包含 0x4000000（这是 WS_CLIPSIBLINGS）。使用此技巧还可以把一个图片设为 Tab 控件或 ListView 的背景。

图标, 光标和动画光标: 图标和光标可以从下列类型的文件中加载: ICO, CUR, ANI, EXE, DLL, CPL, SCR 以及包含图标资源的其他类型. 要使用文件中的图标组而不是首个图标, 请在 选项 包含单词 Icon 和图标组编号. 在下面的例子中，将使用第二个图标组中的默认图标：Gui, Add, Picture, Icon2, C:\My Application.exe。

在 选项 中指定单词 AltSubmit 会让程序使用微软的 GDIPlus.dll 来加载图像, 这可能让 GIF, BMP 和图标图像产生不同的外观. 例如, 它可以把含透明背景的 ICO/GIF 作为透明的位图进行加载, 这样允许 BackgroundTrans 选项才生效. 如果 GDIPlus 不可用 (请参阅下个段落), 则 AltSubmit 选项会被忽略而使用常规方法加载图像.

在所有的操作系统中都支持 GIF, JPG, BMP, ICO, CUR 和 ANI 图像. 在 Windows XP 或更高版本中, 还支持其他图像格式, 例如PNG, TIF, Exif, WMF 和 EMF. 比 XP 早的操作系统可以通过复制微软免费的 GDI+ DLL 到 AutoHotkey.exe 文件夹中来提供支持 (但如果是 已编译脚本, 则复制此 DLL 到脚本的文件夹). 要下载这个 DLL, 请在 www.microsoft.com 搜索下列短语: gdi redistributable

GIF 动画: 虽然 GIF 动画文件可以显示在图片控件中, 但实际上它们并不会动起来. 要解决此问题, 请使用 AniGIF DLL (对非商业用途免费), 演示的例子请参阅 www.autohotkey.com/forum/topic19264.html

按钮

描述: 按下后可以触发动作的按钮. 此时最后一个参数为按钮的名称 (显示在按钮上), 其中可以包含换行符 (`n) 来开始新行. 例如：

Gui, Add, Button, Default, OK

上面的例子在其 选项 中包含单词 Default 来让 "OK" 成为默认按钮. 每当用户按下回车键时会自动触发默认按钮的动作, 除非此时键盘焦点在另一个按钮上或含有 WantReturn 样式的多行编辑控件中. 以后要改变默认按钮为另一个按钮，请参照此例，这里让 Cancel 按钮成为默认按钮：GuiControl, +default, Cancel。以后要让窗口没有默认按钮，请参照此例：GuiControl, -default, OK。

在按钮名称中使用和符号 (&) 可以让其中的某个字母带下划线显示. 例如：

Gui, Add, Button,, &Pause

在上述示例中, 字母 P 将被添加下划线, 这允许用户按下 Alt+P 作为其 快捷键. 要显示一个原义的和符号, 请指定两个连续的和符号 (&&).

如果一个按钮没有明确的 g 标签, 则使用自动标签. 例如, 如果首个 GUI 窗口包含一个 OK 按钮, 则当按下此按钮时将运行 ButtonOK 标签 (如果存在). 对于非首个 GUI 窗口，则需要在按钮的自动标签前加上窗口编号；例如：2ButtonOK。

如果按钮上的文本包含空格或 &`r`n`t` 集合中的任意一个字符, 则在其自动标签中会删去这些字符. 例如, 名为 "&Pause" 的按钮其自动标签的名称将为 ButtonPause. 同样地, 名为 "Save && Exit" 的按钮其自动标签的名称将为 ButtonSaveExit (两个连续的和符号用来显示单个原义的和符号).

已知限制: 某些桌面主题可能无法正确的显示按钮文本. 如果遇到此情况，请尝试在按钮的选项中包含 -Wrap（负 Wrap）。不过这样也使得按钮名称中无法包含多行文本.

Checkbox

描述: 一个小方框, 可以选中或取消选中来表示 On/Off, Yes/No, 等等. 例如：

Gui, Add, Checkbox, vShipToBillingAddress, Ship to billing address?

最后一个参数是紧跟着方框显示的标注, 这通常是关于复选框用途的提示或描述. 它可以包含换行符 (`n) 来开始新行. 如果 选项 中指定了宽度 (W) 而没有指定 行数 (R) 或高度 (H), 那么在需要时控件的文本将自动换行, 同时自动设置控件的高度. 在选中时复选框的关联输出变量（如果有）接收到数字 1，未选中时为 0，而灰色不确定时为 -1。

在 选项 中指定单词 Check3 来启用第三种状态即显示灰色的选择标记而不是黑色的 (灰色状态表示复选框既不处于选中状态也不处于未选中状态). 在 选项 中指定单词 Checked 或 CheckedGray 可以让复选框初始状态分别为黑色选中状态或灰色状态. 单词 Checked 后面可以紧跟着 0, 1 或 -1 来表示初始状态. 换句话说，Checked 和 Checked%VarContainingOne% 是一样的。

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户点击或改变复选框时 MySubroutine 标签会自动运行.

已知限制: 某些桌面主题可能无法正确的显示按钮文本. 如果遇到此情况，请尝试在按钮的选项中包含 -Wrap（负 Wrap）。不过这样也使得按钮名称中无法包含多行文本.

Radio

单选按钮是一个小空圆, 可以被选中 (打开) 或不选中 (关闭). 例如：

Gui, Add, Radio, vMyRadioGroup, Wait for all items to be in stock before shipping.

此控件经常出现在 单选按钮组, 每组包含两个或多个单选按钮. 当用户点击一个单选按钮来打开它时, 其所在的单选按钮组中其他所有的单选按钮会自动关闭 (在单选按钮组中用户也可以使用方向键导航). 在所有连续添加的单选按钮周围会自动创建一个单选按钮组. 要开始一个新组, 请在新组的首个单选按钮的 选项 中指定单词 Group, 或者在新组和之前的组之间简单地添加一个非单选按钮控件, 因为这样会自动开始一个新组.

在最后一个参数中指定的标注会显示在单选按钮的右侧. 此标注通常作为提示或描述, 它可以包含换行符 (`n) 来开始新行. 如果在 选项 中指定了宽度 (W) 而没有指定行数 (R) 或高度 (H), 那么在需要时控件的文本将自动换行, 同时自动设置控件的高度.

在 选项 中指定单词 Checked 来让按钮初始为选中状态. 可以在单词 Checked 后紧跟着 0 或 1 来表示初始状态: 0 表示未选中, 而 1 表示选中. 换句话说，Checked 和 Checked%VarContainingOne% 是一样的。

选中时单选按钮的关联输出变量（如果有）接收到数字1而未选中时为0。但是, 如果单选组中仅有一个按钮含有关联变量, 则此变量将接收当前选择按钮的编号: 首个单选按钮为 1 (根据原来的创建顺序), 第二个为 2, 依此类推. 如果没有选择的按钮, 则保存 0.

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户选中按钮时 MySubroutine 标签会自动运行. 与之前段落中的单变量模式不同, 这里必须为单选按钮组中每个按钮指定 g 标签, 这样选中某个按钮时相应的标签才会运行. 这样可以灵活地忽略某些按钮的点击. 最后, 通过检查 A_GuiEvent 是否包含单词 DoubleClick 可以检测到双击事件.

已知限制: 某些桌面主题可能无法正确的显示按钮文本. 如果遇到此情况，请尝试在按钮的选项中包含 -Wrap（负 Wrap）。不过这样也使得按钮名称中无法包含多行文本.

DropDownList (或 DDL)

描述: 当按下一个小按钮时显示的选择列表. 此时，最后一个参数是管道分隔的选择列表，例如 Choice1|Choice2|Choice3。例如：

Gui, Add, DropDownList, vColorChoice, Black|White|Red|Green|Blue

要在窗口初次出现时预选其中的某项，请在此项后包含两个管道符（例如 Red|Green||Blue）。或者，在选项中包含单词 Choose 紧跟着想预选的编号。例如，Choose5 会预选第五项（和其他选项一样，它也可以为变量，例如 Choose%Var%）。要在控件创建后改变选择或添加/移除列表中的条目，请使用 GuiControl。

在 选项 中指定单词 Uppercase 或 Lowercase 来把列表中的所有项目自动转换成大写字母或小写字母. 指定单词 Sort 来按字母顺序自动排列列表的内容 (这也会影响后面通过 GuiControl 添加的所有项目). Sort 选项还会启用在弹出下拉列表时的增量搜索; 这使得可以通过输入一个项目名称的前几个字符来选择此项.

当使用Gui Submit命令后，控件的关联输出变量（如果有）会接收到当前选择项目的文本. 但是, 如果控件含有 AltSubmit 属性, 则输出变量将接收到项目的位置编号 (首个项目为 1, 第二个为 2, 等等.).

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户选择新项目时 MySubroutine 标签会自动运行.

使用 R 或 H 选项 来控制弹出列表的高度. 例如，指定 R5 会设置列表为 5 行高，而 H400 会设置选区字段和列表的总高度为 400 像素。如果同时省略 R 和 H 选项, 则列表会自动扩展到用户桌面的可用高度 (但是在早于 Windows XP 的操作系统中默认会显示 3 行).

要设置选区字段或列表项的高度，请使用 CB_SETITEMHEIGHT 消息，示例如下：

Gui Add, DDL, vcbx w200 hwndhcbx, One||Two
; CB_SETITEMHEIGHT = 0x153
PostMessage, 0x153, -1, 50,, ahk_id %hcbx%  ; 设置选区字段的高度。
PostMessage, 0x153,  0, 50,, ahk_id %hcbx%  ; 设置列表项的高度。
Gui Show, h70, Test

字段间的分隔符可以改变为管道符 (|) 外的其他字符. 例如 Gui +Delimiter`n 将改变分隔符为换行符而 Gui +DelimiterTab 将改变为 tab（`t）。

ComboBox

描述: 和 DropDownList 一样, 不过还允许输入自由格式的文本作为列表中可选的项目. 例如：

Gui, Add, ComboBox, vColorChoice, Red|Green|Blue|Black|White

除了可以使用上面描述的所有 DropDownList 选项外, 选项 中还可以包含单词 Limit 来限制用户的输入在 ComboBox 编辑区域的可见宽度内. 此外, 可以指定单词 Simple 来让 ComboBox 表现的像一个下方带有 ListBox 的 Edit 区域.

当使用Gui Submit命令后，控件的关联输出变量（如果有）会接收到当前选择项目的文本. 但是, 如果控件含有 AltSubmit 属性, 则输出变量将接收到项目的位置编号 (首个项目为 1, 第二个为 2, 等等.). 在这两种情况中, 如果没有选择的项目, 则输出变量将被设置为 ComboBox 编辑区域的内容.

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户选择新项目时 MySubroutine 标签会自动运行.

ListBox

描述: 一个包含选择列表的较高的框. 此时，最后一个参数是管道分隔的选择列表，例如 Choice1|Choice2|Choice3。例如：

Gui, Add, ListBox, vColorChoice, Red|Green|Blue|Black|White

要在窗口初次出现时预选其中的某个或某些项目, 请在这些项目中的每个后面包含两个管道符 (如果要预选多个项目, 则需要 Multi 选项). 或者, 在 选项 中包含单词 Choose 紧接着预选的单个项目编号. 例如，Choose5 会预选第五项。要在控件创建后改变选择或添加/移除列表中的条目，请使用 GuiControl。

当使用Gui Submit命令后，控件的关联输出变量（如果有）会接收到当前选择项目的文本. 但是, 如果控件含有 AltSubmit 属性, 则输出变量将接收到项目的位置编号 (首个项目为 1, 第二个为 2, 等等).

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户选择新项目时 MySubroutine 标签会自动运行. 如果用户双击一个项目, 则内置变量 A_GuiEvent 会包含字符串 DoubleClick 而不是 Normal. 此外, 变量 A_EventInfo 将包含被双击项目的位置 (首个项目为 1, 第二个为 2, 等等).

当添加大量项目到 ListBox 时，在操作前使用 GuiControl, -Redraw, MyListBox 并且在操作后使用 GuiControl, +Redraw, MyListBox 也许会提高性能。

ListBox 选项

Choose: 请参阅 上面.

Multi: 允许使用 shift-click 和 control-click 同时选择多个项目 (如果不希望使用 shift/control-click, 请指定 数字 8 代替单词 Multi). 此时, Gui Submit 会保存管道分隔的项目字符串列表到控件的 输出变量. 不过, 如果存在 AltSubmit 选项, 则 Gui Submit 保存管道分隔的项目编号列表. 例如，1|2|3 表示选择了前三个项目。要提取每个项目，请使用解析循环，例如：

Loop, parse, MyListBox, |
{
    MsgBox Selection number %A_Index% is %A_LoopField%.
}

字段间的分隔符可以改变为管道符 (|) 外的其他字符. 例如 Gui +Delimiter`n 将改变分隔符为换行符而 Gui +DelimiterTab 将改变为 tab（`t）。

ReadOnly: 对选择的项目不进行高亮显示 (但 Gui Submit 仍会保存选择的项目).

Sort: 按字母顺序自动排列列表的内容 (这也会影响后面通过 GuiControl 添加的所有项目). Sort 选项还会启用增量搜索; 这使得可以通过输入一个项目名称的前几个字符来选择此项.

Tn: 字母 T 可以用来设置制表位, 它可以把文本格式成列. 如果没有使用字母 T, 则每 32 个对话框单位设置一次制表位 (每个对话框单位的宽度由操作系统决定). 如果仅使用一次字母 T, 则每 n 个单位设置一次横跨整个控件宽度的制表位. 例如，Gui, Add, ListBox, vMyListBox t64 将设置制表位之间的距离为默认的两倍。要自定义制表位，请指定字母 T 多次，例如：Gui, Add, ListBox, vMyListBox t8 t16 t32 t64 t128。在列表中每个绝对的列位置设置一个制表位, 制表位数目最大可达 50 个.

0x100: 在选项中包含 0x100 来打开 LBS_NOINTEGRALHEIGHT 样式. 此选项强制 ListBox 准确符合指定的高度而不是适应于避免在底部的行只显示一部分的高度. 此选项也避免了其字体改变时 ListBox 缩小的情况.

要指定文本的行数 (或高度和宽度), 请参阅 控件的位置和大小.

ListView 和 TreeView

请参阅单独的页面 ListView 和 TreeView.

Link [v1.1.06+]

描述: 一个包含可点击链接的文本控件. 链接控件使用类似 HTML 的标记语法, 但只支持 <A> 标签. 在开标签内, 可以以 Attribute="value" 指定属性. 这一般是 ID 或 HREF 属性, 例如:

Gui, Add, Link,, This is a <a href="http://ahkscript.org">link</a>
Gui, Add, Link,, Links may be used anywhere in the text like <a id="1">this</a> or <a id="2">that</a>

在设置了 HREF 属性的链接上点击时会被自动处理并执行 (像 URL 或命令). 如果HREF属性未设置或无法执行，则会运行类似gMySubroutine这样的g 标签（如果提供了）。然后 ErrorLevel 变量会包含属性值, 这样就可以对点击过的链接进行标识.

Hotkey

描述: 一个看起来像单行编辑控件的框, 但它接受用户按下的按键组合. 例如, 在英语键盘布局的系统中如果用户按下 Control+Alt+C, 那么此框中将显示 "Ctrl + Alt + C".

Gui, Add, Hotkey, vChosenHotkey

使用Gui Submit命令后，控件的关联输出变量（如果有）会接收到热键修饰符和按键名称，它们与Hotkey命令中的按键名称是一致的。例如：^!C，+!Home，+^Down，^Numpad1，!NumpadEnd。如果控件中没有热键, 则输出变量被置空. 注: 一些按键即使它们作为不同的名称获取也显示为相同的名称. 例如，^Numpad7 和 ^NumpadHome 都可能显示为 Ctrl + Num 7。

默认情况下, 控件在初始时不含有热键. 要让控件含有默认的热键，请在最后一个参数中指定热键修饰符和按键名称，例如：Gui, Add, Hotkey, vChosenHotkey, ^!p
支持的修饰符仅包含 ^ (Control), !(Alt) 和 + (Shift). 请参阅 按键列表 了解可用的按键名称.

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户改变热键时 MySubroutine 标签会自动运行. 每次运行g标签还会保存热键到控件的关联输出变量（如果有）。注: 即使控件中存在不完整的热键时 g 标签也会运行. 例如, 如果用户按住 Control 键, 则 g 标签会运行一次, 此时输出变量仅包含抑扬符 (^). 当用户按完热键后, g 标签会再次运行, 此时输出变量包含完整的热键.

要限制用户可以使用的热键类型, 请在选项中包含单词 Limit 接着一个或多个下列数字的和:

1: 阻止不含修饰符的键
2: 阻止修饰符仅含 Shift 的键
4: 阻止修饰符仅含 Control 的键
8：阻止修饰符仅含 Alt 的键
16: 阻止修饰符含 Shift-Control 的键
32: 阻止修饰符含 Shift-Alt 的键
64: 不支持这个值 (它不会正确执行).
128: 阻止修饰符含 Shift-Control-Alt 的键.

例如，Limit1 将阻止输入不含修饰符的热键（例如字母和数字），而 Limit15 则要求至少有两个修饰键。如果用户输入了被禁止的修饰键组合, 则自动使用 Control+Alt 组合代替.

Hotkey 控件对热键的支持有限. 例如, 它不支持鼠标/游戏杆热键或 Windows 键 (LWin 和 RWin). 解决此问题的一种方法是提供一个或多个 checkbox 作为用户启用额外的修饰键 (例如 Windows 键) 的工具.

DateTime

描述: 一个看起来像单行编辑控件的框, 不过它接受日期和/或时间. 同时提供下拉日历. 例如：

Gui, Add, DateTime, vMyDateTime, LongDate

最后一个参数可以为下列的其中一个:

(省略): 省略时, 使用区域设置的短日期格式. 例如, 在某些区域设置中它看起来像这样: 6/1/2005

LongDate: 使用区域设置的长日期格式. 例如, in 在某些区域设置中它看起来像这样: Wednesday, June 01, 2005

Time: 仅显示时间, 使用区域设置的时间格式. 尽管不显示日期, 但它仍然存在于控件中并且与 YYYYMMDDHH24MISS 格式的时间一起被获取.

(自定义格式): 指定 日期和时间格式 的任意组合. 例如，M/d/yy HH:mm 格式显示的时间看起来像 6/1/05 21:37。同样，dddd MMMM d, yyyy hh:mm:ss tt 格式显示的时间看起来像 Wednesday June 1, 2005 09:37:45 PM。想要原义显示的字母和数字应该括在一对单引号中，例如：'Date:' MM/dd/yy 'Time:' hh:mm:ss tt。与之相比, 非字母数字字符 (例如空格, tab, 斜杠, 冒号, 逗号和其他标点) 不需要包围在单引号中. 例外情况是单引号字符本身: 要产生原义的单引号, 请使用四个连续的单引号 (''''), 不过如果它们已经包含在一对外部引号中则仅使用连续的两个就行了.

DateTime 用法

要预选今天外的其他日期, 请在 选项 中包含单词 Choose 紧跟着 YYYYMMDD 格式的日期. 例如，Choose20050531 将预选 May 31, 2005（和其他选项一样，它还可以为变量，例如 Choose%Var%）。要不预选日期/时间，请指定 ChooseNone。ChooseNone 还会在控件中创建一个复选框，只有控件中不含日期则此复选框为未选中状态。当控件中没有选择日期时，Gui Submit 和 GuiControlGet 会获取到空值（空字符串）。

日期的时间部分是可选的. 但是, 当进入或离开控件时, 时间部分必须总是在日期之前. 时间部分的格式为 HH24MISS (小时数, 分钟数, 秒数), 其中 HH24 含义是用 24 小时格式表示; 例如, 09 为 9am 而 21 为 9pm. 因此, 完整的日期时间字符串的格式应为 YYYYMMDDHH24MISS.

当指定了 YYYYMMDDHH24MISS 格式的日期时, 只有前导部分是不能缺少的. 其他任何省略的元素将使用下列默认值代替:
MM: 月份 01
DD: 日期 01
HH24: 小时 00
MI: 分钟 00
SS: 秒 00

在下拉日历中, 可以点击底部的今日字符串来选择今天的日期. 此外, 还可以点击年份和月份名称来方便地导航到新的月份或年份.

键盘导航: 使用上/下方向键, NumpadPlus/Minus, 和 Home/End 来增加或减少控件的值. 使用左右方向键在控件中的区域间移动. 在下拉日历中, 使用方向键在日期间移动; 使用 PageUp/Down 在月份间往后/往前移动; 使用 Ctrl-PageUp/Down 在年份间移动; 使用 Home/End 选择当月的第一天/最后一天.

使用Gui Submit命令后，控件的关联输出变量（如果有）会接收到所选择的YYYYMMDDHH24MISS格式表示的日期和时间。日期和时间都存在, 不论它们在控件中实际是否可见.

如果控件含有 g 标签, 则当用户改变日期或时间时此标签会运行. 每次运行时，控件的关联输出变量（如果有）会自动更新为当前选择的日期/时间。

DateTime 选项

Choose: 请参阅 上面.

Range: 限制可以选择的日期范围. 在单词 Range 后指定以 YYYYMMDD 格式表示的最小和最大的日期 (它们之间使用破折号连接). 例如，Range20050101-20050615 将限制可选择的日期为 5.5 年的前 5 个半月。最小或最大的日期可以省略, 此时控件中在这个方向上的日期不受限制. 例如，Range20010101 将禁止选择早于 2001 年的日期而 Range-20091231（有前导的破折号）将禁止选择迟于 2009 年的日期。如果不含 Range 选项, 则可以选择介于 1601 和 9999 年份之间的任何日期. 无法限制日期的时间部分.

Right: 让下拉日历在控件的右边而不是左边拉下.

1：在选项中指定数字1会在此控件的右边提供一个增减控件来修改日期和时间的值，这会取代其他地方可用的下拉月历的修改按钮。这不能和上面所述的LongDate格式选项联用。

2: 在 选项 中指定数字 2 在控件中提供复选框, 用户可以取消此复选框选择来表示没有选择日期/时间. 控件创建后无法改变此选项.

MonthCal

描述: 一个又高又宽的控件, 其中以日历的格式显示一个月中的所有日子. 用户可以选择单个日期或日期范围. 例如：

Gui, Add, MonthCal, vMyCalendar

要预选今天外的其他日期，请在最后一个参数中指定 YYYYMMDD 格式的日期（例如 20050531）。通过在两个日期间包含破折号可以预选一个日期范围（例如 20050525-20050531）。

通常最好忽略 MonthCal 的宽度 (W) 和高度 (H), 这样它会自动调整大小来准确适应一个月份. 要垂直地显示多个月份，请选项中指定 R2 或更高。要水平地显示多个月份，请指定 W-2（W 负 2）或更高。这两个选项可以同时出现, 此时会在两个方向上扩展.

可以点击控件底部的今日字符串来选择今天的日期. 此外, 还可以点击年份和月份名称来方便地选择新的月份或年份.

与 DateTime 的下拉日历不同, 在 MonthCal 中一般不支持键盘导航.

使用Gui Submit命令后，控件的关联输出变量（如果有）会接收到所选择的YYYYMMDD格式表示的日期（不带任何时间部分）。但是，存在多选选项时，会得到以破折号连接的最小和最大日期（例如 20050101-20050108）。在可以多选的日历中如果仅选择单个日期, 则最小和最大日期都会存在但它们是相同的. 可以使用 StringSplit 把两个日期分离开来。例如，后面的命令将把最小日期保存在 Date1 而最大日期保存在 Date2：StringSplit, Date, MyMonthCal, -。

如果MonthCal含有g 标签，则它每次运行时会更新控件的关联输出变量（如果有）为当前选择的日期或范围。默认情况下, 仅当出现下列情况时这个标签才会运行: 1) 用户改变了选择对象; 或 2) 每隔两分钟, 以防新的一天到来 (此行为是操作系统的怪癖). 但是, 如果控件的 选项 中包含单词 AltSubmit, 则 g 标签 会运行地更频繁, 而内置变量 A_GuiEvent 在改变日期时包含单词 Normal, 点击一个日期时包含数字 1, 而当 MonthCal 释放 "鼠标捕获" 时包含数字 2. 例如, 如果用户双击一个新日期, 则标签会运行五次: 其中一次为 Normal, 两次为 1, 还有两次为 2. 通过 计算两次数字 1 实例之间的时间间隔 可以检测双击.

指定 YYYYMMDD 格式的日期时, MM 和/或 DD 部分可以省略, 此时它们默认为 1. 例如，200205 被视为 20020501，而 2005 被视为 20050101。

MonthCal 选项

Multi: 多选. 允许用户使用 shift-click 或 click-drag 来选择一个连续的日期范围 (此时用户仍然可以选择单个日期). 可以明确指定此选项或在创建控件时通过指定一个选择范围的方法来让此选项自动生效. 例如：Gui, Add, MonthCal, vMyCal, 20050101-20050108。控件创建后无法改变此选项.

Range: 限制日历中可以选择的时间范围. 在单词 Range 后指定以 YYYYMMDD 格式表示的最小和最大的日期 (它们之间使用破折号连接). 例如，Range20050101-20050615 将限制选区为 2005 年的前 5 个半月。最小或最大的日期可以省略, 此时日历中在这个方向上的日期不受限制. 例如，Range20010101 将禁止选择早于 2001 年的日期而 Range-20091231（有前导的破折号）将禁止选择迟于 2009 年的日期。如果不含 Range 选项, 则可以选择介于 1601 和 9999 年份之间的任何日期.

4: 在 选项 中指定数字 4 来在每行日期的左边显示周数 (1-52). Week 1 被定义为至少包含四天的第一周.

8: 在 选项 中指定数字 8 来禁止控件中当前日期往复循环.

16: 在 选项 中指定数字 16 来禁止在控件的底部显示今天的日期.

Slider

描述: 一个滑动栏, 用户可以让它沿着垂直或水平轨道移动. 滑动栏的一个常见的例子是在任务栏托盘中的标准音量控件. 例如：

Gui, Add, Slider, vMySlider, 50

请在最后一个参数中指定滑动栏的初始位置. 如果最后一个参数省略, 则滑动栏初始位置为 0 或允许的范围中最接近 0 的数字.

用户可以通过下列方法滑动控件: 1) 使用鼠标拖拉滑动栏; 2) 用鼠标在滑动栏的轨道区域点击; 3) 当焦点在控件上时转动鼠标滚轮; 或 4) 当焦点在控件上时使用下列键: 方向键, 向上翻页键, 向下翻页键, Home 和 End.

使用Gui Submit命令后，控件的关联输出变量（如果有）会接收到滑动栏当前的数字位置。每当控件的 g 标签 运行时也会将此位置保存到输出变量中.

如果滑动栏含有 g 标签, 默认情况下仅当用户停止移动滑块时它才运行 (例如在拖拉滑块后释放了鼠标按钮). 但是, 如果控件的 选项 中包含单词 AltSubmit, 则所有滑动栏事件发生时 g 标签都会运行, 同时内置变量 A_GuiEvent 将包含下列数字或字符串的其中一个:

0: 用户按下了左方向键或上方向键.
1: 用户按下了右方向键或下方向键.
2: 用户按下了向上翻页键.
3: 用户按下了向下翻页键.
4: 用户用鼠标滚轮移动了滑块或已经把滑块拖放到新的位置.
5: 用户正用鼠标拖动滑块, 即鼠标按钮当前是按住的.
6: 用户按下了 Home 键来移动滑块到左端或顶部.
7: 用户按下了 End 键来移动滑块到右端或底部.
Normal: 用户已经使用鼠标或键盘移动了滑块. 注: 鼠标滚轮 (#4) 的例外情况是, 即使对于上面的数字事件其中一个 g 标签 已经运行了一次, 对于 "normal" 事件它还会再次运行.

Slider 选项

Buddy1 和 Buddy2: 最多可以指定两个现有的控件来自动定位到滑动条的两侧. Buddy1 显示在左边或顶部 (取决于是否存在 Vertical 选项). Buddy2 显示在右侧或底部. 在单词 Buddy1 或 Buddy2 后指定现有控件的 变量名. 例如, Buddy1MyTopText 将分配变量名为 MyTopText 的控件.

Center: 滑块 (用户移动的滑动栏) 两端将是钝的而不指向其中一端.

Invert: 反转控件, 把较低值作为右边/底端而不是左边/顶端. 此选项常用来让垂直滑动栏在传统的音量控件方向上移动. 注: 下面描述的工具提示选项不会遵循反转, 因此此时不应该使用.

Left: 滑块 (用户移动的滑动栏) 将指向上方而不是下方 (原文中为顶端和底端, 这里用上/下放是为了避免和滑动栏的顶端/底端混淆). 但如果存在 Vertical 选项, 则滑块将指向左边而不是右边.

Line: 指定当用户按下其中一个方向键时要移动位置的数目. 在单词 Line 后指定移动位置的数目. 例如：Line2。

NoTicks: 不在轨道旁边显示刻度标记.

Page: 指定当用户按下向上或向下翻页键时移动位置的数目. 在单词 Page 后指定移动位置的数目. 例如：Page10。

Range: 使用 0 到 100 外的其他范围. 在单词 Range 后指定最小值, 破折号和最大值. 例如，Range1-1000 将允许选择一个介于 1 和 1000 之间的数字；Range-50-50 将允许介于 -50 和 50 之间的数字；而 Range-10--10 将允许介于 -10 和 -5 之间的数字。

Thick: 指定滑块的长度. 在单词 Thick 后指定以像素为单位的厚度（例如 Thick30）。在 Windows XP 或更高版本中，要超过一定的厚度可能需要指定 Center 选项或移除控件的主题（通过在控件的选项中指定 -Theme 来实现）。

TickInterval: 在轨道旁边指定间隔的位置显示刻度标记. 在单词 TickInterval 后指定间隔来显示附加的刻度标记 (如果省略间隔, 则使用默认值 1). 例如，TickInterval10 将每隔 10 位置显示一个刻度标记。

ToolTip: 创建工具提示, 当用户拖动滑动栏时显示它的数字位置. 要让工具提示不显示在默认位置，请指定下列单词的其中一个代替：ToolTipLeft 或 ToolTipRight（对于水平滑动条）；ToolTipTop 或 ToolTipBottom（对于垂直滚动条）。

Vertical: 让控件上下滑动而不是左右滑动.

在控件创建后可以使用 GuiControl 改变上面的选项.

Progress

描述: 一个双彩条, 通常用来指示一个操作接近完成的程度. 例如：

Gui, Add, Progress, w300 h20 cBlue vMyProgress

在最后一个参数中指定进度条的初始位置 (如果省略, 则进度条的初始位置为 0 或允许的范围中最接近 0 的数字). 之后要改变进度条的位置，请参照下面的例子，它们都是操作关联变量名为 MyProgress 的进度条：

GuiControl,, MyProgress, +20  ; 增加 20 到当前位置.
GuiControl,, MyProgress, 50  ; 设置当前位置为 50.

对于水平进度条, 进度条的厚度等于控件的高度. 对于垂直进度条它等于控件的宽度.

Progress 选项

Cn: 改变进度条的颜色. 指定 n 为 16 种 HTML 基础颜色 之一或 6 位的 RGB 颜色值. 例如：cRed，cFFFF33，cDefault。如果从没有使用过 C 选项（或指定 cDefault，则使用系统默认的进度条颜色。

BackgroundN: 改变进度条的背景颜色. 指定 n 为 16 种 HTML 基础颜色 之一或 6 位的 RGB 颜色值. 例如：BackgroundGreen，BackgroundFFFF33，BackgroundDefault。如果从没有使用过 Background 选项（或指定 BackgroundDefault），则使用窗口的或进度条后选项卡控件的颜色作为背景颜色。

Range: 使用 0 到 100 外的其他范围. 在单词 Range 后指定最小值, 破折号和最大值. 例如，Range0-1000 将允许一个介于 0 和 1000 之间的数字；Range-50-50 将允许介于 -50 和 50 之间的数字；而 Range-10--5 将允许介于 -10 和 -5 之间的数字。

-Smooth (负 Smooth): 显示一段段的长度而不是一个平滑连续的进度条. 指定 -Smooth 也是在 Windows XP 或更高版本中显示含主题的进度条的其中一个要求。其他的要求是没有使用自定义的颜色, 即同时省略了 C 和 Background 选项.

Vertical: 让进度条垂直上升或下降而不是水平移动.

在控件创建后可以使用 GuiControl 改变上面的选项.

GroupBox

描述: 一个矩形的框, 常用来封装一组相关的控件. 此时最后一个参数为组合框的标题, 其 (如果存在) 显示在组合框的左上角. 例如：

Gui, Add, GroupBox, w400 h300, Geographic Criteria

默认情况下, 组合框的标题可以只有一行文本. 在选项中指定 Wrap 可以改变此特性。

要指定控件中的行数 (或高度和宽度), 请参阅 控件的位置和大小.

Tab2

描述: 一个大的包含多个页面的控件, 其中的每个包含其他控件. 从此以后, 这些页面被称为 "选项卡".

Tab2 与 Tab 的异同: v1.0.47.05 添加了 "Tab2" 控件, 其中修复了原 "Tab" 控件中很少出现的重绘问题 (例如通过点击 GUI 窗口中控件的某个部分 (如滚动条) 来激活窗口时, 可能无法正确重绘). 为了向后兼容而保留了原 Tab 控件, 因为 Tab2 在 tab 键导航顺序中把它的选项卡控件放在它所包含的控件之后. 新脚本应尽可能使用 Tab2. 例如：

Gui, Add, Tab2,, General|View|Appearance|Settings

上述的最后一个参数是管道分隔的选项卡名称列表. 要在窗口初次出现时预选其中的某个选项卡，请在它后面包含两个管道符（例如 Red|Green||Blue）。或者，在选项中包含单词 Choose 紧跟着想预选的编号。例如，Choose5 会预选第五个选项卡（和其他选项一样，它也可以为变量，例如 Choose%Var%）。要在控件创建后改变选择的选项卡，请使用 GuiControl。

创建选项卡控件后, 随后添加的控件自动属于其首个选项卡. 这可以在任何时候改变, 请参照这些例子:

Gui, Tab  ; 随后的控件不属于任何选项卡控件的一部分.
Gui, Tab, 3  ; 随后的控件属于当前选项卡控件的第三个选项卡.
Gui, Tab, 3, 2  ; 随后的控件属于第二个选项卡控件的第三个选项卡.
Gui, Tab, Name  ; 随后的控件属于名称以 Name (不区分大小写) 开始的选项卡.
Gui, Tab, Name,, Exact  ; 与上面相同, 不过这里需要准确匹配 (也区分大小写).

还可以使用上面的每个例子分配控件到还不存在的选项卡或选项卡控件 (不包括使用 Name 方法的情况). 但在此情况下, 不支持下面描述的相对位置选项.

Positioning：当一个选项卡控件的每个选项卡接收到其首个子控件，此子控件在下列情况下将具有特殊的默认位置：1) 同时省略 X 和 Y 坐标，此时首个子控件放在选项卡控件内部的左上角（带有标准的边距），而首个子控件后的其他子控件放在之前控件的下面；2) 指定了 X+n 和/或 Y+n 位置选项，此时子控件放在相对于选项卡控件内部的左上角的位置。例如，指定 x+10 y+10 会把控件放置在左上角往右和往下各 10 个像素的位置。

子控件不一定要在它们的选项卡控件边界的内部: 每当选择或取消选择它们的选项卡时仍会隐藏和显示它们. 此行为特别适合于下面描述的 "buttons" 样式.

使用Gui Submit命令后，控件的关联输出变量（如果有）会接收到当前选择的选项卡名称。但是, 如果控件含有 AltSubmit 属性, 则输出变量将接收到选项卡位置的编号 (首个选项卡为 1, 第二个为 2, 等等).

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户切换到新选项卡时 MySubroutine 标签会自动运行. 如果选项卡控件同时含有 g 标签 和 输出变量, 则每当用户切换到新选项卡时, 输出变量将被设置为原来选择的选项卡名称 (在含有 AltSubmit 时则为编号).

键盘导航: 用户可以按下 Control-PageDown/PageUp 来在选项卡控件的页面间导航; 如果键盘焦点在不属于选项卡控件的控件上, 则会导航到窗口的首个选项卡控件. 也可以使用 Control-Tab 和 Control-Shift-Tab, 除非当前焦点控件在多行编辑控件中 (此时它们不起作用).

每个窗口不能含有超过 255 个选项卡控件. 每个选项卡控件不能含有超过 256 个选项卡 (页面). 此外, 一个选项卡控件不能包含其他的选项卡控件.

Tab 选项

Choose: 请参阅 上面.

-Background (负号跟着单词 background): 取消 窗口的自定义背景颜色 而使用系统默认的选项卡控件的颜色. 指定 +Theme -Background 来让选项卡控件适应于当前桌面主题。然而, 在这样选项卡控件内的大多数类型的控件看起来会很奇怪, 因为它们的背景颜色不匹配选项卡控件的背景颜色. 对于某些类型的控件 (例如 Text), 这种情况可以在它们的选项中添加 BackgroundTrans 来修复.

Buttons: 在控件的顶部创建一系列按钮而不是选项卡 (此时在默认情况下将没有边界, 因为显示的区域实际并不包含控件).

Left/Right/Bottom: 指定这些单词的其中一个让选项卡显示在左边, 右边或底部而不是顶部. 请参阅 TCS_VERTICAL 了解对于 Left 和 Right 的限制.

-Wrap: 阻止选项卡占用多行 (此时为了适应过多的选项卡, 会显示箭头按钮以允许用户滑动来查看更多选项卡).

要指定控件中文本的行数 (或高度和宽度), 请参阅 控件的位置和大小.

在选项卡中添加图标: 通过 SendMessage 可以在每个选项卡的名称/文本旁边显示图标. 演示的例子请参阅论坛主题 Icons in tabs.

StatusBar[v1.0.44+]

描述: 附加到窗口底部的一行文本和/或图标, 通常用来报告状态的变化. 例如：

Gui, Add, StatusBar,, Bar's starting text (omit to start off empty).
SB_SetText("There are " . RowCount . " rows selected.")

状态栏最简单的用法是每当应该报告给用户一些状态改变时调用 SB_SetText(). 要报告多片的信息, 请使用 SB_SetParts() 把状态栏分成多段. 要在状态栏中显示图标, 请使用 SB_SetIcon().

下列所有的状态栏函数操作于当前线程的默认 GUI 窗口（这可以使用 Gui, 2:Default 进行改变）。如果默认窗口不存在或不含有状态栏, 则所有 SB 函数会返回 0 来表明此问题.

SB_SetText(NewText [, PartNumber, Style])

在状态栏指定部分显示 NewText。如果省略 PartNumber，则使用默认值 1。否则, 请指定介于 1 和 256 之间的整数. 如果省略 Style，则使用默认值 0，此时使用让状态栏那部分看起来凹陷的传统边界。否则, 指定 1 则不含边界, 而 2 则含有让状态栏看起来是高出的边界. 最后，在 NewText 中任意地方可以使用最多两个 tab 字符（`t）：在首个 tab 字符右边的任何内容显示在此部分中心，而在第二个 tab 右边的内容显示为右对齐。成功时 SB_SetText() 返回 1 而失败时为 0.

SB_SetParts([Width1, Width2, ... Width255])

根据指定的宽度（单位为像素）把状态栏分成多个部分。如果省略所有参数, 则状态栏恢复为单个很长的唯一一个部分. 否则, 指定除了最后一部分外的其他每个部分的宽度 (最后一部分将填充状态栏的剩余宽度). 例如，SB_SetParts(50, 50) 将创建三个部分：前两个部分的宽度都为 50，而最后一部分占据剩余的所有宽度。注: SB_SetParts() "删除" 的任何部分下次显示时初始不含文本 (而且会自动销毁其中的图标). 成功时，SB_SetParts() 返回非零值（状态栏的 HWND）。失败时返回 0.

SB_SetIcon(Filename [, IconNumber, PartNumber])

在指定部分的文本左边显示一个小图标（如果省略 PartNumber，则使用默认值 1）。Filename 为图标（.ICO）、光标（.CUR）或动画光标（.ANI）文件的名称（动画光标在状态栏上实际将不会动）。图标的其他来源包含下列类型的文件: EXE, DLL, CPL, SCR 以及包含图标资源的其他类型. 要使用文件中的图标组而不是首个图标，请在 IconNumber 指定它的编号。例如，SB_SetIcon("Shell32.dll", 2) 将使用第二个图标组中的默认图标。如果 IconNumber 为负数，则假定其绝对值表示可执行文件中图标的资源 ID。SB_SetIcon() 成功时返回图标的 HICON 而失败时返回 0. HICON 是可以被大多数脚本安全忽略的系统资源, 因为状态栏所在窗口销毁时它会被自动销毁. 同样, 当 SB_SetIcon() 用新图标替换旧图标时会销毁旧图标. 这种情况可以使用以下方法避免:

Gui +LastFound
SendMessage, 0x40F, part_number - 1, my_hIcon, msctls_statusbar321  ; 0x40F 为 SB_SETICON.

SB_SetProgress()

创建和控制状态栏中的进度条。此函数可以从 www.autohotkey.com/forum/topic37754.html 获取

G 标签通知

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户点击状态栏时 MySubroutine 标签会自动运行。此子程序中可引用内置变量 A_Gui 和 A_GuiControl。更重要的是，它可以参考 A_GuiEvent，其包含下列字符串的其中一个（考虑到和未来版本的兼容性，脚本不应假定这些字符串是唯一可能的值）：

  • Normal: 用户左键单击了状态栏. 变量 A_EventInfo 包含目标部分的编号 (然而, 如果用户点击状态栏右边靠近大小调整手柄的地方时, 目标部分的编号可能是很大的整数).
  • RightClick: 用户右键单击了状态栏. 变量 A_EventInfo 包含目标部分的编号. 注: 如果状态栏含有 g 标签将不会调用 GuiContextMenu. 此外, 当脚本需要知道用户点击的是哪个部分的编号 (A_EventInfo) 时, 应该使用 g 标签的 RightClick 事件代替 GuiContextMenu.
  • DoubleClick: 用户双击了状态栏. 变量 A_EventInfo 包含目标部分的编号.
  • R: 用户 右键双击 了状态栏. 变量 A_EventInfo 包含目标部分的编号.

字体和颜色

尽管字体大小、外观和样式可以使用 Gui Font 设置（像普通控件一样），但是无法改变文本颜色。而且，不遵循 Gui Color 的颜色设置；代替的方法是，状态栏的背景颜色可以通过在选项中指定单词 Background 紧跟着颜色名称（请参阅颜色图表）或 RGB 值（0x 前缀可以省略）来改变。例如：BackgroundSilver，BackgroundFFDD99，BackgroundDefault。

隐藏状态栏

创建时，可以使用 Gui, Add, StatusBar, Hidden vMyStatusBar 隐藏状态栏。要在创建后某个时候隐藏它，请使用 GuiControl, Hide, MyStatusBar。要显示，请使用 GuiControl, Show, MyStatusBar。注: 隐藏状态栏不会降低窗口的高度. 如果希望这样，一个简便的方法是 Gui, Show, AutoSize。

样式（很少使用）

请参阅状态栏样式表。

已知限制

1) 如果某个控件的位置和状态栏重叠，那么它有可能会被绘制在状态栏的上方。避免这种情况的一种方法是通过 GuiSize 标签动态地缩小这样的控件。2) 每个窗口只允许有一个状态栏控件.

示例

TreeView 页面底部演示了一个多部分的状态栏。

ActiveX [v1.1.03+]

ActiveX 组件 (例如 MSIE 浏览器控件) 可以嵌入到 GUI 窗口, 请参照此例:

Gui Add, ActiveX, w980 h640 vWB, Shell.Explorer  ; 最后一个参数是ActiveX组件的名称。
WB.Navigate("http://ahkscript.org/boards/")  ; 该句只适用于web浏览器控件。
Gui Show

创建控件时，ActiveX对象被储存到控件的关联变量中（如果有）。可以使用 GuiControlGet 来获取此对象.

要处理由对象公开的事件, 请使用 ComObjConnect, 如下所示:

Gui Add, Edit, w930 r1 vURL, http://ahkscript.org/boards/
Gui Add, Button, x+6 yp w44 Default, Go
Gui Add, ActiveX, xm w980 h640 vWB, Shell.Explorer
ComObjConnect(WB, WB_events)  ; 连接WB事件到WB_events类对象。
Gui Show
; 继续加载初始页面：
ButtonGo:
Gui Submit, NoHide
WB.Navigate(URL)
return

class WB_events
{
    NavigateComplete2(wb, NewURL)
    {
        GuiControl,, URL, %NewURL%  ; 更新 URL 编辑控件.
    }
}

GuiClose:
ExitApp

ComObjType 可以用来判断保存在控件变量中的对象类型.

定制[v1.1.10+]

AutoHotkey 不直接支持的控件还可以嵌入到 GUI 窗口。要实现这样的操作，需要在 Gui, Add的 Class 选项中指定 Win32 类名。示例:

Gui, Add, Custom, ClassComboBoxEx32  ; 添加 ComboBoxEx 控件。
Gui, Add, Custom, ClassScintilla  ; 添加 Scintilla 控件。注意必须加载 SciLexer.dll 库后才能添加此控件。

AutoHotkey 通过 Gui, Add 或 GuiControl/Get 使用标准的 Windows 操作方法来获取或替换控件中的文本。

G 标签通告：类似 gMySubroutine 这样的 g 标签 可以使用在控件的选项中，这样可以捕获控件中的事件。此子程序中可引用内置变量 A_Gui 和 A_GuiControl。更重要的是，它可以参考 A_GuiEvent，其包含下列字符串的其中一个（考虑到和未来版本的兼容性，脚本不应假定这些字符串是唯一可能的值）：

  • Normal：接收到 WM_COMMAND 消息。A_EventInfo 包含了控件定义的通告码（相当于 C/C++ 中的 HIWORD(wParam)）。
  • N：接收到 WM_NOTIFY 消息。A_EventInfo 包含了到控件通告结构体（NMHDR）的指针。把它赋值给 ErrorLevel 则可以向控件返回一个 32 位的有符号整型值（默认会把 g 标签线程的 ErrorLevel 设为零）。无效的值被视为零。

下面这个例子演示了如何添加 IP 地址控件：

Gui, Add, Custom, ClassSysIPAddress32 r1 w150 hwndhIPControl gIPControlEvent
Gui, Add, Button, Default, OK
IPCtrlSetAddress(hIPControl, A_IPAddress1)
Gui, Show
return

GuiClose:
ExitApp

ButtonOK:
Gui, Hide
ToolTip
MsgBox % "You chose " IPCtrlGetAddress(hIPControl)
ExitApp

IPControlEvent:
if A_GuiEvent = Normal
{
    ; 接收到 WM_COMMAND。

    if (A_EventInfo = 0x0300)  ; EN_CHANGE
        ToolTip Control changed!}
else if A_GuiEvent = N
{
    ; 接收到 WM_NOTIFY。    ; 获取通告码。一般情况下这个字段是 UInt 类型，但 IP 地址
    ; 控件使用负值，所以为了方便我们把它作为有符号整型读取出来。
    nmhdr_code := NumGet(A_EventInfo + 2*A_PtrSize, "int")
    if (nmhdr_code != -860)  ; IPN_FIELDCHANGED
        return

    ; 从 NMIPADDRESS 结构体中提取信息
    iField := NumGet(A_EventInfo + 2*A_PtrSize + 4, "int")
    iValue := NumGet(A_EventInfo + 2*A_PtrSize + 8, "int")
    if iValue >= 0
        ToolTip Field #%iField% modified: %iValue%
    else
        ToolTip Field #%iField% left empty
}
return

IPCtrlSetAddress(hControl, ipaddress)
{
    static WM_USER := 0x400
    static IPM_SETADDRESS := WM_USER + 101

    ; 把 IP 地址打包成 32 位字以用于 SendMessage。
    ipaddrword := 0
    Loop, Parse, ipaddress, .
        ipaddrword := (ipaddrword * 256) + A_LoopField
    SendMessage IPM_SETADDRESS, 0, ipaddrword,, ahk_id %hControl%
}

IPCtrlGetAddress(hControl)
{
    static WM_USER := 0x400
    static IPM_GETADDRESS := WM_USER + 102

    VarSetCapacity(addrword, 4)
    SendMessage IPM_GETADDRESS, 0, &addrword,, ahk_id %hControl%
    return NumGet(addrword, 3, "UChar") "." NumGet(addrword, 2, "UChar") "." NumGet(addrword, 1, "UChar") "." NumGet(addrword, 0, "UChar")
}

相关页面

ListView, TreeView, Gui, GuiControl, GuiControlGet, Menu


GuiControl

对 GUI 窗口中的控件进行各种设置。

GuiControl, Sub-command, ControlID [, Param3]

参数

Sub-command

请参阅后面的列表.

ControlID

如果目标控件有关联变量, 则指定此变量名作为 ControlID (此方法优先于下面描述的那个). 由于这个原因, 通常最好给每个之后要使用 GuiControl 或 GuiControlGet 访问的控件分配一个变量, 即使那个控件不是可输入型 (例如 GroupBox 或 Text).

或者 ControlID 可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。注: 图片控件的文件名 (和控件创建时指定的一样) 可以作为 ControlID 使用.

[v1.1.04+]：ControlID 可以是控件的 HWND。在 ControlID 中使用其他类型的值且此控件不在默认的 Gui 上时，必须同时指定 Gui。

Param3

除了下面的子命令列表中注明的, 否则省略此参数.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果指定的窗口/控件不存在或由于其他问题使得命令无法工作, 则 ErrorLevel 被置为 1. 否则被置为 0.

子命令

(空): 留空 Sub-command 来把 Param3 作为新内容设置到控件. 具体地:

Picture: 指定 Param3 为要加载的新图像的文件名 (请参阅 Gui Picture 了解支持的文件类型). 在文件名的前面可以指定零个或多个下列选项：*wN（宽度 N）、*hN（高度 N）以及 *IconN（在 DLL 或 EXE 文件中的图标组编号 N）。在下面的例子中，将加载第二个图标组中的默认图标，设置宽度为 100 且在“保持高宽比”的情况下自动设置高度：GuiControl,, MyPic, *icon2 *w100 *h-1 C:\My Application.exe。请指定 *w0 *h0 来使用图像的实际宽度和高度。如果同时省略 *w 和 *h，则调整图像以适应控件当前的大小。从多图标的 .ICO 文件中加载时, 指定宽度和高度也决定了加载哪个图标. 注: 在最后一个选项和文件名之间只能含有一个空格或 tab; 其他任何空格或 tab 都会被视为文件名的一部分.

Text/Button/GroupBox/StatusBar: 指定 Param3 为控件的新文本. 因为控件不会自动进行扩展，所以如果需要加宽控件请使用 GuiControl, Move, MyText, W300。对于 StatusBar，这里只设置了首部分的文本（使用 SB_SetText() 会更灵活）。

Edit: Param3 中任何没有前导回车符 (`r) 的换行符 (`n) 会被自动转换成 CR+LF (`r`n) 才能正确显示. 然而，通常不需要担心，因为 Gui Submit 和 GuiControlGet OutputVar 命令会自动把 CR+LF 替换为 LF（`n）进行复原。

Hotkey: 指定 Param3 为空来清空控件, 或键名和修饰符的集合. 例如：^!c，^Numpad1，+Home。支持的修饰符仅包含 ^ (Control), !(Alt) 和 + (Shift). 请参阅 按键列表 了解可用的按键名称。

Checkbox: 指定 Param3 为 0 来取消选中按钮, 1 来选中它或 -1 来设置灰色的选中标记. 否则, Param3 被视为控件的新标题/文本. 请参阅下面的 Text 了解如何覆盖这种行为.

Radio: 与上面的 Checkbox 相同. 然而, 如果单选按钮已经被选中 (打开) 且它是多个单选按钮组成的组中的成员, 那么这个组中其他的单选按钮会自动取消选中. 要选中只含有一个变量的单选按钮组中的新按钮, 如果这个新按钮没有直接关联的变量, 则请在 ControlID 中指定它的名称/文本.

DateTime/MonthCal: 指定 Param3 为 YYYYMMDDHH24MISS 格式的时间戳. 指定 %A_Now% 来使用当前本地日期和时间（当天）。对于DateTime控件，可以省略Param3来让控件不预选日期/时间（如果它在创建时含有这个能力）。对于 MonthCal 控件，如果控件是多选的则可以指定一个日期范围。

UpDown/Slider/Progress: 指定 Param3 为控件的新位置. 如果 Param3 的首个字符是加号, 则这个数字会被认为是相对于当前位置的偏移. 例如，+10 会给当前位置加上 10 而 +-10（加减十）会减去 10。如果新位置在控件的范围之外, 则控件一般会被设置为最接近的有效值.

Tab/DropDownList/ComboBox/ListBox: 指定 Param3 为要附加到控件列表末尾的管道符分隔的条目列表. 要替换（覆盖）这个列表，请加上管道符作为首个字符（例如 |Red|Green|Blue）。要将控件内容清空, 请只指定一个管道符 (|). 要预选其中的某个条目，请在这个条目后包含两个管道符（例如 Red|Green||Blue）。字段间的分隔符可以改变为管道符外的其他字符. 例如 Gui +Delimiter`n 将改变分隔符为换行符而 Gui +DelimiterTab 将改变为 tab（`t）。

Tab 控件: 除了上面段落中描述的行为, 一个选项卡的子控件和它们原始的选项卡编号保持关联; 即它们不会和它们选项卡的实际显示名称关联. 因此, 重命名或移除一个选项卡不会改变子控件所属的选项卡编号. 例如，如果有三个选项卡“Red|Green|Blue”，使用 GuiControl,, MyTab, |Red|Blue 移除第二个选项卡，则原来和 Green 关联的子控件现在和 Blue 关联。由于这种特性, 通常只应该移除默认的选项卡. 使用这种方法移除的选项卡以后还可以添加回来, 此时它们会要回原来的控件集合.

ListView 和 TreeView: 当 Sub-command 为空时不支持它们. 作为替代, 请使用内置的 ListView 函数 和 TreeView 函数.

GuiControl, Text：除了下面的情况，其他行为和上面一样：
Checkbox/Radio: 把 Param3 作为新文本/标题, 即使它为 -1, 0 或 1.
DateTime: 把 Param3 作为新 日期/时间格式 显示到控件中. 如果省略 Param3, 则移除所有自定义格式然后使用短日期格式.
ComboBox: 把 Param3 作为文本直接放到 ComboBox 中编辑控件.

GuiControl, Move：改变控件的位置和大小。请在 Param3 中指定一个或多个下列选项字母：X（相对于 GUI 窗口工作区的 x 坐标，这是窗口中不包括标题栏、菜单栏和边框的区域）；Y（y 坐标）、W（宽度）、H（高度）。(规定每个数字为十进制, 而不是十六进制.) 例如:

GuiControl, Move, MyEdit, x10 y20 w200 h100
GuiControl, Move, MyEdit, % "x" VarX+10 "y" VarY+5 "w" VarW*2 "h" VarH*1.5 ; 通过 "% " 前缀使用 表达式.

GuiControl, MoveDraw：除了上面的“Move”功能，它还重绘控件占据的 GUI 窗口区域。尽管重复和快速调用这个功能时可能导致不想要的闪烁效果，不过它解决了某些控件类型（例如 GroupBox）的部分重绘问题。在 v1.0.48.04+, 可以省略最后一个参数来重绘控件而不进行移动.

GuiControl, Focus：设置键盘焦点到控件。要让设置生效, 窗口一般不能处于最小化或隐藏状态.

GuiControl, Enable / Disable：启用或禁用（灰化）控件。对于选项卡控件, 这样还会启用或禁用选项卡中的所有子控件. 然而，通过GuiControl Disable 禁用的任何子控件会记住此设置，因此在重新启用选项卡控件后仍然保持禁用状态。单词 Disable 或 Enable 后可以紧跟着 0 或 1. 零会产生相反的效果. 例如，Enable 和 Enable%VarContainingOne% 都会启用控件，但 Enable%VarContainingZero% 会禁用它。

GuiControl, Hide / Show：隐藏或显示控件。对于选项卡控件, 这样还会显示或隐藏选项卡中的所有子控件. 如果您还想同时禁用控件的快捷键（加下划线的字母），请使用 GuiControl Disable 来禁用控件。单词 Hide 或 Show 后可以紧跟着 0 或 1. 零会产生相反的效果. 例如，Show 和 Show%VarContainingOne% 都会显示控件，但 Show%VarContainingZero% 会隐藏它。

GuiControl, Delete（尚未实现）：这个子命令还不存在。作为变通的解决方法，请使用上面的 Hide 和/或 Disable，或使用 Gui Destroy 销毁整个窗口后重新创建。

GuiControl, Choose, ControlID, N：设置 ListBox、DropDownList、ComboBox 或 Tab 控件中的选择对象为第 N 个条目。对于首个条目 N 为 1, 对第二个则为 2, 等等. 如果 N 不是整数，则使用下面描述的 ChooseString 方法代替。[v1.1.06+]：如果 N 为零，则移除 ListBox、DropDownList 或 ComboBox 的当前选择对象。

与 Control Choose 不同, 此子命令不会触发与控件关联的任何 g 标签, 除非在 N 前面加上管道符 (即使如此, 也只有在新选择对象与旧的不同时才会触发 g 标签, 至少对 Tab 控件 是这样). 例如：GuiControl, Choose, MyListBox, |3。

要同时产生结束事件 (双击 ListBox 时), 请用两个前导的管道符而不是一样 (这不支持 Tab 控件).

要选择或取消选择 多选 ListBox 中的 所有 项目, 请参照此例:

Gui +LastFound  ; 让后面不需要指定 WinTitle.
PostMessage, 0x185, 1, -1, ListBox1  ; 选择所有项目. 0x185 is LB_SETSEL.
PostMessage, 0x185, 0, -1, ListBox1  ; 取消选择所有项目.
GuiControl, Choose, ListBox1, 0  ; 取消选择所有项目 (需要 v1.1.06+).

GuiControl, ChooseString, ControlID, String：设置 ListBox、DropDownList、ComboBox 或 Tab 控件的选择对象为开始部分匹配 String 的条目。搜索不区分大小写. 例如, 如果控件包含项目 "UNIX Text", 那么指定单词 unix (小写) 也能选中它. 还支持管道符和双管道符前缀 (请参阅上面的 "Choose" 了解详情).

GuiControl, Font：改变控件的字体为它所在窗口当前使用的字体、大小、颜色和样式。例如：

Gui, Font, s18 cRed Bold, Verdana  ; 如果需要, 使用这样的一行给窗口设置新的默认字体.
GuiControl, Font, MyEdit  ; 让上面的字体设置对控件生效.

GuiControl, +/-Option1 +/-Option2 ... ：添加或删除各种控件专用或通用选项和样式。

在下面的例子中, 启用 AltSubmit 但同时移除控件的 g 标签:

GuiControl,  +AltSubmit -g, MyListBox

在下一个例子中, 会把 OK 按钮设置为新的默认按钮:

GuiControl, +Default, OK

尽管也能识别 样式 和扩展样式, 但是其中的某些无法在控件创建后应用或移除. 如果至少成功应用一个指定的改变, 则 ErrorLevel 被置为 0. 否则, 它被设置为 1 来表示没有应用任何改变. 即使成功应用了变化, 控件也可能选择忽略它 (还是等于没有任何效果).

备注

要对非默认窗口进行操作 (请参阅下面), 需要在子命令前加上窗口名称或编号和一个冒号, 例如:

GuiControl, MyGui:Show, MyButton
GuiControl, MyGui:, MyListBox, Item1|Item2

即使 ControlID 为控件的关联变量或 HWND 这也是必须的。

GUI 线程 是由 GUI 动作启动的. GUI 动作包含从 GUI 窗口的菜单栏选择一个项目或触发其某个 g 标签 (例如按下按钮).

GUI 线程的 默认窗口名称 是运行此线程的窗口名称. 非 GUI 线程的默认窗口编号为 1.

相关

Gui, GuiControlGet, Control

示例

GuiControl,, MyListBox, |Red|Green|Blue  ; 把当前列表替换为新列表.
GuiControl,, MyEdit, New text line 1.`nNew text line 2.
GuiControl,, MyRadio2, 1  ; 选择此单选按钮并关闭同组中其他所有单选按钮.
GuiControl, Move, OK, x100 y200  ; 移动 OK 按钮到新位置.
GuiControl, Focus, LastName  ; 设置键盘焦点到变量名或文本为 "LastName" 的控件.


GuiControlGet

获取 GUI 窗口中控件的各种类型的信息。

GuiControlGet, OutputVar [, Sub-command, ControlID, Param4]

参数

OutputVar

用来存储结果的变量名. 如果此命令无法完成 (请参阅下面的 ErrorLevel), 则此变量被置空.

Sub-command

请参阅后面的列表.

ControlID

如果为空或省略, 则使用指定的输出变量名. 例如，GuiControlGet, MyEdit 等同于 GuiControlGet, MyEdit,, MyEdit。

如果目标控件有关联变量, 则指定此变量名作为 ControlID (此方法优先于下面描述的那个). 由于这个原因, 通常最好给每个之后要使用 GuiControl 或 GuiControlGet 访问的控件分配一个变量, 即使那个控件不是可输入型 (例如 GroupBox 或 Text).

或者 ControlID 可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。注: 图片控件的文件名 (和控件创建时指定的一样) 可以作为 ControlID 使用.

[v1.1.04+]：ControlID 可以是控件的 HWND。在 ControlID 中使用其他类型的值且此控件不在默认的 Gui 上时，必须同时指定 Gui。

Param4

除了下面的子命令列表中注明的, 否则省略此参数.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果指定的窗口/控件不存在或由于其他问题使得命令无法工作, 则 ErrorLevel 被置为 1. 否则被置为 0.

子命令

(空): 留空 Sub-command 来获取控件的内容. 除了下面的控件类型, 其他都是无须解释的:

Picture: 获取控件创建时最初指定的图片文件名. 即使指定了新的图片文件名, 此名称也不会改变.

Edit: 获取控件的内容, 但文本中断行的位置表示为单独的换行符 (`n) 而不是非 GUI 命令 (例如 ControlGetText 和 ControlSetText) 使用的传统 CR+LF (`r`n).

Hotkey: 如果控件中不含控件, 则获取到空值. 否则它获取到修饰符和键名. 例如：^!C，^Home，+^NumpadHome。

Checkbox/Radio: 控件被选中时获取的值为 1, 未选中时为 0, 而灰色状态时为 -1. 要获取控件的文本/标题, 请指定单词 Text 到 Param4. 注: 与 Gui Submit 不同, 单选按钮的状态总是单独获取的, 不论它们是否在单选按钮组中.

UpDown/Slider/Progress: 获取控件的当前位置.

Tab/DropDownList/ComboBox/ListBox: 获取当前选择的项目/选项卡的文本 (如果控件含有 AltSubmit 则为其位置). 对于组合框, 如果没有选择的项目, 则获取控件编辑区域的文本. 对于 多选列表框, 输出结果中使用窗口的 当前分隔符.

ListView 和 TreeView: 当 Sub-command 为空时不支持它们. 作为替代, 请使用内置的 ListView 函数 和 TreeView 函数.

StatusBar: 仅获取首个部分的文本.

ActiveX: 获取控件的 ActiveX 组件的新包装器对象.

注：要无条件获取任意控件的文本/标题而不是其内容，请在 Param4 中指定单词 Text。

GuiControlGet, OutputVar, Pos：获取控件的位置和大小。这里的位置相对于 GUI 窗口的工作区, 这是窗口中不包括标题栏, 菜单栏和边框的区域. 获取的结果保存在四个名称以 OutputVar 开始的变量中. 例如：

GuiControlGet, MyEdit, Pos
MsgBox The X coordinate is %MyEditX%. The Y coordinate is %MyEditY%. The width is %MyEditW%. The height is %MyEditH%.

在 函数 中, 要创建一组全局变量而不是局部变量, 请在此命令前 声明 OutputVar 为全局变量 (对于 假设全局 函数, 反之亦成).

GuiControlGet, OutputVar, Focus：获取当前含键盘焦点的控件的标识符（ClassNN）。由于指定的 GUI 窗口必须是 活动的, 这样其中的某个控件才会含有焦点, 所以如果窗口不是活动的则 OutputVar 被置空. 用法示例：GuiControlGet, focused_control, focus。

GuiControlGet, OutputVar, FocusV [v1.0.43.06+]: 与上面的 Focus 相同, 不过它获取的是焦点控件的 关联变量 的名称. 如果那个控件没有关联变量, 则获取控件的文本/标题中前 63 个字符 (这常用来避免给每个按钮分配变量名).

GuiControlGet, OutputVar, Enabled: 如果控件是启用的则获取的值为 1, 禁用的则为 0.

GuiControlGet, OutputVar, Visible: 如果控件是可见的则获取的值为 1, 隐藏的则为 0.

GuiControlGet, OutputVar, Hwnd [v1.0.46.16+]: 获取控件的窗口句柄 (HWND). 控件的 HWND 常用于 PostMessage, SendMessage 和 DllCall. 注: HwndOutputVar 通常是获取 HWND 的一种较简便的方法.

GuiControlGet, OutputVar, Name [v1.1.03+]: 获取控件的 关联变量名, 如果没有则 OutputVar 被置空.

备注

要对非默认窗口进行操作 (请参阅下面), 需要在子命令前加上窗口名称或编号和一个冒号, 例如:

GuiControlGet, MyEdit, MyGui:
GuiControlGet, MyEdit, MyGui:Pos
GuiControlGet, Outputvar, MyGui:Focus

即使 ControlID 为控件的关联变量或 HWND 这也是必须的。

GUI 线程 是由 GUI 动作启动的. GUI 动作包含从 GUI 窗口的菜单栏选择一个项目或触发其某个 g 标签 (例如按下按钮).

GUI 线程的 默认窗口名称 是运行此线程的窗口名称. 非 GUI 线程的默认窗口编号为 1.

相关

Gui, GuiControl, ControlGet

示例

GuiControlGet, MyEdit
GuiControlGet, CtrlContents,, MyEdit  ; 和上面相同, 不过这里使用非默认的输出变量.
GuiControlGet, MyCheckbox1 ; 如果选中的则获取的值为 1, 未选中的则为 0.
GuiControlGet, MyCheckbox1,,, Text  ; 获取复选框的标题/文本.
GuiControlGet, Pic, Pos, Static4  ; 位置/大小会保存到 PicX, PicY, PicW 和 PicH


ListView (GUI)

ListView

目录

  • 入门和简单示例
  • 选项和样式
  • 视图模式: 报告 (默认), 图标, 平铺, 小图标和列表.
  • 内置函数:
    • 行函数 (添加, 修改和删除行)
    • 列函数
    • 从 ListView 中获取数据
  • G 标签通知
  • 图像列表 (把图标添加到 ListView 的方法)
  • ListView 备注
  • 示例

入门和简单示例

List-View 是由操作系统提供的最精心设计的控件之一. 在其最容易识别的形式中, 它显示一个多行多列组成的表格视图, 最常见的例子是资源管理器的文件和文件夹列表 (详细信息视图).

尽管它可能是精细的, 但 ListView 的基本功能也易于使用. 创建 ListView 的语法为:

Gui, Add, ListView, Options, ColumnTitle1|ColumnTitle2|...

这是一个可运行脚本, 它创建和显示包含用户 "我的文档" 目录中文件列表的 ListView:

; 创建含名称和大小两列的 ListView:
Gui, Add, ListView, r20 w700 gMyListView, Name|Size (KB)

; 从文件夹中获取文件名列表并把它们放入 ListView:
Loop, %A_MyDocuments%\*.*
    LV_Add("", A_LoopFileName, A_LoopFileSizeKB)

LV_ModifyCol()  ; 根据内容自动调整每列的大小.
LV_ModifyCol(2, "Integer")  ; 为了进行排序, 指出列 2 是整数.

; 显示窗口并返回. 每当用户点击一行时脚本会发出通知.
Gui, Show
return

MyListView:
if A_GuiEvent = DoubleClick
{
    LV_GetText(RowText, A_EventInfo)  ; 从行的第一个字段中获取文本.
    ToolTip You double-clicked row number %A_EventInfo%. Text: "%RowText%"
}
return

GuiClose:  ; 表示当窗口关闭时脚本应自动退出.
ExitApp

用于 "Gui, Add, ListView, Options" 的选项和样式

AltSubmit: 通知脚本有比正常更多的 ListView 事件类型. 换句话说, g 标签会运行地更频繁. 请参阅 ListView 通知 了解详情.

Background: 指定单词 Background 后面紧跟着颜色名称 (请参阅 颜色图表) 或 RGB 值 (0x 前缀可以省略). 例如：BackgroundSilver，BackgroundFFDD99。如果此选项不存在，则 ListView 初始默认的背景颜色由 Gui Color 的最后一个参数设置（如果没有，则使用系统默认的背景颜色）。指定 BackgroundDefault 来应用系统的默认背景颜色（通常为白色）。例如，使用 GuiControl, +BackgroundDefault, MyListView 可以把 ListView 恢复为默认的颜色。

C: 文本颜色. 指定字母 C 后面紧跟着颜色名称 (请参阅 颜色图表) 或 RGB 值 (0x 前缀可以省略). 例如：cRed，cFF2211，c0xFF2211，cDefault。

Checked: 在每行的左侧提供一个复选框. 当 添加 行时, 在其选项中指定单词 Check 来让复选框初始为选中而不是未选中状态. 用户可以点击复选框或按下空格键来选中或取消选中一行.

Count: 指定单词 Count 后面跟着 ListView 最后会包含的总行数. 这不是限制: 超过此数目后仍然可以添加行. 相反, 此选项给控件一个暗示, 允许它一次性的而不是每次添加一行时分配内存, 这样极大地提高了添加行时的性能 (这也可以提高排序性能). 要提升更多的性能，请在添加大量行之前使用 GuiControl, -Redraw, MyListView。随后，使用 GuiControl, +Redraw, MyListView 来重新启用重绘（这样也重绘了控件）。

Grid: 提供水平的和垂直的线以形象地显示出行与行和列与列之间的边界.

Hdr: 指定 -Hdr（负 Hdr）来隐藏包含列标题的特殊顶行。后面要让它显示，请使用 GuiControl, +Hdr, MyListView。

LV: 指定字符串 LV 后面紧跟着 扩展 ListView 样式 的数字. 这些样式完全独立于通用扩展样式. 例如，指定 -E0x200 会移除通用扩展样式 WS_EX_CLIENTEDGE 来去除控件的默认边框。与之相比，指定 -LV0x20 会移除 LVS_EX_FULLROWSELECT。

LV0x10：指定 -LV0x10 阻止用户通过拖动列标题到左边或右边来对它们重新排序。然而, 通常没必要这么做, 因为列的实际重排不会影响脚本看到的列顺序. 例如, 从脚本的角度看第一列总是 column 1, 即使用户实际已经把它移动到其他列的右边.

LV0x20：指定 -LV0x20 来要求点击一行的第一个字段才可以进行选择（正常情况下，点击任意字段都可以选择）。这样的好处是用户可以更方便地拖动矩形包围一组行来选择它们.

Multi：指定 -Multi（负 Multi）来禁止用户一次选择多行。

NoSortHdr: 禁止点击标题. 此时会显示平坦的外观而不是正常的类似按钮的外观. 与其他大多数 ListView 样式不同, 此样式在 ListView 创建后无法改变.

NoSort: 关闭当用户点击标题时发生的自动排序. 然而, 标题的外观看起来仍像按钮 (除非指定了 NoSortHdr). 此外, g 标签仍会接收到 ColClick 通知, 可以用自定义排序或其他动作对它进行响应.

ReadOnly：指定 -ReadOnly（负 ReadOnly）来允许编辑每行首列的文本。要编辑某行，请在选择后按下 F2 键。或者, 您可以对一行点击一次来选择它, 至少等待半秒钟, 然后再次点击同一行进行编辑.

R: 行高 (创建时). 指定字母 R 后面紧跟着要在控件中留出空间的行数. 例如，R10 会设置控件为 10 行的高度。如果使用报告视图外的其他视图模式创建 ListView，则控件会调整大小以适应含图标的行而不是文本行。注：添加图标到 ListView 的行中会增加每行的高度，这会让此选项不准确。

Sort: 让控件根据首列的内容保持按字母顺序排列.

SortDesc: 和上面一样, 不过这里是降序排列.

WantF2 [v1.0.44+]：指定 -WantF2（负 WantF2）来禁止使用 F2 键击编辑当前焦点行。仅当 -ReadOnly 也有效时此设置才不会被忽略。不论此设置如何，g 标签仍会接收到 F2 通告。

(未命名的数值样式): 由于上述以外的其他样式很少使用, 所以没有为它们命名. 请参阅 ListView 样式表 了解这些样式.

视图模式

ListView 有五种视图模式, 其中最常见的是报告视图 (这是默认的). 要使用其他某种视图, 请在选项列表中指定它的名称. 还可以在控件创建后改变视图模式；例如：GuiControl, +IconSmall, MyListView。

Icon: 显示大图标视图. 在此视图和除 Report 外的其他所有视图中, 只有首列中的文本才可见. 要在此模式中显示图标, ListView 必须分配有含大图标的 图像列表.

Tile: 显示大图标视图, 但具有人体工学差异, 例如每项的文本显示在图标的右边而不是下面. Checkbox 不能使用于此视图中. 此外, 在比 Windows XP 早的操作系统中显示此视图没有效果.

IconSmall: 显示小图标视图.

List: 以列表格式显示小图标视图, 其中图标显示在列中. 列的数目取决于控件的宽度和控件中最宽文本项目的高度.

Report: 切换会报告视图, 这是最初的默认模式. 例如：GuiControl, +Report, MyListView。

ListView 中的内置函数

所有的 ListView 函数操作于当前线程的默认 GUI 窗口（这可以使用 Gui, 2:Default 进行改变）。如果默认窗口不存在或不含有 ListView 控件, 则所有函数返回零来表明此问题.

如果窗口含有多个 ListView 控件, 默认情况下函数操作于最近添加的那个. 要改变这种情况，请指定 Gui, ListView, ListViewName，其中 ListViewName 为 ListView 的关联变量的名称或 Window Spy 中显示的其 ClassNN（在 v1.1.04+）或其 HWND。一旦改变后, 所有现有和将来的 线程 将使用指定的 ListView.

当在此页面使用短语 "row number", 它指的是 ListView 中行的当前位置. 最上面一行为 1, 第二行为 2, 依此类推. 添加一行后, 其行号会因为排序, 删除和插入其他行而发生变化. 因此, 要根据内容查找特定的一行或多行, 通常最好在循环中使用 LV_GetText().

行函数

LV_Add([Options, Field1, Field2, ...])

添加新行到列表底部。参数 Field1 和其后的字段是新行的列内容，可以是文本或数字（包括数值的表达式结果）。要让任何字段为空, 请指定 "" 或等价物. 如果参数中太少字段而无法填满所有列, 则留空后面剩下的列. 如果太多字段, 则忽略后面多出的字段.

失败时, LV_Add() 返回 0. 成功时它返回新 行号, 如果 ListView 含有 Sort 或 SortDesc 样式则此行不一定是最后一行.

行选项

Options 参数是一个包含零个或多个下表中单词的字符串（不区分大小写）。在单词间使用空格或 tab 分隔. 要移除选项, 请在选项前加上负号. 要添加选项, 在选项前的正号可以省略.

Check: 在行中显示选中标记 (需要 ListView 含有 复选框). 以后要取消选中它，请使用 LV_Modify(RowNumber, "-Check")。

Col: 指定单词 Col 后紧跟着列号, 从此列开始往后应用参数 Col1 和其后参数的内容. 此选项通常和 LV_Modify() 一起使用来修改行中的个别字段, 不会影响它们左边的那些字段.

Focus: 设置键盘焦点到此行 (通常和 Select 一起使用). 以后要取消它的焦点，请使用 LV_Modify(RowNumber, "-Focus")。

Icon: 指定单词 Icon 后紧跟着这行图标的编号, 这行图标显示在首列的左侧. 如果此选项不存在, 则使用 图像列表 中的首个图标. 要显示空白图标, 请指定一个大于图像列表中图标数目的数字. 如果控件没有小图标的图像列表, 则 报告视图 中既不显示图标也不为其保留空间.

Select: 选择行. 以后要取消选择，请使用 LV_Modify(RowNumber, "-Select")。当选择行时，通常最好确保至少有一行总含有焦点属性，因为这样允许Appskey在焦点行附近显示其上下文菜单（如果有）。单词 Select后可以紧跟着 0 或 1 来表示初始状态。换句话说，"Select" 和 "Select" . VarContainingOne 是一样的（此处的句点是连接运算符）。这种技术也适用于上面的 Focus 和 Check.

Vis [v1.0.44+]：必要时通过滚动 ListView 来确保指定行完全可见。此参数仅对 LV_Modify() 有效，例如：LV_Modify(RowNumber, "Vis")。

LV_Insert(RowNumber [, Options, Col1, Col2, ...])

与 LV_Add() 行为一样，除了其首个参数指定了新插入行的行号。通过下移 RowNumber 及其下方的行来为新行腾出空间。如果 RowNumber 大于列表中行的数目（甚至可以高达 2147483647），则新行被添加到列表的底部。要了解选项，请参阅行选项。

LV_Modify(RowNumber, Options [, NewCol1, NewCol2, ...])

修改行的属性和/或文本，成功时返回 1 而失败时返回 0。如果 RowNumber 为 0，则修改控件中所有行（此时如果操作完全成功时返回 1 而部分失败时返回 0）。如果只存在前两个参数, 则仅修改行的属性而不改变其文本. 同样, 如果参数太好而无法覆盖所有列, 则后面剩下的列保持不变. ColN 选项可以用来更新指定的列而不影响其他列。关于其他选项，请参阅行选项。

LV_Delete([RowNumber])

如果省略此参数，则删除 ListView 中所有行。否则，仅删除指定 RowNumber 所在的行。成功时返回 1 而失败时返回 0.

列函数

LV_ModifyCol([ColumnNumber, Options, ColumnTitle])

修改指定列的属性和/或文本以及标题。首列编号为 1 (不是 0). 如果省略所有参数, 则调整所有列的宽度以适应行的内容. 如果仅存在首个参数, 则仅调整指定列的大小. 只有在报告 (详细信息) 视图中自动调整大小才有效果. 此函数成功时返回 1 而失败时返回 0.

列选项

Options 参数是一个包含零个或多个下表中单词的字符串（不区分大小写）。在单词间使用空格或 tab 分隔. 要移除选项, 请在选项前加上负号. 要添加选项, 在选项前的正号可以省略.

列选项: 常规

N: 指定 N 为列的新宽度, 单位为像素. 如果这是唯一的选项, 则此数字可以不加引号. 例如，后面两种形式都是有效的：LV_ModifyCol(1, 50) 和 LV_ModifyCol(1, "50 Integer")。

Auto: 调整列宽来适应其内容. 只有在报告 (详细信息) 视图中此选项才有效果.

AutoHdr: 调整列宽来适应其内容和列标题的文本, 以其中较宽的为准. 当应用于最后一列时, 它将被设置为至少和 ListView 中剩余空间的宽度一样. 通常最好仅在行已经添加后才应用此设置, 因为这样允许当调整最后一列的大小时考虑到可能新增加的垂直滚动栏. 只有在报告 (详细信息) 视图中此选项才有效果.

Icon: 指定单词 Icon 后紧跟着 图像列表 中要显示在列标题文本后的图标的编号. 指定 -Icon（负 icon）来移除任何现有的图标。

IconRight: 把图标放在列的右边而不是左边.

列选项: 数据类型

Float: 为了进行排序, 指明此列包含浮点数 (不支持十六进制格式). 浮点数和文本列的排序性能最多可能比整数列的慢 25 倍.

Integer: 为了进行排序, 指明此列包含整数. 要正确排序, 每个整数必须是 32 位的; 即在范围 -2147483648 到 2147483647 内. 任何非整数的值在排序时将被视为零 (不过如果这些值以一个数字开头, 则使用这个数字). 数字格式可以为十进制或十六进制（例如 0xF9E0）。

Text: 更改列返回到文本模式进行排序, 这是每列初始默认的排序方式. 在排序时只有文本开始的 8190 个字符是有意义的 (如果如果使用了 Logical 选项, 此时限制为 4094).

列选项: 对齐 / 字距调整

Center: 让文本居于列中央. 要让 Integer 或 Float 列居中, 请把单词 Center 加到 Integer 或 Float 后.

Left: 让列文本左对齐, 这是每列初始默认的对齐方式. 在较旧的操作系统中, 首列可能会强制进行左对齐.

Right: 让列文本右对齐. 对于 Integer 和 Float 数列不需要指定此属性, 因为它们默认是右对齐的. 通过指定例如 "Integer Left" 或 "Float Center" 的字符串可以覆盖此默认的对齐方式。

列选项: 排序

Case: 让列排序区分大小写 (仅影响 文本 列). 如果 Case, CaseLocale 以及 Logical 选项都省略, 则在排序中大写字母 A-Z 被视为等同于它们相应的小写形式.

CaseLocale [v1.0.43.03+]: 让列排序基于当前用户的区域设置且不区分大小写 (仅影响 文本 列). 例如, 大多数英语和西欧地区把字母 A-Z 和 ANSI 字母例如 Ä 和 Ü 等同于它们的小写形式. 这种方法也使用 "单词排序", 它把单词中的连字符和撇号例如 "coop" 和 "co-op" 保持在一起.

Desc: 降序排列. 用户首次对此列排序时使用下降的顺序.

Logical [v1.0.44.12+]: 与 CaseLocale 相同, 除了把文本中的任何数字位序列看成真正的数字而不仅仅字符. 例如，字符串“T33”将被视为大于 “T4”。Logical 需要 Windows XP 或更高版本 (在较旧的操作系统中, 会自动使用 CaseLocale 代替). 此外, Logical 和 Case 是互斥的: 只有最近指定的那个才有效.

NoSort: 避免用户点击此列对自动排序产生的影响. 要禁用所有列的排序而不仅是其中的子集, 请在 ListView 的选项中包含 NoSort. 如果 ListView 含有 g 标签, 则当用户点击 no-sort 的列时仍会接收到 ColClick 通知.

Sort: 立即对列按升序排列 (即使它含有 Desc 选项).

SortDesc: 立即对列按降序排列.

Uni: 单向排序. 此选项防止在相同列进行第二次点击来反转排序方向.

LV_InsertCol(ColumnNumber [, Options, ColumnTitle])

创建新列，插入到指定的 ColumnNumber（移动其他的列到右边来腾出空间）。首列编号为 1 (不是 0). 如果 ColumnNumber 大于当前控件中列的数目，则新列被添加到列表的末尾（最右边）。新插入的列初始内容为空, 然而如果它是首列则会继承原来首列的内容, 同时原来首列的内容变为空的. 新列的属性（例如是否使用整数排序）开始时总为它们的默认值，不过可以使用选项改变。此函数返回新列的位置编号 (失败时为 0). ListView 中的最大列数为 200.

LV_DeleteCol(ColumnNumber)

删除指定的列及其中所有内容。成功时返回 1 而失败时返回 0. 当一个列被删除后, 在此列右边的任何列的编号减小 1. 因此，调用 LV_DeleteCol(2) 两次将删除第二列和第三列。在比 Windows XP 旧的操作系统中, 试图删除原始的首列可能会失败并返回 0.

从 ListView 中获取数据

LV_GetCount(["Selected | Column"])

省略参数时，函数返回控件中的总行数。当参数为 "S" 或 "Selected" 时, 计数仅包括选择的/高亮的行. 当参数为 "Col" 或 "Column", 函数返回控件中的列数. 此函数总是即时的, 因为控件会跟踪这些计数.

此函数常用在一个循环的顶行, 此时将仅调用一次函数 (在首次循环前). 例如：

Loop % LV_GetCount()
{
    LV_GetText(RetrievedText, A_Index)
    if InStr(RetrievedText, "some filter text")
        LV_Modify(A_Index, "Select")  ; 选择首个字段包含过滤文本的所有行.
}

要获取 ListView 的列宽 (用于例如保存它们到 INI 文件以便在会话期间保持一致), 请参照此例:

Gui +LastFound
Loop % LV_GetCount("Column")
{
    SendMessage, 4125, A_Index - 1, 0, SysListView321  ; 4125 为 LVM_GETCOLUMNWIDTH.
    MsgBox Column %A_Index%'s width is %ErrorLevel%.
}

LV_GetNext([StartingRowNumber, "Checked | Focused"])

返回下一个选择的，选中的或焦点行的行号。如果没有找到, 则返回零. 如果 StartingRowNumber 省略或小于 1，则从列表的顶部开始搜索。否则，从 StartingRowNumber 行后开始搜索。如果省略第二个参数, 则函数搜索下一个选择的/高亮的行. 否则, 指定 "C" 或 "Checked" 来寻找下一个选中的行; 或指定 "F" 或 "Focused" 来寻找焦点行 (在整个列表中不可能有多个焦点行, 且有时甚至没有). 下面的例子报告 ListView 中所有选择的行:

RowNumber = 0  ; 这样使得首次循环从列表的顶部开始搜索.
Loop
{
    RowNumber := LV_GetNext(RowNumber)  ; 在前一次找到的位置后继续搜索.
    if not RowNumber  ; 上面返回零, 所以选择的行已经都找到了.
        break
    LV_GetText(Text, RowNumber)
    MsgBox The next selected row is #%RowNumber%, whose first field is "%Text%".
}

判断一个特定的行是否被选中的另一种方法如下:

Gui +LastFound
SendMessage, 4140, RowNumber - 1, 0xF000, SysListView321  ; 4140 为 LVM_GETITEMSTATE.  0xF000 为 LVIS_STATEIMAGEMASK.
IsChecked := (ErrorLevel >> 12) - 1  ; 如果 RowNumber 为选中的则设置 IsChecked 为真, 否则为假.

LV_GetText(OutputVar, RowNumber [, ColumnNumber])

获取在指定的 RowNumber 和 ColumnNumber 位置上的文本并保存到 OutputVar。如果省略 ColumnNumber，则它默认为 1（首列的文本）。如果 RowNumber 为 0，则获取列标题的文本。如果文本长度超过 8191, 则仅获取前 8191 个字符. 此函数成功时返回 1 而失败时返回 0. 失败时，OutputVar 也被置空。

用户可能已经完成的拖放操作不会修改脚本看到的列编号. 例如, 最初首列的编号仍是 1, 即使用户已经把它拖到其他列的右边.

G 标签通知 (主要)

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户在控件中执行动作时 MySubroutine 标签会自动运行. 此子程序中可引用内置变量 A_Gui 和 A_GuiControl 来找出产生事件的是哪个窗口和 ListView. 更重要的是, 它可以参考 A_GuiEvent, 其包含下列字符串或字母的其中一个 (考虑到和未来版本的兼容性, 脚本不应假定这些字符串或字母是唯一可能的值):

DoubleClick：用户在控件内双击了。变量 A_EventInfo 包含焦点行号. LV_GetNext() 可用来获取首个选中的行号，当用户在空位置双击时为 0。

R: 用户在控件内 双击了右键. 变量 A_EventInfo 包含焦点行号.

ColClick: 用户点击了列标题. 变量 A_EventInfo 包含列编号, 这是在列创建时分配的原始编号; 即它不会反映任何用户对列完成的拖放操作. 对列点击的一种可能的响应是通过一个包含排序友好格式 (例如 YYYYMMDD 的整数日期) 数据的隐藏列 (零宽度) 进行排序. 这样的隐藏列可以以更友好的格式 (例如 MM/DD/YY) 显示与其他某列相同的数据. 例如，脚本可以通过 LV_ModifyCol(3, 0) 隐藏 column 3，接着通过 LV_ModifyCol(2, "NoSort") 关闭可见的 column 2 的自动排序。然后为了响应 column 2 的 ColClick 通告，脚本通过 LV_ModifyCol(3, "Sort") 使用隐藏的列对 ListView 进行排序。

D: 用户尝试开始拖动行或图标 (目标还没有内置对拖动行或图标的支持). 变量 A_EventInfo 包含焦点行号. 在 v1.0.44+, 即使不含 AltSubmit 此通知也会产生.

d (小写的 D): 和上面相同, 除了指右键拖动而不是左键.

e（小写的 E）：用户完成编辑一行的首个字段（只有当 ListView 选项中含有 -ReadOnly 时用户才可以进行编辑）。变量 A_EventInfo 包含目标行号.

G 标签通知 (次要)

如果 ListView 的 选项 中含有单词 AltSubmit, 则其 g 标签会运行的更频繁并且 A_GuiEvent 还可能包含下列值:

Normal: 用户左键单击了一行. 变量 A_EventInfo 包含焦点行号.

RightClick: 用户右键单击了一行. 变量 A_EventInfo 包含焦点行号. 在大多数情况下, 最好不要通过显示菜单来响应此通过. 而应使用 GuiContextMenu 标签, 因为它还能识别 Appskey. 例如：

GuiContextMenu:  ; 运行此标签来响应右键点击或按下 Appskey.
if A_GuiControl <> MyListView  ; 这个检查是可选的. 让它只为 ListView 中的点击显示菜单.
    return
; 在提供的坐标处显示菜单, A_GuiX 和 A_GuiY.  应该使用这些
; 因为即使用户按下 Appskey 它们也会提供正确的坐标:
Menu, MyContextMenu, Show, %A_GuiX%, %A_GuiY%
return

A: 激活了一行, 这种情况默认发生在双击这行的时候. 变量 A_EventInfo 包含目标行号.

C: ListView 释放了鼠标捕获.

E：用户开始编辑一行的首个字段（只有在 ListView 选项中含有 -ReadOnly 时用户才可以进行编辑）。变量 A_EventInfo 包含目标行号.

F: ListView 接收到键盘焦点.

f (小写的 F): ListView 失去了键盘焦点.

I: 项目发生了变化. 通过变成选择的/未选择的, 选中的/未选中的等让一行改变了. 如果用户选择了一个新行, 则至少会接收到两个这样的通知: 一个是在取消之前的行时, 而另一个是在选择新行时. 在 v1.0.44+, 变量 A_EventInfo 包含目标行号. 在 v1.0.46.10+, ErrorLevel 包含零个或多个下列字母来表示项目发生的变化: S (选择) 或 s (取消选择), 和/或 F (成为焦点) 或 f (失去焦点), 和/或 C (选中) 或 c (取消选中). 例如, SF 表示此行被选择且成为了焦点. 要检查是否存在一个特定的字母，请使用解析循环或带区分大小写选项的 InStr(); 例如：InStr(ErrorLevel, "S", true)。注: 考虑到和未来版本的兼容性, 脚本不应假定 "SsFfCc" 包含了所有可能的字母或字母组合. 此外, 指定 Critical 作为 g 标签 子程序的首行来确保接收到所有的 "I" 通知 (否则, 如果脚本无法跟上, 则它们其中一些可能会丢失).

K: 当 ListView 拥有焦点时用户按下了一个键. A_EventInfo 包含此键的虚拟按键代码, 这是介于 1 和 255 之间的数字. 如果此键是字母键，则在大多数键盘布局中可以使用 Chr(A_EventInfo) 把它转换成相应的字符。不论 WantF2 选项如何都可以接收到 F2 键击。然而，不会接收到 Enter 键击；要接收它，请像下面描述的那样使用一个默认按钮。

M: 选取框. 用户开始在一组行或图标周围拖动一个矩形选区.

S: 用户开始滚动 ListView.

s (小写的 S): 用户完成滚动 ListView.

图像列表（用于添加图像到 ListView 的方法）

图像列表是保存在内存中的一组大小相同的图标. 创建时每个图像列表是空的. 脚本重复调用 IL_Add() 来添加图标到列表中, 且给每个图标分配一个序号, 序号从 1 开始. 脚本引用此编号在一行中或列标题中显示一个特定的图标. 这是个可运行示例, 其中演示了如何在 ListView 的行中显示图标:

Gui, Add, ListView, h200 w180, Icon & Number|Description  ; 创建 ListView.
ImageListID := IL_Create(10)  ; 创建加载 10 个小图标的图像列表.
LV_SetImageList(ImageListID)  ; 把上面的图像列表指定给当前的 ListView.
Loop 10  ; 把 DLL 中的一系列图标装入图像列表.
    IL_Add(ImageListID, "shell32.dll", A_Index)
Loop 10  ; 在 ListView 中添加行（出于演示的目的，每个图标一行）。
    LV_Add("Icon" . A_Index, A_Index, "n/a")
LV_ModifyCol("Hdr")  ; 自动调整列宽。
Gui Show
return

GuiClose:  ; 当用户关闭 ListView 所在 GUI 窗口时退出脚本。
ExitApp

IL_Create([InitialCount, GrowCount, LargeIcons?])

创建新的初始为空的图像列表，并返回图像列表的唯一 ID（失败时为 0）。InitialCount 为希望马上放入列表的图标数（如果省略，则它默认为 2）。GrowCount 为列表每次将增长时超出当前列表容量的图标数（如果省略，则它默认为 5）。LargeIcons 应该为数值：如果不为零，则图像列表将包含大图标。如果为零, 则它包含小图标 (这是省略时的默认情况). 会按比例对添加到列表中的图标自动进行缩放以符合系统中大图标和小图标的尺寸.

LV_SetImageList(ImageListID [, 0|1|2])

此函数一般在 ListView 添加行之前调用。它设置关联的图像列表，其中的图标会显示在 ListView 的行中（可选的，以及列）。ImageListID 为前面调用 IL_Create() 返回的数字。如果省略第二个参数, 则自动检测图像列表中的图标为大图标还是小图标. 否则，对于大图标指定 0，对于小图标指定 1，而状态图标则为 2（还没有直接支持状态图标，不过可以通过 SendMessage 使用）。

一个 ListView 最多可以关联两个图像列表: 小图标和/或大图标. 这可用于脚本允许用户在大图标视图和其他视之间切换的时候. 要再关联一个图像列表到 ListView, 请再次调用 LV_SetImageList(), 其中指定第二个列表的 ImageListID. 同时关联有大图标和小图标图像列表的 ListView 应该确保两个列表中包含图标的顺序相同. 这是因为使用一个指定图标的大小版本时会引用相同的 ID 编号.

尽管除了图标模式和平铺模式显示小图标外, 对于其他的 视图模式 这是惯例, 但通过传递一个大图标列表到 LV_SetImageList 并且在第二个参数中指定 1 (小图标) 可以覆盖此行为. 这也增加了 ListView 中每行的高度以适合大图标.

如果成功, 则 LV_SetImageList() 返回之前与 ListView 关联的 ImageListID (如果没有则为 0). 任何分离的图像列表一般应使用 IL_Destroy(ImageListID) 进行销毁.

IL_Add(ImageListID, Filename [, IconNumber, ResizeNonIcon?])

添加图标或图片到指定的 ImageListID 并返回新图标的索引（首个图标索引为 1，第二个为 2，依此类推）。Filename 为图标（.ICO）、光标（.CUR）或动画光标（.ANI）文件的名称（动画光标在 ListView 中显示时实际将不会动）。图标的其他来源包含下列类型的文件: EXE, DLL, CPL, SCR 以及包含图标资源的其他类型. 要使用文件中的图标组而不是首个图标，请在 IconNumber 指定它的编号。如果 IconNumber 为负数，则假定其绝对值表示可执行文件中图标的资源 ID。在下面的例子中，将使用第二个图标组中的默认图标：IL_Add(ImageListID, "C:\My Application.exe", 2)。

还可以加载非图标图像, 例如 BMP, GIF 和 JPG. 然而, 此时应该指定最后两个参数以确保正确执行: IconNumber 应该为屏蔽的/透明的颜色编码 (对于大多数图片 0xFFFFFF [白色] 可能是最佳的); 而 ResizeNonIcon 应该为非零值来缩放图片为单个图标, 或者为零来把图像分割为多个可以匹配实际宽度的图标.

在所有的操作系统中都支持 GIF, JPG, BMP, ICO, CUR 和 ANI 图像. 在 Windows XP 或更高版本中, 还支持其他图像格式, 例如PNG, TIF, Exif, WMF 和 EMF. 比 XP 早的操作系统可以通过复制微软免费的 GDI+ DLL 到 AutoHotkey.exe 文件夹中来提供支持 (但如果是 已编译脚本, 则复制此 DLL 到脚本的文件夹). 要下载这个 DLL, 请在 www.microsoft.com 搜索下列短语: gdi redistributable

IL_Destroy(ImageListID)

删除指定的图像列表，成功时返回 1 而失败返回 0。通常没必要销毁图像列表, 因为一旦关联到 ListView, 当 ListView 或其父窗口销毁时它们会被自动销毁. 但是，如果一个 ListView 和其他 ListView 共享图像列表（通过在选项中包含 0x40），在所有使用此图像列表的 ListView 销毁后脚本应该明确地销毁它。同样地, 如果脚本使用一个新的图像列表代替 ListView 中原来的, 则应该明确销毁原来的图像列表.

ListView 备注

Gui Submit 命令对 ListView 控件没有效果. 因此，脚本可以使用ListView的关联变量（如果有）来保存其他数据而不用担心它会被覆盖。

在对某个列进行排序后（通过用户点击其标题的方法或脚本调用 LV_ModifyCol(1, "Sort")），任何随后添加的行将出现在列表的底部而不会遵循排序顺序。例外情况是 Sort 和 SortDesc 样式，它们会把新添加的行移动正确的位置。

当 ListView 拥有焦点时如果要检测到用户按下的回车键, 请使用 默认按钮 (如果需要则可以隐藏它). 例如：

Gui, Add, Button, Hidden Default, OK
...
ButtonOK:
GuiControlGet, FocusedControl, FocusV
if FocusedControl <> MyListView
    return
MsgBox % "Enter was pressed. The focused row number is " . LV_GetNext(0, "Focused")
return

使用键盘除了在行与行之间导航外, 用户还可以通过输入首列中一个项目名称的前几个字符来进行增量搜索. 这使得选择对象跳转到最近匹配的行.

尽管 ListView 中的每个字段可以存储任意长度的文本, 但仅显示开始的 260 个字符.

尽管 ListView 中可以使用的最大行数仅受系统可用内存的限制, 但参照 Count 选项中描述的方法可以极大地提高添加行的性能..

可以使用图片作为 ListView 周围的背景 (即作为 ListView 的框架). 要实现这个效果，请在 ListView 后创建图片控件并且在图片控件的选项中包含 0x4000000（这是 WS_CLIPSIBLINGS）。

脚本可以在每个窗口中创建多个 ListView. 要对非默认的 ListView 进行操作, 请参阅 内置函数.

最后不要使用 SendMessage 直接插入或删除列. 这是因为程序为每个列维护一个 排序参数 集, 而这会让它们无法同步. 作为替代, 请使用 内置列函数.

要对 ListView 执行一些操作 (例如调整大小, 隐藏或改变字体), 请使用 GuiControl.

要从外部的 ListView（不属于脚本自身的那些），请使用 ControlGet List。

相关

TreeView, 其他控件类型, Gui, GuiContextMenu, GuiControl, GuiControlGet, ListView 样式表

示例

; 指定行号为 0 来选择或取消选择所有行:
LV_Modify(0, "Select")   ; 选择所有.
LV_Modify(0, "-Select")  ; 取消选择所有.
LV_Modify(0, "-Check")  ; 取消选中所有 复选框.

; 自动根据内容调整所有列的宽度:
LV_ModifyCol()  ; 此时不需要参数.

; 主示例
; 下面是一个比此页面顶部附近那个更精巧的可运行脚本.
; 它显示用户文件夹中的文件, 且每个文件分配一个与其类型关联的图标.
; 用户在一个文件上双击或在一个或多个文件上右击后, 会显示上下文菜单.

; 允许用户最大化窗口或拖动来改变窗口的大小:
Gui +Resize

; 创建一些按钮:
Gui, Add, Button, Default gButtonLoadFolder, Load a folder
Gui, Add, Button, x+20 gButtonClear, Clear List
Gui, Add, Button, x+20, Switch View

; 创建 ListView 及其列:
Gui, Add, ListView, xm r20 w700 vMyListView gMyListView, Name|In Folder|Size (KB)|Type
LV_ModifyCol(3, "Integer")  ; 为了排序, 表示 Size 列中的内容是整数.

; 创建图像列表, 这样 ListView 才可以显示图标:
ImageListID1 := IL_Create(10)
ImageListID2 := IL_Create(10, 10, true)  ; 大图标列表和小图标列表.

; 关联图像列表到 ListView, 然而它就可以显示图标了:
LV_SetImageList(ImageListID1)
LV_SetImageList(ImageListID2)

; 创建作为上下文菜单的弹出菜单:
Menu, MyContextMenu, Add, Open, ContextOpenFile
Menu, MyContextMenu, Add, Properties, ContextProperties
Menu, MyContextMenu, Add, Clear from ListView, ContextClearRows
Menu, MyContextMenu, Default, Open  ; 让 "Open" 粗体显示表示双击时会执行相同的操作.

; 显示窗口并返回. 当用户执行预期的动作时
; 操作系统会通知脚本:
Gui, Show
return

ButtonLoadFolder:
Gui +OwnDialogs  ; 强制用户解除此对话框后才可以操作主窗口.
FileSelectFolder, Folder,, 3, Select a folder to read:
if not Folder  ; 用户取消了对话框.
    return

; 检查文件夹名称的最后一个字符是否为反斜线, 对于根目录则会如此,
; 例如 C:\. 如果是, 则移除这个反斜线以避免之后出现两个反斜线.
StringRight, LastChar, Folder, 1
if LastChar = \
    StringTrimRight, Folder, Folder, 1  ; 移除尾随的反斜线.

; 计算 SHFILEINFO 结构需要的缓存大小.
sfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
VarSetCapacity(sfi, sfi_size)

; 获取所选择文件夹中的文件名列表并添加到 ListView:
GuiControl, -Redraw, MyListView  ; 在加载时禁用重绘来提升性能.
Loop %Folder%\*.*
{
    FileName := A_LoopFileFullPath  ; 必须保存到可写的变量中供后面使用.

    ; 建立唯一的扩展 ID 以避免变量名中的非法字符,
    ; 例如破折号.  这种使用唯一 ID 的方法也会执行地更好,
    ; 因为在数组中查找项目不需要进行搜索循环.
    SplitPath, FileName,,, FileExt  ; 获取文件扩展名.
    if FileExt in EXE,ICO,ANI,CUR
    {
        ExtID := FileExt  ; 特殊 ID 作为占位符.
        IconNumber = 0  ; 进行标记这样每种类型就含有唯一的图标.
    }
    else  ; 其他的扩展名/文件类型, 计算它们的唯一 ID.
    {
        ExtID = 0  ; 进行初始化来处理比其他更短的扩展名.
        Loop 7     ; 限制扩展名为 7 个字符, 这样之后计算的结果才能存放到 64 位值.
        {
            StringMid, ExtChar, FileExt, A_Index, 1
            if not ExtChar  ; 没有更多字符了.
                break
            ; 把每个字符与不同的位位置进行运算来得到唯一 ID:
            ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
        }
        ; 检查此文件扩展名的图标是否已经在图像列表中. 如果是,
        ; 可以避免多次调用并极大提高性能,
        ; 尤其对于包含数以百计文件的文件夹而言:
        IconNumber := IconArray%ExtID%
    }
    if not IconNumber  ; 此扩展名还没有相应的图标, 所以进行加载.
    {
        ; 获取与此文件扩展名关联的高质量小图标:
        if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "str", FileName
            , "uint", 0, "ptr", &sfi, "uint", sfi_size, "uint", 0x101)  ; 0x101 为 SHGFI_ICON+SHGFI_SMALLICON
            IconNumber = 9999999  ; 把它设置到范围外来显示空图标.
        else ; 成功加载图标.
        {
            ; 从结构中提取 hIcon 成员:
            hIcon := NumGet(sfi, 0)
            ; 直接添加 HICON 到小图标和大图标列表.
            ; 下面加上 1 来把返回的索引从基于零转换到基于一:
            IconNumber := DllCall("ImageList_ReplaceIcon", "ptr", ImageListID1, "int", -1, "ptr", hIcon) + 1
            DllCall("ImageList_ReplaceIcon", "ptr", ImageListID2, "int", -1, "ptr", hIcon)
            ; 现在已经把它复制到图像列表, 所以应销毁原来的:
            DllCall("DestroyIcon", "ptr", hIcon)
            ; 缓存图标来节省内存并提升加载性能:
            IconArray%ExtID% := IconNumber
        }
    }

    ; 在 ListView 中创建新行并把它和上面的图标编号进行关联:
    LV_Add("Icon" . IconNumber, A_LoopFileName, A_LoopFileDir, A_LoopFileSizeKB, FileExt)
}
GuiControl, +Redraw, MyListView  ; 重新启用重绘 (上面把它禁用了).
LV_ModifyCol()  ; 根据内容自动调整每列的大小.
LV_ModifyCol(3, 60) ; 把 Size 列加宽一些以便显示出它的标题.
return

ButtonClear:
LV_Delete()  ; 清理 ListView, 但为了简化保留了图标缓存.
return

ButtonSwitchView:
if not IconView
    GuiControl, +Icon, MyListView    ; 切换到图标视图.
else
    GuiControl, +Report, MyListView  ; 切换回详细信息视图.
IconView := not IconView             ; 进行反转以为下次做准备.
return

MyListView:
if A_GuiEvent = DoubleClick  ; 脚本还可以检查许多其他的可能值.
{
    LV_GetText(FileName, A_EventInfo, 1) ; 从首个字段中获取文本.
    LV_GetText(FileDir, A_EventInfo, 2)  ; 从第二个字段中获取文本.
    Run %FileDir%\%FileName%,, UseErrorLevel
    if ErrorLevel
        MsgBox Could not open "%FileDir%\%FileName%".
}
return

GuiContextMenu:  ; 运行此标签来响应右键点击或按下 Appskey.
if A_GuiControl <> MyListView  ; 仅在 ListView 中点击时才显示菜单.
    return
; 在提供的坐标处显示菜单, A_GuiX 和 A_GuiY.  应该使用这些
; 因为即使用户按下 Appskey 它们也会提供正确的坐标:
Menu, MyContextMenu, Show, %A_GuiX%, %A_GuiY%
return

ContextOpenFile:  ; 用户在上下文菜单中选择了 "Open".
ContextProperties:  ; 用户在上下文菜单中选择了 "Properties".
; 为了简化, 仅对焦点行进行操作而不是所有选择的行:
FocusedRowNumber := LV_GetNext(0, "F")  ; 查找焦点行.
if not FocusedRowNumber  ; 没有焦点行.
    return
LV_GetText(FileName, FocusedRowNumber, 1) ; 获取首个字段的文本.
LV_GetText(FileDir, FocusedRowNumber, 2)  ; 获取第二个字段的文本.
IfInString A_ThisMenuItem, Open  ; 用户在上下文菜单中选择了 "Open".
    Run %FileDir%\%FileName%,, UseErrorLevel
else  ; 用户在上下文菜单中选择了 "Properties".
    Run Properties "%FileDir%\%FileName%",, UseErrorLevel
if ErrorLevel
    MsgBox Could not perform requested action on "%FileDir%\%FileName%".
return

ContextClearRows:  ; 用户在上下文菜单中选择了 "Clear".
RowNumber = 0  ; 这会使得首次循环从顶部开始搜索.
Loop
{
    ; 由于删除了一行使得此行下面的所有行的行号都减小了,
    ; 所以把行号减 1, 这样搜索里包含的行号才会与之前找到的行号相一致
    ; (以防选择了相邻行):
    RowNumber := LV_GetNext(RowNumber - 1)
    if not RowNumber  ; 上面返回零, 所以没有更多选择的行了.
        break
    LV_Delete(RowNumber)  ; 从 ListView 中删除行.
}
return

GuiSize:  ; 扩大或缩小 ListView 来响应用户对窗口大小的改变.
if A_EventInfo = 1  ; 窗口被最小化了.  无需进行操作.
    return
; 否则, 窗口的大小被调整过或被最大化了. 调整 ListView 的大小来适应.
GuiControl, Move, MyListView, % "W" . (A_GuiWidth - 20) . " H" . (A_GuiHeight - 40)
return

GuiClose:  ; 当窗口关闭时, 自动退出脚本:
ExitApp


TreeView (GUI)

TreeView [v1.0.44+]

目录

  • 入门和简单示例
  • 选项和样式
  • 内置函数:
    • 添加、修改、删除项目
    • 从 TreeView 中获取数据
  • G 标签通知
  • 备注
  • 更长的示例

入门和简单示例

Tree-View 通过缩进父项目下的子项目来显示出层级关系. 最常见的例子是资源管理器的驱动器和文件夹数.

创建 TreeView 的语法为:

Gui, Add, TreeView, Options

这是一个创建和显示简单项目层次结构的可运行脚本:

Gui, Add, TreeView
P1 := TV_Add("First parent")
P1C1 := TV_Add("Parent 1's first child", P1)  ; 指定 P1 为此项目的父项目.
P2 := TV_Add("Second parent")
P2C1 := TV_Add("Parent 2's first child", P2)
P2C2 := TV_Add("Parent 2's second child", P2)
P2C2C1 := TV_Add("Child 2's first child", P2C2)

Gui, Show  ; 显示窗口及其 TreeView.
return

GuiClose:  ; 当用户关闭 TreeView 所在的 GUI 窗口时退出脚本.
ExitApp

用于 "Gui, Add, TreeView, Options" 的样式和选项

AltSubmit: 通知脚本有比正常更多的 TreeView 事件类型. 换句话说, g 标签会运行地更频繁. 请参阅 TreeView 通知 了解详情.

Background: 指定单词 Background 后面紧跟着颜色名称 (请参阅 颜色图表) 或 RGB 值 (0x 前缀可以省略). 例如：BackgroundSilver，BackgroundFFDD99。如果此选项不存在，则 TreeView 初始默认的背景颜色由 Gui Color 的最后一个参数设置（如果没有，则使用系统默认的背景颜色）。指定 BackgroundDefault 来应用系统的默认背景颜色（通常为白色）。例如，使用 GuiControl, +BackgroundDefault, MyTreeView 可以把 TreeView 恢复为默认的颜色。

Buttons：指定 -Buttons（负 Buttons）来避免在每个含有子项目的项目左边显示加号或减号按钮。

C: 文本颜色. 指定字母 C 后面紧跟着颜色名称 (请参阅 颜色图表) 或 RGB 值 (0x 前缀可以省略). 例如：cRed，cFF2211，c0xFF2211，cDefault。

Checked: 在每项的左边提供一个复选框. 当 添加 项目时, 在其选项中指定单词 Check 来让复选框初始为选中而不是未选中状态. 用户可以点击复选框或按下空格键来选中或取消选中项目. 要找出 TreeView 中当前选中了哪些项目, 请调用 TV_GetNext() 或 TV_Get().

HScroll：指定 -HScroll（负 HScroll）来禁用控件中的水平滚动（而且控件将不显示水平滚动条）。

ImageList: 这是把图标添加到 TreeView 的方法. 指定单词 ImageList 后紧跟着由之前调用 IL_Create() 返回的 ImageListID. 此选项仅在创建 TreeView 时才有效果 (但是, TV_SetImageList() 没有此限制). 这里是一个可运行示例:

ImageListID := IL_Create(10)  ; 创建初始容量为 10 个图标的图像列表.
Loop 10  ; 加载一些标准系统图标到图像列表中.
    IL_Add(ImageListID, "shell32.dll", A_Index)
Gui, Add, TreeView, ImageList%ImageListID%
TV_Add("Name of Item", 0, "Icon4")  ; 添加项目到 TreeView 并给它分配文件夹图标。
Gui Show

Lines：指定 -Lines（负 Lines）来避免显示连接父项目和它们的子项目之间的网状线。但是, 移除这些线也阻止了顶级项目坐标加号/减号按钮的显示.

ReadOnly：指定 -ReadOnly（负 ReadOnly）来允许编辑每项的文本/名称。要编辑某项，请选择它接着按下 F2 键。或者, 您可以对某个项目点击一次来选择它, 至少等半秒, 然后再次点击同一项目进行编辑. 编辑后, 可以对一个项目在其同级项目之间按字母顺序进行重新定位, 请参考下面的例子:

Gui, Add, TreeView, -ReadOnly gMyTree
; ...
MyTree:
if (A_GuiEvent == "e")  ; 用户结束了对项目的编辑 (使用 == 来进行区分大小写的比较).
    TV_Modify(TV_GetParent(A_EventInfo), "Sort")  ; 当一个项目没有父项目时, 此语句也有效.
return

R: 行高 (创建时). 指定字母 R 后面紧跟着要在控件中留出空间的行数. 例如，R10 会设置控件为 10 个项目的高度。

WantF2：指定 -WantF2（负 WantF2）来禁止使用 F2 键击编辑当前选择的项目。仅当 -ReadOnly 也有效时此设置才不会被忽略. 不论此设置如何, g 标签仍会接收到 F2 通知.

(未命名的数值样式): 由于上述以外的其他样式很少使用, 所以没有为它们命名. 请参阅 TreeView 样式表 了解这些样式.

TreeView 中的内置函数

所有的 TreeView 函数操作于当前线程的默认 GUI 窗口（这可以使用 Gui, 2:Default 进行改变）。如果默认窗口不存在或不含有 TreeView 控件, 则所有函数返回零来表明此问题.

如果窗口中含有多个 TreeView 控件, 则默认情况下函数操作于最近添加的那个. 要改变这种情况，请指定 Gui, TreeView, TreeViewName，其中 TreeViewName 为 TreeView 的关联变量的名称或 Window Spy 中显示的其 ClassNN 或（在 v1.1.04+）它的 HWND。一旦改变后, 所有现有和将来的 线程 都会使用指定的 TreeView.

TV_SetImageList(ImageListID [, 0|2]) [v1.1.02+]

设置或替换 TreeView 的 ImageList。ImageListID 为前面调用 IL_Create() 返回的数字。第二个参数一般情况下忽略, 此时它默认为 0. 否则，对于状态图标指定 2（还没有直接支持状态图标，不过可以通过 SendMessage 使用）。如果成功, 则 TV_SetImageList() 返回之前与 TreeView 关联的 ImageListID (如果没有则为 0). 任何分离的图像列表一般应使用 IL_Destroy(ImageListID) 进行销毁。

添加, 修改和删除项目

TV_Add(Name, [ParentItemID, Options])

添加新的项目到 TreeView 并返回其唯一的项目 ID 号（失败时返回 0）。Name 为被显示的文本，它可以为文本或数值（包括数值的表达式结果）。ParentItemID 为新项目的父项的 ID 号（省略它或指定 0 来添加顶级项目）。当添加大量项目时，在添加项目前使用 GuiControl, -Redraw, MyTreeView 并且在添加项目后使用 GuiControl, +Redraw, MyTreeView 可以提升性能。

TV_Add() 和 TV_Modify() 中的选项参数

Options 参数是一个包含零个或多个下表中单词的字符串（不区分大小写）。在单词间使用空格或 tab 分隔. 要移除选项, 请在选项前加上负号. 要添加选项, 在选项前的正号可以省略.

Bold: 用粗体显示项目的名称. 以后要取消项目名称的粗体显示，请使用 TV_Modify(ItemID, "-Bold")。

Check: 在项目的坐标显示一个复选标记 (需要 TreeView 含有 复选框). 以后要取消复选它，请使用 TV_Modify(ItemID, "-Check")。在单词 Check 后可以紧跟着 0 或 1 来表示初始状态. 换句话说，"Check" 和 "Check" . VarContainingOne 是相同的（这里中间使用的是连接运算符）。

Expand：展开此项以让其子项目显示出来（如果有）。以后要折叠项目，请使用 TV_Modify(ItemID, "-Expand")。如果没有子项目, 那么 TV_Modify() 返回 0 而不是它的项目 ID. 与之相比, TV_Add() 标记此项目为展开的以防以后要添加子项目. 与下面的 "Select" 不同, 展开一个项目不会自动展开其父项目. 最后, 在单词 Expand 后可以紧跟着 0 或 1 来表示初始状态. 换句话说，"Expand" 和 "Expand" . VarContainingOne 是相同的。

First | Sort | N: 这些选项仅适用于 TV_Add(). 它们指定新项目相对于 其同级项目的位置 (此处 同级项目 是同一级别的其他任何项目). 如果这些选项都不存在, 则新项目被添加到同级项目的最后一个/底部. 否则，请指定 First 来添加项目到同级项目的第一个/顶部，或指定 Sort 来按字母顺序插入新项目到同级项目中间。如果指定一个纯整数 (N), 则假定它为同级项目的 ID 号, 新项目会被插入到它的后面 (如果整数 N 是唯一使用的选项, 则它不需要括在引号中).

Icon: 指定单词 Icon 后紧跟着此项目图标的编号, 项目图标显示在项目名称的左边. 如果此选项不存在, 则使用 图像列表 中的首个图标. 要显示空白图标, 请指定一个大于图像列表中图标数目的数字. 如果控件没有图像列表, 则既不显示图标也不为图标保留空间.

Select: 选择项目. 因为一次只能选择一个项目, 此时任何原来选择的项目会自动取消选择. 此外, 如果有必要此选项会展开其父项目以显示新选择的项目. 要找出当前选择的项目, 请使用 TV_GetSelection().

Sort: 对于 TV_Modify(), 此选项按字母顺序排列指定项目的子项目. 要对所有顶级项目进行排序，请使用 TV_Modify(0, "Sort")。如果不含子项目, 则返回 0 而不是所修改项目的 ID.

Vis: 通过滚动 TreeView 和/或展开其父项目 (必要时) 来确保此项完全可见.

VisFirst: 和上面一样, 不过在可行时它还会滚动 TreeView 使得此项显示在最上面. 此选项与 TV_Modify() 一起使用比与 TV_Add() 通常更有效.

TV_Modify(ItemID [, Options, NewName])

修改项目的属性和/或名称。成功时返回项目自己的 ID 而失败 (或部分失败) 时返回 0. 如果只使用首个参数，则选择指定的项目。如果省略 NewName，则保持当前名称不变。要了解Options，请参阅上面的列表。

TV_Delete([ItemID])

如果省略 ItemID，则删除 TreeView 中所有项目。否则，仅删除指定的 ItemID 表示的项目。成功时返回 1 而失败时返回 0.

从 TreeView 中获取数据

TV_GetSelection()

返回选择项目的 ID 号。

TV_GetCount()

返回控件中项目的总数。此函数总是即时的, 因为控件会跟踪此计数.

TV_GetParent(ItemID)

返回指定项目的父项目的 ID。顶级项目没有父项目, 因此返回 0.

TV_GetChild(ParentItemID)

返回指定项目的第一个/最上面的子项目的 ID 号（如果没有则为 0）。

TV_GetPrev(ItemID)

返回指定项目上面一个的同级项目的 ID 号（如果没有则为 0）。

TV_GetNext([ItemID, "Checked | Full"])

它包含了下列模式：

  1. 省略所有参数时, 它返回 TreeView 中第一个/最上面的项目的 ID 号 (如果没有则为 0).
  2. 如果仅存在首个参数 (ItemID), 则它返回指定项目下面一个同级项目的 ID 号 (如果没有则为 0). 如果首个参数为 0, 则它返回 TreeView 中第一个/最上面的项目的 ID 号 (如果没有则为 0).
  3. 当第二个参数为 "Full" 或 "F", 则获取下一个项目, 不论它是否为指定项目的同级项目. 这使得脚本可以容易地逐项遍历整个数. 例如：
    ItemID = 0  ; 这样使得首次循环从树的顶部开始搜索.
Loop
{
    ItemID := TV_GetNext(ItemID, "Full")  ; 把 "Full" 替换为 "Checked" 来找出所有含复选标记的项目.
    if not ItemID  ; 没有更多项目了.
        break
    TV_GetText(ItemText, ItemID)
    MsgBox The next Item is %ItemID%, whose text is "%ItemText%".
}
  4. 当第二个参数为 "Check", "Checked" 或 "C", 与上面行为相同, 不过会跳过任何没有复选标记的项目. 这样可以逐个获取 TreeView 中所有含有复选标记的项目.

TV_GetText(OutputVar, ItemID)

获取指定 ItemID 的文本/名称并保存到 OutputVar。如果文本长度超过 8191, 则仅获取前 8191 个字符. 成功时函数返回项目自己的 ID. 失败时返回 0（且 OutputVar 被置空）。

TV_Get(ItemID, "Expand | Check | Bold")

如果指定的项目含有指定的属性，则返回它自己的 ItemID。否则返回 0. 在第二个参数中指定“E”、“Expand”或“Expanded”来判断此项当前为展开的（即它的子项目是显示的）；指定“C”、“Check”或“Checked”来判断此项含有复选标记；或指定“B”或“Bold”来判断此项当前显示为粗体。

提示：因为在 IF 语句中把任何非零值视为“真”，所以下面两行功能相同：

  1. if TV_Get(ItemID, "Checked") = ItemID
  2. if TV_Get(ItemID, "Checked")

G 标签通知 (主要)

g 标签例如 gMySubroutine 可以使用在此控件的选项中。这使得当用户在控件中执行动作时 MySubroutine 标签会自动运行. 此子程序中可引用内置变量 A_Gui 和 A_GuiControl 来找出产生事件的是哪个窗口和 TreeView. 更重要的是, 它可以参考 A_GuiEvent, 其包含下列字符串或字母的其中一个 (考虑到和未来版本的兼容性, 脚本不应假定这些字符串或字母是唯一可能的值):

DoubleClick: 用户双击了一项. 变量 A_EventInfo 包含目标项目 ID.

D: 用户尝试开始拖动一个项目 (目前还没有内置对拖动项目的支持). 变量 A_EventInfo 包含目标项目 ID.

d (小写的 D): 和上面相同, 除了指右键拖动而不是左键.

e（小写的 E）：用户完成编辑一个项目（只有当 TreeView 选项中含有 -ReadOnly 时用户才可以编辑项目）。变量 A_EventInfo 包含目标项目 ID.

S: 选择了一个新项目, 可以是用户或脚本自己选择的. 变量 A_EventInfo 包含新选择项目的 ID.

G 标签通知 (次要)

如果 TreeView 的 选项 中含有单词 AltSubmit, 则其 g 标签会运行的更频繁并且 A_GuiEvent 还可能包含下列值:

Normal: 用户左键单击了一个项目. 变量 A_EventInfo 包含目标项目 ID.

RightClick: 用户右键单击了一个项目. 变量 A_EventInfo 包含目标项目 ID. 在大多数情况下, 最好不要通过显示菜单来响应此通过. 而应使用 GuiContextMenu 标签, 因为它还能识别 Appskey. 例如：

GuiContextMenu:  ; 运行此标签来响应右键点击或按下 Appskey.
if A_GuiControl <> MyTreeView  ; 这个检查是可选的. 让它只为 TreeView 中的点击显示菜单.
    return
; 在提供的坐标处显示菜单, A_GuiX 和 A_GuiY.  应该使用这些
; 因为即使用户按下 Appskey 它们也会提供正确的坐标:
Menu, MyContextMenu, Show, %A_GuiX%, %A_GuiY%
return

E: 用户开始编辑一个项目 (只有当 TreeView 选项中含有 -ReadOnly 时用户才可以编辑项目). 变量 A_EventInfo 包含目标项目 ID.

F: TreeView 接收到键盘焦点.

f (小写的 F): TreeView 失去了键盘焦点.

K: 当 TreeView 拥有焦点时用户按下了一个键. A_EventInfo 包含此键的虚拟按键代码, 这是介于 1 和 255 之间的数字. 如果此键是字母键，则在大多数键盘布局中可以使用 Chr(A_EventInfo) 把它转换成相应的字符。不论 WantF2 选项如何都可以接收到 F2 键击。然而，不会接收到 Enter 键击；要接收它，请像下面描述的那样使用一个默认按钮。

+ (加号): 展开了一个项目来显示它的子项目. 变量 A_EventInfo 包含目标项目 ID.

- (减号): 折叠一个项目来隐藏它的子项目. 变量 A_EventInfo 包含目标项目 ID.

备注

Gui Submit 命令对 TreeView 控件没有效果. 因此，脚本可以使用TreeView的关联变量（如果有）来保存其他数据而不用担心它会被覆盖。

当 TreeView 拥有焦点时如果要检测到用户按下的回车键, 请使用 默认按钮 (如果需要可以隐藏它). 例如：

Gui, Add, Button, Hidden Default, OK
...
ButtonOK:
GuiControlGet, FocusedControl, FocusV
if FocusedControl <> MyTreeView
    return
MsgBox % "Enter was pressed. The selected item ID is " . TV_GetSelection()
return

使用键盘除了在项与项之间导航外, 用户还可以通过输入一个项目名称的前几个字符来进行增量搜索. 这使得选择对象跳转到最近匹配的项目.

尽管 TreeView 中的每个项目可以存储任意长度的文本, 但仅显示开始的 260 个字符.

尽管理论上 TreeView 中的项目数可以多达 65536, 然而接近此数目时添加项的性能将显著降低. 通过使用 TV_Add() 中描述的重绘提示可以稍微减轻这种情况.

与 ListView 不同, 当 TreeView 销毁时它的图像列表不会自动被销毁. 因此, 如果 TreeView 中使用的图像列表以后不再用于其他地方, 则在销毁 TreeView 所在的窗口后脚本应调用 IL_Destroy(ImageListID) 来销毁此图像列表. 然而, 如果脚本很快将退出, 这样做是没必要的, 因为那时所有的图像列表会自动被销毁.

脚本可以在每个窗口中创建多个 TreeView. 要对非默认的 TreeView 进行操作, 请参阅 内置函数.

要执行一些操作, 例如调整大小, 隐藏或改变 TreeView 的字体, 请使用 GuiControl.

Tree View eXtension (TVX) 扩展了 TreeView 的功能, 增加对移动, 插入和删除的支持. 演示的例子请参阅 www.autohotkey.com/forum/topic19021.html

相关

ListView, 其他控件类型, Gui, GuiContextMenu, GuiControl, GuiControlGet, TreeView 样式表

示例

; 下面是一个比此页面顶部附近那个更精巧的可运行脚本.
; 它创建和显示包含了在所有用户开始菜单的所有文件夹的 TreeView.  当
; 用户选择文件夹时, 它的内容会显示在右边的 ListView (类似于 Windows 资源管理器).
; 此外, StatusBar 控件会显示当前选择文件夹的信息.

; 下面的文件夹为 TreeView 的根文件夹. 请注意如果指定
; 整个驱动器例如 C:\，那么加载可能需要很长时间：
TreeRoot = %A_StartMenuCommon%
TreeViewWidth := 280
ListViewWidth := A_ScreenWidth - TreeViewWidth - 30

; 让用户可以最大化或拖动调整窗口大小：
Gui +Resize

; 创建图像列表并在其中放入一些标准的系统图标：
ImageListID := IL_Create(5)
Loop 5
    IL_Add(ImageListID, "shell32.dll", A_Index)
; 创建 TreeView 和 ListView，让它们像在 Windows 资源管理器中那样靠在一起：
Gui, Add, TreeView, vMyTreeView r20 w%TreeViewWidth% gMyTreeView ImageList%ImageListID%
Gui, Add, ListView, vMyListView r20 w%ListViewWidth% x+10, Name|Modified

; 设置 ListView 的列宽（可选的）：
Col2Width = 70  ; 缩小到只显示 YYYYMMDD 部分。
LV_ModifyCol(1, ListViewWidth - Col2Width - 30)  ; 保留垂直滚动条的空间。
LV_ModifyCol(2, Col2Width)

; 创建状态栏，显示文件夹数及其总大小的信息：
Gui, Add, StatusBar
SB_SetParts(60, 85)  ; 创建状态栏的三个部分（第三部分占用所有剩余宽度）。

; 添加文件夹及其子文件夹到树中。如果加载需要很长时间，则显示提示信息：
SplashTextOn, 200, 25, TreeView and StatusBar Example, Loading the tree...
AddSubFoldersToTree(TreeRoot)
SplashTextOff

; 显示窗口并返回。每当用户执行符合条件的动作时，操作系统会通知脚本：
Gui, Show,, %TreeRoot%  ; 在标题栏中显示源目录（树的根目录）。
return

AddSubFoldersToTree(Folder, ParentItemID = 0)
{
    ; 此函数添加指定文件夹中所有子文件夹到 TreeView。
    ; 它还可以调用自己来递归获取到任意深度的内嵌文件夹。
    Loop %Folder%\*.*, 2  ; 获取所有文件夹的子文件夹.
        AddSubFoldersToTree(A_LoopFileFullPath, TV_Add(A_LoopFileName, ParentItemID, "Icon4"))
}

MyTreeView:  ; 此子程序处理用户的操作（例如点击）。
if A_GuiEvent <> S  ; 即“选择树中的新项目”外的其他操作。
    return  ; 什么都不做。; 否则，把选择的文件夹中的内容放入 ListView。; 首先确定选择的文件夹的完整路径：
TV_GetText(SelectedItemText, A_EventInfo)
ParentID := A_EventInfo
Loop  ; 建立到选择的文件夹的完整路径。
{
    ParentID := TV_GetParent(ParentID)
    if not ParentID  ; 没有更多的高层项目了。
        break
    TV_GetText(ParentText, ParentID)
    SelectedItemText = %ParentText%\%SelectedItemText%
}
SelectedFullPath = %TreeRoot%\%SelectedItemText%

; 把文件放入 ListView：
LV_Delete()  ; 清除所有行。
GuiControl, -Redraw, MyListView  ; 加载过程中禁用重绘来提升性能。
FileCount = 0  ; 为下面的循环进行初始化。
TotalSize = 0
Loop %SelectedFullPath%\*.*  ; 为了简化，这里省略了文件夹，所以只在 ListView 中显示文件。
{
    LV_Add("", A_LoopFileName, A_LoopFileTimeModified)
    FileCount += 1
    TotalSize += A_LoopFileSize
}
GuiControl, +Redraw, MyListView

; 更新状态栏的三个部分，让它们显示当前选择的文件夹的信息：
SB_SetText(FileCount . " files", 1)
SB_SetText(Round(TotalSize / 1024, 1) . " KB", 2)
SB_SetText(SelectedFullPath, 3)
return

GuiSize:  ; 当用户改变窗口大小时扩展/收缩 ListView 和 TreeView。
if A_EventInfo = 1  ; 窗口被最小化了。无需进行操作。
    return
; 否则，窗口的大小被调整过或被最大化了。调整控件大小以适应。
GuiControl, Move, MyTreeView, % "H" . (A_GuiHeight - 30)  ; 预留 30 用于状态栏和边距。
GuiControl, Move, MyListView, % "H" . (A_GuiHeight - 30) . " W" . (A_GuiWidth - TreeViewWidth - 30)
return

GuiClose:  ; 当用户关闭 TreeView 所在的 GUI 窗口时退出脚本。
ExitApp


InputBox

显示输入框让用户输入字符串。

InputBox, OutputVar [, Title, Prompt, HIDE, Width, Height, X, Y, Font, Timeout, Default]

参数

OutputVar

用来保存用户输入文本的变量名.

标题

输入框的标题. 如果为空或省略, 则它默认为脚本的名称.

Prompt

输入框的文本, 通常是用于提示用户期望输入的数据类型的信息. 如果 Prompt 较长, 可以通过 延续片段 的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

HIDE

如果此参数为 HIDE, 则屏蔽用户的输入, 这可以用于输入密码.

Width

如果此参数为空或省略, 则窗口的初始宽度为 375. 此参数可以为 表达式.

Height

如果此参数为空或省略, 则窗口的初始高度为 189. 此参数可以为 表达式.

X, Y

窗口的 X 和 Y 坐标 (使用 0,0 来将其移动到桌面的左上角), 可以为 表达式. 如果其中一个坐标为空或省略, 则对话框在这个方向上将居中. 其中一个或两个坐标都可以为负数来把窗口部分或完全移出桌面.

Font

尚未实现 (留空). 将来它可能接受类似 verdana:8 这样的内容

超时

以秒为单位的超时时间（可以为小数或表达式）。如果这个值超过 2147483（24.8 天），那么它会被设置为 2147483。达到超时时间后, 输入框窗口会自动关闭同时把 ErrorLevel 设置为 2. OutputVar 仍会被设置为用户输入的内容.

Default

对话框首次出现时显示在输入框中的字符串. 用户可以使用退格或其他方法修改这个字符串.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

请参阅下面.

备注

此对话框允许用户输入文本然后按下 OK 或 CANCEL. 用户可以通过拖动对话框的边界来调整它的大小.

当用户按下取消按钮时 ErrorLevel 值被设置为 1，按下确定时值为 0，如果对话框超时则为 2。在这三种情况中，OutputVar 都被设置为输入的值。这使得 CANCEL 按钮执行其他的功能而不是脚本设计者期望的取消功能.

GUI 窗口可以使用 Gui +OwnDialogs 的方法显示模态的输入框. 模态输入框在其消失之前会阻止用户与 GUI 窗口进行交互.

相关

GUI, Input, MsgBox, FileSelectFile, FileSelectFolder, SplashTextOn, ToolTip

示例

InputBox, password, Enter Password, (your input will be hidden), hide
InputBox, UserInput, Phone Number, Please enter a phone number., , 640, 480
if ErrorLevel
    MsgBox, CANCEL was pressed.
else
    MsgBox, You entered "%UserInput%"


Menu

创建、删除、修改和显示菜单和菜单项。改变托盘图标和它的提示。控制是否可以打开已编译脚本的主窗口。

Menu, MenuName, Cmd [, P3, P4, P5]

参数

MenuName

它可以为 TRAY 或任何自定义菜单的名称. 首次和 Add 命令一起使用自定义菜单的名称时会自动创建此菜单. 例如：Menu, MyMenu, Add, Item1。

创建后, 可以用 Show 命令显示自定义菜单. 通过 Add 命令还可以把它作为子菜单附加到一个或更多的其他菜单上.

Cmd, P3, P4, P5

这 4 个参数彼此依赖. 请参阅下表了解允许的组合.

添加或改变菜单项

Add [, MenuItemName, Label-or-Submenu, Pn]: 此命令有多种用途, 包括添加菜单项, 使用新的子菜单或标签更新菜单项或把普通菜单转换成子菜单 (或相反). 如果 MenuItemName 还不存在, 则把它添加到菜单. 否则，将使用新指定的 Label-or-Submenu 更新 MenuItemName。

要添加菜单分隔线, 请省略所有三个参数.

当用户选择菜单项时, 标签子程序作为新 线程 运行 (类似于 Gosub 和 热键子程序). 如果省略 Label-or-Submenu, 那么将使用 MenuItemName 同时作为标签和菜单项的名称.

要让 MenuItemName 变成子菜单 (在选择时打开新菜单的菜单项), 请在 Label-or-Submenu 中指定冒号后面跟着现有自定义菜单的 MenuName. 例如：

Menu, MySubmenu, add, Item1
Menu, tray, add, This Menu Item Is A Submenu, :MySubmenu

最后一个参数可以包含字母 P 后面跟着菜单的线程优先级，例如 P1。如果添加菜单时省略此参数, 则优先级将为 0, 这是标准的默认值. 如果在更新菜单时省略, 则菜单项的优先级将保持不变. 要改变现有菜单项的优先级，请省略 Label-or-Submenu 参数。使用十进制 (不是十六进制) 数表示优先级.

Delete [, MenuItemName]：从菜单中删除 MenuItemName。标准菜单项例如 Exit (请参阅下面) 不能被单独删除. 如果删除了默认菜单项，则效果与使用 NoDefault 选项类似。. 如果省略了 MenuItemName，则会删除整个 MenuName 以及在其他菜单中名称为 MenuName 的任何子菜单项。

DeleteAll: 从菜单中删除所有自定义菜单项, 当不包含 标准 菜单项 (请参阅下面) 时则让菜单留空. 与使用 Delete 命令 (请参阅上面) 完全删除菜单不同, 此时仍然存在一个空菜单, 因此其他任何包含此菜单项作为子菜单的菜单仍保留这些子菜单.

Rename, MenuItemName [, NewName]：改变 MenuItemName 为 NewName（如果 NewName 为空，则 MenuItemName 会变为分隔线）。NewName 不能和任何现有的自定义菜单项名称相同. 菜单项的当前目标标签或子菜单不会改变.

Check, MenuItemName：在MenuItemName前添加复选标记（如果还没有）。

Uncheck, MenuItemName：从MenuItemName中移除复选标记（如果有）。

ToggleCheck, MenuItemName: 如果没有复选标记则进行添加; 否则移除它.

Enable, MenuItemName: 允许用户再次选择之前禁用 (灰色) 的 MenuItemName.

Disable, MenuItemName：把 MenuItemName 变成灰色以指示用户无法选择它。

ToggleEnable, MenuItemName: 禁用之前启用的 MenuItemName; 否则启用它.

Default [, MenuItemName]: 改变菜单的默认项为 MenuItemName 并加粗其字体 (当前在 TRAY 以外的菜单中设置默认项只是改变外观而没有其他作用). 当用户双击托盘图标时, 会运行其默认菜单项. 如果没有默认项, 则双击没有效果. 如果省略了 MenuItemName, 则效果等同于使用了下面的 NoDefault.

NoDefault: 对于托盘菜单: 让菜单恢复其默认菜单项, 对于未编译脚本为 OPEN 而对于 已编译脚本 则没有 (除非 MainWindow 选项有效). 如果因为之前使用了下面的 NoStandard 命令使得 OPEN 菜单项不存在, 那么将没有默认菜单项, 因此双击托盘图标没有效果. 对于 TRAY 以外的其他菜单: 任何现有的默认项恢复为非加粗字体.

Standard：在菜单底部插入标准菜单项（如果还不存在）。此命令可用于托盘菜单或其他任何菜单.

NoStandard：从托盘菜单移除所有标准（非自定义）的菜单项（如果存在）。

设置或移除菜单项的图标 [AHK_L 17+]

Icon, MenuItemName, FileName [, IconNumber, IconWidth]: 设置 MenuItemName 的图标. FileName 可以为图标文件或 AutoHotkey 支持的格式的任何图像. 要使用文件中的图标组而不是首个图标, 请在 IconNumber 指定它的编号 (如果省略, 则它默认为 1). 如果 IconNumber 为负数，则假定其绝对值表示可执行文件中图标的资源 ID。在 IconWidth 中指定期望的图标宽度. 如果 IconNumber 表示的图标组包含多种大小的图标，则使用最接近的匹配并将图标缩放到指定的大小。请参阅示例部分的用法示例.

当前在 Windows Vista 和更高版本中如果需要被设置的图标保留透明度时, 则必须指定 "真实的大小". 例如：

Menu, MenuName, Icon, MenuItemName, Filename.png,, 0

已知限制: 在 Windows XP 和更早版本中, Gui 菜单栏中的图标无法放置到正确的位置.

NoIcon, MenuItemName：移除MenuItemName的图标（如果有）。

改变托盘图标或工具提示 (MenuName 必须为 TRAY)

Icon [, FileName, IconNumber, 1]: 改变脚本的图标为 FileName 中的某个图标. 支持下列的文件类型: ICO, CUR, ANI, EXE, DLL, CPL, SCR 以及包含图标资源的其他类型. 要使用文件中的图标组而不是首个图标, 请在 IconNumber 指定它的编号 (如果省略, 则它默认为 1). 例如, 2 将加载第二个图标组中的默认图标. 如果 IconNumber 为负数，则假定其绝对值表示可执行文件中图标的资源 ID。在 FileName 指定星号（*）来恢复脚本到其默认图标。

最后一个参数: 在最后一个参数指定 1 来冻结图标, 而 0 则解冻它 (或留空来保持冻结/解冻状态不变). 当图标已经冻结时, Pause 和 Suspend 不会改变它. 注：要冻结或解冻当前的图标，请使用 1 或 0，例如：Menu, Tray, Icon,,, 1。

改变托盘图标同时也改变由 InputBox, Progress 和后续创建的 GUI 窗口显示的图标. 也会影响 已编译脚本, 即使它在编译时指定了自定义的图标. 注：如果之前使用如 #NoTrayIcon 的方法隐藏了托盘图标，则改变图标不会让它显示出来；要让它显示，请使用 Menu, Tray, Icon（不带参数）。

从 .ICO 外的其他类型文件中加载托盘图标时可能产生轻微的变形. 尤其是对于 16x16 的图标. 要避免此问题, 请把要使用的托盘图标保存到 .ICO 文件.

操作系统的 DLL 和 CPL 文件包含的一些图标可能会有用. 例如：Menu, Tray, Icon, Shell32.dll, 174。

内置变量 A_IconNumber 和 A_IconFile 分别包含了当前图标的编号和名称 (带完整路径) (如果为默认图标则两者都为空).

Icon （不带参数）：如果还没有托盘图标则进行创建。如果在脚本中使用了 #NoTrayIcon, 则此命令会覆盖它.

NoIcon: 如果存在托盘图标则移除它. 如果在脚本的最顶部使用此命令, 则当脚本运行时托盘图标可能出现短暂的时间. 要避免这种情况, 请使用 #NoTrayIcon. 如果托盘图标当前是隐藏的, 则内置变量 A_IconHidden 的值为 1, 否则为 0.

Tip [, Text]: 改变托盘图标的工具提示, 这是在鼠标悬停在托盘图标上时显示的. 要创建多行的工具提示, 请在两行之间使用换行符 (`n), 例如 Line1`nLine2. 仅显示Text中的前127个字符，并且如果Text中存在tab字符，则首个此字符后的内容被截除。如果省略 Text, 则把工具提示恢复为默认文本. 内置变量 A_IconTip 包含了当前工具提示的默认文本 (如果文本是默认的, 则为空).

杂项命令

Show [, X, Y]: 显示 MenuName, 允许用户使用方向键, 菜单快捷键 (下划线字母) 或鼠标选择菜单项. 可以显示包括托盘菜单在内的任何菜单, 但 GUI 菜单栏例外. 如果同时省略 X 和 Y, 则菜单显示在鼠标光标的当前位置. 如果仅省略其中一个, 则用鼠标光标的位置代替省略的这个. X 和 Y 相对于活动窗口. 预先指定 "CoordMode, Menu" 可以让它们相对于整个屏幕.

Color, ColorValue [, Single]: 改变菜单的背景颜色为 ColorValue, 它是 16 种 HTML 基础颜色之一或 6 位的 RGB 颜色值 (请参阅 颜色图标). 将 ColorValue 留空 (或指定单词 Default) 来恢复菜单的默认颜色. 如果后一个参数不是单词 Single, 则任何附加到此菜单的子菜单都会改变颜色.

Click, ClickCount: 在 ClickCount 中指定 1 来允许单击激活托盘菜单的默认菜单项. 在 ClickCount 中指定 2 来恢复到默认行为 (双击). 例如：Menu, Tray, Click, 1。

MainWindow: 此命令仅影响 已编译脚本. 它允许用户通过托盘图标打开脚本主窗口, 否则这是不行的. 它同时也启用了主窗口的 View 菜单项 (例如 "Lines most recently executed"), 这样就允许查看脚本的源代码和其他信息. MenuName 必须为 TRAY.

NoMainWindow (默认): 此命令仅影响 已编译脚本. 它恢复脚本的默认行为, 即阻止打开主窗口. 即使此选项有效, 脚本运行中遇到下列命令时仍然会显示主窗口: ListLines, ListVars, ListHotkeys 和 KeyHistory. MenuName 必须为 TRAY.

UseErrorLevel [, off]: 如果脚本中从未使用过此选项, 则它默认为 OFF. 每当 Menu 命令遇到错误时, OFF 设置会显示一个对话框并终止 当前线程. 指定 Menu, Tray, UseErrorLevel 来阻止显示对话框和终止线程；作为替代，如果遇到问题则 ErrorLevel 被设置为 1 否则为 0。要让此选项转回 off, 请在后一个参数中指定 OFF. 此设置是全局的, 这意味着它影响所有的菜单, 而不只是 MenuName.

备注

要给一个菜单项名称中的某个字母加下划线，请在这个字母前加上和符号（&）。当菜单显示时, 通过按下键盘上相应的按键可以选择这样的菜单项. 要显示一个原义的和符号，请指定两个连续的和符号，例如：“Save && Exit”

菜单和菜单项的名称长度最多可达 260 个字符.

引用一个现有的菜单或菜单项时, 名称不区分大小写但必须包含和符号. 例如: &Open

使用 Menu, tray, add（即省略其他所有参数）可以给菜单添加分隔线。不过, 当前不能单独删除分隔线. 要变通解决此问题，请使用 Menu, tray, DeleteAll 然后重新添加自定义菜单项。

新的菜单项总是添加到菜单的底部. 对于托盘菜单：要把您的菜单项放到标准菜单项的上面，（在添加完自定义菜单项后）执行 Menu, tray, NoStandard 后面接着执行 Menu, tray, Standard。

不能使用任何菜单子命令单独操作标准菜单项, 例如 "Pause Script" 和 "Suspend Hotkeys".

如果一个菜单项已变得完全空了（例如使用 Menu, MyMenu, DeleteAll），则无法把它显示出来。如果托盘菜单变成空的, 则右击和双击托盘菜单将没有效果 (此时通常使用 #NoTrayIcon 更好).

如果一个菜单项的子程序已经运行而用户再次选择相同的菜单项, 则会创建一个新 线程 运行相同的子程序, 并中断之前的线程. 要缓冲这样的事件到以后执行, 请在子程序的首行使用 Critical (不过, 这样也将缓冲/延迟其他线程, 例如按下的热键).

每当通过菜单项运行子程序时, 它会使用设置 (例如 SendMode) 的默认值开始. 这些默认值可以在 自动执行段 改变.

内置变量 A_ThisMenuItem 和 A_ThisMenuItemPos 分别包含了最近用户选择的自定义菜单项的名称和位置（如果没有则为空）。同样地, A_ThisMenu 是选择的 A_ThisMenuItem 的菜单名称. 这些变量可用于在创建的菜单内容不总是相同的时候. 在这种情况下, 通常最好把所有这样的菜单项指向相同的标签, 并在此标签中引用上面的变量来决定执行什么动作.

要让非热键且非 GUI 的脚本持续运行 (例如仅包含自定义菜单或菜单项的脚本), 请使用 #Persistent.

相关

GUI, 线程, Thread, Critical, #NoTrayIcon, Gosub, Return, SetTimer, #Persistent

示例

; 示例 #1: 这是个可运行脚本, 它添加一个新菜单项到托盘图标菜单的底部.

#Persistent  ; 让脚本持续运行, 直到用户退出.
Menu, tray, add  ; 创建分隔线.
Menu, tray, add, Item1, MenuHandler  ; 创建新菜单项.
return

MenuHandler:
MsgBox You selected %A_ThisMenuItem% from menu %A_ThisMenu%.
return

; 示例 #2: 这是个可运行脚本, 它创建了一个在用户按下 Win-Z 热键时显示的弹出菜单.

; 添加一些菜单项来创建弹出菜单.
Menu, MyMenu, Add, Item1, MenuHandler
Menu, MyMenu, Add, Item2, MenuHandler
Menu, MyMenu, Add  ; 添加分隔线.

; 添加子菜单到上面的菜单中.
Menu, Submenu1, Add, Item1, MenuHandler
Menu, Submenu1, Add, Item2, MenuHandler

; 创建第一个菜单的子菜单 (右箭头指示符). 当用户选择它时会显示第二个菜单.
Menu, MyMenu, Add, My Submenu, :Submenu1

Menu, MyMenu, Add  ; 在子菜单下添加分隔线.
Menu, MyMenu, Add, Item3, MenuHandler  ; 在子菜单下添加另一个菜单项.
return  ; 脚本的自动运行段结束.

MenuHandler:
MsgBox You selected %A_ThisMenuItem% from the menu %A_ThisMenu%.
return

#z::Menu, MyMenu, Show  ; 即按下 Win-Z 热键来显示菜单.

; 示例 #3: 这是个可运行脚本, 它演示了一些菜单命令.

#Persistent
#SingleInstance
menu, tray, add ; 分隔符
menu, tray, add, TestToggle&Check
menu, tray, add, TestToggleEnable
menu, tray, add, TestDefault
menu, tray, add, TestStandard
menu, tray, add, TestDelete
menu, tray, add, TestDeleteAll
menu, tray, add, TestRename
menu, tray, add, Test
return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TestToggle&Check:
menu, tray, ToggleCheck, TestToggle&Check
menu, tray, Enable, TestToggleEnable ; 同时启用了下一行的测试, 因为它不能撤销自己的禁用状态.
menu, tray, add, TestDelete ; 类似于上面.
return

TestToggleEnable:
menu, tray, ToggleEnable, TestToggleEnable
return

TestDefault:
if default = TestDefault
{
    menu, tray, NoDefault
    default =
}
else
{
    menu, tray, Default, TestDefault
    default = TestDefault
}
return

TestStandard:
if standard <> n
{
    menu, tray, NoStandard
    standard = n
}
else
{
    menu, tray, Standard
    standard = y
}
return

TestDelete:
menu, tray, delete, TestDelete
return

TestDeleteAll:
menu, tray, DeleteAll
return

TestRename:
if NewName <> renamed
{
    OldName = TestRename
    NewName = renamed
}
else
{
    OldName = renamed
    NewName = TestRename
}
menu, tray, rename, %OldName%, %NewName%
return

Test:
MsgBox, You selected "%A_ThisMenuItem%" in menu "%A_ThisMenu%".
return
; 示例 #4: 这是个添加图标到其菜单项的可运行脚本.
Menu, FileMenu, Add, Script Icon, MenuHandler
Menu, FileMenu, Add, Suspend Icon, MenuHandler
Menu, FileMenu, Add, Pause Icon, MenuHandler
Menu, FileMenu, Icon, Script Icon, %A_AhkPath%, 2 ;使用文件中的第二个图标组
Menu, FileMenu, Icon, Suspend Icon, %A_AhkPath%, -206 ;使用资源标识符 206 表示的图标
Menu, FileMenu, Icon, Pause Icon, %A_AhkPath%, -207 ;使用资源表示符 207 表示的图标
Menu, MyMenuBar, Add, &File, :FileMenu
Gui, Menu, MyMenuBar
Gui, Add, Button, gExit, Exit This Example
Gui, Show
MenuHandler:
Return

Exit:
ExitApp


MsgBox

在含有一个或多个按钮（例如“是”和“否”）的小窗口中显示指定的文本 。

MsgBox, Text
MsgBox [, Options, Title, Text, Timeout]

参数

文本

如果省略所有的参数，MsgBox 会显示“Press OK to continue.”文本。否则，此参数表示消息框中显示的文本，用来引导用户如何操作或提示信息。

可以使用 转义序列 来显示特殊字符. 例如, `n 表示换行符, 它结束当前行并开始一个新行. 因此使用 text1`n`ntext2 会在 text1 和 text2 之间添加一个空行.

如果 Text 较长, 可以通过 延续片段 的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

选项

表示消息框的类型和合适的按钮组合。如果为空或省略，则默认为 0。请参阅下表来了解允许的值.

此参数必须为原义的数字或（在 v1.1.06+）强制表达式，例如 % Options。其他任何非空值都不会被看做是此参数, 相反的只是被认为是单参数模式中 Text 的一部分.

标题

消息框窗口的标题。如果省略或为空, 那么它默认为脚本的名称 (不含路径).

超时

（可选）以秒为单位的超时时间，默认情况下可以为小数但不能是表达式。在 v1.1.06+，此参数可以强制为表达式，例如 % mins*60。

如果这个值超过 2147483（24.8 天），那么它会被设置为 2147483。经过这个超时时间后消息框将自动关闭且 IfMsgBox 命令将看到表示超时状态的值 TIMEOUT。

已知限制: 如果 MsgBox 仅含有一个 "确定" 按钮, 且当 MsgBox 自身的 线程 被其他线程中断时超时了, 那么 IfMsgBox 将认为用户按下了 "确定" 按钮.

Options 参数可以为一个或多个下列值的组合（和）。

功能 | 十进制值 | 十六进制值
确定 (即仅显示一个 "确定" 按钮) | 0 | 0x0
确定/取消 | 1 | 0x1
终止/重试/忽略 | 2 | 0x2
是/否/取消 | 3 | 0x3
是/否 | 4 | 0x4
重试/取消 | 5 | 0x5
Cancel/Try Again/Continue | 6 | 0x6
添加一个 "帮助" 按钮 (请参阅后面的备注) | 16384 | 0x4000
错误图标 (停止/错误) | 16 | 0x10
问号图标 | 32 | 0x20
惊叹号图标 | 48 | 0x30
星号图标 (信息) | 64 | 0x40
让第二个按钮成为默认按钮 | 256 | 0x100
让第三个按钮成为默认按钮 | 512 | 0x200
系统模态 (总是在顶部) | 4096 | 0x1000
任务模态 | 8192 | 0x2000
总是在顶部 (WS_EX_TOPMOST 样式) (和系统模态类似, 但省略了标题栏图标) | 262144 | 0x40000
让文本右对齐显示 | 524288 | 0x80000
用于希伯来语/阿拉伯语的从右向左的阅读顺序 | 1048576 | 0x100000

备注

使用上面的表格时, 可以把您期望用于 MsgBox 的选项值加在一起. 例如, 要显示一个默认按钮为 "否" 的 "是"/"否" 消息框, 那么需要把 Options 的值设置为 256+4 (260). 使用十六进制表示为 0x100+0x4 (0x104).

MsgBox 对逗号的处理比较智能, 所以通常不需要对 Text 参数中的逗号进行 转义.

要判断用户在最近的 MsgBox 中按下了哪个按钮, 请使用 IfMsgBox 命令. 例如：

MsgBox, 4,, Would you like to continue? (press Yes or No)
IfMsgBox Yes
    MsgBox You pressed Yes.
else
    MsgBox You pressed No.

参照 这个例子 可以自定义按钮的名称.

提示: 当 MsgBox 窗口活动时按下 Control-C 将复制其中的文本到剪贴板. 这适用于所有的 MsgBox, 而不仅是 AutoHotkey 生成的那些.

在 GUI 窗口中使用 MsgBox: 通过 Gui +OwnDialogs 的方法可以在 GUI 窗口中显示 模态 MsgBox. 模态 MsgBox 在其消失之前会阻止用户与原来的 GUI 窗口进行交互。此时, 不需要指定上表中的系统模态或任务模态选项.

当 Gui +OwnDialogs 无效 时, 在用户响应 MsgBox 前可以使用任务模态选项 (8192) 来禁用所有的脚本窗口.

"帮助" 按钮: 在 Options 中使用了 "帮助" 按钮选项 (83) 时, 只有符合下面两个条件, 那么按下 "帮助" 按钮才会有效果:

  1. MsgBox 是由 GUI 窗口通过 Gui +OwnDialogs 的方法显示的.
  2. 脚本正在监听 WM_HELP 消息 (0x53). 例如：OnMessage(0x53, "WM_HELP")。调用 WM_HELP() 函数时, 它可以通过如显示另一个窗口或 MsgBox 的方法引导用户.

关闭按钮（在 MsgBox 的标题栏）：由于 MsgBox 窗口是操作系统内置的特性，所以它的 X 按钮仅在某些按钮存在时才会启用。如果只有一个 "确定" 按钮, 那么点击 X 按钮等同于按下 "确定" 按钮. 其他情况下, 只有含有 "取消" 按钮时才会启用 X 按钮, 此时点击 X 等同于按下 "取消" 按钮.

相关

IfMsgBox, InputBox, FileSelectFile, FileSelectFolder, ToolTip, GUI

示例

MsgBox This is the 1-parameter method. Commas (,) do not need to be escaped.
MsgBox, 4, , This is the 3-parameter method. Commas (,) do not need to be escaped.
MsgBox, 4, , Do you want to continue? (Press YES or NO)
IfMsgBox No
    return
MsgBox, 4, , 4-parameter method: this MsgBox will time out in 5 seconds.  Continue?, 5
IfMsgBox Timeout
    MsgBox You didn't press YES or NO within the 5-second period.
else IfMsgBox No
    return

; 通过在任何参数前加上“% ”，可以让此参数支持表达式。在下面的例子中，
; 执行数学运算、访问伪数组元素且调用函数。所有这些项
; 都可以通过“.”运算符串联成 MsgBox 可以显示的单个字符串：
MsgBox % "New width for object #" . A_Index . " is: " . RestrictWidth(ObjectWidth%A_Index% * ScalingFactor)

; 下面的例子提醒用户 MsgBox 即将获取焦点（此时用户正在输入）。
SplashTextOn,,, A MsgBox is about to appear.
Sleep 3000
SplashTextOff
MsgBox The backup process has completed.


Progress / SplashImage

创建或更新含有进度条或图像的窗口.

SplashImage, Off
SplashImage [, ImageFile, Options, SubText, MainText, WinTitle, FontName]

Progress, Off
Progress, ProgressParam1 [, SubText, MainText, WinTitle, FontName]

参数

ImageFile

如果此参数为单词 OFF, 则销毁窗口. 如果它为单词 SHOW, 则显示当前隐藏的窗口.

否则, 此参数为要显示的 BMP, GIF 或 JPG 图像的文件名 (要显示其他格式的图像例如 PNG, TIF 以及 ICO, 请考虑使用 Gui 命令创建包含图片控件的窗口).

[AHK_L 59+]: 任何 Gui 支持的图像格式都可用于 SplashImage.

如果未指定绝对路径则假定 ImageFile 在 %A_WorkingDir% 中. 如果 ImageFile 和 Options 都为空且窗口已经存在, 则窗口中的图像保持不变, 但其中的文本将更新为由 SubText, MainText 以及 WinTitle 提供的新字符串.

对于新创建的窗口, 如果 ImageFile 为空或加载图片时出现问题, 那么显示的窗口中将不含图片.

ProgressParam1

如果进度条窗口已经存在: 如果 Param1 为单词 OFF, 则销毁进度条窗口. 如果 Param1 为单词 SHOW, 则显示当前隐藏的窗口.

否则, 如果 Param1 是一个数字, 则更新进度条的位置为这个值. 如果 Param1 为空, 则其进度条位置保持不变, 但其中的文本将更新为由 SubText, MainText 以及 WinTitle 提供的新字符串. 在这两个形式中, 如果进度条窗口已经不存在, 则使用所有选项的默认值进行创建.

如果进度条窗口不存在: 创建新的进度条窗口 (替换任何旧的), 此时 Param1 是由下表中零个或多个选项组成的字符串.

选项

此参数是由较远的下面列表中零个或多个选项组成的字符串.

SubText

显示在图像或进度条下面的文本. 尽管会自动换行, 但如果要明确开始新行, 请使用 (`n). 要设置现有窗口的文本为空, 请指定 %A_Space%. 为了自动计算窗口的高度, 可以像下面的 MainText 那样保留空行.

MainText

显示在图像或进度条上面的文本 (其字体为半粗体). 尽管会自动换行, 但如果要明确开始新行, 请使用 (`n).

如果为空或省略, 则窗口中不会预留空间给 MainText. 要为以后添加内容预留单行空间, 或设置现有窗口的文本为空, 请指定 %A_Space%. 要预留多行的空间, 请添加一个或多个换行符 (`n).

当设置好 MainText 的控件区域的高度后, 这个高度只有重新创建窗口才能改变.

WinTitle

窗口标题. 如果省略并且正新建窗口, 则使用脚本名称 (不带路径) 作为窗口标题. 如果指定了 B (无边框) 选项, 则会看不见窗口的标题栏, 但是在诸如 WinMove 的命令中仍可以通过这个标题引用此窗口.

FontName

用于 MainText 和 SubText 中文本的字体名称. 字体表中列出了 Windows 系统各种版本中包含的字体。如果未指定或无法找到指定的字体, 则使用系统默认的 GUI 字体.

关于如何改变字体的大小, 粗细和颜色, 请参阅下面的选项部分.

窗口的大小, 位置和行为

A: 窗口将 不 总是置顶.

B: 无边框: 窗口将不含有边框和标题栏. 要含有边框而没有标题栏, 请使用 B1 添加薄边框或 B2 添加对话框样式的边框.

M: 用户可以移动窗口 (除非不含有边框). 此外, 要让窗口大小可以调整 (通过拖动边框的方法), 请指定 M1. 此外, 要让窗口的标题栏中包含系统菜单和最小化/最大化/关闭按钮的集合, 请指定 M2.

Pn: 对于进度条窗口, 请指定 n 为进度条的初始位置 (默认值为 0 或者是允许的范围内最接近 0 的数字). 以后要改变进度条的位置，请参照此例：Progress, 50。

Rx-y: 对于进度条窗口, 请指定 x-y 为进度条的数值范围 (如果没有使用 R 选项, 则默认为 0-100). 例如，R0-1000 将允许一个介于 0 和 1000 之间的数字；R-50-50 将允许介于 -50 和 50 之间的数字；而 R-10--5 将允许介于 -10 和 -5 之间的数字。

T: 给窗口增加任务栏按钮并使窗口变成非从属的/独立的. 一般情况下, 从属于脚本主窗口的窗口是没有任务栏按钮的. 此设置也避免了 GUI 窗口使用 Gui +OwnDialogs 的方法获取弹出窗口或进度条窗口的所有权关系.

Hn: 指定 n 为窗口工作区的高度 (这是窗口中不包括标题栏和边框的区域). 如果未指定, 那么将根据图像/进度条和文本的高度 自动 计算窗口的高度.

Wn: 指定 n 为窗口工作区的宽度. 如果未指定，则根据SplashImage（如果含有图像）自动计算窗口的宽度。否则, 它默认为 300.

Xn: 指定 n 为窗口左上角的 x 坐标. 如果未指定, 则窗口在屏幕上将水平居中.

Yn: 指定 n 为窗口左上角的 y 坐标. 如果未指定, 则窗口在屏幕上将垂直居中.

Hide: 窗口初始为隐藏状态. 以后要显示时请使用 Progress Show 或 SplashImage Show。

窗口中的组件布局

Cxy: 居中: 如果未使用此选项, 则 SubText 和 MainText 都将在窗口内居中显示. 指定 x 为 0 来让 SubText 向左对齐. 指定为 1 来让它居中. 在 y 中指定相同的值效果是一样的, 不过其应用于 MainText (y 可以省略). 例如：c10。

ZHn: 组件的高度: 对于进度条窗口, 指定 n 为进度条的厚度 (默认为 20). 对于 SplashImage 窗口, 指定 n 为图像的高度. 指定 -1 来让高度自适应于在 ZWn 中指定的宽度 (即 "保持高宽比"). 如果未指定, 则使用图像的实际高度. 在这两种情况中, 指定 0 来不显示整个组件, 此时允许窗口仅显示自定义字体样式, 大小和颜色的文本.

ZWn: 组件的宽度 (仅适用于 SplashImage): 指定 n 为图像的宽度. 指定 -1 来让宽度自适应于在 ZHn 中指定的高度 (即 "保持高宽比"). 如果未指定, 则使用图像的实际宽度.

ZXn: 指定 n 为窗口左/右边缘的空白大小总和. 对于不含文本的 SplashImage 窗口默认大小为 0, 其他情况默认大小为 10.

ZYn: 指定 n 为窗口顶部和底部以及每个控件间在垂直方向上空白空间的大小总和. 对于不含文本的 SplashImage 窗口默认大小为 0, 其他情况默认为 5.

注: 要创建垂直的进度条或进行更灵活地窗口布局, 请使用 Gui 命令, 例如:

Gui, Add, Progress, Vertical vMyProgress
Gui, Show
return
; ... 后面...
GuiControl,, MyProgress, +10  ; 把进度条向前移动 10%. 省略 + 来设置绝对的位置.

字体大小和粗细

FMn: 指定 n 为 MainText 中的字体大小. 默认为 0, 此时在大多数系统中会使用 10 作为字体大小. 此默认值不会影响在控制面板 > 显示设置中系统选择的字体大小.

FSn: 指定 n 为 SubText 中的字体大小. 默认为 0, 此时在大多数系统中会使用 8 作为字体大小.

WMn: 指定 n 为 MainText 中的字体粗细. 字体粗细应该介于 1 和 1000 之间. 如果未指定, 则使用 600 (半粗体).

WSn: 指定 n 为 SubText 中的字体粗细. 字体粗细应该介于 1 和 1000 之间 (700 一般被认为是 "粗体"). 如果未指定, 则使用 400 (正常字体).

组件颜色

颜色值可以是下表中的其中一个名称 或 6 位的十六进制 RGB 值. 例如，指定 cw1A00FF 将设置窗口背景颜色中红色通道为 1A，绿色通道为 00，而蓝色通道为 FF。

如果在每个颜色选项后面还跟着更多的选项, 则请在颜色选项后添加空格. 例如：cbRed ct900000 cwBlue。

CBn: 进度条的颜色: 指定 n 为 16 种 HTML 基础颜色之一或 6 位的 RGB 颜色值. 如果未指定, 则使用系统默认的进度条颜色. 指定单词 Default 来返回到系统的默认进度栏颜色.

CTn: 文本颜色: 指定 n 为 16 种 HTML 基础颜色之一或 6 位的 RGB 颜色值. 如果未指定, 则使用系统默认的文本颜色 (通常为黑色). 指定单词 Default 来返回到系统默认的文本颜色.

CWn: 窗口颜色 (背景): 指定 n 为 16 种 HTML 基础颜色之一或 6 位的 RGB 颜色值. 如果未指定, 则使用按钮外观的系统颜色 (以后指定单词 Default 来返回到此颜色). 要让窗口的背景透明，请使用 WinSet TransColor。

颜色名称和相应的 RGB 值
Black = 000000 | Green = 008000
Silver = C0C0C0 | Lime = 00FF00
Gray = 808080 | Olive = 808000
White = FFFFFF | Yellow = FFFF00
Maroon = 800000 | Navy = 000080
Red = FF0000 | Blue = 0000FF
Purple = 800080 | Teal = 008080
Fuchsia = FF00FF | Aqua = 00FFFF

备注

如果首个参数为单词 OFF, 则销毁窗口.

每个脚本可以显示多达 10 个进度窗口和 10 个 SplashImage 窗口. 创建每个窗口时都会给它分配一个编号. 如果未指定, 则此编号为 1 (对于首个窗口). 否则, 请在首个参数前加上窗口编号和冒号. 例如，带有 2:Off 参数的 Progress 命令将关闭编号为 2 的进度条窗口，2:75 将设置其进度条到 75% 的位置，2: 将改变其一个或多个文本区域，而 2:B 将创建新的无边界进角度条窗口。同样地，带有 2:Off 参数的 SplashImage 命令将关闭编号为 2 的 SplashImage 窗口，2: 将改变其一个或多个文本区域，而 2:C:\My Images\Picture1.jpg 将创建新的编号为 2 的 SplashImage 窗口。

在创建时, 大于桌面的窗口会被自动缩小以适应桌面.

指定 SubText 和 MainText 为空且包含下列选项：b zx0 zy0，可以显示单独的进度条。加上 B 选项后, 用相同的方法可以显示单独的图像.

在 Windows XP 或更高版本中, 如果当前使用的不是经典主题, 则进度条的内部可能显示为一段段而不是平滑连续的条. 要避免这种情况, 请明确指定进度条颜色, 例如 cbBlue.

除非特别注明, 否则在需要数字的选项字母中使用十进制数 (而不是十六进制数).

像 WinSet 和 WinMove 这样的命令可以改变现有窗口的属性而不必重新创建窗口.

GUI 窗口可以使用 Gui +OwnDialogs 的方法获取进度条窗口或弹出窗口的所有权. 这会使得弹出窗口或进度条窗口总是保持在其父窗口的前面. 此外, 当其从属的 GUI 窗口销毁时, 进度条窗口或弹出窗口会自动销毁.

相关

GUI, SplashTextOn, ToolTip

示例

Progress, b w200, My SubText, My MainText, My Title
Progress, 50 ; 设置进度条的位置为 50%.
Sleep, 4000
Progress, Off

; 创建只用来显示一些18 磅 Courier 文本的窗口:
Progress, m2 b fs18 zh0, This is the Text.`nThis is a 2nd line., , , Courier New

; 创建简单的 SplashImage 窗口:
SplashImage, C:\My Pictures\Company Logo.gif

; 创建无边框的 SplashImage 窗口, 在其中图像的下面显示一些大文本:
SplashImage, C:\My Pictures\Company Logo.gif, b fs18, This is our company logo.
Sleep, 4000
SplashImage, Off

; 这是个可运行示例, 它演示了如何把进度条窗口覆盖在
; SplashImage 的上面来生成专业外观的安装程序屏幕:
IfExist, C:\WINDOWS\system32\ntimage.gif, SplashImage, %A_WinDir%\system32\ntimage.gif, A,,, Installation
Loop, %A_WinDir%\system32\*.*
{
    Progress, %a_index%, %a_loopfilename%, Installing..., Draft Installation
    Sleep, 50
    if a_index = 100
        break
}
; 在 GUI 页面 的底部有一个类似的例子. 它的优点是只使用了
; 一个窗口并且可以对窗口布局进行更好的控制.


SplashTextOn / SplashTextOff

创建自定义文本的弹出窗口。

SplashTextOff
SplashTextOn [, Width, Height, Title, Text]

参数

Width

以像素为单位的窗口宽度. Default 200. 此参数可以为 表达式.

Height

窗口（不包括标题栏）的高度，单位为像素。默认为 0 (即只显示标题栏). 此参数可以为 表达式.

标题

窗口标题. 默认为空.

文本

窗口的文本. 默认为空. 如果 Text 较长, 可以通过 延续片段 的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

备注

要对布局和字体名称/颜色/大小进行更多的控制，请使用带 zh0 选项的 Progress 命令，它不显示标题栏而只显示文本。例如：Progress, zh0 fs18, Some 18-point text to display。

使用 SplashTextOff 命令来移除现有的弹出窗口.

弹出窗口是 "置顶的", 意味着它总是保持在其他所有普通窗口的上面. 要改变这种状态，请使用 WinSet, AlwaysOnTop, Off, <insert title of splash window>。WinSet 还可以让弹出窗口透明。

WinMove 可以用来对此命令显示的 SplashText 窗口进行移动和调整大小.

与 Progress, SplashImage, MsgBox, InputBox, FileSelectFile 以及 FileSelectFolder 不同, 每个脚本只能显示一个 SplashText 窗口.

如果在已经显示弹出窗口时使用 SplashTextOn, 则使用新的参数值重新创建窗口. 然而, 当您想改变弹出窗口的标题或文本时与其重新创建弹出窗口, 不如使用下列方法来获得更好的性能, 尤其在需要频繁改变窗口时:

WinSetTitle, <insert title of splash window>, , NewTitle
ControlSetText, Static1, NewText, <insert title of splash window>

相关

Progress, SplashImage, ToolTip, MsgBox, InputBox, FileSelectFile, FileSelectFolder, WinMove, WinSet

示例

SplashTextOn, , , Displays only a title bar.
Sleep, 2000
SplashTextOn, 400, 300, Clipboard, The clipboard contains:`n%clipboard%
WinMove, Clipboard, , 0, 0  ; 把弹出窗口移动到左上角.
Msgbox, Press OK to dismiss the SplashText
SplashTextOff


ToolTip

在屏幕的任意位置创建总是置顶的窗口。

ToolTip [, Text, X, Y, WhichToolTip]

参数

文本

如果为空或省略，则隐藏现有的工具提示（如果有）。否则, 此参数为要在工具提示中显示的文本. 要创建多行的工具提示, 请在两行之间使用换行符 (`n), 例如 Line1`nLine2.

如果 Text 较长, 可以通过 延续片段 的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

X, Y

相对于活动窗口的 X 和 Y 坐标（请使用 CoordMode, ToolTip 来让坐标相对于屏幕）。如果省略坐标, 则工具提示显示在鼠标光标附近. X 和 Y 可以为表达式。

WhichToolTip

如果您不需要同时显示多个工具提示, 请省略此参数. 否则, 请指定 1 和 20 之间的一个数字来表示要操作的工具提示窗口编号. 如果未指定, 则此编号为 1 (对于首个窗口). 此参数可以为 表达式.

备注

如果 X & Y 坐标会让工具提示离开屏幕, 则会对其进行重新定位以使其完全可见.

工具提示会一直显示, 直到出现下列的其中一种情况:

  • 脚本终止.
  • 再次执行了 Text 参数为空的 ToolTip 命令.
  • 用户点击了工具提示 (此行为可能因操作系统版本而变化).

GUI 窗口可以使用 Gui +OwnDialogs 的方法成为工具提示的拥有者. 这样的工具提示在其拥有者被销毁时也会自动被销毁.

相关

CoordMode, TrayTip, GUI, Progress, SplashTextOn, MsgBox, InputBox, FileSelectFile, FileSelectFolder

示例

ToolTip, Multiline`nTooltip, 100, 150

; 要让工具提示在一段时间后消失
; 而不使用 Sleep 的方法 (它停止了当前线程):
#Persistent
ToolTip, Timed ToolTip`nThis will be displayed for 5 seconds.
SetTimer, RemoveToolTip, 5000
return

RemoveToolTip:
SetTimer, RemoveToolTip, Off
ToolTip
return


TrayTip

在托盘图标附近创建气球提示窗口。

TrayTip [, Title, Text, Seconds, Options]

参数

标题

如果省略所有参数, 则移除任何当前显示的托盘提示窗口.

否则, 此参数为窗口标题, 可以长达 73 个字符 (超出此长度的字符不会显示出来).

如果 Title 为空, 则会移除气球窗口中的标题行, 这会让它垂直高度变短.

文本

如果此参数省略或为空, 则移除当前显示的任何托盘提示窗口.

否则, 请指定要显示的消息, 它会显示在 Title 的下面. 仅显示 Text 中前 265 个字符. 可以使用回车 (`r) 或换行 (`n) 来创建多行文本. 例如：Line1`nLine2。

如果 Text 较长, 可以通过 延续片段 的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

秒

要窗口显示的近似秒数, 达到这时间后它会被操作系统自动移除. 指定小于 10 或大于 30 的数字时通常会使用最小 (10) 或最大 (30) 的显示时间代替。如果为空或省略, 则一般使用最小的时间. 此参数可以为 表达式.

真实的时间可能不同于指定的时间. 微软解释说，“如果用户没有在使用计算机，那么系统不会被这个时间计算为超时前经过的时间。”（技术细节请参阅此处。）因此，要更精确地控制托盘提示显示的时间，请使用 Sleep 命令后面跟着不带参数的 TrayTip，或像下面的示例中演示的那样使用 SetTimer。

选项

指定下列数字的其中一个来让小图标显示在 Title 的左边:

1: 信息图标
2: 警告图标
3: 错误图标

如果省略, 则它默认为 0, 此时没有图标. 此参数可以为 表达式.

备注

如果脚本没有托盘图标（使用 #NoTrayIcon 或 Menu, tray, NoIcon），则不会显示托盘提示的气球窗口。同样地, 如果下列的 REG_DWORD 值已经存在且被设置为 0, TrayTip 不起作用:

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced >> EnableBalloonTips

在显示气球提示时操作系统通常会播放声音. 此声音可以通过 Options 参数中加上 16 来禁止（即 16 为无声音无图标，17 为无声音信息图标等等）。

相关提示, 每当用户把鼠标悬停在脚本托盘图标上时会显示工具提示. 此工具提示的内容可以使用这样的方法改变：Menu, Tray, Tip, My New Text。

相关

ToolTip, SetTimer, Menu, SplashTextOn, MsgBox, InputBox, FileSelectFile, FileSelectFolder

示例

TrayTip, My Title, Multiline`nText, 20, 17

; 要更精确的控制显示的时间
; 而不使用 Sleep 的方法 (它停止了当前线程):
#Persistent
TrayTip, Timed TrayTip, This will be displayed for 5 seconds.
SetTimer, RemoveTrayTip, 5000
return

RemoveTrayTip:
SetTimer, RemoveTrayTip, Off
TrayTip
return

; 要让托盘提示永久显示, 请使用计时器进行周期性的刷新:
SetTimer, RefreshTrayTip, 1000
Gosub, RefreshTrayTip  ; 调用一次来让它立即开始.
return

RefreshTrayTip:
TrayTip, Refreshed TrayTip, This is a more permanent TrayTip., , 16
return


#HotkeyInterval

与 #MaxHotkeysPerInterval 一起指定热键激活的速率，超过此速率会显示警告对话框。

#HotkeyInterval Milliseconds

参数

Milliseconds

间隔长度，单位为毫秒。

备注

如果脚本中未使用此指令, 那么它会表现的就像此设置为 2000 那样.

更多细节和注意事项, 请参阅 #MaxHotkeysPerInterval.

相关

#MaxHotkeysPerInterval

示例

#HotkeyInterval 2000  ; 这是默认值 (毫秒).
#MaxHotkeysPerInterval 200


#HotkeyModifierTimeout

影响热键修饰符的行为：CTRL、ALT、WIN 和 SHIFT。

#HotkeyModifierTimeout Milliseconds

参数

Milliseconds

间隔长度，单位为毫秒。此值设为 -1 时, 它永远不会超时 (在 Send 后修饰键总是被推回到按下的状态), 设为 0 时则总是超时 (修饰键总是不会被推回到按下的状态).

备注

在下列情况中 不需要 使用此指令:

  • 热键通过 SendInput 或 SendPlay 模式发送键击. 这是由于这些模式会延迟用户的物理键击到 Send 完成后.
  • 脚本安装了键盘钩子（您可以通过主窗口中的“View->Key history”菜单项或KeyHistory命令判断您的脚本是否使用了钩子）。这是由于钩子可以记录用户实际按住的修饰键 (ALT/CTRL/WIN/SHIFT), 因而不需要使用超时.

为了说明此指令的效果，请看这个例子：^!a::Send, abc。

执行 Send 命令时, 它会首先释放 CTRL 和 ALT 键, 这样才能正确发送这些字符. 在发送所有键击后, 此命令不知道它是否可以安全的推回 CTRL 和 ALT 到原来的按下状态 (为了和用户仍然按住它们相匹配). 但是如果流逝的时间小于指定的毫秒数, 那么它会认为用户还没有释放按键并把它们推回到按下的状态以匹配物理状态. 否则, 修饰键不会被推回到按下的状态, 而用户必须再次按下它们来修饰同一个或其他的热键.

超时的时间值应该设置为小于用户在释放热键修饰符前按住它们的时间. 否则, 即使用户已经释放了修饰键时它们仍可能被恢复到按下的状态 (卡住).

在下列情况中您可以减少或不使用此指令:

  • 在脚本的任意位置添加 #InstallKeybdHook 来安装键盘钩子。
  • 使用 SendInput 或 SendPlay 模式而不使用传统的 SendEvent 模式.
  • 使用传统的 SendEvent 模式时, 减小 SetKeyDelay 为 0 或 -1, 这样可以快速发送键击因而会有些帮助.

如果脚本中未使用此指令, 那么它会表现的就像此设置为 50.

相关

GetKeyState

示例

#HotkeyModifierTimeout 100


#Hotstring

改变热字串选项或终止符。

#Hotstring NoMouse
#Hotstring EndChars NewChars
#Hotstring NewOptions

参数

NoMouse

阻止鼠标点击像 这里 描述的那样重置热字串识别器. 副作用是, 这样也阻止了热字串需要的 鼠标钩子 (尽管在其他地方需要时脚本仍然会安装鼠标钩子, 例如鼠标热键). 在脚本的任意位置使用 #Hotstring NoMouse 会影响所有的热字串，而不只是影响在它后面的那些。

EndChars NewChars

指定单词 EndChars 后跟着单个空格和新的终止符. 例如：

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

由于不管使用 EndChars 指令的位置如何, 新的终止符都对整个脚本有效, 所以不需要多次使用 EndChars.

终止符的字符数最大为 100. 超出此长度的字符被忽略.

要让 tab 成为终止符, 请在列表中包含 `t. 要让空格成为终止符, 请在列表的其他两个字符中间包含空格 (如果列表中除空格外只包含一个或不包含其他字符, 那么要把空格放在列表的开始处).

NewOptions

根据 热字串选项 中的描述在这里指定新选项. 例如：#Hotstring r s k0 c0。

与上面的 EndChars 不同, #Hotstring 指令在这种方式中是与位置有关的. 换句话说, 热字串的整个部分可以使用不同的默认选项, 例如:

::btw::by the way

#Hotstring r c  ; 默认情况下后面的所有热字串会使用 "send raw" 且区分大小写.
::al::airline
::CEO::Chief Executive Officer

#Hotstring c0  ; 让从这里往后的所有热字串不区分大小写.

相关

热字串


#If

#If [AHK_L]

创建上下文相关的热键和热字串。这样的热键会根据表达式的结果执行不同的操作 (或什么都不做).

#If [, Expression ]

参数

Expression

任何有效的 表达式.

基本操作

可以使用任何有效的表达式定义激活热键的上下文. 例如：

#If WinActive("ahk_class Notepad") or WinActive(MyWindowTitle)
#Space::MsgBox You pressed Win+Spacebar in Notepad or %MyWindowTitle%.

与 #IfWin 指令一样, #If 是与位置有关的: 它会作用于脚本中实际在它后面的所有热键和热字串. #If 和 #IfWin 也是互斥的; 即只有最近的 #If 或 #IfWin 会起作用.

要关闭上下文相关性, 请指定 #If 或任一 #IfWin 指令但省略所有参数. 例如：

#If

一般说明

当按下的按键组合形成了热键时, #If 表达式的计算结果决定了是否激活热键. 只有在表达式计算完成或超时后系统才会响应键盘或鼠标输入。在计算这个表达式过程中发送键击或鼠标点击（例如来自它所调用的函数）可能导致复杂的情况，应该避免这样做。

由于 AutoHotkey 设计的问题，在单个键盘或鼠标事件时可能会计算这个表达式两次。

由于前面所说的原因，应该把这个表达式设计为尽快结束并且不会产生副作用。

[AHK_L 53+]: A_ThisHotkey 和 A_TimeSinceThisHotkey 包含与当前正在求值的 #If 表达式的热键相关的值.

[v1.0.95.00+]: A_PriorHotkey 和 A_TimeSincePriorHotkey 临时包含了与对应的 "This" 变量包含的前一个值.

相关

大部分 #IfWin 指令的行为属性也适用于 #If.

可以使用 #IfTimeout 覆盖默认的超时时间值.

示例

; 示例 1: 在任务栏上滚动鼠标来调节音量.
#If MouseIsOver("ahk_class Shell_TrayWnd")
WheelUp::Send {Volume_Up}
WheelDown::Send {Volume_Down}

MouseIsOver(WinTitle) {
    MouseGetPos,,, Win
    return WinExist(WinTitle . " ahk_id " . Win)
}

; 示例 2: 在所有的编辑控件中的轻松删除单词的快捷键.
#If ActiveControlIsOfClass("Edit")
^BS::Send ^+{Left}{Del}
^Del::Send ^+{Right}{Del}

ActiveControlIsOfClass(Class) {
    ControlGetFocus, FocusedControl, A
    ControlGet, FocusedControlHwnd, Hwnd,, %FocusedControl%, A
    WinGetClass, FocusedControlClass, ahk_id %FocusedControlHwnd%
    return (FocusedControlClass=Class)
}

; 示例 3: 与上下文不相关的热键.
#If
Esc::ExitApp

; 示例 4: 动态热键. 需要示例 1.
NumpadAdd::
Hotkey, If, MouseIsOver("ahk_class Shell_TrayWnd")
if (doubleup := !doubleup)
    Hotkey, WheelUp, DoubleUp
else
    Hotkey, WheelUp, WheelUp
return

DoubleUp:
Send {Volume_Up 2}
return


#IfTimeout

#IfTimeout [AHK_L 8+]

设置计算单个 #If 表达式可以使用的最大时间.

#IfTimeout Timeout

参数

超时

全局有效的超时时间值, 单位为毫秒.

备注

设置超时时间是为了防止长时间计算表达式而延迟了键盘输入的处理. 如果超过了此超时时间值，则会继续计算表达式，但键盘钩子将假定表达式结果为假而继续执行。

如果脚本中未使用此指令, 那么它会表现的就像此设置为 1000 那样.

注意系统使用它自己的超时时间. 如果超过了系统的超时时间, 那么可能会同时激活热键和按键原有的功能. 系统超时时间值定义为 DWORD 类型值 LowLevelHooksTimeout, 并保存在后面的注册表键中:

HKEY_CURRENT_USER\Control Panel\Desktop

相关

#If

示例

#IfTimeout 10 ; 设置超时时间为 10 ms.


#IfWinActive / #IfWinExist

创建上下文相关的热键和热字串。这样的热键会根据窗口是否活动或存在的不同情况执行不同的动作（或什么都不做）。

#IfWinActive [, WinTitle, WinText]
#IfWinExist [, WinTitle, WinText]
#IfWinNotActive [, WinTitle, WinText]
#IfWinNotExist [, WinTitle, WinText]
#If [, Expression]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

匹配行为由自动执行段中设置的 SetTitleMatchMode 决定。

和其他大多数指令一样，不支持变量。尽管可通过 ahk_pid 和 ahk_id 使用硬编码的进程或窗口 ID，不过直接通过 GroupAdd 或 Hotkey IfWin 使用 #IfWin 更常见。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 只有在自动执行段 (脚本的顶部) 中打开 DetectHiddenText 设置时, 这样会检测到隐藏文本元素.

ExcludeTitle
ExcludeText

尽管这些不受支持，但是通过在 WinTitle 中指定 ahk_group MyGroup 可以间接地使用它们（此处 MyGroup 是由 GroupAdd 建立的窗口组；它支持 ExcludeTitle/Text）。

基本操作

#IfWin 指令可以简单地创建上下文相关的 热键 和 热字串. 例如：

#IfWinActive ahk_class Notepad
#space::MsgBox You pressed Win+Spacebar in Notepad.

#IfWin 指令是与位置有关的: 它们会影响脚本中实际在它们后面的所有热键和热字串. 它们也是互斥的; 即只有最近的那个会起作用.

要关闭上下文相关性, 请指定任一 #IfWin 指令但省略所有参数. 例如：

#IfWinActive

当 #IfWin 关闭时 (或从未在脚本中使用), 所有的 热键 和 热字串 对所有的窗口有效 (除非使用 Suspend 或 Hotkey 命令 进行禁用).

使用 #IfWin 禁用鼠标或键盘热键后，它会执行它原来的功能，即会直接被传递到活动窗口，就像不存在这样的热键。有一种情况例外：对于操纵杆热键，尽管 #IfWin 有效，但它不能阻止其他程序探测到按钮的按下动作。

#IfWin 还可以用来改变普通按键的行为, 例如 Enter 或 Space. 这可以用于特殊的窗口忽略那个按键或执行您不希望的其他动作时. 例如：

#IfWinActive Reminders ahk_class #32770  ; Outlook 中的 "提醒" 窗口.
Enter::Send !o  ; 让 "Enter" 键打开选择的提醒.
#IfWinActive

变体 (副本) 热键

在脚本中特殊的 热键 或 热字串 可以使用不同的 #IfWin 条件定义多次. 这被称为 热键变体. 例如：

#IfWinActive ahk_class Notepad
^!c::MsgBox You pressed Control+Alt+C in Notepad.
#IfWinActive ahk_class WordPadClass
^!c::MsgBox You pressed Control+Alt+C in WordPad.
#IfWinActive
^!c::MsgBox You pressed Control+Alt+C in a window other than Notepad/WordPad.

如果有多个变体符合触发条件, 那么只有最接近脚本顶部的那个会触发. 例外的情况是全局变体 (不含 #IfWin 条件的变体): 它的优先级总是最低; 因此, 只有在没有其他变体符合条件时才会触发它 (这种例外情况不适用于 热字串).

创建重复热键时, 修饰符 的顺序例如 ^!+# 没有关系. 例如：^!c等效于!^c。但是, 按键必须拼写一致. 例如，用于此目的时 Esc 与 Escape 是有区别的（尽管不会受大小写形式的影响）。同样，含 通配符前缀 (*) 的热键和不含通配符的是完全独立的；例如，*F1 和 F1 每个都有自己的变体集。

要让多个变体执行相同的热键子程序, 最简单的方法是把同个热键的变体叠放在一起, 其中在每个的前面使用不同的 #IfWin 指令. 例如：

#IfWinActive ahk_class Notepad
#z::
#IfWinActive ahk_class WordPadClass
#z::
MsgBox You pressed Win+Z in either Notepad or WordPad.
return

或者通过 #IfWinActive ahk_group MyGroup 使用 窗口组。

要动态创建热键变体 (在脚本运行时), 请参阅 "Hotkey IfWin".

一般说明

#IfWin 还能在适当时恢复前缀键为它们原来的功能 (在 "a & b" 这样的热键中 前缀键 为 "a" 键). 每当组合键中给定的前缀没有启动热键时会发生这样的情况, 即前缀键恢复为原来的功能.

当使用 Gosub 或 Goto 跳转到热键或热字串标签时, 它会跳转到最接近脚本顶部的变体.

当前被 #IfWin 禁用的热键, 其中的按键或鼠标按钮在 KeyHistory 的 "Type" 列中显示时会带有 "#" 字符. 这样可以帮助调试脚本.

当前不支持变量引用, 例如 %Var%. 因此, 百分号必须 转义 为 `% 以便在将来支持它们. 同样, 原义的逗号必须进行转义 (为 `,) 以便在将来增加额外的参数. 如果您需要解决此限制, 请使用 GroupAdd 和 ahk_group.

由 Hotkey 命令 设置的热键的标签不会直接受 #IfWin 影响. 相反地, 在靠近脚本的底部使用 #IfWin 会影响所有由 Hotkey 命令创建的热键 (除非使用 "Hotkey IfWin" 改变了这种行为).

Alt-tab 热键 不受 #IfWin 影响: 它们总是对所有窗口有效的.

#IfWinActive/Exist 会设置 最近找到的窗口 (但不包括 #IfWinNotActive/NotExist). 例如：

#IfWinExist ahk_class Notepad
#n::WinActivate  ; 激活由 #IfWin 找到的窗口.

如果 #IfWin 的某个参数中含有前导或尾随空格/tab, 需要使用 转义序列 `s 和 `t 代替.

由于性能的原因, #IfWin 不会持续监视指定窗口的激活或存在. 相反地, 它只会在您输入热键或热字串时检查匹配窗口. 如果匹配窗口不存在，那么您的键击或鼠标点击会原样传递给活动窗口。

窗口标题和文本是区分大小写的. 只有在自动执行段（脚本的顶部）中打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

#If 表达式, Hotkey 命令, 热键, 热字串, Suspend, IfWinActive, IfWinExist, SetTitleMatchMode, DetectHiddenWindows

示例

#IfWinActive ahk_class Notepad
^!a::MsgBox You pressed Ctrl-Alt-A while Notepad is active.  ; 在其他窗口按下此热键会没有效果 (并且它会 "传递").
#c::MsgBox You pressed Win-C while Notepad is active.
::btw::This replacement text for "btw" will occur only in Notepad.
#IfWinActive
#c::MsgBox You pressed Win-C in a window other than Notepad.


#InputLevel

#InputLevel [v1.1.06+]

控制热键和热字串是否忽略模拟的键盘和鼠标事件。

#InputLevel [, Level]

参数

Level

介于 0 和 100 之间的整数. 如果省略, 则它默认为 0.

一般说明

关于 SendLevel 和 #InputLevel 的用法, 请参阅 SendLevel.

此指令是与位置有关的: 它会作用于在它到下一个 #InputLevel 指令之间的所有热键和热字串. 如果未指定 #InputLevel 指令, 则热键和热字串的默认级别为 0.

热键或非自动替换型热字串的输入级别同时也作为由此热键或热字串生成的任何键击或按钮点击的默认 发送级别. 因为键盘或鼠标 重映射 实际上是一对热键, 这样就可通过 #InputLevel 来让重映射触发其他热键.

早于 v1.1.06 的 AutoHotkey 版本会表现的就像 #InputLevel 0 和 SendLevel 0 那样.

相关

SendLevel, 热键, 热字串

示例

#InputLevel 1
Numpad0::LButton
#InputLevel 0
; 使用 Numpad0 或 LButton 都可以触发此热键:
~LButton::Msgbox Clicked


#MaxHotkeysPerInterval

与 #HotkeyInterval 一起指定热键激活的速率，超过此速率会显示警告对话框。

#MaxHotkeysPerInterval Value

参数

值

在 #HotkeyInterval 设置的时间里，不触发警告对话框情况下可以按下的热键最大数目。

备注

注意不要把上面的数值设置的过于宽松, 因为如果您可能曾经不小心引入了无限循环的键击 (通过会意外触发其他热键的 Send 命令), 那么您的电脑会因快速的键击事件流而无响应.

举个简单的例子，热键 ^c::Send ^c 会产生无限循环的键击。要避免此问题，添加 $ 前缀 到热键的定义（例如 $^c::），这样 Send 命令就不会触发热键了。

如果脚本中未使用此指令, 那么它会表现的就像此设置为 70 那样.

相关

#HotkeyInterval

示例

#MaxHotkeysPerInterval 200


#MaxThreads

设置可同时存在的线程的最大数目。

#MaxThreads Value

参数

值

可以同时存在的最大 线程 数. 指定大于 255 的数字相当于指定 255 (在 1.0.48 之前的版本中, 此限制为 20).

备注

此设置是全局的, 这意味着只需要使用一次 (在脚本的任意位置) 就会影响整个脚本.

尽管可以把这个值设置为 1, 但不建议这么做, 因为这样每当脚本显示 MsgBox 或其他对话框时会阻止新的 热键 运行. 在其他 线程 休眠或等待时还会阻止 计时器 运行.

在达到 #MaxThreads 的限制后, 最多可以创建两个下列类型的 线程: 子程序的首行为 ExitApp, Pause, Edit, Reload, KeyHistory, ListLines, ListVars 或 ListHotkeys 的 热键, 热字串, OnClipboardChange 或 GUI 事件. 而且, 不管存在多少个线程 OnExit 子程序 总是会运行.

如果此设置小于 #MaxThreadsPerHotkey, 那么它会覆盖那个设置.

如果脚本中未使用此指令, 那么它会表现的就像此设置为 10 那样.

相关

#MaxThreadsPerHotkey, 线程, #MaxHotkeysPerInterval, #HotkeyInterval, ListHotkeys, #MaxMem

示例

#MaxThreads 2


#MaxThreadsBuffer

当某些或所有的热键达到 #MaxThreadsPerHotkey 限制时，这个指令让它们缓冲而不是忽略键击。

#MaxThreadsBuffer On|Off

参数

On|Off

On：从这里到下一个 #MaxThreadsBuffer ON 指令间的所有热键子程序在它们的子程序数目达到 #MaxThreadsPerHotkey 限制时会缓存而不是忽略它们热键的键击。

Off：这是默认行为。. 当运行的热键线程数已经达到最大数目（通常为 1，不过可通过 #MaxThreadsPerHotkey 改变）时，热键的键击会被忽略。

备注

很少使用此指令, 因为这种类型的缓冲通常都弊大于利, 所以默认情况下的设置为 OFF. 例如, 当您意外地按了一个热键两次, 如果热键的首次 线程 只消耗不到 1 秒的时间就结束了且此设置为 ON, 则这个热键子程序会自动运行两次 (根据设计, 这种类型的缓冲在 1 秒后超时). 注意 AutoHotkey 中有多种其他方法可以缓冲热键（例如 Thread Interrupt 和 Critical）。只是这种特殊的方法可能是有害的, 所以默认设置为 OFF.

此指令主要用于增加键盘自动重复功能的响应性. 例如, 当您按下一个 #MaxThreadsPerHotkey 设置为 1 (默认) 的热键时, 如果此热键的子程序在运行中, 那么传入的键击会被忽略. 因此, 从子程序结束到下一次自动重复键击传入, 它可能需要等待 50ms 或更多时间, 因为这是捕获到自动重复循环的键击的间隔. 为任何需要最好响应性的自动重复热键启用此指令可以避免这 50ms 的延迟.

和所有的 # 指令一样，这个指令不应该像命令那样放在脚本中（即它不需要被包含在子程序中）。相反, 应该把它放在您希望影响的首个热键标签之前.

相关

#MaxThreads, #MaxThreadsPerHotkey, Critical, Thread（命令）, 线程, Hotkey, #MaxHotkeysPerInterval, #HotkeyInterval, ListHotkeys

示例

#MaxThreadsBuffer on
#x::MsgBox, This hotkey will use this type of buffering.
#y::MsgBox, And this one too.
#MaxThreadsBuffer off
#z::MsgBox, But not this one.


#MaxThreadsPerHotkey

设置每个热键或热字串可同时存在的最大线程数。

#MaxThreadsPerHotkey Value

参数

值

指定的热键/热字串可运行的最大 线程 数 (限制在 20 内).

备注

此设置用来控制指定的 热键 或 热字串 子程序允许同时存在多少个 "实例". 例如, 如果一个热键的此限制为 1, 那么当它的子程序在运行时再次按下这个热键, 那么键击会被忽略. 这有助于防止意外的重复按键. 然而, 如果您想要缓存这些键击而不是忽略它们 (可能要增加键盘自动重复功能的响应性), 那么请使用 #MaxThreadsBuffer.

与 #MaxThreads 不同, 此设置 不是 全局的. 相反, 应该把它放在您希望影响的首个热键标签之前, 那么从这里到再次使用此指令之间的所有热键都会受到这个限制.

不论此设置如何, 任何首行为 ExitApp, Pause, Edit, Reload, KeyHistory, ListLines, ListVars 或 ListHotkeys 的热键 子程序总是会运行.

如果 #MaxThreads 的设置小于此设置, 那么它会优先生效.

如果脚本中未使用此指令, 那么它会表现的就像此设置为 1 那样.

相关

#MaxThreads, #MaxThreadsBuffer, Critical, 线程, Hotkey, #MaxHotkeysPerInterval, #HotkeyInterval, ListHotkeys

示例

#MaxThreadsPerHotkey 3


#MenuMaskKey

#MenuMaskKey [AHK_L 38+]

改变用来屏蔽 Win 或 Alt keyup 事件的按键。

#MenuMaskKey KeyName

参数

KeyName

按键名称 或指定了非零虚拟按键代码的 vkNN 序列. 这里不使用扫描码.

备注

此设置是全局的, 这意味着只需要使用一次 (在脚本的任意位置) 就会影响整个脚本.

如果热键使用了键盘钩子或鼠标钩子, 那么最后的键击对于活动窗口和系统可能会不可见. 对于使用了 Win 或 Alt 修饰键的热键, 在释放这些修饰键时可能会激活开始菜单或活动窗口的菜单栏. 为了避免这种情况, AutoHotkey 通过发送键击来 "屏蔽" 这个 keyup 事件. 在修订号 38 之前, 这个按键总是 Ctrl 键击, 已知在某些应用程序中会产生问题.

如果脚本中未使用此指令, 那么它会表现的就像此设置为 Ctrl 那样.

相关

请参阅 这个帖子 了解背景信息.

示例

#MenuMaskKey vk07  ; vk07 是未分配的.
#UseHook
#Space::
!Space::
    KeyWait LWin
    KeyWait RWin
    KeyWait Alt
    KeyHistory
return


#UseHook

强制使用钩子实现全部或部分键盘热键。

#UseHook [On|Off]

参数

On|Off

单独使用 #UseHook 等同于 #UseHook On。

On：将用键盘钩子来实现从这里到下一个 #UseHook OFF（如果有的话）之间的所有键盘热键。

Off：用默认方法（不能使用 RegisterHotkey() 时才使用键盘钩子）实现热键。

备注

一般情况下, 只要可能都会用 windows API 函数 RegisterHotkey() 来实现键盘热键. 不过在一些情况下, 如果使用 键盘钩子 可能响应性更好.

切换此指令为 ON 相当于在每个受影响的热键定义中使用 $ 前缀.

和只在脚本启动时处理一次的所有 # 指令一样，#UseHook 不应该像命令那样放在脚本中（即它不需要被包含在子程序中）。相反, 应该把它放在您希望影响的首个热键标签之前.

默认情况下, 使用 键盘钩子 的热键不会被 Send 命令的方法触发. 同样地, 鼠标热键也不会被像 Click 这样的命令触发, 因为所有的鼠标热键都使用 鼠标钩子. 一种解决方法是使用 Gosub 直接跳转到此热键的子程序. 例如：Gosub #LButton。

[v1.1.06+]: #InputLevel 和 SendLevel 对 Send 命令是否触发热键和热字串提供了额外的控制功能.

如果脚本中未使用此指令, 那么它会表现的就像此设置为 OFF 那样.

相关

#InstallKeybdHook, #InstallMouseHook, ListHotkeys, #InputLevel

示例

#UseHook  ; 强制从这里往后的热键使用键盘钩子。
#x::MsgBox, This hotkey will be implemented with the hook.
#y::MsgBox, And this one too.
#UseHook off
#z::MsgBox, But not this one.


Hotkey

在脚本运行时创建、修改、启用或禁用热键。

Hotkey, KeyName [, Label, Options]
Hotkey, IfWinActive/Exist [, WinTitle, WinText]
Hotkey, If [, Expression]

参数

KeyName

热键触发键的名称, 包括所有 修饰符. 例如，指定 #c 来触发 Win+C 热键。

如果 KeyName 是现有的热键, 那么将使用此命令的其他参数值更新原来的热键.

KeyName 也可以是现有的热键标签的名称 (即双冒号标签), 这样会使用此命令的其他参数值更新原来的热键.

指定 现有的 热键时, KeyName 是不区分大小写的. 但是, 按键名称必须和现有的热键拼写相同 (例如在这种情况下 Esc 与 Escape 是不同的). 此外, 修饰符 (例如 ^!+#) 是无关紧要的.

首次创建一个热键时 (通过 Hotkey 命令或脚本中的 双冒号标签), 其键名以及修饰符的顺序成为此热键的固定名称, 像 A_ThisHotkey 包含的那样. 即使之后 Hotkey 命令使用不同的修饰符顺序操作此热键, 此名称也不会改变.

[v1.1.15+]：如果已存在该热键变体，则根据 KeyName 是否包含颚化符（~）前缀更新它的行为。

标签

按下热键时会执行 (作为新 线程) 的 标签 的名称. 可以使用普通标签或 热键/热字串 标签. 不要包含尾随的冒号. 如果使用动态的 Label (例如 %VarContainingLabelName%), 请首先调用 IsLabel(VarContainingLabelName) 来检查此标签是否存在.

如果 KeyName 为现有的热键, 则此参数可以留空, 此时其标签不会发生变化. 这可用于仅需要修改热键的 Options 时.

如果指定了标签但热键之前已经使用此命令禁用了, 那么热键会保持禁用状态. 要启用它, 请在 Options 中包含单词 ON.

此参数还可以是下列特定值的其中一个:

On: 启用热键. 如果热键已经处于启用状态, 则不进行操作.

Off: 禁用热键. 如果热键已经处于禁用状态, 则不进行操作.

Toggle: 设置热键到相反的状态 (启用或禁用).

AltTab (及其他): 这些是 这里 描述的特殊的 Alt-Tab 热键动作.

注: 仅当不存在相应的标签时 这些值才有特殊含义. 例如, 如果标签 On: 存在并且此参数为单词 ON, 则它被当成标签的名称. 要启用或禁用这样的热键, 请使用 Options 参数. 可以省略 Label; 例如, Hotkey Esc,, Off.

选项

由零个或多个下列字母组成的字符串, 字母间可以用空格分隔. 例如：UseErrorLevel B0。

UseErrorLevel: 如果命令遇到问题, 使用此选项会跳过警告对话框, 设置 ErrorLevel 为 下表 中的一个代码, 然后让 当前线程 继续执行.

On: 如果热键当前是禁用的则启用它.

Off: 如果热键当前是启用的则禁用它. 此选项常用来创建初始状态为禁用的热键.

B 或 B0: 指定字母 B 将按照 #MaxThreadsBuffer 描述的方法缓冲热键. 指定 B0 (B 后跟着数字 0) 来禁用这种类型的缓冲.

Pn: 指定字母 P 后面跟着热键的 线程优先级. 如果创建热键时省略 P 选项, 则设置优先级为 0.

Tn: 指定字母 T 后面跟着一个表示此热键允许的线程数, 如同 #MaxThreadsPerHotkey 中描述的那样. 例如：T5。

如果 B 和 T 选项同时省略或省略了其中一个且热键已经存在, 则这些设置不会改变. 但如果热键还不存在 (即使用当前命令创建时), 它们将使用最近使用的值. 例如, 会使用最靠近脚本末尾的 #MaxThreadsBuffer 实例. 如果脚本中没有使用 #MaxThreadsBuffer, 则使用其默认设置 (此时为 OFF). 对于 #IfWin 也是这样: 除非脚本启动后执行过 "Hotkey IfWin", 否则将对新创建的热键应用最近的实例.

IfWinActive
IfWinExist

(也支持 IfWinNotActive 和 IfWinNotExist). 这些子命令让此后创建的所有热键都是上下文相关的. 请参阅 后面 了解详情.

WinTitle
WinText

在这两个参数中, 任何变量引用 (例如 %var%) 会在命令执行结束时被固定下来. 换句话说, 此后对这些变量内容的改变不会影响现有的 IfWin 热键.

与 #IfWinActive/Exist 一样，WinTitle 和 WinText 为 SetTitleMatchMode 和 DetectHiddenWindows 使用在自动执行段中的默认设置。请参阅 #IfWinActive/Exist 了解详情.

If, Expression

[AHK_L]: #If Expression 的副本. Expression 必须准确匹配 现有的 #If Expression 的文字, 不包括 "#If" 或 "#If,". 当用于 Hotkey 命令时, "If" 后面的逗号是必须的. 尽管此命令不能创建新的表达式, 但它可以使用现有的表达式创建新的热键. 请参阅 #If 示例 4.

已知限制：如果 Expression 包含 and/or 运算符，则它不会被识别为表达式。为了避免此问题，请在原来的 #If 表达式和传递给 Hotkey 命令的表达式中使用等价的 &&/|| 运算符。

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

只有在出现下列情况时 ErrorLevel 才会被改变: 1) 首个参数为 IfWin[Not]Active/Exist, 此时如果遇到问题它会被设置为 1 否则为 0; 或 2) 在 Options 参数中使用了单词 UseErrorLevel.

错误 | 说明
1 | Label 参数指定了不存在的标签名.
2 | KeyName 参数指定了一个或多个当前键盘布局/语言无法识别或不支持的键.
3 | 不支持的前缀键. 例如，不支持使用鼠标滚轮作为热键（如 WheelDown & Enter）的前缀。
4 | KeyName 参数不适合用于 AltTab 或 ShiftAltTab功能。这种情况下要求热键为两个键的组合. 例如：RControl & RShift::AltTab。
5 | 命令试图修改不存在的热键.
6 | 命令试图修改现有热键的不存在的 变体. 要解决此问题，请使用 Hotkey IfWin 来设置匹配那些需修改的热键变体的标准。
98 | 创建此热键后将超过每脚本 1000 个热键的限制 (不过, 每个热键的 变体 数目不受限制, 并且对于 热字串 的数目也没有限制).
99 | 内存不足. 这种情况极少, 通常仅在操作系统变得不稳定时才会发生.

提示: 使用 UseErrorLevel 选项可以检查一个热键的变体是否存在. 例如：

Hotkey, ^!p,, UseErrorLevel
if ErrorLevel in 5,6
    MsgBox The hotkey does not exist or it has no variant for the current IfWin criteria.

备注

当前的 IfWin 设置 决定了 Hotkey 命令将操作热键的哪个 变体.

如果需要根据活动窗口的类型自动禁用选择的热键或热字串，使用 Hotkey, ^!c, Off 通常不如 #IfWinActive/Exist（或它们下面的动态副本“Hotkey IfWinActive/Exist”）来的方便。

通过 双冒号 创建热键比使用 Hotkey 命令执行地更好, 因为在脚本启动时会批量启用它们 (而非一个一个地启用). 因此, 最好使用此命令创建那些在脚本开始运行后才知道键名的热键. 一种这样的情况是通过 INI 文件 为热键配置了多个不同的动作.

给定的标签可以是多个热键的目标. 如果某个热键调用了标签, 您可以通过检查内置变量 A_ThisHotkey 来确定是哪个热键.

如果脚本是 挂起的, 那么新增加/启用的热键也将是挂起的, 直到挂起状态被关闭 (除非它们像 Suspend 命令中描述的那样被免除了).

由此命令做出的改变使得 键盘 和/或 鼠标 钩子被安装或移除是正常的.

尽管 Hotkey 命令不能直接启用或禁用脚本中不是它创建的热键, 但在大多数情况下它可以通过创建或启用相同的热键来 覆盖 它们. 这样是否有效取决于下列因素：1) 在其他脚本中需要被覆盖的热键是否为钩子热键（非钩子热键总是可以成功覆盖）；2) 最近启动的热键通常优先于其他脚本中的相同热键（因此，如果要覆盖其他脚本中的脚本是最近启动的，覆盖总是会成功）；3) 此热键的启用或创建是否会重新激活键盘或鼠标钩子（如果是，那么覆盖总是会成功）。

每当脚本含有至少一个热键时, 它会变成持续运行的, 这意味着应该使用 ExitApp 而不是 Exit 来终止它. 同时热键脚本自动为 #SingleInstance 的单实例属性，不过可以指定 #SingleInstance Off 来关闭。

关于 Hotkey, IfWinXX [, WinTitle, WinText] 的备注

"Hotkey IfWin" 命令允许在脚本运行时创建或修改上下文相关的 热键 (与之相比, #IfWinActive/Exist 指令是由位置决定的并且在脚本启动时生效). 例如：

Hotkey, IfWinActive, ahk_class Notepad
Hotkey, ^!e, MyLabel  ; 创建仅在记事本中有效的热键.

使用 "Hotkey IfWin" 会把后续创建或修改的所有 热键 都变成上下文相关的. 此外, 每个 IfWin 子命令是互斥的; 即只有最近的那个会起作用.

要关闭上下文相关性 (即让后续创建的热键对所有窗口有效), 请指定任一省略了 WinTitle/Text 参数的 IfWin 子命令. 例如：Hotkey, IfWinActive。

如果脚本中没有使用过“Hotkey IfWin”，则最近使用的#IfWin指令（如果有）将作用于Hotkey命令。

通过 IfWin 禁用鼠标或键盘热键后, 则热键会执行它原来的功能; 即如同这样的热键不存在那样被直接传递到活动窗口. 有一种情况例外：对于操纵杆热键，尽管 #IfWin 有效，但它不能阻止其他程序探测到按钮的按下动作。

变体 (副本) 热键

只要每次定义时含有不同的 IfWin 条件, 一个特定的热键可以被创建多次. 这被称为 热键变体. 例如：

Hotkey, IfWinActive, ahk_class Notepad
Hotkey, ^!c, MyLabelForNotepad
Hotkey, IfWinActive, ahk_class WordPadClass
Hotkey, ^!c, MyLabelForWordPad
Hotkey, IfWinActive
Hotkey, ^!c, MyLabelForAllOtherWindows

如果有多个变体符合触发条件, 那么仅触发最早创建的那个. 这种情况的例外是全局变体 (不带有 IfWin 条件的那个): 它的优先级总是最低, 仅当其他变体都不触发时它才会被触发.

创建重复热键时, 修饰符 的顺序例如 ^!+# 没有关系. 例如：^!c等效于!^c。但是, 按键必须拼写一致. 例如，用于此目的时 Esc 与 Escape 是有区别的（尽管不会受大小写形式的影响）。最后，任何带有通配符前缀（*）的热键和不带通配符的完全不同；例如, *F1 和 F1 将拥有各自的变体设置。

关于 IfWin 热键的更多信息, 请参阅 #IfWin 的一般说明.

相关

热键修饰符, #IfWinActive/Exist, #MaxThreadsBuffer, #MaxThreadsPerHotkey, Suspend, IsLabel(), 线程, Thread, Critical, Gosub, Return, Menu, SetTimer

示例

Hotkey, ^!z, MyLabel
return

MyLabel:
MsgBox You pressed %A_ThisHotkey%.
return

; 其他的例子:
Hotkey, RCtrl & RShift, AltTab ; 让 RCtrl & RShift 执行 Alt-Tab 的功能.
Hotkey, #c, On  ; 重新启用 Win-C 热键.
Hotkey, $+#c, Off  ; 禁用 Shift-Win-C 热键.
Hotkey, ^!a, , T5  ; 改变热键为允许 5 个线程.

Hotkey, IfWinActive, ahk_class Notepad
Hotkey, ^!c, MyLabelForNotepad  ; 创建仅在记事本中有效的热键 Ctrl-Alt-C.


ListHotkeys

显示当前脚本包含的热键，不论它们的子程序当前是否运行，也不论它们是否使用键盘或鼠标钩子。

ListHotkeys

此命令等同于在主窗口中选择 View->Hotkeys 菜单项.

如果某个热键被 Hotkey 命令禁用, 则在列表中它会显示为 OFF 或 PART ("PART" 意思是此热键中只有某些 变体 被禁用了).

如果一个热键的子程序当前正在运行, 则显示那个热键的线程总数.

最后, 还会显示热键的类型, 其为下列的其中一个:

reg: 此热键是使用操作系统 RegisterHotkey() 函数实现的.
reg(no): 与上面相同, 不过此热键当前不可用 (由于不支持, 被禁用或 挂起).
k-hook: 此热键是使用 键盘钩子 实现的.
m-hook: 此热键是使用 鼠标钩子 实现的.
2-hooks: 此热键需要两面提到的两种钩子.
joypoll: 此热键通过定时轮询操纵杆实现的.

相关

#InstallKeybdHook, #InstallMouseHook, #UseHook, KeyHistory, ListLines, ListVars, #MaxThreadsPerHotkey, #MaxHotkeysPerInterval

示例

ListHotkeys


#InstallKeybdHook

强制无条件安装键盘钩子。

#InstallKeybdHook

备注

使用键盘钩子监视键击是为了激活不受 RegisterHotkey (这是操作系统内置的功能) 支持的 热字串 和键盘 热键. 它还支持其他一些功能, 例如 Input 命令.

AutoHotkey 不会无条件安装键盘和鼠标钩子, 因为它们合起来至少占用 500 KB 的内存. 因此, 一般只有在脚本包含下列的其中一种情况时才会安装键盘钩子: 1) 热字串; 2) 一个或多个需要键盘钩子的 热键 (大多数不需要); 3) SetCaps/Scroll/Numlock AlwaysOn/AlwaysOff; 4) Input 命令, 在首次实际使用时安装钩子.

与之相比, 使用 #InstallKeybdHook 指令会无条件安装键盘钩子, 这样可以用来在 KeyHistory 中显示最近的 20 次键击 (便于调试), 或避免使用 #HotkeyModifierTimeout.

您可以通过 KeyHistory 命令或菜单项判断脚本是否使用了钩子. 您可以通过 ListHotkeys 命令或菜单项判断哪个热键使用了钩子.

此指令还会让脚本变成 持续运行的, 这意味着应该使用 ExitApp 结束脚本.

相关

#InstallMouseHook, #UseHook, Hotkey, Input, #Persistent, KeyHistory, 热字串, GetKeyState, KeyWait

示例

#InstallKeybdHook


#InstallMouseHook

强制无条件安装鼠标钩子。

#InstallMouseHook

备注

使用鼠标钩子监视鼠标点击是为了激活 热键 和 辅助热字串.

AutoHotkey 不会无条件安装键盘和鼠标钩子, 因为它们合起来至少占用 500 KB 的内存 (但如果已经安装键盘钩子, 此时再安装鼠标钩子只需要增加约 50 KB 的内存, 且反之亦然). 因此, 一般只有在脚本包含一个或多个鼠标 热键 时才会安装鼠标钩子. 还会为 热字串 进行安装, 不过可以通过 #Hotstring NoMouse 禁用.

与之相比，使用 #InstallMouseHook 指令会无条件安装鼠标钩子，这样可以在 KeyHistory 中监视鼠标点击。

您可以通过 KeyHistory 命令或菜单项判断脚本是否使用了钩子. 您可以通过 ListHotkeys 命令或菜单项判断哪个热键使用了钩子.

此指令还会让脚本变成 持续运行的, 这意味着应该使用 ExitApp 结束脚本.

相关

#InstallKeybdHook, #UseHook, Hotkey, #Persistent, KeyHistory, GetKeyState, KeyWait

示例

#InstallMouseHook


#KeyHistory

设置在 KeyHistory 窗口中显示的键盘和鼠标事件的最大数目。您可以将其设置为 0 来禁用按键历史。

#KeyHistory MaxEvents

参数

MaxEvents

在 KeyHistory 窗口中显示的键盘和鼠标事件的最大数目（默认 40，最大值 500）。指定 0 可以完全禁用按键历史.

备注

因为此设置在脚本开始运行前已经生效了, 所以只需要指定一次 (在脚本的任何位置).

因为每次键击或鼠标点击都是由按下事件和弹起事件组成, 所以 KeyHistory 只显示在这里指定的数目一半的 "完整事件". 例如，如果脚本中含有 #KeyHistory 50，那么最多显示 25 次的键击和鼠标点击。

相关

KeyHistory, #NoTrayIcon

示例

#KeyHistory 0    ; 禁用按键历史。
#KeyHistory 100  ; 最多保存 100 事件。


BlockInput

禁用或启用用户通过键盘和鼠标与计算机交互的能力。

BlockInput, Mode

参数

Mode

模式 1: 下列单词的其中一个:

On: 阻止用户与计算机交互 (鼠标和键盘输入都无效).

Off: 重新启用输入.

模式 2：此模式的操作独立于其他两种。例如，BlockInput On 会继续阻塞输入直到使用了 BlockInput Off，即使在下面某个单词仍然有效的情况下。

Send: 正在执行 Send 或 SendRaw 命令 (仅对于传统的 SendEvent 模式) 时, 用户的键盘和鼠标输入被忽略. 这样避免了用户的键击扰乱模拟键击流. 当 Send 结束时，会重新启用输入（在之前没有使用 BlockInput On 阻塞的情况下）。

Mouse: 正在执行 Click, MouseMove, MouseClick 或 MouseClickDrag 命令 (仅对于传统的 SendEvent 模式) 时, 用户的键盘和鼠标输入被忽略. 这样避免了用户的鼠标移动和点击扰乱模拟鼠标事件. 当鼠标命令结束时，会重新启用输入（在之前没有使用 BlockInput On 阻塞的情况下）。

SendAndMouse: 上面两种模式的组合.

Default: 同时关闭 Send 和 Mouse 模式, 但不改变输入阻塞的当前状态. 例如，如果 BlockInput On 当前有效，那么使用 BlockInput Default 不会关闭它。

模式 3（需要 v1.0.43.11+）：此模式的操作独立于其他两种。例如，如果 BlockInput On 和 BlockInput MouseMove 都有效，那么鼠标移动会被阻塞直到这两者被同时关闭。

MouseMove: 鼠标光标不会随用户对鼠标的物理移动而移动 (DirectInput 应用程序可能是个例外). 脚本中首次使用此命令时, 会安装 鼠标钩子 (在还没有安装时). 同时, 脚本变成 持续运行的, 这意味着应该使用 ExitApp 结束脚本. 鼠标钩子会一直保持加载状态，直到下一次使用 Suspend 或 Hotkey 命令，此时如果没有任何热键或热字串需要那么它会被移除（请参阅 #Hotstring NoMouse）。

MouseMoveOff: 允许用户移动鼠标光标.

备注

比起 BlockInput，通常优先考虑使用 SendMode Input 或 SendMode Play 会更好，这样键击和鼠标点击会变得不可中断。这是因为与 BlockInput 不同, 这些模式不会丢弃发送期间用户输入的内容; 作为替代, 这些键击被缓冲起来在之后发送. 不使用 BlockInput 也避免了下一段落所描述的需要解决的粘滞按键问题.

如果在用户按住按键时启用 BlockInput, 可能会导致这些键 "卡住". 通过等待这些按键释放后才启用 BlockInput 可以避免此问题, 与本例一样:

^!p::
KeyWait Control  ; 等待按键释放.  为每个热键修饰符使用一次 KeyWait 命令.
KeyWait Alt
BlockInput On
; ... 发送键击和鼠标点击 ...
BlockInput Off
return

每当发送 ALT 事件时, 输入阻塞会自动和临时禁用 (之后重新启用).

BlockInput 生效时，用户的输入被拦截，不过 AutoHotkey 可以模拟键击和鼠标点击。然而由于 Windows API 的特性，按下 Ctrl+Alt+Del 将重新启用输入。

钩子热键 的某些类型在 BlockInput 启用时仍然可以被触发. 例子包括 MButton（鼠标钩子）和 LWin & Space（含有除修饰符$#外的明确前缀的键盘钩子）。

当脚本关闭时会自动重新启用输入.

相关

SendMode, Send, Click, MouseMove, MouseClick, MouseClickDrag

示例

BlockInput, on
Run, notepad
WinWaitActive, Untitled - Notepad
Send, {F5} ; 粘贴时间和日期
BlockInput, off


点击

Click [v1.0.43+]

在指定坐标处点击鼠标按钮。它还可以按下鼠标按钮，转动鼠标滚轮或移动鼠标。

这里有一些常见用法的例子 (所有逗号都是可选的):

Click (单独的) | 在鼠标光标的当前位置点击一次鼠标左键.
Click 44, 55 | 在 44, 55 坐标 (基于 CoordMode) 处点击一次鼠标左键.
Click right 44, 55 | 与上述相同, 不过这里点击鼠标右键.
Click 2 | 在光标的当前位置点击两次鼠标左键 (即双击).
Click down | 按下鼠标左键不放.
Click up right | 释放鼠标右键.
Click %x% %y% | 由于 click 不支持 表达式, 所以变量应该括在百分号中.

Click 后可以跟零个或多个下列项. 每个项之间至少需要一个空格, tab 和/或逗号分隔. 除了ClickCount必须放在坐标后面（如果使用了坐标），各项可以按任何顺序出现。

X, Y: 在点击前, 鼠标光标要移动到的 x/y 坐标. 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置. 如果省略, 那么使用光标的当前位置.

按钮名称：Left（默认）、Right、Middle（或仅使用这些名称的首个字母），或鼠标的第四或第五个按钮（X1 或 X2）。注意: 与 MouseClick 不同, 这里左键和右键的行为在所有系统上都是一致的, 即使用户通过系统控制面板交换了按钮的功能.

鼠标滚轮：指定 WheelUp 或 WU 来向上转动滚轮（远离您的方向），指定 WheelDown 或 WD 来向下转动滚轮（靠近您的方向）。在 v1.0.48+, 还可以指定 WheelLeft (或 WL) 或 WheelRight (或 WR) (不过它们在 Windows Vista 以前的系统上无效). 对于 ClickCount (下面的), 指定滚轮要转动的格数. 然而, 有些程序不接受鼠标滚轮转动的格数 ClickCount 大于 1 的情况. 对于这些程序, 请参考下面的例子使用 Loop:

Loop 5
    Click WheelUp

ClickCount：鼠标要点击的次数（例如：Click 2，Click 100, 200, 2）。如果省略, 那么点击鼠标一次. 如果指定了坐标, 那么 ClickCount 必须放在坐标后面. 指定零（0）来移动鼠标而不进行点击（例如：Click 200, 0, 100）。

Down 或 Up: 这两个单词通常省略, 此时每次点击包括按下事件和接着的弹起事件. 否则, 指定 Down (或字母 D) 来按下鼠标按钮不放. 之后, 使用单词 Up (或字母 U) 来释放鼠标按钮.

Relative: 使用单词 Rel 或 Relative 会把指定的 X 和 Y 坐标视为距离当前鼠标位置的偏移. 换句话说, 会把光标从当前位置往右移动 X 像素 (负值则往左) 且往下移动 Y 像素 (负值则往上).

备注

Click 通常比 MouseClick 更好, 因为它不受用户通过系统控制面板对左右键功能交换的设置的影响.

Click 使用的发送模式由 SendMode 设置. 要忽略此模式进行特殊的点击，请使用特定的 Send 命令，例如：SendEvent {Click, 100, 200}。

要进行 shift-click 或 control-click，使用 Send {Click} 方法通常是最简单的。例如：

Send +{Click 100, 200}  ; Shift+LeftClick
Send ^{Click 100, 200, right}  ; Control+RightClick

与 Send 不同, Click 不会自动释放修饰键 (Control, Alt, Shift 和 Win). 例如，如果现在 Control 键处于按下的状态，那么 Click 会产生 control-click 但 Send {Click} 会产生普通的点击。

SendPlay 模式 生成的鼠标事件可以比其他模式适应更大范围的游戏. 此外, 某些应用程序和游戏在鼠标移动过快时可能会跟踪困难, 此时可以使用 SetDefaultMouseSpeed 减慢速度 (但仅在 SendEvent 模式 中有效).

可以使用 BlockInput 命令防止用户对鼠标的任何物理操作扰乱由鼠标命令生成的模拟鼠标事件. 不过, 在 SendInput 和 SendPlay 模式中通常不需要这个命令, 因为它们会自动延迟用户对鼠标的物理操作到发送之后.

在每次鼠标按下事件和鼠标弹起事件后都会有一个自动的延时 (不包括在 SendInput 模式 中转动鼠标滚轮的情况). 使用 SetMouseDelay 可以改变延时的长度.

相关

Send {Click}, SendMode, CoordMode, SetDefaultMouseSpeed, SetMouseDelay, MouseClick, MouseClickDrag, MouseMove, ControlClick, BlockInput

示例

Click  ; 在鼠标光标的当前位置点击鼠标左键.
Click 100, 200  ; 在指定坐标处点击鼠标左键.
Click 100, 200, 0  ; 移动而不点击鼠标.
Click 100, 200 right  ; 点击鼠标右键.
Click 2  ; 执行双击.
Click down  ; 按下鼠标左键不放.
Click up right  ; 释放鼠标右键.


ControlClick

发送鼠标按钮或鼠标滚轮事件到控件。

ControlClick [, Control-or-Pos, WinTitle, WinText, WhichButton, ClickCount, Options, ExcludeTitle, ExcludeText]

参数

Control-or-Pos

如果此参数为空, 则点击目标窗口的顶层控件 (或如果窗口没有控件则点击窗口自身). 否则, 使用下列两种模式的其中一个.

模式 1 (位置): 指定相对于目标窗口左上角的 X 和 Y 坐标. X 坐标必须在 Y 坐标前面, 且它们之间需要含有至少一个空格或 tab. 例如：X55 Y33。如果在指定的坐标存在控件, 则会发送点击事件到这个坐标处. 如果没有控件, 则发送事件到目标窗口自身 (根据窗口的性质, 这可能不会产生效果). 注意：在此模式中，会忽略 Options 参数中的 X 和 Y 字母选项。

模式 2 (ClassNN 或文本): 可以指定 ClassNN (控件的类名和实例编号) 或控件的名称/文本, 它们都可以通过 Window Spy 获取. 使用名称/文本时, 匹配行为由 SetTitleMatchMode 决定.

默认情况下, 模式 2 优先于模式 1. 例如, 在一种不太可能的情况中某个控件的文本或 ClassNN 格式为 "Xnnn Ynnn", 那么此时会使用模式 2. 要覆盖此行为而无条件使用模式 1，请在 Options 中加上单词 Pos，例如：ControlClick, x255 y152, WinTitle,,,, Pos

要操作控件的 HWND（窗口句柄），请将此参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

WhichButton

要点击的按钮: LEFT, RIGHT, MIDDLE (或这些单词的首个字母). 如果省略或为空, 则使用 LEFT 按钮.

还支持 X1（XButton1：第四个鼠标按钮）和 X2（XButton2：第五个鼠标按钮）。

还支持 WheelUp（或 WU）和 WheelDown（或 WD）。此时 ClickCount 为需要转动的滚轮格数.

Windows Vista 或更高版本 [v1.0.48+]: 还支持 WheelLeft (或 WL) 和 WheelRight (或 WR) (它们在较旧的操作系统中没有效果). 此时 ClickCount 为需要转动的滚轮格数.

ClickCount

要点击鼠标的次数, 可以为 表达式. 如果省略或为空, 则点击 1 次.

选项

零个或多个下列选项字母组成的系列. 例如：d x50 y25。

NA [v1.0.45+]: 也许可以提高可靠性. 请参阅后面的 可靠性.

D: 按住鼠标按钮不放 (即生成按下事件). 如果 D 和 U 选项都没有包含, 则会发送完整的点击事件 (按下事件和弹起事件).

U: 释放鼠标按钮 (即生成弹起事件). 此选项不能和 D 选项同时使用.

Pos: 在 Options 的任意位置指定单词 Pos, 这样会无条件使用在上面 Control-or-Pos 参数中描述的 X/Y 位置模式.

Xn: 指定 n 为要点击的相对于控件左上角的 X 坐标. 如果未指定, 则在控件的水平中心点击.

Yn：指定 n 为要点击的相对于控件左上角的 Y 坐标。如果未指定, 则在控件的垂直中心点击.

在 X 和 Y 选项中使用十进制数而不是十六进制数.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

可靠性

要提高可靠性, 尤其是在 ControlClick 期间用户同时在使用鼠标, 请尝试下面的一种或两种方法也许会有所帮助:

1) 请在 ControlClick 前面加上 SetControlDelay -1。这样可以避免在点击时按住鼠标, 减少对用户使用鼠标的干扰.

2) 在第六个参数 (Options) 中指定字符串 NA, 如下所示:

SetControlDelay -1
ControlClick, Toolbar321, WinTitle,,,, NA

NA 可以避免激活目标窗口，同时避免混淆它和脚本的输入，这样可以防止鼠标实际移动产生的冲突（但通常只在目标窗口不活动时）。然而, 此方法不是对所有的窗口和控件都有效.

备注

在滚动鼠标滚轮时, 有些程序不会接受大于 1 的 ClickCount. 对于这些程序, 请使用循环来转动多个格数, 例如这个例子转动 5 格:

Loop, 5
    ControlClick, Control, WinTitle, WinText, WheelUp

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

SetControlDelay, Control, ControlGet, ControlGetText, ControlMove, ControlGetPos, ControlFocus, ControlSetText, ControlSend, Click

示例

ControlClick, OK, Some Window Title  ; 点击 OK 按钮
ControlClick, x55 y77, WinTitle  ; 在坐标上进行点击. 注意 X 和 Y 之间的空隙.

; 下面的方法可以提高可靠性并减少副作用:
SetControlDelay -1
ControlClick, Toolbar321, WinTitle,,,, NA x192 y10  ; 使用 NA 模式在相对于命名控件的坐标处进行点击.


ControlSend / ControlSendRaw

发送模拟键击到窗口或控件。

ControlSend [, Control, Keys, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlSendRaw: 参数同上.

参数

控件

可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。如果此参数为空或省略, 则使用目标窗口的顶层控件. 如果此参数为ahk_parent，则直接发送键击到目标窗口而非其中的某个控件（请参阅自动化Winamp中的例子）。

要对控件的 HWND（窗口句柄）进行操作，请将 Control 参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

键

要发送的按键序列 (请参阅 Send 命令了解详情). 要发送原义的逗号, 需要对它进行 转义 (`,). 发送字符的速率由 SetKeyDelay 决定.

与 Send 命令不同, ControlSend 不能发送鼠标点击. 请用 ControlClick 发送.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

ControlSendRaw 会准确地按照原样发送 Keys 参数中的键击, 而不把 {Enter} 转换成 ENTER 键击, 把 ^c 转换成 Control-C, 等等.

如果省略 Control 参数, 那么此命令会尝试直接发送到目标窗口的顶层控件 (一般这个是正确的), 当目标窗口没有控件时则发送到窗口自身. 这可以用在窗口还不含有任何控件或无所谓发送给哪个控件的时候.

默认情况下, 修饰符键击 (Control, Alt, Shift 和 Win) 的发送方法和在 Send 命令一般模式下发送相同. 这样可以让命令提示符和其他控制台窗口正确检测到大写字母, 控制字符, 等等. 这样也提供了其他方面的可靠性.

然而, 在某些情况下这些修饰符事件可能和活动窗口发生冲突, 尤其是在 ControlSend 发送期间或正发送 Alt 键的时候用户正在输入 (因为 Alt 会激活活动窗口的菜单栏). 通过明确地发送修饰键的按下和弹起时间可以避免此问题, 例如:

ControlSend, Edit1, {Alt down}f{Alt up}, Untitled - Notepad

上面的方法还可以在工作站被锁定 (被登录提示保护) 时发送修饰符键击 (Control/Alt/Shift/Win).

使用 ControlSend 发送键击到控制台窗口 (例如命令提示符) 时, 应该避免使用 BlockInput. 因为它可能让大写字符和修饰符按键例如 Control 工作不正常.

SetKeyDelay 的值决定了发送按键的速度. 如果目标窗口无法可靠地接收到键击, 请尝试在 SetKeyDelay 的第二个参数中增加按键时长, 例如:

SetKeyDelay, 10, 10
SetKeyDelay, 0, 10
SetKeyDelay, -1, 0

如果目标控件是 Edit 控件 (或类似的控件), 则使用下列方法通常比 ControlSend 更可靠和快速:

Control, EditPaste, This text will be inserted at the caret position., ControlName, WinTitle
ControlSetText, ControlName, This text will entirely replace any current text., WinTitle

ControlSend 通常不能很好的操作窗口的菜单栏. 要变通解决此问题, 请使用 WinMenuSelectItem. 如果由于菜单栏的性质而操作失败, 那么您可以参照 发送消息指南 来尝试找到想要选择的菜单的对应消息.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

SetKeyDelay, 转义序列（如 `%）, Control, ControlGet, ControlGetText, ControlMove, ControlGetPos, ControlClick, ControlSetText, ControlFocus, Send, 自动化 Winamp

示例

ControlSend, Edit1, This is a line of text in the notepad window., Untitled
SetTitleMatchMode, 2
ControlSend, , abc, cmd.exe  ; 直接发送到命令提示符窗口.


CoordMode

为多个命令设置坐标模式，相对于活动窗口还是屏幕。

CoordMode, ToolTip|Pixel|Mouse|Caret|Menu [, Screen|Window|Client]

参数

Param1

ToolTip: 作用于 ToolTip.

Pixel: 作用于 PixelGetColor, PixelSearch 和 ImageSearch.

Mouse: 作用于 MouseGetPos, Click 以及 MouseMove/Click/Drag.

Caret: 作用于内置变量 A_CaretX 和 A_CaretY.

Menu：作用于为 Menu Show 命令指定坐标的时候。

Param2

如果省略 Param2, 则默认为 Screen.

Screen: 坐标相对于桌面 (整个屏幕).

Relative: 坐标相对于活动窗口.

Window [v1.1.05+]: 与 Relative 效果相同, 但由于含义清晰, 因此建议使用.

Client [v1.1.05+]：坐标相对于活动窗口的工作区，其中不包括标题栏、菜单栏（如果它含有标准菜单栏）和边框。Client 坐标模式较少依赖于操作系统版本和主题.

备注

如果没有使用此命令, 除了另外注明的那些外的所有命令 (例如 WinMove 和 InputBox) 都使用相对于活动窗口的坐标模式.

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

Click, MouseMove, MouseClick, MouseClickDrag, MouseGetPos, PixelGetColor, PixelSearch, ToolTip, Menu

示例

CoordMode, ToolTip, Screen  ; 把 ToolTips 放置在相对于屏幕坐标的位置:
CoordMode, ToolTip  ; 和上面效果相同, 因为 "screen" 是默认的坐标模式.


GetKeyState

检查键盘按键或鼠标/操纵杆按钮是否按下或放开。也可以获取操纵杆的状态。

GetKeyState, OutputVar, KeyName [, Mode]
KeyIsDown := GetKeyState("KeyName" [, "Mode"])

参数

OutputVar

用来保存获取的按键状态的变量名, 它的值在按下时是 D 而弹起时是 U (不过 GetKeyState() 函数在按下时返回 true (1) 而弹起时返回 false (0)). 如果按键的状态无法识别, 则此变量为空.

下面是关于操纵杆的几点说明:

1) 对于像 JoyX 这样的操纵杆轴, OutputVar 将被设置为介于 0 和 100 之间的浮点数, 作为该轴活动范围的百分率, 表示操纵杆的位置. 可以使用 SetFormat 改变此数字的格式. 此 测试脚本 可以用来分析您的操纵杆.

2) 当 KeyName 为 JoyPOV 时, 获取的值将介于 0 和 35900 之间. 许多操纵杆使用与下列近似的 POV 值:
-1: 没有角度
0: 向前 POV
9000 (即 90 度): 向右 POV
27000 (即 270 度): 向左 POV
18000 (即 180 度): 向后 POV

KeyName

此参数可以是键盘中任何的单个字符或 按键列表 中的其中一个键名, 例如鼠标/操纵杆按钮. 例如: B, 5, LWin, RControl, Alt, Enter, Escape, LButton, MButton, Joy1.

或者, 可以指定明确的虚拟按键代码, 例如 vkFF. 只有在一个按键没有指定名称这样少见的情况下, 这种方法才有用. 这种按键的虚拟按键代码可以通过按键列表页面底部的步骤来确定。

已知限制: 此函数无法区别共享相同虚拟按键代码的两个按键, 例如 Left 和 NumpadLeft.

Mode

获取操纵杆状态时, 此参数被忽略.

如果省略, 则默认的模式是获取按键的逻辑状态. 这是操作系统和活动窗口所认为的按键所处的状态, 但可能和它的物理状态不一致.

或者, 可以指定这些字母的其中一个:

P: 获取物理状态 (即用户是否实际按住了按键). 如果没有安装键盘和/或鼠标钩子，则按键或鼠标按钮的物理状态通常和逻辑状态一致（有时逻辑状态可能比物理状态滞后）；如果安装了钩子，则它会准确反映出用户是否按下了按键或鼠标按钮（只要在脚本执行时它正被按住）。您可以通过 KeyHistory 命令或菜单项确定脚本中是否使用了钩子。通过添加 #InstallKeybdHook 和/或 #InstallMouseHook 指令到脚本中您可以强制安装钩子。

T: 获取切换状态 (仅对可以切换的按键才有效, 例如 Capslock, Numlock, Scrolllock 和 Insert). 获取的值为 D 表明按键是打开的, 而 U 表明它是关闭的 (不过 GetKeyState() 函数当打开时返回 true (1) 而关闭时返回 false (0)).

备注

为了等待按键或鼠标/操纵杆按钮进入新的状态, 通常用 KeyWait 代替 GetKeyState 的循环会更简单.

带有不常见键盘驱动的系统更新按键的状态可能比较慢, 尤其是像 Capslock 这样按键的切换状态. 在按键状态改变后立即对其状态进行检查的脚本可以预先使用 Sleep, 以便系统有时间更新按键的状态.

关于对操纵杆使用 GetKeyState 的例子, 请参阅 操纵杆重映射页面 和 操纵杆到鼠标的映射脚本.

相关

GetKeyState(), KeyWait, 按键列表, 操纵杆重映射, KeyHistory, #InstallKeybdHook, #InstallMouseHook

示例

; 基本示例:
GetKeyState, state, RButton  ; 鼠标右键.
GetKeyState, state, Joy2  ; 第一个操纵杆的第二个按钮.

GetKeyState, state, Shift
if state = D
    MsgBox At least one Shift key is down.
else
    MsgBox Neither Shift key is down.

GetKeyState, state, CapsLock, T ;  当 CapsLock 打开时为 D, 否则为 U.
state := GetKeyState("Capslock", "T")  ; 当 CapsLock 打开时为真, 否则为假.

; 重映射的例子 (这里只是为了演示因为使用
; 内置的重映射功能 会更简单):
; 在下面的热键中, 当 NumpadAdd 按下时鼠标按钮会保持按住的状态,
; 这个热键把 NumpadAdd 映射为鼠标按钮. 此方法
; 还可以用来在用户按住按键或按钮时重复一个动作:
*NumpadAdd::
MouseClick, left,,, 1, 0, D  ; 按住鼠标左键.
Loop
{
    Sleep, 10
    GetKeyState, state, NumpadAdd, P
    if state = U  ; 按键已经被释放, 所以退出循环.
        break
    ; ... 此处放置您想要重复的任何动作.
}
MouseClick, left,,, 1, 0, U  ; 释放鼠标按钮.
return

; 示例: 让操纵杆按钮根据操纵杆轴位置产生不同的反应.
joy2::
GetKeyState, joyx, JoyX
if joyx > 75
    MsgBox Action #1 (button pressed while joystick was pushed to the right).
else if joyx < 25
    MsgBox Action #2 (button pressed while joystick was pushed to the left).
else
    MsgBox Action #3 (button pressed while joystick was centered horizontally).
return

; 请参阅 操纵杆重映射页面 和 操纵杆到鼠标的映射脚本 查看其他示例.


KeyHistory

显示脚本信息和最近键击和鼠标点击的历史。

KeyHistory

备注

此命令等同于在主窗口中选择 "View->Key history" 菜单项.

要禁用按键历史, 请在脚本的任何位置指定下面这行:

#KeyHistory 0

#KeyHistory 还可以用来来改变显示的事件的最大数目.

此特性旨在帮助 调试脚本和热键. 通过使用 按键列表 页面底部描述的步骤, 它还可以用来检测非标准键盘按键的扫描码 (知道按键的扫描码就可以把这个按键用在热键中).

滚轮事件 (WheelDown, WheelUp, WheelLeft 和 WheelRight) 的虚拟键 (VK) 是一些在 AutoHotkey 外没有任何意义的占位符值. 此外, 滚轮事件的扫描码实际上是滚轮转动的格数 (通常为 1).

如果脚本没有安装 键盘钩子, 那么 KeyHistory 窗口将只显示由脚本自己 (即不包含用户的) 生成的按键事件. 如果脚本没有安装 鼠标钩子, 那么将不显示鼠标按钮事件. 如果您的脚本使用了其中的一种钩子, 那么可以通过脚本主窗口 (可通过托盘图标的 "Open" 菜单打开) 的菜单项 "View->Key History" 找到它. 通过添加下面两行语句中的任何一行或同时添加两行到脚本中, 您可以强制安装钩子:

#InstallKeybdHook
#InstallMouseHook

相关

#KeyHistory, #InstallKeybdHook, #InstallMouseHook, ListHotkeys, ListLines, ListVars, GetKeyState, KeyWait, A_PriorKey

示例

KeyHistory ; 在窗口中显示历史信息.


KeyWait

等待按键或鼠标/操纵杆按钮被松开或按下。

KeyWait, KeyName [, Options]

参数

KeyName

此参数可以是键盘中任何的单个字符或 按键列表 中的其中一个键名, 例如鼠标/操纵杆按钮. 不支持除操纵杆按钮外的其他操纵杆属性.

还可以指定明确的虚拟按键代码，例如 vkFF。只有在一个按键没有指定名称且按下时不产生可见的字符这样少见的情况下, 这种方法才有用. 它的虚拟按键代码可以通过按键列表页面底部的步骤来确定。

选项

如果此参数为空, 则命令会无限期等待用户松开指定的按键或鼠标/操纵杆按钮. 不过, 如果没有安装 键盘钩子 并且 KeyName 是使用类似 Send 命令模拟释放的键盘按键, 则此按键会被视为物理松开了. 没有安装鼠标钩子时，对鼠标按钮同样如此。

选项: 由一个或多个下列字母组成的字符串 (可任意顺序, 字母间可以用空格分隔):

D: 等待按键被按下.

L: 检测按键的逻辑状态, 这是操作系统和活动窗口所认为的按键所处的状态 (可能和它的物理状态不一致). 对于操纵杆按钮会忽略此选项.

T：超时（例如 T3）。超时前等待的秒数，超时后设置 ErrorLevel 为 1。如果按键或按钮达到指定的状态, 则命令不再等待超时时间到期. 相反地，它会立即设置 ErrorLevel 为 0 并让脚本继续执行。

此超时时间值可以为浮点数 (例如 2.5), 但不能为十六进制值 (例如 0x03).

ErrorLevel

命令超时后 ErrorLevel 被置为 1, 否则为 0.

备注

如果没有安装键盘和/或鼠标钩子，则按键或鼠标按钮的物理状态通常和逻辑状态一致（有时逻辑状态可能比物理状态滞后）；如果安装了钩子，则它会准确反映出用户是否按下了按键。您可以通过 KeyHistory 命令或菜单项确定脚本中是否使用了钩子. 通过添加 #InstallKeybdHook 和 #InstallMouseHook 指令到脚本中您可以强制安装其中一种或两种钩子.

当此命令处于等待状态时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

要等待两个或多个按键被释放, 请连续使用 KeyWait. 例如：

KeyWait Control  ; 等待 Control 和 Alt 被释放.
KeyWait Alt

要等待一组按键中的任意一个被按下, 请参阅 Input 命令的示例部分.

相关

GetKeyState, 按键列表, Input, KeyHistory, #InstallKeybdHook, #InstallMouseHook, ClipWait, WinWait

示例

; 示例 #1: 基本用法:
KeyWait, a  ; 等待 A 被释放.
KeyWait, LButton, D  ; 等待鼠标左键被按下.
KeyWait, Joy1, D T3  ; 等待首个操纵杆按钮在 3 秒内被按下.
KeyWait, LAlt, L  ; 等待左 Alt 键被逻辑释放.

; 示例 #2: 简单的热键:
~Capslock::
KeyWait, Capslock  ; 等待用户实际释放.
MsgBox You pressed and released the Capslock key.
return

; 示例 #3: 重映射按键或鼠标按钮 (这里仅为了演示
; 因为使用 内置的重映射功能 会更容易使用):
; 当 NumpadAdd 按下时持续按住鼠标左键, 这样实际上
; 把 NumpadAdd 映射成了鼠标左键.
*NumpadAdd::
MouseClick, left,,, 1, 0, D  ; 按住鼠标左键.
KeyWait, NumpadAdd  ; 等待按键被释放.
MouseClick, left,,, 1, 0, U  ; 释放鼠标按钮.
return

; 示例 #4: 检测什么时候两次按下了某个按键 (类似于双击).
; 当您使用 RControl 修饰另一个键时
; 使用 KeyWait 来停止键盘自动重复功能以避免产生不想要的两次按下.  它通过保持热键
; 线程的运行且依靠
; #MaxThreadsPerHotkey 默认设置 1 来实现拦截自动重复的目的.
; 注: 在 SetTimer 页面的底部有一个更精巧的脚本,
; 能分辨出单次, 两次和三次按下的区别.
~RControl::
if (A_PriorHotkey <> "~RControl" or A_TimeSincePriorHotkey > 400)
{
    ; 两次按下时间间隔太长, 所以这不是一个两次按下.
    KeyWait, RControl
    return
}
MsgBox You double-pressed the right control key.
return


Input

等待用户输入字符串。

Input [, OutputVar, Options, EndKeys, MatchList]

参数

OutputVar

用来保存用户输入文本的变量名 (默认情况下, 模拟输入也被保存下来).

如果省略此参数和其他参数, 那么会终止在其他 线程 中正在执行的任何 Input 并且将那个 Input 的 ErrorLevel 设置为单词 NewInput. 与之相比, 如果终止了之前的 Input 则把当前线程的 ErrorLevel 设置为 0, 如果没有需要终止的 Input 则为 1.

OutputVar 本身并不记录键击. 而是记录通过键击根据活动窗口的键盘布局/语言产生的字符. 因此, 不产生字符的键击 (例如 PageUp 和 Escape) 不会被记录下来 (尽管可以通过下面的 EndKeys 参数识别它们).

会原义保存空白字符, 例如 TAB (`t). ENTER 被保存为换行符 (`n).

选项

由零个或多个下列字母组成的字符串 (可任意顺序, 字母间可以用空格分隔):

B: 忽略退格键. 一般情况下, 按下退格键会删除最后一个输入的字符. 注: 如果输入的文本是可见的 (例如在编辑器中), 在其中使用方向键或其他方式移动了光标后, 退格键仍然会删除最后一个字符而不是光标 (插入点) 后面的字符.

C: 区分大小写. 一般情况下, MatchList 是不区分大小写的 (在 1.0.43.03 之前的版本中, 只有字母 A-Z 被认为具有大小写形式, 而像 ü/Ü 这样的字母则没有).

I: 忽略由 AutoHotkey 脚本产生的所有字符, 例如 SendEvent 命令. 然而, 不论此设置如何, SendInput 和 SendPlay 模式生成的输入总是被忽略.

L：长度限制（例如 L5）。允许输入文本的最大长度. 当文本到达这个长度，则输入会被终止且 ErrorLevel 被设置为单词 Max，不过如果此时文本匹配 MatchList 中的某个词组，则把 ErrorLevel 设置为单词 Match。如果未指定, 则长度限制为 16383, 这也是绝对的最大长度.

M: 如果含修饰符的键击 (例如 Control-A 到 Control-Z) 对应于真实的 ASCII 字符, 则会识别并对它们进行转译. 参考这个例子, 其中识别了 Control-C:

Transform, CtrlC, Chr, 3 ; 把 Ctrl-C 对应的字符保存到 CtrlC 变量。
Input, OutputVar, L1 M
if OutputVar = %CtrlC%
    MsgBox, You pressed Control-C.
ExitApp

注: 从 Ctrl-A 到 Ctrl-Z 对应的字符为从 Chr(1) 到 Chr(26). 此外，M 选项可能会导致某些键盘快捷键（例如 Ctrl-LeftArrow）在 Input 执行时表现不正常。

T：超时（例如 T3）。在终止输入前等待的秒数，超时后设置 ErrorLevel 为单词 Timeout。Input 超时后，OutputVar 会被设置为用户在超时前输入的文本。这个值可以为浮点数, 例如 2.5.

V: 可见. 一般情况下, 用户的输入是阻塞的 (隐藏在操作系统后). 使用此选项来发送用户的键击到活动窗口.

*: 通配符 (查找所有地方). 一般情况下, 用户输入的文本必须准确匹配 MatchList 中的某个词组, 匹配才会成功. 使用此选项搜索输入文本的整个长度, 这样会更容易找到匹配.

EndKeys

零个或多个按键组成的列表, 按下其中的任何一个都可以终止输入 (EndKey 自身不会被写入 OutputVar). 使用此方式终止输入后, ErrorLevel 被设置为单词 EndKey 后跟着冒号和 EndKey 的名称. 例如：EndKey:., EndKey:Escape。

EndKey 列表使用类似于 Send 命令的格式. 例如，指定 {Enter}.{Esc} 会使得 ENTER、句点（.）或 ESCAPE 其中任何一个都可以终止输入。要使用大括号作为终止键，请指定 {{} 和/或 {}}。

要使用 Control, Alt 或 Shift 作为终止键, 请指定它们的左和/或右版本, 而不是中性版本. 例如，指定 {LControl}{RControl} 而不是 {Control}。

尽管不支持诸如 Control-C (^c) 这样修饰键, 但在 v1.0.14+ 中支持某些需要按住 shift 键来输入的字符 (即标点符号, 例如 ?!:@&{}).

还可以指定明确的虚拟按键代码，例如 {vkFF}。只有在一个按键没有指定名称且按下时不产生可见的字符这样少见的情况下, 这种方法才有用. 它的虚拟按键代码可以通过按键列表页面底部的步骤来确定。

MatchList

逗号分隔的关键词组列表, 其中的任何一个都可以终止输入 (此时 ErrorLevel 被设置为单词 Match). 用户输入的全部文本必须准确匹配列表中的某个词组, 匹配才会成功 (除非使用了 * 选项). 此外, 在分隔逗号周围的任何空格或 tab 都是有意义的, 这表示它们也是匹配字符串的一部分. 例如, 如果 MatchList 为 "ABC , XYZ ", 则用户必须输入在 ABC 后或 XYZ 前输入空格才形成匹配.

在匹配列表中两个连续的逗号产生单个原义逗号. 例如, 后面的匹配列表会在 string1 的末尾产生单个原义逗号: "string1,,,string2". 同样地, 后面的匹配列表仅包含其中含有一个原义逗号的单个项目: "single,,item".

因为 MatchList 中的每一项并不是作为独立的参数, 所以此列表可以完整的包含在一个变量中. 事实上, 如果此列表的长度超过 16383, 那么列表的全部或部分必须包含在变量中以变量表示, 因为这个长度是任何脚本行的最大长度. 例如，MatchList 可以由 %List1%,%List2%,%List3% 组成，其中的每个变量包含了用来匹配词组的一个大的子列表。

ErrorLevel

[v1.1.04+] 此命令在不带参数调用且没有 Input 正在执行时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

1 或 0 | 不带参数使用此命令时, 如果成功终止了之前的 Input 则 ErrorLevel 被设置为 0, 如果没有需要终止的 Input 则为 1.
NewInput | 此 Input 被另一个使用 Input 的 线程 中断.
Max | 输入的文本达到了允许的最大长度且没有匹配 MatchList 中的任何一项.
超时 | 输入超时.
Match | 输入的内容匹配 MatchList 中的某项.
EndKey:name | EndKeys 的某个终止键被按下来终止了输入. 此时，ErrorLevel 包含单词 EndKey 后跟着冒号和不带大括号的终止键的名称，例如 “EndKey:Enter”，“EndKey:Escape”等等。

备注

如果在使用此命令时另一个 线程 中的 Input 正在执行, 则那个 Input 会被终止且其 ErrorLevel 会被设置为单词 NewInput. 之后 (如果给出了参数), 新的 Input 开始执行.

在执行 Input 时, 仍然可以启动新的 线程 (例如 自定义菜单项 和 计时子程序). 同样地, 当 Input 可见 时键盘 热键 仍然是有效的. 如果 Input 不可见, 那么只会触发 钩子热键.

脚本中首次使用此命令时, 会安装 键盘钩子 (在还没有安装时). 同时, 脚本变成 持续运行的, 这意味着应该使用 ExitApp 结束脚本. 键盘钩子会一直保持加载状态, 直到下一次使用 Suspend 或 Hotkey 命令, 此时如果没有任何热键或热字串需要那么它会被移除.

如果您使用多种语言或多种键盘布局, 则 Input 会使用活动窗口的键盘布局而不是脚本的 (不论 Input 是否 可见). 然而, 在 1.0.44.03 之前的脚本中, 则使用脚本自己的布局.

尽管不够灵活, 但 热字串 通常比 Input 命令更容易使用.

相关

KeyWait, 热字串, InputBox, #InstallKeybdHook, 线程, if var in/contains MatchList

示例

; 等待用户按下任意键.  产生不可见字符的这些键 (例如
; 修饰键, 功能键和方向键) 已经被列为终止键, 这样
; 就能检测到它们.
Input, SingleKey, L1, {LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{BS}{Capslock}{Numlock}{PrintScreen}{Pause}

; 这是个可运行的热键示例.  由于此热键含有颚化符（~）
; 前缀，所以它本身的键击会被传递到活动窗口。; 因此，如果您键入 [btw（或其他某个匹配
; 词组）到任意编辑器中，脚本会自动执行
; 您选择的动作（例如替换键入的文本）：

~[::
Input, UserInput, V T5 L4 C, {enter}.{esc}{tab}, btw,otoh,fl,ahk,ca
if (ErrorLevel = "Max")
{
    MsgBox, You entered "%UserInput%", which is the maximum length of text.
    return
}
if (ErrorLevel = "Timeout")
{
    MsgBox, You entered "%UserInput%" at which time the input timed out.
    return
}
if (ErrorLevel = "NewInput")
    return
If InStr(ErrorLevel, "EndKey:")
{
    MsgBox, You entered "%UserInput%" and terminated the input with %ErrorLevel%.
    return
}
; 否则，找到了匹配。
if (UserInput = "btw")
    Send, {backspace 4}by the way
else if (UserInput = "otoh")
    Send, {backspace 5}on the other hand
else if (UserInput = "fl")
    Send, {backspace 3}Florida
else if (UserInput = "ca")
    Send, {backspace 3}California
else if (UserInput = "ahk")
    Run, http://ahkscript.org
return


MouseClick

点击或按住鼠标按钮，或滚动鼠标滚轮。注意：Click 命令通常更灵活和易于使用。

MouseClick [, WhichButton , X, Y, ClickCount, Speed, D|U, R]

参数

WhichButton

要点击的按钮：Left（默认）、Right、Middle（或仅使用这些名称的首个字母），或鼠标的第四或第五个按钮（X1 或 X2）。例如：MouseClick, X1。此参数可以省略, 此时它默认为 Left.

要转动的鼠标滚轮：指定 WheelUp 或 WU 来向上转动滚轮（远离您的方向），指定 WheelDown 或 WD 来向下转动滚轮（靠近您的方向）。在 v1.0.48+, 使用 WheelLeft (或 WL) 或 WheelRight (或 WR) 分别向左或向右滚动滚轮 (但是它们在比 Windows Vista 早的操作系统中没有效果). ClickCount 为需要转动的滚轮格数.

要避免受用户通过系统控制面板对左右键功能交换的设置的影响, 请使用 Click 命令 代替.

X, Y

在点击前, 鼠标光标要移动到的 x/y 坐标, 可以为 表达式. 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置. 如果省略, 那么使用光标的当前位置.

ClickCount

点击鼠标的次数，可以为表达式。如果省略, 那么点击鼠标一次.

Speed

移动鼠标的速度，介于 0（最快）和 100（最慢）之间，可以为表达式。注：速度为 0 表示瞬时移动鼠标到目标位置。如果省略，则使用默认速度（通过 SetDefaultMouseSpeed 设置，若为设置则使用 2）。

在 SendInput/Play 模式 中会忽略 Speed; 它们会瞬时移动鼠标到目标位置 (不过 SetMouseDelay 有适用于 SendPlay 的模式). 要显示鼠标移动轨迹（例如使用脚本向观众进行演示时），请使用 SendEvent {Click 100, 200} 或 SendMode Event（可以和 BlockInput 联合使用）。

D|U

如果省略此参数, 则每次点击会由 "按下" 事件后接着 "弹起" 事件组成. 或者:
D = 按下鼠标按钮后不释放 (即生成按下事件).
U = 释放鼠标按钮 (即生成弹起事件).

R

如果此参数为字母 R, 则会把 X 和 Y 坐标视为距离当前鼠标位置的偏移. 换句话说, 会把光标从当前位置往右移动 X 像素 (负值则往左) 且往下移动 Y 像素 (负值则往上).

备注

此命令的发送模式由 SendMode 设置.

比起 MouseClick, 更推荐使用 Click 命令, 因为:

  1. 它自动适应控制面板中左右键功能交换的设置.
  2. 它一般更容易使用.

要进行 shift-click 或 control-click, 请在操作前后使用 Send 命令, 例如:

; 示例 #1:
Send, {Control down}
MouseClick, left, 55, 233
Send, {Control up}
; 示例 #2:
Send, {Shift down}
MouseClick, left, 55, 233
Send, {Shift up}

SendPlay 模式 生成的鼠标事件可以比其他模式适应更大范围的游戏. 此外, 某些应用程序和游戏在鼠标移动过快时可能会跟踪困难. 可以使用 SetDefaultMouseSpeed 的 speed 参数来降低鼠标的速度 (仅对默认的 SendEvent 模式 有效).

有些程序不接受鼠标滚轮转动的格数 ClickCount 大于 1 的情况. 对于这些程序, 请参考下面的例子使用 Loop:

Loop, 5
    MouseClick, WheelUp

可以使用 BlockInput 命令防止用户对鼠标的任何物理操作扰乱由鼠标命令生成的模拟鼠标事件. 不过, 在 SendInput/Play 模式中通常不需要这个命令, 因为它们会自动延迟用户对鼠标的物理操作到发送之后.

在每次鼠标按下事件和鼠标弹起事件后都会有一个自动的延时 (不包括在 SendInput 模式 中转动鼠标滚轮的情况). 使用 SetMouseDelay 可以改变延时的长度.

相关

CoordMode, SendMode, SetDefaultMouseSpeed, SetMouseDelay, Click, MouseClickDrag, MouseGetPos, MouseMove, ControlClick, BlockInput

示例

; 在当前鼠标位置双击:
MouseClick, left
MouseClick, left

; 和上面相同:
MouseClick, left, , , 2

; 移动到指定的坐标然后点击一次右键:
MouseClick, right, 200, 300

; 这里是两个模拟转动鼠标滚动的热键:
#up::MouseClick, WheelUp, , , 2  ; Turn it by two notches.
#down::MouseClick, WheelDown, , , 2


MouseClickDrag

点击并按住指定的鼠标按钮，接着移动鼠标到目标坐标，然后松开按钮。

MouseClickDrag, WhichButton, X1, Y1, X2, Y2 [, Speed, R]

参数

WhichButton

要点击的按钮: Left, Right, Middle (或这些单词的首个字母). 对于第四个按钮使用 X1，对第五个则用 X2。例如：MouseClickDrag, X1, ...。

要避免受用户通过系统控制面板对左右键功能交换的设置的影响, 请使用 Click 命令 代替.

X1, Y1

拖动的起始位置的 x/y 坐标, 可以为 表达式 (在开始拖动前会移动鼠标到这个坐标). 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置. 如果省略, 则使用鼠标的当前位置.

X2, Y2

拖动的目标位置的 x/y 坐标, 可以为 表达式. 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置.

Speed

移动鼠标的速度，介于 0（最快）和 100（最慢）之间，可以为表达式。注：速度为 0 表示瞬时移动鼠标到目标位置。如果省略，则使用默认速度（通过 SetDefaultMouseSpeed 设置，若为设置则使用 2）。

在 SendInput/Play 模式 中会忽略 Speed; 它们会瞬时移动鼠标到目标位置 (不过 SetMouseDelay 有适用于 SendPlay 的模式). 要显示鼠标移动轨迹（例如使用脚本向观众进行演示时），请使用 SendEvent {Click 100, 200} 或 SendMode Event（可以和 BlockInput 联合使用）。

R

如果此参数为字母 R, 则会把 X1 和 Y1 坐标视为距离当前鼠标位置的偏移. 换句话说, 会把光标从当前位置往右移动 X1 像素 (负值则往左) 且往下移动 Y1 像素 (负值则往上).

同样地, 会把 X2 和 Y2 坐标视为距离 X1 和 Y1 坐标的偏移. 例如，后面的例子中会首先把鼠标从起始位置往下和往右移动 5 个像素，然后从这个位置往下和往右拖动 10 个像素：MouseClickDrag, Left, 5, 5, 10, 10, , R。

备注

此命令的发送模式由 SendMode 设置.

还可以使用其他 Send 命令进行拖动, 这样更灵活, 因为可以通过命令名指定发送的模式. 例如：

SendEvent {Click 6, 52, down}{click 45, 52, up}

上面这种方法的另一个好处是与 MouseClickDrag 不同, 它不受用户通过系统控制面板对左右键功能交换的设置的影响.

SendPlay 模式 生成的鼠标事件可以比其他模式适应更大范围的游戏. 然而, 使用 SendPlay 进行拖动操作在 RichEdit 控件中 (可能还有其他的) 例如 WordPad 和 Metapad, 可能无法工作.

某些应用程序和游戏在鼠标移动过快时可能会跟踪困难. 可以使用 SetDefaultMouseSpeed 的 speed 参数来降低鼠标的速度 (仅对默认的 SendEvent 模式 有效).

可以使用 BlockInput 命令防止用户对鼠标的任何物理操作扰乱由鼠标命令生成的模拟鼠标事件. 不过, 在 SendInput/Play 模式中通常不需要这个命令, 因为它们会自动延迟用户对鼠标的物理操作到发送之后.

在每次鼠标按下事件和鼠标弹起事件后都会有一个自动的延时 (不包括 SendInput 模式). 此延时同样发生在拖动期间鼠标的移动之后. 使用 SetMouseDelay 可以改变延时的长度.

相关

CoordMode, SendMode, SetDefaultMouseSpeed, SetMouseDelay, Click, MouseClick, MouseGetPos, MouseMove, BlockInput

示例

MouseClickDrag, left, 0, 200, 600, 400

; 下面的例子打开微软的画图工具并画一个小房子:
Run, mspaint.exe
WinWaitActive, ahk_class MSPaintApp,, 2
if ErrorLevel
    return
MouseClickDrag, L, 150, 250, 150, 150
MouseClickDrag, L, 150, 150, 200, 100
MouseClickDrag, L, 200, 100, 250, 150
MouseClickDrag, L, 250, 150, 150, 150
MouseClickDrag, L, 150, 150, 250, 250
MouseClickDrag, L, 250, 250, 250, 150
MouseClickDrag, L, 250, 150, 150, 250
MouseClickDrag, L, 150, 250, 250, 250


MouseGetPos

获取鼠标光标的当前位置以及鼠标当前悬停的窗口和控件（可选的）。

MouseGetPos, [OutputVarX, OutputVarY, OutputVarWin, OutputVarControl, 1|2|3]

参数

OutputVarX/Y

用来保存 X 和 Y 坐标的变量名. 获取的坐标相对于活动窗口, 除非曾使用 CoordMode 改变成屏幕坐标.

OutputVarWin

这个可选的参数是用来保存鼠标光标下窗口的 唯一 ID 号 的变量名. 如果无法检测到此窗口, 则此变量被置空.

即使窗口不处于活动状态, 也能检测到它的信息. 无法检测到隐藏窗口.

OutputVarControl

这个可选的参数是用来保存鼠标光标下控件的类名 (ClassNN) 的变量名. 如果无法检测到此控件, 则此变量被置空.

这里控件的名称应该总是和随 v1.0.14+ 一起发布的 Window Spy 中显示的相同 (但可能和旧版 Window Spy 显示的不同). 然而, 与 Window Spy 不同的是, 即使鼠标光标下的窗口不处于活动状态, 也能检测到其中控件的信息.

1|2|3

如果省略, 则它默认为 0. 否则, 请指定下列数字的其中一个:

1: 使用更简单的方法来获取 OutputVarControl. 这种方法可以正确获取多文档界面 (MDI) 应用程序 (例如 SysEdit 或 TextPad) 的活动/顶级子窗口的信息. 不过, 对于其他的情况 (例如获取 GroupBox 控件中的控件) 就没有那么准确了.

2 [v1.0.43.06+]: 把 控件的 HWND 保存到 OutputVarControl 而不是控件的 ClassNN.

3 [v1.0.43.06+]: 上面 1 和 2 选项的组合.

备注

如果不需要相应的信息, 则可以省略相应的输出变量.

相关

CoordMode, WinGet, SetDefaultMouseSpeed, Click

示例

MouseGetPos, xpos, ypos
Msgbox, The cursor is at X%xpos% Y%ypos%.

; 这里例子允许您移动鼠标来查看
; 鼠标悬停窗口的标题:
#Persistent
SetTimer, WatchCursor, 100
return

WatchCursor:
MouseGetPos, , , id, control
WinGetTitle, title, ahk_id %id%
WinGetClass, class, ahk_id %id%
ToolTip, ahk_id %id%`nahk_class %class%`n%title%`nControl: %control%
return


MouseMove

移动鼠标光标。

MouseMove, X, Y [, Speed, R]

参数

X, Y

鼠标移动的目标位置的 x/y 坐标, 可以为 表达式. 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置.

Speed

移动鼠标的速度，介于 0（最快）和 100（最慢）之间，可以为表达式。注：速度为 0 表示瞬时移动鼠标到目标位置。如果省略，则使用默认速度（通过 SetDefaultMouseSpeed 设置，若为设置则使用 2）。

在 SendInput/Play 模式 中会忽略 Speed; 它们会瞬时移动鼠标到目标位置 (不过 SetMouseDelay 有适用于 SendPlay 的模式). 要显示鼠标移动轨迹（例如使用脚本向观众进行演示时），请使用 SendEvent {Click 100, 200} 或 SendMode Event（可以和 BlockInput 联合使用）。

R

如果此参数为字母 R, 则会把 X 和 Y 坐标视为距离当前鼠标位置的偏移. 换句话说, 会把光标从当前位置往右移动 X 像素 (负值则往左) 且往下移动 Y 像素 (负值则往上).

备注

此命令的发送模式由 SendMode 设置.

SendPlay 模式 生成的鼠标事件可以比其他模式适应更大范围的游戏. 此外, 某些应用程序和游戏在鼠标移动过快时可能会跟踪困难. 可以使用 SetDefaultMouseSpeed 的 speed 参数来降低鼠标的速度 (仅对默认的 SendEvent 模式 有效).

可以使用 BlockInput 命令防止用户对鼠标的任何物理操作扰乱由鼠标命令生成的模拟鼠标事件. 不过, 在 SendInput/Play 模式中通常不需要这个命令, 因为它们会自动延迟用户对鼠标的物理操作到发送之后.

在每次鼠标移动后会有一个自动的延时 (不包括 SendInput 模式). 使用 SetMouseDelay 可以改变延时的长度.

下面是另一种移动鼠标的方法, 它在某些多显示器环境中可能工作得更好:

DllCall("SetCursorPos", int, 100, int, 400)  ; 第一个数字是 X 坐标而第二个是 Y (相对于屏幕).

相关提示, 鼠标光标可以通过 隐藏光标示例 临时隐藏起来.

相关

CoordMode, SendMode, SetDefaultMouseSpeed, SetMouseDelay, Click, MouseClick, MouseClickDrag, MouseGetPos, BlockInput

示例

; 移动鼠标到新位置:
MouseMove, 200, 100

; 缓慢移动鼠标 (速度 50 比较起默认的 2 显然要缓慢) 到
; 距离当前位置右边 20 个像素且在下面 30 个像素的位置:
MouseMove, 20, 30, 50, R


Send/SendRaw/SendInput/SendPlay/SendEvent：发送按键和点击

Send / SendRaw / SendInput / SendPlay / SendEvent: 发送按键和点击

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

Send Keys
SendRaw Keys
SendInput Keys
SendPlay Keys
SendEvent Keys

参数

键

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

原始模式: SendRaw 命令会原样发送所有字符, 而不把 {Enter} 转换成 ENTER 键击, 把 ^c 转换成 Control-C, 等等. 不过, 转义系列, 变量引用和表达式的一般规则仍然适用, 因为它们在命令执行前就已经被处理了. 要在 SendInput、SendPlay 或 SendEvent 中使用原始模式，请把 {Raw} 写在需发送的按键序列前面；例如：SendInput {Raw}abc。

普通模式: 不处于原始模式时, 下列字符被看成是修饰键 (这些修饰键仅影响紧跟着的下一个键):

!: 发送 ALT 键击. 例如，Send This is text!a 将发送按键序列“This is text”并接着按下 ALT+a。注: 在某些程序中 !A 和 !a 会产生不同的效果. 这是由于 !A 按了 ALT+SHIFT+A 而 !a 按了 ALT+a. 如果不确定, 请使用小写字母.

+: 发送 SHIFT 键击. 例如，Send +abC 会发送文本“AbC”，而 Send !+a 会按下 ALT+SHIFT+a。

^: 发送 CONTROL 键击. 例如，Send ^!a 会按下 CTRL+ALT+a，而 Send ^{Home} 则发送 CONTROL+HOME。注: 在某些程序中 ^A 和 ^a 会产生不同的效果. 这是由于 ^A 按了 CONTROL+SHIFT+A 而 ^a 按了 CONTROL+a. 如果不确定, 请使用小写字母.

#：发送 WIN 键击，因此 Send #e 会在按住 Windows 键时按下字母“e”。

SendInput 和 SendPlay [v1.0.43+]: SendInput 和 SendPlay 与 Send 使用相同的语法但通常更快更可靠. 此外, 它们缓存了发送期间任何物理的键盘或鼠标活动, 这样避免了在发送时夹杂用户的键击. 可以使用 SendMode 让 Send 和 SendInput 或 SendPlay 执行相同的功能. 关于每种模式的更多细节, 请参阅下面的 SendInput 和 SendPlay.

SendEvent [v1.0.43+]: SendEvent 和 1.0.43 之前版本的 Send 命令使用相同的方法发送键击. 键击发送的频率由 SetKeyDelay 决定. 默认情况下, Send 和 SendEvent 功能相同; 但通过 SendMode 可以让它变成和 SendInput 或 SendPlay 一样.

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

按键名称 | 生成的键击
{F1} - {F24} | 功能键. 例如: {F12} 表示 F12 键.
{!} !
{#} #
{+} +
{^} ^
{{} {
{}} }
{Enter} | 主键盘上的 ENTER 键
{Escape} 或 {Esc} | ESCAPE
{Space} | SPACE (仅对于要发送的按键序列开始或末尾的空格才需要这样表示, 而序列中间的空格是原义的)
{Tab} | TAB
{Backspace} 或 {BS} | 退格键
{Delete} 或 {Del} | Delete
{Insert} 或 {Ins} | Insert
{Up} | 主键盘上的向上键
{Down} | 主键盘上的向下键
{Left} | 主键盘上的向左键
{Right} | 主键盘上的向右键
{Home} | 主键盘上的 Home 键
{End} | 主键盘上的 End 键
{PgUp} | 主键盘上的向上翻页键
{PgDn} | 主键盘上的向下翻页键
{CapsLock} | CapsLock（在 2k/XP 中使用 SetCapsLockState 更可靠）。发送 {CapsLock} 之前可能要求 SetStoreCapslockMode Off.
{ScrollLock} | ScrollLock (另请参阅: SetScrollLockState)
{NumLock} | NumLock (另请参阅: SetNumLockState)
{Control} 或 {Ctrl} | CONTROL (技术信息: 发送中性的虚拟按键代码和左边的扫描码, 即在 vkXXscYYY 中, XX 为中性的而 YYY 为左边的扫描码)
{LControl} 或 {LCtrl} | 左 CONTROL 键（技术信息：发送左边的虚拟按键而非中性的那个）
{RControl} 或 {RCtrl} | 右 CONTROL 键
{Control Down} 或 {Ctrl Down} | 按住 CONTROL 键直到发送 {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} | 左 Windows 键
{RWin} | 右 Windows 键
{LWin Down} | 按住左 Windows 键直到发送 {LWin Up}
{RWin Down} | 按住右 Windows 键直到发送 {RWin Up}
{AppsKey} | Windows Appskey (调用右键点击或上下文菜单)
{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 菜单项找到. 另请参阅: 特殊按键
{Numpad0} - {Numpad9} | 小键盘上的数字键 (与 Numlock 打开时输入的一样). 例如: {Numpad5} 为数字 5.
{NumpadDot} | 小键盘上的点 (与 Numlock 打开时输入的一样).
{NumpadEnter} | 小键盘上的 Enter 键
{NumpadMult} | 小键盘上的乘
{NumpadDiv} | 小键盘上的除
{NumpadAdd} | 小键盘上的加
{NumpadSub} | 小键盘上的减
{NumpadDel} | 小键盘上的 Delete 键 (此键和后面的小键盘按键是在 Numlock 关闭时输入的)
{NumpadIns} | 小键盘上的 Insert 键
{NumpadClear} | 小键盘上的 Clear 键 (通常在 Numlock 关闭时输入 '5' 的键).
{NumpadUp} | 小键盘上的向上键
{NumpadDown} | 小键盘上的向下键
{NumpadLeft} | 小键盘上的向左键
{NumpadRight} | 小键盘上的向右键
{NumpadHome} | 小键盘上的 Home 键
{NumpadEnd} | 小键盘上的 End 键
{NumpadPgUp} | 小键盘上的向上翻页键
{NumpadPgDn} | 小键盘上的向下翻页键
{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} | Print Screen
{CtrlBreak} | Ctrl+break
{Pause} | 暂停
{Click [选项]}
[v1.0.43+] 		使用与 Click 命令 中相同的可用选项发送鼠标点击. 例如，{Click} 会在鼠标光标当前位置点击一次鼠标左键，而 {Click 100, 200} 则在坐标 100, 200 处点击（这里的坐标模式取决于 CoordMode）。要移动鼠标而不点击，请在坐标后指定 0；例如：{Click 100, 200, 0}。在鼠标点击之间的延迟由 SetMouseDelay 决定（而不是 SetKeyDelay）。
{WheelDown}, {WheelUp}, {WheelLeft}, {WheelRight}, {LButton}, {RButton}, {MButton}, {XButton1}, {XButton2} | 向指针当前位置发送鼠标按钮事件 (要指定位置和其他选项, 请使用上面的 {Click}). 在鼠标点击之间的延迟由 SetMouseDelay 决定. WheelLeft/Right 需要 v1.0.48+, 并且在 Windows Vista 之前的操作系统中没有效果.
{Blind}

当按键序列中首个项目为 {Blind} 时, 如果 Alt/Control/Shift/Win 在发送开始时为按下的状态则不松开. 例如，热键 +s::Send {Blind}abc 将发送 ABC 而不是 abc，因为用户按住了 Shift 键。

{Blind} 还会忽略 SetStoreCapslockMode; 即不会改变 Capslock 的状态. 最后, {Blind} 会忽略发送的键击中的额外控制功能; 这样的键击中可以避免后面的情况: 1) 发送 LWin/RWin 键击时出现开始菜单; 2) 发送 Alt 键击时激活菜单栏.

在 按键的重映射 内部使用了 Blind 模式. 例如, 重映射 a::b 会发生这样的情况: 1) 输入 "a" 时会映射为 "b"; 2) 输入大写字母 A 时映射为大写字母 B; 并且 3) 按下 Control-A 时映射为按了 Control-B.

SendRaw 和 ControlSendRaw 不支持 {Blind}. 此外, SendPlay 也不完全支持这种模式, 尤其是在处理修饰键 (Control, Alt, Shift 和 Win) 时.
{Raw}
[v1.0.43+] 		准确按照原样发送键击，而不把 {Enter} 转换成 ENTER 键击，把 ^c 转换成 Control-C 等等。{Raw} 可以不放在按键序列的开始处, 在按键序列中出现时, 它会影响它后面的剩余部分.

重复或按住按键

重复键击: 把需要重复的按键名称和重复次数写入到大括号中. 例如：

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}  ; 松开按键.

还可以使用单词 DownTemp. 除了对修饰键 (Control/Shift/Alt/Win) 有区别外它的效果与 Down 相同. 在那些情况下, DownTemp 告知后续的 send 命令这个键不是永久按下, 并可能在需要时随时松开. 例如，Send {Control DownTemp} 之后接着执行 Send a 会产生普通的“a”键击，而不是 control-A 键击。

一般说明

Send 命令支持发送的字符没有特殊限制。对于当前键盘布局中不存在的字符，根据 AutoHotkey 版本的不同可以通过发送 Unicode 字符包或 Alt+nnnnn 组合来模拟。在 AutoHotkey 的 Unicode 版本中直接支持文本形式的 Unicode 字符，而在所有版本中都可以使用 {U+nnnn} 表示法。

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

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

由于操作系统不允许程序模拟 CTRL-ALT-DELETE 组合键，所以执行像 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 最大的优势是具有在相当多种游戏中 "play back" 键击和鼠标点击能力. 例如, 某种特殊的游戏可能仅接受 SendPlay 选项 的 热字串. 但是, SendPlay 在启用了用户账户控制的 Windows Vista 或更高版本中则可能没有效果, 即使以管理员运行脚本. 下面的脚本提供了此问题的变通解决方法: http://www.autohotkey.com/forum/topic75595.html.

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

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

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

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

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

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

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

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

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

相关

SendMode, SetKeyDelay, SetStoreCapslockMode, 转义序列（例如 `%）, ControlSend, BlockInput, 热字串, WinActivate

示例

Send Sincerely,{enter}John Smith  ; 输入两行的签名.
Send !fs ; 选择 File->Save 菜单 (Alt+F 后面跟着 S).
Send {End}+{Left 4} ; 跳到文本的末尾然后发送四次 shift 和左方向键组合的键击.
SendInput {Raw}A long series of raw characters sent via the fastest method (SendInput).


SendLevel

SendLevel [v1.1.06+]

控制热键和热字串是否忽略模拟的键盘和鼠标事件。

SendLevel, Level

参数

Level

介于 0 和 100 之间的整数, 可以为 表达式.

一般说明

默认情况下, 钩子 热键 和 热字串 会忽略由任何 AutoHotkey 脚本生成的键盘和鼠标事件. 在某些情况下它可用于覆盖默认行为; 例如, 可使用重映射键来触发其他热键. SendLevel 和 #InputLevel 提供了实现此目的的方法.

SendLevel 设置由当前 脚本线程 生成的事件级别, 而 #InputLevel 设置它下面所有热键或热字串的级别. 要让脚本生成的事件触发钩子热键或热字串, 则此事件的发送级别必须高于热键或热字串的输入级别.

兼容性：

  • SendPlay 不受 SendLevel 影响。
  • SendInput 会受 SendLevel 的影响，但在 SendInput 执行时其所在脚本中的钩子热键无法激活，因为这个命令会让钩子暂时失效。
  • 使用 "reg" 方法实现的热键不能区分物理和模拟输入, 所以不会受 SendLevel 的影响. 然而, 级别高于 0 的热键总是使用了键盘或鼠标钩子.
  • 自动替换型 热字串 生成事件的级别总是为 0, 因为通常在替换文本时不希望触发其他热字串或热键. 要变通解决此问题, 请使用非自动替换型热字串和 Send 命令.
  • 任何没有与当前键盘布局中的按键相对应的字符都无法触发热字串，即使使用 SendLevel 也不行。这是热字串识别程序的限制。

每个新运行的热键或热字串 线程 初始的发送级别等于此热键或热字串的 输入级别. 每个新运行的其他线程 (例如 自定义菜单项 或 定时 子程序) 都会以默认设置开始, 一般为 0, 不过可以在 自动执行段 中使用此命令进行改变.

如果在 自动执行段 中使用 SendLevel, 它还会影响 键盘和鼠标重映射.

早于 v1.1.06 的 AutoHotkey 版本会表现的就像 #InputLevel 0 和 SendLevel 0 那样。

相关

#InputLevel, Send, Click, MouseClick, MouseClickDrag

示例

SendLevel 1
Send btw{Space} ; 生成 "by the way ".

; 这可以在其他脚本中定义:
::btw::by the way


SendMode

SendMode [v1.0.43+]

让 Send 和 SendInput 或 SendPlay 具有相同的功能而不是默认的（SendEvent）。也使 Click 和 MouseMove/Click/Drag 使用指定的方法。

SendMode Input|Play|Event|InputThenPlay

首个参数为下列单词的其中一个:

Event: 这是所有脚本开始时默认使用的. 它让 Send, SendRaw, Click 和 MouseMove/Click/Drag 使用 SendEvent 模式.

Input: 让 Send, SendRaw, Click 和 MouseMove/Click/Drag 切换到 SendInput 方法. 已知限制:

  • Windows 资源管理器会忽略 SendInput 模拟的某些导航的热键, 例如 Alt+LeftArrow. 要变通解决此问题，请使用 SendEvent !{Left} 或 SendInput {Backspace}。

InputThenPlay [v1.0.43.02+]: 与上面相同, 不过当 SendInput 不可用 时恢复为下面的 Play 模式而不是退回到 Event 模式. 这也会使得 SendInput 命令 自身在 SendInput 不可用时恢复到 Play 模式.

Play: 让 Send, SendRaw, Click 和 MouseMove/Click/Drag 切换到 SendPlay 方法.
已知限制:

  • 不能发送在当前键盘布局上不存在的字符 (例如英语中的 Ô). 要变通解决此问题, 请使用 SendEvent.
  • 在 RichEdit 控件 (可能还有其他的) 例如 WordPad 和 Metapad, 模拟鼠标拖动可能没有效果. 要为特殊的拖动使用替换模式，请参照此例：SendEvent {Click 6, 52, down}{Click 45, 52, up}。
  • 模拟鼠标滚轮的滚动只进行一个方向上的移动 (通常是向下, 但在一些程序中可能是向上). 此外, 滚轮的滚动在类似 MS Word 和 Notepad 的程序中可能没有效果. 要为特殊的滚动使用替换模式，请参照此例：SendEvent {WheelDown 5}。
  • 当在自动执行段（脚本的顶部）使用 SendMode Play 时，会影响所有的重映射按键并可能失去它们的某些功能。请参阅 SendPlay 的重映射限制 了解详情.
  • SendPlay 不会触发 AutoHotkey 的热键或热字串及由操作系统或其他程序注册的全局热键。

备注

由于 SendMode 也改变了 Click 和 MouseMove/Click/Drag 的模式, 所以您有机会为特殊的鼠标事件使用不同的模式. 实现这种操作最便捷的方法是使用 {Click}. 例如：

SendEvent {Click 100, 200}  ; SendEvent 使用更老更传统的方法进行点击.

如果在自动执行段 (脚本的顶部) 使用了 SendMode, 那么它还会影响 键盘和鼠标重映射. 尤其是您在重映射时使用了 SendMode Play，请参阅 SendPlay 的重映射限制。

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

Send, SetKeyDelay, SetMouseDelay, Click, MouseClick, MouseClickDrag, MouseMove

示例

SendMode Input
SendMode InputThenPlay


SetDefaultMouseSpeed

设置在 Click 和 MouseMove/Click/Drag 中没有指定鼠标速度时使用的速度。

SetDefaultMouseSpeed, Speed

参数

Speed

移动鼠标的速度，介于 0（最快）和 100（最慢）之间。注：速度为 0 表示瞬时移动鼠标到目标位置。此参数可以为 表达式.

备注

在 SendInput/Play 模式 中会忽略 SetDefaultMouseSpeed; 它们会瞬时移动鼠标到目标位置 (然而, SetMouseDelay 有适用于 SendPlay 的模式). 要显示鼠标移动轨迹（例如使用脚本向观众进行演示时），请使用 SendEvent {Click 100, 200} 或 SendMode Event（可以和 BlockInput 联合使用）。

如果没有使用此命令, 则默认鼠标速度为 2. 内置变量 A_DefaultMouseSpeed 包含了当前的设置.

命令 MouseClick, MouseMove 和 MouseClickDrag 都提供了一个用来设置鼠标速度代替默认速度的参数.

每当 Speed 大于零时, SetMouseDelay 还会影响在鼠标朝目标位置移动时的速度, 这是通过在鼠标每次移动后产生的延迟实现的.

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

SetMouseDelay, SendMode, Click, MouseClick, MouseMove, MouseClickDrag, SetWinDelay, SetControlDelay, SetKeyDelay, SetKeyDelay

示例

SetDefaultMouseSpeed, 0 ; 瞬时移动鼠标.


SetKeyDelay

设置每次 Send 和 ControlSend 发送键击后自动的延时.

SetKeyDelay [, Delay, PressDuration, Play]

参数

Delay

毫秒表示的时间, 可以为 表达式. 使用 -1 表示无延时，而 0 表示最小延时（然而如果使用了 Play 参数，则 0 和 -1 都表示无延时）。留空此参数来保持当前的 Delay.

如果脚本中没有使用过 SetKeyDelay，则对于传统的 SendEvent 模式默认 Delay 为 10。对于 SendPlay 模式, 默认 Delay 为 -1. 对于这两种模式默认的 按住时长 (下面的) 为 -1.

PressDuration

某些游戏和特殊的应用程序可能要求每次键击具有一定的按下时间; 即按下按键后, 持续一段时间, 然后才松开.

使用 -1 表示无延时 (默认), 而 0 表示最小延时 (然而, 如果使用了 Play 参数, 则 0 和 -1 都表示无延时). 注: 这里的延时指按住按键的持续时间, 上面的延时是两次键击之间的间隔时间. 省略此参数来保留当前的 按住时长 不变.

注: PressDuration 同样会在支持其他按键发送的修饰键 (CTRL, ALT, SHIFT 和 WIN) 状态改变后产生延时.

此参数可以为 表达式.

Play
[v1.0.43+]

单词 Play 会把上面的设置应用于 SendPlay 模式 而不是传统的 SendEvent 模式. 如果脚本没有使用此参数, 则 SendPlay 模式的延时总是为 -1/-1.

备注

注: SetKeyDelay 的设置不会影响 SendInput; 在这种模式的键击之间没有延时. 当 SendMode Input 生效时对于 Send 同样如此.

在每次 Send 或 ControlSend 发送键击后会自动进行短暂的延时. 这样做提高了脚本的可靠性, 因为窗口有时无法响应快速的键击流.

由于操作系统计时系统的精确度, 延时可能会被向上取整到最近的 10 或 15 的倍数. 例如，在大部分 Windows XP 系统上介于 1 和 10（含边界）的延时都相当于 10 或 15（可能也适用于 2k）。

对于 Send/SendEvent 模式, 延时为 0 时实际内部会执行 Sleep(0), 这样会将脚本时间片的剩余部分分配给其他需要的进程. 如果没有进程需要, 那么 Sleep(0) 相当于完全没有延时. 与之相比, 延时为 -1 则从不休眠. 为了提高可靠性, 推荐使用 0 而不是 -1.

当延时设为 -1 时, 脚本的进程优先级会成为传统的 SendEvent 模式 中键击发送速度的重要因素. 要提升脚本的优先级，请使用 Process, Priority,, High。尽管这通常会使得键击发送的速度超过 活动窗口 的处理速度, 不过系统会自动对它们进行缓冲. 在 Send 命令完成后, 被缓冲的键击会继续到达目标窗口 (即使此窗口现在已经不是活动窗口). 这种情况一般是不要紧的, 因为任何后续发送给相同窗口的键击会排列在缓冲中的那些键击之后.

内置变量 A_KeyDelay 包含了 Send/SendEvent 模式的当前 Delay 设置。没有对应于 PressDuration 或 SendPlay 的 Delay 的内置变量。

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

Send, ControlSend, SendMode, SetMouseDelay, SetControlDelay, SetWinDelay, SetBatchLines, Click

示例

SetKeyDelay, 0


SetMouseDelay

设置每次鼠标移动或点击后自动的延时。

SetMouseDelay, Delay [, Play]

参数

Delay

毫秒表示的时间, 可以为 表达式. 使用 -1 表示无延时，而 0 表示最小延时（然而如果使用了 Play 参数，则 0 和 -1 都表示无延时）。如果未设置, 则对于传统的 SendEvent 模式默认延时为 10 而对于 SendPlay 模式 为 -1.

Play
[v1.0.43+]

单词 Play 会把上面的延时应用于 SendPlay 模式 而不是传统的 SendEvent 模式. 如果脚本没有使用此参数, 则 SendPlay 模式的延时总是为 -1.

备注

在每次 Click 和 MouseMove/Click/Drag 生成的鼠标移动或点击后会自动进行短暂的延时 (除非处于 SendInput 模式). 这样做提高了脚本的可靠性, 因为窗口有时无法响应快速的鼠标事件流.

由于操作系统计时系统的精确度, 延时可能会被向上取整到最近的 10 或 15 的倍数. 例如，在大部分 Windows XP 系统上介于 1 和 10（含边界）的延时都相当于 10 或 15（可能也适用于 2k）。

延时为 0 时实际内部会执行 Sleep(0), 这样会将脚本时间片的剩余部分分配给其他需要的进程. 如果没有进程需要, 那么 Sleep(0) 相当于完全没有延时. 与之相比, 延时为 -1 则从不休眠.

内置变量 A_MouseDelay 包含了 Send/SendEvent 模式的当前设置 (没有用于 SendPlay 模式 的内置变量).

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

SetDefaultMouseSpeed, Click, MouseMove, MouseClick, MouseClickDrag, SendMode, SetKeyDelay, SetControlDelay, SetWinDelay, SetBatchLines

示例

SetMouseDelay, 0


SetCapsLockState/SetNumLockState/SetScrollLockState

设置 Capslock/NumLock/ScrollLock 键的状态. 还可以强制此键保持打开或关闭状态。

SetCapsLockState [, State]
SetNumLockState [, State]
SetScrollLockState [, State]

参数

State

如果省略此参数，则清除按键的AlwaysOn/Off状态（如果存在）。否则, 请指定下列单词的其中一个:

On：打开按键并清楚按键的 AlwaysOn/Off 状态（如果存在）。

Off：关闭按键并清除按键的 AlwaysOn/Off 状态（如果存在）。

AlwaysOn：强制按键保持打开状态。

AlwaysOff：强制按键保持关闭状态。

备注

要把按键切换到相反的状态还可以通过 Send 命令，例如：Send {Capslock}。

保持一个按键 AlwaysOn 或 AlwaysOff 需要 键盘钩子, 在这样的情况中会自动进行安装.

相关

SetStoreCapslockMode, GetKeyState

示例

SetNumlockState, on
SetScrollLockState, AlwaysOff


SetStoreCapslockMode

设置在 Send 后是否恢复 CapsLock 的状态。

SetStoreCapslockMode, On|Off

参数

On|Off

On：这是所有脚本的初始设置，如果 Send 在发送时需要临时改变 CapsLock 的状态，则在发送后它会被恢复为之前的状态。

Off：CapsLock 的状态从不改变。所以，如果在 Send 发送时 Capslock 恰巧是打开的，则它所发送的字符是大小写颠倒的。

备注

这意味着在 Send 和 ControlSend 执行时不总是会关闭 Capslock. 即使成功关闭了, 在发送按键后也可能不会恢复原来的状态.

此命令极少使用, 因为在大多数情况中默认行为是最佳的.

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

SetCaps/Num/ScrollLockState, Send, ControlSend

示例

SetStoreCapslockMode, off


Random

生成伪随机数。

Random, OutputVar [, Min, Max]
Random, , NewSeed

参数

OutputVar

用来存储结果的变量名. 存储的浮点数的格式由 SetFormat 决定.

Min
可以生成的最小数字, 可以为负数, 浮点数或 表达式. 如果省略, 最小的数字默认为 0. 允许的最小整数值为 -2147483648, 但浮点数没有限制.
Max

可以生成的最大数字, 可以为负数, 浮点数或 表达式. 如果省略, 最大的数字默认为 2147483647 (这也是允许的最大整数值, 但浮点数没有限制).

NewSeed

此模式使用 NewSeed 重新设定随机数生成器的种子 (可以为 表达式). 这会影响后续生成的所有随机数. NewSeed 应该为介于 0 和 4294967295 (0xFFFFFFFF) 之间的整数. 重新设定种子可以提高随机数的质量/安全性, 尤其当 NewSeed 是真正的随机数而不是质量不佳的伪随机数时. 重新设定种子通常只需要进行一次.

如果脚本没有重新设定种子, 则使用自 1601 年 1 月 1 日开始 100 纳秒间隔数目的 64 位值的低 32 位作为种子开始. 这个值在 ~7.2 分钟内从 0 变化到 4294967295.

备注

此命令生成伪随机数, 即一个模拟真正随机数的数字, 但它实际上是通过复杂的公式计算使得判断/猜测下一个数字极为困难的数字.

在指定范围中所有数字被生成的机率几乎是相同的 (然而, 请参阅下面的 "已知限制").

如果 Min 或 Max 其中一个为小数，则最后结果将为由 SetFormat 设置格式的浮点数。否则，结果为整数。

结果为浮点数的已知限制: 1) 对于任何特殊的范围只能生成大约 4,294,967,296 个截然不同的数字, 所以永远不会生成范围中的其他所有数字; 2) 优势结果可能比指定的 Max 略大一些 (这种情况部分是由浮点数固有的不精确性导致的).

相关

SetFormat

示例

Random, rand, 1, 10
Random, rand, 0.0, 1.0

基于原始来源的注释

This function uses the Mersenne Twister random number generator, MT19937, written by Takuji Nishimura and Makoto Matsumoto, Shawn Cokus, Matthe Bellew and Isaku Wada.

The Mersenne Twister is an algorithm for generating random numbers. It was designed with consideration of the flaws in various other generators. The period, 219937-1, and the order of equidistribution, 623 dimensions, are far greater. The generator is also fast; it avoids multiplication and division, and it benefits from caches and pipelines. For more information see the inventors' web page at www.math.keio.ac.jp/~matumoto/emt.html

Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Do NOT use for CRYPTOGRAPHY without securely hashing several returned values together, otherwise the generator state can be learned after reading 624 consecutive values.

When you use this, send an email to: matumoto@math.keio.ac.jp with an appropriate reference to your work. It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu when you write.

This above has been already been done for AutoHotkey, but if you use the Random command in a publicly distributed application, consider sending an e-mail to the above people to thank them.


SetFormat

设置数学运算得到的整数和浮点数的格式。

SetFormat, NumberType, Format

参数

NumberType

必须为 IntegerFast, FloatFast, Integer 或 Float (其中两种快速模式需要 v1.0.48+; 请参阅 备注).

Format

当 NumberType 为 Integer 或 IntegerFast, 对于十六进制数请指定 H 或 HEX, 而十进制则指定 D. 十六进制数必须以前缀 0x 开头 (例如 0xFF). [AHK_L 42+]: 当此参数为 h 时十六进制数会被格式化为含有小写数字 A-F, 而为 H 时则为大写形式.

当 NumberType 为 Float 或 FloatFast，请指定总宽度.小数位数（例如 0.6）。在 v1.0.46.11+，可以在后面添加字母“e”来得到科学计数法表示的结果；例如 0.6e 或 0.6E（使用大写字母 E 则在结果的数字中使用大写的 E）。注：在 AutoHotkey 1.x，使用科学计数法表示格式时必须包含小数点；例如 1.0e1 是正确的但 1e1 则错误。

总宽度 通常为 0 表示结果不需要使用空格或零填充. 如果总宽度大于实际宽度, 则结果中将使用空格或零填充 (请参阅 备注) 到指定宽度.

小数位数 为要显示的小数部分的位数 (超出部分将进行四舍五入). 如果为空或零, 则结果中不会显示小数点和小数部分, 即浮点运算的结果会显示为整数而不是浮点数. 默认的小数位数为 6.

填充: 如果 总宽度 大于实际宽度, 那么结果中将在左边填充空格; 即每个数字是右对齐的. 要让数字左对齐, 请在 总宽度 前加上负号. 要使用零而不是空格填充，请在总宽度前加上零（例如 06.2）。

快速模式与慢速模式的比较

在 v1.0.48+, 可以使用 IntegerFast 代替 Integer, 和使用 FloatFast 代替 Float.
  • 优点: 快速模式能维持变量缓存整数和浮点数的能力, 这样可以极大地加快数值密集型运算. (相反地, 慢速模式强制将所有的数值结果立即转换并保存为字符串.)
  • 缺点: 保存数字到变量时, 快速模式延迟 SetFormat 的效果到脚本实际需要此变量的文本/字符串版本时 (例如要在 MsgBox 显示变量的内容). 由于不同的 SetFormat 可能同时生效 (例如更多或更少的小数位), 这可能导致不可预期的结果. 要让当前的快速模式立即生效，请执行像 HexValue .= "" 这样的操作，这个操作中把空字符串附加到当前保存在 HexValue 的数字上。

如果在脚本的任意位置使用了慢速模式 "Integer" 或 "Float", 即使 SetFormat 命令所在的这行从未执行, 在脚本开始运行时都会禁用整数或浮点数的缓冲.

浮点格式

在 v1.0.48+，浮点变量的内部精确度大约为 15 位，除非在脚本的某个位置使用了 SetFormat Float（即慢速模式）。此时, 浮点数保存的精度由 小数位数 决定 (就像 1.0.48 之前的版本那样). 换句话说，一旦浮点运算的结果保存到变量中，多余的精度会丢失并且无法通过再进行像 SetFormat, Float, 0.15 这样的计算进行还原。为了防止精度丢失，请避免在脚本中使用 SetFormat Float，或者使用 SetFormat FloatFast 代替。

不论当前有效的是快速模式还是慢速模式, 每当浮点结果和变量需要显示或转换到字符串文本 (例如 MsgBox 或 FileAppend) 时, 它们都会被四舍五入到 小数位数. 要查看完整的精度，请使用类似 SetFormat, FloatFast, 0.15 这样的命令。

要把浮点数转换成整数，请使用 Var:=Round(Var)、Var:=Floor(Var) 或 Var:=Ceil(Var)。要把整数转换成浮点数，给它加上 0.0（例如 Var+=0.0）或使用像 MyFloat:=Round(MyInteger, 1) 这样的命令。

内置变量 A_FormatFloat 包含了当前的浮点格式（例如 0.6）。

整数格式

整数的运算结果一般显示为十进制, 而不是十六进制. 要切换为十六进制，请使用 SetFormat, IntegerFast, Hex。这种方法还可以用来把整数从十进制转换为十六进制（反之亦然），如同此页面底部示例演示的那样。

在脚本中指定为原义的整数可以写为十六进制或十进制. 十六进制整数必须以前缀 0x 开头（例如 0xA9）。它们可以用在任何需要数字的地方. 例如，Sleep 0xFF 相当于 Sleep 255，不论当前 SetFormat 中整数格式的设置如何。

AutoHotkey 支持 64 位有符号整数, 其范围从 -9223372036854775808 (-0x8000000000000000) 到 9223372036854775807 (0x7FFFFFFFFFFFFFFF).

内置变量 A_FormatInteger 包含了当前的整数格式 (H 或 D).

一般说明

如果脚本中没有使用 SetFormat，则整数默认为十进制格式，而浮点数默认为总宽度.小数位数 = 0.6。每个新运行的线程（例如热键、自定义菜单项或定时子程序）都会以这些默认设置开始；但可以在脚本的自动执行段（脚本的顶部）使用 SetFormat 来改变这些默认值。

旧式风格的赋值（如 x=%y%）会忽略任何前导或尾随的空格（即填充的）。要避免这种情况，请使用 AutoTrim 或冒号等号运算符（例如 x:=y）。

使用 "if var is number/integer/float" 可以判断一个变量的内容是否为数值.

要对整数填充零或空格时可以不需要进行浮点运算, 请参照此例:

Var := "          " . Var     ; 引号内包含 10 个空格.  要用零填充, 请把其中的空格替换为零.
StringRight, Var, Var, 10  ; 这里用足够的空格填充 Var 中数字使其总宽度为 10 个字符.
Var := SubStr("          " . Var, -9)  ; 这里一行实现上面两行的操作.

相关

表达式赋值 (:=), EnvAdd, EnvSub, EnvMult, EnvDiv, AutoTrim, if var is type

示例

Var = 11.333333
SetFormat, float, 6.2
Var -= 1  ; 因为总宽度为 6, 所以赋值 Var 为带一个前导空格的 10.33.
SetFormat, float, 0.2
Var += 1  ; 赋值 Var 为不带前导空格的 11.33.
SetFormat, float, 06.0
Var += 0  ; 赋值 Var 为 000011

; 把十进制整数转换为十六进制:
SetFormat, IntegerFast, hex
Var += 0  ; 赋值 Var (原来的内容为 11) 为 0xb.
Var .= ""  ; 这行是必须的, 因为在快速模式.
SetFormat, IntegerFast, d


Transform

执行各种数学计算、按位运算以及类似 ASCII/Unicode 转换的任务。

Transform, OutputVar, Cmd, Value1 [, Value2]

参数

OutputVar

用来保存 Cmd 结果的变量名. SetFormat 决定了整数结果是保存为十六进制还是十进制.

Cmd, Value1/2

请参阅后面的列表.

Cmd, Value1, Value2

Cmd, Value1 和 Value2 参数相互依赖, 它们的用法描述如下.

Unicode [, String]：（此子命令在 AutoHotkey 的 Unicode 版本中不可用）获取或保存剪贴板上的 Unicode 文本。注：使用ClipboardAll的方法可以保存和恢复整个剪贴板的内容，这样可以在不丢失剪贴板原始内容情况下用“Transform Unicode”操作剪贴板。

此子命令的两种操作模式举例如下:

Transform, OutputVar, Unicode  ; 获取剪贴板中的 Unicode 文本为 UTF-8 字符串.
Transform, Clipboard, Unicode, %MyUTF_String%  ; 把 Unicode 文本放到剪贴板中.

在上面的第二个例子中, 可以使用原义的 UTF-8 字符串代替 %MyUTF_String%.

使用热键 (例如下面这个) 来得到与指定的 Unicode 字符串相应的 UTF-8 字符串:

^!u::  ; Control+Alt+U 热键.
MsgBox Copy some Unicode text onto the clipboard, then return to this window and press OK to continue.
Transform, ClipUTF, Unicode
Clipboard = Transform, Clipboard, Unicode, %ClipUTF%`r`n
MsgBox The clipboard now contains the following line that you can paste into your script. When executed, this line will cause the original Unicode string you copied to be placed onto the clipboard:`n`n%Clipboard%
return

注：Send {U+nnnn} 命令是生成 Unicode 字符的一种备用方法。

Asc, String：获取 String 中首个字符的 ASCII 码（一个介于 1 和 255 之间的数字）。如果 String 为空, 则 OutputVar 也会被置空. 例如：Transform, OutputVar, Asc, %VarContainingString%。对应的函数: Asc(String).

Chr, Value1: 获取 ASCII 码为 Value1 的单个字符. 如果 Value1 不是 1 和 255 及其之间的数字, 那么 OutputVar 会被置空来表明此问题. 例如：Transform, OutputVar, Chr, 130。对应的函数: Chr(Number).

Deref, String: 展开变量引用和包含在其他变量中的 转义序列. 任何糟糕格式的变量引用在展开时会被忽略. 把 OutputVar 展开为它的内容时也是如此; 换句话说, 在 String 变量中任何对 OutputVar 的引用在展开时会被忽略 (但请注意 String 自身可以 是 %OutputVar%). 在下面的例子中，如果 var1 包含字符串“test”而 var2 包含原义的字符串“%var1%”，则 OutputVar 会被赋值为字符串“test”：Transform, OutputVar, deref, %var2%。在 函数 内, String 中的每个变量总是被解析为局部变量, 只有在局部变量不存在时才解析为全局变量 (如果没有则为空).

HTML, String [, Flags]:

对于 ANSI 可执行脚本：通过把 ASCII 值大于 127 的字符译成它们的 HTML 名称来把 String 转换为与它对应的 HTML 字符串（例如把 £ 译成 &pound;）。此外, 这四个字符 "&<> 依次被译成 &quot;&amp;&lt;&gt;. 最后, 每个换行符 (`n) 被译成 <br>`n (即 <br> 后面跟着一个换行符). 忽略 Flags 参数。

在 Unicode 可执行脚本：除了上述的功能外，Flags 可以为零或下列值的组合（和）。如果省略, 则它默认为 1.

  • 1: 把某些字符转换成命名表示法. 例如 € 被转换成 &euro;
  • 2: 把某些字符转换成编号表示法. 例如 € 被转换成 &#8364;

仅影响非 ASCII 字符. 如果 Flags = 3, 仅在命名表示法不可用的情况下才使用编号表示法. 后面的这些字符总是需要转换: <>"& 和 `n (换行符).

FromCodePage / ToCodePage: 不赞成使用. 请使用 StrPut() / StrGet() 代替.

Mod, Dividend, Divisor: 获取被除数 Dividend 除以除数 Divisor 后得到的余数. 如果 Divisor 为零, 则 OutputVar 被置空. Dividend 和 Divisor 都可以为小数. 如果 Divisor 为负数, 那么在计算中会被视为正数处理. 后面的例子结果为 2：Transform, OutputVar, mod, 5, 3。对应的函数：Mod(Dividend, Divisor)。

Pow, Base, Exponent: 获取底数 Base 的指数 Exponent 次幂. Base 和 Exponent 都可以为小数. 如果 Exponent 为负数, 那么即使 Base 和 Exponent 都是整数, OutputVar 也会被格式化为浮点数. 不支持 Base 为负数且 Exponent 为分数例如 1.5 的情况; 它会使得 OutputVar 被置空. 另请参阅: ** 运算符.

Exp, N: 获取 e (它的近似值为 2.71828182845905) 的 N 次幂. N 可以为负数也可以为小数. 对应的函数: Exp(N).

Sqrt, Value1: 获取 Value1 的平方根. 如果 Value1 为负数, 则 OutputVar 会被置空. 对应的函数: Sqrt(Number).

Log, Value1: 获取 Value1 的对数 (底数为 10). 如果 Value1 为负数, 则 OutputVar 会被置空. 对应的函数: Log(Number).

Ln, Value1: 获取 Value1 的自然对数 (底数为 e). 如果 Value1 为负数, 则 OutputVar 会被置空. 对应的函数: Ln(Number).

Round, Value1 [, N]: 如果 N 省略, 则 OutputVar 会被设置为 Value1 四舍五入后的整数. 如果 N 为正数, 则 Value1 会被取整到 N 个小数位. 如果 N 为负数，则 Value1 会被取整到小数点左边 N 位。例如, -1 表示取整到个位, -2 表示取整到十位, 而 -3 表示取整到百位. 注: 取整小数位时不会移除末尾的零. 例如, 12.333 被取整到十分位后会变成 12.300000. 在操作前使用类似 SetFormat, float, 0.1 的命令可以改变此行为（事实上，第一步使用 SetFormat 后就不需要再使用 Round 了）。对应的函数: Round(Number [, N]).

Ceil, Value1: 获取 Value1 向上取整到最近的整数. 对应的函数: Ceil(Number).

Floor, Value1: 获取 Value1 向下取整到最近的整数. 对应的函数: Floor(Number).

Abs, Value1：获取Value1的绝对值，这是通过移除Value1前面的负号（破折号）（如果有）来计算的。对应的函数: Abs(Number).

Sin, Value1: 获取 Value1 的正弦三角函数值. Value1 必须用弧度表示. 对应的函数: Sin(Number).

Cos, Value1: 获取 Value1 的余弦三角函数值. Value1 必须用弧度表示. 对应的函数: Cos(Number).

Tan, Value1: 获取 Value1 的正切三角函数值. Value1 必须用弧度表示. 对应的函数: Tan(Number).

ASin, Value1: 获取弧度表示的反正弦值 (此数字的正弦值为 Value1). 如果 Value1 小于 -1 或大于 1, 则 OutputVar 会被置空. 对应的函数: ASin(Number).

ACos, Value1: 获取弧度表示的反余弦值 (此数字的余弦值为 Value1). 如果 Value1 小于 -1 或大于 1, 则 OutputVar 会被置空. 对应的函数: ACos(Number).

ATan, Value1: 获取弧度表示的反正切值 (此数字的正切值为 Value1). 对应的函数: ATan(Number).

请注意: 下面的每个按位操作都有相应的用于表达式中的更简洁的 按位运算符.

BitNot, Value1: 把 Value1 按位取反后保存到 OutputVar (如果 Value1 是浮点数, 则在计算前把它截取成整数). 如果 Value1 介于 0 和 4294967295 (0xffffffff) 之间, 那么它会被视为 无符号的 32 位值. 否则, 它被视为 有符号的 64 位值. 后面的例子结果为 0xfffff0f0（4294963440）：Transform, OutputVar, BitNot, 0xf0f。

BitAnd, Value1, Value2: 获取 Value1 和 Value2 按位与运算的结果 (在计算前首先把浮点数截取成整数). 后面的例子结果为 0xff00（65280）：Transform, OutputVar, BitAnd, 0xff0f, 0xfff0。

BitOr, Value1, Value2: 获取 Value1 和 Value2 按位或运算的结果 (在计算前首先把浮点数截取成整数). 后面的例子结果为 0xf0f0（61680）：Transform, OutputVar, BitOr, 0xf000, 0x00f0。

BitXOr, Value1, Value2: 获取 Value1 和 Value2 按位异或运算的结果 (在计算前首先把浮点数截取成整数). 后面的例子结果为 0xff00（65280）：Transform, OutputVar, BitXOr, 0xf00f, 0x0f0f。

BitShiftLeft, Value1, Value2: 获取 Value1 往左移动 Value2 个位的结果, 这相当于 Value1 乘以 "2 的 Value2 次幂" (在计算前首先把浮点数截取成整数). 后面的例子结果为 8：Transform, OutputVar, BitShiftLeft, 1, 3。

BitShiftRight, Value1, Value2: 获取 Value1 往右移动 Value2 个位的结果, 这相当于 Value1 除以 "2 的 Value2 次幂", 舍去余数 (在计算前首先把浮点数截取成整数). 后面的例子结果为 2：Transform, OutputVar, BitShiftRight, 17, 3。

备注

接受数值参数的子命令在它们的这些参数中也可以使用 表达式.

如果 Value1 或 Value2 其中一个为浮点数，则后面的 Cmd 的结果为浮点数而不是整数：Mod, Pow, Round 和 Abs。获取结果的小数位数由 SetFormat 决定.

要将弧度转换成角度, 请将它乘以 180/pi (约为 57.29578). 要将角度转换成弧度, 请将其乘以 pi/180 (约为 0.01745329252).

pi 的值 (约为 3.141592653589793) 为 1 的反正切值的 4 倍.

相关

SetFormat, 表达式, EnvMult, EnvDiv, StringLower, if var is type

示例

Transform, OutputVar, Asc, A  ; 获取字母 A 的 ASCII 码.


ImageSearch

在屏幕的某个区域中搜索图像。

ImageSearch, OutputVarX, OutputVarY, X1, Y1, X2, Y2, ImageFile

参数

OutputVarX/Y

用来保存在屏幕上找到的图像的左上角像素的 X 和 Y 坐标的变量名 (如果没有找到匹配, 则这两个变量被置空). 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置.

其中一个或两个参数都可以留空, 此时可以使用 ErrorLevel (请参阅下面) 来判断是否找到了匹配.

X1,Y1

要搜索的矩形区域的左上角的 X 和 Y 坐标, 可以为 表达式. 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置.

X2,Y2

要搜索的矩形区域的右下角的 X 和 Y 坐标, 可以为 表达式. 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置.

ImageFile

图像文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中. 在所有的操作系统中都支持 GIF, JPG, BMP, ICO, CUR 和 ANI 图像 (BMP 图像必须为 16 位或更高). 图标的其他来源包含下列类型的文件: EXE, DLL, CPL, SCR 以及包含图标资源的其他类型. 在 Windows XP 或更高版本中, 还支持其他图像格式, 例如PNG, TIF, Exif, WMF 和 EMF. 比 XP 早的操作系统可以通过复制微软免费的 GDI+ DLL 到 AutoHotkey.exe 文件夹中来提供支持 (但如果是 已编译脚本, 则复制此 DLL 到脚本的文件夹). 要下载这个 DLL, 请在 www.microsoft.com 搜索下列短语: gdi redistributable

选项: 在文件名前面可以直接添加零个或多个下列字符串. 在选项间使用单个空格或 tab 分隔. 例如：*2 *w100 *h-1 C:\Main Logo.bmp。

*IconN：要使用文件中的图标组而不是首个图标，请指定 *Icon 后紧跟着图标组编号。例如，*Icon2 将加载第二个图标组中的默认图标。

*n (渐变值): 指定 n 为介于 0 和 255 (包含的) 之间的数字, 用于表示每个像素颜色红/绿/蓝通道强度在每个方向上允许的渐变值. 例如，*2 将允许二的渐变值。此参数可用于图像的颜色轻微变化或 ImageFile 使用的格式（例如 GIF 或 JPG）不能准确表示屏幕上的图像的时候。如果指定 255 为浮动的渐变值, 则匹配所有颜色. 默认渐变值为 0.

*TransN: 此选项通过指定图像内的某种颜色能匹配屏幕上的任何颜色, 使得更容易找到匹配. 它常用于寻找含有透明区域的 PNG, GIF 和 TIF 文件 (然而, 对于图标则不需要此选项, 因为它们的透明度是自动支持的). 对于 GIF 文件，*TransWhite 很可能会有用。对于 PNG 和 TIF 文件，*TransBlack 可能是最佳的。否则，指定 N 为其他颜色名称或 RGB 值（请参阅颜色图表进行了解或使用 PixelGetColor 的 RGB 模式）。例如：*TransBlack，*TransFFFFAA，*Trans0xFFFFAA。

*wn 和 *hn：用于缩放图像尺寸的目标宽度和高度（此宽度和高度也决定了从多图标的 .ICO 文件中加载哪个图标）。如果同时省略这两个选项，则把从 ICO、DLL 或 EXE 文件中加载的图标调整到系统默认的小图标大小，通常为 16 X16（通过指定 *w0 *h0 您可以强制使用实际/内部的大小）。图标外的其他图像以它们的实际大小加载. 要保持高宽比来缩放图像, 请在其中一个尺寸中指定 -1 而在另一个中指定正数. 例如，指定 *w200 *h-1 将缩放图像到 200 像素的宽度同时自动设置其高度。

ErrorLevel

[v1.1.04+] 此命令在搜索遇到问题时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果在指定的区域找到指定的图像, 则 ErrorLevel 被设置为 0, 没有找到则为 1, 而如果在命令执行过程中遇到问题使搜索无法进行 (例如打开图像文件失败或糟糕的格式选项) 则为 2.

备注

ImageSearch 可用于在屏幕上查找缺少文本或其文本不易获取的图形目标. 例如, 它可用于查找图片按钮, 图标, 网页链接或游戏目标的位置. 找到后, 可以使用 Click 点击这样的目标.

在有些时候有用的一个策略是搜索图像中的一小块剪辑而不是整个图像. 此方法可以在图像整体发生变化而其内部某些部分保持不变时提高可靠性. 提取剪辑的一种方法是:

  1. 在活动窗口中图像可见时按下 Alt+PrintScreen. 这样把屏幕截图放在了剪贴板中.
  2. 打开图像处理程序, 例如 Paint.
  3. 粘贴剪贴板的内容 (即屏幕截图).
  4. 选择对图像而言唯一且不变的区域.
  5. 复制并粘贴那个区域到新的图像文档.
  6. 保存为小文件供 ImageSearch 使用.

要实现匹配, 屏幕上的图像必须与通过 ImageFile 参数及其选项加载的图像具有相同的尺寸.

要搜索的目标区域必须是可见的; 换句话说, 无法搜索隐藏在其他窗口背后的窗口区域. 与之相比, 部分在鼠标光标下方的图像通常可以检测出来. 例外情况是游戏的指针, 在大多数情况下它会遮住在它下方的任何图像.

由于搜索从目标区域的顶行开始往下, 所以如果有多个匹配, 则会找到最接近顶部的那个.

包含透明色的图标会自动允许那个颜色匹配屏幕上的任何颜色. 因此, 在图标后的颜色是不重要的.

ImageSearch 可支持 8 位色 (256 色) 或更高的屏幕.

搜索行为可能会因显示适配器的颜色深度而变化 (尤其对于 GIF 和 JPG 文件). 因此, 如果脚本会在多种颜色深度下运行, 最好在每种深度设置下进行测试. 您可以使用渐变选项 (*n) 来辅助协调在多种颜色深度下的搜索行为.

如果屏幕上的图像是半透明的, 则 ImageSearch 很可能无法找到它. 要避免此问题，请尝试渐变选项（*n）或使用 WinSet, Transparent, Off 临时地关闭窗口的透明。

相关

PixelSearch, PixelGetColor, CoordMode, MouseGetPos

示例

ImageSearch, FoundX, FoundY, 40,40, 300, 300, C:\My Images\test.bmp

CoordMode Pixel  ; 将下面的坐标解释为相对于屏幕而不是活动窗口.
ImageSearch, FoundX, FoundY, 0, 0, A_ScreenWidth, A_ScreenHeight, *Icon3 %A_ProgramFiles%\SomeApp\SomeApp.exe
if ErrorLevel = 2
    MsgBox Could not conduct the search.
else if ErrorLevel = 1
    MsgBox Icon could not be found on the screen.
else
    MsgBox The icon was found at %FoundX%x%FoundY%.


PixelGetColor

获取指定的 x, y 坐标处像素的颜色。

PixelGetColor, OutputVar, X, Y [, Alt|Slow|RGB]

参数

OutputVar

用来保存十六进制的蓝绿红 (BGR) 格式的颜色 ID 的变量名. 例如, 紫色的颜色 ID 为 0x800080, 因为其蓝色和红色成分的强度为 80, 而绿色成分的为 00.

X, Y

目标像素的 X 和 Y 坐标, 可以为 表达式. 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置.

Alt|Slow|RGB

此参数可以包含零个或多个下列单词. 如果含有多个单词，则它们之间使用空格分隔（例如 Alt RGB）。

Alt [v1.0.43.10+]: 使用另一种方法获取颜色, 当在特殊类型的窗口中正常的方法获取到无效或错误的颜色时, 应考虑使用这种方法. 此方法比正常方法大约慢 10%.

Slow [v1.0.43.10+]: 使用一种更精细复杂的方法获取颜色, 在某些全屏应用程序中其他方法失败时, 此方法可能有效. 此方法比正常方法大约慢三倍. 注: Slow 方法优先于 Alt, 所以此时不需要指定 Alt.

RGB: 获取 RGB 格式的颜色值而不是 BGR 格式. 即交换了其中的红色和蓝色的成分. 此选项可用在要让获取的颜色适用于 WinSet、Gui、Progress 和 SplashImage 的时候。

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

像素必须是可见的; 换句话说, 无法获取隐藏在其他窗口背后的窗口的像素颜色. 与之相比, 鼠标光标下方的像素颜色通常可以检测出来. 例外情况是游戏的指针, 在大多数情况下它会隐藏在它下方的任何像素.

使用 Window Spy (从托盘图标菜单打开) 或参阅本页底部的示例可以确定当前屏幕上的颜色.

已知限制:

  • 在 部分透明 或其中某种颜色透明 (TransColor) 的窗口中实际获取的是它后面窗口的颜色而不是它自己的颜色 (即我们在屏幕上看到的颜色).
  • 在某些应用程序中 PixelGetColor 可能得不到准确的结果. 如果发生这种情况, 请尝试在最后一个参数中指定单词 Alt 或 Slow.

相关

PixelSearch, ImageSearch, CoordMode, MouseGetPos

示例

^!z::  ; Control+Alt+Z 热键.
MouseGetPos, MouseX, MouseY
PixelGetColor, color, %MouseX%, %MouseY%
MsgBox The color at the current cursor position is %color%.
return


PixelSearch

在屏幕某个区域中搜索指定颜色所在的像素。

PixelSearch, OutputVarX, OutputVarY, X1, Y1, X2, Y2, ColorID [, Variation, Fast|RGB]

参数

OutputVarX/Y

用来保存首个匹配 ColorID 像素的 X 和 Y 坐标 (如果没有发现匹配, 则此变量被置空). 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置.

其中一个或两个参数都可以留空, 此时可以使用 ErrorLevel (请参阅下面) 来判断是否找到了匹配.

X1, Y1

要搜索的矩形区域的左上角的 X 和 Y 坐标, 可以为 表达式. 坐标相对于活动窗口，除非曾使用 CoordMode 改变了这个设置。

X2, Y2

要搜索的矩形区域的右下角的 X 和 Y 坐标, 可以为 表达式. 坐标相对于活动窗口, 除非曾使用 CoordMode 改变了这个设置.

ColorID

要搜索的十进制或十六进制的颜色 ID, 使用蓝绿红 (BGR) 格式, 可以为 表达式. 颜色 ID 可以使用 Window Spy (可从托盘菜单打开) 或 PixelGetColor 来确定. 例如：0x9d6346。

Variation

一个介于 0 和 255 (包含的) 之间的数字, 用于表示此颜色红/绿/蓝成分强度在每个方向上允许的渐变值 (可以为 表达式). 此参数用于需要寻找的颜色渐变值可能变化时. 如果指定 255 为浮动的渐变值, 则匹配所有颜色. 默认渐变值为 0.

Fast|RGB

此参数可以包含单词 Fast, RGB 或同时包含两者 (同时包含两者时它们之间请用空格分隔; 即 Fast RGB).

Fast: 使用快速的搜索方法, 在大多数情况下此方法可以明显减少搜索时消耗的 CPU 时间. 尽管此方法支持颜色深度低至 8 位 (256 色), 不过在 24 位或 32 位颜色深度下此快速模式执行地更好. 如果屏幕的颜色深度为 16 位或更低, 则 Variation 参数在慢速模式和快速模式的行为可能有轻微的差异. 最后, 快速模式按行搜索屏幕 (从上往下) 而不是按列. 因此, 如果屏幕上有多个匹配的像素, 则快速模式可能找到一个和慢速模式不同的像素.

RGB: 把 ColorID 解释为 RGB 值而不是 BGR. 即交换了其中的红色和蓝色的成分.

ErrorLevel

[v1.1.04+] 此命令在搜索遇到问题时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果在指定的区域找到指定的颜色, 则 ErrorLevel 被设置为 0, 没有找到则为 1, 而如果在命令执行过程中遇到问题使搜索无法进行则为 2.

备注

要搜索的目标区域必须是可见的; 换句话说, 无法搜索隐藏在其他窗口背后的窗口区域. 与之相比, 鼠标光标下方的像素颜色通常可以检测出来. 例外情况是游戏的指针, 在大多数情况下它会隐藏在它下方的任何像素.

对于慢速模式: 默认情况下从区域左上角的像素开始搜索, 在垂直方向上检查下面所有像素以寻找匹配. 如果没有找到匹配, 则继续往右逐列搜索, 直到找到一个匹配的像素. 通过交换参数列中 X1 和 X2 的位置, 可以使默认的从左往右搜索反向进行. 换句话说, 如果 X1 大于 X2, 搜索会从右往左进行, 从 X1 开始. 同样地, 如果 Y1 大于 Y2, 则从区域底部而不是顶部开始搜索每列像素. 最后, 当需要搜索的目标区域很大而且快速的重复搜索, 这可能会占用大量的 CPU 时间. 为了减轻这种情况, 请保持目标区域的大小为最小值.

相关

PixelGetColor, ImageSearch, CoordMode, MouseGetPos

示例

PixelSearch, Px, Py, 200, 200, 300, 300, 0x9d6346, 3, Fast
if ErrorLevel
    MsgBox, That color was not found in the specified region.
else
    MsgBox, A color within 3 shades of variation was found at X%Px% Y%Py%.


#NoTrayIcon

不显示托盘图标。

#NoTrayIcon

在脚本的任意位置使用此指令可以避免脚本在运行时显示托盘图标 (也适用于编译成 EXE 的脚本).

如果您在含热键的脚本中使用此指令, 那么可能需要为 ExitApp 命令指定热键. 否则, 将没有简单的办法退出程序 (在不重启计算机或强制关闭进程的情况下). 例如：#x::ExitApp。

使用 Menu, Tray, Icon 或 Menu, Tray, NoIcon 可以在脚本执行期间隐藏或恢复它的托盘图标。在脚本顶部使用 Menu, Tray, NoIcon 的唯一缺点是在脚本启动时它的托盘图标可能会出现短暂的时间。要避免此问题, 请使用 #NoTrayIcon 代替.

当托盘图标隐藏时, 内置变量 A_IconHidden 的值为 1, 否则为 0.

相关

Menu, ExitApp

示例

#NoTrayIcon


#SingleInstance

决定当脚本已经运行时是否允许它再次运行。

#SingleInstance [force|ignore|off]

参数

force|ignore|off

此参数决定当脚本前一个实例正在运行时, 启动该脚本时会执行的动作:

单词 FORCE 会跳过对话框并自动替换旧实例, 效果类似于 Reload 命令.

单词 IGNORE 会跳过对话框并让旧实例继续运行. 换句话说, 试图启动已经运行的脚本会被忽略.

单词 OFF 允许一个脚本同时运行多个实例.

如果省略此参数, 那么会显示对话框, 其中会询问是否让旧实例继续运行还是替换为新实例.

备注

包含 热键, 热字串, #Persistent, OnMessage() 或 Gui 默认是单实例的 (重复运行时会显示对话框与提示). 而其他脚本默认允许多个实例. 使用前面描述的方法可以禁用或修改这种行为.

相关

Reload, #Persistent

示例

#SingleInstance force
#SingleInstance ignore
#SingleInstance off


#Warn

#Warn [v1.0.95.00+]

启用或禁用可能产生错误的特定状况时的警告，例如书写错误或缺少全局声明。

#Warn [, WarningType, WarningMode]

参数

WarningType

要启用或禁用的警告类型。如果省略, 默认为 All.

UseUnsetLocal 或 UseUnsetGlobal：在读取之前没有赋值或使用 VarSetCapacity 初始化的变量时产生警告。如果这种变量计划为空的，则可以为它赋值空字符串来屏蔽这样的警告。

根据用于局部和全局变量这种警告被分成两种单独的类型，这是由于全局变量的持久、脚本范围作用域的性质，所以对不首先初始化而使用全局变量更常用。因此，一些脚本作者会希望在局部启用这种警告类型，但禁用全局的。

#Warn
;y := ""  ; 这样将屏蔽警告。
x := y    ; y 还不含有值。

UseEnv：在自动使用环境变量代替空的脚本变量时产生警告。当环境变量名意外地与脚本中使用的某个变量名相同时会发生这种情况。这种警告会在访问变量时会产生，但如果脚本使用了 #NoEnv（由于多种原因而推荐使用）则可以避免。

#Warn
;#NoEnv             ; 如果“temp”不是计划为环境变量则添加这行。
;EnvGet temp, TEMP  ; 这里将复制环境变量的值到脚本变量中。
temp := ""          ; 不考虑这行，temp 仍然含有值。
MsgBox % temp       ; 这里访问名称为“TEMP”的环境变量。

LocalSameAsGlobal：在脚本开始运行前，为与全局变量名称相同的每个未声明局部变量显示警告。这是用来避免在函数中由于忘记在访问全局变量前进行声明引起的错误。如果变量确实为局部变量，则可以用类似 local x 或 static y 这样的声明来屏蔽这种警告。

#Warn
g := 1
ShowG() {       ; 即使从未调用这个函数也会显示警告。
    ;global g   ; <-- 访问全局变量时需要这行。
    MsgBox % g  ; 没有声明，所以“g”是个空的局部变量。
}

All: 应用指定的 WarningMode 支持的所有警告类型.

WarningMode

表示警告方式的值。如果省略, 默认为 MsgBox.

MsgBox：显示描述警告的消息框。注意当这种消息框解除后，脚本将照常继续。

StdOut [v1.1.04+]：把警告的描述以及相应的文件名和行号发送到 stdout（程序的标准输出流）。这样可以让类似 SciTE 的高级编辑器在不干扰脚本的同时捕获警告, 之后用户可以通过编辑器的控制面板跳转到各个出错行.

OutputDebug：把警告的描述发送到调试器显示出来。如果没有活动的调试器，则这个值没有效果。想了解更多细节, 请参阅 OutputDebug.

Off：禁用指定 WarningType 的警告。

备注

默认情况下, 所有的警告都是关闭的.

无法在运行时启用或禁用警告, 这个设置是在脚本加载时确定的. 因此, 它在脚本中的位置是不重要的 (并且与其他的 # 指令一样, #Warn 不能根据条件执行).

然而, 多个 #Warn 指令的顺序是有意义的: 最近一次设置指定警告的指令决定了这种警告的模式. 所以, 例如下面的两个语句会启用除 UseEnv 之外的所有警告的组合效果:

#Warn All
#Warn UseEnv, Off

EnvSet EnvVar, 1
x := EnvVar       ; 由于没有使用 #NoEnv, 所以这句是正确的.
x := NotAnEnvVar  ; 产生警告.

相关

局部变量和全局变量

示例

#Warn All, Off                    ; 禁用所有警告.  这是默认设置.
#Warn                             ; 启用每种警告并将它们显示到消息框中。
#Warn UseUnsetLocal, OutputDebug  ; 在赋值前使用局部变量时发送警告到 OutputDebug.


AutoTrim

设置在 Var1 = %Var2% 这样的语句中进行赋值时是否忽略 Var2 的前导和尾随空格和 tab。

AutoTrim, On|Off

参数

On|Off

On：在类似 Var1 = %Var2% 这样的语句中，把 Var2 赋值给 Var1 时忽略其中的前导和尾随 tab 和空格。这是默认的.

Off: 不忽略这样的 tab 和空格.

不论此设置如何, 总是会忽略任何字面上的 tab 和空格. 在 v1.1.06 之前的版本中, 这里包括了 `t 和任何转义的空格和 tab. 例如，当 AutoTrim 设置为 Off 时，语句 Var = `t 在 v1.1.06 中则赋值一个 tab 字符，而在早期版本中会赋值空字符串。

备注

如果没有在脚本中使用此命令, 那么此默认设置为 ON.

内置变量 A_AutoTrim 包含了此命令当前的设置 (On 或 Off).

内置变量 A_Space 和 A_Tab 分别包含单个空格和单个 tab 字符.

AutoTrim 对诸如 Var := " string " 这样的 表达式赋值没有影响。换句话说, 在这种情况下总是会保留前导和尾随空格和 tab.

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

SetEnv

示例

AutoTrim, off
NewVar1 = %OldVar%  ; 如果 OldVar 包含前导和尾随空格, 那么 NewVar 也会包含它们.
NewVar2 = %A_Space%  ; 使用 AutoTrim off 的设置时, 可以用这种方式赋值单个空格.

Var1 := "`t" . Var2 . " "  ; AutoTrim 的设置对此语句没有影响, 因为它是 表达式.


Edit

在关联编辑器中打开当前脚本进行编辑。

Edit

Edit 命令使用注册表中与 "edit" 操作关联的编辑器 (如果没有则为记事本) 打开当前脚本进行编辑. 然而, 如果已经有一个编辑器窗口中打开了这个脚本 (根据窗口标题判断), 那么会激活这个窗口而不打开编辑器的新实例.

在已编译脚本中执行此命令将没有效果.

相关提示，可以在多种编辑器中启用 AutoHotkey 语法高亮——请参阅下面。此外, 通过 这个例子 可以在任何编辑器中激活 AutoHotkey 命令的上下文相关帮助. 最后, 通过使用像 ISense 这样几乎可以在任何编辑器上工作的自动完成工具可以提升您的效率. 它监视您的输入并显示菜单和参数列表, 帮助您输入某些内容以及提醒您参数的顺序.

相关

Reload

示例

Edit ; 打开当前脚本进行编辑。
; 如果您编辑器的命令行用法像下面这样,
; 那么可以使用此脚本把它设置为 ahk 文件的默认编辑器:
;
;   Editor.exe "Full path of script.ahk"
;
; 当您运行这个脚本时, 它会提示您
; 选择您编辑器的可执行文件.
;
FileSelectFile Editor, 2,, Select your editor, Programs (*.exe)
if ErrorLevel
    ExitApp
RegWrite REG_SZ, HKCR, AutoHotkeyScript\Shell\Edit\Command,, "%Editor%" "`%1"

带有 AutoHotkey 支持的编辑器

SciTE4AutoHotkey 是 SciTE 文本编辑器的自定义版本, 为 AutoHotkey 脚本量身订制的. 其特性包括:

  • 语法高亮
  • 智能自动缩进
  • 自动完成
  • 调用提示 (也称为智能感应)
  • 代码折叠
  • 支持 交互式调试
  • 辅助编写 AutoHotkey 脚本的其他工具

SciTE4AutoHotkey可从此处下载：http://fincs.ahk4.net/scite4ahk/

支持 AutoHotkey 语法高亮的 其他编辑器:

  • AkelPad - http://www.autohotkey.com/forum/topic23586.html
  • Crimson Editor - http://www.autohotkey.com/forum/topic5506.html
  • Eclipse, FAR manager 和任何使用 Colorer take5 的编辑器 - http://www.autohotkey.com/forum/topic10378.html
  • Emacs - http://www.autohotkey.com/wiki/index.php?title=Emacs
  • Notepad++ - http://www.autohotkey.com/forum/topic58792.html
  • Notepad2 - http://www.autohotkey.com/forum/viewtopic.php?t=37652
  • PSPad - http://www.autohotkey.com/forum/topic9294.html
  • SciTE 或其他基于 Scintilla 的编辑器 - http://www.autohotkey.com/forum/topic9656.html
  • Sublime Text Editor - http://www.autohotkey.com/forum/viewtopic.php?p=368326#368326
  • Total Commander 的 Synplus 插件 - http://www.autohotkey.com/forum/topic7278.html

此外, AutoHotkey Basic (http://www.autohotkey.com/download/) 的 zip 下载包中含有在下列编辑器中激活语法高亮的文件. 然而, 其中一些文件严重过时, 所以可能有效也可能无效:

  • ConTEXT
  • EditPlus
  • EmEditor
  • jEdit
  • MED
  • TextPad
  • UltraEdit
  • Vim

如果您最喜爱的编辑器没有在这里列出来, 那么搜索 论坛 试试您的运气.

要添加编辑器到此页面，请通过论坛或GitHub联系Lexikos。


ListLines

显示最近执行的脚本行。

ListLines [, On|Off]

参数

On|Off

如果为空或省略, 则显示最近执行的脚本行的历史. 在 v1.0.48.01+, 添加了可选的首个参数, 可以为 On 或 Off. 它只影响 当前线程 的行为, 说明如下:

On：包括历史中后续执行的行。对于所有的脚本这是初始默认值.

Off：在历史中略去后续执行的行。

备注

ListLines (不带参数) 等同于在主窗口中选择了 "View->Lines most recently executed" 菜单项. 可用于调试脚本。

ListLines Off/On 可用来选择性的从历史中略去一些行，这样有助于避免历史被过快填满（例如在含许多快速重复的循环中）。ListLines Off 还可以提升一些脚本的性能。

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

尽管没有内置变量 "A_ListLines", 但在脚本中使用下列语句可以实现相同的功能:

ListLines(PassTrueToTurnOnOrFalseToTurnOff)  ; 返回 ListLines 之前的设置 (在此调用之前).
{
    static sListLines := true  ; 对于所有的脚本的初始默认设置为 "ListLines On".
    ListLines % PassTrueToTurnOnOrFalseToTurnOff ? "On" : "Off"  ; 无条件执行 ListLines 来略去日志还未执行的行.
    ListLines_prev := sListLines
    sListLines := PassTrueToTurnOnOrFalseToTurnOff
    return ListLines_prev
}

; 使用上面的函数:
prev_ListLines := ListLines(false)  ; 临时关闭 ListLines.
; ...
ListLines(prev_ListLines)  ; 恢复 ListLines 到原来的设置.

相关提示, 内置变量 A_LineNumber 和 A_LineFile 分别包含当前执行的行的编号和所属文件名.

相关

KeyHistory, ListHotkeys, ListVars

示例

ListLines
ListLines Off


ListVars

显示脚本的变量：它们的名称和当前的内容。

ListVars

备注

此命令等同于在主窗口中选择 "View->Variables" 菜单项. 可用于调试脚本。

列表中的每行由以下部分组成:
1) 变量名.
2) 变量内容的长度和变量 占用的空间. 例如: [50 of 63]
3) 变量内容的前 60 个字符.

如果在 函数 内使用此命令, 则首先列出此函数的 局部变量 (在脚本全局变量的上方).

已知限制: 如果 函数 (或全局变量自身的列表) 包含 10,000 个变量以上, 则此命令可能不会以准确的字母顺序显示它们; 即某些可能不显示出来.

相关

KeyHistory, ListHotkeys, ListLines

示例

ListVars


OutputDebug

发送字符串到调试器（如果有）显示出来。

OutputDebug, Text

参数

文本

要发送到调试器中显示出来的文本. 此文本可以包含换行符 (`n) 来开始新行. 此外, 一个长行可以使用 延续片段 的方法分成较短的几行.

备注

如果脚本的进程没有附加调试器, 那么系统调试器会显示此字符串. 如果系统调试器未激活, 则此命令没有效果.

调试器的一个例子是 DebugView, 它是免费的并可从 www.sysinternals.com 获取.

另请参阅: 其他调试方法

相关

FileAppend, 延续片段

示例

OutputDebug, %A_Now%: Because the window "%TargetWindowTitle%" did not exist, the process was aborted.


SysGet

获取屏幕分辨率、多显示器信息、系统对象的尺寸和其他系统属性。

SysGet, OutputVar, Sub-command [, Param3]

参数

OutputVar

用来存储结果的变量名.

Sub-command
请参阅后面的列表.
Param3

除了下面注明的, 否则省略此参数.

子命令

MonitorCount: 获取监视器的总数. 与下表提到的 SM_CMONITORS 不同，MonitorCount 包括所有的监视器，甚至是没有不是桌面一部分的那些。

MonitorPrimary: 获取主监视器的数目, 在单监示器系统上这个数目为 1.

Monitor [, N] ：获取编号为 N 的监视器的边界坐标（如果 N 省略，则使用主监视器）。获取的结果保存在四个名称以 OutputVar 开始的变量中. 如果 N 太大或获取信息时遇到问题, 那么这些变量都被置空. 例如：

SysGet, Mon2, Monitor, 2
MsgBox, Left: %Mon2Left% -- Top: %Mon2Top% -- Right: %Mon2Right% -- Bottom %Mon2Bottom%.

在 函数 中, 要创建一组全局变量而不是局部变量, 请在此命令前 声明 Mon2 为全局变量 (对于 假设全局 函数, 反之亦成).

MonitorWorkArea [, N]: 与上面相同, 不过这个区域不包括任务栏和其他注册的桌面工具栏占用的空间.

MonitorName [, N]: 监视器编号为 N 的操作系统名称 (如果省略 N, 则使用主监视器).

(数值): 指定 Sub-command 下表的其中一个数字来获取相应的值. 后面的丽日会保存鼠标按钮的数目到变量“MouseButtonCount”：SysGet, MouseButtonCount, 43。

常用的

数字 | 说明
80 | SM_CMONITORS: 桌面上监视器数目 (不包括 "不显示的伪监视器").
43 | SM_CMOUSEBUTTONS: 鼠标按钮的数目 (没有安装鼠标则为 0).
16, 17 | SM_CXFULLSCREEN, SM_CYFULLSCREEN: 在主监视器上全屏窗口工作区的宽度和高度, 单位为像素.
61, 62 | SM_CXMAXIMIZED, SM_CYMAXIMIZED: 主监视器上已最大化的顶层窗口的尺寸, 单位为像素.
59, 60 | SM_CXMAXTRACK, SM_CYMAXTRACK: 包含标题和可调整大小边框的窗口的默认最大尺寸, 单位为像素. 这个度量指向整个桌面. 用户无法拖动窗口边框超过这些尺寸指定的大小.
28, 29 | SM_CXMIN, SM_CYMIN: 窗口的最小宽度和高度, 单位为像素.
57, 58 | SM_CXMINIMIZED, SM_CYMINIMIZED: 已最小化的窗口的尺寸, 单位为像素.
34, 35 | SM_CXMINTRACK, SM_CYMINTRACK: 窗口的最小跟踪宽度和高度, 单位为像素. 用户无法拖动窗口边框小于这些尺寸指定的大小. 窗口可以通过处理 WM_GETMINMAXINFO 消息来覆盖这些值.
0, 1 | SM_CXSCREEN, SM_CYSCREEN: 主监视器屏幕的宽度和高度, 单位为像素. 这两个值等同于内置变量 A_ScreenWidth 和 A_ScreenHeight.
78, 79 | SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN: 虚拟屏幕的宽度和高度, 单位为像素. 虚拟屏幕是所有监视器的边框. SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN 度量是虚拟屏幕左上角的坐标.
19 | SM_MOUSEPRESENT: 如果安装了鼠标则为非零值, 否则为零.
75 | SM_MOUSEWHEELPRESENT: 如果安装了带滚轮的鼠标则为非零值, 否则为零.
63 | SM_NETWORK: 网络存在时设置最低的有效位, 否则进行清除. 其他的位保留供将来使用.
8193 | SM_REMOTECONTROL: 此系统度量用于终端服务环境. 如果当前的会话是由远程控制的则它的值不为零; 否则为零.
4096 | SM_REMOTESESSION: 此系统度量用于终端服务环境. 如果调用线程与终端服务的客户端会话关联, 则返回非零值. 如果调用线程与终端服务的控制台会话关联, 则返回零. 控制台会话不一定是实际的控制台.
70 | SM_SHOWSOUNDS: 如果用户要求一个原本只提供声音信息的场合中同时提供可视化信息时为非零值, 否则为零.
8192 | SM_SHUTTINGDOWN: 当前会话正在关闭时为非零值, 否则为零. Windows 2000： 获取的值总是 0。
23 | SM_SWAPBUTTON: 交换了鼠标左右键的功能时为非零值, 否则为零.
76, 77 | SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN: 虚拟屏幕左边和上面的坐标. 虚拟屏幕是所有监视器的边框. 与之相比, the SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN 度量 (较远的上面) 为虚拟屏幕的宽度和高度.

不常用的

数字 | 说明
56 | SM_ARRANGE: 指定系统排列最小化窗口方式的标志. 请参阅 MSDN 了解更多信息.
67 | SM_CLEANBOOT: 指定系统启动的方式. 0正常启动 1失败-安全启动 2失败-带网络的安全启动
5, 6 | SM_CXBORDER, SM_CYBORDER: 窗口边框的宽度和高度, 单位为像素. 对于 3D 外观的窗口, 这相当于它的 SM_CXEDGE 值.
13, 14 | SM_CXCURSOR, SM_CYCURSOR: 光标的宽度和高度, 单位为像素. 系统无法创建其他大小的光标.
36, 37 | SM_CXDOUBLECLK, SM_CYDOUBLECLK: 在双击序列中首次点击位置周围矩形的宽度和高度, 单位为像素. 第二次点击只有出现在这个矩形内才会被系统认为这两次点击为双击. (两次点击还必须发生在指定的时间内.)
68, 69 | SM_CXDRAG, SM_CYDRAG: 以拖动点为中心, 在拖动操作开始前允许鼠标指针在其中进行有限的移动的矩形的宽度和高度. 这些值的单位为像素. 这允许用户方便地点击和释放鼠标按钮而不会意外开始拖动操作.
45, 46 | SM_CXEDGE, SM_CYEDGE: 3D 边框的尺寸, 单位为像素. 它们是 SM_CXBORDER 和 SM_CYBORDER 的 3D 副本.
7, 8 | SM_CXFIXEDFRAME, SM_CYFIXEDFRAME (与 SM_CXDLGFRAME, SM_CYDLGFRAME 含义相同): 含标题栏而不可调整大小的窗口的边框厚度, 单位为像素. SM_CXFIXEDFRAME 为水平边界的高度, 而 SM_CYFIXEDFRAME 为垂直边界的宽度.
83, 84 | SM_CXFOCUSBORDER, SM_CYFOCUSBORDER: 控件的焦点矩形的左右边缘的宽度和上下边缘的高度, 单位为像素. Windows 2000： 获取的值总是 0。
21, 3 | SM_CXHSCROLL, SM_CYHSCROLL: 水平滚动条上箭头位图的宽度, 单位为像素; 垂直滚动条的高度, 单位为像素.
10 | SM_CXHTHUMB: 水平滚动条中滚动块的宽度, 单位为像素.
11, 12 | SM_CXICON, SM_CYICON: 图标的默认宽度和高度, 单位为像素.
38, 39 | SM_CXICONSPACING, SM_CYICONSPACING: 大图标视图中项目网格单元格的尺寸, 单位为像素. 排列时每个项目会对齐到这个大小的矩形中. 这两个值总是大于或等于 SM_CXICON 和 SM_CYICON.
71, 72 | SM_CXMENUCHECK, SM_CYMENUCHECK: 默认菜单复选标记位图的尺寸, 单位为像素.
54, 55 | SM_CXMENUSIZE, SM_CYMENUSIZE: 菜单栏按钮的尺寸, 例如多文档界面中使用的子窗口的关闭按钮, 单位为像素.
47, 48 | SM_CXMINSPACING SM_CYMINSPACING: 已最小化窗口的网格单元格的尺寸, 单位为像素. 排列时每个已最小化的窗口会对齐到这个大小的矩形中. 这两个值总是大于或等于 SM_CXMINIMIZED 和 SM_CYMINIMIZED.
30, 31 | SM_CXSIZE, SM_CYSIZE: 窗口标题文字或标题栏按钮的宽度和高度, 单位为像素.
32, 33 | SM_CXSIZEFRAME, SM_CYSIZEFRAME: 可调整大小窗口周围可调整边框的厚度, 单位为像素. SM_CXSIZEFRAME 为水平边框的宽度, 而 SM_CYSIZEFRAME 为垂直边框的高度. 与 SM_CXFRAME 和 SM_CYFRAME 含义相同.
49, 50 | SM_CXSMICON, SM_CYSMICON: 小图标的推荐尺寸, 单位为像素. 小图标一般出现在窗口标题和小图标视图中.
52, 53 | SM_CXSMSIZE SM_CYSMSIZE: 小标题按钮的尺寸, 单位为像素.
2, 20 | SM_CXVSCROLL, SM_CYVSCROLL: 垂直滚动条的宽度, 单位为像素; 垂直滚动条上箭头位图的高度, 单位为像素.
4 | SM_CYCAPTION: 标题区域的高度, 单位为像素.
18 | SM_CYKANJIWINDOW: 对于双字节字符集版本的系统, 这是在屏幕底部的 Kanji 窗口的高度, 单位为像素.
15 | SM_CYMENU: 单行菜单栏的高度, 单位为像素.
51 | SM_CYSMCAPTION: 小标题的高度, 单位为像素.
9 | SM_CYVTHUMB: 垂直滚动条滚动块的高度, 单位为像素.
42 | SM_DBCSENABLED: 当 User32.dll 支持 DBCS 时为非零值; 否则为零.
22 | SM_DEBUG: 如果安装了调试版本的 User.exe 则为非零值; 否则为零.
82 | SM_IMMENABLED: 如果启用了输入法管理器/输入法编辑器则为非零值; 否则为零. SM_IMMENABLED 表示系统是否准备在 Unicode 程序中使用基于 Unicode 的输入法. 要确保语言依赖的输入法可用, 请检查 SM_DBCSENABLED 和系统 ANSI 代码页. 否则 ANSI 到 Unicode 的转换可能无法正确执行, 或者不存在某些组件, 例如字体或注册表设置.
87 | SM_MEDIACENTER: 如果当前操作系统为 Windows XP Media Center Edition 时为非零值, 如果不是则为零.
40 | SM_MENUDROPALIGNMENT: 如果下拉菜单与相应的菜单项右对齐时为非零值; 而左对齐时为零.
74 | SM_MIDEASTENABLED: 如果系统启用了希伯来和阿拉伯语言则为非零值, 如果没有则为零.
41 | SM_PENWINDOWS: 如果安装了 Microsoft Windows for Pen computing 扩展则为非零值; 否则为零.
44 | SM_SECURE: 如果存在安全支持则为非零值; 否则为零.
81 | SM_SAMEDISPLAYFORMAT: 如果所有的监视器使用相同的颜色格式则为非零值, 否则为零. 请注意两个显示器中可以含有相同的位深度而不同的颜色格式. 例如, 红, 绿和蓝像素可以使用不同的位数进行编码, 或者这些位可能位于像素颜色值的不同地方.
86 | SM_TABLETPC: 如果当前操作系统为 Windows XP Tablet PC 版本时为非零值, 如果不是则为零.

备注

内置变量 A_ScreenWidth 和 A_ScreenHeight 包含了主监视器的尺寸, 单位为像素.

相关

DllCall, WinGet

示例

; 示例 #1:
SysGet, MouseButtonCount, 43
SysGet, VirtualScreenWidth, 78
SysGet, VirtualScreenHeight, 79

; 示例 #2: 这是个显示每个监视器信息的可运行脚本:
SysGet, MonitorCount, MonitorCount
SysGet, MonitorPrimary, MonitorPrimary
MsgBox, Monitor Count:`t%MonitorCount%`nPrimary Monitor:`t%MonitorPrimary%
Loop, %MonitorCount%
{
    SysGet, MonitorName, MonitorName, %A_Index%
    SysGet, Monitor, Monitor, %A_Index%
    SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index%
    MsgBox, Monitor:`t#%A_Index%`nName:`t%MonitorName%`nLeft:`t%MonitorLeft% (%MonitorWorkAreaLeft% work)`nTop:`t%MonitorTop% (%MonitorWorkAreaTop% work)`nRight:`t%MonitorRight% (%MonitorWorkAreaRight% work)`nBottom:`t%MonitorBottom% (%MonitorWorkAreaBottom% work)
}


UrlDownloadToFile

从互联网下载文件。

UrlDownloadToFile, URL, Filename

参数

URL

要下载的文件的 URL. 例如, http://someorg.org 也许会获取那个组织的欢迎页面.

Filename

下载到文件: 指定要在本地创建的文件名, 如果未指定绝对路径则假定在 %A_WorkingDir%. 任何现有的文件会被新文件 覆盖.

下载到变量：请参阅后面的示例。

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

甚至在远程文件不存在时, 下载也可能显示成功. 这是因为许多网络服务器会发送错误页面代替缺失的文件. 这个错误页面会代替 Filename 被保存起来.

必须安装 Internet Explorer 3 或更高版本, 此功能才有效. 防火墙或存在多个网络适配器可能导致此功能失败. 此外, 一些网站可能拦截这样的下载.

缓存:

  • 在 v1.0.44.07+, 直接从远程服务器中获取 URL 表示的文件 (即决不从 Internet Explorer 的缓存中获取). 要允许使用缓存，请在 URL 前加上 *0 和空格；例如：*0 http://someorg.org。在星号后面的零可以替换为任何有效的 dwFlags 数字; 要了解详情, 请在 www.microsoft.com 中搜索 InternetOpenUrl.
  • 在比 1.0.44.07 早的版本中, 每当可能时都会从缓存中获取文件. 要避免这种情况, 请在 URL 的末尾指定查询字符串. 例如：http://www.someorg.org/doc.html?fakeParam=42。注：如果您频繁的下载同一个文件，那么查询字符串应该进行改变。

代理: 如果在微软的 Internet Explorer 设置中配置了代理服务器, 那么 UrlDownloadToFile 会使用它访问 Internet.

FTP 和 Gopher: v1.0.48.04+ 支持 FTP 和 Gopher URL. 例如：

UrlDownloadToFile, ftp://example.com/home/My File.zip, C:\My Folder\My File.zip  ; 匿名登录.
UrlDownloadToFile, ftp://user:pass@example.com:21/home/My File.zip, C:\My Folder\My File.zip  ; 以指定的用户登录.
UrlDownloadToFile, ftp://user:pass@example.com/My Directory, C:\Dir Listing.html  ; 获取 HTML 格式的目录列表.

相关

FileRead, FileCopy

示例

UrlDownloadToFile, http://ahkscript.org/download/1.1/version.txt, C:\AutoHotkey Latest Version.txt
UrlDownloadToFile, http://someorg.org/archive.zip, C:\SomeOrg's Archive.zip
; 示例：下载文本到变量：
whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
whr.Open("GET", "http://ahkscript.org/download/1.1/version.txt")
whr.Send()
version := whr.ResponseText
MsgBox % version


Process

对进程执行下列的其中一个操作：检查进程是否存在；改变进程的优先级；关闭进程；等待进程关闭。

Process, Cmd, PID-or-Name [, Param3]

参数

Cmd

下列单词的其中一个:

Exist: 如果存在一个匹配的进程则设置 ErrorLevel 为此进程 ID (PID), 否则为 0. 如果 PID-or-Name 参数为空, 则获取脚本自身的 PID. 获取脚本的 PID 的另一种单行的方法是 PID := DllCall("GetCurrentProcessId")。

Close: 如果成功终止一个匹配的进程, 则设置 ErrorLevel 为此进程原来的进程 ID (PID). 否则 (没有找到匹配的进程或在终止匹配进程的过程中出现了问题) 它被设置为 0. 因为进程会被突然终止 (可能在一个关键点中断它的工作或导致窗口中未保存数据的丢失), 因此只有当无法使用 WinClose 作用于它的窗口来关闭相应进程时才应该使用这种方法.

List: 尽管还不支持 List, 但 示例部分 中的例子演示了通过 DllCall 获取进程列表的方法.

Priority: 改变首个匹配进程的优先级 (如同 Windows 任务管理器中看到的那样) 为 Param3 同时设置 ErrorLevel 为它的进程 ID (PID). 如果 PID-or-Name 参数为空, 则改变脚本自己的优先级. 如果没有找到匹配的进程或在改变匹配进程的优先级过程中出现了问题, 则 ErrorLevel 被设置为 0.

Param3 应该为下列字母或单词的其中一个: L (或 Low), B (或 BelowNormal), N (或 Normal), A (或 AboveNormal), H (或 High), R (或 Realtime). 注: 任何不是设计为 Realtime 优先级运行的进程如果设置为这个优先级可能会降低系统的稳定性.

Wait: 在 Param3 指定的秒数 (可以为小数) 中检查是否存在匹配的进程. 如果省略 Param3, 则此命令会无限期等待. 如果找到了匹配的进程, 则 ErrorLevel 被设置为它的进程 ID (PID). 如果命令超时了, 则 ErrorLevel 被置为 0.

WaitClose: 在 Param3 指定的秒数 (可以为小数) 中检查所有匹配的进程是否关闭. 如果省略 Param3, 则此命令会无限期等待. 如果所有的匹配进程都关闭了, 则 ErrorLevel 被置为 0. 如果命令超时了, 则 ErrorLevel 被设置为仍然存在的首个匹配进程的进程 ID (PID).

PID-or-Name

此参数可以为数字 (PID) 或下面描述的进程名称. 它还可以被留空来改变脚本自己的优先级.

PID: 进程 ID, 唯一标识一个特定进程的数字 (只有在此进程的生存期这个数字才有意义). 新运行的进程的 PID 可以通过 Run 命令获取. 同样的, 窗口的 PID 可以通过 WinGet 获取. Process 命令自身也可以获取 PID.

Name: 进程的名称, 通常和它的可执行文件名相同 (不带路径), 例如 notepad.exe 或 winword.exe. 一个名称可能匹配多个正在运行的进程, 但只会对第一个进程进行操作. 这个名称不区分大小写.

Param3

请参阅上面的 Cmd 了解详情.

ErrorLevel

请参阅上面的 Cmd 了解详情.

备注

对于 Wait 和 WaitClose: 会每隔 100 毫秒检查目标进程一次; 当目标进程满足条件时, 命令不再继续等待. 换句话说，这时不会等待超时时间到期，而是像上面描述的那样立即设置 ErrorLevel，然后继续往后执行脚本。此外, 当此命令处于等待状态时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

相关

Run, WinGet, WinClose, WinKill, WinWait, WinWaitClose, IfWinExist

示例

; 示例 #1:

Run Notepad.exe, , , NewPID
Process, priority, %NewPID%, High
MsgBox The newly launched notepad's PID is %NewPID%.

; 示例 #2:

Process, wait, Notepad.exe, 5.5
NewPID = %ErrorLevel%  ; 由于 ErrorLevel 会经常发生改变, 所以要立即保存这个值.
if NewPID = 0
{
    MsgBox The specified process did not appear within 5.5 seconds.
    return
}
; 否则:
MsgBox A matching process has appeared (Process ID is %NewPID%).
Process, priority, %NewPID%, Low
Process, priority, , High  ; 把脚本自己设置为高优先级.
WinClose Untitled - Notepad
Process, WaitClose, %NewPID%, 5
if ErrorLevel ; PID 仍然存在.
    MsgBox The process did not close within 5 seconds.

; 示例 #3: 一个改变活动窗口进程优先级的热键:

#z:: ; Win+Z hotkey
WinGet, active_pid, PID, A
WinGetTitle, active_title, A
Gui, 5:Add, Text,, Press ESCAPE to cancel, or double-click a new`npriority level for the following window:`n%active_title%
Gui, 5:Add, ListBox, vMyListBox gMyListBox r5, Normal|High|Low|BelowNormal|AboveNormal
Gui, 5:Add, Button, default, OK
Gui, 5:Show,, Set Priority
return

5GuiEscape:
5GuiClose:
Gui, Destroy
return

MyListBox:
if A_GuiEvent <> DoubleClick
    return
; 否则直接进入下一个标签:
5ButtonOK:
GuiControlGet, MyListBox
Gui, Destroy
Process, Priority, %active_pid%, %MyListBox%
if ErrorLevel
    MsgBox Success: Its priority was changed to "%MyListBox%".
else
    MsgBox Error: Its priority could not be changed to "%MyListBox%".
return

; 示例 #4: 使用 DllCall 获取正在运行的进程列表然后显示在 MsgBox.

d := "  |  "  ; 字符串分隔符
s := 4096  ; 缓存和数组的大小 (4 KB)

Process, Exist  ; 设置 ErrorLevel 为这个正在运行脚本的 PID
; 使用 PROCESS_QUERY_INFORMATION (0x0400) 获取此脚本的句柄
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel, "Ptr")
; 打开此进程的可调整的访问令牌 (TOKEN_ADJUST_PRIVILEGES = 32)
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
VarSetCapacity(ti, 16, 0)  ; 特权结构
NumPut(1, ti, 0, "UInt")  ; 特权数组中的一个条目...
; 获取调试特权的本地唯一标识符:
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
NumPut(luid, ti, 4, "Int64")
NumPut(2, ti, 12, "UInt")  ; 启用这个特权: SE_PRIVILEGE_ENABLED = 2
; 使用新的访问令牌更新此进程的特权:
r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", t)  ; 关闭此访问令牌句柄以节约内存
DllCall("CloseHandle", "Ptr", h)  ; 关闭此进程句柄以节约内存

hModule := DllCall("LoadLibrary", "Str", "Psapi.dll")  ; 通过预加载来提升性能
s := VarSetCapacity(a, s)  ; 接收进程列表标识符的数组:
c := 0  ; 用于进程标识符的计数器
DllCall("Psapi.dll\EnumProcesses", "Ptr", &a, "UInt", s, "UIntP", r)
Loop, % r // 4  ; 把数组解析为 DWORD (32 位) 的标识符:
{
   id := NumGet(a, A_Index * 4, "UInt")
   ; 打开进程: PROCESS_VM_READ (0x0010) | PROCESS_QUERY_INFORMATION (0x0400)
   h := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", id, "Ptr")
   if !h
      continue
   VarSetCapacity(n, s, 0)  ; 接收模块基础名称的缓存:
   e := DllCall("Psapi.dll\GetModuleBaseName", "Ptr", h, "Ptr", 0, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
   if !e    ; 用于 64 位进程在 32 位模式时的回退方法:
      if e := DllCall("Psapi.dll\GetProcessImageFileName", "Ptr", h, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
         SplitPath n, n
   DllCall("CloseHandle", "Ptr", h)  ; 关闭进程句柄以节约内存
   if (n && e)  ; 如果映像不是空的, 则添加到列表:
      l .= n . d, c++
}
DllCall("FreeLibrary", "Ptr", hModule)  ; 卸载库来释放内存
;Sort, l, C  ; 取消注释这行来按字母顺序对列表进行排序
MsgBox, 0, %c% Processes, %l%

; 示例 #5: 使用 COM 获取正在运行的进程列表.

Gui, Add, ListView, x2 y0 w400 h500, Process Name|Command Line
for process in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
    LV_Add("", process.Name, process.CommandLine)
Gui, Show,, Process List

; Win32_Process: http://msdn.microsoft.com/en-us/library/aa394372.aspx


Run / RunWait

运行外部程序。与 Run 不同, RunWait 会等待程序结束才继续往后执行.

Run, Target [, WorkingDir, Max|Min|Hide|UseErrorLevel, OutputVarPID]

参数

Target

要运行的文档, URL, 可执行文件 (.exe, .com, .bat, 等等), 快捷方式 (.lnk) 或 系统动词 (请参阅备注). 如果 Target 是本地文件且指定时没有包含路径, 则首先搜索 A_WorkingDir. 如果那里没有找到匹配的文件, 如果它是集成的 ("已知") 则系统会搜索并运行此文件, 例如包含在 PATH 环境变量的其中某个文件夹中.

要传递参数, 请让它们紧跟在程序或文档名的后面. 如果参数包含空格, 则把它们括在双引号中是最可靠的 (虽然它在某些情况下没有括在双引号中也能工作).

WorkingDir

用于运行项目的工作目录. 即使它包含空格, 也不要括在双引号中. 如果省略, 则使用脚本自己的工作目录 (A_WorkingDir).

Max|Min|Hide
UseErrorLevel

如果省略, 则正常运行 Target. 或者, 它可以包含一个或多个这些单词:

Max: 最大化运行

Min: 最小化运行

Hide: 隐藏运行 (不能和上面任意一个选项组合使用)

注: 一些程序 (例如 Calc.exe) 不会遵循请求的启动状态, 因此对于它们 Max/Min/Hide 没有效果.

UseErrorLevel: 可以单独指定 UseErrorLevel 或和上面的其中一个单词组合使用 (把它和其他单词用空格分隔). 如果运行失败, 则使用此选项会跳过警告对话框, 设置 ErrorLevel 为单词 ERROR, 并让 当前线程 继续执行. 如果运行成功, 则 RunWait 会把 ErrorLevel 设置为程序的退出代码, 而 Run 把它设置为 0.

指定 UseErrorLevel 时, 变量 A_LastError 被设置为操作系统 GetLastError() 函数返回的结果. A_LastError 是一个介于 0 和 4294967295 之间的数字 (总是为十进制而非十六进制). 零 (0) 意味着成功, 但其他任何数字意味着运行失败. 每个数字对应一种特定的错误状态 (要获取整个列表, 请在 www.microsoft.com 中搜索 "system error codes"). 像 ErrorLevel 一样，A_LastError 是与每个线程关联的设置，即由其他线程产生的中断不会改变它。然而, A_LastError 还可能由 DllCall 设置.

OutputVarPID

变量名, 用来存储新运行程序的唯一 进程 ID (PID). 如果无法确定则 PID 被设置为空, 这经常发生在运行系统动词, 文档或快捷方式而不是直接的可执行文件时. RunWait 也支持此参数, 不过它获取的 OuputVarPID 必须在 另一个线程 中进行检查 (否则, 这个 PID 将是无效的, 因为 RunWait 后的代码执行时相应的进程已经终止了).

在 Run 命令获取 PID, 此进程要创建的窗口可能还不存在. 要等待它至少创建一个窗口，请使用 WinWait ahk_pid %OutputVarPID%。

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

Run: 只有在使用了 UseErrorLevel 时才会设置 ErrorLevel, 在这种情况下失败时 ErrorLevel 被设置为单词 ERROR 而成功时为 0.

RunWait: 设置 ErrorLevel 为程序的退出代码 (32 位的有符号整数). 如果使用了 UseErrorLevel 且运行失败, 则把它设置为单词 ERROR.

备注

与 Run 不同, RunWait 会等待 Target 关闭或退出, 此时 ErrorLevel 被设置为程序的退出代码 (32 位的有符号整数). 一些程序即使它们仍在运行但看起来立即返回了; 这些程序启动了另外的进程.

如果 Target 包含逗号, 则必须对它们进行 转义, 如同下面例子中的三次演示:

Run rundll32.exe shell32.dll`,Control_RunDLL desk.cpl`,`, 3  ; 打开控制面板 > 显示属性 > 设置

通过 Comspec (cmd.exe) 运行程序时 (也许由于您需要重定向程序的输入和输出), 如果可执行程序的路径或名称包含空格, 则整个字符串必须括在一对外部的引号中. 在下面的例子中, 外部引号显示为红色, 而内部所有的引号显示为黑色:

Run %comspec% /c ""C:\My Utility.exe" "param 1" "second param" >"C:\My File.txt""

如果无法启动 Target，则显示错误窗口，然后脚本表现的就像遇到 Exit 命令那样。要避免这种情况, 请在第三个参数中添加字符串 UseErrorLevel.

当 Target 为准确路径时可轻微提升性能，例如使用 Run, C:\Windows\Notepad.exe "C:\My Documents\Test.txt" 代替 Run, C:\My Documents\Test.txt。

Run 还可以打开特殊的 CLSID 文件夹. 例如：

Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}  ; 打开 "我的电脑" 文件夹.
Run ::{645ff040-5081-101b-9f08-00aa002f954e}  ; 打开回收站.

系统动词对应于资源管理器中文件右键菜单的可用操作. 如果启动文件时没有指定动词, 则使用那种文件类型的默认动词 (通常为 "打开"). 如果指定了, 则动词后应该跟着默认文件名. 目前支持下列动词:

*动词 | [AHK_L 57+]: 任何系统定义或自定义的动词. 例如: Run *Compile %A_ScriptFullPath% 在 Windows Vista 和更高版本中，可以使用 *RunAs 动词代替以管理员身份运行右键菜单。
properties | 显示指定文件的资源管理器属性窗口. 例如: Run, properties "C:\My File.txt" 注: 当脚本终止时属性窗口会自动关闭. 要避免这种情况, 请使用 WinWait 等待窗口出现, 然后使用 WinWaitClose 等待用户关闭它.
find | 在指定的文件夹中打开资源管理器的搜索助理或查找文件窗口实例. 例如: Run, find D:\
explore | 打开指定文件夹的资源管理器实例. 例如：Run, explore %A_ProgramFiles%。
edit | 打开指定的文件进行编辑. 如果指定的文件类型没有关联 "edit" 动作时, 它不起作用. 例如: Run, edit "C:\My File.txt"
open | 打开指定的文件 (一般不需要, 因为这对于大多数文件类型是默认的动作). 例如：Run, open "My File.txt"。
print | 使用关联的应用程序打印指定的文件，如果有。例如: Run, print "My File.txt"

当 RunWait 处于等待状态时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

相关

RunAs, Process, Exit, CLSID 列表, DllCall

示例

Run, Notepad.exe, C:\My Documents, max

Run, mailto:someone@domain.com?subject=This is the subject line&body=This is the message body's text.
Run, ReadMe.doc, , Max UseErrorLevel  ; 最小化运行, 且在失败时不显示对话框.
if ErrorLevel = ERROR
    MsgBox The document could not be launched.

RunWait, %comspec% /c dir c:\ >>c:\DirTest.txt, , min
Run, c:\DirTest.txt
Run, properties c:\DirTest.txt

Run, http://www.google.com ; 即可以运行任意网址。
Run, mailto:someone@somedomain.com  ; 这样应该会打开默认的电子邮件程序。

Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}  ; 打开“我的电脑”文件夹。
Run ::{645ff040-5081-101b-9f08-00aa002f954e}  ; 打开回收站。

; 要连续执行多个命令，请在命令间使用“&&”分隔：
Run, %comspec% /c dir /b > C:\list.txt && type C:\list.txt && pause


RunAs

指定在后续所有的 Run 和 RunWait 中使用的一组用户凭据。

RunAs [, User, Password, Domain]

参数

User

如果省略此参数和其他所有参数, 则关闭 RunAs 的功能, 这样会恢复 Run 和 RunWait 到它们默认的行为. 否则, 它为用来创建新进程的用户名.

Password

User 的密码.

Domain

User 域. 要使用本地账户, 请留空此参数. 如果这样不起作用, 请尝试使用 @YourComputerName.

备注

此命令只通知 AutoHotkey 为后续所有的 Run 和 RunWait 使用 (或不使用) 替换的用户凭据.

此命令不会改变 ErrorLevel. 如果指定的User、Password或Domain无效，则Run和RunWait会显示错误消息来指出此问题（除非使用了UseErrorLevel 选项）。

当 RunAs 功能有效时, Run 和 RunWait 不能启动文档, URL 或系统动词. 换句话说, 此时只能运行可执行文件.

"Secondary Logon" 服务必须设为手动或自动, 这样此命令才能工作 (设为手动时操作系统会在需要时自动启动它).

相关

Run, RunWait

示例

RunAs, Administrator, MyPassword
Run, RegEdit.exe
RunAs  ; 恢复为普通行为.


Shutdown

关闭、重启或注销系统。

Shutdown, Code

参数

Code

在下面列出的关闭代码的组合.

备注

关闭代码包含下列值:

logoff | 0
Shutdown | 1
重启 | 2
强制 | 4
断电 | 8
挂起/休眠 | 请参阅本页底部的 DllCall 示例.
关闭显示器 | 请参阅 PostMessage 示例。

把需要的值加在一起. 例如, 要关闭并切断电源的代码为 9 (关闭 + 切断电源 = 1 + 8 = 9). 或者, 可以使用 表达式, 例如 1+8.

使用 "强制" 值 (4) 来强制关闭所有打开的应用程序. 它应该仅用于紧急的情况中, 因为这样可能导致打开的应用程序数据丢失.

"断电" 数值表示关闭系统并切断电源.

相关提示, 脚本通过 OnExit 可以检测到系统正在关闭或用户正在注销.

相关

Run, ExitApp, OnExit

示例

; 强制重新启动 (重启 + 强制 = 2 + 4 = 6):
Shutdown, 6

; 调用 Windows API 函数 "SetSuspendState" 来让系统挂起或休眠.
; 参数 #1: 使用 1 代替 0 来进行休眠而不是挂起.
; 参数 #2: 使用 1 代替 0 来立即挂起而不询问每个应用程序以获得许可.
; 参数 #3: 使用 1 而不是 0 来禁止所有的唤醒事件.
DllCall("PowrProf\SetSuspendState", "int", 0, "int", 0, "int", 0)


RegDelete

从注册表中删除子键或值。

RegDelete, RootKey, SubKey [, ValueName]

参数

RootKey

必须为 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_USER, HKEY_CLASSES_ROOT 或 HKEY_CURRENT_CONFIG 的其中一个 (或者它们的缩写, 例如 HKLM). 要访问远程注册表, 请在前面加上计算机名和冒号, 例如: \\workstation01:HKEY_LOCAL_MACHINE

SubKey

子键名 (例如 Software\SomeApplication).

ValueName

要删除的值名. 如果省略，将删除整个SubKey。要删除 Subkey 的默认值（即注册表中值名显示为“(默认)”的值），请在此参数中使用 AHK_DEFAULT。

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

对注册表进行删除操作可能引发潜在的问题, 操作前请三思!

要获取和操作多个注册表键或值, 请考虑使用 注册表循环.

关于如何访问远程计算机注册表的详情, 请参阅 注册表循环 中的备注.

要在 32 位脚本中删除注册表 64 位部分的条目或进行相反的操作，请使用 SetRegView。

相关

RegRead、RegWrite、注册表循环、SetRegView、IniDelete

示例

RegDelete, HKEY_LOCAL_MACHINE, Software\SomeApplication, TestValue


RegRead

从注册表读取值。

RegRead, OutputVar, RootKey, SubKey [, ValueName]

参数

OutputVar

用来存储获取值的变量名. 如果无法获取, 则变量被置空且 ErrorLevel 被设置为 1.

RootKey

必须为 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_USER, HKEY_CLASSES_ROOT 或 HKEY_CURRENT_CONFIG 的其中一个 (或者它们的缩写, 例如 HKLM). 要访问远程注册表, 请在前面加上计算机名和冒号, 例如: \\workstation01:HKEY_LOCAL_MACHINE

SubKey

子键名 (例如 Software\SomeApplication).

ValueName

要获取的值名. 如果省略, 则获取 Subkey 的默认值, 这是在注册表中值名显示为 "(默认)" 的值. 如果没有默认值 (即注册表中显示 "数值未设置"), 则 OutputVar 被置空且 ErrorLevel 被设置为 1.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题 (例如不存在的键或值名) 则 ErrorLevel 被设置为 1, 否则为 0.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

目前只支持下列这些值类型: REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ, REG_DWORD 以及 REG_BINARY.

REG_DWORD 值总是被转换为正十进制数.

读取 REG_BINARY 键时, 获取的结果为十六进制字符的字符串. 例如, REG_BINARY 类型的值 01,a9,ff,77 的读取结果为字符串 01A9FF77.

读取 REG_MULTI_SZ 键时, 值的每个部分会以换行符结束 (`n). 如果值为空, 则 OutputVar 会被置空. 请参阅 FileSelectFile 中的示例了解如何从 OutputVar 中逐个提取单独的部分.

大于 64K 的 REG_BINARY 值只有在 v1.1.10.01 或更高版本中才能读取。

要获取和操作多个注册表键或值, 请考虑使用 注册表循环.

关于如何访问远程计算机注册表的详情, 请参阅 注册表循环 中的备注.

要在 32 位脚本中读写注册表 64 位部分的条目或进行相反的操作，请使用 SetRegView。

相关

RegDelete、RegWrite、注册表循环、SetRegView、IniRead

示例

RegRead, OutputVar, HKEY_LOCAL_MACHINE, SOFTWARE\Microsoft\Windows\CurrentVersion, ProgramFilesDir
MsgBox, Program files are in: %OutputVar%

; 下面的例子获取注册表值的类型 (例如 REG_SZ 或 REG_DWORD).
MsgBox % RegKeyType("HKCU", "Environment", "TEMP")
return

RegKeyType(RootKey, SubKey, ValueName)  ; 此函数返回指定值的类型.
{
    Loop, %RootKey%, %SubKey%
        if (A_LoopRegName = ValueName)
            return A_LoopRegType
    return "Error"
}


RegWrite

写入值到注册表。

RegWrite, ValueType, RootKey, SubKey [, ValueName, Value]

参数

ValueType

必须为 REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ, REG_DWORD 或 REG_BINARY 的其中一个.

RootKey

必须为 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_USER, HKEY_CLASSES_ROOT 或 HKEY_CURRENT_CONFIG 的其中一个 (或者它们的缩写, 例如 HKLM). 要访问远程注册表, 请在前面加上计算机名和冒号, 例如: \\workstation01:HKEY_LOCAL_MACHINE

SubKey

子键名 (例如 Software\SomeApplication). 如果 SubKey 不存在，则进行创建（需要时创建它的父键以及父键的父键等）。如果 SubKey 留空, 则直接把值写入到 RootKey (不过一些操作系统可能会拒绝写入到 HKEY_CURRENT_USER 的根键中).

ValueName

将被写入的值名. 如果为空或省略, 则使用 Subkey 的默认值, 这是在注册表中值名显示为 "(默认)" 的值.

值

要写入的值. 如果省略, 则根据 ValueType 的不同它默认为空字符串或 0. 如果文本较长, 可以通过 延续片段 的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

如果 ValueType 为 REG_DWORD, 则 Value 应该介于 -2147483648 和 4294967295 (0xFFFFFFFF) 之间.

写入 REG_BINARY 键时, 请使用十六进制的字符串, 例如 REG_BINARY 值 01,a9,ff,77 在写入时要使用字符串 01A9FF77.

写入 REG_MULTI_SZ 键时, 您必须使用换行符 (`n) 分隔各个部分. 最后一个部分后面的换行符是可选的. 不允许存在空的部分. 换句话说, 在一行中不能连续指定两个换行符 (`n`n), 因为这样会导致写入到注册表的值比期望的短.

在 v1.1.10.01 或更高版本中支持大于 64K 的 REG_BINARY 和 REG_MULTI_SZ 值。在旧版本中，它们会被截断成 64K。

要获取和操作多个注册表键或值, 请考虑使用 注册表循环.

关于如何访问远程计算机注册表的详情, 请参阅 注册表循环 中的备注.

要在 32 位脚本中读写注册表 64 位部分的条目或进行相反的操作，请使用 SetRegView。

相关

RegDelete、RegRead、注册表循环、SetRegView、IniWrite

示例

RegWrite, REG_SZ, HKEY_LOCAL_MACHINE, SOFTWARE\TestKey, MyValueName, Test Value
RegWrite, REG_BINARY, HKEY_CURRENT_USER, Software\TEST_APP, TEST_NAME, 01A9FF77
RegWrite, REG_MULTI_SZ, HKEY_CURRENT_USER, Software\TEST_APP, TEST_NAME, Line1`nLine2


SetRegView

SetRegView [v1.1.08+]

设置 RegRead、RegWrite、RegDelete 和注册表循环使用的注册表视图。

SetRegView, RegView

参数

RegView

指定 32 以 32 位程序的方式来查看注册表，而 64 以 64 位程序的方式浏览注册表。

指定单词 Default 来恢复到默认的行为。

一般说明

此命令仅在 64 位 Windows 上有用。它在 32 位 Windows 中没有效果。

在 64 位系统中，32 位程序运行于被称为 WOW64 的 Windows 子系统中。默认情况下，系统会重定向某些注册表键来避免冲突。例如，在 32 位脚本中，HKLM\SOFTWARE\AutoHotkey 会被重定向到 HKLM\SOFTWARE\Wow6432Node\AutoHotkey。SetRegView 允许 32 位脚本中的注册表命令访问在 64 位注册表视图中被重定向的键，反之亦然。

内置变量 A_RegView 包含了当前设置。每个新运行的线程（例如热键、自定义菜单项或定时子程序）都会以此命令的默认设置开始。通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

RegRead、RegWrite、RegDelete、Loop（注册表）

示例

示例 1 演示了如何设置特定的注册表视图以及注册表重定向对脚本的影响。

; 以 32 位程序的方式访问注册表。
SetRegView 32
RegWrite REG_SZ, HKLM, SOFTWARE\Test.ahk, Value, 123

; 以 64 位程序的方式访问注册表。
SetRegView 64
RegRead value, HKLM, SOFTWARE\Wow6432Node\Test.ahk, Value
RegDelete HKLM, SOFTWARE\Wow6432Node\Test.ahk

MsgBox Read value '%value%' via Wow6432Node.

; 恢复默认的注册表视图，这
; 取决于脚本是 32 位还是 64 位的。
SetRegView Default
;...

示例 2 演示了如何判断正在运行脚本的 EXE 和操作系统的类型。

if (A_PtrSize = 8)
    script_is := "64-bit"
else ; if (A_PtrSize = 4)
    script_is := "32-bit"

if (A_Is64bitOS)
    OS_is := "64-bit"
else
    OS_is := "32-bit, which has only a single registry view"

MsgBox This script is %script_is%, and the OS is %OS_is%.


SoundBeep

让 PC 扬声器发出蜂鸣音。

SoundBeep [, Frequency, Duration]

参数

Frequency

声音的频率, 可以为 表达式. 它应该是介于 37 和 32767 之间的数字. 如果省略, 则频率为 523.

Duration

声音的持续时间, 单位为毫秒 (可以为 表达式). 如果省略, 则持续时间为 150.

备注

脚本会等待声音结束后才继续执行. 此外, 在发出声音时系统的响应可能会减慢.

如果计算机没有声卡, 则 PC 扬声器将播放标准的哗音.

要生成标准的系统声音而不是 PC 扬声器的哗音, 请参阅 SoundPlay 中的星号模式.

相关

SoundPlay

示例

SoundBeep  ; 以默认的音高和持续时间进行发音.
SoundBeep, 750, 500  ; 以较高的音高进行发音并持续半秒.


SoundGet

从音频设备中获取各种设置（主静音、主音量等）。

SoundGet, OutputVar [, ComponentType, ControlType, DeviceNumber]

参数

OutputVar

用来保存获取的设置的变量名, 可以为一个介于 0 和 100 (包含的) 之间的浮点数或单词 ON 或 OFF (仅用于 控制器类型 为 ONOFF, MUTE, MONO, LOUDNESS, STEREOENH 以及 BASSBOOST 的时候). 如果在获取设置时遇到问题, 则此变量会被置空. 浮点数的格式 (例如它的小数位数) 由 SetFormat 决定.

ComponentType

如果省略或为空, 则它默认为单词 MASTER. 否则, 它可以为下列单词的其中一个: MASTER (与 SPEAKERS 含义相同), DIGITAL, LINE, MICROPHONE, SYNTH, CD, TELEPHONE, PCSPEAKER, WAVE, AUX, ANALOG, HEADPHONES 或 N/A. 如果音频设备缺少指定的 组件类型, 则 ErrorLevel 会表明此问题.

在某些混音器中标为 Auxiliary 的组件可能需要作为 ANALOG 而不是 AUX 进行访问.

如果一个设备含有同种 组件类型 的多个实例 (例如两个 LINE 类型), 那么通常首个包含播放设置, 第二个包含录制设置. 要访问首个实例外的其他实例, 请在此参数后加上冒号和数字. 例如：Analog:2 表示 analog 组件的第二个实例。

ControlType

如果省略或为空, 则它默认为 VOLUME. 否则, 它可以为下列单词的其中一个: VOLUME (或 VOL), ONOFF, MUTE, MONO, LOUDNESS, STEREOENH, BASSBOOST, PAN, QSOUNDPAN, BASS, TREBLE, EQUALIZER 或表示有效的控制器类型数字 (请参阅 声卡分析脚本). 如果指定的 组件类型 没有指定的 控制器类型, 则 ErrorLevel 会表明此问题.

注：音频设备通常仅支持 VOLUME（或VOL）和 MUTE，不过根据 Windows 和音频设备的不同还可能支持其他。

DeviceNumber

介于 1 和支持设备总数之间的数字。如果省略此参数，则它默认为 1（首个音频设备），在 Windows Vista 及更高版本中则为系统默认的录制和播放设备。此参数可以为 表达式. 声卡分析脚本有助于确定要使用的编号。

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

命令执行成功时 ErrorLevel 被设置为 0. 否则, 它会被设置为下列短语的其中一个:

Invalid Control Type or Component Type
Can't Open Specified Mixer
Mixer Doesn't Support This Component Type
Mixer Doesn't Have That Many of That Component Type
Component Doesn't Support This Control Type
Can't Get Current Setting

备注

在 v1.1.10 中添加了对 Windows Vista 及更高版本的支持。

要找出安装在系统上的音频设备 (混音器) 的功能 (例如可用的组件类型和控制器类型), 请运行 声卡分析脚本.

与音频设备相关的更多功能和细微控制，考虑使用 VA 库。

使用 SoundSet 来改变设置.

相关

SoundSet, SoundGetWaveVolume, SoundSetWaveVolume, SoundPlay

示例

SoundGet, master_volume
MsgBox, Master volume is %master_volume% percent.

SoundGet, master_mute, , mute
MsgBox, Master Mute is currently %master_mute%.

SoundGet, bass_level, Master, bass
if ErrorLevel
    MsgBox, Error Description: %ErrorLevel%
else
    MsgBox, The BASS level for MASTER is %bass_level% percent.

SoundGet, microphone_mute, Microphone, mute
if microphone_mute = Off
    MsgBox, The microphone is not muted.


SoundGetWaveVolume

获取音频设备的波形输出音量.

SoundGetWaveVolume, OutputVar [, DeviceNumber]

参数

OutputVar

用来保存获取的音量级别的变量名, 它是一个介于 0 和 100 (包含的) 之间的浮点数. 如果在获取音量时遇到问题, 则此变量会被置空. 浮点数的格式 (例如它的小数位数) 由 SetFormat 决定.

DeviceNumber

如果省略此参数, 则它默认为 1 (首个音频设备), 通常是系统默认的录制和播放设备. 可以通过指定大于 1 的数字来操作其他音频设备.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

使用 SoundSetWaveVolume 可以设置当前的波形输出音量级别. 其他设置 (例如主音量, 合成器, 麦克风, 静音, 高音和低音) 可以使用 SoundSet 和 SoundGet 进行设置和获取.

Windows Vista 及更高版本（v1.1.10+）：此命令相当于 ComponentType 参数被设为 Wave 且 ControlType 被设为 Volume 的 SoundGet 命令。

相关

SoundSetWaveVolume, SoundSet, SoundGet, SoundPlay

示例

SoundGetWaveVolume, OutputVar
MsgBox, The current wave output volume level is %OutputVar%`%.


SoundPlay

播放音频、视频或其他支持的文件类型。

SoundPlay, Filename [, wait]

参数

Filename

要播放的文件名, 如果未指定绝对路径则假定在 %A_WorkingDir% 中.

要发出标准的系统声音, 请像下面显示的那样指定星号后跟着数字. 注: 在此模式中 wait 参数没有效果.
*-1：简单的哔哔声。如果声卡不可用, 则使用扬声器生成这个声音.
*16：手型（停止/错误声）
*32：问号声
*48：感叹声
*64：星号（消息声）

wait

如果省略, 则在播放文件时脚本的 当前线程 会移动到下一个命令. 要避免这种情况, 请指定 1 或单词 WAIT, 这会使得当前线程会等到文件播放结束后才继续执行. 即使在等待时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

已知限制: 如果省略 WAIT 参数, 则操作系统可能认为播放的文件 "在使用中", 直到脚本关闭或播放另一个文件 (甚至是不存在的文件).

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

所有 Windows 操作系统应该够能播放 .wav 文件. 不过, 如果操作系统中没有安装正确的解码器或功能, 那么其他文件 (.mp3, .avi, etc.) 可能无法播放.

如果在播放一个文件时当前脚本播放了第二个文件, 那么第一个文件会被停止后才可以播放第二个. 在一些系统中, 即使在完全独立的脚本中播放新文件时, 某些文件类型也可能停止播放.

要停止当前正在播放的文件，请对不存在的文件使用 SoundPlay，例如：SoundPlay, Nonexistent.avi。

如果脚本退出了, 那么任何由它启动的当前正在播放的文件将会停止.

相关

SoundBeep, SoundGet, SoundSet, SoundGetWaveVolume, SoundSetWaveVolume, MsgBox, 线程

示例

SoundPlay, %A_WinDir%\Media\ding.wav
SoundPlay *-1  ; 简单的哗哗声. 如果声卡不可用, 则使用扬声器生成这个声音..


SoundSet

改变音频设备的各种设置（主静音、主音量等）。

SoundSet, NewSetting [, ComponentType, ControlType, DeviceNumber]

参数

NewSetting

介于 -100 和 100 (包含的) 之间的百分数 (它可以为浮点数或 表达式). 如果这个数字以加号或减号开头，则将当前设置往上或往下调指示的数量。否则, 此设置将被明确地设置为 NewSetting 表示的级别.

对于只有两种可能设置的 控制器类型 而言 (即 ONOFF, MUTE, MONO, LOUDNESS, STEREOENH 以及 BASSBOOST), 任何正数都将开启设置, 而 0 则进行关闭. 然而, 如果这个数字以加号或减号开头, 则对设置进行切换 (设置为和当前状态相反).

ComponentType

如果省略或为空, 则它默认为单词 MASTER. 否则, 它可以为下列单词的其中一个: MASTER (与 SPEAKERS 含义相同), DIGITAL, LINE, MICROPHONE, SYNTH, CD, TELEPHONE, PCSPEAKER, WAVE, AUX, ANALOG, HEADPHONES 或 N/A. 如果音频设备缺少指定的 组件类型, 则 ErrorLevel 会表明此问题.

在某些混音器中标为 Auxiliary 的组件可能需要作为 ANALOG 而不是 AUX 进行访问.

如果一个设备含有同种 组件类型 的多个实例 (例如两个 LINE 类型), 那么通常首个包含播放设置, 第二个包含录制设置. 要访问首个实例外的其他实例, 请在此参数后加上冒号和数字. 例如：Analog:2 表示 analog 组件的第二个实例。

ControlType

如果省略或为空, 则它默认为 VOLUME. 否则, 它可以为下列单词的其中一个: VOLUME (或 VOL), ONOFF, MUTE, MONO, LOUDNESS, STEREOENH, BASSBOOST, PAN, QSOUNDPAN, BASS, TREBLE, EQUALIZER 或表示有效的控制器类型数字 (请参阅 声卡分析脚本). 如果指定的 组件类型 没有指定的 控制器类型, 则 ErrorLevel 会表明此问题.

注：音频设备通常仅支持 VOLUME（或VOL）和 MUTE，不过根据 Windows 和音频设备的不同还可能支持其他。

DeviceNumber

介于 1 和支持设备总数之间的数字。如果省略此参数，则它默认为 1（首个音频设备），在 Windows Vista 及更高版本中则为系统默认的录制和播放设备。此参数可以为 表达式. 声卡分析脚本有助于确定要使用的编号。

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

命令执行成功时 ErrorLevel 被设置为 0. 否则, 它会被设置为下列短语的其中一个:

Invalid Control Type or Component Type
Can't Open Specified Mixer
Mixer Doesn't Support This Component Type
Mixer Doesn't Have That Many of That Component Type
Component Doesn't Support This Control Type
Can't Get Current Setting
Can't Change Setting

备注

在 v1.1.10 中添加了对 Windows Vista 及更高版本的支持。

与音频设备相关的更多功能和细微控制，考虑使用 VA 库。

另一种调整音量方法是在脚本中发送音量控制键击来改变整个系统的主音量，如后面的例子所示：

Send {Volume_Up}  ; 增加 1 个音程的主音量 (通常为 5%).
Send {Volume_Down 3}  ; 降低 3 个音程的主音量.
Send {Volume_Mute}  ; 对主音量进行静音/取消静音.

要找出安装在系统上的音频设备 (混音器) 的功能 (例如可用的组件类型和控制器类型), 请运行 声卡分析脚本.

Windows 2000/XP/2003：当 SoundSet 改变一个组件的音量时，此组件的所有声道（例如左和右）都会被设置为相同级别。换句话说, 会丢失任何原来的不平衡的声道设置. 此问题可以使用 SoundSetWaveVolume 设置 WAVE 组件来避免, 它在改变音量级别时会尝试维持原有的声道平衡.

Windows Vista 及更高版本（v1.1.10+）：SoundSet 在改变音量级别时会尝试维持原有的声道平衡。

使用 SoundGet 来获取某个设置的当前值.

相关

SoundGet, SoundGetWaveVolume, SoundSetWaveVolume, SoundPlay

示例

; 基本示例:
SoundSet, 50  ; 将主音量设置为 50%
SoundSet +10  ; 将主音量增加 10%
SoundSet -10  ; 将主音量减小 10%
SoundSet, 1, Microphone, mute  ; 对麦克风进行静音
SoundSet, +1, , mute  ; 切换主静音 (设置到相反的状态)
SoundSet, +20, Master, bass  ; 将低音级别增加 20%.
if ErrorLevel
    MsgBox, The BASS setting is not supported for MASTER.

声卡分析

使用下面的脚本来找出您声卡的功能（组件类型和控制器类型）。它会在简单的 ListView 中显示结果。还可以从后面的论坛主题中下载用于 Windows Vista 及更高版本的脚本，它提供了更多的细节（例如显示设备名称）：http://www.autohotkey.com/board/topic/90877-/

SetBatchLines -1
SplashTextOn,,, Gathering Soundcard Info...

; 下面的大部分纯数字也许不存在于任何混音器中，但查询时需要它们才完整。; 对应于下面项目的数字（按顺序）：CUSTOM、BOOLEANMETER、SIGNEDMETER、PEAKMETER、
; UNSIGNEDMETER、BOOLEAN、BUTTON、DECIBELS、SIGNED、UNSIGNED、PERCENT、SLIDER、FADER、SINGLESELECT、MUX、
; MULTIPLESELECT、MIXER、MICROTIME、MILLITIME
ControlTypes = VOLUME,ONOFF,MUTE,MONO,LOUDNESS,STEREOENH,BASSBOOST,PAN,QSOUNDPAN,BASS,TREBLE,EQUALIZER,0x00000000, 0x10010000,0x10020000,0x10020001,0x10030000,0x20010000,0x21010000,0x30040000,0x30020000,0x30030000,0x30050000,0x40020000,0x50030000,0x70010000,0x70010001,0x71010000,0x71010001,0x60030000,0x61030000

ComponentTypes = MASTER,HEADPHONES,DIGITAL,LINE,MICROPHONE,SYNTH,CD,TELEPHONE,PCSPEAKER,WAVE,AUX,ANALOG,N/A

; 创建 ListView，为主循环做准备：
Gui, Add, Listview, w400 h400 vMyListView, Component Type|Control Type|Setting|Mixer
LV_ModifyCol(4, "Integer")
SetFormat, Float, 0.2  ; 限制小数位数为两位。

Loop  ; 对于系统中存在的每个混音器编号，查询它的性能。
{
    CurrMixer := A_Index
    SoundGet, Setting,,, %CurrMixer%
    if ErrorLevel = Can't Open Specified Mixer  ; 除了这个外的其他任何错误都表明混音器存在。
        break

    ; 对于此混音器中的每个组件类型，查询它的实例和控制器类型：
    Loop, parse, ComponentTypes, `,
    {
        CurrComponent := A_LoopField
        ; 首先检查这个组件类型是否实际存在于混音器中：
        SoundGet, Setting, %CurrComponent%,, %CurrMixer%
        if ErrorLevel = Mixer Doesn't Support This Component Type
            continue  ; 移动到下一个组件类型进行新的重复。
        Loop  ; 对于此组件类型的每个实例，查询它的控制器类型。
        {
            CurrInstance := A_Index
            ; 首先检查当前实例的这个实例是否存在于混音器中：
            SoundGet, Setting, %CurrComponent%:%CurrInstance%,, %CurrMixer%
            ; 检查下面两个错误以允许在较旧的版本中运行此脚本：
            if ErrorLevel in Mixer Doesn't Have That Many of That Component Type,Invalid Control Type or Component Type
                break  ; 这个组件类型已经没有更多实例了。
            ; 获取这个组件的当前实例中存在的每个控制器类型的当前设置：
            Loop, parse, ControlTypes, `,
            {
                CurrControl := A_LoopField
                SoundGet, Setting, %CurrComponent%:%CurrInstance%, %CurrControl%, %CurrMixer%
                ; 检查下面两个错误以允许在较旧的版本中运行此脚本：
                if ErrorLevel in Component Doesn't Support This Control Type,Invalid Control Type or Component Type
                    continue
                if ErrorLevel  ; 出现其他错误，这是意外的情况，所以把它显示在结果中。
                    Setting := ErrorLevel
                ComponentString := CurrComponent
                if CurrInstance > 1
                    ComponentString = %ComponentString%:%CurrInstance%
                LV_Add("", ComponentString, CurrControl, Setting, CurrMixer)
            }  ; 对于每个控制器类型。
        }  ; 对于每个组件实例。
    }  ; 对于每个组件类型。
}  ; 对于每个混音器。

Loop % LV_GetCount("Col")  ; 自动根据内容调节每列的宽度。
    LV_ModifyCol(A_Index, "AutoHdr")

SplashTextOff
Gui, Show
return

GuiClose:
ExitApp


SoundSetWaveVolume

改变音频设备的波形输出音量。

SoundSetWaveVolume, Percent [, DeviceNumber]

参数

Percent

介于 -100 和 100 (包含的) 之间的百分数 (它可以为浮点数或 表达式). 如果这个数字以加号或减号开头, 则将 当前音量级别 往上或往下调指示的数量. 否则, 音量将被明确地设置为 Percent 表示的级别.

DeviceNumber

如果省略此参数, 则它默认为 1 (首个音频设备), 通常是系统默认的录制和播放设备. 可以通过指定大于 1 的数字来操作其他音频设备.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

使用 SoundGetWaveVolume 可以获取当前的波形输出音量级别. 其他设置 (例如主音量, 合成器, 麦克风, 静音, 高音和低音) 可以使用 SoundSet 和 SoundGet 进行设置和获取.

Windows Vista 及更高版本（v1.1.10+）：此命令相当于 ComponentType 参数被设为 Wave 且 ControlType 被设为 Volume 的 SoundSet 命令。这两者都会尝试维持原有的声道平衡。

Windows 2000/XP/2003：与 SoundSet 不同，此命令在改变音量级别时会尝试维持原有的声道平衡（例如左和右）。

相关

SoundGetWaveVolume, SoundSet, SoundGet, SoundPlay

示例

SoundSetWaveVolume, 50  ; 将波形音量设为一半.
SoundSetWaveVolume, -10  ; 将当前级别减小 10 (例如 80 会变成 70).
SoundSetWaveVolume, +20  ; 将当前级别增加 20.


FormatTime

转换 YYYYMMDDHH24MISS 时间戳到指定的日期/时间格式。

FormatTime, OutputVar [, YYYYMMDDHH24MISS, Format]

参数

OutputVar

用来存储结果的变量名.

YYYYMMDD...

留空此参数来使用当前本地日期和时间. 否则, 否则请指定 YYYYMMDDHH24MISS 格式的时间戳中所有或前面的部分. 如果时间戳中日期和/或时间部分是无效的 (例如平年的二月 29 日), 则这部分会从 OutputVar 中删去. 尽管仅支持 1601 和 9999 之间的年份, 但只要时间部分是有效的, 对于更早的年份仍然可以生成格式化的时间.

Format

如果省略, 则它默认为时间后跟着长日期, 并且会对它们根据当前用户区域设置进行格式化. 例如: 4:55 PM Saturday, November 27, 2004

否则, 请指定一个或多个下面的日期-时间格式以及在它们之间的任何原义空格和标点 (逗号不需要转义; 它们可以正常使用). 在下面的例子中, 请注意 M 必须为大写: M/d/yyyy h:mm tt

日期格式 (区分大小写)

d | 不含前导零的天数 (1 - 31)
dd | 含前导零的天数 (01 – 31)
ddd | 在当前的用户语言里星期几的简称 (例如 Mon)
dddd | 在当前的用户语言里星期几的全称 (例如 Monday)
M | 不含前导零的月份 (1 – 12)
MM | 含前导零的月份 (01 – 12)
MMM | 在当前的用户语言里月份的简称 (例如 Jan)
MMMM | 在当前的用户语言里月份的全称 (例如 January)
y | 不含世纪的年份, 不含前导零 (0 – 99)
yy | 不含世纪的年份, 含前导零 (00 - 99)
yyyy | 含世纪的年份. 例如: 2005
gg | 当前用户区域设置的时代/纪元字符串 (如果没有则为空)

时间格式 (区分大小写)

h | 不含前导零的小时数; 十二小时制格式 (1 - 12)
hh | 含前导零的小时数; 十二小时制格式 (01 - 12)
H | 不含前导零的小时数; 二十四小时制格式 (0 - 23)
HH | 含前导零的小时数; 二十四小时制格式 (00 - 23)
m | 不含前导零的分钟数 (0 – 59)
mm | 含前导零的分钟数 (00 – 59)
s | 不含前导零的秒数 (0 – 59)
ss | 含前导零的秒数 (00 – 59)
t | 单字符时间标记, 例如 A 或 P (取决于区域设置)
tt | 多字符时间标记, 例如 AM 或 PM (取决于区域设置)

下面的格式必须 单独 使用; 即在 Format 参数中不能含有其他格式或文本. 这些格式不区分大小写.

(空) | 留空 Format 来生成时间后跟着长日期. 例如, 在某些区域设置中它可能看起来像这样: 4:55 PM Saturday, November 27, 2004
Time | 当前用户区域设置的时间表示, 例如 5:26 PM
ShortDate | 当前用户区域设置的短日期表示, 例如 02/29/04
LongDate | 当前用户区域设置的长日期表示, 例如 Friday, April 23, 2004
YearMonth | 当前用户区域设置的年份和月份格式, 例如 February, 2004
YDay | 不含前导零的年份的天数 (1 – 366)
YDay0 | 含前导零的年份的天数 (001 – 366)
WDay | 星期的天数 (1 – 7). 星期天为 1.
YWeek | ISO 8601 中规定的完全年份和周数. 例如: 200453. 如果含有 1 月 1 日的星期有四天以上在新年里, 则它被认为是新年的第一星期. 否则, 它为前一年的最后一个星期, 而下一星期为新年的第一星期. 因此, 1 月 4 日和首个星期四总是在第一周.

附加选项

下列选项可以紧跟在 YYYYMMDDHH24MISS 时间戳后 (如果没有时间戳, 它们也可以单独使用). 在下面的例子中, 请注意最后的四项间没有逗号.

FormatTime, OutputVar, 20040228 LSys D1 D4

R: 反转. 让日期在时间之前 (仅当 Format 为空时才有意义).

Ln: 如果此选项 不 存在, 则使用当前用户区域设置来格式化字符串. 要使用系统的区域设置, 请指定 LSys. 要使用特殊的区域设置, 请指定字母 L 后面跟着十六进制或十进制的区域设置标识符 (LCID). 关于如何构建 LCID 的信息, 请在 www.microsoft.com 上搜索下列短语: Locale Identifiers

Dn: 日期选项. 请指定 n 为下列数字的其中一个:
0: 强制使用默认选项. 这也会让短日期生效.
1: 使用短日期 (仅当 Format 为空时才有意义; 与 2 和 8 不兼容).
2: 使用长日期 (仅当 Format 为空时才有意义; 与 1 和 8 不兼容).
4：使用备用日历（如果有）。
8: 使用年份-月份格式 (仅当 Format 为空时才有意义; 与 1 和 2 不兼容).
0x10: 为从左到右的阅读顺序布局添加标记.
0x20: 为从右到左的阅读顺序布局添加标记.
0x80000000: 不遵循任何用户对系统默认日期格式的覆盖.
0x40000000: 使用系统 ANSI 代码页而不是区域设置代码页进行字符串转换.

Tn: 时间选项. 请指定 n 为下列数字的其中一个:
0: 强制使用默认选项. 这也使得会显示分钟数和秒数.
1: 省略分钟数和秒数.
2: 省略秒数.
4: 省略时间标记 (例如 AM/PM).
8: 始终使用二十四小时制而不是十二小时制.
12: 上面两个参数的组合.
0x80000000: 不遵循任何用户对系统默认时间格式的覆盖.
0x40000000: 使用系统 ANSI 代码页而不是区域设置代码页进行字符串转换.

Note：Dn 和 Tn 可以使用多次以使多个选项生效，例如：FormatTime, OutputVar, 20040228 D2 D4 T1 T8

备注

从 Format 到 OutputVar 的转换时，您希望原义转换的字母和数字必须包含在单引号中，例如：'Date:' MM/dd/yy 'Time:' hh:mm:ss tt。

与之相比, 非字母数字字符 (例如空格, tab, 换行符 (`n), 斜杠, 冒号, 逗号和其他标点) 不需要包围在单引号中. 例外情况是单引号字符本身: 要产生原义的单引号, 请使用四个连续的单引号 (''''), 不过如果它们已经包含在一对外部引号中则仅使用连续的两个就行了.

如果 Format 同时包含日期和时间元素, 则它们不能混用. 换句话说, 这个字符串应该分成两半: 一半时间, 一半日期. 例如, 包含 "hh yyyy mm" 的格式字符串不会产生期望的结果, 因为它在两个时间元素间包含日期元素.

当Format包含数值的天数（d或dd）后跟着月份的全称（MMMM），则使用月份名称的所有格形式（如果当前语言有所有格形式）。

如果 Format 包含超过 2000 个字符, 则 OutputVar 会被置空.

相关提示, 使用 EnvAdd 和 EnvSub 可以对日期和时间进行加减.

相关

要进行反向的转换 (即 从 格式化的日期/时间 转到 YYYYMMDDHH24MISS 格式), 请参阅 www.autohotkey.com/forum/topic20405.html

另请参阅: Gui DateTime 控件, SetFormat, Transform, 内置的日期和时间变量, FileGetTime

示例

FormatTime, TimeString
MsgBox The current time and date (time first) is %TimeString%.

FormatTime, TimeString, R
MsgBox The current time and date (date first) is %TimeString%.

FormatTime, TimeString,, Time
MsgBox The current time is %TimeString%.

FormatTime, TimeString, T12, Time
MsgBox The current 24-hour time is %TimeString%.

FormatTime, TimeString,, LongDate
MsgBox The current date (long format) is %TimeString%.

FormatTime, TimeString, 20050423220133, dddd MMMM d, yyyy hh:mm:ss tt
MsgBox The specified date and time, when formatted, is %TimeString%.

FormatTime, TimeString, 200504, 'Month Name': MMMM`n'Day Name': dddd
MsgBox %TimeString%

FormatTime, YearWeek, 20050101, YWeek
MsgBox January 1st of 2005 is in the following ISO year and week number: %YearWeek%
; 改变文件的日期-时间戳:
FileSelectFile, FileName, 3,, Pick a file
if FileName =  ; 用户没有选取文件.
    return
FileGetTime, FileTime, %FileName%
FormatTime, FileTime, %FileTime%   ; 由于省略了最后一个参数, 所以获取长日期和时间.
MsgBox The selected file was last modified at %FileTime%.
; 下面的函数把指定的秒数转换成相应的
; 小时数, 分钟数和秒数 (hh:mm:ss 格式).

MsgBox % FormatSeconds(7384)  ; 7384 = 2 小时 + 3 分钟 + 4 秒. 它的结果: 2:03:04

FormatSeconds(NumberOfSeconds)  ; 把指定的秒数转换成 hh:mm:ss 格式.
{
    time = 19990101  ; 任意日期的 *午夜*.
    time += %NumberOfSeconds%, seconds
    FormatTime, mmss, %time%, mm:ss
    return NumberOfSeconds//3600 ":" mmss
    /*
    ; 和上面方法不同的是，这里不支持超过 24 小时的秒数：
    FormatTime, hmmss, %time%, h:mm:ss
    return hmmss
    */
}


SetEnv

SetEnv (Var = Value)

把指定的值赋给变量。

SetEnv, Var, Value
Var = Value

参数

Var

用来保存 Value 的 变量 名.

值

要保存的字符串或数字. 如果字符串较长, 可以通过 延续片段 的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

备注

默认情况下, 把 Value 赋值给 Var 时忽略其中的前导和尾随空格或 tab. 要避免这种情况, 请使用 AutoTrim Off 中描述的方法.

“SetEnv”名称容易让人误解，是来自 AutoIt v2 的遗留物。与 AutoIt v2 不同, AutoHotkey 没有把它的变量保存在系统环境中. 这是由于性能会变差且操作系统限制环境变量大小在 32 KB 之内. 使用 EnvSet 而不是 SetEnv 来设置 环境变量.

通过赋值为空可以释放大变量占用的内存，例如 Var =。

这个命令以及其他任何接受 OutputVar 参数的命令都可以创建伪数组。这可以通过让 OuputVar 包含到另一个变量的引用来实现，例如 array%i% = 123。请参阅数组了解更多细节。

相关

AutoTrim, EnvSet, EnvAdd, EnvSub, EnvMult, EnvDiv, If, 数组

示例

Var1 = This is a string.
Color2 = 450
Color3 = %Var1%
Array%i% = %A_TICKCOUNT%


Sort

以字母、数字或随机顺序排列变量的内容（可以选择是否移除重复项）。

Sort, VarName [, Options]

参数

VarName

内容需要排序的变量名.

选项

请参阅后面的列表.

选项

由零个或多个下列字母组成的字符串 (可任意顺序, 字母间可以用空格分隔):

C: 区分大小写的排序 (如果同时存在 N 选项则此选项被忽略). 如果同时省略 C 和 CL, 则在排序中大写字母 A-Z 被视为等同于它们相应的小写形式.

CL [v1.0.43.03+]: 基于当前用户区域设置的不区分大小写的排序. 例如, 大多数英语和西欧地区把字母 A-Z 和 ANSI 字母例如 Ä 和 Ü 等同于它们的小写形式. 这种方法也使用 "单词排序", 它把单词中的连字符和撇号例如 "coop" 和 "co-op" 保持在一起. 根据需要排序的内容, 它的执行性能比默认的不区分方法差了 1 到 8 倍.

Dx：指定 x 作为分隔符，它决定了 VarName 中每个项目的开始和结束。如果此选项不存在, 则 x 默认为换行符 (`n), 这样当 VarName 中每行以 LF (`n) 或 CR+LF (`r`n) 结尾时都可以正确排序.

F MyFunction [v1.0.47+]: 根据 MyFunction 中的标准进行自定义排序 (然而这样的排序需要更长的时间). 指定字母 "F" 后跟着可选的空格/tab, 然后是可以对列表中的任意两项进行比较的 函数 名. 此函数必须接受两个或三个参数. 当函数判断出首个参数大于第二个时, 它应该返回正整数; 当判断出两个参数相等时, 应该返回 0, "" 或不返回; 否则它应该返回负整数. 如果返回值中包含小数部分, 则这部分被忽略 (即 0.8 等同于 0). 如果含有第三个参数, 则它接受原始/未排序列表中第二个项目相对于第一个的偏移 (字符数) (请参阅示例). 最后, 此函数使用和调用它的 Sort 命令相同的全局设置 (例如 StringCaseSense).

注: F 选项会使得除 D, Z 和 U 外的选项被忽略 (尽管如此, 但 N, C 和 CL 仍会影响对于 重复项 的检测). 并且, 当指定的函数出现下列情况时不会进行排序: 1) 函数不存在; 2) 接受的参数个数少于两个; 或 3) 第一或第二个参数为 ByRef 类型.

N: 数值排序: 把每个项目看成数字而不是字符串进行排序 (例如, 如果此选项不存在, 则根据字母顺序字符串 233 被认为小于字符串 40). 十进制和十六进制字符串 (例如 0xF1) 都被认为是数字. 不是以数字开头的字符串在排序中被看成是零. 把数字作为64位浮点值进行处理，这样可以考虑到小数部分的每位数字（如果有）。

Pn: 根据第 n 个位置的字符进行排序 (n 不能为十六进制数). 如果此选项不存在, 则 n 默认为 1, 这是首个字符的位置. 在字符串间排序比较时从它们的第 n 个字符开始. 如果 n 大于某个字符串的长度, 则在排序中此字符串被看成是空的. 和选项 N (数值排序) 一起使用时, 此时使用字符串的字符位置, 它不一定和数字位的位置相同.

R: 逆向排序 (根据其他选项进行字母或数字排序).

Random: 随机排序. 此选项会使得除 D, Z 和 U 外的其他选项被忽略 (尽管如此, 但 N, C 和 CL 仍会影响对于重复项的检测). 示例:

Sort, MyVar, Random
Sort, MyVar, Random Z D|

U: 移除列表中的重复项使得每个项都是唯一的. ErrorLevel 被设置为移除的项目数 (如果没有则为 0). 如果存在 C 选项, 则项目的大小写必须匹配才被看成是等同的. 如果存在 N, 那么像 2 这样的项目会被看成是 2.0 的副本. 如果存在 Pn 或 \（反斜线）的其中一个选项，则整个项目必须相同才看成是重复项，而不仅是用于排序的子字符串。如果存在 Random 或 F Function 选项, 则仅删除排序结果中彼此相邻的重复项 (说明:这句中"F Function"在原英文帮助中中间的不是空格而是斜杠,我觉得可能是错误). 例如, 对 "A|B|A" 进行随机排序, 结果中可能包含一个或两个 A.

Z: 要理解此选项, 请考虑内容为 RED`nGREEN`nBLUE`n 的变量. 如果不存在 Z, 则最后的换行符 (`n) 会被认为是最后那个项目的一部分, 因此变量中只有三个项目. 但如果指定了选项 Z，则最后的 `n（如果存在）将被认为分隔了列表最后的一个空项目，因此变量中有四个项目（最后一个是空的）。

\: 根据每个项目中最后的反斜线后面的子字符串进行排序. 如果项目中不含有反斜线, 则使用整个项目作为排序的子字符串. 此选项可用于排序单独的文件名称 (即不包含路径), 例如在下面的例子中, 排序后 AAA.txt 行在 BBB.txt 行的上面, 因为在排序中它们的目录被忽略了:

C:\BBB\AAA.txt
C:\AAA\BBB.txt

注: 当反斜线选项存在时, N 和 P 选项被忽略.

备注

此命令常用于排序包含行列表的变量, 其中每行以换行符 (`n) 结尾. 获取含有行列表的变量的一种方法是使用 FileRead 装载整个文件.

如果 VarName 为 Clipboard 且剪贴板中包含文件 (例如从打开的资源管理器窗口中复制的文件), 那么这些文件将被它们文件名排序后的列表覆盖. 换句话说, 操作后剪贴板将不再包含文件本身.

仅当存在 U 选项时此命令才会改变 ErrorLevel.

可以使用 #MaxMem 增加变量所的最大内存空间.

对占用大内存的变量进行排序后当它的内容不再需要时，您可以清空它来释放占用的内存，例如 MyVar =。

相关

FileRead, 文件读取循环, 解析循环, StringSplit, RegisterCallback(), 剪贴板, #MaxMem

示例

MyVar = 5,3,7,9,1,13,999,-4
Sort MyVar, N D,  ; 数值排序, 使用逗号作为分隔符.
MsgBox %MyVar%   ; 结果是 -4,1,3,5,7,9,13,999

; 下面的例子对文件的内容进行排序:
FileRead, Contents, C:\Address List.txt
if not ErrorLevel  ; 装载成功.
{
    Sort, Contents
    FileDelete, C:\Address List (alphabetical).txt
    FileAppend, %Contents%, C:\Address List (alphabetical).txt
    Contents =  ; 释放内存.
}

; 下面的例子设置 Win+C 热键来从打开的资源管理器窗口中
; 复制文件, 对其中的文件名进行排序后放回剪贴板:
#c::
Clipboard = ; 必须为空以检测是否有效.
Send ^c
ClipWait 2
if ErrorLevel
    return
Sort Clipboard
MsgBox Ready to be pasted:`n%Clipboard%
return

; 下面的例子演示了通过回调函数进行自定义排序.
MyVar = def`nabc`nmno`nFGH`nco-op`ncoop`ncop`ncon`n
Sort, MyVar, F StringSort
StringSort(a1, a2)
{
    return a1 > a2 ? 1 : a1 < a2 ? -1 : 0  ; 基于 StringCaseSense 的设置按字母顺序进行排序.
}

MyVar = 5,3,7,9,1,13,999,-4
Sort, MyVar, F IntegerSort D,
IntegerSort(a1, a2)
{
    return a1 - a2  ; 按上升的数值顺序进行排序.  此方法只有在两个数字的差不会超出 64 位有符号整数的范围才有效.
}

MyVar = 1,2,3,4
Sort, MyVar, F ReverseDirection D,  ; 反转列表, 这样它包含了 4,3,2,1
ReverseDirection(a1, a2, offset)
{
    return offset  ; 如果原始列表中 a2 在 a1 的后面则偏移是正数; 否则为负数.
}


StringCaseSense

设置在字符串比较中是否区分大小写（默认为“不区分大小写”）。

StringCaseSense, On|Off|Locale

参数

On|Off|Locale

On: 字符串比较时区分大小写. 此设置也让 表达式等号运算符 (=) 和 InStr() 的不区分大小写模式使用下面的 locale 方式进行处理.

Off (初始默认值): 字母 A-Z 被视为等同于它们的小写副本. 为了向后兼容和保持高效, 这是所有脚本的初始默认值 (根据被比较字符串的性质, 使用 Locale 比 Off 慢 1 到 8 倍).

Locale [v1.0.43.03+]: 字符串比较 不 区分大小写, 且遵循当前用户区域设置. 例如, 在大多数英语及西欧地区, 不仅将 A-Z 视为等同于它们的小写形式, 同时也视为等同于它们的 ANSI 字母, 例如 Ä 和 Ü.

备注

此设置适用于:

  • 表达式比较运算符 (除了 ==). 但是, 由于 等号运算符 (=) 总是不区分大小写, 当 StringCaseSense 设置为 On 时它使用 Locale 模式, 与 InStr() 的不区分大小写模式相同.
  • IfInString, StringGetPos 和 InStr(). 然而, InStr() 在其 CaseSensitive 参数为 true 不会受此设置影响.
  • StringReplace
  • if var in/contains MatchList, if var between 和 IfEqual 及其系列.
  • [AHK_L 42+]: if var is [not] type 仅在 Locale 模式生效时才遵循系统区域设置.

内置变量 A_StringCaseSense 包含了当前设置 (单词 On, Off 或 Locale).

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

IfEqual, IfInString, if var between, StringReplace, StringGetPos

示例

StringCaseSense Locale


StringGetPos

获取指定的子字符串在某个字符串中的位置。

StringGetPos, OutputVar, InputVar, SearchText [, L#|R#, Offset]
Position := InStr(Haystack, Needle [, CaseSensitive?, StartingPos]) ; 请参阅 InStr() 函数 了解详情.

参数

OutputVar

用来存储获取的相对于 InputVar 首个字符的位置的变量名. StringGetPos 中首个字符的位置为 0, 而 InStr() 中首个字符的位置为 1.

InputVar

内容将被搜索的输入变量名. 不要把名称括在百分号中, 除非您希望使用变量的 内容 作为被解析的变量名.

SearchText

要搜索的字符串. 如果没有启用 StringCaseSense, 那么匹配过程不区分大小写.

L#|R#

当 SearchText 在 InputVar 中出现多次时, 此参数决定找到哪个. 如果省略此参数, 那么会从 InputVar 左边开始查找, 直到找到首个匹配. 如果此参数为 1 或字母 R, 那么将从 InputVar 的右边往左开始查找, 直到找到首个匹配.

要查找非首个匹配, 请在字母 L 或 R 后面指定出现位置的编号. 例如, 要找到从右边开始的第四个匹配, 请指定 r4. 注意: 如果编号小于或等于零, 将找不到匹配.

Offset

最左边或最右边 (取决于上面的参数) 需要跳过的字符数. 省略时默认为 0. 例如，后面的语句会从左边的第十个字符开始查找：StringGetPos, OutputVar, InputVar, abc, , 9。此参数可以为 表达式.

ErrorLevel

在 InputVar 中的指定位置没有找到 SearchText 时 ErrorLevel 被置为 1，否则为 0。

备注

与 StringMid 和 InStr() 不同, StringGetPos 中首个字符的位置为 0.

获取的位置总是相对于 InputVar 的首个字符, 不受 L#|R# 和/或 Offset 的值影响. 例如, 如果在 123abc789 中查找 "abc", 那么获取的位置总为 3, 而不论查找的参数如何.

如果 SearchText 不存在于 InputVar 中的指定出现位置, 那么 OutputVar 将被置为 -1 且 ErrorLevel 被置为 1.

使用 SplitPath 可以更容易地将文件路径分解为目录, 文件名和扩展名.

内置变量 %A_Space% 和 %A_Tab% 分别包含了单个空格和单个 tab 字符. 当您需要搜索单独的空格或 tab 或在 SearchText 的开始或末尾含有空格或 tab 时, 这很有用.

相关

InStr(), RegExMatch(), IfInString, if var in/contains MatchList, StringCaseSense, StringReplace, SplitPath, StringLeft, StringRight, StringMid, StringTrimLeft, StringTrimRight, StringLen, StringLower, StringUpper, if var is type

示例

Haystack = abcdefghijklmnopqrs
Needle = def
StringGetPos, pos, Haystack, %Needle%
if pos >= 0
    MsgBox, The string was found at position %pos%.

; 示例 #2:
; 把文件的完整路径名分解成各个部分.
; 请注意使用 StringSplit 或
; 解析循环 会更容易, 这里只是为了演示.
FileSelectFile, file, , , Pick a filename in a deeply nested folder:
if file <>
{
    StringLen, pos_prev, file
    pos_prev += 1 ; 改变位置到最后一个字符的后面.
    循环
    {
        ; 从右边开始查找第 N 个匹配:
        StringGetPos, pos, file, \, R%A_Index%
        if ErrorLevel
            break
        length := pos_prev - pos - 1
        pos_prev := pos
        pos += 2  ; 进行调整以便使用 StringMid.
        StringMid, path_component, file, %pos%, %length%
        MsgBox Path component #%a_index% (from the right) is:`n%path_component%
    }
}


StringLeft / StringRight

从字符串的左边或右边提取一些字符.

StringLeft, OutputVar, InputVar, Count
StringRight, OutputVar, InputVar, Count
NewStr := SubStr(String, StartPos [, Length]) ; 请参阅 SubStr() 函数 了解详情.

参数

OutputVar

用来存储从 InputVar 提取的子字符串的变量名.

InputVar

需要被提取的变量名. 不要把名称括在百分号中, 除非您希望使用变量的 内容 作为被解析的变量名.

Count

需提取的字符数, 可以为 表达式. 如果 Count 小于或等于零, 那么 OutputVar 会被置空. 如果 Count 超过了 InputVar 的长度, 那么 OutputVar 会被置为 InputVar 的完整内容.

备注

在这个及其他所有命令中，OutputVar 和 InputVar 中可以使用相同的变量。

相关

SubStr(), StringMid, StringTrimLeft, StringTrimRight, IfInString, StringGetPos, StringLen, StringLower, StringUpper, StringReplace

示例

String = This is a test.
StringLeft, OutputVar, String, 4  ; 保存字符串 "This" 到 OutputVar.
StringRight, OutputVar, String, 5  ; 保存字符串 "test." 到 OutputVar.


StringLower / StringUpper

把字符串中的英文字母转换成小写或大写.

StringLower, OutputVar, InputVar [, T]
StringUpper, OutputVar, InputVar [, T]

参数

OutputVar

用来存储新的转换后的字符串的变量名.

InputVar

需要被读取内容的变量名. 不要把名称括在百分号中, 除非您希望使用变量的 内容 作为被解析的变量名.

T

如果此参数为字母 T, 那么字符串会被转换为标题格式. 例如, "GONE with the WIND" 会被转换成 "Gone With The Wind".

备注

要判断字符或字符串是否全部为大写或小写字母, 请使用 "if var is [not] upper/lower".

在这个及其他所有命令中，OutputVar 和 InputVar 中可以使用相同的变量。

相关

IfInString, StringGetPos, StringMid, StringTrimLeft, StringTrimRight, StringLeft, StringRight, StringLen, StringReplace

示例

StringUpper, String1, String1  ; 即输出可以和输入相同.
StringLower, String2, String2


StringMid

从字符串的指定位置提取一个或多个字符。

StringMid, OutputVar, InputVar, StartChar [, Count , L]
NewStr := SubStr(String, StartPos [, Length]) ; 请参阅 SubStr() 函数 了解详情.

参数

OutputVar

用来存储从 InputVar 提取的子字符串的变量名.

InputVar

需要被提取子字符串的变量名. 不要把名称括在百分号中, 除非您希望使用变量的 内容 作为被解析的变量名.

StartChar

需提取的首个字符的位置, 可以为 表达式. 与 StringGetPos 不同, 首个字符的位置为 1. 如果 StartChar 小于 1, 那么它将被视为 1. 如果 StartChar 超过了字符串的长度, 则 OutputVar 会被置空.

Count

在 v1.0.43.10+, 此参数可以省略或留空, 此时等同于指定了可从字符串中获取所有字符的足够大的整数.

否则, 请指定需提取的字符数, 可以为 表达式. 如果 Count 小于或等于零, 那么 OutputVar 会被置空. 如果 Count 超过了 InputVar 中从 StartChar 开始计算的长度, 那么 OutputVar 会被置为 InputVar 中从 StartChar 开始的所有字符.

L

使用字母 L 可以从 StartChar 开始往左边提取字符而不是右边. 在后面的例子中, OutputVar 会被置为 Red:

InputVar = The Red Fox
StringMid, OutputVar, InputVar, 7, 3, L

如果使用了 L 选项且 StartChar 小于 1，那么 OutputVar 会被置空。如果 StartChar 超过了 InputVar 的长度, 那么只会提取在 Count 内的那些字符. 例如, 下面的例子会把 OutputVar 设置为 Fox:

InputVar = The Red Fox
StringMid, OutputVar, InputVar, 14, 6, L

备注

在这个及其他所有命令中，OutputVar 和 InputVar 中可以使用相同的变量。

相关

SubStr(), StringLeft, StringRight, StringTrimLeft, StringTrimRight, IfInString, StringGetPos, StringLen, StringLower, StringUpper, StringReplace

示例

Source = Hello this is a test.
StringMid, the_word_this, Source, 7, 4


StringReplace

用新字符串替换指定的子字符串。

StringReplace, OutputVar, InputVar, SearchText [, ReplaceText, ReplaceAll?]

参数

OutputVar

用来存储替换后的新字符串的变量名.

InputVar

需要被读取内容的变量名. 不要把名称括在百分号中, 除非您希望使用变量的 内容 作为被解析的变量名.

SearchText

要搜索的字符串. 如果没有启用 StringCaseSense, 那么匹配过程不区分大小写.

ReplaceText

用来替换 SearchText 的文本. 如果省略或为空, 那么 SearchText 会被替换为空. 换句话说, 它会被从 OutputVar 删除.

ReplaceAll?

如果省略, 那么只替换 SearchText 的首个匹配如果此参数为 1, A 或 All, 那么替换所有匹配.

指定单词 UseErrorLevel 可以把替换的次数保存到 ErrorLevel (没有则为 0). UseErrorLevel 包含了 "All" 的作用.

ErrorLevel

最后一个参数为 UseErrorLevel 时, ErrorLevel 中会保存替换的次数 (没有则为 0). 否则，如果在 InputVar 中没有找到 SearchText 则 ErrorLevel 被置为 1，找到则置为 0。

备注

在这个及其他所有命令中，OutputVar 和 InputVar 中可以使用相同的变量。

内置变量 %A_Space% 和 %A_Tab% 分别包含了单个空格和单个 tab 字符. 当您需要搜索单独的空格或 tab 或在 SearchText 的开始或末尾含有空格或 tab 时, 这很有用.

在 v1.0.45, 为了改善性能和内存的利用率, AllSlow 选项已经作废. 尽管仍可以指定它, 但不会有效果.

相关

RegExReplace(), IfInString, StringCaseSense, StringLeft, StringRight, StringMid, StringTrimLeft, StringTrimRight, StringLen, StringLower, StringUpper, StringGetPos, if var is type

示例

; 移除剪贴板中所有的 CR+LF:
StringReplace, clipboard, clipboard, `r`n, , All

; 用加号替换所有空格:
StringReplace, NewStr, OldStr, %A_SPACE%, +, All

; 移除变量中所有空行:
Loop
{
    StringReplace, MyString, MyString, `r`n`r`n, `r`n, UseErrorLevel
    if ErrorLevel = 0  ; 不需要再进行替换.
        break
}


StringTrimLeft / StringTrimRight

从字符串的左边或右边移除一些字符.

StringTrimLeft, OutputVar, InputVar, Count
StringTrimRight, OutputVar, InputVar, Count
NewStr := SubStr(String, StartPos [, Length]) ; 请参阅 SubStr() 函数 了解详情.

参数

OutputVar

用来存储 InputVar 缩短后字符串的变量名.

InputVar

需要被读取内容的变量名. 不要把名称括在百分号中, 除非您希望使用变量的 内容 作为被解析的变量名.

Count

需移除的字符数, 可以为 表达式. 如果 Count 小于或等于零, 那么 OutputVar 会被置为与 InputVar 相同. 如果 Count 超过了 InputVar 的长度, 那么 OutputVar 会被置空.

备注

在这个及其他所有命令中，OutputVar 和 InputVar 中可以使用相同的变量。

相关

SubStr(), StringMid, StringLeft, StringRight, IfInString, StringGetPos, StringLen, StringLower, StringUpper, StringReplace

示例

String = This is a test.
StringTrimLeft, OutputVar, String, 5  ; 保存字符串 "is a test." 到 OutputVar.
StringTrimRight, OutputVar, String, 6  ; 保存字符串 "This is a" 到 OutputVar.


Trim

Trim [AHK_L 31+]

移除字符串的开始和/或末尾的某些字符.

Result :=  Trim(String, OmitChars = " `t")
Result := LTrim(String, OmitChars = " `t")
Result := RTrim(String, OmitChars = " `t")

参数

String

任何字符串值或变量. 不支持数字.

OmitChars

可选的字符列表 (区分大小写), 用来从 String 的开始和/或结尾部分移除这些字符. 如果省略, 则移除空格和 tab.

示例

text := "  text  "
MsgBox % "No trim:`t '" text "'"
    . "`nTrim:`t '" Trim(text) "'"
    . "`nLTrim:`t '" LTrim(text) "'"
    . "`nRTrim:`t '" RTrim(text) "'"
MsgBox % LTrim("00000123","0")


控件

对控件进行各种改变。

Control, Cmd [, Value, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

Cmd, Value

请参阅后面的列表.

控件

可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。如果此参数为空, 则使用目标窗口的顶层控件.

要对控件的 HWND（窗口句柄）进行操作，请将 Control 参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

Cmd, Value

Cmd 和 Value 参数互相依赖, 它们的用法描述如下.

Check: 打开 (选中) 单选框或复选框.

Uncheck: 关闭单选框或复选框.

Enable: 启用之前禁用的控件.

Disable: 禁用或 "灰化" 控件.

Show: 显示之前隐藏的控件.

Hide: 隐藏控件. 如果您还想同时禁用控件的快捷键（加下划线的字母），请使用 Control Disable 来禁用控件。

Style, N 或 ExStyle, N：分别改变控件的样式或扩展样式。如果 N 的首个字符为加号或减号, 那么会添加或移除 N 中的样式. 如果首个字符为脱字符 (^), 那么 N 中的样式会被切换到相反的状态. 如果首个字符为数字, 则控件样式会被完全覆盖为 N. 没有找到目标窗口/控件或无法应用此样式时 ErrorLevel 被设为 1。

改变某些样式后需要使用 WinSet Redraw 重绘整个窗口. 此外, 样式表 列出了一些样式编号. 例如：

Control, Style, ^0x800000, Edit1, WinTitle  ; 切换 WS_BORDER 样式到相反状态.

ShowDropDown: 拉下组合框, 使得其选项可见.

HideDropDown: 反转上面的功能.

TabLeft [, Count] 和 TabRight [, Count]: 在 SysTabControl32 中向左或向右移动一个或多个选项卡. 如果 Count 省略或为空, 则假定为 1. 要通过编号直接选择选项卡, 请把下面示例中的数字 5 替换为比您想要选择的选项卡的编号小 1 的数字. 换句话说, 使用 0 选择首个选项卡, 1 选择第二个, 依此类推.

SendMessage, 0x1330, 5,, SysTabControl321, WinTitle  ; 0x1330 为 TCM_SETCURFOCUS.
Sleep 0  ; 此行和下一行只对于某些选项卡控件才需要.
SendMessage, 0x130C, 5,, SysTabControl321, WinTitle  ; 0x130C 为 TCM_SETCURSEL.

Add, String: 把 String 作为新条目添加到列表框或组合框 (以及其他适合的类型) 的底部.

Delete, N: 删除列表框或组合框中的第 N 个条目. 对于首个条目 N 为 1, 对第二个则为 2, 等等.

Choose, N: 设置列表框或组合框中的选区为第 N 个条目. 对于首个条目 N 为 1, 对第二个则为 2, 等等. 要选择或取消选择 多选 列表框中的所有项目, 请参照此例:

PostMessage, 0x185, 1, -1, ListBox1, WinTitle  ; 选择所有项目. 0x185 为 LB_SETSEL.

ChooseString, String: 设置列表框或组合框中的选区为开始部分匹配 String 的首个条目. 搜索不区分大小写. 例如, 如果列表框/组合框包含条目 "UNIX Text", 那么指定单词 unix (小写) 也能选中它.

EditPaste, String: 在编辑控件的光标处/插入位置粘贴 String (此功能不会影响 剪贴板 的内容).

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

为了提高可靠性, 每次使用此命令后都会自动进行延迟 (不包括 Style 和 ExStyle). 这个延迟可以使用 SetControlDelay 进行改变.

要获取鼠标当前悬停的控件的 ClassNN 或 HWND，请使用 MouseGetPos。

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

SetControlDelay, ControlGet, GuiControl, ControlGetText, ControlSetText, ControlMove, ControlGetPos, ControlClick, ControlFocus, ControlSend, WinSet

示例

Control, HideDropDown, , ComboBox1, Some Window Title


ControlFocus

设置输入焦点到窗口的指定控件上。

ControlFocus [, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

控件

可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。如果此参数为空或省略, 则使用目标窗口的顶层控件.

要对控件的 HWND（窗口句柄）进行操作，请将 Control 参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

要让设置生效, 控件所在的窗口一般不能处于最小化或隐藏状态.

要提高可靠性, 每次使用此命令后都会自动进行延迟. 这个延迟可以使用 SetControlDelay 进行改变.

要获取鼠标当前悬停的控件的 ClassNN 或 HWND，请使用 MouseGetPos。

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

SetControlDelay, ControlGetFocus, Control, ControlGet, ControlMove, ControlGetPos, ControlClick, ControlGetText, ControlSetText, ControlSend

示例

ControlFocus, OK, Some Window Title  ; 设置焦点到 OK 按钮上


ControlGet

获取控件的各种类型的信息。

ControlGet, OutputVar, Cmd [, Value, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

OutputVar

用来保存 Cmd 结果的变量名.

Cmd, Value
请参阅后面的列表.
控件

可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。如果此参数为空, 则使用目标窗口的顶层控件.

要对控件的 HWND（窗口句柄）进行操作，请将 Control 参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

Cmd, Value

Cmd 和 Value 参数互相依赖, 它们的用法描述如下.

List: 从列表视图, 列表框, 组合框或下拉列表中获取条目列表.

ListView：从列表视图中获取条目列表的方法是：

ControlGet, OutputVar, List, Options, SysListView321, WinTitle, WinText

如果 Options 为空或省略, 则获取控件中所有文本. 除最后一行外的其他行都以换行符 (`n) 结尾. 在每行中, 除最后一个字段外的其他字段 (列) 都以 tab 字符 (`t) 结尾.

在 Options 指定零个或多个下列单词, 单词间使用空格或 tab 分隔:

Selected: 仅获取选择 (高亮) 行而不是所有行. 如果没有, 则 OutputVar 被置空.
Focused: 仅获取焦点行. 如果没有, 则 OutputVar 被置空.
Col4: 仅获取第四列 (字段) 而不是所有列 (把 4 替换为您选择的数字).
Count: 获取控件中总行数 (单个数字表示).
Count Selected: 获取选择 (高亮) 的行数.
Count Focused: 获取焦点行的行号 (位置) (如果没有焦点行则为 0).
Count Col: 获取控件的列数 (如果列的总是无法确定则为 -1).

注意: 某些应用程序秘密地保存它们列表视图中的文本, 这样阻止了这些文本被获取. 在这种情况下, ErrorLevel 通常被置为 0 (表示成功) 但获取的所有字段都是空的. 还有注意的是列表视图的文本是不受 #MaxMem 限制的.

如果获取成功, 则 ErrorLevel 被置为 0. 如果失败, 则它被置为 1 且 OutputVar 被置空. 引起失败的原因有：1) 目标窗口或控件不存在；2) 目标控件不是 SysListView32 类型；3) 无法打开拥有列表视图的进程，可能由于缺少用户权限或被锁定了；4) ColNN option 指定的列不存在。

要从列表视图中逐个提取每行和每个字段, 请使用 解析循环, 例如:

ControlGet, List, List, Selected, SysListView321, WinTitle
Loop, Parse, List, `n  ; 行之间由换行符 (`n) 分隔.
{
    RowNumber := A_Index
    Loop, Parse, A_LoopField, %A_Tab%  ; 每行中的字段 (列) 之间由 tab (A_Tab) 分隔.
        MsgBox Row #%RowNumber% Col #%A_Index% is %A_LoopField%.
}

相关提示, 列表视图中的列可以使用 SendMessage 来调整大小, 如下所示:

SendMessage, 4126, 0, 80, SysListView321, WinTitle  ; 4126 为消息 LVM_SETCOLUMNWIDTH.
; 在上面的语句中, 0 表示首列 (1 表示第二列, 2 表示第三列, 等等.)  此外, 80 是新宽度.
; 把 80 替换为 -1 来自动调整列的大小. 替换为 -2 来实现相同的功能, 并且调整标题文本的宽度.

ListBox、ComboBox、DropDownList：获取控件中所有的文本（即不支持上面的列表视图选项，例如Count和Selected）。

除最后一行外的其他行都以换行符 (`n) 结束. 要逐个访问每个项目, 请使用 解析循环, 例如:

ControlGet, List, List,, ComboBox1, WinTitle
Loop, Parse, List, `n
    MsgBox Item number %A_Index% is %A_LoopField%.

Checked: 如果复选框或单选框被选中, 则设置 OutputVar 为 1; 否则为 0.

Enabled: 如果 Control 处于启用状态, 则设置 OutputVar 为 1; 禁用则为 0.

Visible: 如果 Control 是可见的, 则设置 OutputVar 为 1; 否则为 0.

Tab: 设置 OutputVar 为 SysTabControl32 控件的选项卡编号. 首个选项卡为 1, 第二个为 2, 等等. 要获取选项卡控件中含有的选项卡 (页) 数目, 请参照此例:

SendMessage, 0x1304,,, SysTabControl321, WinTitle  ; 0x1304 为 TCM_GETITEMCOUNT.
TabCount = %ErrorLevel%

FindString, String: 设置 OutputVar 为列表框或组合框中准确匹配 String 的条目编号. 控件中首个条目为 1, 第二个为 2, 依此类推. 如果没有找到匹配, 则 OutputVar 被置空且 ErrorLevel 被设置为 1.

Choice：设置OutputVar列表框或组合框中当前选择的条目名称。要获取所选条目的位置, 请参照此例 (只需使用下面开始两行中的其中一行):

SendMessage, 0x188, 0, 0, ListBox1, WinTitle  ; 0x188 为 LB_GETCURSEL (对于列表框).
SendMessage, 0x147, 0, 0, ComboBox1, WinTitle  ; 0x147 为 CB_GETCURSEL (对于下拉列表或组合框).
ChoicePos = %ErrorLevel%  ; 如果没有选中的条目, 那么它会为 -1.
ChoicePos += 1  ; 从基于 0 转换到基于 1, 这样首个条目被称为 1, 而不是 0.

LineCount: 设置 OutputVar 为编辑控件中的行数. 所有的编辑控件至少含有一行, 即使控件是空的.

CurrentLine: 设置 OutputVar 为编辑控件光标处 (插入点) 所在的行号. 首行为 1. 如果控件中选择了文本, 则 OutputVar 被设置为选区开始处所在的行号.

CurrentCol: 设置 OutputVar 为编辑控件光标处 (文本插入点) 所在的列号. 首列为 1. 如果控件中选择了文本, 则 OutputVar 被设置为选区开始处所在的列号.

Line, N: 设置 OutputVar 为编辑控件中行 N 的文本. 行 1 为首行. 根据控件的性质, OutputVar 可能以回车符 (`r) 或换车和换行符 (`r`n) 结束. 如果指定的行号没有内容或不存在, 则 ErrorLevel 被置为 1 且 OutputVar 被置空.

Selected: 设置 OutputVar 为编辑控件中选择的文本. 如果没有选择的文本, 则 OutputVar 会被置空且 ErrorLevel 被设置为 0 (即没有错误). 某些类型的控件, 例如 RichEdit20A, 在某些情况下可能无法获取到正确的文本 (例如 Metapad).

Style: 获取表示控件样式的 8 位十六进制数. 请参阅样式表了解一些样式。

ExStyle: 获取表示控件扩展样式的 8 位十六进制数.

Hwnd [v1.0.43.06+]: 获取指定控件的窗口句柄 (HWND). 例如：ControlGet, OutputVar, Hwnd,, Edit1, WinTitle。控件的 HWND 常用于 PostMessage, SendMessage 和 DllCall. 相关提示, 还可以使用 MouseGetPos 获取控件的 HWND. 最后, 控件的 HWND 可以直接用在 ahk_id WinTitle 中 (即使 DetectHiddenWindows 设置关闭时, 这样对于隐藏控件也是有效的).

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

成功时, ErrorLevel 被置为 0. 如果遇到问题, 例如窗口或控件不存在, 则 ErrorLevel 被置为 1 且 OutputVar 被置空.

备注

和其他改变控件的命令不同, ControlGet 后没有自动的延时; 即, SetControlDelay 不会影响它.

要获取鼠标当前悬停的控件的 ClassNN 或 HWND，请使用 MouseGetPos。要获取窗口中控件列表, 请使用 WinGet ControlList.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

Control, GuiControlGet, ControlMove, ControlGetText, ControlSetText, ControlGetPos, ControlClick, ControlFocus, ControlSend, WinGet

示例

ControlGet, OutputVar, Line, 1, Edit1, Some Window Title

ControlGet, WhichTab, Tab, , SysTabControl321, Some Window Title
if ErrorLevel
    MsgBox There was a problem.
else
    MsgBox Tab #%WhichTab% is active.


ControlGetFocus

如果有，则获取目标窗口中含输入焦点的控件。

ControlGetFocus, OutputVar [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

OutputVar

用来保存控件标识符的变量名, 控件标识符由控件的类名以及在父窗口中的序列编号组成, 例如 Button12.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果成功获取含输入焦点的控件, 则 ErrorLevel 被置为 0. 否则 (例如目标窗口不存在或它所有的控件都不含输入焦点) 被置为 1.

备注

此命令获取的控件是含键盘焦点的那个, 即在用户输入时会接收到键击的那个.

目标窗口必须是活动的, 才能含有焦点控件. 如果窗口不是活动的, 则 OutputVar 被置为空.

如果以很高的频率 (即每 500 ms 或更快) 重复执行 ControlGetFocus, 那么可能会干扰用户双击鼠标. 一种解决方法是通过 DllCall 调用操作系统的 GetGUIThreadInfo(). 例如：

; 此脚本获取活动窗口焦点控件的 ahk_id（HWND）。
GuiThreadInfoSize = 48
VarSetCapacity(GuiThreadInfo, GuiThreadInfoSize)
NumPut(GuiThreadInfoSize, GuiThreadInfo, 0)
if not DllCall("GetGUIThreadInfo", uint, 0, str, GuiThreadInfo)
{
    MsgBox GetGUIThreadInfo() indicated a failure.
    return
}
FocusedHWND := NumGet(GuiThreadInfo, 12)  ; 从结构中获取 hwndFocus 字段.
MsgBox % "The focused control's ahk_id (HWND) is " . FocusedHWND
; 此 ID 可以用在所有的控件命令中.  例如:
; ControlGetText, OutputVar,, ahk_id %FocusedHWND%

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

ControlFocus, ControlMove, ControlClick, ControlGetText, ControlSetText, ControlSend

示例

ControlGetFocus, OutputVar, Untitled - Notepad
if ErrorLevel
    MsgBox, The target window doesn't exist or none of its controls has input focus.
else
    MsgBox, Control with focus = %OutputVar%


ControlGetPos

获取控件的位置和大小。

ControlGetPos [, X, Y, Width, Height, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

X, Y

用来保存 Control 左上角的 X 和 Y 坐标 (单位为像素) 的变量名. 这些坐标相对于目标窗口的左上角, 因此它们和 ControlMove 中使用的坐标是一样的.

如果省略 X 或 Y 的其中一个, 则相应的值会被丢弃.

Width/Height

用来储存 Control 宽度和高度 (单位为像素) 的变量名. 如果省略, 则丢弃相应的数据.

控件

可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。如果此参数为空, 则使用目标窗口的顶层控件.

要对控件的 HWND（窗口句柄）进行操作，请将 Control 参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

如果没有找到匹配窗口或控件, 则输出变量会被置空.

和其他改变控件的命令不同, ControlGetPos 后没有自动的延时 (SetControlDelay 不会影响它).

要获取鼠标当前悬停的控件的 ClassNN 或 HWND，请使用 MouseGetPos。要获取窗口中所有控件的列表, 请使用 WinGet.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

ControlMove, WinGetPos, Control, ControlGet, ControlGetText, ControlSetText, ControlClick, ControlFocus, ControlSend

示例

; 这个可运行示例会持续地更新和显示
; 鼠标光标下的当前控件的名称和位置:
Loop
{
    Sleep, 100
    MouseGetPos, , , WhichWindow, WhichControl
    ControlGetPos, x, y, w, h, %WhichControl%, ahk_id %WhichWindow%
    ToolTip, %WhichControl%`nX%X%`tY%Y%`nW%W%`t%H%
}


ControlGetText

获取控件的文本。

ControlGetText, OutputVar [, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

OutputVar

用来存储获取的文本的变量名.

控件

可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。如果此参数为空或省略, 则使用目标窗口的顶层控件.

要对控件的 HWND（窗口句柄）进行操作，请将 Control 参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

注意: 要获取列表视图, 列表框或组合框的文本, 请使用 ControlGet List.

如果获取的文本看起来像被截短了（不完整），请在 ControlGetText 前尝试使用 VarSetCapacity(OutputVar, 55) [把 55 替换为超过截短文本许多的大小]。在一些应用程序不能正确响应 WM_GETTEXTLENGTH 消息时需要这样, 否则会导致 AutoHotkey 把输出变量设的过小以致无法保存所有的文本.

可获取的最多文本数限制于变量的最大容量 (这可以通过 #MaxMem 指令改变). 因此，如果目标控件（例如打开了大文档的编辑器）包含大量文本，那么此命令可能会使用大量的内存。不过，在使用后可以为变量赋值为空来释放它占用的内存，即 OutputVar =。

从大多数控件类型获取的文本使用回车和换行符 (`r`n) 而不是单独的换行符 (`n) 来表示每行的结尾.

执行 SetTitleMatchMode Slow 是不需要的，因为 ControlGetText 总是使用慢速模式获取文本（这样它可以工作于更大范围的控件类型）。

要获取窗口中所有控件的列表, 请使用 WinGet ControlList.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

ControlSetText, WinGetText, Control, ControlGet, ControlMove, ControlFocus, ControlClick, ControlSend, #MaxMem

示例

ControlGetText, OutputVar, Edit1, Untitled -


ControlMove

移动控件或调整其大小。

ControlMove, Control, X, Y, Width, Height [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

控件

可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。如果此参数为空, 则使用目标窗口的顶层控件.

要对控件的 HWND（窗口句柄）进行操作，请将 Control 参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

X, Y

Control 新位置的左上角的 X 和 Y 坐标 (单位为像素), 可以为 表达式. 如果其中一个坐标为空, 那么 Control 在这个维度中的位置将保持不变. 这里的坐标相对于 Control 父窗口的左上角; 可以使用 ControlGetPos 或 Window Spy 来确定它们.

Width, Height

Control 的新宽度和高度 (单位为像素), 可以为 表达式. 如果其中一个参数为空或省略, 那么 Control 在这个维度中的大小将保持不变.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

要提高可靠性, 每次使用此命令后都会自动进行延迟. 这个延迟可以使用 SetControlDelay 进行改变.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

ControlGetPos, WinMove, SetControlDelay, Control, ControlGet, ControlGetText, ControlSetText, ControlClick, ControlFocus, ControlSend

示例

SetTimer, ControlMoveTimer
InputBox, OutputVar, My Input Box
return

ControlMoveTimer:
IfWinNotExist, My Input Box
    return
; 否则上面设置了 "上次找到的" 窗口:
SetTimer, ControlMoveTimer, off
WinActivate
ControlMove, OK, 10, , 200  ; 将 OK 按钮移动到左边并增加其宽度.
return


ControlSetText

改变控件的文本。

ControlSetText [, Control, NewText, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

控件

可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。如果此参数为空, 则使用目标窗口的顶层控件.

要对控件的 HWND（窗口句柄）进行操作，请将 Control 参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

NewText

为控件设置的新文本. 如果为空或省略, 则控件的文本被设置为空.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

大多数控件类型使用回车和换行符 (`r`n) 而不是单独的回车符 (`n) 来表示每行的结尾. 要转换包含 `n 字符的文本块，请参照此例：

StringReplace, MyVar, MyVar, `n, `r`n, All

要提高可靠性, 每次使用此命令后都会自动进行延迟. 这个延迟可以使用 SetControlDelay 进行改变.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

SetControlDelay, ControlGetFocus, ControlGetText, ControlGet, Control, ControlMove, ControlGetPos, ControlClick, ControlFocus, ControlSend

示例

ControlSetText, Edit1, New Text Here, Untitled -


PostMessage / SendMessage

发送消息到窗口或控件（SendMessage 还会等待回复）。

PostMessage, Msg [, wParam, lParam, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
SendMessage, Msg [, wParam, lParam, Control, WinTitle, WinText, ExcludeTitle, ExcludeText, Timeout]

参数

Msg

要发送的消息号, 可以为 表达式. 请参阅 消息列表 来确定编号.

wParam

消息的第一个组件, 可以为 表达式. 如果为空或省略, 则会被设置为 0.

lParam

消息的第二个组件, 可以为 表达式. 如果为空或省略, 则会被设置为 0.

控件

如果此参数为空或省略, 则消息会被直接发送到目标窗口而不是它的某个控件. 或者此参数可以是 ClassNN（控件的类名和实例编号）或控件的文本，它们都可以通过 Window Spy 获取。使用文本时，匹配行为由 SetTitleMatchMode 决定。

要对控件的 HWND（窗口句柄）进行操作，请将 Control 参数留空同时在 WinTitle 参数中指定 ahk_id %ControlHwnd%（即使在 DetectHiddenWindows 设置关闭时，这样也可以操作隐藏控件）。获取控件的 HWND 的一般方法是使用 ControlGet Hwnd, MouseGetPos 或 DllCall.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

超时

[AHK_L 42+]：等待目标窗口处理消息的最大毫秒数。如果省略，则默认为 5000 （毫秒），这同时也是不支持此参数的 AutoHotkey 旧版本的默认行为。如果在这时间内消息没有被处理, 则命令结束并设置 ErrorLevel 为单词 FAIL. 此参数可以为 表达式.

ErrorLevel

[v1.1.04+] 这两个命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

PostMessage: 如果遇到问题 (例如目标窗口或控件不存在) 则 ErrorLevel 被置为 1. 否则被置为 0.

SendMessage：如果遇到问题或命令超时，则 ErrorLevel 被设置为单词 FAIL。否则, 它被设置为此消息的数值结果, 这有时可能是由消息的性质和目标窗口决定的 "回复". 这个结果是介于 0 和 4294967295 之间的整数. 如果结果应该为有符号整数，请参照这个例子转换为负数：

MsgReply := ErrorLevel > 0x7FFFFFFF ? -(~ErrorLevel) - 1 : ErrorLevel

备注

应该小心使用这些命令, 因为发送消息到错误的窗口 (或发送错误的消息) 可能导致意外的行为或者甚至让目标应用程序崩溃. 这是因为大多数应用程序在设计时不会考虑到从外部来源中接受某些类型的消息.

PostMessage 把消息放置到和目标窗口关联的消息队列中. 它不会等待答复或回应. 与之相比，SendMessage 在到达超时时间前会等待目标窗口处理消息。

参数 Msg, wParam 和 lParam 都应该是介于 -2147483648 和 4294967295 (0xFFFFFFFF) 之间的整数. 和 AutoHotkey 中的所有整数值相同, 可以加上 0x 前缀表示十六进制值. 例如, 0xFF 等同于 255.

通过 wParam 或 lParam 指定变量的地址可以发送字符串. 下面的例子使用 地址运算符 (&) 来实现这个目的:

SendMessage, 0xC, 0, &MyVar, ClassNN, WinTitle  ; 0XC 为 WM_SETTEXT

在 v1.0.43.06+, 由消息的接收者放入 MyVar 的字符串可以正确识别而不需要额外的步骤. 不过，这只有在参数的首个字符为和符号（&）时才可以；例如，5+&MyVar 不行但 &MyVar 或 &MyVar+5 可以。

引号包围的/原义的字符串也可以发送, 例如下面这个可运行示例 (此时不应该使用 & 运算符):

Run Notepad
WinWait Untitled - Notepad
SendMessage, 0xC, 0, "New Notepad Title"  ; 0XC 为 WM_SETTEXT

要发送消息到系统中的所有窗口（包括隐藏或禁用的那些），请在 WinTitle 中指定 ahk_id 0xFFFF（0xFFFF 为 HWND_BROADCAST）。这种技术应该只用于目标为广播的消息, 例如:

SendMessage, 0x1A,,,, ahk_id 0xFFFF  ; 0x1A 为 WM_SETTINGCHANGE

要让脚本接收消息, 请使用 OnMessage().

请参阅 消息指南 来查看使用这些命令的介绍.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

消息列表, 消息指南, OnMessage(), 自动化 Winamp, DllCall, ControlSend, WinMenuSelectItem

示例

#o::  ; Win+O 热键关闭显示器.
Sleep 1000  ; 让用户有机会释放按键 (以防释放它们时再次唤醒显视器).
; 关闭显示器:
SendMessage, 0x112, 0xF170, 2,, Program Manager  ; 0x112 为 WM_SYSCOMMAND, 0xF170 为 SC_MONITORPOWER.
; 对上面命令的注释: 使用 -1 代替 2 来打开显示器.
; 使用 1 代替 2 来激活显示器的节能模式.
return

; 启动用户选择的屏幕保护程序:
SendMessage, 0x112, 0xF140, 0,, Program Manager  ; 0x112 为 WM_SYSCOMMAND, 而 0xF140 为 SC_SCREENSAVE.

; 向上滚动一行 (用于含垂直滚动条的控件):
ControlGetFocus, control, A
SendMessage, 0x115, 0, 0, %control%, A

; 向下滚动一行:
ControlGetFocus, control, A
SendMessage, 0x115, 1, 0, %control%, A

; 切换活动窗口的键盘布局/语言为英语:
PostMessage, 0x50, 0, 0x4090409,, A  ; 0x50 为 WM_INPUTLANGCHANGEREQUEST.

; 这个例子请求 Winamp 的当前活动的轨道编号:
SetTitleMatchMode, 2
SendMessage, 1024, 0, 120, - Winamp
if ErrorLevel <> FAIL
{
    ErrorLevel++  ; Winamp 的计数从 "0" 开始, 所以加 1 进行调整.
    MsgBox, Track #%ErrorLevel% is active or playing.
}
; 请参阅 自动化 Winamp 了解详情.

; 找出 AHK 脚本的进程 ID (另一种方法是 "WinGet PID"):
SetTitleMatchMode, 2
DetectHiddenWindows, on
SendMessage, 0x44, 0x405, 0, , SomeOtherScript.ahk - AutoHotkey v
MsgBox %ErrorLevel% is the process id.


SetControlDelay

设置在每次控件修改命令执行后自动的延时。

SetControlDelay, Delay

参数

Delay

毫秒表示的时间, 可以为 表达式. 使用 -1 表示无延时, 而 0 表示最小延时. 如果未设置, 默认延时为 20.

备注

在每次控件改变命令执行后, 都会自动进行短暂的延时 (休眠), 这些命令包括 Control, ControlMove, ControlClick, ControlFocus 和 ControlSetText (ControlSend 例外, 它使用 SetKeyDelay). 这样做提高了脚本的可靠性, 因为有时控件在被这里的其中一个命令改变后需要一个 "休息" 期. 这个休息期让它可以更新它自己, 以便为下一个可能对它进行操作的命令进行响应.

虽然允许使用 -1（无延时），但是推荐至少使用 0，这样增加了 CPU 高负荷时脚本正确运行的几率。

延时为 0 时实际内部会执行 Sleep(0), 这样会将脚本时间片的剩余部分分配给其他需要的进程. 如果没有进程需要, 那么 Sleep(0) 相当于完全没有延时.

如果 CPU 比较慢或在负载下或启用的窗口动画, 那么可能需要较高的延迟值.

内置变量 A_ControlDelay 包含了当前的设置.

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

Control, ControlMove, ControlClick, ControlFocus, ControlSetText, SetWinDelay, SetKeyDelay, SetMouseDelay, SetBatchLines

示例

SetControlDelay, 0


WinMenuSelectItem

调用指定窗口菜单栏中的菜单项。

WinMenuSelectItem, WinTitle, WinText, Menu [, SubMenu1, SubMenu2, SubMenu3, SubMenu4, SubMenu5, SubMenu6, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

Menu

顶级菜单的名称, 例如 File, Edit, View. 此参数也可以使用期望的菜单项的位置, 例如 1& 表示首个菜单, 2& 表示第二个等.

SubMenu1

要选择的菜单项名称或位置 (请参阅上面).

SubMenu2

如果 SubMenu1 包含子菜单, 那么这是子菜单项的名称或位置.

SubMenu3

同上.

SubMenu4

同上.

SubMenu5

同上.

SubMenu6

同上.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

使用此命令时, 目标窗口可以处于不活动状态. 然而, 某些窗口可能需要处于 非最小化 状态.

此命令对于使用非标准菜单栏的应用程序 无效. 例如 Microsoft Outlook 和 Outlook Express, 它们使用伪装的工具栏作为菜单栏. 在这种情况下，考虑使用 ControlSend 或 PostMessage，它们应该能和一些这样的非标准菜单栏交互。

参数中的菜单名称是不区分大小写的 (即 File->Save 等同于 file->save), 而且可以不需要使用和符号 (&) 来表示菜单项中加了下划线的字母 (即 &File 等同于 File).

参数中的菜单名称还可以使用位置代替. 提供这种方法是为了支持不包含文本的菜单 (可能是由于它们包含文本的图片而不是真实的文本). 位置 1& 表示首个菜单项 (例如 File 菜单), 位置 2& 表示第二个菜单项 (例如 Edit 菜单)等. 为了确定菜单项的位置, 菜单分隔线也作为菜单项计算.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

ControlSend, PostMessage

示例

; 这里选择记事本的 文件->打开 菜单:
WinMenuSelectItem, Untitled - Notepad, , File, Open

; 与上面相同, 只是这里指定菜单的位置而不是名称:
WinMenuSelectItem, Untitled - Notepad, , 1&, 2&


GroupActivate

激活由 GroupAdd 定义的窗口组中的下一个窗口。

GroupActivate, GroupName [, R]

参数

GroupName

要激活的组名称, 和原来由 GroupAdd 定义的一样.

R

每当目标组的成员当前都没有处于活动状态时, 此参数决定是激活目标组中最老的窗口还是最新的. 如果省略, 则总是激活最老的窗口. 如果它是字母 R, 则激活最新的窗口 (最近激活的那个), 不过仅当命令中的组没有活动的成员时. "R" 可用于当您临时切换工作到不相关的任务时. 当您使用 GroupActivate, GroupDeactivate 或 GroupClose 返回到目标组时, 会激活您最近工作的窗口而不是最老的窗口.

ErrorLevel [AHK_L 54+]

如果没有找到要激活的窗口则 ErrorLevel 被置为 1, 否则为 0.

备注

此命令会对匹配窗口组中任意一条窗口规格的首个窗口进行激活. 再次使用此命令将激活系列窗口中的下一个, 依此类推. 通常给它分配一个热键, 以便使用热键自动遍历窗口.

在激活一个窗口后立即激活其他的窗口, 在一些系统上任务栏按钮可能会闪烁 (取决于操作系统和设置). 要避免此问题, 请使用 #WinActivateForce.

请参阅 GroupAdd 了解关于窗口组的更多细节.

相关

GroupAdd, GroupDeactivate, GroupClose, #WinActivateForce

示例

GroupActivate, MyGroup, R


GroupAdd

增加窗口规格到窗口组，必要时创建组。

GroupAdd, GroupName [, WinTitle, WinText, Label, ExcludeTitle, ExcludeText]

参数

GroupName

用来保存这种窗口规格的组名. 如果组不存在, 则它会被创建. 组名不区分大小写.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 在使用 GroupActivate, GroupDeactivate 和 GroupClose 时如果 DetectHiddenText 的设置为 ON, 那么会检测到隐藏文本元素.

标签

当使用 GroupActivate 命令时, 如果没有找到匹配这个组 (在 AHK_L 54 之前为 窗口规格)的窗口时运行的子程序标签. 跳到此标签就像使用 Gosub 一样. 如果不使用, 则请省略或留空.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

每使用此命令一次则添加一条新规则到组中. 换句话说, 一个组由窗口规格的集合组成而不是固定的窗口列表. 后面当类似 GroupActivate 的命令使用组时, 会使用这些规则中的每一条检查桌面上的每个窗口. 如果一个窗口匹配组里的其中一条规则, 则它被视为一个匹配.

尽管 SetTitleMatchMode 和 DetectHiddenWindows 不会直接影响此命令的行为，但它们会影响其他组命令（例如 GroupActivate 和 GroupClose）。它们还会影响其他任何命令的 WinTitle 参数中 ahk_group 的使用。

窗口组的典型用法是将相关窗口收集绑定在一起, 这可用于包含许多相关窗口的任务或有许多子窗口的程序. 例如, 如果您频繁地工作在一个图形程序或文本编辑器的多个实例时, 您可以使用热键通过 GroupActivate 来切换此程序的每一个实例 (每次一个), 而不需要使用 alt-tab 或任务栏按钮找到它们.

由于每组中的条目仅需要添加一次, 所以此命令通常使用在自动执行段中 (脚本的顶部). 添加重复的条目到组中会被忽略.

要在一个组中包含 所有 窗口 (除了特殊的 Program Manager 窗口), 请使用这个例子:

GroupAdd, AllWindows

通过在 WinTitle 参数中指定 ahk_group MyGroupName，所有的窗口命令都可以操作窗口。命令 WinMinimize, WinMaximize, WinRestore, WinHide, WinShow, WinClose 和 WinKill 会对一个组中的 所有 窗口进行操作. 要仅对顶层窗口进行操作, 请参照此例:

WinHide % "ahk_id " . WinExist("ahk_group MyGroup")

与之相比, 其他的窗口命令 (例如 WinActivate 和 IfWinExist) 只对组中的顶层窗口进行操作.

相关

GroupActivate, GroupDeactivate, GroupClose

示例

; 在脚本顶部的自动执行段：
GroupAdd, MSIE, ahk_class IEFrame ; 只添加 Internet Explorer 窗口到该组。
return ; 自动执行段结束。

; 设置一个热键激活该组，它会遍历
; 打开的所有 MSIE 窗口，每次一个
; （即每次使用热键时激活一个窗口）。
Numpad1::GroupActivate, MSIE, r

; 这是用于 MS Outlook 2002 的更复杂的组。; 在脚本顶部的自动执行段：
SetTitleMatchMode, 2
GroupAdd, mail, Message - Microsoft Word ; 用于当前正在编写的邮件
GroupAdd, mail, - Message ( ; 用于已打开的项目
; 需要附加文本以避免激活错误窗口：
GroupAdd, mail, Advanced Find, Sear&ch for the word(s)
GroupAdd, mail, , Recurrence:
GroupAdd, mail, Reminder
GroupAdd, mail, - Microsoft Outlook
return  ; 自动执行段结束。

Numpad5::GroupActivate, mail ; 设置一个热键用于激活每个 Outlook 窗口（每次一个）。


GroupClose

关闭刚刚由 GroupActivate 或 GroupDeactivate 激活的活动窗口。接着激活系列中的下一个窗口。它还可以关闭组中所有窗口。

GroupClose, GroupName [, A|R]

参数

GroupName

组名, 和原来由 GroupAdd 定义的一样.

A|R

如果此参数为字母 A, 则关闭目标组的所有成员. 与使用 WinClose ahk_group GroupName 效果相同。

否则如果此命令关闭了活动窗口，则它会接着激活系列中的下一个窗口。此参数决定是激活目标组中最老的窗口还是最新的. 如果省略, 则总是激活最老的窗口. 如果它是字母 R, 则激活最新的窗口 (最近激活的那个), 不过仅当命令中的组没有活动的成员时. "R" 可用于当您临时切换工作到不相关的任务时. 当您使用 GroupActivate, GroupDeactivate 或 GroupClose 返回到目标组时, 会激活您最近工作的窗口而不是最老的窗口.

备注

如果 A|R 参数不是字母 "A", 则此命令的行为由前面对 GroupName 进行操作的命令是 GroupActivate 还是 GroupDeactivate 决定. 如果它是 GroupDeactivate, 则仅当活动窗口 不是 目标组的成员时此命令才关闭活动窗口 (否则它什么都不做). 如果它是 GroupActivate 或者没有, 则仅当活动窗口 是 目标组的成员时此命令才关闭活动窗口 (否则它什么都不做). 这种特性允许分配一个热键到 GroupClose 来配合 GroupName 的 GroupActivate 或 GroupDeactivate 热键.

请参阅 GroupAdd 了解关于窗口组的更多细节.

相关

GroupAdd, GroupActivate, GroupDeactivate

示例

GroupClose, MyGroup, R


GroupDeactivate

类似于 GroupActivate，不同的是它激活不在组中的下一个窗口。

GroupDeactivate, GroupName [, R]

参数

GroupName

目标组的名称, 和原来由 GroupAdd 定义的一样.

R

每当目标组的其中一个成员当前处于活动状态时, 此参数决定是激活最老的非成员窗口还是最新的. 如果省略, 则总是激活最老的非成员窗口. 如果它是字母 R, 则激活最新的非成员窗口 (最近激活的那个), 不过仅当活动窗口为命令中的组的其中一个成员时. "R" 可用于当您临时切换工作到不相关的任务时. 当您使用 GroupActivate, GroupDeactivate 或 GroupClose 返回到目标组时, 会激活您最近工作的窗口而不是最老的窗口.

备注

GroupDeactivate 会激活 不 匹配组中任何窗口规格的首个窗口. 再次使用 GroupDeactivate 将激活系列窗口中的下一个. 通常给 GroupDeactivate 分配一个热键, 以便使用热键自动遍历窗口.

此命令可用于您有几乎总是在运行的最爱窗口的集合时. 通过把这些窗口添加到一个组中, 您可以使用 GroupDeactivate 访问非最爱的每个窗口并决定是否关闭它. 此命令可以让您快速清理桌面, 比手动快得多.

请参阅 GroupAdd 了解关于窗口组的更多细节.

相关

GroupAdd, GroupActivate, GroupClose

示例

GroupDeactivate, MyFavoriteWindows  ; 访问非最爱的窗口来清理桌面.


#WinActivateForce

跳过温和的方法而直接使用强制的方法激活窗口。

#WinActivateForce

在脚本的任意位置使用此指令, 可以让激活窗口的命令, 例如 WinActivate, WinActivateBottom 和 GroupActivate, 跳过 "温和" 的方法而直接使用强制的方法激活窗口.

尽管这个指令不能让窗口激活的更迅速, 不过它也许可以阻止在快速连续激活窗口时任务栏按钮的闪烁.

相关

WinActivate, WinActivateBottom, GroupActivate

示例

#WinActivateForce


DetectHiddenText

设置在探测窗口时窗口中隐藏的文本是否“可见”。此设置影响例如 IfWinExist 和 WinActivate 的这些命令。

DetectHiddenText, On|Off

参数

On|Off

On：这是默认的。能检测到隐藏文本.

Off：不检测隐藏文本。

备注

"隐藏文本" 是与窗口中那些不可见控件有关的一个术语. 它们的文本因此被认为是 "隐藏的". 当您想检测多窗格窗口或多选项卡式对话框中不同窗格的差异时, 可能需要关闭 DetectHiddenText. 使用 Window Spy 可以判断当前活动窗口中有哪些隐藏文本. 此设置会影响所有接受 WinText 参数的命令, 包括 WinActivate, IfWinActive, WinWait 和 IfWinExist.

内置变量 A_DetectHiddenText 包含了当前的设置 (On 或 Off).

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

DetectHiddenWindows

示例

DetectHiddenText, off


DetectHiddenWindows

设置脚本是否可以“看见”隐藏的窗口。

DetectHiddenWindows, On|Off

参数

On|Off

On：能检测到隐藏窗口。

Off：这是默认的。除了 WinShow 命令，其他都不会检测到隐藏窗口。

备注

在一些情况下打开 DetectHiddenWindows 可能会让脚本运行更困难, 因为有些隐藏的系统窗口可能意外地匹配上您想要操作的另一个窗口的标题或文本. 因此在大多数脚本中应该让此设置保持关闭. 然而, 当您希望直接操作隐藏窗口而不想首先使用 WinShow 显示这些窗口时, 则需要打开此设置.

除 WinShow 外的所有窗口命令都会受此设置的印象, 包括 WinActivate, IfWinActive, WinWait, IfWinExist. 与之相比, 即使没有检测到隐藏窗口, WinShow 也总是能让它们显示.

使用 ahk_id 方法 或作为 上次找到的窗口 访问控件或子窗口时, 可以不需要打开 DetectHiddenWindows. 使用 Gui +LastFound 访问 GUI 窗口时，同样是不需要的。

内置变量 A_DetectHiddenWindows 包含了当前设置 (On 或 Off).

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

DetectHiddenText

示例

DetectHiddenWindows, on


SetTitleMatchMode

设置在类似 WinWait 命令中 WinTitle 参数的匹配模式。

SetTitleMatchMode, MatchMode
SetTitleMatchMode, Fast|Slow

参数

MatchMode

下列数字的其中一个或单词 RegEx:

1: 窗口标题必须以指定的 WinTitle 开头.
2：窗口标题的某个位置必须包含 WinTitle。
3: 窗口标题必须准确匹配 WinTitle.

RegEx (v1.0.45+): 改变 WinTitle, WinText, ExcludeTitle 以及 ExcludeText 为 正则表达式. 在这些命令中使用时, 不要把正则表达式括在引号中. 例如：WinActivate Untitled.*Notepad。RegEx 还适用于 ahk_class；例如，ahk_class IEFrame 会搜索类名包含 IEFrame 的任意窗口（这是由于在默认情况下，正则表达式在目标字符串任意位置查找匹配）。注：对于 WinText，RegEx 会分别与每个文本元素（即每个控件的文本）进行对照来寻找匹配。因此, 匹配不会横跨多个文本元素.

上面的模式还会对 ExcludeTitle 产生与 WinTitle 相同的影响。例如, 模式 3 要求被排除的窗口的标题必须准确匹配 ExcludeTitle.

Fast|Slow

Fast: 这是默认行为. 性能比起 Slow 有较大提升, 但某些类型窗口中的一些 WinText 可能无法被各种窗口命令检测到.

Slow: 速度慢得多, 但窗口命令会获取窗口中所有可能的文本以寻找 WinText 匹配. Window Spy中会显示哪些部分的窗口文本（如果有）需要慢速模式才能匹配到。

备注

此命令影响所有窗口命令的行为, 例如 IfWinExist 和 WinActivate.

如果未指定，则 TitleMatchMode 默认为 1 和 fast 模式。

如果使用 窗口组, 则当前标题匹配模式适用于组中的每个单独的规则.

通常, 在使用标题和 快速 模式的文本无法唯一标识目标窗口时才应该使用 慢速 模式. 这是因为当任意一个应用程序窗口正忙或 "无响应" 时慢速模式会非常慢.

AutoHotkey 自带的 Window Spy 自定义版本会在单独区域中显示 slow 文本, 这样很容易判断是否需要使用 慢速 模式.

如果您想同时改变两个属性, 请执行两次命令, 例如:

SetTitleMatchMode, 2
SetTitleMatchMode, slow

内置变量 A_TitleMatchMode 和 A_TitleMatchModeSpeed 包含了当前的设置.

不管当前的 TitleMatchMode 如何，WinTitle、WinText、ExcludeTitle 和 ExcludeText 都是区分大小写的。唯一的例外是带不区分大小写选项的 RegEx 模式；例如：i)untitled - notepad。

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

SetWinDelay, IfWinExist, WinActivate, RegExMatch()

示例

SetTitleMatchMode 2
; 或:
SetTitleMatchMode RegEx

SetTitleMatchMode Slow  ; Slow/Fast 可以独立于其他所有模式进行设置.


SetWinDelay

设置在每次执行窗口命令（例如 WinActivate）后自动的延时。

SetWinDelay, Delay

参数

Delay

毫秒表示的时间, 可以为 表达式. 使用 -1 表示无延时, 而 0 表示最小延时. 如果未设置, 默认延时为 100.

备注

在每次执行除了 IfWinActive 和 IfWinExist 外的窗口操作命令后会自动进行短暂的延时. 这样做提高了脚本的可靠性, 因为有时对窗口进行创建, 激活或最小化等等操作后需要一个 "休息" 期. 这让它有机会更新它自己, 以便为下一个可能对它进行操作的命令进行响应.

虽然允许使用 -1（无延时），但是推荐至少使用 0，这样增加了 CPU 高负荷时脚本正确运行的几率。

延时为 0 时实际内部会执行 Sleep(0), 这样会将脚本时间片的剩余部分分配给其他需要的进程. 如果没有进程需要, 那么 Sleep(0) 相当于完全没有延时.

如果 CPU 比较慢或在负载下或启用的窗口动画, 那么可能需要较高的延迟值.

内置变量 A_WinDelay 包含了当前的设置.

每个新运行的 线程 (例如 热键, 自定义菜单项 或 定时 子程序) 都会以此命令的默认设置开始. 通过在脚本的自动执行段 (脚本的顶部) 使用此命令可以改变这个默认设置.

相关

SetControlDelay, SetKeyDelay, SetMouseDelay, SetBatchLines, SendMode

示例

SetWinDelay, 10


StatusBarGetText

获取标准状态栏控件的文本。

StatusBarGetText, OutputVar [, Part#, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

OutputVar

用来存储获取的文本的变量名.

Part#

要获取的状态栏的那一部分的编号, 可以为 表达式. 默认为 1, 这部分通常包含了我们感兴趣的文本.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被设置为 1, 否则为 0. 遇到问题时, OutputVar 也被置空.

备注

该命令尝试读取窗口中首个标准状态栏（微软通用控件：msctls_statusbar32）。某些程序使用它们自己的状态栏或微软通用控件的特殊版本，此时无法获取它的文本。

在大多数时候，在循环中使用此命令效率不如 StatusBarWait，因为后者包含了避免重复调用 StatusBarGetText 形成的高开销的优化。

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

StatusBarWait, WinGetTitle, WinGetText, ControlGetText

示例

StatusBarGetText, RetrievedText, 1, Search Results
IfInString, RetrievedText, found, MsgBox, Search results have been found.


StatusBarWait

等待窗口的状态栏包含指定的字符串。

StatusBarWait [, BarText, Seconds, Part#, WinTitle, WinText, Interval, ExcludeTitle, ExcludeText]

参数

BarText

此命令所等待的文本或部分文本. 默认为空, 这意味着等待目标状态栏变成空的. 此文本是区分大小写的, 且匹配行为由 SetTitleMatchMode 决定, 类似于下面的 WinTitle.

要等待状态栏文本 改变, 请在循环中使用 StatusBarGetText, 或像本页底部的例子那样使用 RegEx.

秒

在超时前等待的秒数 (可以为小数或 表达式), 超时后 ErrorLevel 会被设置为 1. 默认为空, 这意味着无限期等待. 指定 0 等同于指定 0.5.

Part#

要获取的状态栏的那一部分的编号, 可以为 表达式. 默认为 1, 这部分通常包含了我们感兴趣的文本.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

Interval

此命令在等待时对状态栏进行检查的时间间隔 (单位为毫秒), 可以为 表达式. 默认为 50.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 如果状态栏无法访问, 则此命令会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果在状态栏出现匹配文本前命令超时了, 则 ErrorLevel 被设置为 1. 如果状态栏无法访问, 则它被设置为 2. 成功找到匹配时则被设置为 0.

备注

StatusBarWait 尝试读取窗口中首个标准状态栏（类名 msctls_statusbar32）。某些程序使用它们自己的状态栏或微软通用控件的特殊版本。此命令不支持这样的状态栏.

在大多数时候, 与其在循环中使用 StatusBarGetText, 不如使用 StatusBarWait 来的有效率, 因为它包含了避免重复调用 StatusBarGetText 形成的高开销的优化.

StatusBarWait 在开始等待匹配前会确定它的目标窗口. 如果那个目标窗口关闭了, 那么此命令会停止等待, 即使存在另一个匹配指定 WinTitle 和 WinText 的窗口.

当此命令处于等待状态时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

StatusBarGetText, WinGetTitle, WinGetText, ControlGetText

示例

; 下面的例子输入新的搜索模式到现有的资源管理器/搜索窗口.
IfWinExist, Search Results ; 设置上次找到的窗口以简化后面的代码.
{
    WinActivate
    Send, {tab 2}!o*.txt{enter}  ; 在搜索窗口中, 输入要搜索的模式.
    Sleep, 400  ; 给状态栏时间, 等它改变为 "Searching".
    StatusBarWait, found, 30
    if ErrorLevel
        MsgBox, The command timed out or there was a problem.
    else
        MsgBox, The search successfully completed.
}

; 下面的例子等待活动窗口的状态栏 发生变化. 此例子需要 v1.0.46.06+.
SetTitleMatchMode RegEx
IfWinExist A  ; 设置上次找到的窗口为活动窗口 (供下面使用).
{
   StatusBarGetText, OrigText
   StatusBarWait, ^(?!^\Q%OrigText%\E$)  ; 该正则表达式等待文本发生任何变化。
}


WinActivate

激活指定的窗口（让它置于最前面）。

WinActivate [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

如果窗口处于最小化状态, 那么会对其还原后再进行激活.

在 60ms 的时间中, 会对目标窗口进行六次激活的尝试. 因此, 通常不需要在 WinActivate 后使用 WinWaitActive 或 IfWinNotActive.

如果匹配窗口已经为活动窗口, 那么会让此窗口继续保持活动状态, 而不会激活此窗口下的其他任何匹配窗口. 一般而言, 如果有多个匹配窗口, 那么会激活最上面的 (最近使用的) 窗口. 您可以使用 WinActivateBottom 激活最下面的 (最早使用的) 窗口.

在激活一个窗口后立即激活其他的窗口, 在一些系统上任务栏按钮可能会闪烁 (取决于操作系统和设置). 要避免此问题, 请使用 #WinActivateForce.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinActivateBottom, #WinActivateForce, SetTitleMatchMode, DetectHiddenWindows, 上次找到的窗口, IfWinExist, IfWinActive, WinWaitActive, WinWait, WinWaitClose, WinClose, GroupActivate, WinSet

示例

IfWinExist, Untitled - Notepad
    WinActivate ; 使用前面找到的窗口
else
    WinActivate, Calculator


WinActivateBottom

和 WinActivate 一样，只是此命令激活最下面的（最早激活的）匹配窗口而不是最上面的。

WinActivateBottom [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

如果只有一个匹配窗口, 那么 WinActivateBottom 的行为和 WinActivate 一样.

窗口组 比此命令更高级, 所以请考虑使用它们以获得更多的功能和灵活性.

如果窗口处于最小化状态, 那么会对其还原后再进行激活.

在 60ms 的时间中, 会对目标窗口进行六次激活的尝试. 因此, 通常不需要在此命令后使用 WinWaitActive 命令.

与 WinActivate 不同, 此命令中不能使用 上次找到的窗口, 因为它可能不是底层窗口. 因此, 至少需要有一个参数不为空.

在激活一个窗口后立即激活其他的窗口, 在一些系统上任务栏按钮可能会闪烁 (取决于操作系统和设置). 要避免此问题, 请使用 #WinActivateForce.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinActivate, #WinActivateForce, SetTitleMatchMode, DetectHiddenWindows, IfWinExist, IfWinActive, WinWaitActive, WinWait, WinWaitClose, GroupActivate

示例

; 此热键可以让您按从最老到最新的顺序访问所有打开的浏览器窗口:
#i::
SetTitleMatchMode, 2
WinActivateBottom, - Microsoft Internet Explorer
return


WinClose

关闭指定的窗口。

WinClose [, WinTitle, WinText, SecondsToWait, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

SecondsToWait

如果省略或为空, 此命令会完全不等待. 如果为 0, 则它会等待 500ms. 否则, 它会等待指定的秒数 (可以为小数或 表达式) 来让窗口关闭. 如果窗口在此期间没有关闭, 那么脚本会继续执行. 此命令 不会 设置 ErrorLevel, 所以如果您需要确定窗口是否关闭时请使用 IfWinExist 或 WinWaitClose. 当此命令处于等待状态时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的线程.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

此命令发送关闭消息到窗口. 结果取决于窗口 (它可能会询问是否保存数据等).

如果匹配窗口是活动的, 那么会优先关闭此窗口而不是它下面的其他匹配窗口. 一般而言, 如果有多个匹配窗口, 那么会关闭最上面的 (最近使用的) 窗口.

此命令仅对最上面的匹配窗口进行操作, 除非 WinTitle 为 ahk_group GroupName, 此时会影响组中所有窗口.

WinClose 发送 WM_CLOSE 消息到目标窗口, 这种关闭方法有些强制性. 关闭窗口的另一种方法是发送下面的消息. 它可能会产生与此命令不同的行为, 因为它类似于按下 Alt-F4 或点击窗口标题栏的关闭按钮的效果:

PostMessage, 0x112, 0xF060,,, WinTitle, WinText  ; 0x112 = WM_SYSCOMMAND, 0xF060 = SC_CLOSE

如果使用 WinClose 无法关闭窗口, 那么您可以使用 WinKill 来强制关闭.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinKill, WinWaitClose, Process, WinActivate, SetTitleMatchMode, DetectHiddenWindows, 上次找到的窗口, IfWinExist, IfWinActive, WinWaitActive, WinWait, GroupActivate

示例

IfWinExist, Untitled - Notepad
    WinClose ; 使用前面找到的窗口
else
    WinClose, Calculator


WinGet

获取指定窗口的唯一 ID、进程 ID、进程名或控件列表。它还可以获取匹配指定条件的所有窗口的列表。

WinGet, OutputVar [, Cmd, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

OutputVar

用来保存 Cmd 结果的变量名.

Cmd
请参阅后面的列表.
WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

Cmd 为要执行的操作, 留空时默认为 ID. 它可以为下列单词的其中一个:

ID: 获取窗口的唯一 ID 号 (HWND/句柄). 如果没有匹配窗口, 那么 OutputVar 被置空. 使用 WinExist() 和 WinActive() 也可以获取窗口的 ID；例如，WinExist("A") 能快速获取活动窗口 ID。要找出控件的 HWND（用于 Post/SendMessage 或 DllCall），请使用 ControlGet Hwnd 或 MouseGetPos。

IDLast: 与上面相同, 不过如果找到多个匹配窗口, 它会获取最后的/最下面的窗口 ID. 如果只有一个匹配, 那么它的效果与 ID 相同. 这种特性类似于 WinActivateBottom.

PID: 获取窗口的 进程 ID (PID).

ProcessName: 获取拥有窗口的进程名 (例如 notepad.exe). 如果没有匹配窗口, 那么 OutputVar 被置空.

ProcessPath [v1.1.01+]: 类似于 ProcessName, 但获取进程的完整路径和名称而不仅是名称.

Count: 获取匹配指定 WinTitle, WinText, ExcludeTitle 以及 ExcludeText 的窗口数 (没有则为 0). 要统计系统中所有窗口数, 请省略所有的四个标题/文本参数. 只有在打开 DetectHiddenWindows 设置时才会包括隐藏窗口.

List: 获取匹配指定的 WinTitle, WinText, ExcludeTitle 以及 ExcludeText 的所有窗口的唯一 ID 号 (要获取整个系统中所有窗口, 请省略所有的四个标题/文本参数). 每个 ID 号保存在名称以 OutputVar 开始的变量（构成伪数组）中，而 OutputVar 自己则保存了获取的项数（没有则为 0）。例如, 如果 OutputVar 为 MyArray 且找到两个匹配的窗口, 那么 MyArray1 会被设置为首个窗口的 ID, MyArray2 被设置为第二个窗口的 ID, 同时 MyArray 自身被设置为数目 2. 窗口获取的顺序是从最上面到最下面 (根据它们在桌面上的堆放顺序). 只有在打开 DetectHiddenWindows 设置时才会包括隐藏窗口. 在函数中，要创建全局而不是局部的伪数组，必须在使用此命令前声明 MyArray 为全局变量（对于假设全局函数，反之亦成）。

MinMax: 获取窗口的最小化/最大化状态. 如果不存在匹配窗口, 则 OuputVar 被置空; 否则, 它被设置为下列数字的其中一个:
-1: 窗口处于最小化状态 (使用 WinRestore 可以让它还原).
1: 窗口处于最大化状态 (使用 WinRestore 可以让它还原).
0: 窗口既不处于最小化状态也不处于最大化状态.

ControlList: 获取窗口中所有控件的控件名称. 如果没有匹配窗口或窗口中没有控件, 那么 OutputVar 被置空. 否则, 每个控件的名称由其类名紧接着序号 (ClassNN) 组成, 如同 Window Spy 显示的那样.

除最后一项外的其他项以换行符结束 (`n). 要逐个检查每个控件的名称, 请使用 解析循环, 如同下文示例部分演示的那样.

控件根据它们的 Z 顺序排列, 当窗口支持 TAB 导航时这通常和 TAB 键导航的顺序相同.

当前鼠标光标下的控件可以通过 MouseGetPos 获取.

ControlListHwnd [v1.0.43.06+]: 与上面相同, 不过它获取每个控件的 窗口句柄 (HWND) 而不是其 ClassNN.

Transparent: 获取度数表示的窗口的透明度 (请参阅 WinSet 了解如何设置透明度). 出现后面这些情况时 OutputVar 被置空: 1) 操作系统低于 Windows XP; 2) 没有匹配窗口; 3) 窗口没有设置透明度等级; 或 4) 其他情况 (由操作系统行为引起), 例如设置透明后窗口被最小化, 还原和/或重设大小. 否则, 被设置为介于 0 和 255 之间的数字, 这里 0 表示完全透明的窗口而 255 表示不透明的窗口. 例如：

MouseGetPos,,, MouseWin
WinGet, Transparent, Transparent, ahk_id %MouseWin%  ; 鼠标光标下的窗口透明度.

TransColor: 获取窗口的透明色 (请参阅 WinSet 了解如何设置透明色). 出现后面这些情况时 OutputVar 被置空: 1) 操作系统低于 Windows XP; 2) 没有匹配窗口; 3) 窗口没有透明色; 或 4) 其他情况 (由操作系统行为引起), 例如设置透明后窗口被最小化, 还原和/或重设大小. 否则, 被设置为六位的十六进制 RGB 颜色值, 例如 0x00CC99. 例如：

MouseGetPos,,, MouseWin
WinGet, TransColor, TransColor, ahk_id %MouseWin%  ; 鼠标光标下的窗口透明色.

Style 或 ExStyle: 分别获取表示窗口样式或扩展样式的 8 位十六进制数. 如果没有匹配窗口, 那么 OutputVar 被置空. 下面的例子判断窗口是否含有 WS_DISABLED 样式:

WinGet, Style, Style, My Window Title
if (Style & 0x8000000)  ; 0x8000000 为 WS_DISABLED.
  ... 窗口处于不可用状态, 执行适当的动作.

下一个例子判断窗口是否含有 WS_EX_TOPMOST 样式 (置顶):

WinGet, ExStyle, ExStyle, My Window Title
if (ExStyle & 0x8)  ; 0x8 为 WS_EX_TOPMOST.
  ... 窗口处于置顶状态, 执行适当的动作.

请参阅 样式表 了解部分样式.

备注

窗口的 ID 号只在窗口的生存期内有效. 换句话说, 如果重启了应用程序, 其所有的窗口都会使用新的 ID 号.

由此命令获取的 ID 号是数值的 (不包含前缀 "ahk_id"), 且不论 SetFormat 的设置如何都保存为十六进制格式.

当前鼠标光标下的窗口 ID 可以通过 MouseGetPos 获取.

尽管当前 ID 号为 32 位的无符号整数, 但是在未来的版本中可能变成 64 位. 因此, 对它们进行数值运算例如加法是不可靠的, 因为这些运算需要把输入字符串解析为有符号而不是无符号的整数.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinGetClass, Process, WinGetTitle, MouseGetPos, ControlGet, ControlFocus, GroupAdd

示例

; Example #1: 最大化活动窗口并显示其唯一 ID:
WinGet, active_id, ID, A
WinMaximize, ahk_id %active_id%
MsgBox, The active window's ID is "%active_id%".

; Example #2: 访问整个系统上所有窗口并显示它们的信息:
WinGet, id, list,,, Program Manager
Loop, %id%
{
    this_id := id%A_Index%
    WinActivate, ahk_id %this_id%
    WinGetClass, this_class, ahk_id %this_id%
    WinGetTitle, this_title, ahk_id %this_id%
    MsgBox, 4, , Visiting All Windows`n%a_index% of %id%`nahk_id %this_id%`nahk_class %this_class%`n%this_title%`n`nContinue?
    IfMsgBox, NO, break
}

; Example #3: 从 ControlList 中提取每个控件的名称:
WinGet, ActiveControlList, ControlList, A
Loop, Parse, ActiveControlList, `n
{
    MsgBox, 4,, Control #%a_index% is "%A_LoopField%". Continue?
    IfMsgBox, No
        break
}

; Example #4: 实时显示活动窗口的控件列表:
#Persistent
SetTimer, WatchActiveWindow, 200
return
WatchActiveWindow:
WinGet, ControlList, ControlList, A
ToolTip, %ControlList%
return


WinGetActiveStats

组合了 WinGetActiveTitle 和 WinGetPos 两个命令的功能。

WinGetActiveStats, Title, Width, Height, X, Y

参数

标题

用来保存活动窗口标题的变量名.

Width/Height

用来保存活动窗口宽度和高度的变量名.

X, Y

用来保存活动窗口左上角的 X 和 Y 坐标的变量名.

备注

如果没有找到匹配窗口, 则输出变量会被置空.

此命令相当于下面的语句序列:

WinGetTitle, Title, A
WinGetPos, X, Y, Width, Height, A

如果活动窗口为隐藏窗口且 DetectHiddenWindows 处于关闭状态 (默认状态), 除 WinShow 外的所有命令都无法 "看见" 它. 由于此或其他任何原因而没有活动窗口, 那么此命令会设置所有的输出变量为空.

相关

WinGetPos, WinGetActiveTitle, WinGetTitle, WinGetClass, WinGetText, ControlGetText

示例

WinGetActiveStats, Title, Width, Height, X, Y
MsgBox, The active window "%Title%" is %Width% wide`, %Height% tall`, and positioned at %X%`,%Y%.


WinGetActiveTitle

获取活动窗口的标题。

WinGetActiveTitle, OutputVar

参数

OutputVar

用来保存活动窗口标题的变量名.

备注

此命令相当于：WinGetTitle, OutputVar, A。

相关

WinGetPos, WinGetActiveStats, WinGetTitle, WinGetClass, WinGetText, ControlGetText

示例

WinGetActiveTitle, Title
MsgBox, The active window is "%Title%".


WinGetClass

获取指定窗口的类名。

WinGetClass, OutputVar [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

OutputVar

用来保存获取的类名的变量名.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

仅获取类名 (OutputVar 中不包含前缀 "ahk_class").

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinGet, WinGetTitle

示例

WinGetClass, class, A
MsgBox, The active window's class is "%class%".


WinGetPos

获取指定窗口的位置和大小。

WinGetPos [, X, Y, Width, Height, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

X, Y

用来保存目标窗口左上角的 X 和 Y 坐标的变量名. 如果省略, 则丢弃相应的数据.

Width/Height

用来保存目标窗口宽度和高度的变量名. 如果省略, 则丢弃相应的数据.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

如果没有找到匹配窗口, 则输出变量会被置空.

如果在 WinTitle 中使用“Program Manager”，那么此命令会获取桌面的大小，这通常与当前的屏幕分辨率相同。

最小化的窗口同样含有位置和大小. 此时返回的值可能因操作系统和配置而变化.

要获取鼠标当前悬停的窗口和控件的名称, 请使用 MouseGetPos.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinMove, ControlGetPos, WinGetActiveStats, WinGetActiveTitle, WinGetTitle, WinGetText, ControlGetText

示例

WinGetPos, X, Y, Width, Height, Calculator
MsgBox, Calculator is at %X%`,%Y%

WinGetPos, X, Y, , , A  ; "A" 表示获取活动窗口的位置.
MsgBox, The active window is at %X%`,%Y%

IfWinExist, Untitled - Notepad
{
    WinGetPos, Xpos, Ypos  ; 使用前面找到的窗口.
    MsgBox, Notepad is at %Xpos%`,%Ypos%
}


WinGetText

获取指定窗口的文本。

WinGetText, OutputVar [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

OutputVar

用来存储获取的文本的变量名.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

[v1.1.04+] 此命令失败时会抛出异常. 想了解更多信息, 请参阅 运行时错误.

如果遇到问题则 ErrorLevel 被置为 1, 否则为 0.

备注

通常情况下获取的文本和 Window Spy 中显示的相同. 但是, 如果 DetectHiddenText 为关闭状态, 那么 OutputVar 中会不包含隐藏文本.

每个文本元素都以回车换行符 (CR+LF) 结束, 它们在脚本中表示为 `r`n. 要提取个别行或子字符串, 请使用类似 StringGetPos 和 StringMid 的命令. 还可以使用 解析循环 来逐个检查每行或每个单词.

如果获取的文本看起来像被截短了（不完整），请在 WinGetText 前尝试使用 VarSetCapacity(OutputVar, 55) [把 55 替换为超过截短文本许多的大小]。在一些应用程序不能正确响应 WM_GETTEXTLENGTH 消息时需要这样, 否则会导致 AutoHotkey 把输出变量设的过小以致无法保存所有的文本.

可获取的最多文本数限制于变量的最大容量 (这可以通过 #MaxMem 指令改变). 因此，如果目标窗口（例如打开了大文档的编辑器）包含大量文本，那么此命令可能会使用大量的内存。要避免这种情况, 考虑使用 ControlGetText 只获取部分的窗口文本. 在任何情况下，可以为变量赋值为空来释放它占用的内容，即 OutputVar =。

要获取窗口中所有控件的列表，请参照此例：WinGet, OutputVar, ControlList, WinTitle

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

ControlGetText, WinGetActiveStats, WinGetActiveTitle, WinGetTitle, WinGetPos, #MaxMem

示例

Run, Calc.exe
WinWait, Calculator
WinGetText, text  ; 使用前面找到的窗口.
MsgBox, The text is:`n%text%


WinGetTitle

获取指定窗口的标题。

WinGetTitle, OutputVar [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

OutputVar

用来存储获取的标题的变量名.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

要获取鼠标当前悬停的窗口的名称, 请使用 MouseGetPos.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinGetActiveStats, WinGetActiveTitle, WinGetClass, WinGet, WinGetText, ControlGetText, WinGetPos

示例

WinGetTitle, Title, A
MsgBox, The active window is "%Title%".


WinHide

隐藏指定的窗口。

WinHide [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

使用 WinShow 来恢复隐藏的窗口 (DetectHiddenWindows 设置为 On 或 Off 都没关系).

此命令仅对最上面的匹配窗口进行操作, 除非 WinTitle 为 ahk_group GroupName, 此时会影响组中所有窗口.

资源管理器任务栏可以通过如下方式隐藏/显示:

WinHide ahk_class Shell_TrayWnd
WinShow ahk_class Shell_TrayWnd

相关

WinShow, SetTitleMatchMode, DetectHiddenWindows, 上次找到的窗口, WinSet

示例

Run, notepad.exe
WinWait, Untitled - Notepad
Sleep, 500
WinHide ; 使用前面找到的窗口
Sleep, 1000
WinShow


WinKill

强制关闭指定的窗口。

WinKill [, WinTitle, WinText, SecondsToWait, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

SecondsToWait

如果省略或为空, 此命令会完全不等待. 如果为 0, 则它会等待 500ms. 否则, 它会等待指定的秒数 (可以为小数或 表达式) 来让窗口关闭. 如果窗口在此期间没有关闭, 那么脚本会继续执行. 此命令 不会 设置 ErrorLevel, 所以如果您需要确定窗口是否关闭时请使用 IfWinExist 或 WinWaitClose.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

此命令首先会用短暂的时间尝试正常地关闭窗口. 如果失败, 那么它会尝试终止窗口进程来强制关闭窗口.

如果匹配窗口是活动的, 那么会优先关闭此窗口而不是它下面的其他匹配窗口. 一般而言, 如果有多个匹配窗口, 那么会关闭最上面的 (最近使用的) 窗口.

此命令仅对最上面的匹配窗口进行操作, 除非 WinTitle 为 ahk_group GroupName, 此时会影响组中所有窗口.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinClose, WinWaitClose, Process, WinActivate, SetTitleMatchMode, DetectHiddenWindows, 上次找到的窗口, IfWinExist, IfWinActive, WinWaitActive, WinWait, GroupActivate

示例

IfWinExist, Untitled - Notepad
    WinKill ; 使用前面找到的窗口
else
    WinKill, Calculator


WinMaximize

最大化指定的窗口。

WinMaximize [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

使用 WinRestore 来还原窗口而使用 WinMinimize 最小化窗口.

如果有特殊类型的窗口无法正确响应 WinMaximize, 请尝试使用下面的方法:

PostMessage, 0x112, 0xF030,,, WinTitle, WinText  ; 0x112 = WM_SYSCOMMAND，0xF030 = SC_MAXIMIZE

此命令仅对最上面的匹配窗口进行操作, 除非 WinTitle 为 ahk_group GroupName, 此时会影响组中所有窗口.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinRestore, WinMinimize

示例

Run, notepad.exe
WinWait, Untitled - Notepad
WinMaximize ; 使用前面找到的窗口

^Up::WinMaximize, A  ; 设置热键来最大化活动窗口.


WinMinimize

缩小指定窗口为任务栏上的按钮。

WinMinimize [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

使用 WinRestore 或 WinMaximize 来还原窗口.

如果有特殊类型的窗口无法正确响应 WinMinimize, 请尝试使用下面的方法:

PostMessage, 0x112, 0xF020,,, WinTitle, WinText ; 0x112 = WM_SYSCOMMAND, 0xF020 = SC_MINIMIZE

此命令仅对最上面的匹配窗口进行操作, 除非 WinTitle 为 ahk_group GroupName, 此时会影响组中所有窗口.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinRestore, WinMaximize, WinMinimizeAll

示例

Run, notepad.exe
WinWait, Untitled - Notepad
WinMinimize ; 使用前面找到的窗口

^Down::WinMinimize, A  ; 设置热键来最小化活动窗口.


WinMinimizeAll / WinMinimizeAllUndo

最小化或还原所有窗口.

WinMinimizeAll
WinMinimizeAllUndo

在大多数系统中, 此命令等同于资源管理器的 Win-M 和 Win-D 热键.

相关

WinMinimize, GroupAdd

示例

WinMinimizeAll
WinMinimizeAllUndo


WinMove

改变指定窗口的位置和/或大小。

WinMove, X, Y
WinMove, WinTitle, WinText, X, Y [, Width, Height, ExcludeTitle, ExcludeText]

参数

X, Y

目标窗口新位置的左上角的 X 和 Y 坐标 (单位为像素), 可以为 表达式. 屏幕左上角坐标为 0, 0.

如果只指定了这两个参数, 那么使用 上次找到的窗口 为目标窗口.

或者可以省略 X 和/或 Y, 此时使用当前位置.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

Width, Height

目标窗口的新宽度和高度 (单位为像素), 可以为 表达式. 如果其中一个省略, 为空或为单词 DEFAULT, 那么在这个维度中的大小将保持不变.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

如果 Width 和 Height 太小 (或为负数), 那么大多数带标题栏的窗口最小尺寸不会小于 112 x 27 像素 (不过, 有些类型的窗口的最小的尺寸可能有差异). 如果 Width 和 Height 太大, 那么大多数窗口最大尺寸不会大于超过桌面尺寸大约 12 像素.

x 和 y 坐标中可以使用负数, 这样可以支持多显示器系统且可以让窗口被完全移出屏幕.

尽管 WinMove 不能移动最小化状态的窗口, 不过当 DetectHiddenWindows 设置开启时它可以移动隐藏窗口.

WinMove 移动窗口的速度受 SetWinDelay 影响.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

ControlMove, WinGetPos, WinHide, WinMinimize, WinMaximize, WinSet

示例

Run, calc.exe
WinWait, Calculator
WinMove, 0, 0 ; 将 WinWait 找到的窗口移动到屏幕的左上角。

SplashTextOn, 400, 300, Clipboard, The clipboard contains:`n%clipboard%
WinMove, Clipboard, , 0, 0 ; 移动启动画面到左上角。
Msgbox, Press OK to dismiss the SplashText
SplashTextOff

; 下面的函数让指定窗口显示在屏幕中间：
CenterWindow(WinTitle)
{
    WinGetPos,,, Width, Height, %WinTitle%
    WinMove, %WinTitle%,, (A_ScreenWidth/2)-(Width/2), (A_ScreenHeight/2)-(Height/2)
}


WinRestore

如果指定的窗口处于最小化或最大化状态，则还原它。

WinRestore [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

如果有特殊类型的窗口无法正确响应 WinRestore, 请尝试使用下面的方法:

PostMessage, 0x112, 0xF120,,, WinTitle, WinText  ; 0x112 = WM_SYSCOMMAND, 0xF120 = SC_RESTORE

此命令仅对最上面的匹配窗口进行操作, 除非 WinTitle 为 ahk_group GroupName, 此时会影响组中所有窗口.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinMinimize, WinMaximize

示例

WinRestore, Untitled - Notepad


WinSet

对指定的窗口进行各种设置，例如“总在最前面”和透明度。

WinSet, Attribute, Value [, WinTitle, WinText,  ExcludeTitle, ExcludeText]

参数

Attribute, Value

请参阅后面的列表.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

Attribute, Value

AlwaysOnTop, [On|Off|Toggle]：让窗口处于置顶状态。使用 ON 打开此设置, 使用 OFF 关闭, 而使用 TOGGLE 切换到当前的相反状态. 如果省略, 默认为 TOGGLE. 可以使用单词 Topmost 代替 AlwaysOnTop.

Bottom: 发送窗口到堆栈的底部; 即在其他所有窗口的下面. 这个效果类似于使用 Alt-Escape. 例如：WinSet, Bottom,, WinTitle。

Top: 把窗口带回到堆栈的顶部而不进行 激活. 但是, 在大多数情况下系统默认设置会激活它. 此外, 当操作系统阻止应用程序从用户抢夺焦点时, 此命令可能没有效果 (这可能取决于当前活动窗口的类型和用户当前正在进行的操作这些因素). 一个可能的解决方法是让窗口暂时 AlwaysOnTop, 然后关闭 AlwaysOnTop.

Disable 或 Enable: 分别为禁用或启用窗口. 当窗口被禁用时, 用户不能移动它或与它的控件进行交互. 此外, 被禁用的窗口会从 alt-tab 列表中移除.

Redraw: 通过通知操作系统窗口的矩形框需要重绘来尝试更新窗口的外观/内容. 如果此方法对特殊的窗口无效, 那么尝试使用 WinMove. 如果仍然无效, 那么请尝试使用下面方法:

WinHide, WinTitle
WinShow, WinTitle

Style, N or ExStyle, N：分别改变窗口的样式或扩展样式。如果 N 的首个字符为加号或减号, 那么会添加或移除 N 中的样式. 如果首个字符为脱字符 (^), 那么 N 中的样式会被切换到相反的状态. 如果首个字符为数字, 则窗口样式会被完全覆盖为 N.

如果设置失败, 则 ErrorLevel 被置为 1, 成功则为 0. 没有找到目标窗口或无法应用此样式时会设置失败。

改变可见窗口的某些样式后，可能需要使用 WinSet Redraw（请参阅下面）对窗口进行重绘。最后, 样式表 中列出了一些常用的样式编号. 示例:

WinSet, Style, -0xC00000, A  ; 移除活动窗口的标题栏 (WS_CAPTION).
WinSet, ExStyle, ^0x80, WinTitle  ; 切换 WS_EX_TOOLWINDOW 属性, 它会移除/添加窗口到 alt-tab 列表.

WinSet, Region [, Options, WinTitle, ...]

改变窗口的形状为指定的矩形, 椭圆形或多边形. 如果 Options 参数为空, 那么恢复窗口为原来的形状. 否则, 可以指定一个或多个的下列选项, 选项之间使用空格分隔:

Wn: 矩形或椭圆形的宽度. 例如：w200。
Hn: 矩形或椭圆形的高度. 例如：h300。
X-Y: 这样的一对为 X/Y 坐标对. 例如，200-0 表示 X 坐标为 200，Y 坐标为 0。
E: 设置窗口形状为椭圆形而不是矩形. 此选项仅在同时指定了 W 和 H 时才有效.
R[w-h]: 设置窗口形状为圆角矩形. 例如，R30-30 表示每个角为 30x30 的椭圆。如果 w-h 省略，则使用 30-30。R 仅在同时指定了 W 和 H 时才有效。

矩形或椭圆形：如果指定了 W 和 H 选项，那么会设置窗口形状为矩形，且其左上角的坐标为首个（且唯一）的 X-Y 坐标对。但是，如果同时指定了 E 选项，那么会设置窗口形状为椭圆形而不是矩形。例如：WinSet, Region, 50-0 W200 H250 E, WinTitle。

多边形：如果 W 和 H 选项都没有指定，那么会设置窗口形状为由多个 X-Y 坐标对确定的多边形（每对坐标以窗口左上角为原点）。例如, 如果指定了三对坐标, 那么在多数时候窗口形状会被设置为三角形. 坐标对彼此间的相对顺序有时很重要. 此外，可以在 Options 中指定单词 Wind 从而使用缠绕法代替变换方法来确定多边形的形状。

如果设置失败, 则 ErrorLevel 被置为 1, 成功则为 0. 出现以下情况时会设置失败: 1) 目标窗口不存在; 2) Options 有一个或多个选项无效; 3) 指定了超过 2000 对坐标; 或 4) 指定的形状是无效的或不适用于目标窗口.

请参阅本页底部查看使用此命令的示例.

WinSet, Transparent, N, WinTitle

设置窗口为半透明状态. 指定 N 为介于 0 和 255 之间的数字来表示透明度: 0 表示完全透明, 255 表示完全不透明. 指定单词 OFF 可以完全关闭透明度. 与指定 255 的区别是, 这样可以提升性能并降低系统资源的占用.

Transparent 和 TransColor 的已知限制:

  • 对于没有标题栏且不含 置顶 属性的窗口没有效果. 对于 GUI 窗口, 可以在设置窗口透明度后才移除标题栏. 或者使用下面的属性让透明度生效：Gui -Caption +ToolWindow。
  • 在关闭透明度之前设置 "透明度" 为 255 可以避免像黑色背景的窗口的重绘问题. 如果窗口仍无法正确重绘, 那么请参阅 Redraw 了解可能的解决方法.
  • 要改变窗口现有的 TransColor, 可能需要在改变前关闭透明度.

提示：要让任务栏透明，请使用 WinSet, Transparent, 150, ahk_class Shell_TrayWnd。类似地, 要让开始菜单透明, 请参照此例:

DetectHiddenWindows, on
WinSet, Transparent, 150, ahk_class BaseBar  ; 要让开始菜单的子菜单透明, 还必须加上下面的代码.

要让系统中所有的或选择的菜单透明, 则让像下面这样的脚本保持运行. 注意尽管此脚本不能让它自己的菜单透明, 但可以让其他脚本的菜单透明:

#Persistent
SetTimer, WatchForMenu, 5
return  ; 自动运行段结束.

WatchForMenu:
DetectHiddenWindows, on  ; 才可以立即检测到菜单.
IfWinExist, ahk_class #32768
    WinSet, Transparent, 150  ; 使用前一行找到的窗口.
return

WinSet, TransColor, Color [N], WinTitle

让目标窗口中指定颜色的所有像素透明，这样可以让它后面的窗口内容显示出来。如果用户点击透明部分, 那么点击会 "穿透" 此窗口传递到它后面的窗口. 在 Color 中指定颜色名称或 RGB 值 (请参阅 颜色图表 进行了解或使用 PixelGetColor 的 RGB 模式). 此外, 要让目标窗口中符合指定颜色的部分半透明, 请在颜色参数后添加空格 (不是逗号) 和透明度等级 (0-255). 例如：WinSet, TransColor, EEAA99 150, WinTitle。

常用 TransColor 来创建屏幕显示 (OSD) 和其他视觉效果. 在 Gui 页面的底部 有一个屏幕显示的例子.

指定单词 OFF 可以完全关闭窗口的透明度. 下面两个语句功能是相同的:

WinSet, Transparent, Off, WinTitle
WinSet, TransColor, Off, WinTitle

已知限制: 请参阅 上面的 列表.

备注

除了上面明确指出的情况外, 此命令不会改变 ErrorLevel.

尽管 Windows 2000/XP 或更高版本中支持透明度, 但只有在 Windows XP 或更高版本中才能获取窗口的当前透明度设置 (通过 WinGet).

通过后面的代码可以取消脚本 SplashText 窗口的置顶状态:

WinSet, AlwaysOnTop, Off, My Splash Window Title

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinGet, WinHide, WinSetTitle, WinMove, WinActivate, Control

示例

WinSet, Transparent, 200, Untitled - Notepad ; 让窗口稍有点透明.
WinSet, TransColor, White, Untitled - Notepad ; 让白色部分透明.
WinSet, AlwaysOnTop, toggle, Calculator ; 切换计算器的置顶状态.

; 较长的例子:
; 这里是一些演示 "Transparent" 和
; "TransColor" 效果的一些热键.  注意: 如果您在鼠标悬停在设置了 TransColor 的窗口透明部分时
; 按下了其中一个热键,
; 那么热键会对在那个位置后面的窗口起作用!还有, Win+G 只有在
; Windows XP 上才有效果, 因为
; Windows 2000 中不支持获取透明度:

#t::  ; 使用 Win+T 来让鼠标光标下的颜色透明.
MouseGetPos, MouseX, MouseY, MouseWin
PixelGetColor, MouseRGB, %MouseX%, %MouseY%, RGB
; 似乎有必要首先关闭任何现有的透明度:
WinSet, TransColor, Off, ahk_id %MouseWin%
WinSet, TransColor, %MouseRGB% 220, ahk_id %MouseWin%
return

#o::  ; 使用 Win+O 来关闭鼠标下窗口的透明度.
MouseGetPos,,, MouseWin
WinSet, TransColor, Off, ahk_id %MouseWin%
return

#g::  ; 使用 Win+G 来显示鼠标下窗口的当前透明设置.
MouseGetPos,,, MouseWin
WinGet, Transparent, Transparent, ahk_id %MouseWin%
WinGet, TransColor, TransColor, ahk_id %MouseWin%
ToolTip Translucency:`t%Transparent%`nTransColor:`t%TransColor%
return

; "WinSet Region" 示例:
WinSet, Region, 50-0 W200 H250, WinTitle  ; 隐藏窗口在此矩形外的部分.
WinSet, Region, 50-0 W200 H250 R40-40, WinTitle  ; 与上面相同, 不过带有 40x40 的圆角.
WinSet, Region, 50-0 W200 H250 E, WinTitle  ; 椭圆形窗口
WinSet, Region, 50-0 250-0 150-250, WinTitle  ; 倒三角形窗口.
WinSet, Region,, WinTitle ; 将窗口恢复原来的形状.

; 这是更复杂的形状示例. 它在窗口中创建了可以看透的矩形洞.
; 下面指定了两个矩形: 一个外部的, 一个内部的每个矩形由 5 对
; X/Y 坐标组成, 因为首对是用来 "闭合" 每个矩形的重复坐标.
WinSet, Region, 0-0 300-0 300-300 0-300 0-0   100-100 200-100 200-200 100-200 100-100, WinTitle


WinSetTitle

改变指定窗口的标题。

WinSetTitle, NewTitle
WinSetTitle, WinTitle, WinText, NewTitle [, ExcludeTitle, ExcludeText]

参数

NewTitle

窗口的新标题. 如果只给出此参数, 那么使用 上次找到的窗口.

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

如果窗口所在的程序经常改变窗口的标题, 那么此命令对标题的修改只是暂时的.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinMove, WinGetActiveStats, WinGetActiveTitle, WinGetText, ControlGetText, WinGetPos, WinSet

示例

WinSetTitle, Untitled - Notepad, , This is a new title

; 另一个例子:
Run, notepad.exe
WinWaitActive, Untitled - Notepad
WinSetTitle, This is a new title  ; 使用前面 WinWaitActive 找到的窗口


WinShow

显示指定的窗口。

WinShow [, WinTitle, WinText, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

备注

默认情况下, WinShow 是唯一一个在任何时候都能检测到隐藏窗口的命令. 只有在 DetectHiddenWindows 设置打开时其他命令才能检测到隐藏窗口.

此命令仅对最上面的匹配窗口进行操作, 除非 WinTitle 为 ahk_group GroupName, 此时会影响组中所有窗口.

相关

WinHide, SetTitleMatchMode, DetectHiddenWindows, 上次找到的窗口

示例

Run, notepad.exe
WinWait, Untitled - Notepad
Sleep, 500
WinHide  ; 因为省略了所有参数, 所以它使用前面找到的窗口.
Sleep, 1000
WinShow


WinWait

等到指定的窗口出现。

WinWait [, WinTitle, WinText, Seconds, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinTitle 只有在 WinText, ExcludeTitle 或 ExcludeText 都存在时才能为空.

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

秒

超时前等待的秒数. 超时后设置 ErrorLevel 为 1. 留空表示无限期等待. 指定 0 等同于指定 0.5. 此参数可以为 表达式.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

命令超时后 ErrorLevel 被置为 1, 否则为 0.

备注

当匹配窗口出现后, 此命令将不再等待 Seconds 到期. 相反地, 它会立即设置 ErrorLevel 为 0, 更新 上次找到的窗口 并让脚本继续执行.

当此命令处于等待状态时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

如果其他 线程 改变了在此命令参数中使用的任何变量内容, 此命令会无视这些变化, 它会继续使用在开始等待时变量中原始的标题和文本.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinWaitActive, WinWaitClose, IfWinExist, IfWinActive, Process, SetTitleMatchMode, DetectHiddenWindows

示例

Run, notepad.exe
WinWait, Untitled - Notepad, , 3
if ErrorLevel
{
    MsgBox, WinWait timed out.
    return
}
else
    WinMinimize  ; 最小化 WinWait 找到的窗口.


WinWaitActive / WinWaitNotActive

等到指定的窗口处于活动或不活动状态.

WinWaitActive [, WinTitle, WinText, Seconds, ExcludeTitle, ExcludeText]
WinWaitNotActive [, WinTitle, WinText, Seconds, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

秒

超时前等待的秒数. 超时后设置 ErrorLevel 为 1. 留空表示无限期等待. 指定 0 等同于指定 0.5. 此参数可以为 表达式.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

命令超时后 ErrorLevel 被置为 1, 否则为 0.

备注

如果匹配窗口符合了命令的要求, 那么此命令不再等待 Seconds 到期. 相反地, 它会立即设置 ErrorLevel 为 0 并让脚本继续执行.

当 WinWaitActive 和 WinWaitNotActive 执行时如果符合条件的窗口是活动的, 那么它们都会更新 上次找到的窗口. 此外, 如果在 WinWaitActive 超时前符合条件的窗口变成活动窗口, 那么它会更新上次找到的窗口.

当此命令处于等待状态时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

如果其他 线程 改变了在此命令参数中使用的任何变量内容, 此命令会无视这些变化, 它会继续使用在开始等待时变量中原始的标题和文本.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinWait, WinWaitClose, IfWinExist, IfWinActive, SetTitleMatchMode, DetectHiddenWindows

示例

Run, notepad.exe
WinWaitActive, Untitled - Notepad, , 2
if ErrorLevel
{
    MsgBox, WinWait timed out.
    return
}
else
    WinMinimize  ; 最小化 WinWaitActive 找到的窗口.


WinWaitClose

等到指定的窗口消失。

WinWaitClose [, WinTitle, WinText, Seconds, ExcludeTitle, ExcludeText]

参数

WinTitle

窗口标题或识别目标窗口的其他条件。请参阅 WinTitle。

WinText

如果使用此参数, 那么它必须是目标窗口中单个文本元素的子字符串 (和内置的 Window Spy 工具显示的一样). 当 DetectHiddenText 的设置为 ON 时, 那么会检测到隐藏文本元素.

秒

超时前等待的秒数. 超时后设置 ErrorLevel 为 1. 留空表示无限期等待. 指定 0 等同于指定 0.5. 此参数可以为 表达式.

ExcludeTitle

标题中含有此参数值的窗口将被排除.

ExcludeText

文本中含有此参数值的窗口将被排除.

ErrorLevel

命令超时后 ErrorLevel 被置为 1, 否则为 0.

备注

每当指定的窗口消失后, 此命令不再等待 Seconds 到期. 相反地, 它会立即设置 ErrorLevel 为 0 并让脚本继续执行.

当此命令处于等待状态时, 可以通过 热键, 自定义菜单项 或 计时器 启动新的 线程.

如果其他 线程 改变了在此命令参数中使用的任何变量内容, 此命令会无视这些变化, 它会继续使用在开始等待时变量中原始的标题和文本.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时，才能检测到隐藏窗口。

相关

WinClose, WinWait, WinWaitActive, IfWinExist, IfWinActive, Process, SetTitleMatchMode, DetectHiddenWindows

示例

Run, notepad.exe
WinWait, Untitled - Notepad
WinWaitClose  ; 等待 WinWait 找到的窗口被关闭.
MsgBox, Notepad is now closed.


#AllowSameLineComments

在 v1.1.09 中移除：不再支持 AutoIt。

仅适用于 AutoIt v2 (.aut) 脚本: 允许注释和命令在同一行.

#AllowSameLineComments

在任何 AutoIt v2 (.aut) 脚本的 顶部 指定此指令会启用同行注释, 出于兼容性的考虑正常情况下这个功能是禁用的. 如果在脚本顶部外的其他地方使用, 那么在使用此指令后才支持同行注释.

示例

#AllowSameLineComments
Sleep, 1  ; 此注释是同行注释.


#ClipboardTimeout

改变当首次访问剪贴板失败后脚本会继续尝试访问剪贴板的持续时间。

#ClipboardTimeout Milliseconds

参数

Milliseconds

间隔长度，单位为毫秒。指定 -1 表示持续访问剪贴板. 指定 0 表示只访问一次. 没有使用此指令的脚本使用 1000 ms 的超时时间.

备注

一些应用程序让剪贴板长时间保持打开, 可能是要读写大量数据. 此时, 增加此设置的值可以让脚本在放弃并显示错误信息前等待较长的时间.

此设置适用于所有的剪贴板操作，这里举些最简单的例子：Var = %Clipboard% 和 Clipboard = New Text。

每当脚本处于等待剪贴板变得可用的状态时, 不能 运行新的 线程 且不会运行 计时器. 但是, 如果用户按下了 热键, 选择了 自定义菜单项 或执行例如按下按钮这样的 GUI 动作, 这些事件会被缓存至后面; 换句话说, 其子程序会在剪贴板变得可用后执行.

此指令还会使得在首次读取剪贴板数据失败后重新尝试访问 (在以前的版本中, 只会对打开的剪贴板重新尝试访问).

相关

Clipboard, Thread

示例

#ClipboardTimeout 2000


#CommentFlag

把脚本的注释符号从分号改为其他字符串。

#CommentFlag NewString

参数

NewString

用来作为新注释符号的一个或多个字符. 最多可指定 15 个字符.

备注

默认的注释符号为分号 (;).

注释符号用来表示它后面跟着的文本脚本不应该执行 (在脚本启动时注释不会被加载到内存中, 所以它们不影响执行的性能).

注释符号和命令在同一行时, 只有在注释符号的左边有至少一个空格或 tab 时, 它才会被视为注释符号的标记. 例如：

MsgBox, Test1 ; 这是注释.
MsgBox, Test2; This is not a comment and will be displayed by MsgBox.

相关

#EscapeChar

示例

#CommentFlag //  ; 改为 C++ 注释风格.


#ErrorStdOut

把阻止脚本运行的任何语法错误发送到标准输出而不显示在对话框中。

#ErrorStdOut

这样可以让类似 Textpad, SciTE, Crimson 和 EditPlus 这样的高级编辑器在语法错误发生时跳到有问题的行. 因为必须添加 #ErrorStdOut 指令到每个脚本中，所以最好设置您的编辑器在运行任何 AutoHotkey 脚本时使用命令行开关 /ErrorStdOut（请参阅较远的后面了解设置说明）。

尽管语法错误会被发送到标准输出 (stdout), 但是它们不会直接显示在命令提示符中. 不过, 可以通过管道或重定向捕获这样的输出. 例如：

"C:\Program Files\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "My Script.ahk" |more
"C:\Program Files\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "My Script.ahk" >"Syntax-Error Log.txt"

您还可以把输出直接传输到剪贴板, 只需下载 cb.zip (4 KB) 接着参照这个例子进行操作:

"C:\Program Files\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "My Script.ahk" |cb.exe

特殊编辑器的设置:

EditPlus:
在菜单栏选择 Tools > Configure User Tools.
点击按钮: Add Tool > Program
Menu Text: 由您决定
Command: C:\Program Files\AutoHotkey\AutoHotkey.exe
Argument: /ErrorStdOut "$(FilePath)"
Initial directory: $(FileDir)
Capture output: Yes

TextPad:
在菜单栏中选择 Configure > Preferences.
展开 Tools 条目.
点击 Add 按钮并选择 "Program".
复制并粘贴 (修改为您的路径): C:\Windows\System32\cmd.exe, 然后点击 OK.
三击列表框中新添加的项 (cmd.exe) 并将其重命名为您选择的名称 (例如 Launch Script).
点击 Apply.
选择左侧树中的新项并输入下列信息:
Command (应该已经填好): cmd.exe (或者加上完整路径)
Parameters (需要时修改为您的路径): /c ""C:\Program Files\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "$File""
Initial folder: $FileDir
选择下列框: 1) Run minimized; 2) Capture output.
点击 OK. 现在新添加的项应该出现在 Tools 菜单中了.

相关

FileAppend (因为它也可以发送文本到 stdout)

示例

#ErrorStdOut


#EscapeChar (及转义序列的说明)

改变脚本的转义符 (例如重音符与反斜线).

#EscapeChar NewChar

参数

NewChar

指定单个字符.

备注

转义符用来表明在其后紧跟着的字符不能像平常那样进行解释.

默认的转义符为重音符（`）。

转义序列 (当重音符为转义符时)

输入这些字符 | 得到这些字符
`, | , (原义的逗号). 注意: 在命令最后一个参数中的逗号不需要转义, 因为程序知道把它们作为原义处理. 对于 MsgBox 所有参数同样如此, 因为它会智能的处理逗号.
`% | % (原义的百分号)
`` | ` (原义的重音符; 即两个连续的转义符产生单个原义字符)
`; | ; (原义的分号). 注意: 仅 在分号的左边有空格或 tab 才需要. 如果没有, 那么它可以被正常识别而不需要转义.
`:: | :: (原义的双冒号). 在 v1.0.40+, 不再需要对它们进行转义.
`n | 新行 (换行/LF)
`r | 回车 (CR)
`b | 退格
`t | tab (最典型的水平移位)
`v | 垂直 tab -- 对应的 Ascii 值为 11. 在一些应用程序中可以通过键入 Control+K 让它显示出来.
`a | 警告 (铃) -- 对应的 Ascii 值为 7. 在一些应用程序中可以通过键入 Control+G 让它显示出来.
`f | 进纸 -- 对应的 Ascii 值为 12. 在一些应用程序中可以通过键入 Control+L 让它显示出来.
发送 | 以默认 (非原始) 模式使用 Send 命令 或 热字串 时, 像 {}^!+# 这些字符具有特殊含义. 因此, 要使用它们的原义字符, 必须把它们包围在大括号中. 例如：Send {^}{!}{{}。
"" | 在 表达式 中, 原义字符串内的两个连续的引号被解析为单个原义的引号. 例如：Var := "The color ""red"" was found."。

相关

还有下面这些极少使用的指令; 它们的用法如这些例子所示:

#DerefChar #  ; 把默认的引用符号 % 改为此符号.
#Delimiter /  ; 把默认的分隔符号逗号改为此符号.

示例

#EscapeChar \  ; 把默认的重音符 (`) 改为反斜线.


#MaxMem

设置每个变量可使用的最大内存兆数。

#MaxMem Megabytes

参数

Megabytes

设置每个 变量 最多允许使用的兆字节数. 大于 4095 的值会被视为 4095. 小于 1 的值会被视为 1.

备注

如果脚本中未使用此指令, 那么它会表现的就像此设置为 64 那样.

限制每个变量的大小是为了防止有问题的脚本消耗完系统中所有可用内存. 增加或降低此限制不会影响脚本的性能, 也不会改变脚本实际使用的内存量 (不过在 WinGetText 和 ControlGetText 的情况中, 增加 #MaxMem 设置可以获取更多的文本).

此设置是全局的, 这意味着只需要使用一次 (在脚本的任意位置) 就会影响整个脚本.

此设置只是限制变量的自动扩充行为. 它不会影响 VarSetCapacity。

相关

VarSetCapacity, 变量, Sort, WinGetText, ControlGetText, #MaxThreads

示例

#MaxMem 256  ; 允许每个变量使用 256 MB.


#NoEnv

#NoEnv [v1.0.43.08+]

不检查空变量是否为环境变量（建议所有新脚本使用）。

#NoEnv

在脚本的任意位置指定 #NoEnv 这行语句可以避免脚本检查空变量是否为环境变量。例如：

#NoEnv
MsgBox %WinDir%

上面这个例子中不会检索 "WinDir" 环境变量（尽管这可以通过在脚本顶部附近加上 WinDir := A_WinDir 来解决）。

建议所有的新脚本使用 #NoEnv，因为：

  1. 每当表达式或命令中使用空变量时, 这样可以显著提升性能. 在 DllCall 中使用没有加引号的参数类型 (例如 int 与 "int") 时性能也能得到提升.
  2. 它能避免由于环境变量意外地和脚本中使用的变量名称相同时引起的脚本错误.
  3. AutoHotkey v2 中把这种行为设为默认的.

为了自然过渡到 #NoEnv, 添加了内置变量 Comspec 和 ProgramFiles. 它们与同名的环境变量包含了相同的内容.

当 #NoEnv 有效时, 脚本中应该使用 EnvGet 来获取环境变量或使用内置变量, 例如 A_WinDir.

相关

EnvGet, Comspec, ProgramFiles, A_WinDir


#Persistent

让脚本持久运行（即直到用户关闭或遇到 ExitApp）。

#Persistent

如果在脚本的任意位置使用此指令, 那么脚本会在自动执行段 (脚本的顶部) 结束后保持运行. 它可以用于当脚本包含 计时器 和/或 自定义菜单项 却不包含 热键, 热字串 或使用任何的 OnMessage() 或 Gui 的时候.

如果添加此指令到现有的脚本中, 您可能需要把一些或全部的 Exit 改为 ExitApp. 这是由于 Exit 不会终止持续运行的脚本; 它只会终止 当前线程.

在 v1.0.16+, 此指令同时也让脚本单实例运行. 要覆盖这种行为或改变单实例的方式, 请参阅 #SingleInstance.

相关

#SingleInstance, SetTimer, Menu, Exit, ExitApp

示例

#Persistent


存档变更

这个页面包含了由Chris Mallett开发的原始AutoHotkey分支的变更历史。

对于最近的更新，请参阅变更和新功能。

1.0.48.05 - September 25, 2009

Fixed crash of SendMessage and PostMessage when wParam or lParam is omitted (broken by 1.0.48.04). [thanks Lexikos]

1.0.48.04 - September 25, 2009

Fixed StringSplit to work properly inside functions of compiled scripts (broken by 1.0.35.01). [thanks engunneer & Lexikos]

Fixed SendPlay not to wait for the release of the Windows key prior to sending an "L" keystroke (broken by 1.0.48.01). [thanks Lexikos]

Fixed A_EndChar to be valid when the B0 option is present, and to be empty when there is no ending character (broken by 1.0.44.09). [thanks Al2000]

Fixed FormatTime to yield a valid time of day even when the specified month is out-of-range (broken by 1.0.48.00). [thanks silveredge78]

Fixed FileCreateDir to support a leading backslash even when it is the only backslash; e.g. \dir. [thanks jaco0646]

Fixed GuiControl/GuiControlGet/Gui/SendMessage to work reliably even when they trigger a callback or OnMessage function. [thanks Lexikos]

Fixed RegExMatch() not to produce too few replacements when an empty-string match is followed by a non-empty-string match.

Changed While() to be recognized as a loop rather than a function. [thanks Crash&Burn]

Improved UrlDownloadToFile to support FTP and Gopher. [thanks Lexikos]

Improved the stdout/asterisk mode of FileAppend to write immediately rather than lazily to standard output. [thanks Lexikos]

Added full support for if % expression. [thanks kenomby]

1.0.48.03 - May 3, 2009

Fixed ListLines On not to erase the most recent log entry in the line history. [thanks Lexikos]

Fixed ListView to respond properly to mouse dragging when timers are running. [thanks Solar]

Fixed key-up hotkeys so that if one is created while its key is being held down, the release of the key doesn't trigger the wrong hotkey. [thanks Peter & engunneer]

1.0.48.02 - April 19, 2009

Changed and fixed Gosub and GroupActivate so that when a function calls an external/public subroutine, that subroutine will treat all dynamic variables as globals, and will have outside-of-function GUI behavior. [thanks kenomby & Lexikos]

Improved performance of True/False/A_EventInfo in expressions by treating them as integers vs. strings.

1.0.48.01 - April 15, 2009

Changed: For Windows Vista and later, hotkeys that include the Windows key (e.g. #a) will wait for LWin and RWin to be released before sending any text containing an "L" keystroke. This prevents such a hotkey from locking the PC. This behavior applies to all sending modes except SendPlay (which doesn't need it) and blind mode.

Fixed A_LoopFileExt to be blank for any filename having no extension but a period in its pathname. [thanks Yek-Toho-Tua].

Fixed the assignment of integers that are 19 or 20 characters long to work as they did prior to v1.0.48. [thanks Laszlo & Lexikos]

Fixed function definitions to work properly inside a block. [thanks rmarko]

Improved performance of A_Index in expressions by treating it as an integer rather than a string.

Improved performance of if var [not] in/contains. [developed by Lexikos]

Improved ListLines with an option to turn line-logging Off or On. [thanks kenomby & ruespe]

1.0.48 - February 25, 2009

Compatibility: The change most likely to affect backward compatibility is that floating point numbers stored in variables now have higher precision. Scripts that rely on tiny differences in precision would either need to be reviewed and updated, or have their compatibility improved by using SetFormat Float (e.g. SetFormat, Float, 0.6) anywhere in the script. SetFormat Float disables the higher precision, but gives up some of the new, faster floating point performance.

Performance: The main theme of this release is faster performance. Almost all scripts should run faster -- especially those that make heavy use of expressions and integer math/comparisons (which may run up to three times as fast). To achieve the full benefit, a script either should avoid using SetFormat or should use SetFormat's fast mode.

Performance improvements

Expressions and function calls are compiled more heavily, making them much faster (especially complex integer expressions, including those with commas).

Binary numbers are cached for variables to avoid conversions to/from strings. This makes numerical operations involving variables much faster.

Literal integers in expressions and math/comparison commands are replaced with binary integers, which makes them faster; e.g. X+5 and if x > 5.

LOOPs, IFs, and ELSEs that have blocks (braces) are faster due to skipping the opening '{'. A side-effect is that the '{' is omitted from ListLines.

Thread-creation performance is improved, which should help rapid-fire threads in OnMessage(), RegisterCallback(), and GUI events.

Changes that might affect existing scripts (other than higher-precision floating point described at the top)

When SetFormat, Integer, Hex is in effect, assigning a literal decimal integer to a variable also converts it to hex. Usually this is only a display issue.

For OnMessage() performance, the message number and HWND arrive as standard numbers rather than appearing unconditionally as hex. Usually this is only a display issue.

To achieve various improvements in performance, scripts now use slightly more memory (proportionate to the number of variables and expressions).

Changed and fixed if var is time and other uses of YYYYMMDDHHMISS date-time stamps to recognize that months outside the range 1-12 are invalid. [thanks Nick]

Changed and improved dynamic function calling to allow passing more parameters than defined by a function, in which case the parameters are evaluated but discarded. [developed by Lexikos]

Other improvements

Added function IsFunc(), which indicates whether a function may be called dynamically. [developed by Lexikos]

Added the while-loop, which repeats its commands until its expression evaluates to false. [developed by Lexikos]

Added an assume-static mode for functions. [developed by Lexikos]

Added built-in variables A_IsPaused and A_IsCritical. [developed by Lexikos]

Improved NumPut() to support UInt64 like DllCall(). [thanks Sean]

Improved mouse wheel support by adding WheelLeft and WheelRight as hotkeys and supporting them in Send, Click, and related commands. However, WheelLeft/Right has no effect on operating systems older than Windows Vista. [developed by Lexikos]

Upgraded compiled script compressor from UPX 3.00 to 3.03.

Fixes

Fixed inability to use MsgBox's timeout parameter when the "Text" parameter had an expression containing commas.

Fixed Menu, Delete, Item-that's-a-submenu not to disrupt the associated submenu. [thanks animeaime & Lexikos]

Fixed the GUI Hotkey control to return usable hotkey names even for dead keys (e.g. "^" instead of Zircumflex). [thanks DerRaphael]

Fixed RegDelete so that it won't delete an entire root key when SubKey is blank. [thanks Icarus]

Fixed registry loops to support subkey names longer than 259 (rare). In prior versions, such subkeys would either be skipped or cause a crash. [thanks Krzysztof Sliwinski & Eggi]

Fixed FileSelectFolder by providing an option to make it compatible with BartPE/WinPE. [thanks markreflex]

Fixed window/control IDs (HWNDs), which in rare cases wrongly started with 0xFFFFFFFF instead of just 0x. [thanks Micahs]

Fixed inability of Send commands to use the Down/Up modifiers with the "}" character. [thanks neovars]

1.0.47.06 - March 9, 2008

Fixed crash when a function was called concurrently with an optional ByRef parameter omitted by one thread but not omitted by the other. [thanks DeathByNukes]

Fixed Menu, Tray, MainWindow to enable the menu items in the main window's View menu. [thanks Lexikos]

Added dynamic function calling. [developed by Lexikos]

1.0.47.05 - November 21, 2007

Fixed the Sort command: 1) fixed the "function" option not to misbehave when it's the last option in the list; 2) fixed the "unique" option so that when the delimiter is CRLF, the last item can be detected as a duplicate even when it doesn't end in CRLF; 3) fixed the "unique" option not to append a trailing delimiter when the last item is a duplicate. [thanks Roland]

Fixed RegExMatch() and RegExReplace() to yield correct results even when Haystack and OutputVar are both the same variable. [thanks Superfraggle]

Fixed inability to pass a parameter that is "a variable to which ClipboardAll has been assigned". [thanks Joy2DWorld & Lexikos]

Updated RegEx/PCRE from 7.0 to 7.4. For a summary of the major changes, see www.pcre.org/news.txt. For full details of every change and fix, see www.pcre.org/changelog.txt.

Added GUI control "Tab2" that fixes rare redrawing problems in the original "Tab" control (e.g. activating a GUI window by clicking on a control's scrollbar). The original Tab control is retained for backward compatibility because "Tab2" puts its tab control after its contained controls in the tab-key navigation order. [thanks Xander]

1.0.47.04 - August 28, 2007

Fixed key-up hotkeys like a up:: not to block the pressing of the "a" key unless the hotkey's #IfWin criteria are met. [thanks Roland]

Fixed Round(Var, NegativeNumber), which in rare cases was off by 1. [thanks Icarus]

Fixed crash of scripts that end in a syntax error consisting of an orphaned IF-statement (broken by 1.0.47.00). [thanks msgbox of the German forum]

Eliminated the "GetClipboardData" error dialog. Instead, an empty string is retrieved when the data cannot be accessed within the #ClipboardTimeout period. [thanks ManaUser & Sean]

Changed GUI checkboxes and radio buttons to default to "no word-wrap" when no width, height, or CR/LF characters are specified. This solves display issues under certain unusual DPI settings. [thanks Boskoop]

1.0.47.03 - August 1, 2007

Fixed expressions to allow literal negative hexadecimal numbers that end in "E"; e.g. fn(-0xe). [thanks Laszlo]

Fixed block syntax to allow a function-call immediately to the right of a '}'. [thanks Roland]

1.0.47.02 - July 19, 2007

Fixed the Number option of Edit controls to properly display a balloon tip when the user types something other than a digit. [thanks tfcahm]

Fixed WM_TIMER not to be blocked unless it's posted to the script's main window. [thanks tfcahm]

Fixed wildcard hotkeys not to acquire tilde behavior when the same hotkey exists in the script with a tilde. [thanks Lexikos]

Fixed declaration initializers not to retain whitespace at the end of literal numbers. Also, they now allow spaces between a closing quote and the next comma. [thanks Hardeep]

1.0.47.01 - July 8, 2007

Fixed RunAs not to crash or misbehave when a domain is specified. [thanks Markus Frohnmaier]

Changed relational operators to yield integers even when the inputs are floating point; e.g. 1.0 < 2.0 yields 1 vs. 1.0. [thanks Lexikos]

1.0.47 - June 19, 2007

Added support for function libraries, which allow a script to call a function in an external file without having to use #Include.

Added RegisterCallback(), which creates a machine-code address that when called, redirects the call to a function in the script. [developed by Jonathan Rennison (JGR)]

Added NumGet() and NumPut(), which retrieve/store binary numbers with much greater speed than Extract/InsertInteger.

Improved Sort with an option to do custom sorting according to the criteria in a callback function. [thanks Laszlo]

Improved OnMessage() with an option to allow more than one simultaneous thread. [thanks JGR]

Improved Critical with an option to change the message-check interval, which may improve reliability for some usages. [thanks Majkinetor and JGR]

Changed Critical to put SetBatchLines -1 into effect.

Changed the error messages produced by #ErrorStdOut to contain a space before the colon. [thanks Toralf]

Fixed OnMessage() functions that return one of their own local variables to return the number in that variable, not 0.

Fixed potential crashing of built-in variables that access the registry (e.g. A_AppData, A_Desktop, A_MyDocuments, A_ProgramFiles). [thanks Tekl]

1.0.46.17 - May 31, 2007

Fixed A_UserName (broken by 1.0.46.16).

1.0.46.16 - May 30, 2007

Fixed Gui, Tab, TabName when used after a previous Gui Tab. [thanks Toralf]

Improved SetTimer to treat negative periods as "run only once". [thanks Majkinetor]

Added GuiControlGet Hwnd, which is a more modular/dynamic way to retrieve a control's HWND. [thanks Majkinetor]

Added built-in variables A_ThisLabel and A_ThisFunc, which contain the names of the currently-executing label/function. [thanks Titan & Majkinetor]

1.0.46.15 - May 9, 2007

Fixed GuiControl, GuiControlGet, and Gui ListView/TreeView to support static variables and ByRefs that point to globals/statics. [thanks Peter]

Fixed FileInstall causing the Random command to become non-random in compiled scripts. [thanks Velocity]

Reduced the size of compiled scripts by about 16 KB due to UPX 3.0. [thanks to atnbueno for discovering the optimal command-line switches]

1.0.46.14 - May 2, 2007

Added the "require administrator" flag to the installer to avoid a warning dialog on Windows Vista. [thanks Roussi Nikolov]

1.0.46.13 - May 1, 2007

Fixed hotkeys like *x to fire even when x is also a hotkey that is prevented from firing due to #IfWin. [thanks Joy2DWorld & Engunneer]

Improved optional parameters to accept quoted/literal strings as default values.

Improved ByRef parameters with the ability to be optional (i.e. they may accept default values). [thanks Corrupt]

1.0.46.12 - April 24, 2007

Fixed inability to recognize a literal scientific notation number that begins with 0, such as 0.15e+1. [thanks Laszlo]

1.0.46.11 - April 23, 2007

Fixed inability to have a function-call as the first item in certain comma-separated expressions. [thanks Majkinetor]

Fixed WinTitles like ahk_id %ControlHwnd% in ControlGet's FindString/Choice/List, and Control's Add/Delete/Choose. [thanks Freighter & PhiLho]

Improved floating point support to recognize scientific notation; e.g. 1.2e-5 (the decimal point is mandatory). Also improved "SetFormat Float" with an option to output in scientific notation. [thanks Laszlo]

1.0.46.10 - March 22, 2007

Fixed StringSplit inside assume-local functions so that it creates a local array even when OutputArray0 exists as a global but not a local. [thanks KZ]

Improved ListView's item-changed notification ("I") to indicate via ErrorLevel whether the item has been selected/deselected, focused/unfocused, and/or checked/unchecked. [thanks foom]

Added an additional layer of protection to compiled scripts. It is recommended that scripts containing sensitive data or source code be recompiled with the /NoDecompile switch.

1.0.46.09 - March 4, 2007

Fixed := deep inside expressions when used to assign the result of a recursive function to a local variable (broken by 1.0.46.06). [thanks Laszlo]

Fixed inability to pass certain ternary expressions to ByRef parameters. [thanks Titan]

Fixed GuiControlGet, OutputVar, Pos so that it doesn't make the OutputVar blank. [thanks PhiLho]

Changed and fixed continuation sections so that the "Comment" option doesn't force the LTrim option into effect. [thanks Titan]

Changed the Terminal Server Awareness flag back to "disabled" on AutoHotkey.exe and compiled scripts. This improves flexibility and backward compatibility (see discussion at forum).

1.0.46.08 - February 7, 2007

Fixed unreliability of ComSpec and environment variables on Windows 9x (broken by v1.0.46.07). [thanks Loriss]

Changed: When AutoHotkey.exe is launched without a script specified, it will now run (or prompt you to create) the file AutoHotkey.ahk in the My Documents folder. The only exception is when AutoHotkey.ini exists in the working directory, in which case it uses the old behavior of executing that file.

Improved DllCall to support an integer in place of the function name, which is interpreted as the address of the function to call. [thanks Sean]

1.0.46.07 - January 23, 2007

Fixed crash of illegally-named dynamic variables on the left of an equal-sign assignment (broken by v1.0.45). [thanks PhiLho]

Fixed FileMoveDir's "Option 2" to work properly even when the directory is being both renamed and moved. [thanks bugmenot]

Fixed inability to pass a variable ByRef if that same expression changed it from empty to non-empty (when #NoEnv is absent). [thanks Joy2DWorld]

Changed DllCall's A_LastError to reflect only changes made by the script, not by AutoHotkey itself. [thanks Azerty]

1.0.46.06 - January 16, 2007

Applied minor fixes and improvements to regular expressions by upgrading from PCRE 6.7 to 7.0. One of the most notable improvements is the `a option, which recognizes any type of newline (namely `r, `n, or `r`n). Similarly, the \R escape sequence means "any single newline of any type". See also: Full PCRE changelog

Changed and fixed all Control commands and StatusBarWait to obey SetTitleMatchMode RegEx as documented.

Changed RegExReplace() to return the original/unaltered string rather than "" when an error occurs.

Changed: Enabled the Terminal Server Awareness flag on AutoHotkey.exe and compiled scripts.

Improved performance when assigning large strings returned from user-defined functions. [thanks Laszlo]

1.0.46.05 - January 4, 2007

Fixed the Input command to allow named end keys like {F9} to work even when the shift key is being held down (broken by v1.0.45). [thanks Halweg]

Fixed inability of "Gui Show" to focus the GUI window when the tray menu is used both to reload the script and to show the GUI window. [thanks Rnon]

Fixed inability to pass some types of assignments (:=) to a ByRef parameter. [thanks Laszlo]

1.0.46.04 - January 2, 2007

Fixed inability to pass the result of an assignment (:=) to a ByRef parameter. [thanks Titan]

1.0.46.03 - December 18, 2006

Fixed ListView's floating point sorting to produce the correct ordering. [thanks oldbrother/Goyyah/Laszlo]

1.0.46.02 - December 17, 2006

Fixed environment variables to work properly as input variables in various commands such as StringLen and StringReplace (broken by 1.0.44.14). [thanks Camarade_Tux]

1.0.46.01 - December 15, 2006

NOTE: Although this release has been extensively tested, several low-level enhancements were made. If you have any mission-critical scripts, it is recommended that you retest them and/or wait a few weeks for any bugs to get fixed.

Fixed comma-separated declaration initializers such as local x = 1, y = 2 to work even when immediately below an if/else/loop statement.

Fixed comma-separated expressions so when the leftmost item is an assignment, it will occur before the others rather than after. [thanks Laszlo]

Changed and fixed function-calls so that any changes they make to dynamic variable names, environment variables, and built-in variables (such as Clipboard) are always visible to subsequent parts of the expression that called them.

Changed: When a multi-statement comma is followed immediately by a variable and an equal sign, that equal sign is automatically treated as a := assignment. For example, all of the following are assignments: x:=1, y=2, a=b=c.

Changed comma-separated expressions to produce the following effects: 1) the leftmost /= operator becomes true divide rather than EnvDiv; 2) blank values are not treated as zero in math expressions (thus they yield blank results).

Improved the performance of expressions by 5 to 20% (depending on type).

Improved the new assignment operators such as .= to support the Clipboard variable (even in comma-separated expressions).

Improved the .= operator so that it doesn't require a space to its left.

Improved GUI controls to accept static variables as their associated variables (formerly only globals were allowed).

Added option HwndOutputVar to Gui Add, which stores a control's HWND in OutputVar. [thanks Corrupt & Toralf]

1.0.46 - November 29, 2006

NOTE: Although this release has been extensively tested and is not expected to break any existing scripts, several low-level enhancements were made. If you have any mission-critical scripts, it is recommended that you retest them and/or wait a few weeks for any bugs to get fixed.

Added function SubStr(), which retrieves the specified number of characters at the specified position in a string.

Added assignment operators //=, .=, |=, &=, ^=, >>=, and <<=, which can be used anywhere in expressions. For example, Var .= "abc" appends the string "abc" to Var's current contents.

Added full support in expressions for the operators :=, ++, --, +=, -=, *=, and /= (formerly, they could be used only as the leftmost operator on a line). All assignment operators (especially ++ and --) behave in a C-like way when their result is used by some other operator.

Added the ternary operator (?:), which is a shorthand replacement for the if-else statement. For example, var := x>y ? 2 : 3 assigns the value 2 if x is greater than y; otherwise it assigns 3.

Added support for comma-separated expressions, which allow a single line to contain multiple assignments, function calls, and other expressions. [thanks PhiLho & Titan]

Improved variable declarations to support initialization on the same line. Note: A static variable's initialization occurs only once, before the script begins executing.

Improved line continuation to support all expression operators. For example, a line that starts with "?" or "+" is automatically appended to the line above it.

Improved performance of operators "." and ".=" to be as fast as the percent-sign method of appending a string.

Improved expressions to allow more types of consecutive unary operators such as !!Var. [thanks Laszlo]

Changed Critical to check messages less often (20 vs. 10ms), which improves the reliability of frequently-called OnMessage functions. [thanks Majkinetor]

Changed: A variable named simply "?" is no longer valid in expressions due to the new ternary operator.

Fixed hotkeys to support ::: (colon as a hotkey) and : & x (colon as a hotkey prefix).

Fixed the installer to remove psapi.dll from the AutoHotkey folder (except on Windows NT4). This avoids a conflict with Internet Explorer 7. [thanks to all who reported it]

1.0.45.04 - November 15, 2006

Fixed crash on Windows 9x when a script doesn't actually run (e.g. due to syntax error) (broken by v1.0.45). [thanks rogerg]

Changed Control Style|ExStyle to report ErrorLevel 0 vs. 1 when the requested style change wasn't necessary because it was already in effect.

Improved #Include to support %A_AppData% and %A_AppDataCommon%. [thanks Tekl]

1.0.45.03 - November 12, 2006

Fixed file-pattern loops not to crash when recursing into paths longer than 259 characters. In addition, such paths and files are now ignored (skipped over) by file-pattern loops, FileSetAttrib, and FileSetTime. [thanks PhilR]

Fixed functions that call themselves and assign the result to one of their own locals (broken by v1.0.45). [thanks bjennings]

Fixed crash of scripts containing regular expressions that have compile errors. [thanks PhiLho]

Fixed GuiControl not to convert checkboxes into 3-state unless requested. [thanks JBensimon]

Changed UrlDownloadToFile to announce a user-agent of "AutoHotkey" to the server rather than a blank string. [thanks jaco0646]

Improved continuation sections to support semicolon comments inside the section via the option-word Comments.

1.0.45.02 - November 8, 2006

Fixed StringUpper and StringLower to work when OutputVar is the clipboard (broken by v1.0.45). [thanks songsoverruins]

Fixed the hotkeys ~Alt, ~Control, and ~Shift to fire upon press-down rather than release (broken by v1.0.44).
Background: Without the tilde, Alt/Control/Shift fire upon release to avoid taking over both the left and right key. But a specific left/right hotkey like LAlt or RShift fires upon press-down.

1.0.45.01 - November 7, 2006

Fixed FileReadLine and FileSelectFile not to crash or misbehave when other threads interrupt them (broken by v1.0.45). [thanks toralf]

Fixed RegExMatch() so that when there's no match, named subpatterns are properly set to "" in the output array. [thanks PhiLho]

Fixed RegExMatch()'s "J" option to properly write duplicate named subpatterns to the output array. [thanks PhiLho]

Changed SetWorkingDir and #Include DirName to succeed even for a root directory such as C: that lacks a backslash.

Improved DllCall() to display a warning dialog if the called function writes to a variable of zero capacity.

1.0.45 - November 4, 2006

NOTE: Although this release has been extensively tested and is not expected to break any existing scripts, several low-level performance enhancements were made. If you have any mission-critical scripts, it is recommended that you retest them and/or wait a few weeks for any bugs to get fixed.

Added support for regular expressions via RegExMatch(), RegExReplace(), and SetTitleMatchMode RegEx. [thanks Philip Hazel & PhiLho]

Improved performance and memory utilization of StringReplace.

Improved performance of the := operator for expressions and functions involving long strings.

Improved ControlClick with a new option "NA" that avoids activating the target window (this mode also improves reliability in some cases). In addition, it's been documented that SetControlDelay -1 can improve the reliability of ControlClick in some cases. [thanks nnesori]

Changed GUI buttons to default to "no word-wrap" when no width, height, or CR/LF characters were specified. This may solve button display issues under some desktop themes.

Fixed "Transform HTML" for the following characters: &`n><

Fixed misinterpretation of lines starting with "if not is" such as "if not IsDone".

Fixed inability of "Gui Show" to move a window vertically downward to where its bottommost row of pixels is now.

Fixed inability to use GroupActivate as the only line beneath an IF or ELSE.

Fixed inability of the Input command to differentiate between end-keys enclosed in braces and their (un)shifted counterparts; e.g. '{' vs. '['. [thanks Laszlo]

Visit www.autohotkey.com/changelog/ for even older changes.


高级热键功能——鼠标和键盘快捷键

高级热键功能

键盘上 一些很容易按到的键 却不经常使用. 我们要让这些键变得更有用. 例如, 如果您很少使用右 ALT 键, 那么可以让它执行常用的操作:

RAlt::
MsgBox You pressed the right ALT key.
return

您甚至可以在保持右 ALT 键原来的功能的同时, 把它作为其他热键的 "前缀" 键来实现上述功能. 在下面的例子中, 右 ALT 作为前缀键, 这让它自动地像平常那样修饰其他 所有 的按键. 但如果您按下并放开右 Alt 期间没有按下其他键, 那么它的热键功能 (上面的例子) 会立即生效:

RAlt & j::AltTab

修饰符 不再局限于 CTRL, ALT, SHIFT 和 WIN; 您可以使用 任意 两个按键或鼠标按钮组成自定义热键. 例如: 按住 Numpad0 且按下 Numpad1 来执行热键 (语法: Numpad0 & Numpad1::); 按住 CapsLock 并按下另一个键或点击鼠标右键 (语法: CapsLock & RButton::). 此时 (运行热键时), CapsLock 键的状态 (大写或小写) 不会发生改变. 更多细节请参阅 自定义组合键.

使用鼠标滚轮 (或您选择的其他任意键 ) 完全代替 Alt-Tab. 点击滚轮来显示窗口选择菜单, 转动滚轮来浏览菜单. 当 Alt-Tab 菜单没有出现时滚轮仍保持正常的功能. 语法:

MButton::AltTabMenu
WheelDown::AltTab
WheelUp::ShiftAltTab

让键盘按键 成为 鼠标按钮, 或当您按住某个键或鼠标按钮时持续重复某个动作. 请参阅 重映射页面 查看示例.

让您的热键上下文相关：让最容易使用的热键根据不同的窗口类型执行适合的操作。在下面的例子中, 右 Control 键会根据活动窗口是记事本还是计算器执行不同的操作:

#IfWinActive ahk_class Notepad
RControl::WinMenuSelectItem, , , File, Save  ; 在记事本中保存当前文件.

#IfWinActive Calculator
RControl::Send, ^c!{tab}^v  ; 复制计算器的结果到之前的活动窗口.

请参阅 #IfWinActive 了解详情.

热字串: 实现扩展缩写的功能. 不需要经过特殊的训练或脚本编写经验. 例如, 包含下列语句的脚本执行后, 在您输入 ceo, cfo 和 btw 时会自动扩展它们:

::ceo::Chief Executive Officer
::cfo::Chief Financial Officer
::btw::by the way

(更多细节)

如果您对游戏有兴趣:

  • 别人拼血流汗时, 您只需动动手指, 就可执行一系列复杂的操作. 因为这些操作可以定义到几乎 任意键 上, 包括单个字母, 方向键, 数字键, 甚至是修饰键 (CTRL/ALT/WIN/SHIFT).
  • 创建鼠标热键, 包括鼠标滚轮按钮 (MButton) 和往上/往下/往左/往右转动滚轮 (WheelUp, WheelDown, WheelLeft 和 WheelRight). 您还可以把键盘键和鼠标按钮组合使用. 例如，按住 Ctrl 时点击鼠标右键可以写为 ^RButton::。
  • 创建 "穿透" 热键. 例如，点击鼠标左键一方面触发热键，另一方面点击仍可以被发送到游戏中（语法：~LButton::）。
  • 使用例如 PixelSearch, PixelGetColor 和 ImageSearch 的命令可以自动化游戏操作.
  • 使用 键盘钩子 来实现热键, 当游戏占用较多 CPU 资源时, 这种方法会比其他方法响应的更及时. 使用钩子还可以解除在游戏中只有某些按键才可以 "映射" 到游戏动作上的限制.

请参阅 热键 部分了解更多细节.


许可

Software License

GNU GENERAL PUBLIC LICENSE

Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.

6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.

7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS


AutoHotkey 指南——启动程序或文档（续）

指南 - 启动程序或文档 (续)

要最小化, 最大化或隐藏启动程序或文档, 请参考下面的 热键 子程序, 其中设置 Win+Z 热键来运行两个记事本实例, 首个为最大化启动而第二个为最大化.

#z::
Run, Notepad, , max
Run, Notepad, , min
return

要在启动程序时使用指定的工作目录, 请参考这个 Win+C 热键, 它在指定目录中创建命令提示符窗口.

#c::Run, %comspec% /k, C:\My Documents

在上面的例子中, comspec 是在一般系统中会被解析为 C:\Windows\system32\cmd.exe 的内置变量.

要传递参数, 需要在程序或文档名称后加上它们, 例如:

Run, %comspec% /c dir >"Output File.txt", C:\My Documents
Run, Notepad.exe "C:\My Documents\Address List.txt"
Run, "%A_AhkPath%" "C:\Scripts\Test Script.ahk" param1 "param2 with spaces" param3

在上面的第二和第三个例子中, 其中含空格的参数必须包围在引号中, 这一般是最可靠的方式. 与之相比, 工作目录即使含有空格也不应该包围在引号中, 例如上面的首个例子.

还支持某些被称为 系统动词 的特殊单词. 下面的首个例子在资源管理器中打开指定文件的属性对话框. 第二个例子打印指定的文档.

Run, properties "C:\Address List.txt"
Run, print "C:\Address List.txt"

最后, RunWait 会设置内置变量 ErrorLevel 为它启动的程序的退出代码 (它还会等待程序结束并关闭). 例如在下面的例子中, 因为 cmd.exe 中遇到了问题, 所以会显示非零的 ErrorLevel.

RunWait, %comspec% /c dir c:\NonExistent.txt, , hide
MsgBox, %ErrorLevel%

想了解关于启动程序和文档的更多内容, 请参阅 Run/RunWait.

返回指南目录


EnvAdd

设置变量的值为它自身加上给定的值的和（还可以从日期-时间值中增加或减去时间）。同义于：var += value。

EnvAdd, Var, Value [, TimeUnits]
Var += Value [, TimeUnits]
Var++

参数

Var

要运算的 变量 名.

值

任何整数, 浮点数或 表达式.

TimeUnits

如果使用此参数, 则此参数指示命令如何添加 Value 到 Var: 把 Var 视为 YYYYMMDDHH24MISS 格式中的日期时间戳并且把 Value 视为要添加的整数或浮点数单元 (使用负数来执行减法运算). TimeUnits 可以为 Seconds, Minutes, Hours 或 Days (或仅使用这些单词的首个字母).

如果 Var 是空变量, 则使用当前时间代替. 如果 Var 包含无效的时间戳或早于 1601 的年份或 Value 不是数值, 则 Var 会被置空来表示此问题.

内置变量 A_Now 包含了 YYYYMMDDHH24MISS 格式的当前本地时间.

要计算两个时间戳之前的间隔, 请使用 EnvSub.

备注

此命令等同于这种简写形式：Var += Value。

通过使用 Var++、Var--、++Var 或 --Var 可以让变量增加或减去 1。

如果 Var 或 Value 其中一个为空或不以数字开头, 那么在计算中它会被视为 0 (不过用在表达式 内部 或使用了 TimeUnits 参数时例外).

如果 Var 或 Value 都为小数, 那么最后的结果将为浮点数, 而格式由 SetFormat 决定.

相关

EnvSub, EnvMult, EnvDiv, SetFormat, 表达式, If var is [not] type, SetEnv, FileGetTime

示例

EnvAdd, MyCount, 2
MyCount += 2  ; 等同于上面的命令

var1 =  ; 赋值为空, 这样下面将会使用当前时间代替.
var1 += 31, days
MsgBox, %var1%  ; 结果将是从现在 31 天后的日期.


EnvDiv

设置变量的值为它自身除以给定的值。同义于：Var /= Value。

EnvDiv, Var, Value

参数

Var

要运算的 变量 名.

值

任何整数, 浮点数或 表达式.

备注

此命令等同于这种简写形式：Var /= Value。

除数为零会导致脚本在加载时出现错误信息窗口（如果可能），否则它会让变量为空。

如果 Var 或 Value 其中一个为空或不以数字开头，那么在计算中它会被视为 0（不过用在表达式内部时例外，例如 Var := X /= Y）。

如果 Var 或 Value 都为小数, 那么最后的结果将为浮点数, 而格式由 SetFormat 决定. 否则, 结果将被截断 (例如 19 除以 10 结果为 1).

相关

EnvAdd , EnvSub, EnvMult, SetFormat, 表达式, If var is [not] type, SetEnv, 按位运算 (Transform)

示例

EnvDiv, MyCount, 2
MyCount /= 2  ; 等同于上面的语句


EnvMult

设置变量的值为它自身乘以给定的值。同义于：Var *= Value。

EnvMult, Var, Value

参数

Var

要运算的 变量 名.

值

任何整数, 浮点数或 表达式.

备注

此命令等同于这种简写形式：Var *= Value。

如果 Var 或 Value 其中一个为空或不以数字开头，那么在计算中它会被视为 0（不过用在表达式内部时例外，例如 Var := X *= Y）。

如果 Var 或 Value 都为小数, 那么最后的结果将为浮点数, 而格式由 SetFormat 决定.

相关

EnvAdd, EnvSub, EnvDiv, SetFormat, 表达式, If var is [not] type, SetEnv, 按位运算 (Transform)

示例

EnvMult, MyCount, 2
MyCount *= 2  ; 等同于上面的语句


EnvSub

设置变量的值为它自身减去给定的值（还可以比较日期-时间值）。同义于：Var -= Value。

EnvSub, Var, Value [, TimeUnits]
Var -= Value [, TimeUnits]
Var--

参数

Var

要运算的 变量 名.

值

任何整数, 浮点数或 表达式 (使用了 TimeUnits 时不支持表达式).

TimeUnits

如果使用此参数, 那么此参数指示命令如何从 Var 中减去 Value: 把它们都视为 YYYYMMDDHH24MISS 格式的日期时间戳. TimeUnits 可以为 Seconds, Minutes, Hours 或 Days (或仅使用这些单词的首个字母). 如果 Value 为空, 则使用当前时间代替. 同样地, 如果 Var 是空变量, 则使用当前时间代替.

结果总是被 向下 取整到最近的整数. 例如, 如果两个时间戳之间的实际差为 1.999 天, 那么运算的结果将为 1 天. 如果需要更高的精度, 请在 TimeUnits 中使用 Seconds 并把结果除以 60.0, 3600.0 或 86400.0 (以得到更精确的分钟数, 小时数或天数).

如果 Var 或 Value 其中一个为无效的时间戳或包含早于 1601 的年份, 则 Var 会被置空来表示此问题.

内置变量 A_Now 包含了 YYYYMMDDHH24MISS 格式的当前本地时间.

要精确地测出两个事件之间所经过的时间, 请使用 A_TickCount method, 因为它提供了毫秒级的精度.

要从一个时间戳中加上或减去一定的秒数, 分钟数, 小时数或天数, 请使用 EnvAdd (减法通过加上负数来实现).

备注

此命令等同于这种简写形式：Var -= Value。

通过使用 Var++、Var--、++Var 或 --Var 可以让变量增加或减去 1。

如果 Var 或 Value 其中一个为空或不以数字开头, 那么在计算中它会被视为 0 (不过用在表达式 内部 或使用了 TimeUnits 参数时例外).

如果 Var 或 Value 都为小数, 那么最后的结果将为浮点数, 而格式由 SetFormat 决定.

相关

EnvAdd, EnvMult, EnvDiv, SetFormat, 表达式, If var is [not] type, SetEnv, FileGetTime

示例

EnvSub, MyCount, 2
MyCount -= 2  ; 等同于上面的命令

var1 = 20050126
var2 = 20040126
EnvSub, var1, %var2%, days
MsgBox, %var1%  ; 结果将是 366, 因为 2004 是个闰年.


Var := expression

计算表达式并把结果保存到 变量.

Var := expression

参数

Var

用来保存 表达式 结果的 变量 名.

Expression

请参阅 表达式 和下面的示例了解详情.

备注

:= 运算符进行了优化, 所以在简单的情况中它和 = 运算符执行的一样快, 例如:

x := y  ; 与 x = %y% 执行效率相同
x := 5  ; 与 x = 5 的执行效率相同.
x := "literal string"  ; 与 x = literal string 的执行效率相同.

单词 true 和 false 是值分别为 1 和 0 的内置变量。使用它们可以增加脚本的可读性, 例如:

CaseSensitive := false
ContinueSearch := true

这个命令以及其他任何接受 OutputVar 参数的命令都可以创建伪数组。这可以通过让 OuputVar 包含到另一个变量的引用来实现，例如 Array%i% := Var/100 + 5。请参阅数组了解更多细节。

相关

表达式, IF (表达式), 函数, SetEnv, EnvSet, EnvAdd, EnvSub, EnvMult, EnvDiv, If, 数组

示例

Var := 3
Var := "literal string"
Var := Price * (1 - Discount/100)

Finished := not Done or A_Index > 100
if not Finished
{
    FileAppend, %NewText%`n, %TargetFile%
    return
}
else
    ExitApp


AutoHotkey 致谢

致谢

除了已经 提到 的 AutoIt 作者, 还有:

Robert Yaklin: 不知疲倦地测试大量孤立的缺陷, 伟大的第一版安装者, 且对命令 应该 如何工作提出过极好的建议 :)

Jason Payam Ahdoot: 提供浮点数支持的建议和描述.

Jay D. Novak: 发现了 Send 命令, Capslock 以及热键修饰符在 Win9x 中存在的问题; 并慷慨地分享了大量的代码以及在热键, 热字串, 钩子用法和输入加速方面的知识.

Rajat: 制作了时尚的图标替换了最初的 AHK 图标; 伟大的产品标志; 制作了 TextPad 的自定义语法; 发现了注册表命令和 AutoIt v2 在兼容上的一些问题; 编写了 SmartGUI Creator; 以及其他很多事情.

Beardboy: 为修补 GetKeyState 和 Send 命令进行了 NT4 上的测试工作; 在论坛上提供大量帮助; 以及许多建议和缺陷报告.

Gregory F. Hogg of Hogg's Software: 编写了 SysGet 命令中多显示器支持的源代码.

Aurelian Maga: 编写了 ImageSearch 和更快的 PixelSearch 源代码.

Joost Mulders: 他的源代码提供了 表达式 的基础.

Laszlo Hars: 提供关于数据结构和算法方面的建议, 有助于极大地加速数组和动态变量.

Marcus Sonntag (Ultra): 研究, 设计, 编码且测试 DllCall.

Gena Shimanovich: 协助调试和编码; 并为未来的特性提供了一些高级原型脚本.

Eric Morin (numEric): 提出了数学方面的建议; 在 OnMessage, 浮点数运算和鼠标移动方面进行了基础调试工作; 以及对整体品质的改善.

Philip Hazel: 提供 兼容 Perl 的正则表达式 (PCRE).

Titan/polyethene：提供 autohotkey.net 社区托管服务，创建了许多有用的脚本和库，创建了论坛上的 JavaScript 用彩色显示代码注释，及其他许多事情。

Philippe Lhoste (PhiLho): 在论坛上耐心地提供支持, 对 RegEx 进行测试并提供建议, 语法和设计理念以及其他许多事情.

John Biederman: 显著地改善了文档的描述和舒适度.

Jonathan Rennison (JGR): 开发了 RegisterCallback() 并提供了有用的建议.

Steve Gray (Lexikos): 开发了动态函数调用和其他新功能; 分析并修复故障; 对论坛上成百上千单独的访问者提供宝贵的支持和意见.

AutoHotkey_L:

jackeiku: 开发了 Unicode 支持和其他新功能.

fincs: 开发了原生的 64 位支持和 try/catch/throw, 编写了新的编译器, 分析并修复故障.

Sean: 开发了内置的 COM 功能并提供关于 COM 的有价值的观点.

TheGood: 合并文档并改写了安装程序脚本.

ac: 开发了 #Warn.

Russell Davis: 开发了 A_PriorKey, ahk_path (WinTitle 参数中 ahk_exe 的基础), #InputLevel 和 SendLevel.

Christian Sander: 开发了对 SysLink 控件的支持.

同时对其他所有提交故障报告或建议的人: 谢谢!


数组

关联数组 [AHK_L 31+]

自包含关联数组可以调用 Object() 创建. 例如：

; 创建数组后, 初始为空:
Array := Object()

; 写入数据到数组:
Loop, Read, C:\Guest List.txt ; 此循环获取文件中的每行, 一次一行.
{
    Array.Insert(A_LoopReadLine) ; 添加此行到数组中.
}

; 从数组中读取:
; Loop % Array.MaxIndex()   ; 较传统的方式.
for index, element in Array ; 在大多数情况下建议使用的方式.
{
    ; 使用 "Loop", 索引必须是连续的数字, 从 1 到
    ; 数组中元素的个数 (或者必须在循环中进行计算).
    ; MsgBox % "Element number " . A_Index . " is " . Array[A_Index]

    ; 使用“for”，同时提供了索引（或“键”）及与它关联
    ; 的值，并且索引可以是您选择的*任何*值。
    MsgBox % "Element number " . index . " is " . element
}

此例仅演示了 对象 提供的 功能 的一个小子集. 可以设置, 获取, 插入, 移除和枚举项目. 除了数字, 还可以把字符串和对象作为键使用. 对象可以作为值存储到其他对象中并且可以作为函数参数或返回值传递. 对象还可以用新功能进行 扩展.

尽管 Insert() 和枚举数有它们的用途, 不过一些用户可能会发现使用它们比用更传统的方式容易些:

  ; 每个数组在使用前必须进行初始化:
  Array := Object()

; Array%j% := A_LoopField
  Array[j] := A_LoopField

; Array%j%_%k% := A_LoopReadLine
  Array[j, k] := A_LoopReadLine

  ArrayCount := 0
  Loop, Read, C:\Guest List.txt
  {
      ArrayCount += 1
    ; Array%ArrayCount% := A_LoopReadLine
      Array[ArrayCount] := A_LoopReadLine
  }

  Loop %ArrayCount%
  {
    ; element := Array%A_Index%
      element := Array[A_Index]
    ; MsgBox % "Element number " . A_Index . " is " . Array%A_Index%
      MsgBox % "Element number " . A_Index . " is " . Array[A_Index]
  }

为了方便而使用 ArrayCount 变量保存数组元素个数, 但可以通过 Array.Count := n 保存到数组自身中, 或使用 Array._MaxIndex() 代替它. 如果希望使用 1 之外的其他值作为起始索引, 还可以使用 Array._MinIndex().

伪数组

伪数组主要是概念上的: 每个数组实际上只是一系列连续编号的 变量 或 函数 的集合, 它们每个被视为数组的 元素. AutoHotkey 不会以任何方式把这些元素链接在一起.

除了如 StringSplit 和 "WinGet List" 这样的数组创建命令外, 任何接受 OutputVar 或把值赋给变量的命令都可以用来创建数组. 最简单的例子是 赋值运算符 (:=), 如下所示:

Array%j% := A_LoopField

通过在索引间使用您选择的分隔符可以创建多维数组. 例如：

Array%j%_%k% := A_LoopReadLine

下面的例子演示了如何创建和访问数组, 这里是从文本文件获取一系列的名称:

; 写入到数组：
ArrayCount = 0
Loop, Read, C:\Guest List.txt   ; 此循环获取文件中的每行, 一次一行.
{
    ArrayCount += 1  ; 记录数组中的项目数.
    Array%ArrayCount% := A_LoopReadLine  ; 把此行保存到数组中的下一个元素.
}

; 从数组中读取:
Loop %ArrayCount%
{
    ; 下一行使用 := 运算符获取数组元素:
    element := Array%A_Index%  ; A_Index 是内置变量.
    ; 可选地, 您可以使用 "% " 前缀让 MsgBox 或其他一些命令的参数中 可以使用表达式:
    MsgBox % "Element number " . A_Index . " is " . Array%A_Index%
}

一个和数组有关的概念是使用 NumPut() 和 NumGet() 储存/获取一批二进制格式的数字. 这在对性能和/或内存占用有要求时比较有用.


AutoIt v2 兼容性

AutoHotkey v1.1.09 及之后的版本不支持 AutoIt v2（.aut）脚本。AutoHotkey 的旧版本支持 AutoIt v2 脚本，但改变了某些命令的默认设置和行为。这个页面包含了从文档的其他页面中移除的信息。

下列的信息只适用于 .aut 文件及 v1.1.08.01 或更早的版本。

#AllowSameLineComments | 默认情况下不允许注释与命令在同一行。
A_ScriptDir | 包含末尾的反斜线。
DetectHiddenText | 默认为 Off。
#EscapeChar | 默认为反斜线（\）。
FileCopy | 若某个文件无法复制则 ErrorLevel 被设置为 1。
IniDelete | ErrorLevel 保持不变。
IniRead | 不支持 Default 参数。如果在读取值时遇到问题则 OutputVar 总是为 ERROR。
IniWrite | ErrorLevel 保持不变。
InputBox | 如果用户按下取消按钮，则 OutputVar 被置为空。只有在超时的情况下，ErrorLevel 才会变化。
SetBatchLines | 默认为 1，这样会让脚本在每行后休眠。
SetKeyDelay | 对于传统的 SendEvent 默认 Delay 为 20。
发送 | 忽略 # 字符。
SplashTextOn | Height 包含了窗口的标题栏。

转义符变换

在 AutoHotkey v1.1.08.01 或早期版本中运行扩展名为 .aut.ahk 的脚本文件时不会执行脚本，相应的它把脚本从 AutoIt v2 默认转义符（反斜线）转换为 AutoHotkey 的默认转义符（重音符）。

过时的命令

通过自动把下列命令自动转换成相应的 AutoHotkey 命令可以支持它们（之前没有记录在文档中）：LeftClick、LeftClickDrag、RightClick、RightClickDrag、HideAutoItWin、Repeat、EndRepeat。在 v1.1.09 中移除了这种自动转换。


Clipboard、ClipboardAll和OnClipboardChange

Clipboard, ClipboardAll 和 OnClipboardChange

Clipboard 是内置 变量, 它包含了当前 Windows 剪贴板中以文本形式表示的内容. 与之相比，ClipboardAll 包含了剪贴板中的所有内容，例如图片和格式。

Clipboard 中的每行文本通常都是以回车和换行符 (CR+LF) 结尾, 它们在脚本中表示为 `r`n. 文件 (例如从资源管理器窗口中使用 Control-C 复制的那些) 被视为文本: 每当在脚本中引用 Clipboard 时, 它们会被自动转换为它们的文件名 (含完整路径). 要逐个提取这些文件, 请参照此例:

Loop, parse, clipboard, `n, `r
{
    MsgBox, 4, , File number %A_Index% is %A_LoopField%.`n`nContinue?
    IfMsgBox, No, break
}

要按字母顺序排列文件名, 请使用 Sort 命令. 要把剪贴板中的文件名写入到文件中, 请使用 FileAppend, %clipboard%`r`n, C:\My File.txt. 要改变脚本尝试打开剪贴板的持续时间, 例如另一个程序在使用剪贴板的时候, 请使用 #ClipboardTimeOut.

基本示例:
clipboard = my text   ; 在剪贴板中存入新内容.
clipboard =   ; 清空剪贴板.
clipboard = %clipboard%   ; 把任何复制的文件, HTML 或其他格式的文本转换为纯文本.
clipboard = %clipboard% Text to append.   ; 追加一些文本到剪贴板.
StringReplace, clipboard, clipboard, ABC, DEF, All   ; 把剪贴板中所有 ABC 替换为 DEF (同时把剪贴板的内容转换为纯文本).

使用 ClipWait 提高脚本的可靠性:

clipboard =  ; 让剪贴板初始为空, 这样可以使用 ClipWait 检测文本什么时候被复制到剪贴板中.
Send ^c
ClipWait  ; 等待剪贴板中出现文本.
MsgBox Control-C copied the following contents to the clipboard:`n`n%clipboard%

ClipboardAll（保存并恢复剪贴板中的所有内容）

ClipboardAll 包含了剪贴板中的所有内容 (例如图片和格式). 它常用来保存剪贴板的内容, 以便脚本可以在某个操作中临时使用剪贴板. 当这个操作结束后, 脚本可以恢复剪贴板为原来的内容, 如下所示:

ClipSaved := ClipboardAll   ; 把剪贴板的所有内容保存到您选择的变量中.
; ... 这里临时使用剪贴板, 例如使用 Transform Unicode 粘贴 Unicode 文本 ...
Clipboard := ClipSaved   ; 恢复剪贴板为原来的内容. 注意这里使用 Clipboard (不是 ClipboardAll).
ClipSaved =   ; 在原来的剪贴板含大量内容时释放内存.

ClipboardAll 中的内容可以保存到文件中 (在这种模式中, FileAppend 总是覆盖任何现有的文件):

FileAppend, %ClipboardAll%, C:\Company Logo.clip ; 文件扩展名无关紧要.

要在之后加载这个文件的内容回剪贴板 (或变量中), 请参照此例:

FileRead, Clipboard, *c C:\Company Logo.clip ; 注意 *c 必须在文件名的前面。

注意

除上面描述的方式外的其他方式使用 ClipboardAll 时, 都会得到空值. 此外，ClipboardAll 不支持在逗号分隔的表达式中使用；即它必须在单独的一行进行赋值，例如 ClipSaved := ClipboardAll。

接受了 ClipboardAll 赋值的变量以二进制格式存储数据, 因为使用类似 MsgBox 这样的方法显示时会出现乱码. 并且, 修改二进制剪贴板变量 (使用类似 StringReplace 的方法) 会将它还原为普通变量, 导致它所保存的剪贴板数据的丢失. 在 v1.0.46+, 二进制剪贴板变量可以作为值传递给 函数 (以前它们只有作为 ByRef 才行).

如果 ClipboardAll 不能获取剪贴板中一个或多个数据对象 (格式), 则会忽略它们但仍保存剩余的所有对象. 获取行为会根据 #ClipboardTimeOut 设置再次进行尝试 (而不只是尝试一次).

包含剪贴板数据的变量可以赋值给另一个变量，例如：ClipSaved2 := ClipSaved

ClipWait 可以用来检测剪贴板包含数据的时候 (可以包含非文本数据).

StrLen / StringLen 可以用来获取接受 ClipboardAll 赋值的变量的总大小。然而, 要在 AutoHotkey 的 Unicode 版本中获取字节的大小, 则前面得到的长度必须乘以 2. A_IsUnicode 可用来支持 ANSI 和 Unicode 版本，例如：size := StrLen(ClipSaved) * (A_IsUnicode ? 2 : 1)。

接受 ClipboardAll 赋值的变量可以通过 <> 和 = 互相进行比较 (但不能直接和 ClipboardAll 进行比较). 在下面的例子中, 首先检查每个变量的大小. 如果大小不足以判断, 则比较它们的内容来得到结果:

if ClipSaved1 <> %ClipSaved2%   ; 这里 必须 使用旧式的 IF 语句, 不能使用表达式.
    MsgBox The two saved clipboards are different.

保存 ClipboardAll 到变量时, 这个变量的大小不受 #MaxMem 设置的内存限制.

保存了剪贴板内容的文件内部由四个字节的格式类型, 接着四个字节的数据块大小以及相应的格式的数据块组成. 如果剪贴板中包含多种格式的内容 (大部分时候都是这样), 这三个组成部分会一直重复, 直到包含所有的内容. 文件以四个字节的 0 格式类型结尾.

已知限制: 当剪贴板中含有 Microsoft Excel 单元格数据时获取 ClipboardAll 可能会导致 Excel 弹出 "找不到打印机" 的对话框.

使用 AutoHotkey 编写的剪贴板实用工具:

  • Deluxe Clipboard: 提供不限数量的私有的命名的剪贴板, 可以用来复制, 剪切, 追加或剪切追加选中的文本. www.autohotkey.com/forum/topic2665.html
  • ClipStep: 仅使用键盘上 Ctrl-X-C-V 控制多个剪贴板. www.autohotkey.com/forum/topic4836.html

OnClipboardChange

如果脚本中含有名称为 OnClipboardChange 的标签, 则当任何应用程序 (甚至是脚本自身) 改变了剪贴板的内容时会自动运行此标签. 当脚本启动时也会运行此标签一次.

内置变量 A_EventInfo 包含:
0 如果剪贴板当前为空;
1 如果剪贴板中仅包含能以文本形式表示的内容 (这里也包含了从资源管理器窗口 复制的文件);
2 如果剪贴板包含了非文本的内容, 例如图片.

下面的例子是个可运行脚本. 运行后, 它会在每次剪贴板内容变化时短暂地显示一个工具提示.

#Persistent
return

OnClipboardChange:
ToolTip Clipboard data type: %A_EventInfo%
Sleep 1000
ToolTip  ; 关闭提示.
return

当 OnClipboardChange 标签正在运行时如果剪贴板内容改变了, 那么会丢弃此通知事件. 如果不希望这样, 请在此标签的首行中指定 Critical. 不过, 这样也会缓冲/延迟在 OnClipboardChange 线程运行期间产生的其他 线程 (例如热键).

如果脚本自身改变了剪贴板的内容, 则脚本中的 OnClipboardChange 标签通常不会立即执行; 即在它之前很可能还会执行改变剪贴板内容的命令之后的命令. 要强制立即执行这个标签，请在改变剪贴板后使用短暂的延迟，例如 Sleep 20。

相关主题: OnExit, OnMessage(), RegisterCallback()


CLSID 列表（Windows类标识符）

操作系统中某些特殊的文件夹使用唯一的字符串进行标识. 这些字符串的其中一些可以用在 FileSelectFile, FileSelectFolder 以及 Run. 例如：

FileSelectFile, OutputVar,, ::{645ff040-5081-101b-9f08-00aa002f954e}  ; 在回收站中选择文件.
FileSelectFolder, OutputVar, ::{20d04fe0-3aea-1069-a2d8-08002b30309d}  ; 在我的电脑中选择文件夹.

CLSID | 含义/位置 | Run 支持吗?
::{d20ea4e1-3957-11d2-a40b-0c5020524153} | 管理工具 |
::{85bbd92o-42a0-1o69-a2e4-08002b30309d} | 公文包 |
::{21ec2o2o-3aea-1o69-a2dd-08002b30309d} | 控制面板 |
::{d20ea4e1-3957-11d2-a40b-0c5020524152} | 字体 |
::{ff393560-c2a7-11cf-bff4-444553540000} | 历史 |
::{00020d75-0000-0000-c000-000000000046} | 收件箱 |
::{00028b00-0000-0000-c000-000000000046} | 微软网络 |
::{20d04fe0-3aea-1069-a2d8-08002b30309d} | 我的电脑 | 是
::{450d8fba-ad25-11d0-98a8-0800361b1103} | 我的文档 | 是
::{208d2c60-3aea-1069-a2d7-08002b30309d} | 网上邻居 | 是
::{1f4de370-d627-11d1-ba4f-00a0c91eedba} | 网络计算机 | 是
::{7007acc7-3202-11d1-aad2-00805fc1270e} | 网络连接 | 是
::{2227a280-3aea-1069-a2de-08002b30309d} | 打印机和传真 | 是
::{7be9d83c-a729-4d97-b5a7-1b7313c39e0a} | 应用程序文件夹 |
::{645ff040-5081-101b-9f08-00aa002f954e} | 回收站 | 是
::{e211b736-43fd-11d1-9efb-0000f8757fcd} | 扫描仪和照相机 |
::{d6277990-4c6a-11cf-8d87-00aa0060f5bf} | 任务计划 | 是
::{48e7caab-b918-4e58-a94d-505519c795dc} | 开始菜单文件夹 |
::{7bd29e00-76c1-11cf-9dd0-00a0c9034933} | Internet 临时文件 |
::{bdeadf00-c265-11d0-bced-00a0c90ab50f} | 网络文件夹 |

最后一列中的 "是" 条目并不总是准确的: 根据不同的系统配置 Run 命令可能支持不同的 CLSID. 要使用 Run 打开 CLSID 文件夹, 请简单地在首个参数中指定 CLSID. 例如：

Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}  ; 打开 "我的电脑" 文件夹.
Run ::{645ff040-5081-101b-9f08-00aa002f954e}  ; 打开回收站.
Run ::{450d8fba-ad25-11d0-98a8-0800361b1103}\My Folder  ; 打开 "我的文档" 中的一个文件夹.
Run %A_MyDocuments%\My Folder  ; 在大多数系统上等同于前一行命令.


ErrorLevel

这是表示一些命令执行成功与否的内置变量（有些命令不会改变 ErrorLevel 的值）。值为 0 时通常表示成功, 而其他值一般表示失败. 您也可以自己设置 ErrorLevel 的值.

特别有意义的是 RunWait 会把 ErrorLevel 设置为它所运行程序的退出代码. 大多数程序在成功完成时会产生退出代码零.

每个 线程 会保持它自己的 ErrorLevel 的值, 这意味着如果 当前线程 被其他线程中断, 那么当原始线程恢复时它仍会拥有它原来的 ErrorLevel 值, 而不是由中断线程设置的 ErrorLevel 值.

注意: 由于一些命令会设置大于 1 的 ErrorLevel 值, 所以最好不要检查 ErrorLevel 是否大于 1, 而是检查它是否等于零.

示例

WinWait, MyWindow, , 1
if ErrorLevel   ; 即既不是空值, 也不是零.
    MsgBox, The window does not exist.
else
    MsgBox, The window exists.


标准 Windows 字体

这些字体名称用于 Progress、GUI 和 SplashImage 命令。

黄色高亮显示的为推荐使用的字体。

字体名称 | Win95 | WinNT | Win98 | Win2000 | WinMe | WinXP
Abadi MT Condensed Light |  |  | x |  |  |
Arial | x | x | x | x | x | x
Arial Alternative Regular |  |  |  |  | x |
Arial Alternative Symbol |  |  |  |  | x |
Arial Black |  |  | x | x | x | x
Arial Bold | x | x | x | x | x | x
Arial Bold Italic | x | x | x | x | x | x
Arial Italic | x | x | x | x | x | x
Book Antiqua |  |  | x |  |  |
Calisto MT |  |  | x |  |  |
Century Gothic |  |  | x |  |  |
Century Gothic Bold |  |  | x |  |  |
Century Gothic Bold Italic |  |  | x |  |  |
Century Gothic Italic |  |  | x |  |  |
Comic Sans MS |  |  | x | x | x |
Comic Sans MS Bold |  |  | x | x | x | x
Copperplate Gothic Bold |  |  | x |  |  |
Copperplate Gothic Light |  |  | x |  |  |
Courier | x | x | x | x | x | x
Courier New | x | x | x | x | x | x
Courier New Bold | x | x | x | x | x | x
Courier New Bold Italic | x | x | x | x | x | x
Courier New Italic | x | x | x | x | x | x
Estrangelo Edessa |  |  |  |  |  | x
Franklin Gothic Medium |  |  |  |  |  | x
Franklin Gothic Medium Italic |  |  |  |  | x |
Gautami |  |  |  |  |  | x
Georgia |  |  |  | x |  | x
Georgia Bold |  |  |  | x |  | x
Georgia Bold Italic |  |  |  | x |  | x
Georgia Italic |  |  |  | x |  | x
Georgia Italic Impact |  |  |  |  |  | x
Impact |  |  | x | x | x |
Latha |  |  |  |  |  | x
Lucida Console |  | x | x | x | x | x
Lucida Handwriting Italic |  |  | x |  |  |
Lucida Sans Italic |  |  | x |  |  |
Lucida Sans Unicode |  |  | x | x |  | x
Marlett |  |  | x |  | x |
Matisse ITC |  |  | x |  |  |
Modern | x | x | x | x |  |
Modern MS Sans Serif |  |  |  |  |  | x
MS Sans Serif | x | x | x | x | x | x
MS Serif | x | x | x | x | x |
Mv Boli |  |  |  |  |  | x
News Gothic MT |  |  | x |  |  |
News Gothic MT Bold |  |  | x |  |  |
News Gothic MT Italic |  |  | x |  |  |
OCR A Extended |  |  | x |  |  |
Palatino Linotype |  |  |  | x |  | x
Palatino Linotype Bold |  |  |  | x |  | x
Palatino Linotype Bold Italic |  |  | x |  | x |
Palatino Linotype Italic |  |  |  | x |  | x
Roman |  | x |  | x |  | x
脚本 |  | x |  | x |  | x
Small Fonts |  | x |  | x |  | x
Smallfonts | x |  | x |  | x |
符号 | x | x | x | x | x | x
Tahoma |  |  | x | x | x | x
Tahoma Bold |  |  | x | x | x | x
Tempus Sans ITC |  |  | x | x |  |
Times New Roman | x | x | x | x | x | x
Times New Roman Bold | x | x | x | x | x | x
Times New Roman Bold Italic | x | x | x | x | x | x
Times New Roman Italic | x | x | x | x | x | x
Trebuchet |  |  |  |  | x |
Trebuchet Bold |  |  |  |  | x |
Trebuchet Bold Italic |  |  |  |  | x |
Trebuchet Italic |  |  |  |  | x |
Trebuchet MS |  |  |  | x |  | x
Trebuchet MS Bold |  |  |  | x |  | x
Trebuchet MS Bold Italic |  |  |  | x |  | x
Trebuchet MS Italic |  |  |  | x |  | x
Tunga |  |  |  |  |  | x
Verdana (包含在 MSIE 3+ 中) |  |  | x | x | x | x
Verdana Bold |  |  | x | x | x | x
Verdana Bold Italic |  |  | x | x | x | x
Verdana Italic |  |  | x | x | x | x
Webdings |  |  | x | x | x | x
Westminster |  |  | x |  | x | x
Wingdings | x | x |  | x |  | x
WST_Czech |  |  |  |  |  | x
WST_Engl |  |  |  |  |  | x
WST_Fren |  |  |  |  |  | x
WST_Germ |  |  |  |  |  | x
WST_Ital |  |  |  |  |  | x
WST_Span |  |  |  |  |  | x
WST_Swed |  |  |  |  |  | x

列表由 KaysKreations 和 AutoIt 团队整理.


标签

标签用来标识代码行, 可以作为 Goto 目标或组成 子程序.

LabelName:

要创建标签, 请像上面那样写下标签名和冒号. 除了空白字符和注释, 其他代码不能与标签写在同一行.

名称: 标签名不区分大小写, 且可以由除空格, tab, 逗号以及 转义字符 (`) 外的其他字符组成. 然而, 考虑到命名的惯例, 通常最好仅使用字母, 数字和下划线 (例如: MyListView, Menu_File_Open 和 outer_loop). 在整个脚本中标签名必须是唯一的.

目标: 标签的目标是下一个可执行的代码行. 可执行代码包含命令, 赋值, 表达式 和 区块, 但不包括指令, 标签, 热键或热字串. 在下面的例子中，run_notepad 和 #n 标签都指向 Run 行：

run_notepad:
#n::
    Run Notepad
    return

执行: 与指令类似, 正常执行到标签时标签会被忽略. 在下面的例子中, 消息框会显示两次: 一次是在执行 Gosub 的目标子程序时, 再次是在前面的子程序返回后:

gosub Label1

Label1:
MsgBox %A_ThisLabel%
return

子程序

子程序是一部分代码, 可以对它进行 调用 来执行特定的任务. 子程序的执行从目标标签开始, 一直执行到遇上 Return 或 Exit. 由于子程序的结尾决定于流控制, 所以任何标签既作为 Goto 的目标同时也是子程序的开始.

动态标签

接受标签名的许多命令也可以接受 变量 引用 (例如 %MyLabel%), 此时变量中保存了目标标签的名称. 然而, 性能会稍微降低, 因为每次都必须 "查找" 目标标签名而不是只在脚本首次加载时查找一次.

热键和热字串

热键 和 热字串标签 也可以作为 Goto, Gosub 以及其他命令的目标. 然而, 如果一个热键或热字串含有多个 变体, 则使用最接近脚本顶部的那个变体. 所有的热键修饰键或热字串选项都是标签名的一部分, 但不包括最后的双冒号 (::).

命名循环

标签还可以用来标识循环, 以便用于 Continue 和 Break 命令. 这样脚本可以很方便地继续或退出任意数目的内嵌循环.

相关

IsLabel(), A_ThisLabel, Gosub, Goto, OnExit, SetTimer, Hotkey, Gui 事件, g 标签, OnClipboardChange


语言代码

下表包含了与每个语言代码对应的语言名称, A_Language 变量的值为其中的某个语言代码. 语言代码自身是下面等号左边的最后四位数字. 例如, 如果 A_Language 的值为 0436, 则系统的默认语言为 Afrikaans. 注意: 包含字母的代码可能使用大写字母或小写字母.

您可以直接把 A_Language 和下面的一个或多个 4 位代码进行比较；例如：if (A_Language = "0436")。或者您可以把整个表粘贴到脚本中, 然后像列表底部演示的那样访问当前语言的名称.

languageCode_0436 = Afrikaans
languageCode_041c = Albanian
languageCode_0401 = Arabic_Saudi_Arabia
languageCode_0801 = Arabic_Iraq
languageCode_0c01 = Arabic_Egypt
languageCode_0401 = Arabic_Saudi_Arabia
languageCode_0801 = Arabic_Iraq
languageCode_0c01 = Arabic_Egypt
languageCode_1001 = Arabic_Libya
languageCode_1401 = Arabic_Algeria
languageCode_1801 = Arabic_Morocco
languageCode_1c01 = Arabic_Tunisia
languageCode_2001 = Arabic_Oman
languageCode_2401 = Arabic_Yemen
languageCode_2801 = Arabic_Syria
languageCode_2c01 = Arabic_Jordan
languageCode_3001 = Arabic_Lebanon
languageCode_3401 = Arabic_Kuwait
languageCode_3801 = Arabic_UAE
languageCode_3c01 = Arabic_Bahrain
languageCode_4001 = Arabic_Qatar
languageCode_042b = Armenian
languageCode_042c = Azeri_Latin
languageCode_082c = Azeri_Cyrillic
languageCode_042d = Basque
languageCode_0423 = Belarusian
languageCode_0402 = Bulgarian
languageCode_0403 = Catalan
languageCode_0404 = Chinese_Taiwan
languageCode_0804 = Chinese_PRC
languageCode_0c04 = Chinese_Hong_Kong
languageCode_1004 = Chinese_Singapore
languageCode_1404 = Chinese_Macau
languageCode_041a = Croatian
languageCode_0405 = Czech
languageCode_0406 = Danish
languageCode_0413 = Dutch_Standard
languageCode_0813 = Dutch_Belgian
languageCode_0409 = English_United_States
languageCode_0809 = English_United_Kingdom
languageCode_0c09 = English_Australian
languageCode_1009 = English_Canadian
languageCode_1409 = English_New_Zealand
languageCode_1809 = English_Irish
languageCode_1c09 = English_South_Africa
languageCode_2009 = English_Jamaica
languageCode_2409 = English_Caribbean
languageCode_2809 = English_Belize
languageCode_2c09 = English_Trinidad
languageCode_3009 = English_Zimbabwe
languageCode_3409 = English_Philippines
languageCode_0425 = Estonian
languageCode_0438 = Faeroese
languageCode_0429 = Farsi
languageCode_040b = Finnish
languageCode_040c = French_Standard
languageCode_080c = French_Belgian
languageCode_0c0c = French_Canadian
languageCode_100c = French_Swiss
languageCode_140c = French_Luxembourg
languageCode_180c = French_Monaco
languageCode_0437 = Georgian
languageCode_0407 = German_Standard
languageCode_0807 = German_Swiss
languageCode_0c07 = German_Austrian
languageCode_1007 = German_Luxembourg
languageCode_1407 = German_Liechtenstein
languageCode_0408 = Greek
languageCode_040d = Hebrew
languageCode_0439 = Hindi
languageCode_040e = Hungarian
languageCode_040f = Icelandic
languageCode_0421 = Indonesian
languageCode_0410 = Italian_Standard
languageCode_0810 = Italian_Swiss
languageCode_0411 = Japanese
languageCode_043f = Kazakh
languageCode_0457 = Konkani
languageCode_0412 = Korean
languageCode_0426 = Latvian
languageCode_0427 = Lithuanian
languageCode_042f = Macedonian
languageCode_043e = Malay_Malaysia
languageCode_083e = Malay_Brunei_Darussalam
languageCode_044e = Marathi
languageCode_0414 = Norwegian_Bokmal
languageCode_0814 = Norwegian_Nynorsk
languageCode_0415 = Polish
languageCode_0416 = Portuguese_Brazilian
languageCode_0816 = Portuguese_Standard
languageCode_0418 = Romanian
languageCode_0419 = Russian
languageCode_044f = Sanskrit
languageCode_081a = Serbian_Latin
languageCode_0c1a = Serbian_Cyrillic
languageCode_041b = Slovak
languageCode_0424 = Slovenian
languageCode_040a = Spanish_Traditional_Sort
languageCode_080a = Spanish_Mexican
languageCode_0c0a = Spanish_Modern_Sort
languageCode_100a = Spanish_Guatemala
languageCode_140a = Spanish_Costa_Rica
languageCode_180a = Spanish_Panama
languageCode_1c0a = Spanish_Dominican_Republic
languageCode_200a = Spanish_Venezuela
languageCode_240a = Spanish_Colombia
languageCode_280a = Spanish_Peru
languageCode_2c0a = Spanish_Argentina
languageCode_300a = Spanish_Ecuador
languageCode_340a = Spanish_Chile
languageCode_380a = Spanish_Uruguay
languageCode_3c0a = Spanish_Paraguay
languageCode_400a = Spanish_Bolivia
languageCode_440a = Spanish_El_Salvador
languageCode_480a = Spanish_Honduras
languageCode_4c0a = Spanish_Nicaragua
languageCode_500a = Spanish_Puerto_Rico
languageCode_0441 = Swahili
languageCode_041d = Swedish
languageCode_081d = Swedish_Finland
languageCode_0449 = Tamil
languageCode_0444 = Tatar
languageCode_041e = Thai
languageCode_041f = Turkish
languageCode_0422 = Ukrainian
languageCode_0420 = Urdu
languageCode_0443 = Uzbek_Latin
languageCode_0843 = Uzbek_Cyrillic
languageCode_042a = Vietnamese

the_language := languageCode_%A_Language%  ; 获取系统默认语言的名称.
MsgBox %the_language%  ; 显示语言名称.


创建键盘宏或鼠标宏

宏是根据需要 "播放" 的一系列事先写好的动作. 宏最常见的用法是向一个或多个窗口发送 模拟键击 和 鼠标点击. 这些窗口会响应每个键击和鼠标点击, 就好像您手动操作一样, 这样可以让重复的任务快速可靠地自动化.

尽管可以手动编写宏, 但如果借助宏录制器 (例如由 Titan/polyethene 编写的 Recorder 脚本) 编写较长的宏时会变得更轻松. 它会监视您输入的内容和点击的位置, 并且跟踪 活动 窗口的变化. 它把这些动作转录成可运行的宏, 之后可以以较快的速度 "回放".

回放宏的最方便的方法之一是为它指定 热键 或 热字串. 例如, 下面的热键会为创建空白电子邮件, 然后输入指定的内容, 并且允许您在发送之前对其进行编辑:

^!s::  ; Control+Alt+S 热键.
IfWinNotExist Inbox - Microsoft Outlook
    return  ; Outlook 没有进入正确的视图, 所以不进行操作.
WinActivate  ; 激活上面命令找到的窗口.
Send ^n  ; 使用 Control+N 创建新的/空白的电子邮件.
WinWaitActive Untitled Message
Send {Tab 2}Product Recall for ACME Rocket Skates  ; 设置主题行.
Send {Tab}Dear Sir or Madam,{Enter 2}We have recently discovered a minor defect ...  ; 等等.
return  ; 这行用来结束热键.

上面这样的热键宏对您每天都要执行多次的任务非常有帮助. 与之相比, 较少使用的宏可以保存在独立的脚本中, 通过在开始菜单或桌面建立快捷方式来运行.

想马上创建您自己的宏和热键, 请阅读 快速入门指南.

-- 主页 --


覆盖热键

覆盖或禁用热键

通过对注册表进行下面的修改, 您可以禁用除 Win+L 和 Win+U 外的其他所有内置的 Windows 热键 (这种方法应该适用于所有操作系统, 但可能需要重启才生效):

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer
NoWinKeys REG_DWORD 0x00000001 (1)

但如果您想进一步设置而非仅仅禁用它们, 那么请继续阅读.

其他程序中定义的热键可以被指定到脚本中的动作来轻松地进行覆盖或禁用. 此特性常用来改变 Windows 内置的热键. 例如, 如果您想用 Win+E (启动 Windows Explorer 的快捷键) 执行其他的动作, 请使用这个:

#e::
MsgBox This hotkey is now owned by the script.
return

在下面的例子中, 把用来打开运行对话框的 Win+R 热键完全禁用了:

#r::return

同样地, 要禁用两个 Windows 键, 请使用这个:

Lwin::return
Rwin::return

要禁用或改变一个应用程序的非全局热键 (即仅对那个应用程序的窗口有效的快捷键), 请参考下面的例子, 其中仅禁用了记事本的 Control+P (打印), 而让它对其他所有窗口保持有效:

$^p::
IfWinActive ahk_class Notepad
    return  ; 即不进行操作, 这样让 Control-P 在记事本中失效.
Send ^p
return

在上面的例子中, 必须使用 $ 前缀, 这样热键才可以 "发送自身" 而不触发它自己 (否则会出现提示无限循环的警告对话框). 另请参阅: 上下文相关的热键.

您可以尝试执行上面的每个例子: 把它们复制到新文本文件 (例如 "Override.ahk"), 然后运行这个文件.


性能

脚本性能

要让性能最佳化, 请避免使用 SetFormat (不包括 快速模式) 并且在每个脚本的顶部附近加上下面的这些行:

#NoEnv
SetBatchLines -1
ListLines Off

此外, 根据脚本的内容下面的命令可能同样会影响性能: SendMode, SetKeyDelay, SetMouseDelay, SetWinDelay, SetControlDelay 和 SetDefaultMouseSpeed.

内置性能特性

在加载和语法检查每个脚本时, 会对它们进行半编译. 这样除了可以减少内存消耗外, 还可以极大地提高运行时的性能.

下面是优化过程 (半编译) 的技术细节:

  • 把输入和输出变量 (当它们的名称不包含到其他变量的引用时) 和 组 名解析为内存地址.
  • 为 Loop, 区块, IF 和 ELSE 提供它们在脚本中相关跳转点的内存地址.
  • 把每个 热键, Gosub 和 Goto 的目标解析为内存地址, 除非它是变量.
  • 使用跳转表把每个命令名替换为地址.
  • 把每行预解析成参数列表，且把每个参数预解析成变量列表（如果有）。
  • 标记化每个 表达式 且把它们从中缀转到后缀.
  • 把每个到 变量 或 函数 的引用解析为内存地址.
  • 把表达式和数学/比较命令中的原义整数替换成二进制整数.

此外, 在脚本执行期间, 对二进制数进行缓存以避免和字符串之间的相互转换. 请参阅 SetFormat 了解详情.


正则表达式（RegEx）——快速参考

基础知识

在任意位置进行匹配: 默认情况下, 正则表达式可以匹配被搜索字符串的 任意位置 的子字符串. 例如, 正则表达式 abc 可以匹配 abc123, 123abc 以及 123abcxyz. 要限制在开始或末尾进行匹配, 请使用 锚.

转义字符: 大多数字符 (例如 abc123) 可以直接使用在正则表达式中. 然而, \.*?+[{|()^$ 这些字符则必须在其前面加上反斜线来进行匹配. 例如, \. 表示一个原义的句点而 \\ 表示一个原义的反斜线. 使用 \Q...\E 能避免转义. 例如: \QLiteral Text\E.

区分大小写: 默认情况下, 正则表达式是区分大小写的. 这种特性可以使用 "i" 选项进行改变. 例如, 模式 i)abc 会搜索所有大小写形式的 "abc". 请参阅下面了解其他的选项.

选项 (区分大小写)

在正则表达式的最前面, 指定零个或多个下列选项后面跟着闭括号. 例如, 模式 "im)abc" 将带有不区分大小写和多行选项来搜索 abc (如果不含选项, 则这个圆括号可以省略). 尽管这种语法有别于传统, 不过它不需要特殊的分隔符 (例如正斜杠), 因此不需要对模式中的这样的分隔符进行转义. 此外, 由于很容易解析出选项, 所以提升了性能.

i | 不区分大小写匹配, 它把字母 A 到 Z 视为等同于它们的小写副本.
m | 多行. 把Haystack视为许多单独的行（如果它包含新行符）的集合而不是一个单个的连续行。具体地, 它会改变下列方式: 1) 抑扬符 (^) 能匹配紧跟在内部所有新行符之后的位置, 如同它总能匹配 Haystack 的开始处一样 (但它不会匹配 Haystack 的 最后面 的新行符之后的位置). 2) 美元符 ($) 能匹配 Haystack 中任何新行符之前的位置 (如同它总能匹配最后面的位置). 例如，模式“m)^abc$”中包含了“m”选项才能在 Haystack“xyz`r`nabc”中形成匹配。 使用了 "m" 选项时 "D" 选项会被忽略.
s | DotAll. 此选项会让句点 (.) 匹配包含新行符在内的所有字符 (一般情况下, 它不能匹配新行符). 然而, 如果换行符是默认的 CRLF (`r`n), 则必须使用两个句点才能进行匹配 (不是一个). 不论是否使用此选项, 排除型字符类 (例如 [^a]) 总能匹配新行符.
x | 忽略模式中的空白字符, 除非对它们进行转义或出现在字符类中. 字符 `n 和 `t 在它们达到 PCRE 时会被忽略, 因为它们已经是原始的/原义的空白字符 (与之相比, \n 和 \t 则不会被忽略, 因为它们是 PCRE 的转义序列). x 选项还会忽略字符类外面的非转义 # 和下一个新行符之间的字符 (包括它们). 这使得在复杂的模式中添加注释成为可能. 然而, 这只适用于数据字符; 空白字符可能永远都不会出现在特殊字符序列中, 例如 (?(, 它以条件子模式开头.
A | 强制固定匹配模式; 即它只能匹配 Haystack 的开始处 (即使开始处是换行符, 也会从换行符开始匹配而不从换行符之后的字符开始). 在大多数条件下, 它的作用等同于在模式中使用 "^".
D | 强制美元符 ($) 匹配 Haystack 的末端, 即使 Haystack 的最后的字符是新行符. 如果没有此选项，则$会匹配最后的新行符之前的位置（如果有新行符，此时匹配不会包括新行符）。注: 使用了 "m" 选项时此选项会被忽略.
J | 允许重复 命名子模式. 它可用于在一组相同的命名子模式中只有其中一个形成匹配的模式. 注: 如果有多个特殊名子模式的实例形成匹配, 那么只保存最左边的那个. 此外, 变量名不区分大小写.
U | 非贪婪. 让限定符 *+?{} 在形成匹配时只消耗必需的那些字符, 把剩下的部分留给模式的后面部分. 没有使用 "U" 选项时, 可以在这些字符后加上问号来限定它们为非贪婪的. 相反地, 使用了 "U" 选项时, 问号会成为贪婪匹配的限定符.
X | PCRE_EXTRA. 启用不兼容 Perl 的 PCRE 功能. 目前, 这样的唯一功能是在模式中的任意反斜线后跟着没有特殊含义的字母时会导致匹配失败并因此设置 ErrorLevel. 此选项会帮助保留未使用的反斜线序列供将来使用. 如果没有此选项, 反斜线后跟着没有特殊含义的字母时会被视为原义的 (即 \g 和 g 都被识别为原义的 g). 不论是否使用此选项, 没有特殊含义的非字母反斜线序列总是被视为原义的 (即 \/ 和 / 都被视为正斜杠).
P | 位置模式. 这会使 RegExMatch() 产生匹配和其子模式的位置和长度而不是匹配它们的子字符串. 更多细节请参阅 UnquotedOutputVar。
S | 研究模式来提高性能. 它可用于要执行多次的特殊模式 (尤其是复杂的模式). 如果 PCRE 找到了提高性能的方法, 则会把这个发现储存到缓存中模式的旁边, 以便在之后执行相同模式时使用 (后续使用此模式时还需要指定 S 选项, 因为要找到缓存中相同的模式则它们的选项也必须完全相同, 包括它们的顺序). (这里的研究主要指在进行匹配前使用其他一些通常较简单快速的方法进行判断, 例如假设模式至少匹配 5 个字符, 而源字符串只有 3 个, 那么正则表达式引擎会直接返回 "没有匹配" 的结果, 而不会进行匹配.)
C | 启用自动调出模式。请参阅正则表达式调出了解更多信息。
`n | 从默认的新行符 (`r`n) 切换到单独的换行符 (`n), 这是 UNIX 系统的标准. 所选择的新行符会影响 锚 (^ 和 $) 和 含句点的模式.
`r | 从默认的新行符 (`r`n) 切换到单独的回车符 (`r).
`a | 在 v1.0.46.06+, `a 可以识别任意类型的新行符, 即 `r, `n, `r`n, `v/VT/vertical tab/chr(0xB), `f/FF/formfeed/chr(0xC) 以及 NEL/next-line/chr(0x85). 在 v1.0.47.05+，新行符可以被限制为 CR、LF 和 CRLF 三种，只需要在模式的开始处（选项后面）指定大写的（*ANYCRLF）；例如 im)(*ANYCRLF)^abc$。

注: 在两个选项间可以使用空格或 tab 分隔.

常用符号和用法

. 默认情况下, 句点匹配除新行符 (`r`n) 序列外的任何单个字符, 但是这种特性可以使用 DotAll (s), 新行 (`n), 回车 (`r), `a 或 (*ANYCRLF) 选项进行改变. 例如, ab. 可以匹配 abc 和 abz 以及 ab_.
*

星号匹配零个或多个前面的字符, 字符类 或 子模式. 例如, a* 可以匹配 ab 和 aaab. 它还可以匹配完全不包含 "a" 的任意字符串的开始处.

通配符: 句点星号模式 .* 是匹配范围最广的模式之一, 因为它可以匹配零个或多个 任意 字符 (除了新行符: `r 和 `n). 例如, abc.*123 可以匹配 abcAnything123, 也能匹配 abc123.
? 问号匹配零或一个前面的字符, 字符类 或 子模式. 可以理解为 "前面的那项是可选的". 例如, colou?r 可以匹配 color 和 colour, 因为 "u" 是可选的.
+ 加号匹配一个或多个前面的字符, 字符类 或 子模式. 例如 a+ 可以匹配 ab 和 aaab. 但与 a* 和 a? 不同的是, 模式 a+ 不会匹配开始处没有 "a" 的字符串.
{min,max}

匹配出现次数介于 min 和 max 的前面的字符, 字符类 或 子模式. 例如, a{1,2} 可以匹配 ab 但只匹配 aaab 中的前两个 a.

此外, {3} 表示准确匹配 3 次, 而 {3,} 则表示匹配 3 次或更多. 注: 指定的数字必须小于 65536, 且第一个必须小于等于第二个.
[...]

字符类: 方括号把一列字符或一个范围括在了一起 (或两者). 例如, [abc] 表示 "a, b 或 c 的中任何一个字符". 使用破折号来创建范围; 例如, [a-z] 表示 "在小写字母 a 和 z (包含的) 之间的任何一个字符". 列表和范围可以组合在一起; 例如 [a-zA-Z0-9_] 表示 "字母, 数字或下划线中的任何一个字符".

字符类后面可以使用 *, ?, + 或 {min,max} 进行限定. 例如, [0-9]+ 匹配一个或多个任意数字; 因此它可以匹配 xyz123 但不会匹配 abcxyz.

通过 [[:xxx:]] 还支持下列 POSIX 命名集, 其中 xxx 是下列单词的其中一个: alnum, alpha, ascii (0-127), blank (space 或 tab), cntrl (控制字符), digit (0-9), xdigit (十六进制数), print, graph (排除了空格的打印字符), punct, lower, upper, space (空白), word (等同于 \w).

在字符类中, 只有在类中具有特殊含义的字符才需要进行转义; 例如 [\^a], [a\-b], [a\]] 和 [\\a].
[^...] 匹配 不 在类中的任何一个字符. 例如, [^/]* 匹配零个或多个 不是 正斜杠的任意字符, 例如 http://. 同样地, [^0-9xyz] 匹配既不是数字也不是 x, y 或 z 的任何一个字符.
\d | 匹配任意一个数字 (相当于类 [0-9]). 相反地，大写的\D表示“任意的非数字字符”。这个和下面的两个都可以用在 字符类 中; 例如, [\d.-] 表示 "任何数字, 句点或负号".
\s | 匹配任意单个空白字符 , 主要是空格, tab 和新行符 (`r 和 `n). 相反地, 大写的 \S 表示 "任何 非空白字符".
\w | 匹配任何单个 "单词" 字符, 即字母, 数字或下划线. 这等同于 [a-zA-Z0-9_]. 相反地, 大写的 \W 表示 "任何 非单词字符".
^
$

抑扬符 (^) 和美元符 ($) 被称为 锚, 因为它们不消耗任何字符; 相反地, 它们把模式限定在被搜索字符串的开始或末尾进行匹配.

在模式的开始处使用 ^ 表示需要在行的开始处进行匹配. 例如, ^abc 可以匹配 abc123 但不匹配 123abc.

在模式的末尾处使用 $ 表示需要在行的末端进行匹配. 例如, abc$ 可以匹配 123abc 但不能匹配 abc123.

这两个锚还可以组合使用. 例如, ^abc$ 仅匹配 abc (即在它的前面或后面不能有另外的字符).

如果被搜索的文本包含多行, 则可以使用 "m" 选项 让锚应用于每行而不是把所有文本作为整体. 例如, m)^abc$ 可以匹配 123`r`nabc`r`n789. 但如果没有 "m" 选项, 则不会形成匹配.
\b | \b 表示 "单词边界", 它类似锚, 因为它不消耗任何字符. 它要求当前字符的 状态为单词字符 (\w), 与前一个字符的状态相反. 它通常用来避免意外地匹配到在其他单词内的某个单词. 例如, \bcat\b 不会匹配 catfish, 但它可以匹配不论周围是否有标点或空白的 cat. 大写的 \B 则相反: 它要求当前字符 不是 单词的边界.
| 竖线将两个或多个可选项目分隔开来. 如果可选项目中 任何一个 满足条件, 则会形成匹配. 例如, gray|grey 既可以匹配 gray 也可以匹配 grey. 同样地, 模式 gr(a|e)y 中通过下面描述的括号的帮助可以实现同样的作用.
(...)

括在括号中的项目常用于:

  • 确定求值的顺序. 例如, (Sun|Mon|Tues|Wednes|Thurs|Fri|Satur)day 可以匹配任何一天的名称.
  • 把 *, ?, + 或 {min,max} 应用到 系列 字符而不只是单个字符. 例如, (abc)+ 匹配一个或一串字符串 "abc"; 因此它可以匹配 abcabc123 但不会匹配 ab123 或 bc123.
  • 捕获子模式, 例如 abc(.*)xyz 中的句点星号. 例如, RegExMatch() 会把匹配每个子模式的子字符串保存到 输出数组. 同样地, RegExReplace() 中允许把匹配每个子模式的子字符串通过像 $1 这样的 后向引用 重新插入到替换结果中. 要使用不捕获子模式的括号, 请把括号内的开始两个字符指定为 ?:; 例如: (?:.*)
  • 在匹配过程中改变 选项. 例如, (?im) 会为模式的后续部分打开不区分大小写和多行选项 (如果它在子模式中则它会改变子模式的选项). 相反地, (?-im) 会关闭它们. 支持除 DPS`r`n`a 外的所有选项.
\t
\r
等等.

这些转义序列表示特殊的字符. 最常见的有 \t (tab), \r (回车) 和 \n (换行). 在 AutoHotkey, 在这些情况中还可以使用重音符 (`) 代替反斜线. 还支持 \xhh 格式的转义序列, 其中 hh 是介于 00 和 FF 之间的任意 ANSI 字符的十六进制码.

在 v1.0.46.06+, \R 表示 "单个任意类型的新行符", 即在 `a 选项 中列出的这些 (然而, \R 在 字符类 中仅仅表示字母 "R"). 在 v1.0.47.05+, \R 可以被限制为 CR, LF 和 CRLF 三种, 只需要在模式的开始处 (选项后面) 指定大写的 (*BSR_ANYCRLF) ; 例如 im)(*BSR_ANYCRLF)abc\Rxyz
\p{xx}
\P{xx}
\X

[AHK_L 61+]: Unicode 字符属性. 在 ANSI 版本中不支持. \p{xx} 匹配带 xx 属性的字符而 \P{xx} 匹配 不带 xx 属性的任意一个字符. 例如, \pL 匹配任意一个字母而 \p{Lu} 匹配任意一个大写字母. \X 匹配组成扩展 Unicode 序列的任何数目的字符.

对于受支持的属性名称的完整列表和其他细节, 请在 www.pcre.org/pcre.txt 中搜索 "\p{xx}".
(*UCP)

[AHK_L 61+]: 考虑到性能, \d, \D, \s, \S, \w, \W, \b 和 \B 默认情况下只识别 ASCII 字符, 即使在 Unicode 版本中也是如此. 如果模式以 (*UCP) 开头, 则会使用 Unicode 属性来判断哪个字符匹配. 例如, \w 变成相当于 [\p{L}\p{N}_] 而 \d 变成等同于 \p{Nd}.

贪婪：默认情况下，*、?、+ 和 {min,max} 是贪婪的，因为它们消耗到最后一个能满足整个模式的可能的所有字符。要让它们停在 首个 可能的字符, 请在它们后面加上问号. 例如, 模式 <.+> (其中没有问号) 表示: "搜索一个 <, 接着一个或多个任意字符, 然后是一个 >". 要在匹配 整个 字符串 <em>text</em> 时停止, 请在加号后加上问号: <.+?>. 这样会让匹配在第一个 '>' 处停止, 因此它只匹配第一个标签 <em>.

预测和回顾断言：这组 (?=...)、(?!...)、(?<=...) 和 (?<!...) 被称为断言，因为它们要求符合某个条件但不消耗任何字符。例如, abc(?=.*xyz) 中含有预测断言, 它要求在字符串 abc 右边的某个位置存在字符串 xyz (如果不存在, 则匹配失败). (?=...) 被称为 正 预测断言, 因为它要求指定的模式存在. 相反地, (?!...) 是 负 预测断言, 因为它要求指定的模式 不 存在. 同样地, (?<=...) 和 (?<!...) 分别是正的和负的 回顾 断言, 因为它们检查当前位置的 左边 而不是右边. 回顾比预测受到更多的限制, 因为它们不支持可变大小的限定符, 例如 *, ? 和 +. 转义序列 \K 类似于回顾断言, 因为它会让前一个匹配的字符在最后的匹配字符串中省略. 例如, foo\Kbar 可以匹配 "foobar" 但报告匹配的结果为 "bar".

相关: 正则表达式由 RegExMatch(), RegExReplace() 和 SetTitleMatchMode 支持.

最后说明: 尽管这个页面涉及了大多数常用的正则表达式功能, 但是还有相当一部分您可能希望了解的其他功能没有提及, 例如条件子模式. 完整的 PCRE 手册请访问 www.pcre.org/pcre.txt


正则表达式调出

正则表达式调出 [AHK_L 14+]

调出提供了在正则表达式模式匹配过程中临时传递控制到脚本的方法。关于 PCRE 标准调出功能的详细信息，请参阅 pcre.txt。

调出当前只有 RegExMatch 和 RegExReplace 支持。

语法

在 AutoHotkey 中调出的语法为 (?CNumber:Function)，其中 Number 和 Function 都是可选的。只有在指定了 Function 才允许使用冒号, 而如果省略 Number 则冒号也可以省略. 如果指定的 Function 不是自定义的函数名称, 则会出现编译错误且不会开始模式匹配.

如果省略 Function, 则必须在 pcre_callout 变量中指定函数名称. 如果同时存在此名称的全局变量和局部变量, 则局部变量优先. 如果 pcre_callout 没有包含自定义函数的名称，那么省略了 Function 的调出会被忽略。

调出函数

Function(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx)
{
    ...
}

调出函数最多可以定义 5 个参数：

  • Match: 相当于 RegExMatch 中的 UnquotedOutputVar, 包含需要时数组变量的创建.
  • CalloutNumber：接收调出的 Number。
  • FoundPos: 接收当前可能匹配的位置.
  • Haystack: 接收传递给 RegExMatch 或 RegExReplace 的 Haystack.
  • NeedleRegEx: 接收传递给 RegExMatch 或 RegExReplace 的 NeedleRegEx.

这些名称只是暗示性的. 实际中可以使用其他的名称.

模式匹配是继续进行或失败，取决于调出函数的返回值：

  • 如果函数返回 0 或没有返回数值, 则匹配操作如常进行.
  • 如果函数返回 1 或更大的数字, 则在当前位置匹配失败, 但继续进行剩余部分的匹配测试.
  • 如果函数返回 -1, 则匹配中止.
  • 如果函数返回小于 -1 的值, 则它被视为 PCRE 错误码且匹配中止. RegExMatch 返回空字符串, 而 RegExReplace 返回原始的 Haystack. 在这两个函数中, ErrorLevel 都包含了错误码.

例如：

Haystack = The quick brown fox jumps over the lazy dog.
RegExMatch(Haystack, "i)(The) (\w+)\b(?CCallout)")
Callout(m) {
    MsgBox m=%m%`nm1=%m1%`nm2=%m2%
    return 1
}

在上面的例子中，对于匹配调出之前的那部分模式的每个子字符串都会调用一次 Func。使用 \b 排除匹配到不完整的单词, 例如 The quic, The qui, The qu, 等等.

EventInfo

通过 A_EventInfo 可以使用 pcre_callout_block 结构的附加信息.

version           := NumGet(A_EventInfo,  0, "Int")
callout_number    := NumGet(A_EventInfo,  4, "Int")
offset_vector     := NumGet(A_EventInfo,  8)
subject           := NumGet(A_EventInfo,  8 + A_PtrSize)
subject_length    := NumGet(A_EventInfo,  8 + A_PtrSize*2, "Int")
start_match       := NumGet(A_EventInfo, 12 + A_PtrSize*2, "Int")
current_position  := NumGet(A_EventInfo, 16 + A_PtrSize*2, "Int")
capture_top       := NumGet(A_EventInfo, 20 + A_PtrSize*2, "Int")
capture_last      := NumGet(A_EventInfo, 24 + A_PtrSize*2, "Int")
pad := A_PtrSize=8 ? 4 : 0  ; 补足 64 位的数据偏移.
callout_data      := NumGet(A_EventInfo, 28 + pad + A_PtrSize*2)
pattern_position  := NumGet(A_EventInfo, 28 + pad + A_PtrSize*3, "Int")
next_item_length  := NumGet(A_EventInfo, 32 + pad + A_PtrSize*3, "Int")
if version >= 2
    mark   := StrGet(NumGet(A_EventInfo, 36 + pad + A_PtrSize*3, "Int"), "UTF-8")

想了解更多信息, 请参阅 pcre.txt, NumGet 和 A_PtrSize.

自动调出

在模式的选项中包含 C 来启用自动调出模式。在这种情况下的调出相当于在模式里的每项前插入了 (?C255)。例如, 下面的模板可以用来调试正则表达式:

; 设置默认的调出函数。
pcre_callout = DebugRegEx

; 使用自动调出选项 C 来调用 RegExMatch。
RegExMatch("xxxabc123xyz", "C)abc.*xyz")

DebugRegEx(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx)
{
    ; 请参阅 pcre.txt 了解这些字段的说明.
    start_match       := NumGet(A_EventInfo, 12 + A_PtrSize*2, "Int")
    current_position  := NumGet(A_EventInfo, 16 + A_PtrSize*2, "Int")
    pad := A_PtrSize=8 ? 4 : 0
    pattern_position  := NumGet(A_EventInfo, 28 + pad + A_PtrSize*3, "Int")
    next_item_length  := NumGet(A_EventInfo, 32 + pad + A_PtrSize*3, "Int")

    ; 指出 >>当前匹配<<.
    _HAYSTACK:=SubStr(Haystack, 1, start_match)
        . ">>" SubStr(Haystack, start_match + 1, current_position - start_match)
        . "<<" SubStr(Haystack, current_position + 1)

    ; 指出 >>要计算的下一个项目<<.
    _NEEDLE:=  SubStr(NeedleRegEx, 1, pattern_position)
        . ">>" SubStr(NeedleRegEx, pattern_position + 1, next_item_length)
        . "<<" SubStr(NeedleRegEx, pattern_position + 1 + next_item_length)

    ListVars
    ; 按下 Pause 继续.
    Pause
}

备注

调出在当前的半线程中执行，但在调出函数返回后将恢复 A_EventInfo 原来的值。在 RegExMatch 或 RegExReplace 返回时才会设置 ErrorLevel 的值.

在一些可以确定不会发生匹配的情况下, 则会对 PCRE 进行优化来提早中止 (即此时会不进行匹配而直接返回 "没有匹配" 的结果). 对于在这些情况中的所有调出，可能需要在模式的开始处指定 (*NO_START_OPT) 来禁用这种优化。此选项需要 v1.1.05 或更高版本.


重映射操纵杆为键盘或鼠标

目录

  • 重要事项
  • 让游戏杆按钮发送键击或鼠标点击
  • 让操纵杆轴向或视点帽发送键击或鼠标点击
  • 备注

重要事项

  • 虽然可以把操纵杆按钮或轴向重映射为按键或鼠标按钮, 但不能把它重映射为其他的操纵杆按钮或轴向. 借助游戏模拟器例如 PPJoy 才有可能实现这样操作.
  • AutoHotkey 用 1 和 32 之间的一个唯一的数字来标识操纵杆上的每个按钮. 要判断这些编号, 请使用 操纵杆测试脚本.

让游戏杆按钮发送键击或鼠标点击

下面是从最简单到最复杂的三种方法. 最复杂的方法能适用于更大范围的情况 (例如需要按下按键或鼠标按钮的游戏).

方法 #1：此方法简单地发送键击和鼠标点击。例如：

Joy1::Send {Left}  ; 让按钮 #1 发送左方向键的键击.
Joy2::Click  ; 让按钮 #2 发送鼠标左键的点击.
Joy3::Send a{Esc}{Space}{Enter}  ; 让按钮 #3 发送字母 "a" 后面跟着 Escape, Space 以及 Enter.
Joy4::Send Sincerely,{Enter}John Smith  ; 让按钮 #4 发送两行的签名.

要让一个按钮执行多个命令, 请把首个命令放到按钮名称的 下面 并使用 return 作为最后一个命令. 例如：

Joy5::
Run Notepad
WinWait Untitled - Notepad
WinActivate
Send This is the text that will appear in Notepad.{Enter}
return

请参阅 按键列表 来了解按键和鼠标/游戏杆按钮的完整列表.

方法 #2：必须使用此方法的情况是当您在按住操纵杆按钮的整个过程中必须按住按键或鼠标按钮的时候。下面的例子把操纵杆的第二个按钮映射为左方向键：

Joy2::
Send {Left down}  ; 按住左方向键.
KeyWait Joy2  ; 等待用户释放操纵杆按钮.
Send {Left up}  ; 释放左方向键.
return

方法 #3：必须使用此方法的情况是在您设置了多个方法 #2 中描述的热键类型，且有时需要同时按下和释放这些热键的时候。下面的例子把操纵杆的第三个按钮映射为鼠标左键:

Joy3::
Send {LButton down}   ; 按住鼠标左键.
SetTimer, WaitForButtonUp3, 10
return

WaitForButtonUp3:
if GetKeyState("Joy3")  ; 按钮仍处于按下的状态, 所以继续等待.
    return
; 否则按钮已经松开了.
Send {LButton up}  ; 释放鼠标左键.
SetTimer, WaitForButtonUp3, off
return

自动重复键击：有些程序或游戏可能需要您重复发送某个按键（就像您按住键盘上的那个键不放一样）。下面的例子在您按住操纵杆的第二个按钮时通过重复发送空格的键击来达到此目的.

Joy2::
Send {Space down}   ; 按下空格键.
SetTimer, WaitForJoy2, 30  ; 减小数字 30 到 20 或 10 来更快地发送按键. 增加这个数字以减小发送的速度.
return

WaitForJoy2:
if not GetKeyState("Joy2")  ; 按钮已经释放了.
{
    Send {Space up}  ; 释放空格键.
    SetTimer, WaitForJoy2, off  ; 停止监视按钮.
    return
}
; 由于上面没有 "return", 所以按钮仍处于按住的状态.
Send {Space down}  ; 再次发送空格键击.
return

上下文相关的操纵杆按钮: #IfWinActive/Exist 指令可以用来让选择的操纵杆按钮根据窗口是否活动或存在的不同情况执行不同的动作 (或什么都不做).

把操纵杆映射为鼠标: 操纵杆映射到鼠标的脚本 通过重映射操纵杆的按钮和轴向控制器来把操纵杆变成鼠标.

让操纵杆轴向或视点帽发送键击或鼠标点击

要让脚本对操纵杆轴向或视点帽的移动进行响应, 请使用 SetTimer 和 GetKeyState. 下面的例子让 X 和 Y 轴的功能像键盘上的方向键群 (左, 右, 上和下):

#Persistent  ; 让脚本保持运行, 直到用户明确退出.
SetTimer, WatchAxis, 5
return

WatchAxis:
GetKeyState, JoyX, JoyX  ; 获取 X 轴的位置.
GetKeyState, JoyY, JoyY  ; 获取 Y 轴的位置.
KeyToHoldDownPrev = %KeyToHoldDown%  ; Prev 现在保存了之前按下的按键（如果有）。

if JoyX > 70
    KeyToHoldDown = Right
else if JoyX < 30
    KeyToHoldDown = Left
else if JoyY > 70
    KeyToHoldDown = Down
else if JoyY < 30
    KeyToHoldDown = Up
else
    KeyToHoldDown =

if KeyToHoldDown = %KeyToHoldDownPrev%  ; 已经按下了正确的按键 (或者不需要按键).
    return  ; 什么都不做.

; 否则, 释放之前的按键并按下新按键:
SetKeyDelay -1  ; 避免键击之间的延迟.
if KeyToHoldDownPrev   ; 要释放之前的按键.
    Send, {%KeyToHoldDownPrev% up}  ; 释放它.
if KeyToHoldDown   ; 要按下按键.
    Send, {%KeyToHoldDown% down}  ; 按下它.
return

下面的例子让操纵杆的视点帽的功能像键盘上的方向键群; 即视点帽会发送方向键的键击 (左, 右, 上和下):

#Persistent  ; 让脚本保持运行，直到用户明确退出。
SetTimer, WatchPOV, 5
return

WatchPOV:
GetKeyState, POV, JoyPOV  ; 获取 POV 控制器的位置。
KeyToHoldDownPrev = %KeyToHoldDown%  ; Prev现在保存了之前按下的按键（如果有）。

; 有些操纵杆可能有平滑/连续的视角切换而不是使用固定的增幅。; 要全部支持它们, 请使用范围:
if POV < 0   ; 没有角度
    KeyToHoldDown =
else if POV > 31500                 ; 315 至 360 度: 向前
    KeyToHoldDown = Up
else if POV between 0 and 4500      ; 0 至 45 度: 向前
    KeyToHoldDown = Up
else if POV between 4501 and 13500  ; 45 至 135 度: 向右
    KeyToHoldDown = Right
else if POV between 13501 and 22500 ; 135 至 225 度: 向下
    KeyToHoldDown = Down
else                                ; 225 到 315 度: 向左
    KeyToHoldDown = Left

if KeyToHoldDown = %KeyToHoldDownPrev%  ; 已经按下了正确的按键 (或不需要按键).
    return  ; 什么都不做.

; 否则, 释放之前的按键并按下新键:
SetKeyDelay -1  ; 避免键击之间的延迟.
if KeyToHoldDownPrev   ; 要释放之前的按键.
    Send, {%KeyToHoldDownPrev% up}  ; 释放它.
if KeyToHoldDown   ; 要按下按键.
    Send, {%KeyToHoldDown% down}  ; 按下它.
return

自动重复键击: 上面的两个例子都可以修改为重复发送按键, 而不只是按住它 (即它们可以模拟按住了某个按键). 要做到这点, 请把下面这行:

return  ; 什么都不做.

替换为:

{
    if KeyToHoldDown
        Send, {%KeyToHoldDown% down}  ; 自动重复的键击.
    return
}

备注

通过在按钮或轴的名称之前加上操纵杆的编号可以使用首个外的其他操纵杆. 例如，2Joy1 表示第二个操纵杆的首个按钮。

要找到其他有用的操纵杆脚本, 请访问 AutoHotkey 论坛. 进行类似 Joystick and GetKeyState and Send 的关键词搜索有可能找到有趣的主题.

相关主题

操纵杆到鼠标的映射脚本 (把操纵杆作为鼠标使用)
操纵杆按钮, 轴向和控制器的列表
GetKeyState
重映射键盘和鼠标


PostMessage/SendMessage 教程

发送消息到窗口或其控件
作者: Rajat

本页讨论 PostMessage 和 SendMessage 命令并将回答这样一些问题:

"如何按下已最小化窗口中的按钮?"
"当 WinMenuSelectItem 不起作用时, 我如何选择一个菜单项?!"
"这是个可更换皮肤的窗口.... 如何确保我每次发送的命令都有效?"
"如果是 隐藏 窗口呢?!"

要求: AutoHotkey v1.0.09+ 和 Winspector Spy (http://www.softpedia.com/get/Security/Security-Related/Winspector.shtml)

像第一个例子那样, 请注意 WinMenuSelectItem 对 Outlook Express 的 "New Message" 窗口中的菜单栏无效. 换句话说, 这代码不起作用:

WinMenuSelectItem, New Message,, &Insert, &Picture...

但 PostMessage 能实现这个操作:

PostMessage, 0x111, 40239, 0, , New Message

太神奇了!但那个是什么? 0x111 是 wm_command 消息 的十六进制代码, 而 40239 是这个特殊窗口理解为选择 'Insert Picture' 菜单项的代码. 现在让我告诉您如何找到类似 40239 这样的值:

  1. 启动 Winspector Spy, 打开 "New Message" 窗口.
  2. 拖动 Winspector Spy 窗口中的十字线到 "New Message" 窗口的标题栏 (没有被 Winspector Spy 覆盖的部分).
  3. 在左边的列表中右键点击所选窗口并选择 'Messages'.
  4. 右键点击空白窗口并选择 'Edit message filter'.
  5. 点击 'filter all' 按钮, 然后双击左边列表中的 'wm_command'. 这样您将只监视此消息.
  6. 现在转到 "New Message" 窗口并在菜单栏中选择: Insert > Picture.
  7. 返回 Winspector Spy 并按下信号灯按钮来停止监视.
  8. 展开收集到的 wm_command 消息 (忽略其他的).
  9. 您想要找的 (通常) 是代码为 0 的消息. 有时会有一些描述为 'win activated' 或 'win destroyed' 以及其他..的 wm_command 消息都是不需要的内容. 您会发现描述为 'Control ID: 40239' 的消息 ...就是它了!
  10. 现在把它放入上面的命令中您就完成了!它就是 wParam 值.

在下一个例子中我会使用画图程序, 因为很可能每个人都会有. 现在假设我们要使用 AutoHotkey 从工具栏中选择一个工具; 假设要选择取色工具.

您会怎么做? 很可能是使用鼠标点击工具栏, 对吗? 但是按钮可能被移动且隐藏了!这个画图程序的工具栏也可能被移动/隐藏. 所以如果目标用户这么做了, 那么您的脚本在这个点上会失效. 但是下面的命令仍然有效:

PostMessage, 0x111, 639,,,untitled - Paint

PostMessage 的另一个好处是窗口可以在后台; 与之相比, 发送鼠标点击要求目标窗口必须是活动的.

这里有其他的例子. 请注意: 我使用的是 WinXP Pro (SP1) ... 如果您使用不同的操作系统, 那么您的参数可能要改变 (仅适用于像写字板和记事本这类 windows 自带的应用程序; 其他的程序应该不用改变):

;设置写字板字体为青色
PostMessage, 0x111, 32788, 0, , Document - WordPad
;打开记事本的关于对话框
PostMessage, 0x111, 65, 0, , Untitled - Notepad
;切换记事本的自动换行属性
PostMessage, 0x111, 32, 0, , Untitled - Notepad
;在 Windows Media Player 中播放/暂停
PostMessage, 0x111, 32808, 0, , Windows Media Player
;挂起正在运行的 AHK 脚本的热键
DetectHiddenWindows, on
SetTitleMatchMode, 2
PostMessage, 0x111, 65305,,, MyScript.ahk - AutoHotkey ; 和挂起操作不同，必须使用 65306 来暂停。

上面讲的是 PostMessage. SendMessage 的工作方式相同, 不过还会等待返回值, 这个值可用于一些情况中, 例如获取 Winamp 中当前正在播放的曲目 (请参阅 自动化 Winamp 的例子).

这里是一些注意事项:

  • 上文也提到了操作系统是 XP 且需要注意消息值随着不同的操作系统而改变. 如果您发现一个消息在您的系统上有效 (对于一个软件的某个版本), 那么在其他系统上它对于这个软件的相同版本仍然是有效的. 此外, 大多数应用程序甚至会在它们的不同版本中使用相同的消息值 (例如 Windows Media Player 和 Winamp).
  • 如果您已经在 Winspector Spy 中设置了过滤器来只显示 wm_command 消息, 却仍然得到大量的消息时, 请右键点击那些不需要的消息并选择隐藏 (消息名)... 这些消息一般是不是由于您和目标软件交互所产生的消息.
  • 在 Winspector Spy 中向右的箭头显示消息值, 而模糊的左箭头显示返回值. 返回值 0 (零) 默认情况下可以安全地认为 '没有错误' (与 SendMessage 一起使用, 返回值会存储在 %ErrorLevel%).
  • 要传递消息到匹配部分标题的窗口, 请添加此行到脚本:
    SetTitleMatchMode, 2
  • 要传递消息到隐藏窗口, 请添加此行到脚本:
    DetectHiddenWindows, On

注: 此技术对某些应用程序无效. 我对 VB 和 Delphi 编写的应用程序只能侥幸. 此技术最适用于 C, C++ 编写的应用程序. 对于 VB 应用程序相同命令的 'LParam' 参数在传递时总是变化的. 对于 Delphi 应用程序... 一些程序的 GUI 甚至不使用 wm_command. 它或许使用鼠标位置和点击吧.

去探索吧.... 并且记得在 AutoHotkey 论坛分享您的经验. 欢迎反馈!

这个指南并不是为新手们准备的 (没有冒犯的意思), 因为这些命令被认为是高级功能. 所以如果读完本文，您还是摸不着头脑，请忘了它吧。

-Rajat


Windows 消息列表

下面是用于 PostMessage 和 SendMessage 中 Msg 参数的值的列表. 要找到如何使用特殊消息的更多细节 (例如 WM_VSCROLL), 请在 http://msdn.microsoft.com 或您喜欢的搜索引擎中搜索消息的名称. 同时, 认真学习 消息指南.

WM_NULL = 0x00
WM_CREATE = 0x01
WM_DESTROY = 0x02
WM_MOVE = 0x03
WM_SIZE = 0x05
WM_ACTIVATE = 0x06
WM_SETFOCUS = 0x07
WM_KILLFOCUS = 0x08
WM_ENABLE = 0x0A
WM_SETREDRAW = 0x0B
WM_SETTEXT = 0x0C
WM_GETTEXT = 0x0D
WM_GETTEXTLENGTH = 0x0E
WM_PAINT = 0x0F
WM_CLOSE = 0x10
WM_QUERYENDSESSION = 0x11
WM_QUIT = 0x12
WM_QUERYOPEN = 0x13
WM_ERASEBKGND = 0x14
WM_SYSCOLORCHANGE = 0x15
WM_ENDSESSION = 0x16
WM_SYSTEMERROR = 0x17
WM_SHOWWINDOW = 0x18
WM_CTLCOLOR = 0x19
WM_WININICHANGE = 0x1A
WM_SETTINGCHANGE = 0x1A
WM_DEVMODECHANGE = 0x1B
WM_ACTIVATEAPP = 0x1C
WM_FONTCHANGE = 0x1D
WM_TIMECHANGE = 0x1E
WM_CANCELMODE = 0x1F
WM_SETCURSOR = 0x20
WM_MOUSEACTIVATE = 0x21
WM_CHILDACTIVATE = 0x22
WM_QUEUESYNC = 0x23
WM_GETMINMAXINFO = 0x24
WM_PAINTICON = 0x26
WM_ICONERASEBKGND = 0x27
WM_NEXTDLGCTL = 0x28
WM_SPOOLERSTATUS = 0x2A
WM_DRAWITEM = 0x2B
WM_MEASUREITEM = 0x2C
WM_DELETEITEM = 0x2D
WM_VKEYTOITEM = 0x2E
WM_CHARTOITEM = 0x2F

WM_SETFONT = 0x30
WM_GETFONT = 0x31
WM_SETHOTKEY = 0x32
WM_GETHOTKEY = 0x33
WM_QUERYDRAGICON = 0x37
WM_COMPAREITEM = 0x39
WM_COMPACTING = 0x41
WM_WINDOWPOSCHANGING = 0x46
WM_WINDOWPOSCHANGED = 0x47
WM_POWER = 0x48
WM_COPYDATA = 0x4A
WM_CANCELJOURNAL = 0x4B
WM_NOTIFY = 0x4E
WM_INPUTLANGCHANGEREQUEST = 0x50
WM_INPUTLANGCHANGE = 0x51
WM_TCARD = 0x52
WM_HELP = 0x53
WM_USERCHANGED = 0x54
WM_NOTIFYFORMAT = 0x55
WM_CONTEXTMENU = 0x7B
WM_STYLECHANGING = 0x7C
WM_STYLECHANGED = 0x7D
WM_DISPLAYCHANGE = 0x7E
WM_GETICON = 0x7F
WM_SETICON = 0x80

WM_NCCREATE = 0x81
WM_NCDESTROY = 0x82
WM_NCCALCSIZE = 0x83
WM_NCHITTEST = 0x84
WM_NCPAINT = 0x85
WM_NCACTIVATE = 0x86
WM_GETDLGCODE = 0x87
WM_NCMOUSEMOVE = 0xA0
WM_NCLBUTTONDOWN = 0xA1
WM_NCLBUTTONUP = 0xA2
WM_NCLBUTTONDBLCLK = 0xA3
WM_NCRBUTTONDOWN = 0xA4
WM_NCRBUTTONUP = 0xA5
WM_NCRBUTTONDBLCLK = 0xA6
WM_NCMBUTTONDOWN = 0xA7
WM_NCMBUTTONUP = 0xA8
WM_NCMBUTTONDBLCLK = 0xA9

WM_KEYFIRST = 0x100
WM_KEYDOWN = 0x100
WM_KEYUP = 0x101
WM_CHAR = 0x102
WM_DEADCHAR = 0x103
WM_SYSKEYDOWN = 0x104
WM_SYSKEYUP = 0x105
WM_SYSCHAR = 0x106
WM_SYSDEADCHAR = 0x107
WM_KEYLAST = 0x108

WM_IME_STARTCOMPOSITION = 0x10D
WM_IME_ENDCOMPOSITION = 0x10E
WM_IME_COMPOSITION = 0x10F
WM_IME_KEYLAST = 0x10F

WM_INITDIALOG = 0x110
WM_COMMAND = 0x111
WM_SYSCOMMAND = 0x112
WM_TIMER = 0x113
WM_HSCROLL = 0x114
WM_VSCROLL = 0x115
WM_INITMENU = 0x116
WM_INITMENUPOPUP = 0x117
WM_MENUSELECT = 0x11F
WM_MENUCHAR = 0x120
WM_ENTERIDLE = 0x121

WM_CTLCOLORMSGBOX = 0x132
WM_CTLCOLOREDIT = 0x133
WM_CTLCOLORLISTBOX = 0x134
WM_CTLCOLORBTN = 0x135
WM_CTLCOLORDLG = 0x136
WM_CTLCOLORSCROLLBAR = 0x137
WM_CTLCOLORSTATIC = 0x138

WM_MOUSEFIRST = 0x200
WM_MOUSEMOVE = 0x200
WM_LBUTTONDOWN = 0x201
WM_LBUTTONUP = 0x202
WM_LBUTTONDBLCLK = 0x203
WM_RBUTTONDOWN = 0x204
WM_RBUTTONUP = 0x205
WM_RBUTTONDBLCLK = 0x206
WM_MBUTTONDOWN = 0x207
WM_MBUTTONUP = 0x208
WM_MBUTTONDBLCLK = 0x209
WM_MOUSEWHEEL = 0x20A
WM_MOUSEHWHEEL = 0x20E

WM_PARENTNOTIFY = 0x210
WM_ENTERMENULOOP = 0x211
WM_EXITMENULOOP = 0x212
WM_NEXTMENU = 0x213
WM_SIZING = 0x214
WM_CAPTURECHANGED = 0x215
WM_MOVING = 0x216
WM_POWERBROADCAST = 0x218
WM_DEVICECHANGE = 0x219

WM_MDICREATE = 0x220
WM_MDIDESTROY = 0x221
WM_MDIACTIVATE = 0x222
WM_MDIRESTORE = 0x223
WM_MDINEXT = 0x224
WM_MDIMAXIMIZE = 0x225
WM_MDITILE = 0x226
WM_MDICASCADE = 0x227
WM_MDIICONARRANGE = 0x228
WM_MDIGETACTIVE = 0x229
WM_MDISETMENU = 0x230
WM_ENTERSIZEMOVE = 0x231
WM_EXITSIZEMOVE = 0x232
WM_DROPFILES = 0x233
WM_MDIREFRESHMENU = 0x234

WM_IME_SETCONTEXT = 0x281
WM_IME_NOTIFY = 0x282
WM_IME_CONTROL = 0x283
WM_IME_COMPOSITIONFULL = 0x284
WM_IME_SELECT = 0x285
WM_IME_CHAR = 0x286
WM_IME_KEYDOWN = 0x290
WM_IME_KEYUP = 0x291

WM_MOUSEHOVER = 0x2A1
WM_NCMOUSELEAVE = 0x2A2
WM_MOUSELEAVE = 0x2A3

WM_CUT = 0x300
WM_COPY = 0x301
WM_PASTE = 0x302
WM_CLEAR = 0x303
WM_UNDO = 0x304

WM_RENDERFORMAT = 0x305
WM_RENDERALLFORMATS = 0x306
WM_DESTROYCLIPBOARD = 0x307
WM_DRAWCLIPBOARD = 0x308
WM_PAINTCLIPBOARD = 0x309
WM_VSCROLLCLIPBOARD = 0x30A
WM_SIZECLIPBOARD = 0x30B
WM_ASKCBFORMATNAME = 0x30C
WM_CHANGECBCHAIN = 0x30D
WM_HSCROLLCLIPBOARD = 0x30E
WM_QUERYNEWPALETTE = 0x30F
WM_PALETTEISCHANGING = 0x310
WM_PALETTECHANGED = 0x311

WM_HOTKEY = 0x312
WM_PRINT = 0x317
WM_PRINTCLIENT = 0x318

WM_HANDHELDFIRST = 0x358
WM_HANDHELDLAST = 0x35F
WM_PENWINFIRST = 0x380
WM_PENWINLAST = 0x38F
WM_COALESCE_FIRST = 0x390
WM_COALESCE_LAST = 0x39F
WM_DDE_FIRST = 0x3E0
WM_DDE_INITIATE = 0x3E0
WM_DDE_TERMINATE = 0x3E1
WM_DDE_ADVISE = 0x3E2
WM_DDE_UNADVISE = 0x3E3
WM_DDE_ACK = 0x3E4
WM_DDE_DATA = 0x3E5
WM_DDE_REQUEST = 0x3E6
WM_DDE_POKE = 0x3E7
WM_DDE_EXECUTE = 0x3E8
WM_DDE_LAST = 0x3E8

WM_USER = 0x400
WM_APP = 0x8000


GUI 样式

用于Gui和GuiControl命令的可用样式

目录

  • 用于 Gui/父窗口和大多数控件类型的通用样式
  • Text | Edit | UpDown | Picture
  • Button | Checkbox | Radio | GroupBox
  • DropDownList | ComboBox
  • ListBox | ListView | TreeView
  • DateTime | MonthCal
  • Slider | Progress | Tab | StatusBar

通用样式 | 值 | 说明
GUI 窗口默认样式 |  | WS_POPUP、WS_CAPTION、WS_SYSMENU、WS_MINIMIZEBOX
GUI 窗口强制样式 |  | WS_CLIPSIBLINGS
WS_BORDER | 0x800000 | +/-Border. 创建含有薄边框的窗口.
WS_POPUP | 0x80000000 | 创建弹出窗口. 此样式不能和 WS_CHILD 样式一起使用。
WS_CAPTION | 0xC00000 | +/-Caption. 创建含有标题栏的窗口. 此样式是 WS_BORDER 和 WS_DLGFRAME 数值的和。
WS_DISABLED | 0x8000000 | +/-Disabled. 创建初始禁用的窗口.
WS_DLGFRAME | 0x400000 | 创建含有常用于对话框的边框样式的窗口.
WS_GROUP | 0x20000 | +/-Group. 表示此控件是一组控件中的首个. 此样式自动用于管理 "一次只能选一个" 的单选按钮的行为. 在极少见的连续添加两组单选按钮 (它们之间没有其他控件类型) 的情况下, 此时可以手动应用此样式到第二个单选按钮组的首个控件中, 这样可以使此控件脱离第一个单选按钮组.
WS_HSCROLL | 0x100000 | 创建含有水平滚动条的窗口.
WS_MAXIMIZE | 0x1000000 | 创建初始为最大化的窗口.
WS_MAXIMIZEBOX | 0x10000 | +/-MaximizeBox. 创建含有最大化按钮的窗口. 不能和 WS_EX_CONTEXTHELP 样式组合使用. 必须同时指定 WS_SYSMENU 样式。
WS_MINIMIZE | 0x20000000 | 创建初始为最小化的窗口.
WS_MINIMIZEBOX | 0x20000 | +/-MinimizeBox. 创建含有最小化按钮的窗口. 不能和 WS_EX_CONTEXTHELP 样式组合使用. 必须同时指定 WS_SYSMENU 样式。
WS_OVERLAPPED | 0 | 创建重叠的窗口. 重叠的窗口含有标题栏和边框. 等同于 WS_TILED 样式.
WS_OVERLAPPEDWINDOW | 0xCF0000 | 创建含有 WS_OVERLAPPED、WS_CAPTION、WS_SYSMENU、WS_THICKFRAME、WS_MINIMIZEBOX 和 WS_MAXIMIZEBOX 样式的重叠窗口。等同于 WS_TILEDWINDOW 样式.
WS_POPUPWINDOW | 0x80880000 | 创建含有 WS_BORDER、WS_POPUP 和 WS_SYSMENU 样式的弹出窗口。必须组合使用 WS_CAPTION 和 WS_POPUPWINDOW 样式来让窗口菜单可见。
WS_SIZEBOX | 0x40000 | +/-Resize. 创建含有可调整大小的边框的窗口. 等同于 WS_THICKFRAME 样式。
WS_SYSMENU | 0x80000 | +/-SysMenu. 创建在标题栏含有窗口菜单的窗口. 必须同时指定 WS_CAPTION 样式。
WS_TABSTOP | 0x10000 | +/-Tabstop. 指定当用户按下 TAB 键时可以接收键盘焦点的控件. 按 TAB 键可以把键盘焦点切换到下一个拥有 WS_TABSTOP 样式的控件。
WS_THICKFRAME | 0x40000 | 创建含有可调整大小的边框的窗口. 等同于 WS_SIZEBOX 样式
WS_VSCROLL | 0x200000 | 创建含有垂直滚动条的窗口.
WS_VISIBLE | 0x10000000 | 创建初始可见的窗口.
WS_CHILD | 0x40000000 | 创建子窗口. 拥有此样式的窗口不能含有菜单栏. 此样式不能和 WS_POPUP 样式一起使用。

Text 样式 | 值 | 说明
默认 |  | 无
强制 |  | 无
SS_BLACKFRAME | 0x7 | 指定带有使用窗框颜色描绘的框架的方形框. 在默认配色方案中此颜色为黑色.
SS_BLACKRECT | 0x4 | 指定使用当前窗框颜色填充的矩形. 在默认配色方案中此颜色为黑色.
SS_CENTER | 0x1 | +/-Center. 指定简单的矩形并在其中居中显示错误值文本. 控件会自动换行其中的文本, 一行末尾多出的文本显示到下一个居中行的开始处.
SS_ETCHEDFRAME | 0x12 | 使用 EDGE_ETCHED 边缘样式描绘静态控件的边框.
SS_ETCHEDHORZ | 0x10 | 使用 EDGE_ETCHED 边缘样式描绘静态控件的顶部和底部边缘.
SS_ETCHEDVERT | 0x11 | 使用 EDGE_ETCHED 边缘样式描绘静态控件的左右边缘.
SS_GRAYFRAME | 0x8 | 指定带有使用屏幕背景 (桌面) 颜色描绘的框架的方形框. 在默认配色方案中此颜色为灰色.
SS_GRAYRECT | 0x5 | 指定使用当前屏幕背景颜色填充的矩形. 在默认配色方案中此颜色为灰色.
SS_LEFT | 0 | +/-Left. 这是默认的. 它指定简单的矩形并在其中左对齐显示文本. 显示前会格式化文本. 一行末尾多出的文本自动显示到下一个左对齐行的开始处. 超出控件宽度的文本被截去.
SS_LEFTNOWORDWRAP | 0xC | +/-Wrap. 指定矩形并在其中左对齐显示文本. 会展开 tab, 但不自动换行文本. 超出一行的文本被截去.
SS_NOPREFIX | 0x80 | 阻止控件文本中任何的和符号 (&) 作为用于强调的前缀字符解释. 此样式用于当包含和符号 (&) 的文件名或其他字符串需要显示在文本控件中的时候.
SS_NOTIFY | 0x100 | 当用户点击控件时发送 STN_CLICKED 通告到父窗口.
SS_RIGHT | 0x2 | +/-Right. 指定矩形并在其中右对齐显示指定的文本.
SS_SUNKEN | 0x1000 | 在静态控件周围绘制半凹陷边框.
SS_WHITEFRAME | 0x9 | 指定带有使用窗口背景颜色描绘的框架的方形框. 在默认配色方案中此颜色为白色.
SS_WHITERECT | 0x6 | 指定使用当前窗口背景颜色填充的矩形. 在默认配色方案中此颜色为白色.

Edit 样式 | 值 | 说明
默认 |  | WS_TABSTOP 和 WS_EX_CLIENTEDGE （扩展样式 E0x200） 如果一个编辑控件由于初始内容包含多行、高度大于 1 行或明确指定大于 1 的行数而自动检测为多行控件时，默认将自动应用下列样式：WS_VSCROLL、ES_WANTRETURN 和 ES_AUTOVSCROLL 如果一个编辑控件被自动检测为单行，那么它默认含有 ES_AUTOHSCROLL。
强制 |  | 无
ES_AUTOHSCROLL | 0x80 | 对于多行编辑控件为 +/-Wrap, 而对于单行编辑控件为 +/-Limit. 当用户在行末输入字符时会自动把文本往右滚动 10 个字符. 当用户按下 ENTER 时, 控件会把所有文本滚动回到零位置.
ES_AUTOVSCROLL | 0x40 | 当用户在最后一行按下 ENTER 时文本向上滚动一页.
ES_CENTER | 0x1 | +/-Center. 在多行编辑控件中居中显示文本.
ES_LOWERCASE | 0x10 | +/-Lowercase. 把在编辑控件中输入的所有字符转换成小写形式.
ES_NOHIDESEL | 0x100 | 取消编辑控件的默认行为. 当控件失去输入焦点时默认会不反色显示选区, 而获得输入焦点时会反色显示选取内容. 如果指定 ES_NOHIDESEL，即使输入焦点不在控件上选区内容也会反色显示。
ES_NUMBER | 0x2000 | +/-Number. 禁止用户输入数字外的其他内容到控件中.
ES_OEMCONVERT | 0x400 | 此样式对于包含文件名的编辑控件最有用.
ES_MULTILINE | 0x4 | +/-Multi. 指定为多行编辑控件. 默认为单行编辑控件.
ES_PASSWORD | 0x20 | +/-Password. 在编辑控件中输入的每个字符的位置显示屏蔽字符来隐藏文本.
ES_READONLY | 0x800 | +/-ReadOnly. 禁止用户输入或编辑控件中的文本.
ES_RIGHT | 0x2 | +/-Right. 在多行编辑控件中右对齐显示文本.
ES_UPPERCASE | 0x8 | +/-Uppercase. 把在编辑控件中输入的所有字符转换成大写形式.
ES_WANTRETURN | 0x1000 | +/-WantReturn. 在对话框的多行编辑控件中输入文本时, 指定当用户按下 ENTER 键时则插入回车符. 如果不指定此样式, 那么按下 ENTER 键相当于点击了对话框的默认按钮. 此样式对于单行编辑控件没有效果.

UpDown 样式 | 值 | 说明
默认 | UDS_ARROWKEYS、UDS_ALIGNRIGHT、UDS_SETBUDDYINT 和 UDS_AUTOBUDDY.
强制 | 无
UDS_WRAP | 0x1 | 命名选项 "Wrap". 当用户试图超出最小值或最大值时, 会让控件返回到其范围的另一端. 如果没有 Wrap, 那么到达最大值或最小值时控件会停止.
UDS_SETBUDDYINT | 0x2 | 使得当 UpDown 控件的位置改变时会设置其伙伴控件的文本 (使用 WM_SETTEXT 消息). 但是, 如果其伙伴控件为 ListBox, 则改变 ListBox 的当前选区.
UDS_ALIGNRIGHT | 0x4 | 命名选项 "Right" (默认). 让 UpDown 定位在其伙伴控件的右边.
UDS_ALIGNLEFT | 0x8 | 命名选项 "Left". 让 UpDown 定位到其伙伴控件的左边.
UDS_AUTOBUDDY | 0x10 | 自动选择 z 顺序中前面的控件作为 UpDown 控件的伙伴控件.
UDS_ARROWKEYS | 0x20 | 允许用户使用键盘上的 Up 或 Down 方向键来增加或减少 UpDown 控件的位置.
UDS_HORZ | 0x40 | 命名选项 "Horz". 让控件的箭头指向左右而不是上下.
UDS_NOTHOUSANDS | 0x80 | 在伙伴控件中每三个十进制位之间不插入千位分隔符.
UDS_HOTTRACK | 0x100 | 让控件展示 "热跟踪" 行为. 即鼠标从控件按钮上通过时高亮控件按钮. 在 Windows XP 中当桌面主题覆盖此样式时它会被忽略。
(十六进制)

把伙伴控件中显示的数字格式从十进制改变为十六进制, 请参照此例:

Gui +LastFound
SendMessage, 1133, 16, 0, msctls_updown321 ; 1133 为 UDM_SETBASE

然而, 这种方法只影响伙伴控件, 而不影响 UpDown 报告的位置.

Picture 样式 | 值 | 说明
默认 |  | 无
强制 |  | 对于图标和光标为 SS_ICON. 对于其他图像类型为 SS_BITMAP.
SS_REALSIZECONTROL | 0x40 | [Windows XP 或更高版本] 调整位图以适应控件的大小.
SS_CENTERIMAGE | 0x200 | 让位图在控件中居中显示. 如果位图太大, 则会对其进行裁剪. 对于文本控件, 如果控件包含单行文本, 那么会在控件的可用高度内垂直居中显示文本. Microsoft Windows XP: 此样式不再使用位图或图标左上角像素的颜色来填充控件的未使用部分. 控件的未使用部分会保持背景颜色.

Button, Checkbox, Radio 和 GroupBox 样式 | 值 | 说明
默认 |  | BS_MULTILINE（不包括 GroupBox 和既没有明确设置高度或宽度也没有在它们的文本中使用任何的 CR/LF 字符的按钮、复选框以及单选按钮） WS_TABSTOP（不包括 GroupBox），但是每个单选按钮组中除首个外的其他单选按钮默认不含有 WS_TABSTOP。此外, 含有 BS_NOTIFY 的单选按钮才可以检测到双击.
强制 |  | Button：BS_PUSHBUTTON 或 BS_DEFPUSHBUTTON Radio: BS_AUTORADIOBUTTON Checkbox: BS_AUTOCHECKBOX 或 BS_AUTO3STATE GroupBox: BS_GROUPBOX
BS_LEFT | 0x100 | +/-Left. 左对齐文本.
BS_PUSHLIKE | 0x1000 | 让复选框或单选按钮的外观和行为像按钮一样. 这样按钮在没有按下或复选时是凸起的, 在按下或复选时是凹陷的.
BS_RIGHT | 0x200 | +/-Right. 右对齐文本.
BS_RIGHTBUTTON | 0x20 | +Right（即 +Right 同时包含了 BS_RIGHT 和 BS_RIGHTBUTTON，但 -Right 仅移除 BS_RIGHT，而不包括 BS_RIGHTBUTTON）。把复选框的方框或单选按钮的圆圈放在控件可用宽度的右边而不是左边.
BS_BOTTOM | 0x800 | 把文本放到控件可用高度的底部.
BS_CENTER | 0x300 | +/-Center. 在控件的可用宽度内水平居中显示文本.
BS_DEFPUSHBUTTON | 0x1 | +/-Default. 创建带浓黑边框的按钮. 如果按钮在对话框中, 即使输入焦点不在按钮上时, 用户可以按下 ENTER 键选择按钮. 此样式用于启用对最常用选项的快速选择.
BS_MULTILINE | 0x2000 | +/-Wrap. 如果文本过长而无法容纳在控件可用宽度的单行中时, 则对文本进行换行操作而变成多行. 此样式还允许使用换行符 (`n) 在文本中开始新行.
BS_TOP | 0x400 | 把文本放到控件可用高度的顶部.
BS_VCENTER | 0xC00 | 在控件的可用高度内垂直居中显示文本.
BS_FLAT | 0x8000 | 指定按钮为二维的; 它不使用默认的底纹来创建三维效果.

DropDownList 和 ComboBox 样式 | 值 | 说明
默认 |  | WS_TABSTOP (+/-Tabstop) DropDownList: WS_VSCROLL ComboBox: WS_VSCROLL, CBS_AUTOHSCROLL
强制 |  | DropDownList: CBS_DROPDOWNLIST ComboBox：CBS_DROPDOWN 或CBS_SIMPLE
CBS_AUTOHSCROLL | 0x40 | +/-Limit. 当用户在行末输入时会自动滚动编辑控件中的文本到右边. 如果未设置此样式, 那么只能输入在矩形边界中能容纳的文本数量.
CBS_DISABLENOSCROLL | 0x800 | 当列表框中不包含需要滚动的足够项目时, 在其中显示被禁用的垂直滚动条. 不含有此样式时, 当列表框中没有包含足够的项目时隐藏滚动条.
CBS_LOWERCASE | 0x4000 | +/-Lowercase. 把输入到组合框编辑控件中的所有大写字符转换成小写.
CBS_NOINTEGRALHEIGHT | 0x400 | 让组合框准确符合创建时设置的大小. 通常, Windows CE 会调整组合框的大小使得它不会只显示部分项目.
CBS_OEMCONVERT | 0x80 | 把输入到组合框编辑控件中的文本从 Windows CE 字符集转到 OEM 字符集, 然后转回 Windows CE 字符集. 此样式最常用于包含文件名的组合框. 它仅适用于使用 CBS_DROPDOWN 样式创建的组合框.
CBS_SIMPLE | 0x1 | +/-Simple (仅 ComboBox). 总是显示列表框. 在编辑控件中显示列表框中的当前选择对象.
CBS_SORT | 0x100 | +/-Sort. 按字母顺序排列下拉列表中的项目.
CBS_UPPERCASE | 0x2000 | +/-Uppercase. 把输入到组合框编辑控件中的所有小写字符转换成大写.

ListBox 样式 | 值 | 说明
默认 |  | WS_TABSTOP、LBS_USETABSTOPS、WS_VSCROLL 和 WS_EX_CLIENTEDGE（扩展样式 E0x200）。
强制 |  | LBS_NOTIFY (支持对双击的检测)
LBS_DISABLENOSCROLL | 0x1000 | 当列表框中没有包含足够项目时显示被禁用的垂直滚动条. 如果未指定此样式, 则在列表框没有包含足够项目时隐藏滚动条.
LBS_NOINTEGRALHEIGHT | 0x100 | 让列表框准确符合创建时设置的大小.
LBS_EXTENDEDSEL | 0x800 | +/-Multi. 允许通过 control-click 和 shift-click 选择多项.
LBS_MULTIPLESEL | 0x8 | 选择多项的一种简化方式, 此时不需要使用 control-click 和 shift-click, 因为普通的单击可以增加选择对象或取消选择已选择的项目.
LBS_NOSEL | 0x4000 | +/-ReadOnly. 让用户可以查看列表框中的字符串但不能进行选择.
LBS_SORT | 0x2 | +/-Sort. 按字母顺序排列列表框中的项目.
LBS_USETABSTOPS | 0x80 | 启用在描绘列表框的字符串时识别并扩展 tab 字符. 默认制表符位置为 32 个对话框单位. 一个对话框单位等于当前对话框基础宽度单位的四分之一.

ListView 样式 | 值 | 说明
默认 |  | WS_TABSTOP、LVS_REPORT、LVS_SHOWSELALWAYS、LVS_EX_FULLROWSELECT、LVS_EX_HEADERDRAGDROP、WS_EX_CLIENTEDGE（E0x200）
强制 |  | 无
LVS_ALIGNLEFT | 0x800 | 在图标和小图标视图中左对齐项目.
LVS_ALIGNTOP | 0 | 在图标和小图标视图中把项目和列表视图控件的顶部对齐. 这是默认的.
LVS_AUTOARRANGE | 0x100 | 在图标和小图标视图中让图标自动保持排列.
LVS_EDITLABELS | 0x200 | +/-ReadOnly. 指定 -ReadOnly (或 +0x200) 可以让用户编辑每行首个字段.
LVS_ICON | 0 | +Icon. 指定大图标视图.
LVS_LIST | 0x3 | +List. 指定列表视图.
LVS_NOCOLUMNHEADER | 0x4000 | +/-Hdr. 让报告视图中不显示列标题.
LVS_NOLABELWRAP | 0x80 | 在图标视图中让项目文本显示在单行. 默认情况下, 在图标视图中项目文本可能换行.
LVS_NOSCROLL | 0x2000 | 禁用滚动. 所有的项目必须在工作区内. 此样式不兼容于 LVS_LIST 或 LVS_REPORT 样式。
LVS_NOSORTHEADER | 0x8000 | +/-NoSortHdr. 让列标题不会按钮那样. 此样式可用于不希望在报告视图中点击列标题时执行动作, 例如排序.
LVS_OWNERDATA | 0x1000 | 此样式指定虚拟列表视图控件 (AutoHotkey 不直接支持).
LVS_OWNERDRAWFIXED | 0x400 | 所有者窗口可以在报告视图中描绘项目来响应 WM_DRAWITEM 消息 (AutoHotkey 不直接支持).
LVS_REPORT | 0x1 | +Report. 指定报告视图.
LVS_SHAREIMAGELISTS | 0x40 | 当控件销毁时不会删除 图像列表. 此样式启用了在多个列表视图控件中使用相同的图像列表.
LVS_SHOWSELALWAYS | 0x8 | 总是显示选择对象（如果有），即使键盘焦点不在控件上。
LVS_SINGLESEL | 0x4 | +/-Multi. 每次只能选择一项. 默认情况下, 可以选择多项.
LVS_SMALLICON | 0x2 | +IconSmall. 指定小图标视图.
LVS_SORTASCENDING | 0x10 | +/-Sort. 根据首个字段的内容对行按升序排列.
LVS_SORTDESCENDING | 0x20 | +/-SortDesc. 与上面相同, 不过这里是降序排列.
LVS_EX_BORDERSELECT | LV0x8000 | 选择一个项目后, 会改变其背景颜色而不进行高亮 (在最近的操作系统中可能不起作用).
LVS_EX_CHECKBOXES | LV0x4 | +/-Checked. 为每个项目显示一个复选框. 设置此样式后, 控件会使用 DrawFrameControl 创建和设置含两个图像的状态图像列表. 状态图像 1 为未选中的方框, 而状态图像 2 为选中的方框. 设置状态图像为零会移除复选框. Windows XP 或更高版本: 在除了 Windows XP 中引入的平铺视图模式外的所有列表视图模式中, 复选框是可见并具有功能的. 在平铺视图模式中点击复选框仅选择项目; 状态不会发生变化.
LVS_EX_FLATSB | LV0x100 | 在列表视图中启用平坦滚动条.
LVS_EX_FULLROWSELECT | LV0x20 | 选择一行时, 高亮显示它的所有字段. 此样式只有和 LVS_REPORT 样式组合使用才有效。
LVS_EX_GRIDLINES | LV0x1 | +/-Grid. 在行和列周围显示网格线. 此样式只有和 LVS_REPORT 样式组合使用才有效。
LVS_EX_HEADERDRAGDROP | LV0x10 | 在列表视图控件中启用拖放来对列重新排序. 此样式只有在含有 LVS_REPORT 样式的列表视图控件中才有效.
LVS_EX_INFOTIP | LV0x400 | 当列表视图控件使用 LVS_EX_INFOTIP 样式时, 在显示项目的工具提示前会发送 LVN_GETINFOTIP 通知消息到父窗口.
LVS_EX_LABELTIP | LV0x4000 | 在任何列表视图模式中如果部分隐藏的标签没有工具提示文本, 那么列表视图控件会展开此标签. 如果未设置此样式, 那么列表视图控件只会在大图标模式中才展开部分隐藏的标签. 需要 Windows XP 或更高版本, 或随 Internet Explorer 5.0 或更高版本一起发布的 DLL. 注: 在某些版本的 Windows 中, 如果设置 GUI 窗口为置顶时此样式可能无法正常工作.
LVS_EX_MULTIWORKAREAS | LV0x2000 | 如果列表视图控件含有 LVS_AUTOARRANGE 样式，只有在定义了一个或多个工作区域后才会自动排列其图标（请参阅 LVM_SETWORKAREAS）。要让此样式生效, 则必须在定义任何工作区域前并且在添加任何项目到控件前设置此样式.
LVS_EX_ONECLICKACTIVATE | LV0x40 | 当用户在项目上点击时, 列表视图控件会发送 LVN_ITEMACTIVATE 通知消息到父窗口. 此样式还启用了列表视图中的热跟踪功能. 热跟踪是指当鼠标移到项目上时, 会高亮显示此项目但不会进行选择.
LVS_EX_REGIONAL | LV0x200 | 设置列表视图窗口区域仅包含使用 SetWindowRgn 的项目图标和文本. 任何非项目部分的区域都被排除出窗口区域. 此样式只有在含有 LVS_ICON 样式的列表视图控件中才有效.
LVS_EX_SIMPLESELECT | LV0x100000 | 在图标视图中, 让控件的状态图像移动到大图标效果图的右上角. 不影响图标视图外的其他视图. 当用户使用空格键改变状态时, 会循环改变所有选定项目的状态, 而不是含有焦点的项目. 需要 Windows XP 或更高版本.
LVS_EX_SUBITEMIMAGES | LV0x2 | 让首个字段外的其他字段可以显示图像. 此样式只有和 LVS_REPORT 样式组合使用才有效。
LVS_EX_TRACKSELECT | LV0x8 | 在列表视图控件中启用热跟踪来选择对象. 热跟踪选择对象是指当鼠标悬停在某个项目上一段时间后自动选择此项目. 通过 LVM_SETHOVERTIME 消息可以改变这个延迟时间的系统默认值. 此样式适用于列表视图控件的所有视图模式. 通过调用 SystemParametersInfo 可以检查是否启用了热跟踪选择对象.
LVS_EX_TWOCLICKACTIVATE | LV0x80 | 当用户在项目上双击时, 列表视图控件会发送 LVN_ITEMACTIVATE 通知消息到父窗口. 此样式还启用了列表视图中的热跟踪功能. 热跟踪是指当鼠标移到项目上时, 会高亮显示此项目但不会进行选择.
LVS_EX_UNDERLINECOLD | LV0x1000 | 让那些可以被激活的非热项目带有下划线文本显示. 此样式要求同时设置 LVS_EX_TWOCLICKACTIVATE 样式。
LVS_EX_UNDERLINEHOT | LV0x800 | 让那些可以被激活的热项目带有下划线文本显示. 此样式要求同时设置 LVS_EX_ONECLICKACTIVATE 或 LVS_EX_TWOCLICKACTIVATE 样式。

TreeView 样式 | 值 | 说明
默认 |  | WS_TABSTOP、TVS_SHOWSELALWAYS、TVS_HASLINES、TVS_LINESATROOT、TVS_HASBUTTONS、WS_EX_CLIENTEDGE（E0x200）
强制 |  | 无
TVS_CHECKBOXES | 0x100 | +/-Checked. 在每个项目旁显示一个复选框.
TVS_DISABLEDRAGDROP | 0x10 | 阻止树形视图控件发送 TVN_BEGINDRAG 通知消息.
TVS_EDITLABELS | 0x8 | +/-ReadOnly. 允许用户编辑树形视图项目的名称.
TVS_FULLROWSELECT | 0x1000 | 启用树形视图中的全行选择功能. 会高亮显示被选择项目所在的行, 且点击行中的任意位置都会选择此项目. 此样式不能和 TVS_HASLINES 样式组合使用。
TVS_HASBUTTONS | 0x1 | +/-Buttons. 在父项目旁显示加号 (+) 和减号 (-) 按钮. 用户点击此按钮可以展开或折叠父项目的子项列表. 要在树形视图的根项目中包含按钮，必须同时指定 TVS_LINESATROOT。
TVS_HASLINES | 0x2 | +/-Lines. 使用线显示项目的层次结构.
TVS_INFOTIP | 0x800 | 通过发送 TVN_GETINFOTIP 通知获取工具提示信息.
TVS_LINESATROOT | 0x4 | +/-Lines. 使用线连接树形视图控件的根项目. 如果没有同时指定 TVS_HASLINES，那么此样式被忽略。
TVS_NOHSCROLL | 0x8000 | +/-HScroll. 禁用控件中的水平滚动. 控件中将不显示水平滚动条.
TVS_NONEVENHEIGHT | 0x4000 | 通过 TVM_SETITEMHEIGHT 消息设置项目的高度为奇数的高度. 默认情况下, 项目的高度必须为偶数值.
TVS_NOSCROLL | 0x2000 | 同时禁用控件中的水平滚动和垂直滚动. 控件中不会显示任何滚动条.
TVS_NOTOOLTIPS | 0x80 | 禁用工具提示.
TVS_RTLREADING | 0x40 | 让文本从右到左 (RTL) 显示. 通常窗口按从左到右 (LTR) 的顺序显示文本.
TVS_SHOWSELALWAYS | 0x20 | 在视图控件失去焦点时让选择的项目仍保持选择的.
TVS_SINGLEEXPAND | 0x400 | 在树形控件中选择后展开所选项目并折叠取消选择的项目. 如果用户在选择项目时按住了 CTRL 键, 那么不会折叠被取消选择的项目.
TVS_TRACKSELECT | 0x200 | 在树形视图控件中启用鼠标的热跟踪功能.

DateTime 样式 | 值 | 说明
默认 | DTS_SHORTDATECENTURYFORMAT 和 WS_TABSTOP（+/-Tabstop）
强制 | 无
DTS_UPDOWN | 0x1 | 在控件右边提供 up-down 控件来修改日期和时间的值, 这会替换其他的可用下拉月历.
DTS_SHOWNONE | 0x2 | 在控件中显示复选框, 取消选中此复选框可以让控件不选择日期/时间. 每当控件中没有日期/时间时, Gui Submit 和 GuiControlGet 将获取到空值 (空字符串).
DTS_SHORTDATEFORMAT | 0x0 | 显示短格式的日期. 在某些区域设置中, 它看起来像 6/1/05 或 6/1/2005. 在较旧的操作系统中, 可能显示两位数的年份. 这是 DTS_SHORTDATECENTURYFORMAT 而不是 DTS_SHORTDATEFORMAT 为默认样式的原因。
DTS_LONGDATEFORMAT | 0x4 | 格式选项“LongDate”。显示长格式的日期. 在某些区域设置中, 它看起来像 Wednesday, June 01, 2005.
DTS_SHORTDATECENTURYFORMAT | 0xC | 格式选项为空/省略。用短格式显示带四位年份的日期. 在某些区域设置中, 它看起来像 6/1/2005. 如果系统中 Comctl32.dll 的版本低于 5.8，那么不支持此样式并自动使用 DTS_SHORTDATEFORMAT 代替。
DTS_TIMEFORMAT | 0x9 | 格式选项“Time”。仅显示时间, 它在某些区域设置中看起来像 5:31:42 PM.
DTS_APPCANPARSE | 0x10 | 尚未支持. 可以让拥有者分析用户输入并执行必要的动作. 它让用户在按下 F2 键后可以对控件的工作区进行编辑. 当用户结束时控件会发送 DTN_USERSTRING 通知消息.
DTS_RIGHTALIGN | 0x20 | +/-Right. 让日历在控件的右边拉下而不是左边.
(下拉日历内的颜色设置) 下拉日历中天数的颜色遵循 Gui Font 命令或 c (Color) 选项的设置. 要改变日历其他部分的颜色, 请参照此例:
Gui +LastFound
SendMessage, 0x1006, 4, 0xFFAA99, SysDateTimePick321 ; 0x1006 为 DTM_SETMCCOLOR。4 为 MCSC_MONTHBK (背景颜色). 颜色必须使用 BGR 与 RGB 格式 (交换了红色和蓝色成分).

MonthCal 样式 | 值 | 说明
默认 | 无
强制 | 无
MCS_DAYSTATE | 0x1 | 让控件发送 MCN_GETDAYSTATE 通知来请求哪些日子应以粗体显示的信息. [尚未支持]
MCS_MULTISELECT 0x2 命名选项 "Multi". 允许用户选择日期范围而不限制为单个日期. 默认情况下, 最大的范围为 366 天, 此设置可以通过给控件发送 MCM_SETMAXSELCOUNT 消息改变. 例如：
Gui +LastFound
SendMessage, 0x1004, 7, 0, SysMonthCal321 ; 7 天。0x1004 为 MCM_SETMAXSELCOUNT.
MCS_WEEKNUMBERS | 0x4 | 在每行日子的左边显示周数 (1-52). Week 1 被定义为至少包含四天的第一周.
MCS_NOTODAYCIRCLE | 0x8 | 禁止控件中当前日期的往复循环.
MCS_NOTODAY | 0x10 | 禁止在控件的底部显示今天的日期.
(颜色) 日历中天数的颜色遵循 Gui Font 命令或 c (Color) 选项的设置. 要改变日历其他部分的颜色, 请参照此例:
Gui +LastFound
SendMessage, 0x100A, 5, 0xFFAA99, SysMonthCal321 ; 0x100A 为 MCM_SETCOLOR。5 为 MCSC_TITLETEXT (标题文本的颜色). 颜色必须使用 BGR 与 RGB 格式 (交换了红色和蓝色成分).

Slider 样式 | 值 | 说明
默认 | WS_TABSTOP (+/-Tabstop)
强制 | 无
TBS_VERT | 0x2 | +/-Vertical. 控件是垂直导向的.
TBS_LEFT | 0x4 | +/-Left. 在控件的顶部显示刻度线（如果含有 TBS_VERT 样式则在其左边）。等同于 TBS_TOP
TBS_TOP | 0x4 | 等同于 TBS_LEFT。
TBS_BOTH | 0x8 | +/-Center. 在控件的两边显示刻度线. 与 TBS_HORZ 一起使用时为顶部和底部，而与 TBS_VERT 一起时则为左右两边。
TBS_AUTOTICKS | 0x1 | 在控件值范围的每个增量处显示刻度线. 使用 +/-TickInterval 可以更灵活.
TBS_ENABLESELRANGE 0x20

让控件仅显示选择范围. 在选择范围起始位置和结束位置的刻度线显示为三角形（而不是垂直的短划线），且高亮选择范围（可能需要使用 Gui -theme 移除主题才能高亮）。

要设置选择范围, 请参照此例, 这里设置起始位置为 55 而结束位置为 66:

SendMessage, 1035, 1, 55, msctls_trackbar321, WinTitle
SendMessage, 1036, 1, 66, msctls_trackbar321, WinTitle
TBS_FIXEDLENGTH | 0x40 | +/-Thick. 允许改变滑块的大小.
TBS_NOTHUMB | 0x80 | 让控件不显示可移动的滑块.
TBS_NOTICKS | 0x10 | +/-NoTicks. 让控件不显示任何刻度线.
TBS_TOOLTIPS | 0x100 | +/-Tooltip. 让控件支持工具提示. 使用此样式创建控件时, 它会自动创建默认的工具提示控件用来显示滑动条当前的位置. 您可以使用 TBM_SETTIPSIDE 消息改变工具提示的位置.
TBS_REVERSED | 0x200 | 很遗憾, 此样式不会影响控件的实际行为, 所以使用它是毫无意义的 (相反, 在控件的选项中使用 +Invert 来反转它的效果). 根据操作系统版本, 此样式可能需要 Internet Explorer 5.0 或更高版本.
TBS_DOWNISLEFT | 0x400 | 很遗憾, 此样式不会影响控件的实际行为, 所以使用它是毫无意义的. 根据操作系统版本, 此样式可能需要 Internet Explorer 5.01 或更高版本.

Progress 样式 | 值 | 说明
默认 |  | PBS_SMOOTH
强制 |  | 无
PBS_SMOOTH | 0x1 | +/-Smooth. 进度条使用平滑滚动条而不是默认分段的条来显示进度状态. 含有此样式时, 在 Windows XP 或更高版本中控件会自动恢复到经典主题外观.
PBS_VERTICAL | 0x4 | +/-Vertical. 进度条垂直地显示进度状态, 从底部到顶部.
PBS_MARQUEE | 0x8 | [需要 Windows XP 或更高版本] 进度条会像大盖帽一样移动; 即每次移动时条会沿着其可用长度向前滑动直到碰到另一端. 含有此样式的条没有明确的位置. 相反, 每次试图改变位置时进度条将移动一格. 此样式常用来指示一个正在进行的完成时间未知的操作.

Tab 样式 | 值 | 说明
默认 |  | WS_TABSTOP 和 TCS_MULTILINE
强制 |  | WS_CLIPSIBLINGS TCS_OWNERDRAWFIXED：根据控件的背景颜色和/或文本颜色的需要强制打开或关闭。
TCS_SCROLLOPPOSITE | 0x1 | 选择一个选项卡时, 不需要的选项卡不会滚动到控件的另一边.
TCS_BOTTOM | 0x2 | +/-Bottom. 选项卡显示在控件的底部而不是顶部.
TCS_RIGHT | 0x2 | 选项卡垂直显示在使用 TCS_VERTICAL 样式控件的右边。
TCS_MULTISELECT | 0x4 | 按住 CTRL 时进行点击可以选择多个选项卡. 此样式必须和 TCS_BUTTONS 样式一起使用。
TCS_FLATBUTTONS | 0x8 | 选择的选项卡显示为缩进到背景中, 而其他选项卡和背景显示在同一平面上. 此样式只影响含 TCS_BUTTONS 样式的选项卡控件。
TCS_FORCEICONLEFT | 0x10 | 让图标和每个固定宽度选项卡的左边缘对齐. 此样式只能和 TCS_FIXEDWIDTH 样式一起使用。
TCS_FORCELABELLEFT | 0x20 | 让标签和每个固定宽度选项卡的左边缘对齐; 即标签紧跟在图标右边显示而不居中显示. 此样式只能和 TCS_FIXEDWIDTH 样式一起使用，同时它隐含了 TCS_FORCEICONLEFT 样式。
TCS_HOTTRACK | 0x40 | 让指针下的项目自动高亮显示.
TCS_VERTICAL | 0x80 | +/-Left 或 +/-Right. 选项卡显示在控件的左边, 且选项卡文本垂直显示. 此样式仅在和 TCS_MULTILINE 样式一起使用时才有效。要让选项卡显示在控件的右边，请同时使用 TCS_RIGHT 样式。 当自定义背景颜色或文本颜色有效时, 此样式将无法正确显示选项卡. 为了解决此问题, 请在选项卡控件的选项中指定 -Background 和/或 cDefault.
TCS_BUTTONS | 0x100 | +/-Buttons. 让选项卡显示为按钮, 且不在显示区域周围描绘边框.
TCS_SINGLELINE | 0 | +/-Wrap. 让所有选项卡显示在一行中. 必要时用户可以滚动来查看到更多的选项卡. 此样式是默认的.
TCS_MULTILINE | 0x200 | +/-Wrap. 必要时让选项卡显示在多行中, 这样可以同时看到所有的选项卡.
TCS_RIGHTJUSTIFY | 0 | 这是默认的. 必要时增加每个选项卡的宽度, 这样每行的选项卡会充满选项卡控件的全部宽度. 只有同时使用 TCS_MULTILINE 样式时此窗口样式才有效.
TCS_FIXEDWIDTH | 0x400 | 让所有选项卡使用相同的宽度. 此样式不能和 TCS_RIGHTJUSTIFY 样式一起组合使用。
TCS_RAGGEDRIGHT | 0x800 | 不会拉伸每行的选项卡来充满控件的全部宽度. 此样式是默认的.
TCS_FOCUSONBUTTONDOWN | 0x1000 | 点击时选项卡控件会获取输入焦点.
TCS_OWNERDRAWFIXED | 0x2000 | 父窗口负责描绘选项卡.
TCS_TOOLTIPS | 0x4000 | 选项卡控件有与其关联的工具提示控件.
TCS_FOCUSNEVER | 0x8000 | 点击时选项卡控件不获取输入焦点.

StatusBar 样式 | 值 | 说明
默认 | SBARS_TOOLTIPS 和 SBARS_SIZEGRIP （当窗口大小可调整时，则仅后者）。
强制 | 无
SBARS_TOOLTIPS 0x800

当鼠标悬停在状态栏部分上时显示工具提示: 1) 文本过多以致无法完全显示; 或 2) 含有图标但没有文本.

工具提示的文本可以使用下面的方法设置:

Gui +LastFound
SendMessage, 0x410, 0, "Text to display", msctls_statusbar321

上面的粗体 0 是从零开始的状态栏部分的编号. 要使用首个外的其他部分, 对第二个指定 1, 对第三个指定 2, 等等. 注意: 在某些操作系统版本中可能永远不会显示工具提示.
SBARS_SIZEGRIP | 0x100 | 在状态栏的右端包含一个大小调整手柄. 大小调整手柄类似于大小调整边框; 它是一个矩形区域, 用户可以点击并拖动它来调整父窗口的大小.


线程

最近事件调用的执行流被定义为 当前线程; 例子包括 热键, SetTimer 子程序, 自定义菜单项 以及 GUI 事件. 当前线程 可以在它自身子程序或由那个子程序调用其他子程序中执行命令.

尽管 AutoHotkey 实际并不支持多线程, 但它模拟了多线程的某些特性: 如果启动了第二个线程, 例如在前一个热键仍在执行时又按了另一个热键, 那么 当前线程 会被中断 (暂时停止) 来让新的线程成为 当前 线程. 如果在第二个线程还在运行时又启动了第三个线程, 那么第二个和第一个线程都会进入休眠状态, 依此类推.

当 当前线程 结束时, 最近中断的线程将恢复执行, 依此类推, 直到最后所有的线程都结束. 当线程被恢复时，它的设置例如 ErrorLevel 和 SendMode 会自动恢复到中断前的状态；换句话说，中断不会给线程带来副作用（不过活动窗口可能会变化而产生影响）。

注意: KeyHistory 命令/菜单项会显示处于中断状态的线程数量, 而 ListHotkeys 命令/菜单项则显示哪些热键拥有线程.

一个脚本可以同时含有多个 MsgBox, InputBox, FileSelectFile 和 FileSelectFolder 对话框. 这是在前一个线程已经显示对话框后启动新线程 (通过 热键, 定时子程序, 自定义菜单项 等) 实现的.

默认情况下，子程序仍在运行的的热键或热字串则不能再次启动。使用 #MaxThreadsPerHotkey 可以改变此特性.

线程优先级

优先级低于 当前线程 的任何线程 (热键, 定时子程序, 自定义菜单项 等) 不能中断当前线程. 在这种时候, 这样的计时器不会运行, 且用户试图创建线程 (例如按下 热键 或 GUI 按钮) 会没有效果, 也不会被缓存起来. 由于这个原因, 通常在设计时最好让高优先级的线程快速结束, 或使用 Critical 而不将它们设置成高优先级.

默认的优先级为 0. 所有线程使用默认的优先级, 不过可以使用下列的其中一种方法改变:
1) 通过 SetTimer 给定时子程序指定优先级.
2) 通过 Hotkey 命令给热键指定优先级.
3) 热字串 在定义时或通过 #Hotstring 可以指定优先级.
4) 通过 Menu 命令给自定义菜单项指定优先级.
5) 使用 Thread 命令给 当前线程 设置自己的优先级.

不论当前线程的优先级如何，OnExit子程序（如果有）被调用时总是会运行。


自动化 Winamp

这个章节演示了即使 Winamp 处于最小化或不活动状态时如何通过热键控制它. 这些代码已经在 Winamp 2.78c 上测试成功, 在其他主要版本应该也能良好运行. 请提交改进改进方法到论坛或联系作者.

这个例子设置 Ctrl+Alt+P 热键为按下 Winamp 的暂停/取消暂停按钮:

^!p::
IfWinNotExist ahk_class Winamp v1.x
    return
; 否则, 上面设置了下面要使用的 "上次找到的" 窗口.
ControlSend, ahk_parent, c  ; 暂停/取消暂停
return

这里是 Winamp 2.x (在其他版本中可能也有效) 中的一些快捷键. 上面的例子可以改用这些按键:

要发送的键 | 效果
c | 暂停/取消暂停
x | 播放/重放/取消暂停
v | 停止
+v | 渐隐停止
^v | 当前音轨结束后停止
b | 下一首
z | 上一首
{left} | 后退 5 秒
{right} | 前进 5 秒
{up} | 增大音量
{down} | 减小音量

; 下面这个例子获取 Winamp 中当前活动的音轨号:
SendMessage, 1024, 0, 120, ahk_class Winamp v1.x
if ErrorLevel <> FAIL
{
    ErrorLevel += 1  ; Winamp 的计数从 0 开始, 所以加 1 进行调整.
    MsgBox, Track #%ErrorLevel% is active or playing.
}


WinTitle 与最近找到的窗口

WinTitle 参数与最近找到的窗口

许多命令和一些函数中含有 WinTitle 参数用来标识要操作的窗口。此参数可以为窗口的标题或部分标题及在此页面描述的其他条件。

快速参考
标题 | 匹配行为
A | 活动窗口
ahk_class | 窗口类
ahk_id | 唯一 ID/HWND
ahk_pid | 进程 ID
ahk_exe | 进程名称、路径
ahk_group | 窗口组
 | 多重条件
（都为空） | 上次找到的窗口

匹配行为

SetTitleMatchMode 控制参数中的部分标题或完整标题与每个窗口标题的比较方式。根据这个设置，WinTitle 可以为准确的标题或包含前面部分或标题任意位置的子字符串或正则模式。这个设置还控制 ahk_class 是解释为准确的类名还是正则模式。

只有在DetectHiddenWindows 设置打开时才会检测到隐藏窗口，不过 WinShow 总是能检测到隐藏窗口。

如果多个窗口匹配 WinTitle 及其他条件，则使用最顶层的匹配窗口。如果活动窗口匹配条件，则它通常优先，因为它一般在其他所有窗口的上面。然而，如果某个置顶窗口也匹配条件（且活动窗口没有置顶），则使用这个置顶窗口。

活动窗口（A）

如果 WinTitle 为字母 A 且其他三个窗口参数（WinText、ExcludeTitle 和 ExcludeText）都为空或省略，则使用活动窗口。

; 获取活动窗口的 ID/HWND
id := WinExist("A")
MsgBox % id

; 按下 Win+↑ 来最大化活动窗口
#Up::WinMaximize, A

ahk_class 窗口类

窗口类是系统用来创建窗口的模板的属性集。换句话说，窗口类表示窗口的类型。要使用窗口类，请根据 Window Spy 显示的指定 ahk_class ExactClassName。可以用 WinGetClass 获取 ExactClassName。

如果启用了正则的标题匹配模式，则 ahk_class 接受正则表达式。

; 激活控制台窗口（即 cmd.exe）
WinActivate, ahk_class ConsoleWindowClass

ahk_id 唯一 ID / HWND

每个窗口或控件都含有唯一 ID，也称为 HWND （即窗口句柄的缩写）。即使在窗口或控件的标题改变时也可用这个 ID 来识别它。窗口的 ID 通常使用 WinExist() 或 WinGet 获取。控件的 ID 通常使用 ControlGet Hwnd、MouseGetPos 或 DllCall 获取。此外，ahk_id 甚至可以操作于隐藏控件，DetectHiddenWindows 的设置不影响控件。

WinActivate, ahk_id %VarContainingID%

ahk_pid 进程 ID

使用 ahk_pid 可以标识属于指定进程的窗口。进程标识符（PID）通常使用 WinGet、Run 或 Process 获取。

WinActivate, ahk_pid %VarContainingPID%

ahk_exe 进程名称、路径 [v1.1.01+]

使用 ahk_exe 可以标识含有指定名称或路径的进程拥有的窗口。

ahk_pid 限制为某个指定进程，而 ahk_exe 可以包含在进程名称或路径中含有指定字符串的所有进程。如果启用了正则的标题匹配模式，则 ahk_exe 可以接受正则表达式。在其他情况下，ahk_exe 接受不区分大小写的名称或完整路径，例如 ahk_exe notepad.exe 包含了 ahk_exe C:\Windows\Notepad.exe、ahk_exe C:\Windows\System32\Notepad.exe 及其他变体。

; 激活现有的 notepad.exe 窗口或打开新窗口
if WinExist("ahk_exe notepad.exe")
    WinActivate, ahk_exe notepad.exe
else
    Run, notepad.exe

ahk_group 窗口组

使用 ahk_group 可以标识匹配之前由窗口组定义的规则的窗口。

WinMinimize、WinMaximize、WinRestore、WinHide、WinShow、WinClose 和 WinKill 将对组中的所有窗口进行操作。相比之下，其他窗口命令（例如 WinActivate 和 IfWinExist）仅对组中最顶层的窗口进行操作。

; 定义组：Windows 资源管理器窗口
GroupAdd, Explorer, ahk_class ExploreWClass ; 在 Vista 及更高版本中不使用
GroupAdd, Explorer, ahk_class CabinetWClass

; 激活匹配上面条件的任意窗口
WinActivate, ahk_group Explorer

多重条件

与 ahk_group （它活动了搜索范围）比起来，在 WinTitle 参数中指定多个条件可以缩小搜索范围。在下面的例子中, 脚本等待标题中包含 My File.txt 且 类名为 Notepad 的窗口出现:

WinWait My File.txt ahk_class Notepad
WinActivate  ; 激活它找到的窗口.

使用这种方法时，应该首先列出标题的文本（如果希望使用），后面跟着一个或多个附加条件。超过一个条件时条件之间必须准确地用一个空格或 tab 分隔 (其他任何空格或 tab 会被视为前面一个条件的文字部分).

ahk_id 可以和其他条件组合来测试窗口标题、类名或其他属性。

MouseGetPos,,, id
if WinExist("ahk_class Notepad ahk_id " id)
    MsgBox The mouse is over Notepad.

"上次找到的" 窗口

这是由 IfWin[Not]Exist、WinExist()、IfWin[Not]Active、WinActive()、WinWait[Not]Active 或 WinWait 最近找到的窗口。这样可以让脚本更容易创建和维护, 因为目标窗口的 WinTitle 和 WinText 不需要在每个窗口命令中重复. 同时, 脚本会执行的更好, 因为在首次找到目标窗口后这些命令不需要再次搜索目标窗口.

"上次找到的" 窗口可以用于除 WinWait, WinActivateBottom 和 GroupAdd 以外的所有窗口命令. 要使用它, 只需简单地省略所有的四个窗口参数 (WinTitle, WinText, ExcludeTitle 和 ExcludeText).

每个 线程 都会保持它自己的 "上次找到的" 窗口值, 这意味着如果 当前线程 被其他线程中断, 当原始线程恢复时它仍会拥有它原来的 "上次找到的" 窗口值, 而不是中断线程的值.

如果上次找到的窗口是隐藏的 Gui 窗口, 那么即使 DetectHiddenWindows 设置为 Off 时它也能用在窗口命令中. 这种特性常常和 Gui +LastFound 一起使用。

Run Notepad
WinWait Untitled - Notepad
WinActivate  ; 使用上次找到的窗口.

IfWinExist, Untitled - Notepad
{
    WinActivate  ; 自动使用上面找到的窗口.
    WinMaximize  ; 同上
    Send, Some text.{Enter}
    return
}

IfWinNotExist, Calculator
    return
else
{
    WinActivate  ; 上面的 "IfWinNotExist" 也为我们设置了 "上次找到的" 窗口.
    WinMove, 40, 40  ; 把它移动到新位置.
    return
}


任意编辑器中的上下文帮助——作者：Rajat

此脚本设置 Ctrl+2 (或您选择的其他热键) 来显示选择的 AutoHotkey 命令或关键字的帮助文件页面. 如果没有选择任何内容, 那么会提取当前行开始处的命令名.

下载此脚本 | 其他示例脚本 | 主页

; 下面的热键使用剪贴板来实现与最大数目的
; 编辑器兼容 (因为 ControlGet 在大多数高级编辑器中无法工作).
; 它会在之后恢复剪贴板原来的内容, 但只是纯文本,
; 这样似乎比什么都不做要好.

$^2::
; 下面的值只在此热键执行期间有效.
; 因此, 不需要恢复它们原来的值
; 因为在线程结束时会自动进行这个操作:
SetWinDelay 10
SetKeyDelay 0
AutoTrim, On

if A_OSType = WIN32_WINDOWS  ; Windows 9x
    Sleep, 500  ; 提供一些时间让用户释放按键.

C_ClipboardPrev = %clipboard%
clipboard =
; 如果有高亮的单词, 则使用它 (因为有时用户可能
; 故意高亮一些不是命令的内容):
Send, ^c
ClipWait, 0.1
if ErrorLevel <> 0
{
    ; 获取整行, 因为编辑器编辑器可能对导航键进行不同的处理:
    Send, {home}+{end}^c
    ClipWait, 0.2
    if ErrorLevel <> 0  ; 罕见的情况, 所以不报告错误.
    {
        clipboard = %C_ClipboardPrev%
        return
    }
}
C_Cmd = %clipboard%  ; 这样会移除前导和尾随的 tab 和空格.
clipboard = %C_ClipboardPrev%  ; 恢复剪贴板为原来的内容.
Loop, parse, C_Cmd, %A_Space%`,  ; 命令末尾的首个空格或逗号.
{
    C_Cmd = %A_LoopField%
    break ; 即我们只需要循环一次.
}
IfWinNotExist, AutoHotkey Help
{
    ; 判断 AutoHotkey 的位置:
    RegRead, ahk_dir, HKEY_LOCAL_MACHINE, SOFTWARE\AutoHotkey, InstallDir
    if ErrorLevel  ; 没有找到, 所以在其他一些常见位置寻找.
    {
        if A_AhkPath
            SplitPath, A_AhkPath,, ahk_dir
        else IfExist ..\..\AutoHotkey.chm
            ahk_dir = ..\..
        else IfExist %A_ProgramFiles%\AutoHotkey\AutoHotkey.chm
            ahk_dir = %A_ProgramFiles%\AutoHotkey
        else
        {
            MsgBox Could not find the AutoHotkey folder.
            return
        }
    }
    Run %ahk_dir%\AutoHotkey.chm
    WinWait AutoHotkey Help
}
; 上面设置了我们下面要使用的 "最后找到的" 窗口:
WinActivate
WinWaitActive
StringReplace, C_Cmd, C_Cmd, #, {#}
send, !n{home}+{end}%C_Cmd%{enter}
return


轻松拖曳窗口（需要 XP/2k/NT）

一般情况下只能通过点击标题栏来拖动窗口. 这个脚本扩展到可以在窗口中任何一点拖动窗口. 要激活这种模式, 请在点击时按住 CapsLock 或鼠标中键, 然后拖动窗口到新的位置.

下载此脚本 | 其他示例脚本 | 主页

; 注意: 在按下鼠标按钮后您可以释放 Capslock 或鼠标中键
; 而不需要在整个拖动过程中按住它.
; 此脚本需要 v1.0.25+.

~MButton & LButton::
CapsLock & LButton::
CoordMode, Mouse  ; 切换到屏幕/绝对坐标。
MouseGetPos, EWD_MouseStartX, EWD_MouseStartY, EWD_MouseWin
WinGetPos, EWD_OriginalPosX, EWD_OriginalPosY,,, ahk_id %EWD_MouseWin%
WinGet, EWD_WinState, MinMax, ahk_id %EWD_MouseWin%
if EWD_WinState = 0  ; 仅在窗口不处于最大化状态时
    SetTimer, EWD_WatchMouse, 10 ; 在用户拖动时跟踪鼠标.
return

EWD_WatchMouse:
GetKeyState, EWD_LButtonState, LButton, P
if EWD_LButtonState = U  ; 按钮已经释放, 所以拖动结束.
{
    SetTimer, EWD_WatchMouse, off
    return
}
GetKeyState, EWD_EscapeState, Escape, P
if EWD_EscapeState = D  ; 按下了 Escape, 所以取消拖动.
{
    SetTimer, EWD_WatchMouse, off
    WinMove, ahk_id %EWD_MouseWin%,, %EWD_OriginalPosX%, %EWD_OriginalPosY%
    return
}
; 否则, 改变窗口的位置以匹配
; 用户拖动鼠标引起的鼠标坐标变化:
CoordMode, Mouse
MouseGetPos, EWD_MouseX, EWD_MouseY
WinGetPos, EWD_WinX, EWD_WinY,,, ahk_id %EWD_MouseWin%
SetWinDelay, -1   ; 让下面的移动更快速/平滑.
WinMove, ahk_id %EWD_MouseWin%,, EWD_WinX + EWD_MouseX - EWD_MouseStartX, EWD_WinY + EWD_MouseY - EWD_MouseStartY
EWD_MouseStartX := EWD_MouseX  ; 为下一次调用此子程序进行更新.
EWD_MouseStartY := EWD_MouseY
return


轻松拖曳窗口——KDE 样式（需要 XP/2k/NT）——作者：Jonny

使用此脚本可以轻松移动窗口或改变它的大小: 1) 按住 ALT 键并在窗口内的任意位置点击左键来拖动窗口到新的位置; 2) 按住 ALT 并在窗口内任意位置点击右键后拖动来轻松调整它的大小; 3) 按下 ALT 两次, 但在第二次松开前, 点击左键来最小化鼠标光标下的窗口, 点击右键进行最大化或点击中键进行关闭.

下载此脚本 | 其他示例脚本 | 主页

; 此脚本是从论坛中许多类似它的脚本获得灵感
; 并建立的. 把感谢送给 ck, thinkstorm, Chris,
; 和 aurelian 的良好工作.

; 更新历史:
; 2006.11.07: 优化了 !RButton 中的大小调整代码, courtesy of bluedawn.
; 2006.02.05: 修复 double-alt (~Alt 热键) 以使它工作于最近的 AHK 版本.

; 双 Alt 修饰键是通过按下
; Alt 两次来激活的, 很像双击. 第二次时保持按住,
; 一直到您点击.
;
; 快捷键:
;  Alt + Left Button  : 拖动来移动窗口.
;  Alt + Right Button : 拖动来调整窗口大小.
;  Double-Alt + Left Button   : 最小化窗口.
;  Double-Alt + Right Button  : 最大化/还原窗口.
;  Double-Alt + Middle Button : 关闭窗口.
;
; 您可以在首次点击 Alt 后
; 松开它而不用在整个过程中都按住.

If (A_AhkVersion < "1.0.39.00")
{
    MsgBox,20,,This script may not work properly with your version of AutoHotkey. Continue?
    IfMsgBox,No
    ExitApp
}

; 这是在我的系统上运行的最顺畅
; 的设置. 根据您显卡和 CPU 的
; 速度, 您可能要增加或减小这个值.
SetWinDelay,2

CoordMode,Mouse
return

!LButton::
If DoubleAlt
{
    MouseGetPos,,,KDE_id
    ; 此消息大部分时候相当于 WinMinimize,
    ; 但是它避免了作用于 PSPad 时的问题.
    PostMessage,0x112,0xf020,,,ahk_id %KDE_id%
    DoubleAlt := false
    return
}
; 获取初始的鼠标位置和窗口 id, 并
; 在窗口处于最大化状态时返回.
MouseGetPos,KDE_X1,KDE_Y1,KDE_id
WinGet,KDE_Win,MinMax,ahk_id %KDE_id%
If KDE_Win
    return
; 获取初始的窗口位置.
WinGetPos,KDE_WinX1,KDE_WinY1,,,ahk_id %KDE_id%
Loop
{
    GetKeyState,KDE_Button,LButton,P ; 如果按钮已经被松开了则退出.
    If KDE_Button = U
        break
    MouseGetPos,KDE_X2,KDE_Y2 ; 获取当前的鼠标位置.
    KDE_X2 -= KDE_X1 ; 得到距离原来鼠标位置的偏移.
    KDE_Y2 -= KDE_Y1
    KDE_WinX2 := (KDE_WinX1 + KDE_X2) ; 把这个偏移应用到窗口位置.
    KDE_WinY2 := (KDE_WinY1 + KDE_Y2)
    WinMove,ahk_id %KDE_id%,,%KDE_WinX2%,%KDE_WinY2% ; 移动窗口到新的位置.
}
return

!RButton::
If DoubleAlt
{
    MouseGetPos,,,KDE_id
    ; 在最大化和还原状态中切换.
    WinGet,KDE_Win,MinMax,ahk_id %KDE_id%
    If KDE_Win
        WinRestore,ahk_id %KDE_id%
    Else
        WinMaximize,ahk_id %KDE_id%
    DoubleAlt := false
    return
}
; 获取初始的鼠标位置和窗口 id, 并
; 在窗口处于最大化状态时返回.
MouseGetPos,KDE_X1,KDE_Y1,KDE_id
WinGet,KDE_Win,MinMax,ahk_id %KDE_id%
If KDE_Win
    return
; 获取初始的窗口位置和大小.
WinGetPos,KDE_WinX1,KDE_WinY1,KDE_WinW,KDE_WinH,ahk_id %KDE_id%
; 定义鼠标当前所处的窗口区域.
; 四个区为左上, 右上, 左下和右下.
If (KDE_X1 < KDE_WinX1 + KDE_WinW / 2)
   KDE_WinLeft := 1
Else
   KDE_WinLeft := -1
If (KDE_Y1 < KDE_WinY1 + KDE_WinH / 2)
   KDE_WinUp := 1
Else
   KDE_WinUp := -1
Loop
{
    GetKeyState,KDE_Button,RButton,P ; 如果按钮已经松开了则退出.
    If KDE_Button = U
        break
    MouseGetPos,KDE_X2,KDE_Y2 ; 获取当前鼠标位置.
    ; 获取当前的窗口位置和大小.
    WinGetPos,KDE_WinX1,KDE_WinY1,KDE_WinW,KDE_WinH,ahk_id %KDE_id%
    KDE_X2 -= KDE_X1 ; 得到距离原来鼠标位置的偏移.
    KDE_Y2 -= KDE_Y1
    ; 然后根据已定义区域进行动作.
    WinMove,ahk_id %KDE_id%,, KDE_WinX1 + (KDE_WinLeft+1)/2*KDE_X2  ; 大小调整后窗口的 X 坐标
                            , KDE_WinY1 +   (KDE_WinUp+1)/2*KDE_Y2  ; 大小调整后窗口的 Y 坐标
                            , KDE_WinW  -     KDE_WinLeft  *KDE_X2  ; 大小调整后窗口的 W (宽度)
                            , KDE_WinH  -       KDE_WinUp  *KDE_Y2  ; 大小调整后窗口的 H (高度)
    KDE_X1 := (KDE_X2 + KDE_X1) ; 为下一次的重复重新设置初始位置.
    KDE_Y1 := (KDE_Y2 + KDE_Y1)
}
return

; "Alt + MButton" 可能简单了点, 不过我
; 喜欢给像这样的操作
; 增加额外的安全检测.
!MButton::
If DoubleAlt
{
    MouseGetPos,,,KDE_id
    WinClose,ahk_id %KDE_id%
    DoubleAlt := false
    return
}
return

; 这里检测 alt 键的双击.
~Alt::
DoubleAlt := A_PriorHotKey = "~Alt" AND A_TimeSincePriorHotkey < 400
Sleep 0
KeyWait Alt  ; 这样避免了键盘的自动重复功能的扰乱.
return


轻松访问收藏夹——作者：Savage

当您在某些类型的窗口活动时点击鼠标中键, 脚本会显示您的收藏夹菜单. 选择收藏夹中的文件夹后, 脚本会让活动窗口立即切换到那个文件夹. 支持下列窗口类型: 1) 标准的文件打开或文件保存对话框; 2) 资源管理器窗口; 3) 控制台 (命令提示符) 窗口. 对于不支持的窗口类型也可以显示此菜单, 此时选择的收藏夹中的文件夹会在新的资源管理器窗口中打开.

下载此脚本 | 其他示例脚本 | 主页

; Note: In Windows Explorer, if "View > Toolbars > Address Bar" is
; not enabled, the menu will not be shown if the hotkey chosen below
; has a tilde.  If it does have a tilde, the menu will be shown
; but the favorite will be opened in a new Explorer window rather
; than switching the active Explorer window to that folder.

; CONFIG: CHOOSE YOUR HOTKEY
; If your mouse has more than 3 buttons, you could try using
; XButton1 (the 4th) or XButton2 (the 5th) instead of MButton.
; You could also use a modified mouse button (such as ^MButton) or
; a keyboard hotkey.  In the case of MButton, the tilde (~) prefix
; is used so that MButton's normal functionality is not lost when
; you click in other window types, such as a browser.  The presence
; of a tilde tells the script to avoid showing the menu for
; unsupported window types.  In other words, if there is no tilde,
; the hotkey will always display the menu; and upon selecting a
; favorite while an unsupported window type is active, a new
; Explorer window will be opened to display the contents of that
; folder.
f_Hotkey = ~MButton

; CONFIG: CHOOSE YOUR FAVORITES
; Update the special commented section below to list your favorite
; folders.  Specify the name of the menu item first, followed by a
; semicolon, followed by the name of the actual path of the favorite.
; Use a blank line to create a separator line.

/*
ITEMS IN FAVORITES MENU <-- Do not change this string.
Desktop      ; %A_Desktop%
Favorites    ; %A_Desktop%\..\Favorites
My Documents ; %A_MyDocuments%

Program Files; %A_ProgramFiles%
*/

; END OF CONFIGURATION SECTION
; Do not make changes below this point unless you want to change
; the basic functionality of the script.

#SingleInstance  ; Needed since the hotkey is dynamically created.

Hotkey, %f_Hotkey%, f_DisplayMenu
StringLeft, f_HotkeyFirstChar, f_Hotkey, 1
if f_HotkeyFirstChar = ~  ; Show menu only for certain window types.
    f_AlwaysShowMenu = n
else
    f_AlwaysShowMenu = y

; Used to reliably determine whether script is compiled:
SplitPath, A_ScriptName,,, f_FileExt
if f_FileExt = Exe  ; Read the menu items from an external file.
    f_FavoritesFile = %A_ScriptDir%\Favorites.ini
else  ; Read the menu items directly from this script file.
    f_FavoritesFile = %A_ScriptFullPath%

;----Read the configuration file.
f_AtStartingPos = n
f_MenuItemCount = 0
Loop, Read, %f_FavoritesFile%
{
    if f_FileExt <> Exe
    {
        ; Since the menu items are being read directly from this
        ; script, skip over all lines until the starting line is
        ; arrived at.
        if f_AtStartingPos = n
        {
            IfInString, A_LoopReadLine, ITEMS IN FAVORITES MENU
                f_AtStartingPos = y
            continue  ; Start a new loop iteration.
        }
        ; Otherwise, the closing comment symbol marks the end of the list.
        if A_LoopReadLine = */
            break  ; terminate the loop
    }
    ; Menu separator lines must also be counted to be compatible
    ; with A_ThisMenuItemPos:
    f_MenuItemCount++
    if A_LoopReadLine =  ; Blank indicates a separator line.
        Menu, Favorites, Add
    else
    {
        StringSplit, f_line, A_LoopReadLine, `;
        f_line1 = %f_line1%  ; Trim leading and trailing spaces.
        f_line2 = %f_line2%  ; Trim leading and trailing spaces.
        ; Resolve any references to variables within either field, and
        ; create a new array element containing the path of this favorite:
        Transform, f_path%f_MenuItemCount%, deref, %f_line2%
        Transform, f_line1, deref, %f_line1%
        Menu, Favorites, Add, %f_line1%, f_OpenFavorite
    }
}
return  ;----End of auto-execute section.

;----Open the selected favorite
f_OpenFavorite:
; Fetch the array element that corresponds to the selected menu item:
StringTrimLeft, f_path, f_path%A_ThisMenuItemPos%, 0
if f_path =
    return
if f_class = #32770    ; It's a dialog.
{
    if f_Edit1Pos <>   ; And it has an Edit1 control.
    {
        ; Activate the window so that if the user is middle-clicking
        ; outside the dialog, subsequent clicks will also work:
        WinActivate ahk_id %f_window_id%
        ; Retrieve any filename that might already be in the field so
        ; that it can be restored after the switch to the new folder:
        ControlGetText, f_text, Edit1, ahk_id %f_window_id%
        ControlSetText, Edit1, %f_path%, ahk_id %f_window_id%
        ControlSend, Edit1, {Enter}, ahk_id %f_window_id%
        Sleep, 100  ; It needs extra time on some dialogs or in some cases.
        ControlSetText, Edit1, %f_text%, ahk_id %f_window_id%
        return
    }
    ; else fall through to the bottom of the subroutine to take standard action.
}
else if f_class in ExploreWClass,CabinetWClass  ; In Explorer, switch folders.
{
    if f_Edit1Pos <>   ; And it has an Edit1 control.
    {
        ControlSetText, Edit1, %f_path%, ahk_id %f_window_id%
        ; Tekl reported the following: "If I want to change to Folder L:\folder
        ; then the addressbar shows http://www.L:\folder.com. To solve this,
        ; I added a {right} before {Enter}":
        ControlSend, Edit1, {Right}{Enter}, ahk_id %f_window_id%
        return
    }
    ; else fall through to the bottom of the subroutine to take standard action.
}
else if f_class = ConsoleWindowClass ; In a console window, CD to that directory
{
    WinActivate, ahk_id %f_window_id% ; Because sometimes the mclick deactivates it.
    SetKeyDelay, 0  ; This will be in effect only for the duration of this thread.
    IfInString, f_path, :  ; It contains a drive letter
    {
        StringLeft, f_path_drive, f_path, 1
        Send %f_path_drive%:{enter}
    }
    Send, cd %f_path%{Enter}
    return
}
; Since the above didn't return, one of the following is true:
; 1) It's an unsupported window type but f_AlwaysShowMenu is y (yes).
; 2) It's a supported type but it lacks an Edit1 control to facilitate the custom
;    action, so instead do the default action below.
Run, Explorer %f_path%  ; Might work on more systems without double quotes.
return

;----Display the menu
f_DisplayMenu:
; These first few variables are set here and used by f_OpenFavorite:
WinGet, f_window_id, ID, A
WinGetClass, f_class, ahk_id %f_window_id%
if f_class in #32770,ExploreWClass,CabinetWClass  ; Dialog or Explorer.
    ControlGetPos, f_Edit1Pos,,,, Edit1, ahk_id %f_window_id%
if f_AlwaysShowMenu = n  ; The menu should be shown only selectively.
{
    if f_class in #32770,ExploreWClass,CabinetWClass  ; Dialog or Explorer.
    {
        if f_Edit1Pos =  ; The control doesn't exist, so don't display the menu
            return
    }
    else if f_class <> ConsoleWindowClass
        return ; Since it's some other window type, don't display menu.
}
; Otherwise, the menu should be presented for this type of window:
Menu, Favorites, show
return


智能感应 -- 作者: Rajat (需要 XP/2k/NT)

此脚本会在您编辑 AutoHotkey 脚本时进行监视. 当它看到您输入命令后跟着逗号或空格后, 会显示此命令的参数列表以给您提示. 此外, 您可以按下 Ctrl+F1 (或您选择的其他热键) 来显示帮助文件中此命令的页面. 要取消参数列表, 请按 Escape 或 Enter.

下载此脚本 | 其他示例脚本 | 主页

; Requires v1.0.41+

; CONFIGURATION SECTION: Customize the script with the following variables.

; The hotkey below is pressed to display the current command's page in the
; help file:
I_HelpHotkey = ^F1

; The string below must exist somewhere in the active window's title for
; IntelliSense to be in effect while you're typing.  Make it blank to have
; IntelliSense operate in all windows.  Make it Pad to have it operate in
; editors such as Metapad, Notepad, and Textpad.  Make it .ahk to have it
; operate only when a .ahk file is open in Notepad, Metapad, etc.
I_Editor = pad

; If you wish to have a different icon for this script to distinguish it from
; other scripts in the tray, provide the filename below (leave blank to have
; no icon). For example: E:\stuff\Pics\icons\GeoIcons\Information.ico
I_Icon =

; END OF CONFIGURATION SECTION (do not make changes below this point unless
; you want to change the basic functionality of the script).

SetKeyDelay, 0
#SingleInstance

if I_HelpHotkey <>
    Hotkey, %I_HelpHotkey%, I_HelpHotkey

; Change tray icon (if one was specified in the configuration section above):
if I_Icon <>
    IfExist, %I_Icon%
        Menu, Tray, Icon, %I_Icon%

; Determine AutoHotkey's location:
RegRead, ahk_dir, HKEY_LOCAL_MACHINE, SOFTWARE\AutoHotkey, InstallDir
if ErrorLevel  ; Not found, so look for it in some other common locations.
{
    if A_AhkPath
        SplitPath, A_AhkPath,, ahk_dir
    else IfExist ..\..\AutoHotkey.chm
        ahk_dir = ..\..
    else IfExist %A_ProgramFiles%\AutoHotkey\AutoHotkey.chm
        ahk_dir = %A_ProgramFiles%\AutoHotkey
    else
    {
        MsgBox Could not find the AutoHotkey folder.
        ExitApp
    }
}

ahk_help_file = %ahk_dir%\AutoHotkey.chm

; Read command syntaxes:
Loop, Read, %ahk_dir%\Extras\Editors\Syntax\Commands.txt
{
    I_FullCmd = %A_LoopReadLine%

    ; Directives have a first space instead of a first comma.
    ; So use whichever comes first as the end of the command name:
    StringGetPos, I_cPos, I_FullCmd, `,
    StringGetPos, I_sPos, I_FullCmd, %A_Space%
    if (I_cPos = -1 or (I_cPos > I_sPos and I_sPos <> -1))
        I_EndPos := I_sPos
    else
        I_EndPos := I_cPos

    if I_EndPos <> -1
        StringLeft, I_CurrCmd, I_FullCmd, %I_EndPos%
    else  ; This is a directive/command with no parameters.
        I_CurrCmd = %A_LoopReadLine%

    StringReplace, I_CurrCmd, I_CurrCmd, [,, All
    StringReplace, I_CurrCmd, I_CurrCmd, %A_Space%,, All
    StringReplace, I_FullCmd, I_FullCmd, ``n, `n, All
    StringReplace, I_FullCmd, I_FullCmd, ``t, `t, All

    ; Make arrays of command names and full cmd syntaxes:
    I_Cmd%A_Index% = %I_CurrCmd%
    I_FullCmd%A_Index% = %I_FullCmd%
}

; Use the Input command to watch for commands that the user types:
Loop
{
    ; Editor window check:
    WinGetTitle, ActiveTitle, A
    IfNotInString, ActiveTitle, %I_Editor%
    {
        ToolTip
        Sleep, 500
        继续
    }

    ; Get all keys till endkey:
    Input, I_Word, V, {enter}{escape}{space}`,
    I_EndKey = %ErrorLevel%

    ; Tooltip is hidden in these cases:
    if I_EndKey in EndKey:Enter,EndKey:Escape
    {
        ToolTip
        继续
    }

    ; Editor window check again!
    WinGetActiveTitle, ActiveTitle
    IfNotInString, ActiveTitle, %I_Editor%
    {
        ToolTip
        继续
    }

    ; Compensate for any indentation that is present:
    StringReplace, I_Word, I_Word, %A_Space%,, All
    StringReplace, I_Word, I_Word, %A_Tab%,, All
    if I_Word =
        继续

    ; Check for commented line:
    StringLeft, I_Check, I_Word, 1
    if (I_Check = ";" or I_Word = "If")  ; "If" seems a little too annoying to show tooltip for.
        继续

    ; Match word with command:
    I_Index =
    循环
    {
        ; It helps performance to resolve dynamic variables only once.
        ; In addition, the value put into I_ThisCmd is also used by the
        ; I_HelpHotkey subroutine:
        I_ThisCmd := I_Cmd%A_Index%
        if I_ThisCmd =
            break
        if (I_Word = I_ThisCmd)
        {
            I_Index := A_Index
            I_HelpOn = %I_ThisCmd%
            break
        }
    }

    ; If no match then resume watching user input:
    if I_Index =
        继续

    ; Show matched command to guide the user:
    I_ThisFullCmd := I_FullCmd%I_Index%
    ToolTip, %I_ThisFullCmd%, A_CaretX, A_CaretY + 20
}

I_HelpHotkey:
WinGetTitle, ActiveTitle, A
IfNotInString, ActiveTitle, %I_Editor%, Return

ToolTip  ; Turn off syntax helper since there is no need for it now.

SetTitleMatchMode, 1  ; In case it's 3. This setting is in effect only for this thread.
IfWinNotExist, AutoHotkey Help
{
    IfNotExist, %ahk_help_file%
    {
        MsgBox, Could not find the help file: %ahk_help_file%.
        return
    }
    Run, %ahk_help_file%
    WinWait, AutoHotkey Help
}

if I_ThisCmd =  ; Instead, use what was most recently typed.
    I_ThisCmd := I_Word

; The above has set the "last found" window which we use below:
WinActivate
WinWaitActive
StringReplace, I_ThisCmd, I_ThisCmd, #, {#}  ; Replace leading #, if any.
Send, !n{home}+{end}%I_HelpOn%{enter}
return


把操纵杆作为鼠标使用

此脚本把操纵杆转换为三键的鼠标. 它允许每个按钮像鼠标按钮那样拖动, 且它几乎不消耗 CPU 时间. 还有, 您将操纵杆推离中央越远, 它会让光标移动的越快. 您可以在脚本的顶部个性化各种设置.

下载此脚本 | 其他示例脚本 | 主页

; Increase the following value to make the mouse cursor move faster:
JoyMultiplier = 0.30

; Decrease the following value to require less joystick displacement-from-center
; to start moving the mouse.  However, you may need to calibrate your joystick
; -- ensuring it's properly centered -- to avoid cursor drift. A perfectly tight
; and centered joystick could use a value of 1:
JoyThreshold = 3

; Change the following to true to invert the Y-axis, which causes the mouse to
; move vertically in the direction opposite the stick:
InvertYAxis := false

; Change these values to use joystick button numbers other than 1, 2, and 3 for
; the left, right, and middle mouse buttons.  Available numbers are 1 through 32.
; Use the Joystick Test Script to find out your joystick's numbers more easily.
ButtonLeft = 1
ButtonRight = 2
ButtonMiddle = 3

; If your joystick has a POV control, you can use it as a mouse wheel.  The
; following value is the number of milliseconds between turns of the wheel.
; Decrease it to have the wheel turn faster:
WheelDelay = 250

; If your system has more than one joystick, increase this value to use a joystick
; other than the first:
JoystickNumber = 1

; END OF CONFIG SECTION -- Don't change anything below this point unless you want
; to alter the basic nature of the script.

#SingleInstance

JoystickPrefix = %JoystickNumber%Joy
Hotkey, %JoystickPrefix%%ButtonLeft%, ButtonLeft
Hotkey, %JoystickPrefix%%ButtonRight%, ButtonRight
Hotkey, %JoystickPrefix%%ButtonMiddle%, ButtonMiddle

; Calculate the axis displacements that are needed to start moving the cursor:
JoyThresholdUpper := 50 + JoyThreshold
JoyThresholdLower := 50 - JoyThreshold
if InvertYAxis
    YAxisMultiplier = -1
else
    YAxisMultiplier = 1

SetTimer, WatchJoystick, 10  ; Monitor the movement of the joystick.

GetKeyState, JoyInfo, %JoystickNumber%JoyInfo
IfInString, JoyInfo, P  ; Joystick has POV control, so use it as a mouse wheel.
    SetTimer, MouseWheel, %WheelDelay%

return  ; End of auto-execute section.

; The subroutines below do not use KeyWait because that would sometimes trap the
; WatchJoystick quasi-thread beneath the wait-for-button-up thread, which would
; effectively prevent mouse-dragging with the joystick.

ButtonLeft:
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, left,,, 1, 0, D  ; Hold down the left mouse button.
SetTimer, WaitForLeftButtonUp, 10
return

ButtonRight:
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, right,,, 1, 0, D  ; Hold down the right mouse button.
SetTimer, WaitForRightButtonUp, 10
return

ButtonMiddle:
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, middle,,, 1, 0, D  ; Hold down the right mouse button.
SetTimer, WaitForMiddleButtonUp, 10
return

WaitForLeftButtonUp:
if GetKeyState(JoystickPrefix . ButtonLeft)
    return  ; The button is still, down, so keep waiting.
; Otherwise, the button has been released.
SetTimer, WaitForLeftButtonUp, off
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, left,,, 1, 0, U  ; Release the mouse button.
return

WaitForRightButtonUp:
if GetKeyState(JoystickPrefix . ButtonRight)
    return  ; The button is still, down, so keep waiting.
; Otherwise, the button has been released.
SetTimer, WaitForRightButtonUp, off
MouseClick, right,,, 1, 0, U  ; Release the mouse button.
return

WaitForMiddleButtonUp:
if GetKeyState(JoystickPrefix . ButtonMiddle)
    return  ; The button is still, down, so keep waiting.
; Otherwise, the button has been released.
SetTimer, WaitForMiddleButtonUp, off
MouseClick, middle,,, 1, 0, U  ; Release the mouse button.
return

WatchJoystick:
MouseNeedsToBeMoved := false  ; Set default.
SetFormat, float, 03
GetKeyState, joyx, %JoystickNumber%JoyX
GetKeyState, joyy, %JoystickNumber%JoyY
if joyx > %JoyThresholdUpper%
{
    MouseNeedsToBeMoved := true
    DeltaX := joyx - JoyThresholdUpper
}
else if joyx < %JoyThresholdLower%
{
    MouseNeedsToBeMoved := true
    DeltaX := joyx - JoyThresholdLower
}
else
    DeltaX = 0
if joyy > %JoyThresholdUpper%
{
    MouseNeedsToBeMoved := true
    DeltaY := joyy - JoyThresholdUpper
}
else if joyy < %JoyThresholdLower%
{
    MouseNeedsToBeMoved := true
    DeltaY := joyy - JoyThresholdLower
}
else
    DeltaY = 0
if MouseNeedsToBeMoved
{
    SetMouseDelay, -1  ; Makes movement smoother.
    MouseMove, DeltaX * JoyMultiplier, DeltaY * JoyMultiplier * YAxisMultiplier, 0, R
}
return

MouseWheel:
GetKeyState, JoyPOV, %JoystickNumber%JoyPOV
if JoyPOV = -1  ; No angle.
    return
if (JoyPOV > 31500 or JoyPOV < 4500)  ; Forward
    Send {WheelUp}
else if JoyPOV between 13500 and 22500  ; Back
    Send {WheelDown}
return


操纵杆测试脚本

此脚本帮助您判断操纵杆的按钮数目和其他属性. 它还可能显示您的操纵杆是否需要校准; 即它的每个轴向的活动范围是否在百分之零到百分之百的范围内, 这是它应该处于的范围. 如果需要校准, 请使用操作系统控制面板或操纵杆的自带软件.

下载此脚本 | 其他示例脚本 | 主页

; July 6, 2005: Added auto-detection of joystick number.
; May 8, 2005 : Fixed: JoyAxes is no longer queried as a means of
; detecting whether the joystick is connected.  Some joysticks are
; gamepads and don't have even a single axis.

; If you want to unconditionally use a specific joystick number, change
; the following value from 0 to the number of the joystick (1-16).
; A value of 0 causes the joystick number to be auto-detected:
JoystickNumber = 0

; END OF CONFIG SECTION. Do not make changes below this point unless
; you wish to alter the basic functionality of the script.

; Auto-detect the joystick number if called for:
if JoystickNumber <= 0
{
    Loop 16  ; Query each joystick number to find out which ones exist.
    {
        GetKeyState, JoyName, %A_Index%JoyName
        if JoyName <>
        {
            JoystickNumber = %A_Index%
            break
        }
    }
    if JoystickNumber <= 0
    {
        MsgBox The system does not appear to have any joysticks.
        ExitApp
    }
}

#SingleInstance
SetFormat, float, 03  ; Omit decimal point from axis position percentages.
GetKeyState, joy_buttons, %JoystickNumber%JoyButtons
GetKeyState, joy_name, %JoystickNumber%JoyName
GetKeyState, joy_info, %JoystickNumber%JoyInfo
Loop
{
    buttons_down =
    Loop, %joy_buttons%
    {
        GetKeyState, joy%a_index%, %JoystickNumber%joy%a_index%
        if joy%a_index% = D
            buttons_down = %buttons_down%%a_space%%a_index%
    }
    GetKeyState, joyx, %JoystickNumber%JoyX
    axis_info = X%joyx%
    GetKeyState, joyy, %JoystickNumber%JoyY
    axis_info = %axis_info%%a_space%%a_space%Y%joyy%
    IfInString, joy_info, Z
    {
        GetKeyState, joyz, %JoystickNumber%JoyZ
        axis_info = %axis_info%%a_space%%a_space%Z%joyz%
    }
    IfInString, joy_info, R
    {
        GetKeyState, joyr, %JoystickNumber%JoyR
        axis_info = %axis_info%%a_space%%a_space%R%joyr%
    }
    IfInString, joy_info, U
    {
        GetKeyState, joyu, %JoystickNumber%JoyU
        axis_info = %axis_info%%a_space%%a_space%U%joyu%
    }
    IfInString, joy_info, V
    {
        GetKeyState, joyv, %JoystickNumber%JoyV
        axis_info = %axis_info%%a_space%%a_space%V%joyv%
    }
    IfInString, joy_info, P
    {
        GetKeyState, joyp, %JoystickNumber%JoyPOV
        axis_info = %axis_info%%a_space%%a_space%POV%joyp%
    }
    ToolTip, %joy_name% (#%JoystickNumber%):`n%axis_info%`nButtons Down: %buttons_down%`n`n(right-click the tray icon to exit)
    Sleep, 100
}
return


屏幕键盘 (需要 XP/2k/NT) -- 作者: Jon

此脚本会在屏幕的底部创建一个模拟键盘来实时显示您按下的按键. 我写这个是为了帮我学习盲打 (来适应不去看键盘). 在脚本的顶部可以自定义屏幕键盘的大小. 还有, 您可以双击托盘图标来显示或隐藏键盘.

下载此脚本 | 其他示例脚本 | 主页

;---- Configuration Section: Customize the size of the on-screen keyboard and
; other options here.

; Changing this font size will make the entire on-screen keyboard get
; larger or smaller:
k_FontSize = 10
k_FontName = Verdana  ; This can be blank to use the system's default font.
k_FontStyle = Bold    ; Example of an alternative: Italic Underline

; Names for the tray menu items:
k_MenuItemHide = Hide on-screen &keyboard
k_MenuItemShow = Show on-screen &keyboard

; To have the keyboard appear on a monitor other than the primary, specify
; a number such as 2 for the following variable.  Leave it blank to use
; the primary:
k_Monitor =

;---- End of configuration section.  Don't change anything below this point
; unless you want to alter the basic nature of the script.

;---- Alter the tray icon menu:
Menu, Tray, Add, %k_MenuItemHide%, k_ShowHide
Menu, Tray, Add, &Exit, k_MenuExit
Menu, Tray, Default, %k_MenuItemHide%
Menu, Tray, NoStandard

;---- Calculate object dimensions based on chosen font size:
k_KeyWidth = %k_FontSize%
k_KeyWidth *= 3
k_KeyHeight = %k_FontSize%
k_KeyHeight *= 3
k_KeyMargin = %k_FontSize%
k_KeyMargin /= 6
k_SpacebarWidth = %k_FontSize%
k_SpacebarWidth *= 25
k_KeyWidthHalf = %k_KeyWidth%
k_KeyWidthHalf /= 2

k_KeySize = w%k_KeyWidth% h%k_KeyHeight%
k_Position = x+%k_KeyMargin% %k_KeySize%

;---- Create a GUI window for the on-screen keyboard:
Gui, Font, s%k_FontSize% %k_FontStyle%, %k_FontName%
Gui, -Caption +E0x200 +ToolWindow
TransColor = F1ECED
Gui, Color, %TransColor%  ; This color will be made transparent later below.

;---- Add a button for each key. Position the first button with absolute
; coordinates so that all other buttons can be positioned relative to it:
Gui, Add, Button, section %k_KeySize% xm+%k_KeyWidth%, 1
Gui, Add, Button, %k_Position%, 2
Gui, Add, Button, %k_Position%, 3
Gui, Add, Button, %k_Position%, 4
Gui, Add, Button, %k_Position%, 5
Gui, Add, Button, %k_Position%, 6
Gui, Add, Button, %k_Position%, 7
Gui, Add, Button, %k_Position%, 8
Gui, Add, Button, %k_Position%, 9
Gui, Add, Button, %k_Position%, 0
Gui, Add, Button, %k_Position%, -
Gui, Add, Button, %k_Position%, =
Gui, Add, Button, %k_Position%, Bk

Gui, Add, Button, xm y+%k_KeyMargin% h%k_KeyHeight%, Tab  ; Auto-width.
Gui, Add, Button, %k_Position%, Q
Gui, Add, Button, %k_Position%, W
Gui, Add, Button, %k_Position%, E
Gui, Add, Button, %k_Position%, R
Gui, Add, Button, %k_Position%, T
Gui, Add, Button, %k_Position%, Y
Gui, Add, Button, %k_Position%, U
Gui, Add, Button, %k_Position%, I
Gui, Add, Button, %k_Position%, O
Gui, Add, Button, %k_Position%, P
Gui, Add, Button, %k_Position%, [
Gui, Add, Button, %k_Position%, ]
Gui, Add, Button, %k_Position%, \

Gui, Add, Button, xs+%k_KeyWidthHalf% y+%k_KeyMargin% %k_KeySize%, A
Gui, Add, Button, %k_Position%, S
Gui, Add, Button, %k_Position%, D
Gui, Add, Button, %k_Position%, F
Gui, Add, Button, %k_Position%, G
Gui, Add, Button, %k_Position%, H
Gui, Add, Button, %k_Position%, J
Gui, Add, Button, %k_Position%, K
Gui, Add, Button, %k_Position%, L
Gui, Add, Button, %k_Position%, `;
Gui, Add, Button, %k_Position%, '
Gui, Add, Button, x+%k_KeyMargin% h%k_KeyHeight%, Enter  ; Auto-width.

; The first button below adds %A_Space% at the end to widen it a little,
; making the layout of keys next to it more accurately reflect a real keyboard:
Gui, Add, Button, xm y+%k_KeyMargin% h%k_KeyHeight%, Shift%A_Space%%A_Space%
Gui, Add, Button, %k_Position%, Z
Gui, Add, Button, %k_Position%, X
Gui, Add, Button, %k_Position%, C
Gui, Add, Button, %k_Position%, V
Gui, Add, Button, %k_Position%, B
Gui, Add, Button, %k_Position%, N
Gui, Add, Button, %k_Position%, M
Gui, Add, Button, %k_Position%, `,
Gui, Add, Button, %k_Position%, .
Gui, Add, Button, %k_Position%, /

Gui, Add, Button, xm y+%k_KeyMargin% h%k_KeyHeight%, Ctrl  ; Auto-width.
Gui, Add, Button, h%k_KeyHeight% x+%k_KeyMargin%, Win      ; Auto-width.
Gui, Add, Button, h%k_KeyHeight% x+%k_KeyMargin%, Alt      ; Auto-width.
Gui, Add, Button, h%k_KeyHeight% x+%k_KeyMargin% w%k_SpacebarWidth%, Space

;---- Show the window:
Gui, Show
k_IsVisible = y

WinGet, k_ID, ID, A   ; Get its window ID.
WinGetPos,,, k_WindowWidth, k_WindowHeight, A

;---- Position the keyboard at the bottom of the screen (taking into account
; the position of the taskbar):
SysGet, k_WorkArea, MonitorWorkArea, %k_Monitor%

; Calculate window's X-position:
k_WindowX = %k_WorkAreaRight%
k_WindowX -= %k_WorkAreaLeft%  ; Now k_WindowX contains the width of this monitor.
k_WindowX -= %k_WindowWidth%
k_WindowX /= 2  ; Calculate position to center it horizontally.
; The following is done in case the window will be on a non-primary monitor
; or if the taskbar is anchored on the left side of the screen:
k_WindowX += %k_WorkAreaLeft%

; Calculate window's Y-position:
k_WindowY = %k_WorkAreaBottom%
k_WindowY -= %k_WindowHeight%

WinMove, A,, %k_WindowX%, %k_WindowY%
WinSet, AlwaysOnTop, On, ahk_id %k_ID%
WinSet, TransColor, %TransColor% 220, ahk_id %k_ID%

;---- Set all keys as hotkeys. See www.asciitable.com
k_n = 1
k_ASCII = 45

Loop
{
    Transform, k_char, Chr, %k_ASCII%
    StringUpper, k_char, k_char
    if k_char not in <,>,^,~,,`,
        Hotkey, ~*%k_char%, k_KeyPress
        ; In the above, the asterisk prefix allows the key to be detected regardless
        ; of whether the user is holding down modifier keys such as Control and Shift.
    if k_ASCII = 93
        break
    k_ASCII++
}

return ; End of auto-execute section.

;---- When a key is pressed by the user, click the corresponding button on-screen:

~*Backspace::
ControlClick, Bk, ahk_id %k_ID%, , LEFT, 1, D
KeyWait, Backspace
ControlClick, Bk, ahk_id %k_ID%, , LEFT, 1, U
return

; LShift and RShift are used rather than "Shift" because when used as a hotkey,
; "Shift" would default to firing upon release of the key (in older AHK versions):
~*LShift::
~*RShift::
~*LCtrl::  ; Must use Ctrl not Control to match button names.
~*RCtrl::
~*LAlt::
~*RAlt::
~*LWin::
~*RWin::
StringTrimLeft, k_ThisHotkey, A_ThisHotkey, 3
ControlClick, %k_ThisHotkey%, ahk_id %k_ID%, , LEFT, 1, D
KeyWait, %k_ThisHotkey%
ControlClick, %k_ThisHotkey%, ahk_id %k_ID%, , LEFT, 1, U
return

~*,::
~*'::
~*Space::
~*Enter::
~*Tab::
k_KeyPress:
StringReplace, k_ThisHotkey, A_ThisHotkey, ~
StringReplace, k_ThisHotkey, k_ThisHotkey, *
SetTitleMatchMode, 3  ; Prevents the T and B keys from being confused with Tab and Backspace.
ControlClick, %k_ThisHotkey%, ahk_id %k_ID%, , LEFT, 1, D
KeyWait, %k_ThisHotkey%
ControlClick, %k_ThisHotkey%, ahk_id %k_ID%, , LEFT, 1, U
Return

k_ShowHide:
if k_IsVisible = y
{
    Gui, Cancel
    Menu, Tray, Rename, %k_MenuItemHide%, %k_MenuItemShow%
    k_IsVisible = n
}
else
{
    Gui, Show
    Menu, Tray, Rename, %k_MenuItemShow%, %k_MenuItemHide%
    k_IsVisible = y
}
return

GuiClose:
k_MenuExit:
ExitApp


最小化窗口到托盘菜单

此脚本会设置您选择的热键来隐藏任意的窗口, 让这些窗口成为脚本托盘菜单底部的条目. 通过在菜单上选择相应的项目可以显示个别隐藏的窗口或全部显示. 如果由于任何原因脚本退出了, 那么它隐藏的所有窗口都会自动显示.

下载此脚本 | 其他示例脚本 | 主页

; CHANGES:
; July 22, 2005 (changes provided by egilmour):
; - Added new hotkey to unhide the last hidden window (Win+U)
;
; November 3, 2004 (changes provided by trogdor):
; - Program manager is prevented from being hidden.
; - If there is no active window, the minimize-to-tray hotkey will have
;   no effect rather than waiting indefinitely.
;
; October 23, 2004:
; - The taskbar is prevented from being hidden.
; - Some possible problems with long window titles have been fixed.
; - Windows without a title can be hidden without causing problems.
; - If the script is running under AHK v1.0.22 or greater, the
;   maximum length of each menu item is increased from 100 to 260.

; CONFIGURATION SECTION: Change the below values as desired.

; This is the maximum number of windows to allow to be hidden (having a
; limit helps performance):
mwt_MaxWindows = 50

; This is the hotkey used to hide the active window:
mwt_Hotkey = #h  ; Win+H

; This is the hotkey used to unhide the last hidden window:
mwt_UnHotkey = #u  ; Win+U

; If you prefer to have the tray menu empty of all the standard items,
; such as Help and Pause, use N.  Otherwise, use Y:
mwt_StandardMenu = N

; These next few performance settings help to keep the action within the
; #HotkeyModifierTimeout period, and thus avoid the need to release and
; press down the hotkey's modifier if you want to hide more than one
; window in a row.  These settings are not needed you choose to have the
; script use the keyboard hook via #InstallKeybdHook or other means:
#HotkeyModifierTimeout 100
SetWinDelay 10
SetKeyDelay 0

#SingleInstance  ; Allow only one instance of this script to be running.

; END OF CONFIGURATION SECTION (do not make changes below this point
; unless you want to change the basic functionality of the script).

Hotkey, %mwt_Hotkey%, mwt_Minimize
Hotkey, %mwt_UnHotkey%, mwt_UnMinimize

; If the user terminates the script by any means, unhide all the
; windows first:
OnExit, mwt_RestoreAllThenExit

if mwt_StandardMenu = Y
    Menu, Tray, Add
else
{
    Menu, Tray, NoStandard
    Menu, Tray, Add, E&xit and Unhide All, mwt_RestoreAllThenExit
}
Menu, Tray, Add, &Unhide All Hidden Windows, mwt_RestoreAll
Menu, Tray, Add  ; Another separator line to make the above more special.

if a_AhkVersion =   ; Since it's blank, version is older than 1.0.22.
    mwt_MaxLength = 100
else
    mwt_MaxLength = 260  ; Reduce this to restrict the width of the menu.

return  ; End of auto-execute section.

mwt_Minimize:
if mwt_WindowCount >= %mwt_MaxWindows%
{
    MsgBox No more than %mwt_MaxWindows% may be hidden simultaneously.
    return
}

; Set the "last found window" to simplify and help performance.
; Since in certain cases it is possible for there to be no active window,
; a timeout has been added:
WinWait, A,, 2
if ErrorLevel <> 0  ; It timed out, so do nothing.
    return

; Otherwise, the "last found window" has been set and can now be used:
WinGet, mwt_ActiveID, ID
WinGetTitle, mwt_ActiveTitle
WinGetClass, mwt_ActiveClass
if mwt_ActiveClass in Shell_TrayWnd,Progman
{
    MsgBox The desktop and taskbar cannot be hidden.
    return
}
; Because hiding the window won't deactivate it, activate the window
; beneath this one (if any). I tried other ways, but they wound up
; activating the task bar.  This way sends the active window (which is
; about to be hidden) to the back of the stack, which seems best:
Send, !{esc}
; Hide it only now that WinGetTitle/WinGetClass above have been run (since
; by default, those commands cannot detect hidden windows):
WinHide

; If the title is blank, use the class instead.  This serves two purposes:
; 1) A more meaningful name is used as the menu name.
; 2) Allows the menu item to be created (otherwise, blank items wouldn't
;    be handled correctly by the various routines below).
if mwt_ActiveTitle =
    mwt_ActiveTitle = ahk_class %mwt_ActiveClass%
; Ensure the title is short enough to fit. mwt_ActiveTitle also serves to
; uniquely identify this particular menu item.
StringLeft, mwt_ActiveTitle, mwt_ActiveTitle, %mwt_MaxLength%

; In addition to the tray menu requiring that each menu item name be
; unique, it must also be unique so that we can reliably look it up in
; the array when the window is later unhidden.  So make it unique if it
; isn't already:
Loop, %mwt_MaxWindows%
{
    if mwt_WindowTitle%a_index% = %mwt_ActiveTitle%
    {
        ; Match found, so it's not unique.
        ; First remove the 0x from the hex number to conserve menu space:
        StringTrimLeft, mwt_ActiveIDShort, mwt_ActiveID, 2
        StringLen, mwt_ActiveIDShortLength, mwt_ActiveIDShort
        StringLen, mwt_ActiveTitleLength, mwt_ActiveTitle
        mwt_ActiveTitleLength += %mwt_ActiveIDShortLength%
        mwt_ActiveTitleLength += 1 ; +1 the 1 space between title & ID.
        if mwt_ActiveTitleLength > %mwt_MaxLength%
        {
            ; Since menu item names are limted in length, trim the title
            ; down to allow just enough room for the Window's Short ID at
            ; the end of its name:
            TrimCount = %mwt_ActiveTitleLength%
            TrimCount -= %mwt_MaxLength%
            StringTrimRight, mwt_ActiveTitle, mwt_ActiveTitle, %TrimCount%
        }
        ; Build unique title:
        mwt_ActiveTitle = %mwt_ActiveTitle% %mwt_ActiveIDShort%
        break
    }
}

; First, ensure that this ID doesn't already exist in the list, which can
; happen if a particular window was externally unhidden (or its app unhid
; it) and now it's about to be re-hidden:
mwt_AlreadyExists = n
Loop, %mwt_MaxWindows%
{
    if mwt_WindowID%a_index% = %mwt_ActiveID%
    {
        mwt_AlreadyExists = y
        break
    }
}

; Add the item to the array and to the menu:
if mwt_AlreadyExists = n
{
    Menu, Tray, add, %mwt_ActiveTitle%, RestoreFromTrayMenu
    mwt_WindowCount += 1
    Loop, %mwt_MaxWindows%  ; Search for a free slot.
    {
        ; It should always find a free slot if things are designed right.
        if mwt_WindowID%a_index% =  ; An empty slot was found.
        {
            mwt_WindowID%a_index% = %mwt_ActiveID%
            mwt_WindowTitle%a_index% = %mwt_ActiveTitle%
            break
        }
    }
}
return

RestoreFromTrayMenu:
Menu, Tray, delete, %A_ThisMenuItem%
; Find window based on its unique title stored as the menu item name:
Loop, %mwt_MaxWindows%
{
    if mwt_WindowTitle%a_index% = %A_ThisMenuItem%  ; Match found.
    {
        StringTrimRight, IDToRestore, mwt_WindowID%a_index%, 0
        WinShow, ahk_id %IDToRestore%
        WinActivate ahk_id %IDToRestore%  ; Sometimes needed.
        mwt_WindowID%a_index% =  ; Make it blank to free up a slot.
        mwt_WindowTitle%a_index% =
        mwt_WindowCount -= 1
        break
    }
}
return

;; This will pop the last minimized window off the stack and unhide it.
mwt_UnMinimize:
;; Make sure there's something to unhide.
if mwt_WindowCount > 0
{
    ;; Get the id of the last window minimized and unhide it
    StringTrimRight, IDToRestore, mwt_WindowID%mwt_WindowCount%, 0
    WinShow, ahk_id %IDToRestore%
    WinActivate ahk_id %IDToRestore%

    ;; Get the menu name of the last window minimized and remove it
    StringTrimRight, MenuToRemove, mwt_WindowTitle%mwt_WindowCount%, 0
    Menu, Tray, delete, %MenuToRemove%

    ;; clean up our 'arrays' and decrement the window count
    mwt_WindowID%mwt_WindowCount% =
    mwt_WindowTitle%mwt_WindowCount% =
    mwt_WindowCount -= 1
}
return

mwt_RestoreAllThenExit:
Gosub, mwt_RestoreAll
ExitApp  ; Do a true exit.

mwt_RestoreAll:
Loop, %mwt_MaxWindows%
{
    if mwt_WindowID%a_index% <>
    {
        StringTrimRight, IDToRestore, mwt_WindowID%a_index%, 0
        WinShow, ahk_id %IDToRestore%
        WinActivate ahk_id %IDToRestore%  ; Sometimes needed.
        ; Do it this way vs. DeleteAll so that the sep. line and first
        ; item are retained:
        StringTrimRight, MenuToRemove, mwt_WindowTitle%a_index%, 0
        Menu, Tray, delete, %MenuToRemove%
        mwt_WindowID%a_index% =  ; Make it blank to free up a slot.
        mwt_WindowTitle%a_index% =
        mwt_WindowCount -= 1
    }
    if mwt_WindowCount = 0
        break
}
return


鼠标手势 -- 作者: deguix

此脚本在您按住鼠标右键时会监视鼠标移动的轨迹. 如果它看到您 "画" 出一个能识别的形状或符号, 那么它会启动程序或执行由您选择的自定义动作 (就像热键那样). 请参阅内含的 README 文件了解如何定义手势.


改变 MsgBox 的按钮名称

这是个可运行示例脚本, 它使用计时器改变 MsgBox 对话框中按钮的名称. 尽管改变了按钮名称, 但 IfMsgBox 命令中仍需要引用它们原始的按钮名称表示的按钮.

下载此脚本 | 其他示例脚本 | 主页

#SingleInstance
SetTimer, ChangeButtonNames, 50
MsgBox, 4, Add or Delete, Choose a button:
IfMsgBox, YES
    MsgBox, You chose Add.
else
    MsgBox, You chose Delete.
return

ChangeButtonNames:
IfWinNotExist, Add or Delete
    return  ; Keep waiting.
SetTimer, ChangeButtonNames, off
WinActivate
ControlSetText, Button1, &Add
ControlSetText, Button2, &Delete
return


小键盘上的 000 键

此示例脚本把某些小键盘上特殊的 000 键设置为等号键. You can change the action by replacing the Send, = line with line(s) of your choice.

下载此脚本 | 其他示例脚本 | 主页

#MaxThreadsPerHotkey 5  ; Allow multiple threads for this hotkey.
$Numpad0::
#MaxThreadsPerHotkey 1
; Above: Use the $ to force the hook to be used, which prevents an
; infinite loop since this subroutine itself sends Numpad0, which
; would otherwise result in a recursive call to itself.
SetBatchLines, 100 ; Make it run a little faster in this case.
DelayBetweenKeys = 30 ; Adjust this value if it doesn't work.
if A_PriorHotkey = %A_ThisHotkey%
{
    if A_TimeSincePriorHotkey < %DelayBetweenKeys%
    {
        if Numpad0Count =
            Numpad0Count = 2 ; i.e. This one plus the prior one.
        else if Numpad0Count = 0
            Numpad0Count = 2
        else
        {
            ; Since we're here, Numpad0Count must be 2 as set by
            ; prior calls, which means this is the third time the
            ; the key has been pressed. Thus, the hotkey sequence
            ; should fire:
            Numpad0Count = 0
            Send, = ; ******* This is the action for the 000 key
        }
        ; In all the above cases, we return without further action:
        CalledReentrantly = y
        return
    }
}
; Otherwise, this Numpad0 event is either the first in the series
; or it happened too long after the first one (e.g. perhaps the
; user is holding down the Numpad0 key to auto-repeat it, which
; we want to allow).  Therefore, after a short delay -- during
; which another Numpad0 hotkey event may re-entrantly call this
; subroutine -- we'll send the key on through if no reentrant
; calls occurred:
Numpad0Count = 0
CalledReentrantly = n
; During this sleep, this subroutine may be reentrantly called
; (i.e. a simultaneous "thread" which runs in parallel to the
; call we're in now):
Sleep, %DelayBetweenKeys%
if CalledReentrantly = y ; Another "thread" changed the value.
{
    ; Since it was called reentrantly, this key event was the first in
    ; the sequence so should be suppressed (hidden from the system):
    CalledReentrantly = n
    return
}
; Otherwise it's not part of the sequence so we send it through normally.
; In other words, the *real* Numpad0 key has been pressed, so we want it
; to have its normal effect:
Send, {Numpad0}
return


把小键盘作为鼠标使用 -- 作者: deguix

此脚本用您的键盘来实现鼠标操作, 几乎相当于真正的鼠标 (在一些任务中甚至更方便). 它支持多达五个鼠标按钮和鼠标滚轮的转动. 它还具有能自定义移动速度, 加速和 "轴反转" 的特点.

下载此脚本 | 其他示例脚本 | 主页

/*
o------------------------------------------------------------o
|Using Keyboard Numpad as a Mouse                            |
(------------------------------------------------------------)
| By deguix           / A Script file for AutoHotkey 1.0.22+ |
|                    ----------------------------------------|
|                                                            |
|    This script is an example of use of AutoHotkey. It uses |
| the remapping of numpad keys of a keyboard to transform it |
| into a mouse. Some features are the acceleration which     |
| enables you to increase the mouse movement when holding    |
| a key for a long time, and the rotation which makes the    |
| numpad mouse to "turn". I.e. NumPadDown as NumPadUp        |
| and vice-versa. See the list of keys used below:           |
|                                                            |
|------------------------------------------------------------|
| Keys                  | Description                        |
|------------------------------------------------------------|
| ScrollLock (toggle on)| Activates numpad mouse mode.       |
|-----------------------|------------------------------------|
| NumPad0               | Left mouse button click.           |
| NumPad5               | Middle mouse button click.         |
| NumPadDot             | Right mouse button click.          |
| NumPadDiv/NumPadMult  | X1/X2 mouse button click. (Win 2k+)|
| NumPadSub/NumPadAdd   | Moves up/down the mouse wheel.     |
|                       |                                    |
|-----------------------|------------------------------------|
| NumLock (toggled off) | Activates mouse movement mode.     |
|-----------------------|------------------------------------|
| NumPadEnd/Down/PgDn/  | Mouse movement.                    |
| /Left/Right/Home/Up/  |                                    |
| /PgUp                 |                                    |
|                       |                                    |
|-----------------------|------------------------------------|
| NumLock (toggled on)  | Activates mouse speed adj. mode.   |
|-----------------------|------------------------------------|
| NumPad7/NumPad1       | Inc./dec. acceleration per         |
|                       | button press.                      |
| NumPad8/NumPad2       | Inc./dec. initial speed per        |
|                       | button press.                      |
| NumPad9/NumPad3       | Inc./dec. maximum speed per        |
|                       | button press.                      |
| ^NumPad7/^NumPad1     | Inc./dec. wheel acceleration per   |
|                       | button press*.                     |
| ^NumPad8/^NumPad2     | Inc./dec. wheel initial speed per  |
|                       | button press*.                     |
| ^NumPad9/^NumPad3     | Inc./dec. wheel maximum speed per  |
|                       | button press*.                     |
| NumPad4/NumPad6       | Inc./dec. rotation angle to        |
|                       | right in degrees. (i.e. 180° =     |
|                       | = inversed controls).              |
|------------------------------------------------------------|
| * = These options are affected by the mouse wheel speed    |
| adjusted on Control Panel. If you don't have a mouse with  |
| wheel, the default is 3 +/- lines per option button press. |
o------------------------------------------------------------o
*/

;START OF CONFIG SECTION

#SingleInstance force
#MaxHotkeysPerInterval 500

; Using the keyboard hook to implement the Numpad hotkeys prevents
; them from interfering with the generation of ANSI characters such
; as à.  This is because AutoHotkey generates such characters
; by holding down ALT and sending a series of Numpad keystrokes.
; Hook hotkeys are smart enough to ignore such keystrokes.
#UseHook

MouseSpeed = 1
MouseAccelerationSpeed = 1
MouseMaxSpeed = 5

;Mouse wheel speed is also set on Control Panel. As that
;will affect the normal mouse behavior, the real speed of
;these three below are times the normal mouse wheel speed.
MouseWheelSpeed = 1
MouseWheelAccelerationSpeed = 1
MouseWheelMaxSpeed = 5

MouseRotationAngle = 0

;END OF CONFIG SECTION

;This is needed or key presses would faulty send their natural
;actions. Like NumPadDiv would send sometimes "/" to the
;screen.
#InstallKeybdHook

Temp = 0
Temp2 = 0

MouseRotationAnglePart = %MouseRotationAngle%
;Divide by 45º because MouseMove only supports whole numbers,
;and changing the mouse rotation to a number lesser than 45º
;could make strange movements.
;
;For example: 22.5º when pressing NumPadUp:
;  First it would move upwards until the speed
;  to the side reaches 1.
MouseRotationAnglePart /= 45

MouseCurrentAccelerationSpeed = 0
MouseCurrentSpeed = %MouseSpeed%

MouseWheelCurrentAccelerationSpeed = 0
MouseWheelCurrentSpeed = %MouseSpeed%

SetKeyDelay, -1
SetMouseDelay, -1

Hotkey, *NumPad0, ButtonLeftClick
Hotkey, *NumpadIns, ButtonLeftClickIns
Hotkey, *NumPad5, ButtonMiddleClick
Hotkey, *NumpadClear, ButtonMiddleClickClear
Hotkey, *NumPadDot, ButtonRightClick
Hotkey, *NumPadDel, ButtonRightClickDel
Hotkey, *NumPadDiv, ButtonX1Click
Hotkey, *NumPadMult, ButtonX2Click

Hotkey, *NumpadSub, ButtonWheelUp
Hotkey, *NumpadAdd, ButtonWheelDown

Hotkey, *NumPadUp, ButtonUp
Hotkey, *NumPadDown, ButtonDown
Hotkey, *NumPadLeft, ButtonLeft
Hotkey, *NumPadRight, ButtonRight
Hotkey, *NumPadHome, ButtonUpLeft
Hotkey, *NumPadEnd, ButtonUpRight
Hotkey, *NumPadPgUp, ButtonDownLeft
Hotkey, *NumPadPgDn, ButtonDownRight

Hotkey, Numpad8, ButtonSpeedUp
Hotkey, Numpad2, ButtonSpeedDown
Hotkey, Numpad7, ButtonAccelerationSpeedUp
Hotkey, Numpad1, ButtonAccelerationSpeedDown
Hotkey, Numpad9, ButtonMaxSpeedUp
Hotkey, Numpad3, ButtonMaxSpeedDown

Hotkey, Numpad6, ButtonRotationAngleUp
Hotkey, Numpad4, ButtonRotationAngleDown

Hotkey, !Numpad8, ButtonWheelSpeedUp
Hotkey, !Numpad2, ButtonWheelSpeedDown
Hotkey, !Numpad7, ButtonWheelAccelerationSpeedUp
Hotkey, !Numpad1, ButtonWheelAccelerationSpeedDown
Hotkey, !Numpad9, ButtonWheelMaxSpeedUp
Hotkey, !Numpad3, ButtonWheelMaxSpeedDown

Gosub, ~ScrollLock  ; Initialize based on current ScrollLock state.
return

;Key activation support

~ScrollLock::
; Wait for it to be released because otherwise the hook state gets reset
; while the key is down, which causes the up-event to get suppressed,
; which in turn prevents toggling of the ScrollLock state/light:
KeyWait, ScrollLock
GetKeyState, ScrollLockState, ScrollLock, T
If ScrollLockState = D
{
    Hotkey, *NumPad0, on
    Hotkey, *NumpadIns, on
    Hotkey, *NumPad5, on
    Hotkey, *NumPadDot, on
    Hotkey, *NumPadDel, on
    Hotkey, *NumPadDiv, on
    Hotkey, *NumPadMult, on

    Hotkey, *NumpadSub, on
    Hotkey, *NumpadAdd, on

    Hotkey, *NumPadUp, on
    Hotkey, *NumPadDown, on
    Hotkey, *NumPadLeft, on
    Hotkey, *NumPadRight, on
    Hotkey, *NumPadHome, on
    Hotkey, *NumPadEnd, on
    Hotkey, *NumPadPgUp, on
    Hotkey, *NumPadPgDn, on

    Hotkey, Numpad8, on
    Hotkey, Numpad2, on
    Hotkey, Numpad7, on
    Hotkey, Numpad1, on
    Hotkey, Numpad9, on
    Hotkey, Numpad3, on

    Hotkey, Numpad6, on
    Hotkey, Numpad4, on

    Hotkey, !Numpad8, on
    Hotkey, !Numpad2, on
    Hotkey, !Numpad7, on
    Hotkey, !Numpad1, on
    Hotkey, !Numpad9, on
    Hotkey, !Numpad3, on
}
else
{
    Hotkey, *NumPad0, off
    Hotkey, *NumpadIns, off
    Hotkey, *NumPad5, off
    Hotkey, *NumPadDot, off
    Hotkey, *NumPadDel, off
    Hotkey, *NumPadDiv, off
    Hotkey, *NumPadMult, off

    Hotkey, *NumpadSub, off
    Hotkey, *NumpadAdd, off

    Hotkey, *NumPadUp, off
    Hotkey, *NumPadDown, off
    Hotkey, *NumPadLeft, off
    Hotkey, *NumPadRight, off
    Hotkey, *NumPadHome, off
    Hotkey, *NumPadEnd, off
    Hotkey, *NumPadPgUp, off
    Hotkey, *NumPadPgDn, off

    Hotkey, Numpad8, off
    Hotkey, Numpad2, off
    Hotkey, Numpad7, off
    Hotkey, Numpad1, off
    Hotkey, Numpad9, off
    Hotkey, Numpad3, off

    Hotkey, Numpad6, off
    Hotkey, Numpad4, off

    Hotkey, !Numpad8, off
    Hotkey, !Numpad2, off
    Hotkey, !Numpad7, off
    Hotkey, !Numpad1, off
    Hotkey, !Numpad9, off
    Hotkey, !Numpad3, off
}
return

;Mouse click support

ButtonLeftClick:
GetKeyState, already_down_state, LButton
If already_down_state = D
    return
Button2 = NumPad0
ButtonClick = Left
Goto ButtonClickStart
ButtonLeftClickIns:
GetKeyState, already_down_state, LButton
If already_down_state = D
    return
Button2 = NumPadIns
ButtonClick = Left
Goto ButtonClickStart

ButtonMiddleClick:
GetKeyState, already_down_state, MButton
If already_down_state = D
    return
Button2 = NumPad5
ButtonClick = Middle
Goto ButtonClickStart
ButtonMiddleClickClear:
GetKeyState, already_down_state, MButton
If already_down_state = D
    return
Button2 = NumPadClear
ButtonClick = Middle
Goto ButtonClickStart

ButtonRightClick:
GetKeyState, already_down_state, RButton
If already_down_state = D
    return
Button2 = NumPadDot
ButtonClick = Right
Goto ButtonClickStart
ButtonRightClickDel:
GetKeyState, already_down_state, RButton
If already_down_state = D
    return
Button2 = NumPadDel
ButtonClick = Right
Goto ButtonClickStart

ButtonX1Click:
GetKeyState, already_down_state, XButton1
If already_down_state = D
    return
Button2 = NumPadDiv
ButtonClick = X1
Goto ButtonClickStart

ButtonX2Click:
GetKeyState, already_down_state, XButton2
If already_down_state = D
    return
Button2 = NumPadMult
ButtonClick = X2
Goto ButtonClickStart

ButtonClickStart:
MouseClick, %ButtonClick%,,, 1, 0, D
SetTimer, ButtonClickEnd, 10
return

ButtonClickEnd:
GetKeyState, kclickstate, %Button2%, P
if kclickstate = D
    return

SetTimer, ButtonClickEnd, off
MouseClick, %ButtonClick%,,, 1, 0, U
return

;Mouse movement support

ButtonSpeedUp:
MouseSpeed++
ToolTip, Mouse speed: %MouseSpeed% pixels
SetTimer, RemoveToolTip, 1000
return
ButtonSpeedDown:
If MouseSpeed > 1
    MouseSpeed--
If MouseSpeed = 1
    ToolTip, Mouse speed: %MouseSpeed% pixel
else
    ToolTip, Mouse speed: %MouseSpeed% pixels
SetTimer, RemoveToolTip, 1000
return
ButtonAccelerationSpeedUp:
MouseAccelerationSpeed++
ToolTip, Mouse acceleration speed: %MouseAccelerationSpeed% pixels
SetTimer, RemoveToolTip, 1000
return
ButtonAccelerationSpeedDown:
If MouseAccelerationSpeed > 1
    MouseAccelerationSpeed--
If MouseAccelerationSpeed = 1
    ToolTip, Mouse acceleration speed: %MouseAccelerationSpeed% pixel
else
    ToolTip, Mouse acceleration speed: %MouseAccelerationSpeed% pixels
SetTimer, RemoveToolTip, 1000
return

ButtonMaxSpeedUp:
MouseMaxSpeed++
ToolTip, Mouse maximum speed: %MouseMaxSpeed% pixels
SetTimer, RemoveToolTip, 1000
return
ButtonMaxSpeedDown:
If MouseMaxSpeed > 1
    MouseMaxSpeed--
If MouseMaxSpeed = 1
    ToolTip, Mouse maximum speed: %MouseMaxSpeed% pixel
else
    ToolTip, Mouse maximum speed: %MouseMaxSpeed% pixels
SetTimer, RemoveToolTip, 1000
return

ButtonRotationAngleUp:
MouseRotationAnglePart++
If MouseRotationAnglePart >= 8
    MouseRotationAnglePart = 0
MouseRotationAngle = %MouseRotationAnglePart%
MouseRotationAngle *= 45
ToolTip, Mouse rotation angle: %MouseRotationAngle%°
SetTimer, RemoveToolTip, 1000
return
ButtonRotationAngleDown:
MouseRotationAnglePart--
If MouseRotationAnglePart < 0
    MouseRotationAnglePart = 7
MouseRotationAngle = %MouseRotationAnglePart%
MouseRotationAngle *= 45
ToolTip, Mouse rotation angle: %MouseRotationAngle%°
SetTimer, RemoveToolTip, 1000
return

ButtonUp:
ButtonDown:
ButtonLeft:
ButtonRight:
ButtonUpLeft:
ButtonUpRight:
ButtonDownLeft:
ButtonDownRight:
If Button <> 0
{
    IfNotInString, A_ThisHotkey, %Button%
    {
        MouseCurrentAccelerationSpeed = 0
        MouseCurrentSpeed = %MouseSpeed%
    }
}
StringReplace, Button, A_ThisHotkey, *

ButtonAccelerationStart:
If MouseAccelerationSpeed >= 1
{
    If MouseMaxSpeed > %MouseCurrentSpeed%
    {
        Temp = 0.001
        Temp *= %MouseAccelerationSpeed%
        MouseCurrentAccelerationSpeed += %Temp%
        MouseCurrentSpeed += %MouseCurrentAccelerationSpeed%
    }
}

;MouseRotationAngle convertion to speed of button direction
{
    MouseCurrentSpeedToDirection = %MouseRotationAngle%
    MouseCurrentSpeedToDirection /= 90.0
    Temp = %MouseCurrentSpeedToDirection%

    if Temp >= 0
    {
        if Temp < 1
        {
            MouseCurrentSpeedToDirection = 1
            MouseCurrentSpeedToDirection -= %Temp%
            Goto EndMouseCurrentSpeedToDirectionCalculation
        }
    }
    if Temp >= 1
    {
        if Temp < 2
        {
            MouseCurrentSpeedToDirection = 0
            Temp -= 1
            MouseCurrentSpeedToDirection -= %Temp%
            Goto EndMouseCurrentSpeedToDirectionCalculation
        }
    }
    if Temp >= 2
    {
        if Temp < 3
        {
            MouseCurrentSpeedToDirection = -1
            Temp -= 2
            MouseCurrentSpeedToDirection += %Temp%
            Goto EndMouseCurrentSpeedToDirectionCalculation
        }
    }
    if Temp >= 3
    {
        if Temp < 4
        {
            MouseCurrentSpeedToDirection = 0
            Temp -= 3
            MouseCurrentSpeedToDirection += %Temp%
            Goto EndMouseCurrentSpeedToDirectionCalculation
        }
    }
}
EndMouseCurrentSpeedToDirectionCalculation:

;MouseRotationAngle convertion to speed of 90 degrees to right
{
    MouseCurrentSpeedToSide = %MouseRotationAngle%
    MouseCurrentSpeedToSide /= 90.0
    Temp = %MouseCurrentSpeedToSide%
    Transform, Temp, mod, %Temp%, 4

    if Temp >= 0
    {
        if Temp < 1
        {
            MouseCurrentSpeedToSide = 0
            MouseCurrentSpeedToSide += %Temp%
            Goto EndMouseCurrentSpeedToSideCalculation
        }
    }
    if Temp >= 1
    {
        if Temp < 2
        {
            MouseCurrentSpeedToSide = 1
            Temp -= 1
            MouseCurrentSpeedToSide -= %Temp%
            Goto EndMouseCurrentSpeedToSideCalculation
        }
    }
    if Temp >= 2
    {
        if Temp < 3
        {
            MouseCurrentSpeedToSide = 0
            Temp -= 2
            MouseCurrentSpeedToSide -= %Temp%
            Goto EndMouseCurrentSpeedToSideCalculation
        }
    }
    if Temp >= 3
    {
        if Temp < 4
        {
            MouseCurrentSpeedToSide = -1
            Temp -= 3
            MouseCurrentSpeedToSide += %Temp%
            Goto EndMouseCurrentSpeedToSideCalculation
        }
    }
}
EndMouseCurrentSpeedToSideCalculation:

MouseCurrentSpeedToDirection *= %MouseCurrentSpeed%
MouseCurrentSpeedToSide *= %MouseCurrentSpeed%

Temp = %MouseRotationAnglePart%
Transform, Temp, Mod, %Temp%, 2

If Button = NumPadUp
{
    if Temp = 1
    {
        MouseCurrentSpeedToSide *= 2
        MouseCurrentSpeedToDirection *= 2
    }

    MouseCurrentSpeedToDirection *= -1
    MouseMove, %MouseCurrentSpeedToSide%, %MouseCurrentSpeedToDirection%, 0, R
}
else if Button = NumPadDown
{
    if Temp = 1
    {
        MouseCurrentSpeedToSide *= 2
        MouseCurrentSpeedToDirection *= 2
    }

    MouseCurrentSpeedToSide *= -1
    MouseMove, %MouseCurrentSpeedToSide%, %MouseCurrentSpeedToDirection%, 0, R
}
else if Button = NumPadLeft
{
    if Temp = 1
    {
        MouseCurrentSpeedToSide *= 2
        MouseCurrentSpeedToDirection *= 2
    }

    MouseCurrentSpeedToSide *= -1
    MouseCurrentSpeedToDirection *= -1

    MouseMove, %MouseCurrentSpeedToDirection%, %MouseCurrentSpeedToSide%, 0, R
}
else if Button = NumPadRight
{
    if Temp = 1
    {
        MouseCurrentSpeedToSide *= 2
        MouseCurrentSpeedToDirection *= 2
    }

    MouseMove, %MouseCurrentSpeedToDirection%, %MouseCurrentSpeedToSide%, 0, R
}
else if Button = NumPadHome
{
    Temp = %MouseCurrentSpeedToDirection%
    Temp -= %MouseCurrentSpeedToSide%
    Temp *= -1
    Temp2 = %MouseCurrentSpeedToDirection%
    Temp2 += %MouseCurrentSpeedToSide%
    Temp2 *= -1
    MouseMove, %Temp%, %Temp2%, 0, R
}
else if Button = NumPadPgUp
{
    Temp = %MouseCurrentSpeedToDirection%
    Temp += %MouseCurrentSpeedToSide%
    Temp2 = %MouseCurrentSpeedToDirection%
    Temp2 -= %MouseCurrentSpeedToSide%
    Temp2 *= -1
    MouseMove, %Temp%, %Temp2%, 0, R
}
else if Button = NumPadEnd
{
    Temp = %MouseCurrentSpeedToDirection%
    Temp += %MouseCurrentSpeedToSide%
    Temp *= -1
    Temp2 = %MouseCurrentSpeedToDirection%
    Temp2 -= %MouseCurrentSpeedToSide%
    MouseMove, %Temp%, %Temp2%, 0, R
}
else if Button = NumPadPgDn
{
    Temp = %MouseCurrentSpeedToDirection%
    Temp -= %MouseCurrentSpeedToSide%
    Temp2 *= -1
    Temp2 = %MouseCurrentSpeedToDirection%
    Temp2 += %MouseCurrentSpeedToSide%
    MouseMove, %Temp%, %Temp2%, 0, R
}

SetTimer, ButtonAccelerationEnd, 10
return

ButtonAccelerationEnd:
GetKeyState, kstate, %Button%, P
if kstate = D
    Goto ButtonAccelerationStart

SetTimer, ButtonAccelerationEnd, off
MouseCurrentAccelerationSpeed = 0
MouseCurrentSpeed = %MouseSpeed%
Button = 0
return

;Mouse wheel movement support

ButtonWheelSpeedUp:
MouseWheelSpeed++
RegRead, MouseWheelSpeedMultiplier, HKCU, Control Panel\Desktop, WheelScrollLines
If MouseWheelSpeedMultiplier <= 0
    MouseWheelSpeedMultiplier = 1
MouseWheelSpeedReal = %MouseWheelSpeed%
MouseWheelSpeedReal *= %MouseWheelSpeedMultiplier%
ToolTip, Mouse wheel speed: %MouseWheelSpeedReal% lines
SetTimer, RemoveToolTip, 1000
return
ButtonWheelSpeedDown:
RegRead, MouseWheelSpeedMultiplier, HKCU, Control Panel\Desktop, WheelScrollLines
If MouseWheelSpeedMultiplier <= 0
    MouseWheelSpeedMultiplier = 1
If MouseWheelSpeedReal > %MouseWheelSpeedMultiplier%
{
    MouseWheelSpeed--
    MouseWheelSpeedReal = %MouseWheelSpeed%
    MouseWheelSpeedReal *= %MouseWheelSpeedMultiplier%
}
If MouseWheelSpeedReal = 1
    ToolTip, Mouse wheel speed: %MouseWheelSpeedReal% line
else
    ToolTip, Mouse wheel speed: %MouseWheelSpeedReal% lines
SetTimer, RemoveToolTip, 1000
return

ButtonWheelAccelerationSpeedUp:
MouseWheelAccelerationSpeed++
RegRead, MouseWheelSpeedMultiplier, HKCU, Control Panel\Desktop, WheelScrollLines
If MouseWheelSpeedMultiplier <= 0
    MouseWheelSpeedMultiplier = 1
MouseWheelAccelerationSpeedReal = %MouseWheelAccelerationSpeed%
MouseWheelAccelerationSpeedReal *= %MouseWheelSpeedMultiplier%
ToolTip, Mouse wheel acceleration speed: %MouseWheelAccelerationSpeedReal% lines
SetTimer, RemoveToolTip, 1000
return
ButtonWheelAccelerationSpeedDown:
RegRead, MouseWheelSpeedMultiplier, HKCU, Control Panel\Desktop, WheelScrollLines
If MouseWheelSpeedMultiplier <= 0
    MouseWheelSpeedMultiplier = 1
If MouseWheelAccelerationSpeed > 1
{
    MouseWheelAccelerationSpeed--
    MouseWheelAccelerationSpeedReal = %MouseWheelAccelerationSpeed%
    MouseWheelAccelerationSpeedReal *= %MouseWheelSpeedMultiplier%
}
If MouseWheelAccelerationSpeedReal = 1
    ToolTip, Mouse wheel acceleration speed: %MouseWheelAccelerationSpeedReal% line
else
    ToolTip, Mouse wheel acceleration speed: %MouseWheelAccelerationSpeedReal% lines
SetTimer, RemoveToolTip, 1000
return

ButtonWheelMaxSpeedUp:
MouseWheelMaxSpeed++
RegRead, MouseWheelSpeedMultiplier, HKCU, Control Panel\Desktop, WheelScrollLines
If MouseWheelSpeedMultiplier <= 0
    MouseWheelSpeedMultiplier = 1
MouseWheelMaxSpeedReal = %MouseWheelMaxSpeed%
MouseWheelMaxSpeedReal *= %MouseWheelSpeedMultiplier%
ToolTip, Mouse wheel maximum speed: %MouseWheelMaxSpeedReal% lines
SetTimer, RemoveToolTip, 1000
return
ButtonWheelMaxSpeedDown:
RegRead, MouseWheelSpeedMultiplier, HKCU, Control Panel\Desktop, WheelScrollLines
If MouseWheelSpeedMultiplier <= 0
    MouseWheelSpeedMultiplier = 1
If MouseWheelMaxSpeed > 1
{
    MouseWheelMaxSpeed--
    MouseWheelMaxSpeedReal = %MouseWheelMaxSpeed%
    MouseWheelMaxSpeedReal *= %MouseWheelSpeedMultiplier%
}
If MouseWheelMaxSpeedReal = 1
    ToolTip, Mouse wheel maximum speed: %MouseWheelMaxSpeedReal% line
else
    ToolTip, Mouse wheel maximum speed: %MouseWheelMaxSpeedReal% lines
SetTimer, RemoveToolTip, 1000
return

ButtonWheelUp:
ButtonWheelDown:

If Button <> 0
{
    If Button <> %A_ThisHotkey%
    {
        MouseWheelCurrentAccelerationSpeed = 0
        MouseWheelCurrentSpeed = %MouseWheelSpeed%
    }
}
StringReplace, Button, A_ThisHotkey, *

ButtonWheelAccelerationStart:
If MouseWheelAccelerationSpeed >= 1
{
    If MouseWheelMaxSpeed > %MouseWheelCurrentSpeed%
    {
        Temp = 0.001
        Temp *= %MouseWheelAccelerationSpeed%
        MouseWheelCurrentAccelerationSpeed += %Temp%
        MouseWheelCurrentSpeed += %MouseWheelCurrentAccelerationSpeed%
    }
}

If Button = NumPadSub
    MouseClick, wheelup,,, %MouseWheelCurrentSpeed%, 0, D
else if Button = NumPadAdd
    MouseClick, wheeldown,,, %MouseWheelCurrentSpeed%, 0, D

SetTimer, ButtonWheelAccelerationEnd, 100
return

ButtonWheelAccelerationEnd:
GetKeyState, kstate, %Button%, P
if kstate = D
    Goto ButtonWheelAccelerationStart

MouseWheelCurrentAccelerationSpeed = 0
MouseWheelCurrentSpeed = %MouseWheelSpeed%
Button = 0
return

RemoveToolTip:
SetTimer, RemoveToolTip, Off
ToolTip
return


搜索 -- 作者: Phi

浏览开始菜单可能是件麻烦事, 尤其在您安装了很多程序的时候. 'Seek' 能让您指定不区分大小写的关键词/短语, 用它从开始菜单里筛选出匹配的程序和目录, 以便您可以轻松地从少数匹配的项目中打开目标程序. 这样就不用在开始菜单中做查找和穿越的苦力活了.

下载此脚本 | 其他示例脚本 | 主页

;*****************************************************************
;
;  Program : Seek
;  Coder   : Phi
;  Updated : Mon Jan 31 10:08:37 2005
;
;  What do you seek, my friend?
;
;*****************************************************************
;
;  I have a lot of fun coding this, and hope you will
;  enjoy using it too. Feel free to drop me an email with
;  your comments and feedback at: phi1618 (*a.t*) gmail
;  :D0T: com.
;
;  Options:
;    -cache Use the cached directory-listing if available
;           (this is the default mode when no option is specified)
;    -scan  Force a directory scan to retrieve the latest
;           directory listing
;    -scex  Scan & exit (this is useful for scheduling the
;           potentially time-consuming directory-scanning as
;           a background job)
;    -help  Show this help
;
;*****************************************************************
;
; HOW TO 'SEEK':
;
; 1. 'Seek' is an AutoHotkey script. You can either run it
;    as Seek.ahk (original script) or Seek.exe (compiled
;    executable).
;
;    To obtain Seek.exe, you can download Seek.zip (includes
;    both the source code and the compiled binary) from
;    http://home.ripway.com/2004-10/188589/
;    Otherwise, you can compile Seek.ahk on your own by
;    using AutoHotkey's Ahk2Exe.exe compiler, or you can
;    ask me for a copy via email. The filesize is small at
;    about 200 kbytes. I can be reached at: phi1618 (*a.t*)
;    gmail :D0T: com.
;
;    To use Seek.ahk, first, you'll need to install
;    AutoHotkey v1.0.25 or higher on your PC (download from
;    http://www.autohotkey.com). Next, run the command:
;
;    X:\myTools\AutoHotkey\AutoHotkey.exe Y:\myAHK\Seek.ahk
;
;    Remember to replace X:\myTools and Y:\myAHK with
;    the proper directory names on your PC.
;
; 2. You can place the executable Seek.exe anywhere you
;    want. There is no installation required, it doesn't
;    write anything to your registry, and it doesn't
;    access the Internet at all (no phoning home). To
;    uninstall, simply delete Seek.exe.
;
;    The only 2 files 'Seek' creates are placed in your
;    TMP directory:
;
;      a. _Seek.key  (cache file for last query string)
;      b. _Seek.list (cache file for directory listing)
;
;    If you're a purist, you can delete them manually
;    when you decide to remove 'Seek' from your system.
;
; 3. The most convenient way to run 'Seek' is via a
;    shortcut/hotkey. If you are not already using any
;    hotkey management program on your PC, I highly
;    recommend AutoHotkey. If you don't intend to install
;    any hotkey management program at the moment, you can
;    make use of Windows shortcut feature and bind a
;    shortcut key (e.g. ALT-F1) to launch 'Seek'. This is
;    important so that you can run 'Seek' at anytime and
;    anywhere.
;
; 4. When you run 'Seek' for the first time, it'll scan
;    your Start Menu, and save the directory listing into
;    a cache file.
;
;    The following directories are included in the scanning:
;    - %A_StartMenu%
;    - %A_StartMenuCommon%
;
;    By default, subsequent runs will read from the
;    cache file so as to reduce the loading time. For
;    more info on options, run 'Seek.exe -help'. If you
;    think your Start Menu doesn't contain too many
;    programs, you can choose not to use the cache and
;    instruct 'Seek' to always do a directory scan (via
;    option -scan).  That way, you will always get the
;    latest listing.
;
; 5. When you run 'Seek', a window will appear, waiting
;    for you to enter a key word/phrase. After you have
;    entered a query string, a list of matching records
;    will be displayed. Next, you need to highlight an
;    entry and press <Enter> or click on the 'Open'
;    button to run the selected program or open the
;    selected directory.
;
;*****************************************************************
;
; TECHNICAL NOTES:
;
; - 'Seek' requires Chris Mallett's AutoHotkey v1.0.25
;   or higher version (http://www.autohotkey.com).
;   Thanks to Chris for his great work on AutoHotkey. :)
;
; - The following environment variables must be valid:
;   a. TMP
;
;*****************************************************************
;
; KNOWN PROBLEMS:
;
; - Nil
;
;*****************************************************************
;
; IMPLEMENTED SUGGESTIONS:
;
; - Highlight 1st matching record by default so that
;   user can just hit <Enter> to run it.
;   (Suggested by Yih Yeong)
;
; - Enable double-click on the listing of the search
;   results to launch the program.
;   (Suggested by Yih Yeong & Jack)
;
; - Auto real-time incremental search.
;   (Suggested by Rajat)
;
; - Fuzzy search when user enters multiple query strings,
;   separated by space.
;   (Suggested by Rajat)
;
;*****************************************************************
;
; SUGGESTED FEATURES (MAY OR MAY NOT BE IMPLEMENTED):
;
; - Log the launch history. List the most frequently
;   used programs at the top of the search results.
;   (Suggested by Yih Yeong)
;
; - Instead of using list box, can it display a series
;   of application icons so that hovering the cursor
;   over the icon will display a tooltip containing the
;   program information (path, etc).
;   (Suggested by Yih Yeong)
;
; - Instead of matching text in the middle, match only
;   those program/directory names that begin with the
;   query string.
;   (Suggested by Stefan)
;
; - Add favorites management. Launch group of programs
;   in a single run.
;   (Suggested by Atomhrt)
;
; - Integrate Seek into the Windows taskbar/toolbar so that
;   it is always available and there is no need to bind a
;   hotkey to launch Seek.
;   (Suggested by Deniz Akay)
;
; - Search by wildcards/regex.
;   (Suggested by Steve)
;
;*****************************************************************
;
; CHANGE HISTORY:
;
; * v1.1.0
; - Initial release.
;
; * v1.1.1
; - Removed maximise-window option since some programs don't
;   function well with it.
; - Added double-click detection to trigger 'Open' function.
;
; * v2.0.0
; - Integrated the 'Seek' popup window into the output screen
;   so that user can re-enter the query string to search for
;   something else without having to exit and run Seek again.
; - Added 'Scan Start-Menu' button.
; - Added real-time incremental search which will auto
;   filter for matching records while you type away,
;   without waiting for you to press <Enter>.
; - Added internal switch (TrackKeyPhrase) to track search-string.
; - Added internal switch (ToolTipFilename) to show filename
;   using tooltip.
;
; * v2.0.1
; - Added horizontal scrollbar to ListBox so that very
;   long records will not be cut-off in the middle.
;
; * v2.0.2
; - Allowed user to add their own customised list of directories
;   to be included in the scanning. User just needs to create a
;   text file 'Seek.dir' in the same directory as Seek.exe or
;   Seek.ahk, and specify the full path of the directory to be
;   added, one directory per line. Do not enclose the path in
;   quotes or double-quotes.
;
; * v2.0.3
; - Added /on option to DIR-command to sort by name.
; - Fuzzy search when user enters multiple query strings,
;   separated by space, for e.g. "med pla". It's a match
;   when all the strings ("med" & "pla") are found. This
;   will match "Media Player", "Macromedia Flash Player",
;   "Play Medieval King", "medpla", "plamed".
; - Corrected tab-movement sequence by adding all buttons
;   right from the start, but disable them until they can
;   be used.
; - Added status bar to replace tooltip-feedback.
; - Removed obsolete internal switch (ToolTipFilename).
; - Replaced the use of "dir" command with AutoHotkey's
;   own "Loop" command for scanning directory contents.
;   "dir" cannot handle extended character set and thus
;   non-English (e.g German) directory and filename are
;   captured wrongly. (Thanks Wolfgang Bujatti and
;   Sietse Fliege for testing this modification)
; - Added internal switch (ScanMode) to define whether
;   files and/or directories are to be included in scan.
; - Replaced hardcoded directory paths of Start Menu with
;   built-in variables A_StartMenu, A_StartMenuCommon.
;   With this, Seek now works for different locales with
;   different naming convention of the Start Menu.
;   (Thanks Wolfgang Bujatti and Sietse Fliege for help
;   in testing another method before these new variables
;   are available.)
; - Added the pre-selection of the last-run program
;   record so that a quick double-<ENTER> will run it.
;
;*****************************************************************

;**************************
;<--- BEGIN OF PROGRAM --->
;**************************

;==== Your Customisation ===================================

; Specify which program to use when opening a directory.
; If the program cannot be found or is not specified
; (i.e. variable is unassigned or assigned a null value),
; the default Explorer will be used.
dirExplorer = E:\utl\xplorer2_lite\xplorer2.exe

; User's customised list of additional directories to be
; included in the scanning. The full path must not be
; enclosed by quotes or double-quotes. If this file is
; missing, only the default directories will be scanned.
SeekMyDir = %A_ScriptDir%\Seek.dir

; Specify the filename and directory location to save
; the cached directory/program listing. There is no
; need to change this unless you want to.
dirListing = %A_Temp%\_Seek.list

; Specify the filename and directory location to save
; the cached key word/phrase of last search. There is
; no need to change this unless you want to.
keyPhrase = %A_Temp%\_Seek.key

; Track search string (ON/OFF)
; If ON, the last-used query string will be re-used as
; the default query string the next time you run Seek.
; If OFF, the last-used query string will not be tracked
; and there will not be a default query string value the
; next time you run Seek.
TrackKeyPhrase = ON

; Specify what should be included in scan.
; 0: Directories are excluded (only files).
; 1: All files and directories are included.
; 2: Only directories are included (no files).
ScanMode = 1

;...........................................................

; INIT
;#NoTrayIcon
StringCaseSense, Off
version = Seek v2.0.3

; DISPLAY HELP INSTRUCTIONS
If 1 in --help,-help,/h,-h,/?,-?
{
    MsgBox,, %version%, Navigating the Start Menu can be a hassle, especially if you have installed many programs over time. 'Seek' 能让您指定不区分大小写的关键词/短语, 用它从开始菜单里筛选出匹配的程序和目录, 以便您可以轻松地从少数匹配的项目中打开目标程序. This eliminates the drudgery of searching and traversing the Start Menu.`n`nI have a lot of fun coding this, and hope you will enjoy using it too. Feel free to drop me an email with your comments and feedback at: phi1618 (*a.t*) gmail :D0T: com.`n`nOptions:`n  -cache`tUse the cached directory-listing if available (this is the default mode when no option is specified)`n  -scan`tForce a directory scan to retrieve the latest directory listing`n  -scex`tScan & exit (this is useful for scheduling the potentially time-consuming directory-scanning as a background job)`n  -help`tShow this help
    Goto QuitNoSave
}

; CHECK THAT THE MANDATORY ENVIRONMENT VARIABLES EXIST AND ARE VALID
; *TMP*
IfNotExist, %A_Temp% ; PATH DOES NOT EXIST
{
    MsgBox This mandatory environment variable is either not defined or invalid:`n`n    TMP = %A_Temp%`n`nPlease fix it before running Seek.
    Goto QuitNoSave
}

; IF NOT SCAN-AND-EXIT
IfNotEqual 1, -scex
{
    ; RETRIEVE THE LAST USED KEY-PHRASE FROM CACHE FILE
    ; TO BE USED AS THE DEFAULT QUERY STRING
    If TrackKeyPhrase = ON
    {
        FileReadLine, PrevKeyPhrase, %keyPhrase%, 1
        FileReadLine, PrevOpenTarget, %keyPhrase%, 2
    }
    NewKeyPhrase = %PrevKeyPhrase%
    NewOpenTarget = %PrevOpenTarget%

    ; ADD THE TEXT BOX FOR USER TO ENTER THE QUERY STRING
    Gui, 1:Add, Edit, vFilename W600, %NewKeyPhrase%

    ; ADD MY FAV TAGLINE
    Gui, 1:Add, Text, X625 Y10, What do you seek, my friend?

    ; ADD THE STATUS BAR FOR PROVIDING FEEDBACK TO USER
    Gui, 1:Add, Text, vStatusBar X10 Y31 R1 W764

    ; ADD THE SELECTION LISTBOX FOR DISPLAYING SEARCH RESULTS
    Gui, 1:Add, ListBox, vOpenTarget gTargetSelection X10 Y53 R28 W764 HScroll Disabled, %List%

    ; ADD THESE BUTTONS, BUT DISABLE THEM FOR NOW
    Gui, 1:Add, Button, gButtonOPEN vButtonOPEN Default X10 Y446 Disabled, Open
    Gui, 1:Add, Button, gButtonOPENDIR vButtonOPENDIR X59 Y446 Disabled, Open Directory
    Gui, 1:Add, Button, gButtonSCANSTARTMENU vButtonSCANSTARTMENU X340 Y446 Disabled, Scan Start-Menu

    ; ADD THE EXIT BUTTON
    Gui, 1:Add, Button, gButtonEXIT X743 Y446, Exit

    ; POP-UP THE QUERY WINDOW
    Gui, 1:Show, Center, %version%
}

; ENABLE RE-SCANNING OF LATEST DIRECTORY LISTING
If 1 in -scan,-scex
    rescan = Y
; CHECK WHETHER THE DIRECTORY LISTING CACHE FILE ALREADY EXISTS. IF NOT, DO A RE-SCAN.
Else IfNotExist, %dirListing%
    rescan = Y

If rescan = Y ; DO A RE-SCAN
{
    ; SHOW STATUS UNLESS USER SPECIFIES SCAN-AND-EXIT OPTION
    IfNotEqual 1, -scex
        GuiControl,, StatusBar, Scanning directory listing...

    ; SCAN START-MENU AND STORE DIRECTORY/PROGRAM LISTINGS IN CACHE FILE
    Gosub ScanStartMenu

    ; QUIT IF USER SPECIFIES SCAN-AND-EXIT OPTION
    IfEqual 1, -scex, Goto, QuitNoSave
}

GuiControl,, StatusBar, Retrieving last query result...

; RETRIEVE THE MATCHING LIST FOR THE LAST USED KEY-PHRASE
Gosub SilentFindMatches

; REMOVE THE STATUS TEXT
GuiControl,, StatusBar,

; DIRECTORY LISTING IS NOW LOADED. ENABLE THE OTHER BUTTONS.
; THESE BUTTONS ARE DISABLED EARLIER BECAUSE THEY SHOULD NOT
; BE FUNCTIONAL UNTIL THIS PART OF THE SCRIPT.
GuiControl, 1:Enable, ButtonOPEN
GuiControl, 1:Enable, ButtonOPENDIR
GuiControl, 1:Enable, ButtonSCANSTARTMENU

; TURN ON INCREMENTAL SEARCH
SetTimer, tIncrementalSearch, 500

; REFRESH THE GUI
Gosub EnterQuery

Return

;***********************************************************
;                                                          *
;                 END OF MAIN PROGRAM                      *
;                                                          *
;***********************************************************

;=== BEGIN ButtonSCANSTARTMENU EVENT =======================

ButtonSCANSTARTMENU:

Gui, 1:Submit, NoHide
GuiControl,, StatusBar, Scanning directory listing...

; DISABLE LISTBOX WHILE SCANNING IS IN PROGRESS
GuiControl, 1:Disable, OpenTarget
GuiControl, 1:Disable, ButtonEXIT
GuiControl, 1:Disable, ButtonOPEN
GuiControl, 1:Disable, ButtonOPENDIR
GuiControl, 1:Disable, ButtonSCANSTARTMENU

; DO THE SCANNING
Gosub ScanStartMenu

; INFORM USER THAT SCANNING HAS COMPLETED
If Filename =
{
    ; IF QUERY STRING IS EMPTY...
    GuiControl, 1:Enable, ButtonEXIT
    GuiControl, 1:Enable, ButtonOPEN
    GuiControl, 1:Enable, ButtonSCANSTARTMENU
    GuiControl,, StatusBar, Scan completed.
    Gosub EnterQuery
}
Else
{
    ; IF QUERY STRING EXISTS...
    ; FILTER FOR SEARCH STRING WITH THE NEW LISTING
    NewKeyPhrase =
    Gosub FindMatches
}
Return

;... END ButtonSCANSTARTMENU EVENT .........................

;=== BEGIN ScanStartMenu SUBROUTINE ========================
; SCAN THE START-MENU AND STORE THE DIRECTORY/PROGRAM
; LISTINGS IN A CACHE FILE
ScanStartMenu:

; DEFINE THE DIRECTORY PATHS TO RETRIEVE.
; THE PATH MUST NOT BE ENCLOSED BY QUOTES OR DOUBLE-QUOTES.
;
; FOR ENGLISH VERSION OF WINDOWS
scanPath = %A_StartMenu%|%A_StartMenuCommon%

; INCLUDE ADDITIONAL USER-DEFINED PATHS FOR SCANNING
IfExist, %SeekMyDir%
{
    Loop, read, %SeekMyDir%
    {
        IfNotExist, %A_LoopReadLine%
            MsgBox, 8192, %version%, Processing your customised directory list...`n`n"%A_LoopReadLine%" does not exist and will be excluded from the scanning.`nPlease update [ %SeekMyDir% ].
        Else
            scanPath = %scanPath%|%A_LoopReadLine%
    }
}

; DELETE EXISTING FILE BEFORE CREATING A NEW VERSION
FileDelete, %dirListing%

; SCAN DIRECTORY LISTING (DELIMITER = |) BY RECURSING
; EACH DIRECTORY TO RETRIEVE THE CONTENTS. HIDDEN FILES
; ARE EXCLUDED.
Loop, parse, scanPath, |
{
    Loop, %A_LoopField%\*, %ScanMode%, 1
    {
        FileGetAttrib, fileAttrib, %A_LoopFileFullPath%
        IfNotInString, fileAttrib, H ; EXCLUDE HIDDEN FILE
            FileAppend, %A_LoopFileFullPath%`n, %dirListing%
    }
}

Return

;... END ScanStartMenu SUBROUTINE ..........................

;=== BEGIN FindMatches SUBROUTINE ==========================
; SEARCH AND DISPLAY ALL MATCHING RECORDS IN THE LISTBOX
FindMatches:

Gui, 1:Submit, NoHide
CurFilename = %Filename%
GuiControl,, StatusBar,

; CHECK FOR EMPTY QUERY STRING
If CurFilename =
{
    MsgBox, 8192, %version%, Please enter the key word/phrase to search for.
    Goto EnterQuery
}

; tIncrementalSearch IS BEING INTERRUPTED. LET IT FINISHES.
If NewKeyPhrase <> %CurFilename%
{
    ; INFORM USER THAT PATIENCE IS A VIRTUE
    GuiControl,, StatusBar, Seeking...
    ResumeFindMatches = TRUE
    Return
}

If List = |
{
    ; NOT EVEN A SINGLE MATCHING RECORD IS FOUND.
    ; LET USER MODIFY THE QUERY STRING AND TRY AGAIN.
    MsgBox, 8192, %version%, The query string "%CurFilename%" does not match any record. Try again.
    GuiControl, 1:Disable, ButtonOPENDIR
    GuiControl, 1:Enable, ButtonSCANSTARTMENU
    Goto EnterQuery
}
Else
{
    ; SELECT THE FIRST RECORD IF NO OTHER RECORD HAS BEEN SELECTED
    Gui, 1:Submit, NoHide
    GuiControl, 1:Enable, OpenTarget
    GuiControl, 1:Enable, ButtonOPEN
    GuiControl, 1:Enable, ButtonOPENDIR
    GuiControl, 1:Enable, ButtonSCANSTARTMENU
    GuiControl, Focus, OpenTarget
    If OpenTarget =
        GuiControl, 1:Choose, OpenTarget, |1
}

; REFRESH GUI
Gui, 1:Show, Center, %version%

Return

;... END FindMatches SUBROUTINE ............................

;=== BEGIN SilentFindMatches SUBROUTINE ====================

SilentFindMatches:

Gui, 1:Submit, NoHide
sfmFilename = %Filename%

; FILTER MATCHING RECORDS BASED ON USER QUERY STRING
List = |
If sfmFilename <>
{
    Loop, read, %dirListing%
    {
        Gui, 1:Submit, NoHide
        tFilename = %Filename%
        If sfmFilename <> %tFilename%
        {
            ; USER HAS CHANGED THE SEARCH STRING. THERE IS NO POINT
            ; TO CONTINUE SEARCHING USING THE OLD STRING, SO ABORT.
            Return
        }
        Else
        {
            ; APPEND MATCHING RECORDS INTO THE LIST
            SplitPath, A_LoopReadLine, name, dir, ext, name_no_ext, drive
            MatchFound = Y
            Loop, parse, sfmFilename, %A_Space%
            {
                IfNotInString, name, %A_LoopField%
                {
                    MatchFound = N
                    中断
                }
            }
            IfEqual, MatchFound, Y
            {
                ; ADD RECORD TO LIST
                List = %List%%A_LoopReadLine%|

                ; PRE-SELECT IF THIS MATCHES THE LAST-RUN PROGRAM
                If (A_LoopReadLine = PrevOpenTarget && sfmFilename = PrevKeyPhrase)
                    List = %List%|
            }
        }
    }
}

; REFRESH LIST WITH SEARCH RESULTS
GuiControl, 1:, OpenTarget, %List%

If List = |
{
    ; NO MATCHING RECORD IS FOUND
    ; DISABLE LISTBOX
    GuiControl, 1:Disable, OpenTarget
    GuiControl, 1:Disable, ButtonOPENDIR
}
Else
{
    ; MATCHING RECORDS ARE FOUND
    ; ENABLE LISTBOX
    GuiControl, 1:Enable, OpenTarget
    GuiControl, 1:Enable, ButtonOPENDIR
}

; REFRESH GUI
Gui, 1:Show, Center, %version%

Return

;... END SilentFindMatches SUBROUTINE ......................

;=== BEGIN EnterQuery SUBROUTINE ===========================
; REFRESH GUI AND LET USER ENTERS SEARCH STRING
EnterQuery:
GuiControl, Focus, Filename
GuiControl, 1:Enable, ButtonOPEN
Gui, 1:Show, Center, %version%
Return
;... END EnterQuery SUBROUTINE .............................

;=== BEGIN TargetSelection EVENT ===========================

TargetSelection:
Gui, 1:Submit, NoHide

; DOUBLE-CLICK DETECTION TO LAUNCH PROGRAM
If A_GuiControlEvent = DoubleClick
{
    Gosub ButtonOPEN
}
Else
{
    ; STUB - FOR FUTURE USE
    If A_GuiControlEvent = Normal
    {
        ; DO NOTHING FOR NOW
    }
}

Return

;... END TargetSelection EVENT .............................

;=== BEGIN ButtonOPEN EVENT ================================

; USER CLICKED ON 'OPEN' BUTTON OR PRESSED <ENTER>
ButtonOPEN:
Gui, 1:Submit, NoHide

; FIND OUT WHERE THE KEYBOARD FOCUS WAS. IF IT'S THE
; TEXT FIELD, RUN THE QUERY TO FIND MATCHES. ELSE, IT
; MUST BE FROM THE LISTBOX.
GuiControlGet, focusControl, 1:Focus
If focusControl = Edit1
{
    GuiControl, Focus, OpenTarget
    GuiControl, 1:Disable, OpenTarget
    GuiControl, 1:Disable, ButtonOPENDIR
    GuiControl, 1:Disable, ButtonSCANSTARTMENU
    Goto FindMatches
}

; NO RECORD FROM THE LISTBOX IS SELECTED
If OpenTarget =
{
    MsgBox, 8192, %version%, Please make a selection before hitting <Enter>.`nPress <Esc> to exit.
    Goto EnterQuery
}

; SELECTED RECORD DOES NOT EXIST (FILE OR DIRECTORY NOT FOUND)
IfNotExist, %OpenTarget%
{
    MsgBox, 8192, %version%, %OpenTarget% does not exist. This means that the directory cache is outdated. You may click on the 'Scan Start-Menu' button below to update the directory cache with your latest directory listing now.
    Goto EnterQuery
}

; CHECK WHETHER THE SELECTED RECORD IS A FILE OR DIRECTORY
FileGetAttrib, fileAttrib, %OpenTarget%
IfInString, fileAttrib, D ; IS DIRECTORY
{
    Gosub sOpenDir
}
Else If fileAttrib <> ; IS FILE
{
    Run, %OpenTarget%
}
Else
{
    MsgBox %OpenTarget% is neither a DIRECTORY or a FILE. This shouldn't happen. Seek cannot proceed. Quitting...
}

Goto Quit

;... END ButtonOPEN EVENT ..................................

;=== BEGIN ButtonOPENDIR EVENT =============================

; USER CLICKED ON 'OPEN DIRECTORY' BUTTON
ButtonOPENDIR:
Gui, 1:Submit, NoHide

; CHECK THAT USER HAS SELECTED A RECORD ALREADY
If OpenTarget =
{
    MsgBox, 8192, %version%, Please make a selection first.
    Goto EnterQuery
}

; RUN SUBROUTINE TO OPEN A DIRECTORY
Gosub sOpenDir

Goto Quit

;... END ButtonOPENDIR EVENT ...............................

;=== BEGIN sOpenDir SUBROUTINE =============================

sOpenDir:

; IF USER SELECTED A FILE-RECORD INSTEAD OF A DIRECTORY-RECORD,
; EXTRACT THE DIRECTORY PATH. (I'M USING DriveGet INSTEAD OF
; FileGetAttrib TO ALLOW THE SCENARIO WHEREBY OpenTarget IS
; INVALID BUT THE DIRECTORY PATH OF OpenTarget IS VALID.
DriveGet, status, status, %OpenTarget%
If status <> Ready ; NOT A DIRECTORY
{
    SplitPath, OpenTarget, name, dir, ext, name_no_ext, drive
    OpenTarget = %dir%
}

; CHECK WHETHER DIRECTORY EXISTS
IfNotExist, %OpenTarget%
{
    MsgBox, 8192, %version%, %OpenTarget% does not exist. This means that the directory cache is outdated. You may click on the 'Scan Start-Menu' button below to update the directory cache with your latest directory listing now.
    Goto EnterQuery
}

; OPEN THE DIRECTORY
IfExist, %dirExplorer%
{
    Run, "%dirExplorer%" "%OpenTarget%", , Max ; OPEN WITH CUSTOMISED FILE EXPLORER
}
Else
{
    Run, %OpenTarget%, , Max ; OPEN WITH DEFAULT WINDOWS FILE EXPLORER
}
Return

;... END sOpenDir SUBROUTINE ...............................

;=== BEGIN tIncrementalSearch EVENT ========================
; AUTOMATICALLY CONDUCT REAL-TIME INCREMENTAL SEARCH
; TO FIND MATCHING RECORDS WITHOUT WAITING FOR USER
; TO PRESS <ENTER>
tIncrementalSearch:

Loop
; REPEAT SEARCHING UNTIL USER HAS STOPPED CHANGING THE QUERY STRING
{
    Gui, 1:Submit, NoHide
    CurFilename = %Filename%
    If NewKeyPhrase <> %CurFilename%
    {
        OpenTarget =
        Gosub SilentFindMatches
        NewKeyPhrase = %CurFilename%
        Sleep, 100 ; DON'T HOG THE CPU!
    }
    Else
    {
        ; QUERY STRING HAS STOPPED CHANGING
        中断
    }
}

; USER HAS HIT <ENTER> TO LOOK FOR MATCHING RECORDS.
; RUN FindMatches NOW.
If ResumeFindMatches = TRUE
{
    ResumeFindMatches = FALSE
    Gosub FindMatches
}

; CONTINUE MONITORING FOR CHANGES
SetTimer, tIncrementalSearch, 500

Return

;... END tIncrementalSearch EVENT ..........................

;=== BEGIN Quit SUBROUTINE =================================

Quit:
ButtonEXIT:
GuiClose:
GuiEscape:

Gui, 1:Submit, NoHide

; SAVE THE KEY WORD/PHRASE FOR NEXT RUN IF IT HAS CHANGED
If TrackKeyPhrase = ON
{
    If (PrevKeyPhrase <> Filename || PrevOpenTarget <> OpenTarget)
    {
        FileDelete, %keyPhrase%
        FileAppend, %Filename%`n, %keyPhrase%
        FileAppend, %OpenTarget%`n, %keyPhrase%
    }
}

QuitNoSave:
ExitApp ; JOB DONE. G'DAY!

;... END Quit SUBROUTINE ...................................

;************************
;<--- END OF PROGRAM --->
;************************

; /* vim: set noexpandtab shiftwidth=4: */


鼠标菜单型的工具提示 (需要 XP/2k/NT) -- 作者: Rajat

此脚本显示弹出菜单来响应短暂地按住鼠标中键的动作. 左键点击来选择菜单项. 在菜单外点击来取消菜单. 最近的改进是可以根据活动的窗口类型来改变菜单的内容 (这里使用了记事本和 Word 作为例子).

下载此脚本 | 其他示例脚本 | 主页

; You can set any title here for the menu:
MenuTitle = -=-=-=-=-=-=-=-

; This is how long the mouse button must be held to cause the menu to appear:
UMDelay = 20

SetFormat, float, 0.0
SetBatchLines, 10ms
SetTitleMatchMode, 2
#SingleInstance

;___________________________________________
;_____Menu Definitions______________________

; Create / Edit Menu Items here.
; You can't use spaces in keys/values/section names.

; Don't worry about the order, the menu will be sorted.

MenuItems = Notepad/Calculator/Section 3/Section 4/Section 5

;___________________________________________
;______Dynamic menuitems here_______________

; Syntax:
;     Dyn# = MenuItem|Window title

Dyn1 = MS Word|- Microsoft Word
Dyn2 = Notepad II|- Notepad

;___________________________________________

Exit

;___________________________________________
;_____Menu Sections_________________________

; Create / Edit Menu Sections here.

Notepad:
Run, Notepad.exe
Return

Calculator:
Run, Calc
Return

Section3:
MsgBox, You selected 3
Return

Section4:
MsgBox, You selected 4
Return

Section5:
MsgBox, You selected 5
Return

MSWord:
msgbox, this is a dynamic entry (word)
Return

NotepadII:
msgbox, this is a dynamic entry (notepad)
Return

;___________________________________________
;_____Hotkey Section________________________

~MButton::
HowLong = 0
Loop
{
    HowLong ++
    Sleep, 10
    GetKeyState, MButton, MButton, P
    IfEqual, MButton, U, Break
}
IfLess, HowLong, %UMDelay%, Return

;prepares dynamic menu
DynMenu =
Loop
{
    IfEqual, Dyn%a_index%,, Break

    StringGetPos, ppos, dyn%a_index%, |
    StringLeft, item, dyn%a_index%, %ppos%
    ppos += 2
    StringMid, win, dyn%a_index%, %ppos%, 1000

    IfWinActive, %win%,
        DynMenu = %DynMenu%/%item%
}

;Joins sorted main menu and dynamic menu
Sort, MenuItems, D/
TempMenu = %MenuItems%%DynMenu%

;clears earlier entries
Loop
{
    IfEqual, MenuItem%a_index%,, Break
    MenuItem%a_index% =
}

;creates new entries
Loop, Parse, TempMenu, /
{
    MenuItem%a_index% = %a_loopfield%
}

;creates the menu
Menu = %MenuTitle%
Loop
{
    IfEqual, MenuItem%a_index%,, Break
    numItems ++
    StringTrimLeft, MenuText, MenuItem%a_index%, 0
    Menu = %Menu%`n%MenuText%
}

MouseGetPos, mX, mY
HotKey, ~LButton, MenuClick
HotKey, ~LButton, On
ToolTip, %Menu%, %mX%, %mY%
WinActivate, %MenuTitle%
Return

MenuClick:
HotKey, ~LButton, Off
IfWinNotActive, %MenuTitle%
{
    ToolTip
    Return
}

MouseGetPos, mX, mY
ToolTip
mY -= 3        ;space after which first line starts
mY /= 13    ;space taken by each line
IfLess, mY, 1, Return
IfGreater, mY, %numItems%, Return
StringTrimLeft, TargetSection, MenuItem%mY%, 0
StringReplace, TargetSection, TargetSection, %a_space%,, A
Gosub, %TargetSection%
Return


屏显 (OSD) 音量 -- 作者: Rajat

此脚本把您选择的热键设置为增加和降低总音量和/或波形音量. 这两种音量以不同的颜色条图形显示.

下载此脚本 | 其他示例脚本 | 主页

;_________________________________________________
;_______User Settings_____________________________

; Make customisation only in this area or hotkey area only!!

; The percentage by which to raise or lower the volume each time:
vol_Step = 4

; How long to display the volume level bar graphs:
vol_DisplayTime = 2000

; Master Volume Bar color (see the help file to use more
; precise shades):
vol_CBM = Red

; Wave Volume Bar color
vol_CBW = Blue

; Background color
vol_CW = Silver

; Bar's screen position.  Use -1 to center the bar in that dimension:
vol_PosX = -1
vol_PosY = -1
vol_Width = 150  ; width of bar
vol_Thick = 12   ; thickness of bar

; If your keyboard has multimedia buttons for Volume, you can
; try changing the below hotkeys to use them by specifying
; Volume_Up, ^Volume_Up, Volume_Down, and ^Volume_Down:
HotKey, #Up, vol_MasterUp      ; Win+UpArrow
HotKey, #Down, vol_MasterDown
HotKey, +#Up, vol_WaveUp       ; Shift+Win+UpArrow
HotKey, +#Down, vol_WaveDown

;___________________________________________
;_____Auto Execute Section__________________

; DON'T CHANGE ANYTHING HERE (unless you know what you're doing).

vol_BarOptionsMaster = 1:B ZH%vol_Thick% ZX0 ZY0 W%vol_Width% CB%vol_CBM% CW%vol_CW%
vol_BarOptionsWave   = 2:B ZH%vol_Thick% ZX0 ZY0 W%vol_Width% CB%vol_CBW% CW%vol_CW%

; If the X position has been specified, add it to the options.
; Otherwise, omit it to center the bar horizontally:
if vol_PosX >= 0
{
    vol_BarOptionsMaster = %vol_BarOptionsMaster% X%vol_PosX%
    vol_BarOptionsWave   = %vol_BarOptionsWave% X%vol_PosX%
}

; If the Y position has been specified, add it to the options.
; Otherwise, omit it to have it calculated later:
if vol_PosY >= 0
{
    vol_BarOptionsMaster = %vol_BarOptionsMaster% Y%vol_PosY%
    vol_PosY_wave = %vol_PosY%
    vol_PosY_wave += %vol_Thick%
    vol_BarOptionsWave = %vol_BarOptionsWave% Y%vol_PosY_wave%
}

#SingleInstance
SetBatchLines, 10ms
Return

;___________________________________________

vol_WaveUp:
SoundSet, +%vol_Step%, Wave
Gosub, vol_ShowBars
return

vol_WaveDown:
SoundSet, -%vol_Step%, Wave
Gosub, vol_ShowBars
return

vol_MasterUp:
SoundSet, +%vol_Step%
Gosub, vol_ShowBars
return

vol_MasterDown:
SoundSet, -%vol_Step%
Gosub, vol_ShowBars
return

vol_ShowBars:
; To prevent the "flashing" effect, only create the bar window if it
; doesn't already exist:
IfWinNotExist, vol_Wave
    Progress, %vol_BarOptionsWave%, , , vol_Wave
IfWinNotExist, vol_Master
{
    ; Calculate position here in case screen resolution changes while
    ; the script is running:
    if vol_PosY < 0
    {
        ; Create the Wave bar just above the Master bar:
        WinGetPos, , vol_Wave_Posy, , , vol_Wave
        vol_Wave_Posy -= %vol_Thick%
        Progress, %vol_BarOptionsMaster% Y%vol_Wave_Posy%, , , vol_Master
    }
    else
        Progress, %vol_BarOptionsMaster%, , , vol_Master
}
; Get both volumes in case the user or an external program changed them:
SoundGet, vol_Master, Master
SoundGet, vol_Wave, Wave
Progress, 1:%vol_Master%
Progress, 2:%vol_Wave%
SetTimer, vol_BarOff, %vol_DisplayTime%
return

vol_BarOff:
SetTimer, vol_BarOff, off
Progress, 1:Off
Progress, 2:Off
return


窗口遮蔽 (卷起窗口到标题栏) -- by Rajat

此脚本通过单个热键实现裁减窗口到它的标题栏, 再次使用热键后恢复为原始大小. 这种方式可以裁减任意数目的窗口 (脚本会记住每个窗口原来的大小). 如果脚本由于任何原因退出了, 那么所有 "卷起" 的窗口会自动恢复为它们原来的高度.

下载此脚本 | 其他示例脚本 | 主页

; Set the height of a rolled up window here.  The operating system
; probably won't allow the title bar to be hidden regardless of
; how low this number is:
ws_MinHeight = 25

; This line will unroll any rolled up windows if the script exits
; for any reason:
OnExit, ExitSub
return  ; End of auto-execute section

#z::  ; Change this line to pick a different hotkey.
; Below this point, no changes should be made unless you want to
; alter the script's basic functionality.
; Uncomment this next line if this subroutine is to be converted
; into a custom menu item rather than a hotkey.  The delay allows
; the active window that was deactivated by the displayed menu to
; become active again:
;Sleep, 200
WinGet, ws_ID, ID, A
Loop, Parse, ws_IDList, |
{
    IfEqual, A_LoopField, %ws_ID%
    {
        ; Match found, so this window should be restored (unrolled):
        StringTrimRight, ws_Height, ws_Window%ws_ID%, 0
        WinMove, ahk_id %ws_ID%,,,,, %ws_Height%
        StringReplace, ws_IDList, ws_IDList, |%ws_ID%
        return
    }
}
WinGetPos,,,, ws_Height, A
ws_Window%ws_ID% = %ws_Height%
WinMove, ahk_id %ws_ID%,,,,, %ws_MinHeight%
ws_IDList = %ws_IDList%|%ws_ID%
return

ExitSub:
Loop, Parse, ws_IDList, |
{
    if A_LoopField =  ; First field in list is normally blank.
        continue      ; So skip it.
    StringTrimRight, ws_Height, ws_Window%A_LoopField%, 0
    WinMove, ahk_id %A_LoopField%,,,,, %ws_Height%
}
ExitApp  ; Must do this for the OnExit subroutine to actually Exit the script.


WinLIRC 客户端

每当您在遥控器上按下按钮时此脚本会接收到来自 WinLIRC 的通知. 它可以用来自动操作 Winamp, Windows Media Player, 等等. 它配置起来很简单. For example, if WinLIRC recognizes a button named "VolUp" on your remote control, create a label named VolUp and beneath it use the command SoundSet +5 to increase the soundcard's volume by 5%.

下载此脚本 | 其他示例脚本 | 主页

; Here are the steps to use this script:
; 1) Configure WinLIRC to recognize your remote control and its buttons.
;    WinLIRC is at http://winlirc.sourceforge.net
; 2) Edit the WinLIRC path, address, and port in the CONFIG section below.
; 3) Launch this script. It will start the WinLIRC server if needed.
; 4) Press some buttons on your remote control. A small window will
;    appear showing the name of each button as you press it.
; 5) Configure your buttons to send keystrokes and mouse clicks to
;    windows such as Winamp, Media Player, etc. See the examples below.

; This script requires AutoHotkey 1.0.38.04 or later.
; HISTORY OF CHANGES
; March 2, 2007:
; - Improved reliability via "Critical" in ReceiveData().
; October 5, 2005:
; - Eliminated Winsock warning dialog "10054" upon system shutdown/logoff.
; - Added option "DelayBetweenButtonRepeats" to throttle the repeat speed.

; -------------------------------------------------
; CONFIGURATION SECTION: Set your preferences here.
; -------------------------------------------------
; Some remote controls repeat the signal rapidly while you're holding down
; a button. This makes it difficult to get the remote to send only a single
; signal. The following setting solves this by ignoring repeated signals
; until the specified time has passed. 200 is often a good setting.  Set it
; to 0 to disable this feature.
DelayBetweenButtonRepeats = 200

; Specify the path to WinLIRC, such as C:\WinLIRC\winlirc.exe
WinLIRC_Path = %A_ProgramFiles%\WinLIRC\winlirc.exe

; Specify WinLIRC's address and port. The most common are 127.0.0.1 (localhost) and 8765.
WinLIRC_Address = 127.0.0.1
WinLIRC_Port = 8765

; Do not change the following two lines. Skip them and continue below.
Gosub WinLIRC_Init
return

; --------------------------------------------
; ASSIGN ACTIONS TO THE BUTTONS ON YOUR REMOTE
; --------------------------------------------
; Configure your remote control's buttons below. Use WinLIRC's names
; for the buttons, which can be seen in your WinLIRC config file
; (.cf file) -- or you can press any button on your remote and the
; script will briefly display the button's name in a small window.
;
; Below are some examples. Feel free to revise or delete them to suit
; your preferences.

VolUp:
SoundSet +5  ; Increase master volume by 5%. On Vista, replace this line with: Send {Volume_Up}
return

VolDown:
SoundSet -5  ; Reduce master volume by 5%. On Vista, replace this line with: Send {Volume_Down}
return

ChUp:
WinGetClass, ActiveClass, A
if ActiveClass in Winamp v1.x,Winamp PE  ; Winamp is active.
    Send {right}  ; Send a right-arrow keystroke.
else  ; Some other type of window is active.
    Send {WheelUp}  ; Rotate the mouse wheel up by one notch.
return

ChDown:
WinGetClass, ActiveClass, A
if ActiveClass in Winamp v1.x,Winamp PE  ; Winamp is active.
    Send {left}  ; Send a left-arrow keystroke.
else  ; Some other type of window is active.
    Send {WheelDown}  ; Rotate the mouse wheel down by one notch.
return

Menu:
IfWinExist, Untitled - Notepad
{
    WinActivate
}
else
{
    Run, Notepad
    WinWait, Untitled - Notepad
    WinActivate
}
Send Here are some keystrokes sent to Notepad.{Enter}
return

; The examples above give a feel for how to accomplish common tasks.
; To learn the basics of AutoHotkey, check out the Quick-start Tutorial
; at http://www.autohotkey.com/docs/Tutorial.htm

; ----------------------------
; END OF CONFIGURATION SECTION
; ----------------------------
; Do not make changes below this point unless you want to change the core
; functionality of the script.

WinLIRC_Init:
OnExit, ExitSub  ; For connection cleanup purposes.

; Launch WinLIRC if it isn't already running:
Process, Exist, winlirc.exe
if not ErrorLevel  ; No PID for WinLIRC was found.
{
    IfNotExist, %WinLIRC_Path%
    {
        MsgBox The file "%WinLIRC_Path%" does not exist. Please edit this script to specify its location.
        ExitApp
    }
    Run %WinLIRC_Path%
    Sleep 200  ; Give WinLIRC a little time to initialize (probably never needed, just for peace of mind).
}

; Connect to WinLIRC (or any type of server for that matter):
socket := ConnectToAddress(WinLIRC_Address, WinLIRC_Port)
if socket = -1  ; Connection failed (it already displayed the reason).
    ExitApp

; Find this script's main window:
Process, Exist  ; This sets ErrorLevel to this script's PID (it's done this way to support compiled scripts).
DetectHiddenWindows On
ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel)
DetectHiddenWindows Off

; When the OS notifies the script that there is incoming data waiting to be received,
; the following causes a function to be launched to read the data:
NotificationMsg = 0x5555  ; An arbitrary message number, but should be greater than 0x1000.
OnMessage(NotificationMsg, "ReceiveData")

; Set up the connection to notify this script via message whenever new data has arrived.
; This avoids the need to poll the connection and thus cuts down on resource usage.
FD_READ = 1     ; Received when data is available to be read.
FD_CLOSE = 32   ; Received when connection has been closed.
if DllCall("Ws2_32\WSAAsyncSelect", "UInt", socket, "UInt", ScriptMainWindowId, "UInt", NotificationMsg, "Int", FD_READ|FD_CLOSE)
{
    MsgBox % "WSAAsyncSelect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
    ExitApp
}
return

ConnectToAddress(IPAddress, Port)
; This can connect to most types of TCP servers, not just WinLIRC.
; Returns -1 (INVALID_SOCKET) upon failure or the socket ID upon success.
{
    VarSetCapacity(wsaData, 400)
    result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData) ; Request Winsock 2.0 (0x0002)
    ; Since WSAStartup() will likely be the first Winsock function called by this script,
    ; check ErrorLevel to see if the OS has Winsock 2.0 available:
    if ErrorLevel
    {
        MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
        return -1
    }
    if result  ; Non-zero, which means it failed (most Winsock functions return 0 upon success).
    {
        MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }

    AF_INET = 2
    SOCK_STREAM = 1
    IPPROTO_TCP = 6
    socket := DllCall("Ws2_32\socket", "Int", AF_INET, "Int", SOCK_STREAM, "Int", IPPROTO_TCP)
    if socket = -1
    {
        MsgBox % "socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }

    ; Prepare for connection:
    SizeOfSocketAddress = 16
    VarSetCapacity(SocketAddress, SizeOfSocketAddress)
    InsertInteger(2, SocketAddress, 0, AF_INET)   ; sin_family
    InsertInteger(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2)   ; sin_port
    InsertInteger(DllCall("Ws2_32\inet_addr", "AStr", IPAddress), SocketAddress, 4, 4)   ; sin_addr.s_addr

    ; Attempt connection:
    if DllCall("Ws2_32\connect", "UInt", socket, "UInt", &SocketAddress, "Int", SizeOfSocketAddress)
    {
        MsgBox % "connect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError") . ". Is WinLIRC running?"
        return -1
    }
    return socket  ; Indicate success by returning a valid socket ID rather than -1.
}

ReceiveData(wParam, lParam)
; By means of OnMessage(), this function has been set up to be called automatically whenever new data
; arrives on the connection.  It reads the data from WinLIRC and takes appropriate action depending
; on the contents.
{
    Critical  ; Prevents another of the same message from being discarded due to thread-already-running.
    socket := wParam
    ReceivedDataSize = 4096  ; Large in case a lot of data gets buffered due to delay in processing previous data.

    VarSetCapacity(ReceivedData, ReceivedDataSize, 0)  ; 0 for last param terminates string for use with recv().
    ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", socket, "Str", ReceivedData, "Int", ReceivedDataSize, "Int", 0)
    if ReceivedDataLength = 0  ; The connection was gracefully closed, probably due to exiting WinLIRC.
        ExitApp  ; The OnExit routine will call WSACleanup() for us.
    if ReceivedDataLength = -1
    {
        WinsockError := DllCall("Ws2_32\WSAGetLastError")
        if WinsockError = 10035  ; WSAEWOULDBLOCK, which means "no more data to be read".
            return 1
        if WinsockError <> 10054 ; WSAECONNRESET, which happens when WinLIRC closes via system shutdown/logoff.
            ; Since it's an unexpected error, report it.  Also exit to avoid infinite loop.
            MsgBox % "recv() indicated Winsock error " . WinsockError
        ExitApp  ; The OnExit routine will call WSACleanup() for us.
    }
    ; Otherwise, process the data received. Testing shows that it's possible to get more than one line
    ; at a time (even for explicitly-sent IR signals), which the following method handles properly.
    ; Data received from WinLIRC looks like the following example (see the WinLIRC docs for details):
    ; 0000000000eab154 00 NameOfButton NameOfRemote
    Loop, parse, ReceivedData, `n, `r
    {
        if A_LoopField in ,BEGIN,SIGHUP,END  ; Ignore blank lines and WinLIRC's start-up messages.
            continue
        ButtonName =  ; Init to blank in case there are less than 3 fields found below.
        Loop, parse, A_LoopField, %A_Space%  ; Extract the button name, which is the third field.
            if A_Index = 3
                ButtonName := A_LoopField
        global DelayBetweenButtonRepeats  ; Declare globals to make them available to this function.
        static PrevButtonName, PrevButtonTime, RepeatCount  ; These variables remember their values between calls.
        if (ButtonName != PrevButtonName || A_TickCount - PrevButtonTime > DelayBetweenButtonRepeats)
        {
            if IsLabel(ButtonName)  ; There is a subroutine associated with this button.
                Gosub %ButtonName%  ; Launch the subroutine.
            else ; Since there is no associated subroutine, briefly display which button was pressed.
            {
                if (ButtonName == PrevButtonName)
                    RepeatCount += 1
                else
                    RepeatCount = 1
                SplashTextOn, 150, 20, Button from WinLIRC, %ButtonName% (%RepeatCount%)
                SetTimer, SplashOff, 3000  ; This allows more signals to be processed while displaying the window.
            }
            PrevButtonName := ButtonName
            PrevButtonTime := A_TickCount
        }
    }
    return 1  ; Tell the program that no further processing of this message is needed.
}

SplashOff:
SplashTextOff
SetTimer, SplashOff, Off
return

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; The caller must ensure that pDest has sufficient capacity.  To preserve any existing contents in pDest,
; only pSize number of bytes starting at pOffset are altered in it.
{
    Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
        DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}

ExitSub:  ; This subroutine is called automatically when the script exits for any reason.
; MSDN: "Any sockets open when WSACleanup is called are reset and automatically
; deallocated as if closesocket was called."
DllCall("Ws2_32\WSACleanup")
ExitApp