快速参考 | AutoHotkey v2

版本 2.0.19

https://www.autohotkey.com

© 2014 Steve Gray, Chris Mallett, 部分属于 © AutoIt 团队和其他人

软件许可: GNU General Public License

快速参考

新手入门:

  • 如何使用程序
  • 指南:
    • 如何运行示例代码
    • 如何编写热键
    • 如何发送击键
    • 如何运行程序
    • 如何管理窗口
    • 初学者向导
  • 支持 AutoHotkey 的文本编辑器
  • 常见问题(FAQ)

脚本:

  • 概念和约定: 解释你需要知道的各种事情.
  • 脚本语言: 如何编写脚本.
  • 杂项主题
  • 内置函数列表
  • 变量和表达式
  • 如何使用函数
  • 对象
  • 交互调试

键盘和鼠标:

  • 热键(鼠标, 控制器和键盘快捷键)
  • 热字串和自动替换
  • 重映射按键和鼠标按钮
  • 按键, 鼠标和控制器控制按钮的列表

其他:

  • DllCall
  • 正则表达式快速参考

致谢

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

最后, AutoHotkey 离开了这些人也不会有今天.

~ Chris Mallett


调试客户端 | AutoHotkey v2

调试客户端

通过 DBGp 可以支持调试功能, DGBp 是一种常见的支持多语言和调试器 UI 通信的调试器协议. 请参阅交互式调试了解更多细节. 在这个页面中列出了一些与 AutoHotkey 兼容的 UI 或 "客户端":

  • SciTE4AutoHotkey
  • XDebugClient
  • 基于脚本的客户端
  • 命令行客户端
  • 其他

SciTE4AutoHotkey

SciTE4AutoHotkey 是一个免费的基于 SciTE 的 AutoHotkey 脚本编辑器. 除了 DBGp 支持, 它还为 AutoHotkey 提供了语法高亮, 调用提示, 参数信息和自动完成, 以及其他拥有的编辑特性和辅助工具.

调试功能包括:

  • 断点.
  • 运行, 逐语句/逐过程/跳出.
  • 查看调用堆栈.
  • 列出局部域和全局域中变量的名称和内容.
  • 在变量上悬停时显示其内容.
  • 检查或编辑变量的内容.
  • 查看对象的结构.

https://www.autohotkey.com/scite4ahk/

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.
  • 执行到断点时, 使用调试菜单或快捷键进行单步调试或继续执行脚本.

特性:

  • 源码语法高亮只读显示.
  • 断点.
  • 运行, 逐语句/逐过程/跳出.
  • 查看调用堆栈.
  • 检查变量 - 选择变量名, 右键点击, 检查.

已知问题:

  • 当脚本运行时用户界面不响应用户的输入.
  • 没有提供列出变量或设置变量值的结构.

基于脚本的客户端

GitHub 上有一个基于脚本的 DBGp 库和示例客户端.

  • dbgp_console.ahk: 简单的命令行客户端.
  • dbgp_test.ahk: 异步调试的示例.
  • dbgp_listvars.ahk: 列出所有运行中脚本变量的示例客户端.

GitHub: Lexikos/dbgp

DebugVars 脚本提供了一种检查和改变任何运行脚本(除了已编译脚本) 的变量和对象的内容的图形用户界面. 它也可作为一个使用 dbgp.ahk 库的范本.

GitHub: Lexikos/DebugVars

命令行客户端

xdebug.org 有一个可用的命令行客户端, 但并不适合大多数用户使用因为它需要您对 DBGp 协议足够熟悉.

其他

还有一些可用的其他 DBGp 客户端, 不过没有在 AutoHotkey 测试过. 关于这些客户端的列表, 请参阅 Xdebug: 文档.


变更 & 新功能 | AutoHotkey v2

变更 & 新功能

v1.1 到 v2.0 的更改涵盖了 v1.1 和 v2.0 之间的差异.

有关更改的全部技术细节, 请参阅 GitHub.

2.0.19 - 2025 年 1 月 25 日

修复 RegEx 编译期间内存越界访问的问题.

修复 外部释放的修饰符在发送 Send 后不会被 "恢复".

修复 模态对话框抑制 InputHook 事件.

修复 在某些情况下, 重复按下键后错误地抑制键松开.

修复 加载没有 alpha 通道的大图标时的 Critical Error.

修复 如果 ClassNN 不能确定, MouseGetPos 使控件空白并不会抛出.

修复 FileSelect 的验证选项.

修复 某些情况下 Catch/Else/Finally/Until 未被标记为错误的问题.

修复 Try/Catch/Else/Finally 在如果 Else 返回时不执行 Finally.

修复 执行 if-else-if-else-if 包含胖箭头函数.

2.0.18 - 2024 年 7 月 6 日

修复 当 GetClipboardData 返回 NULL 时, A_Clipboard 静默退出的问题.

修复 a.b[c] := d, 以便 a.b 在没有 setter 的情况下调用 getter.

2.0.17 - 2024 年 6 月 5 日

优化 WinText 参数.[PR #335 (Descolada)]

变更 UnsetError 消息, 建议使用全局声明, 而不是在变量名后添加 "(与全局名称相同)".

变更 VarUnset 的警告信息, 使其与 UnsetError 一致.

修复 自增/自减操作符在 var 未设置时抛出 UnsetError, 而不是 TypeError.

修复 OwnProps 在属性删除自己的情况下安全地分配属性名称的问题.

修复 在没有块的控制流语句下的箭头函数中工作的断点.

修复 在步出函数时, 调试器在调用行中断的问题.(此行为在版本 31 中添加，并在 v1.1.30.00 中被打破.)

从作为新线程调用的函数中跳出, 现在在被中断的行中断, 而不是等到到达下一行.

修复 调试器不删除临时断点, 这些断点在计算 DBGp property_get 或 context_get 时被忽略.

2.0.16 - 2024 年 5 月 30 日

修复 在某些情况下发送到标准输出的加载时错误, 显示不正确的文件/行号.

修复 ExitApp 在加载时错误/警告对话框使用退出码 2 的问题.

修复 在当前用户(非管理员) 安装中定位 WindowSpy.ahk 的问题.

修复 DBGp property_get 分页项错误(再次).

修复 如果指定了 Length/Buffer 并且 MultiByteToWideChar 不支持目标代码页的 WC_NO_BEST_FIT_CHARS 标志时, StrPut 失败的问题.

修复 如果服务器请求客户端身份验证, Download 尝试匿名身份验证.

2.0.15 - 2024 年 5 月 16 日

修复 DBGp property_get 由于分页错误而无法检索属性的问题(自 v2.0.14 起).

修复 DBGp 属性计算导致没有 Catch 的 Try 失败的问题(自 v2.0.14 起).

修复 <base> 调试器伪属性泄漏引用的问题(自 v2.0.14 起).

2.0.14 - 2024 年 5 月 6 日

修复 错误对话框以便在文本聚焦时也能处理字母快捷键.

修复 MonthCal W-n(月份) 宽度值不受 DPI 缩放的影响.

修复 Click 不返回整数的问题.

修复 将 key::try { 检测为错误的问题.

修复 :B0*O:XY::Z 以产生 XYZ, 而非 XZ(抑制了 Y).

修复 Send 使任何先前的 {modifier Down} 即使在物理按键被按住的情况下仍然有效.

改进 在弹出菜单时脚本获取焦点的可靠性.

调试器改进:

修复 在处理另一条命令期间发送的 stdout/stderr 数据包, 以免破坏待处理的响应.

修复 property_get -n <exception>.message 及类似问题.

修复 当属性返回带有字符串的临时对象(如 x.y.z where y => {z:"a"}) 时, property_get 的结果被破坏的问题.

修复 在处理另一条命令时收到异步命令而导致崩溃的问题.

修复 通过 property_set 抑制异常后, 不被删除的问题.

修复 property_get -c 0 -d 0 允许使用全局变量, 因为 -d 1 已允许使用全局变量.

修复 property_get 无法正确分页枚举项的问题.

改进 property_get 使其支持带一个参数的属性获取器(以前只有隐式 __Item property 属性支持此功能).

改进 property_get 以支持原始值属性. 值仍必须包含在变量中或从属性中返回.

改进 property_get 允许调用 <=1 个参数的函数.

改进 property_get to 以支持浮点键/参数.

变更 调试器以抑制属性计算过程中的异常.

变更 调试器忽略由 __Enum 引发的错误(视为无项目).

变更 <enum> 伪属性使其需要 __Enum. 这可防止对象本身作为枚举器被调用.

在调试器中优化了少量代码.

2.0.13 - 2024 年 4 月 20 日

更改 热键函数, 如果选项包含无效选项则抛出 ValueError.

修复 在退格键作为撤销操作时, InputHook 遵守 +S 选项.

修复 调试器, 在枚举期间安全地处理属性删除.

修复 OLE 剪贴板内容(例如错误对话框文本) 在退出时丢失.

修复 检测热键上的无效后缀, 例如 Hotkey "a pu".

修复 DllCall AStr* arg 类型仅在地址发生变化时才复制回去.

修复 #Include 正确地 "关闭" 它读取的任何内置变量(对实际脚本没有已知影响).

修复 具有两个不同 ahk_id 值的 WinTitles 无法匹配.

2.0.12 - 2024 年 3 月 23 日

修复 当 Gui 拥有所有者窗口或 +DPIScale 属性时, Gui 的 GetPos/GetClientPos.

修复 在文件循环中, Until 阻止子文件夹递归.

修复 当参数类型为 UStr 时, DllCall 抛出错误的问题.

修复 每次正则表达式调出发生的内存泄漏.

修复 Send 由于竞争条件而错误释放修饰符的问题. 例如, 如果其他键盘钩子比脚本自己的钩子安装得更晚, ~LAlt::Send "{Blind}x" 间歇性地释放 LAlt.

修复 图标加载器在存在相同大小的多个位图时, 优先选择更高的位深度的问题.

修复 如果 SendInput 已经释放 RAlt 且键盘布局中没有 AltGr, SendInput 无法释放 LCtrl 的问题.

修复 在修饰符键改变后重复按键时, 键松开不会被触发. 例如, F1::Send "{Ctrl down}" 应该允许 F1 up:: 在键被释放时执行, 即使 Ctrl 是按下的, 但在键重复发生后不允许执行.

修复 涉及 #HotIf 的错误信息, 而不是 #IfWin. [PR #327]

修复 OwnProps 错误地跳过带有可选参数的属性.

修复 克隆动态属性的不一致行为.

  • OwnProps 不会跳过需要参数的克隆属性.
  • 参数不被递归传递给无参数属性(即允许 a.b[c] 计算为 (a.b)[c]).

修复 在网络子系统不起作用时, SysGetIPAddresses 导致的 Critical 错误; 例如在 Windows 安全模式下.

更改 在无法确定焦点时, ControlGetFocus 返回 0, 例如当控制台窗口处于活动状态时.

2.0.11 - 2023 年 12 月 23 日

新增 一个解决方案, 在 Windows 10 第一个显示的菜单不接受键盘输入.

修复 Add 方法(Gui) to 支持 DateTime 控件的 ShortDate 选项.

修复 多级函数嵌套的引用计数错误.

修复 #include <x> 在函数内部使用会导致加载时崩溃的问题.

修复 ListView.Opt("NoSort").

修复 克隆没有自有属性的对象时发生的内存泄漏.

修复 #include 和 FileInstall(未编译) 按顺序比较文件名, 而不是按语言比较文件名的问题.

2.0.10 - 2023 年 9 月 24 日

修复 在 #HotIf 之后使用命名函数热键时崩溃的问题.

修复 以点结尾的原义数字使行延续中断的问题.

修复 预增/减 能与链式数组索引配合使用.

修复 OnNotify/OnCommand 应用样式仅适用于 OnEvent.

修复 使用 emptydir\* 时, FileExist/DirExist 泄漏句柄的问题.

修复 当只有文件匹配时, DirExist 泄漏句柄的问题.

2.0.9 - 2023 年 9 月 17 日

修复 带有 X 选项的热键的堆叠.

修复 如果函数位于堆栈底部, 调试器不列出局部变量的问题.

修复 Gui 线程显示在调试器的调用堆栈.

修复 &/ByRef 的一些组合导致 ExitApp 中的堆栈溢出.

2.0.8 - 2023 年 9 月 11 日

修复 在未设置时, ByRef 参数错误地将默认值赋值给调用者的 VarRef 问题.

修复 一些影响抑制 Alt/Ctrl/Shift/Win 热键的问题, 例如:

  • *LCtrl:: 从活动窗口阻止屏蔽 LCtrl, 但是发送 Alt 键组合会失败, 因为系统认为 Ctrl 是按下的, 因此会发送 WM_KEYDOWN, 而不是 WM_SYSKEYDOWN.
  • *LAlt:: 导致系统忘记任何先前的 {LAlt DownR}, 所以 LCtrl::LAlt 这样的重映射在 LAlt 物理按下时, 会表现地不正常, 即使 LAlt 被抑制.
  • 系统对修饰符键的底层跟踪与逻辑状态不匹配的其他潜在问题.

修复 一些影响延续片段的问题:

  • Join 选项中的转义序列被转换两次, 造成 ```` 变为一个原义的 ` 而不是两个, ``n 变为一个换行符, 等等.
  • 如果延续片段采用相同类型的引号括起来并且缺少 ` 选项, `" 或 `' 将产生一个原义反引号并结束字符串, 而不是产生一个原义的引号.

优化 延续片段中引号和反引号的自动转义.

修复 breakpoint_list(调试器) 在包含胖箭头函数的行上返回重复项的问题.

修复 +BackgroundDefault 无法覆盖 Gui 的 BackColor 属性.

2.0.7 - 2023 年 9 月 2 日

修复 MouseClickDrag 允许省略 X1 和 Y1.

修复 鼠标 AltTab 热键不抑制前缀热键的执行, 如 1 & WheelDown::AltTab 中的 1:: . (Broken by v2.0.4)

修复 钩子热键不能识别 SendInput 按下的修饰符的问题.

修复 A_AhkPath 不依赖于用于启动进程的命令行的大小写/格式.

修复 在涉及组的窗口搜索期间堆损坏的问题. (Broken by v2.0.6)

Launcher

修复 如果 #Requires 后跟除 ; prefer xxx 之外的注释时, #Requires 无法检测的问题.(Broken by v2.0.6)

修复 语法检测错误解释多行自动替换热字串.

Window Spy

修改 字体为 Segoe UI 9 号字, 与 Dash 一致.

2.0.6 - 2023 年 8 月 30 日

修复 一些模糊的 COM 调用, 如 x.y 作为 x.y().

修复 断点上的控制流语句被 "hit" 时, 返回一个在它下面的行的胖箭头函数.

修复 Default : 不与它下面的行合并. 这阻止了 Default : 在 Switch 块的末尾使用, 并导致任何后续行采用 Default 的行号.

优化 ProcessGetPath, ProcessSetPriority 和 ProcessClose 在给定有效 PID 时, 不扫描所有进程, 即使对进程的访问被拒绝.

修复 LWin::Alt 无法激活某些 Alt 组合键的问题.

修复 x is y 抛出的 TypeError, 说 "Class" 而不是 "Object".

修复 WinTitle 支持超过 1023 个字符的条件.

修复 在同一变量的不同别名上使用 &ref 时的问题.

修复 可选参数默认表达式(除了简单的原义值) 阻止假设全局/假设静态的使用.

2.0.5 - 2023 年 8 月 12 日

修复 通过 COM 枚举对象时由于不正确的引用计数而导致的内存泄漏. [PR# 325]

修复 内部调用 __Enum 不调用 __Call 的问题.

修复 有关参数 #65535 的错误消息.

修复 不正确的 IEnumVARIANT 返回计数.

修复 当错误应该为非零值时, Download 抛出 OSError(0) 的问题.

修复 当传递最小参数数时, LV.Add/Insert/Modify 崩溃的问题.

修复 堆栈跟踪排除对 Error 子类的 __new 调用的问题.

2.0.4 - 2023 年 7 月 3 日

更改 错误/警告对话框上的 Reload 按钮, 显式关闭对话框, 即使当前脚本实例没有终止.

删除 对 return var 的优化, 该优化导致在 finally 块中访问该变量时显示为空白.

修复 Default(Switch) 允许冒号前的空格.

修复 在 Length 通过 unset 或 var? "显式省略", Array.Prototype.RemoveAt 返回移除值.

修复 当 ComObject 传递给 for 循环时只指定第二个变量时的崩溃.

更改 合并 v1.1.37.00 和 v1.1.37.01 的变更:

修改 COM 方法和属性调用, 将大整数作为 VT_I8, 而不是 VT_R8(浮点) 传递, 因此保留了原来的类型和精度. 32 位范围内的整数仍作为 VT_I4 传递.

新增 对带有 IDispatch 包装的 AutoHotkey 对象的双变量枚举器(for-loops) 的支持. 调用对象的脚本和对象本身都必须运行在支持的 AutoHotkey 版本.

修复 通过 IDispatch(COM) 调用 AutoHotkey 方法时, 省略的参数接收其默认值, 而不是 "可选参数标记" 的问题. 在以前的版本中, 调用 COM 方法时, 已经完成了反向转换.

修复 VerCompare(a, ">" b), 并略微减少了代码大小.

修复 AltTab-related 相关的加载时错误, 使之与其他错误一致.

修复 由 ComObject 包装器抛出的错误, 如果它是通过对象/COM 调用的, 不会被正确传播.

修复 热键 GUI 控件, 允许将符号 ^, ! 和 + 设置为热键.

修复 热键控件, 当其值被设置为一个符号时, 包括修饰符.

修复 InputHook.KeyOpt() 单字符的潜在错误行为.

  • 删除选项可能不会影响相应的 SC.
  • 选项可能也适用于 sc000.

修复 自定义组合的错误, 即如果单独用 #HotIf 禁用 a::, 一组热键如 a & b::, a:: 和 a up:: 将不能抑制 a 的释放.

修复 一个错误, 即一个键按下事件能被热键正确抑制, 但在 SendLevel > 0 的情况下, 发送一个额外的键按下, 会阻止随后的键松开被抑制, 即使由于 #InputLevel, 忽略发送的事件.

修复 a & b up:: 在 a & b:: 存在, 但被 #HotIf 禁用的情况下, 不会抑制 b 的问题.

修复 热键由于竞争状态而无法触发的问题. 如果修饰符热键(如 ~*RWin::) 太早调用 Send 或 GetKeyState, 操作系统可能会报告 RWin 没有按下, 因此修饰符的钩子的状态将被 "纠正", 热键将错误地触发或无法触发. 只有当另一个键盘钩子比脚本自己的钩子安装得更晚时才可能发生这种情况, 因为在这种情况下,操作系统不会更新按键的状态, 直到另一个钩子的线程恢复并返回..

修复 热字串使用 #HotIf 设置的最后找到的窗口.

修复 任何尝试重新安装键盘或鼠标钩子的问题, 如果操作系统已自动卸载该钩子. 在进行任何此类尝试之前, 仍有必要满足某些条件.

优化 内置 IDispatch 缓存的 COM 属性名的分配.

重构 代码以支持 AutoHotkey 作为 DLL 的构建配置.

2.0.3 - 2023 年 6 月 19 日

修复 Hotkey("a", "b") 去使用原始的函数 "b", 而不是 "a". [PR #318]

修复 在文件读取循环中使用 FileSetAttribute 时崩溃的问题. [PR #323]

修复 重复 Gui 控件名称错误, 以正确中止线程.

修复 DateTime/MonthCal 范围选项不应用最小值.

修复 s[x] => x 和其他以 "s" 开头的单行属性.

修复 在包含 => 的静态行中删除断点的错误.

修复 当点击时, Button 控件不成为默认.

修复 没有找到像素, PixelSearch 取消设置 X.

修复 带转义序列的热字串导致下一行被跳过.

修复 当 "ahk_" 在字符 2 时, WinTitle 忽略字符 1.

修复 重映射, 以利用右手修饰符已经按下. 例如, +x::+y 将不再释放 RShift 来按下 LShift.

更改 a == b && c() 和类似情况的错误消息, 以避免暗指传统的 =.

改进 某些情况下意外续行的错误信息.

修复 允许保留字作为方法名的问题, 如文档所示.

修复 一些键盘消息的重复 OnMessage 调用.

修复 过早删除互引用闭包的问题.

修复 SetFont 允许在 Options 参数中使用前导空格的问题.

修复 {ASC nnnn} 的发送.

修复 a.base := a 抛出错误的问题.

修复 x.y := unset 导致崩溃或未定义的行为.

修复 GuiControl.Move() 相对于 GUI 的客户端区域的问题，即使 GUI 不是它的父界面.

修复 Menu Add 覆盖由 Menu Insert 附加的项目.

Launcher

在没有参数的情况下运行, 运行 Dash, 而不是在文档中显示旧的欢迎页面.

修复 版本选择 GUI 在未选择版本的情况下按 Enter 键时引发错误的问题. [PR UX/#4]

检查版本不存在是否可以下载时, 抑制错误.

修复 如果 UAC 被禁用, 没有版本下载提示, 不显示 UAC 屏蔽的问题.

修复 #Requires 解释的问题.

  • 支持省略 "v" 前缀.
  • 支持运算符(> >= < <= =).
  • 版本号支持单独的数字.
Installation

修复 命令行使用的默认安装目录.

重命名 开始菜单快捷方式 "AutoHotkey" 为 "AutoHotkey Dash".

修复 当以 SYSTEM 运行时的 EnableUIAccess.

修复 在选择证书时验证私钥的 EnableUIAccess.

Dash

修复 启动配置 GUI 更新 "以管理员身份运行" 和 "以UI访问运行" 选项.

修复 启动配置 GUI 中的 Up/Down 键的处理.

2.0.2 - 2023 年 1 月 2 日

修复 短 DllCall 参数类型和无效类型的未定义行为.

修复 AutoHotkey 二进制文件的(非字符串) 版本号.

修复 参数类型错误以显示正确的参数编号.

2.0.1 - 2023 年 1 月 1 日

修复 Func.IsOptional(1) 在某些情况下, 错误的返回 0 的问题.

修复 当 Gui 是自己的事件接收器时, Gui 事件处理函数不删除 Gui 参数.

修复 当没有可用的描述时, COM 错误不显示 "(null)".

修复 ToolTip 间歇性出现在错误的位置.

修复 __Enum(unset) 允许数组, 匹配和 Gui 的第二个变量.

修复 #include <> 错误消息显示 "Script library" 而不是 "Function library" 的问题.

修复 带有 Critical 的新线程无法阻止消息检查的问题.

优化 DllCall 类型名称的转换.

优化 代码.

预发布

有关 v2.0.0 版本之前的更改历史, 请参阅以下内容(但注意一些更改已被取代):

  • v2.0 候选版本
  • v2.0-beta 版本
  • v2.0-alpha 版本


二进制兼容性 | AutoHotkey v2

二进制兼容性

本文档包含一些主题, 这些主题在处理外部库或向控件或窗口发送消息时有时很重要.

  • Unicode vs ANSI
    • Buffer
    • DllCall
    • NumPut / NumGet
  • 指针大小

Unicode 与 ANSI

注意: 本节建立在文档其他部分中涉及的主题之上: 字符串, 字符编码.

在一个字符串(文本值) 中, 每个字符的数字编码和大小(字节) 取决于字符串的编码. 这些细节通常对做以下事情的脚本很重要:

  • 通过 DllCall 传递字符串到外部函数.
  • 通过 PostMessage 或 SendMessage 传递字符串.
  • 通过 NumPut/NumGet 直接操作字符串.
  • 分配 Buffer 来容纳特定数量的字符.

AutoHotkey v2 原生使用 Unicode(UTF-16), 但一些外部库或窗口信息可能需要 ANSI 字符串.

ANSI: 每个字符占用一个字节(8 位). 大于 127 的字符编码取决于系统的语言设置(或在对文本进行编码时选择的编码页, 例如, 当它被写入文件时).

Unicode: 每个字符占用两个字节(16 位). 字符编码是由 UTF-16 格式定义的.

语义注: 技术上, 一些 Unicode 字符表示为 两个 16 位代码单元, 一起被称为 "代理项对". 同样地, 一些 ANSI 代码页(通常称为双字节字符集, 例如 cp936 中的汉字) 含有一些双字节字符. 然而, 由于特殊的原因它们几乎都被视为两个单独的单元(为了简化而称为 "字符").

Buffer

在分配 Buffer 时, 要注意为所需的任何编码计算正确的 字节 数. 例如:

ansi_buf  := Buffer(capacity_in_chars)
utf16_buf := Buffer(capacity_in_chars * 2)

如果使用 StrPut 将 ANSI 或 UTF-8 字符串写入缓冲, 不要使用 StrLen 来确定缓冲的大小, 因为 ANSI 或 UTF-8 的长度可能与原生(UTF-16) 长度不同. 相反, 使用 StrPut 来计算所需的缓冲大小. 例如:

required_bytes := StrPut(source_string, "cp0")
ansi_buf := Buffer(required_bytes)
StrPut(source_string, ansi_buf)

DllCall

使用 "Str" 类型时, 表示字符串使用当前版本原生的编码格式. 由于一些函数可能需要或返回特殊格式的字符串, 所以有时还需要使用下列的字符串格式:

 | 字符大小 | C / Win32 类型 | 编码
WStr | 16-位 | wchar_t*, WCHAR*, LPWSTR, LPCWSTR | UTF-16
AStr | 8-位 | char*, CHAR*, LPSTR, LPCSTR | ANSI(系统默认 ANSI 代码页)
Str | -- | TCHAR*, LPTSTR, LPCTSTR | 等同于 AutoHotkey v2 中的 WStr.

如果 "Str" 或 "WStr" 被用于一个参数, 字符串的地址被传递给函数. 对于 "AStr", 会创建一个字符串的临时 ANSI 拷贝, 并传递其地址. 一般来说, "AStr" 不应该用于输出参数, 因为缓冲区的大小只够容纳输入的字符串.

注意: "AStr" 和 "WStr" 对于参数和函数的返回值同样是有效的.

一般来说, 如果脚本通过 DllCall 调用一个接受字符串参数的函数, 必须采取以下一种或多种方法:

  1. 如果函数的 Unicode(W) 和 ANSI(A) 版本都可用, 省略 W 或 A 的后缀, 对输入参数或返回值使用 "Str" 类型. 例如, DeleteFile 函数从 kernel32.dll 导出为 DeleteFileA 和 DeleteFileW. 由于 DeleteFile 本身并不真正存在, DllCall 自动尝试 DeleteFileW:
    DllCall("DeleteFile", "Ptr", StrPtr(filename))
DllCall("DeleteFile", "Str", filename)

    在这两种情况下, 原始的未修改的字符串的地址被传递给函数.

    在某些情况下, 这种方法可能会适得其反, 因为 DllCall 只有在找不到原名称的函数时才会添加 W 后缀. 例如, shell32.dll 导出的 ExtractIconExW, ExtractIconExA 和 ExtractIconEx 都没有后缀, 最后两个是等价的. 在这种情况下, 省略 W 的后缀会导致 ANSI 版本被调用.

  2. 如果函数仅接受特定类型的字符串作为输入, 那么脚本可能需要使用相应的字符串类型:
    DllCall("DeleteFileA", "AStr", filename)
DllCall("DeleteFileW", "WStr", filename)
  3. 如果函数有一个用于输出的字符串参数, 脚本必须如上 所述分配一个缓冲并将其传递给函数. 如果该参数接受输入, 脚本还必须将输入的字符串转换为适当的格式; 为此可以使用 StrPut.

NumPut / NumGet

当使用 NumPut 或 NumGet 操作字符串时, 对于给定类型的字符串其偏移和类型都必须正确. 可以参考下面的代码:

;  8 位/ANSI   字符串:  size_of_char=1  type_of_char="UChar"
; 16 位/UTF-16 字符串:  size_of_char=2  type_of_char="UShort"
nth_char := NumGet(buffer_or_address, (n-1)*size_of_char, type_of_char)
NumPut(type_of_char, nth_char, buffer_or_address, (n-1)*size_of_char)

对于第一个字符, n 的值应为 1.

指针大小

指针在 32 位版本中是 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;
*/
pi := Buffer(A_PtrSize*2 + 8) ; Ptr + Ptr + UInt + UInt
DllCall("CreateProcess", <为简短而省略>, "Ptr", &pi, <省略>)
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")


概念和约定 | AutoHotkey v2

概念和约定

本文档涵盖了 AutoHotkey 所使用的一些通用概念和约定, 重点放在解释而不是代码上. 不会假定读者之前具备任何脚本或编程的知识, 但应该做好学习新术语的准备.

有关语法的更多具体细节, 请参阅脚本语言.

目录

  • 值
    • 字符串
    • 数字
    • 布尔值
    • 空值
    • 对象
    • 对象协议
  • 变量
    • 未初始化变量
    • 内置变量
    • 变量引用(VarRef)
    • 环境变量
    • 缓存
  • 函数
    • 方法
  • 控制流
  • 细节
    • 字符编码
    • 纯数字
    • 名称
    • 对象引用

值

值 只是程序中的一条信息. 例如, 要发送的键名或要运行的程序名, 热键被按下的次数, 要激活的窗口的标题, 或在程序或脚本中具有某种意义的其他任何内容.

AutoHotkey 支持这些类型的值:

  • 字符串(文本)
  • 数字(整数和浮点数)
  • 对象

Type 函数可用于确定值的类型.

其他一些相关的概念:

  • 布尔值
  • 空值

字符串

字符串 只是文本. 每个字符串实际上是一个由字符组成的序列或 字符串, 但可以视为单个实体. 字符串的 长度 是序列中字符的数量, 而字符串中字符的 位置 只是该字符的序号. 按 AutoHotkey 中的约定, 第一个字符的位置为 1.

数字字符串: 当数学运算或比较需要时, 数字字符串(或任何其他受支持的数字格式) 自动解释为数字.

脚本中如何书写原义文本, 取决于上下文. 例如, 在表达式中, 字符串必须括在双引号中. 在指令(除了 #HotIf) 和自动替换热字串中, 不需要双引号.

有关字符串如何工作的更详细说明, 请参阅字符编码.

数字

AutoHotkey 支持这些数字格式:

  • 十进制整数, 如 123, 00123 或 -1.
  • 十六进制整数, 如 0x7B, 0x007B 或 -0x1.
  • 十进制浮点数, 如 3.14159.

除非本文档注明, 十六进制数字必须使用 0x 或 0X 前缀. 这个前缀必须写在 + 或 - 号之后(如果存在), 并且在前导零之前. 例如, 0x001 有效, 但 000x1 无效.

带小数点的数字总是被认为是浮点数, 即使小数部分是零. 例如, 42 和 42.0 通常可以互换, 但并非总是如此. 科学记数法也是认可的(例如 1.0e4 和 -2.1E-4), 但总是产生浮点数(即使没有小数点).

小数点分隔符总是一个点, 即使用户的区域设置指定了一个逗号.

当数字被转换为字符串时, 它被格式化为十进制. 浮点数以全精度进行格式化(但是丢弃尾部多余的零), 这在某些情况下可能会暴露它们的不准确性. 使用 Format 函数生成不同格式的数字字符串. 浮点数也可以使用 Round 函数进行格式化.

有关数字值的范围和精度的详细信息, 请参阅纯数字.

布尔值

布尔值 可以是 true 或 false. 布尔值用于表示具有两种可能状态的任何东西, 例如表达式的 真假. 例如, 当 x 小于或等于 y 的值时, 表达式 (x <= y) 为 true. 布尔值也可以表示 yes 或 no, on 或 off, down 或 up(如 GetKeyState) 等等.

AutoHotkey 没有特定的布尔类型, 因此它使用整数值 0 表示 false, 而 1 表示 true. 当要求判断一个值的真假时, 空白或零值被认为是假, 而所有其他值被认为是真. (对象总是被视为真.)

单词 true 和 false 是值分别为 1 和 0 的内置变量. 使用它们可以增加脚本的可读性.

空值

AutoHotkey 中没有像其他语言那样有一个独特的表示 nothing, null, nil 或 undefined 的值.

任何读取没有值的变量, 属性, 数组元素或映射项的尝试都会导致抛出 UnsetError, 而不是产生 "null" 或 "undefined" 值. 这比隐式地允许空值在代码中传播更容易识别错误. 另请参阅: 未初始化变量.

函数的可选参数可以在调用时 省略, 在这种情况下, 函数可能会改变其行为或使用默认值. 参数通常通过从代码中文本省略来省略, 但也可以通过使用 unset 关键字显式或有条件地省略. 这个特殊的信号只能通过 maybe 操作符(var?) 显式地传播. 未设置的参数在函数执行前自动接收其默认值(如果有的话).

主要是由于历史原因, 空字符串有时会在其他语言中使用 null 或未定义值的地方使用, 例如没有显式返回值的函数.

如果一个变量或参数被称为 "空" 或 "空白", 这通常意味着一个空字符串(长度为零的字符串). 这与省略参数不同, 尽管在某些情况下可能会产生相同的效果.

对象

对象 是 AutoHotkey 的复合或抽象数据类型. 对象可以由任意数量的 属性(可以检索或设置) 和 方法(可以调用) 组成. 每个属性或方法的名称和效果取决于特定的对象或对象类型.

  • 对象是不能被包含的; 它们只是引用. 例如, alpha := [] 创建一个新数组并在 alpha 中存储一个引用. bravo := alpha 复制引用(不是对象) 到 bravo, 因此两者都引用同一个对象. 当一个数组或变量被认为包含一个对象时, 它实际上包含的是对该对象的引用.
  • 只有在引用同一个对象时, 两个对象引用才被视为相等的.
  • 当结果需要布尔值时, 对象总是被视为 true , 例如在 if obj, !obj 或 obj ? x : y.
  • 每个对象都有一个唯一的地址(内存中的位置), ObjPtr 函数可以检索该地址, 但通常不直接使用. 此地址唯一标识对象, 但仅在释放对象之前.
  • 在某些情况下, 当一个对象被使用在不期望对象的任何上下文中, 它可能会被当作一个空字符串. 例如, MsgBox(myObject) 显示一个空的消息框. 在其他情况下, 可能会抛出 TypeError(这应该成为未来的标准).

注意: 所有从对象派生的对象都具有额外的共享行为, 属性和方法.

对象的一些使用方法包括:

  • 包含项目或 元素 的集合. 例如, 数组包含一系列项, 而 Map 则将键与值相关联. 对象允许将一组值视为一个值, 赋值给单个变量, 传递给函数或从函数返回, 等等.
  • 表示真实或概念性的东西. 例如: 如屏幕上某个位置的 X 坐标和 Y 坐标; 通讯录中的联系人, 包括姓名, 电话号码, 电子邮件地址等. 通过将对象与其他对象组合, 对象可用于构建更复杂的信息集.
  • 封装一个或一组服务, 允许脚本的其他部分将重点放在任务上, 而不是该任务是如何执行的. 例如, File 对象提供了文件读取或写入数据的方法. 如果将信息写入文件的脚本函数接受 File 对象作为参数, 它不需要知道文件是如何打开的. 可以重复利用相同的函数将信息写入其他目标, 如 TCP/IP 套接字或 WebSocket(通过用户定义的对象).
  • 以上的组合. 例如, Gui 表示 GUI 窗口; 它向脚本提供了创建和显示图形用户界面的方法; 它包含一组控件, 并通过 Title 和 FocusedCtrl 等属性提供有关窗口的信息.

适当的使用对象(特别是类) 能产生 模块化 和 可重复使用 的代码. 模块化代码通常更容易测试, 理解和维护. 例如, 人们可以改进或修改一段代码, 而不需要知道其他段的细节, 也不必对这些段做相应的修改. 可重复使用的代码节省了时间, 避免了一遍又一遍地为相同或相似的任务编写和测试代码.

对象协议

本节以这些概念为基础, 这些概念将在后面的章节中介绍: 变量, 函数

对象通过 消息传递 的原理工作. 您不知道对象的代码或变量实际驻留在哪里, 因此您必须将消息传递给对象, 如 "give me foo" 或 "go do bar", 并依赖对象来响应消息. AutoHotkey 中的对象支持以下基本消息:

  • Get(获取) 属性.
  • Set(设置) 属性, 使用 :=.
  • Call(调用) 方法, 使用 ().

属性 只是可以设置和/或检索的对象的某个方面. 例如, 数组具有 Length 属性, 它对应于数组中元素的数量. 如果您定义了一个属性, 它可以具有您想要的任何含义. 通常属性的作用类似于一个变量, 但是它的值可以根据需要计算, 而不是实际存储在任何地方.

每条消息包含以下内容, 通常在属性或调用方法的地方编写:

  • 属性或方法的名称.
  • 零个或多个参数, 其可能会影响执行哪个操作, 值如何存储或返回哪个值. 例如, 属性可以采用数组索引或键.

例如:

myObj.methodName(arg1)
value := myObj.propertyName[arg1]

对象还可以具有 默认 属性, 当使用方括号而没有属性名时, 将调用该属性. 例如:

value := myObj[arg1]

通常, Set 与赋值有相同的含义, 所以它使用相同的运算符:

myObj.name := value
myObj.name[arg1, arg2, ..., argN] := value
myObj[arg1, arg2, ..., argN] := value

变量

一个变量允许您使用一个名称作为一个值的占位符. 在脚本运行期间, 这个值可能会重复更改. 例如, 一个热键可以使用一个变量 press_count 来计算它被按下的次数, 并且当 press_count 是 3 的倍数(每第三次按下) 时, 发送一个不同的键. 即使只有一次赋值的变量也是有用的. 例如, WebBrowserTitle 变量可用于在更改首选 Web 浏览器时, 或者由于软件更新而导致标题或窗口类发生更改时, 更容易更新代码.

在 AutoHotkey 中, 创建变量仅需要使用它们即可. 每个变量都 不是 永久性地限制在一个数据类型中, 而是可以保存任何类型的值: 字符串, 数字或对象. 试图读取一个没有分配值的变量会被视为一个错误, 所以初始化变量是很重要的.

一个变量有三个主要方面:

  • 变量的 名称.
  • 变量本身.
  • 变量的 值.

某些适用于变量名称的限制 - 请参阅名称了解详细信息. 简而言之, 坚持使用由 ASCII 字母(不区分大小写), 数字和下划线组成的名称是最安全的, 并避免使用以数字开头的名称.

变量名称具有 作用域(范围), 该范围定义了代码中的哪些位置可使用变量名称来引用该特定变量; 换句话说, 变量在哪些位置是 可见的. 如果一个变量在一个给定的范围内是不可见的, 那么在该给定的范围内相同的名称可以引用不同的变量. 两个变量可能同时存在, 但只有一个对脚本的每个部分是可见的. 全局变量在 "全局范围"(即函数之外) 中是可见的, 并可被函数默认读取, 但如果要在函数中给它们赋值, 则必须声明. 局部变量只在创建它们的函数内部可见.

一个变量可以被认为是一个值的容器或存储位置, 所以你会经常发现文档引用变量的值作为 变量的内容. 对于变量 x := 42, 我们也可以说变量 x 的值是 42, 或者 x 的值是 42.

值得注意的是, 一个变量和它的值是不一样的. 例如, 我们可以说 "myArray 是一个数组", 但是我们真正的意思是 myArray 是一个包含对数组的引用的变量. 我们通过使用变量的名称来引用其值, 但是 "myArray" 实际上只是变量的名称; 数组对象不知道它有一个名称, 并且可以被许多不同的变量引用(因此有很多的名称).

未初始化变量

初始化 变量就是给它分配一个起始值. 一个尚未分配值的变量是 未初始化变量(或简写为 unset). 试图读取一个未初始化的变量被视为一个错误. 这有助于检测错误, 例如拼写错误的名称和忘记的赋值.

IsSet 可用于确定一个变量是否已经初始化, 例如在首次使用时初始化一个全局或静态变量.

通过将直接赋值(:=) 与 unset 关键字或 maybe(var?) 运算符联合使用, 可以 un-set(取消设置) 变量. 例如: Var := unset, Var1 := (Var2?).

当变量缺少值时, or-maybe 运算符(??) 可用于提供默认值. 例如, MyVar ?? "Default" 等同于 IsSet(MyVar) ? MyVar : "Default".

内置变量

程序中内置了许多有用的变量, 可以通过任何脚本来引用. 除特殊说明外, 这些变量是只读的; 也就是说, 他们的内容不能被脚本直接改变. 按照惯例, 这些变量中的大部分以前缀 A_ 开头, 所以最好避免使用这个前缀作为你自己的变量.

某些变量如 A_KeyDelay 和 A_TitleMatchMode 代表控制脚本行为的设置, 并为每个线程保留不同的值. 这允许由新线程(如热键, 菜单, 计时器等) 启动的子例程在不影响其他线程的情况下更改设置.

一些特殊的变量不是周期性地更新, 而是脚本引用变量时检索或计算它们的值. 例如, A_Clipboard 以文本形式检索剪贴板的当前内容, A_TimeSinceThisHotkey 计算自热键被按下以来经过的毫秒数.

相关: 内置变量列表.

环境变量

环境变量由操作系统维护. 在命令提示符中输入 SET 并回车后, 您可以看到环境变量列表.

脚本中可以使用 EnvSet 创建新的环境变量或改变现有环境变量的内容. 系统的其他部分不会看到这种添加和改变. 但是, 通过调用 Run 或 RunWait 启动的任何程序或脚本会继承其父脚本的环境变量的副本.

要检索环境变量, 请使用 EnvGet. 例如:

Path := EnvGet("PATH")

变量引用(VarRef)

在一个表达式中, 每个变量引用都会自动解析为它的内容, 除非它是赋值或引用运算符(&) 的目标. 换句话说, 调用 myFunction(myVar) 将把 myVar 的值传递给 myFunction, 而不是变量本身. 然后, 函数将拥有自己的局部变量(参数), 其值与 myVar 相同, 但不能给 myVar 赋新值. 简而言之, 参数是 按值 来传递的.

引用操作符(&) 允许像处理值一样处理变量. &myVar 产生一个 VarRef, 它可以像其他值一样使用: 赋值给其他变量或属性, 插入数组, 传递给函数或从函数中返回等等. VarRef 可以用来赋值给原始的目标变量, 或者通过解引用来检索它的值.

为了方便起见, 函数参数可以通过在参数名前加上引用符(&) 来声明为 ByRef(按引用). 这需要调用者传递一个 VarRef, 并允许函数本身通过仅引用参数(不带百分号) 来 "解引用" VarRef.

class VarRef extends Any

VarRef 类目前还没有预定义的方法或属性, 但 value is VarRef 可以用来测试一个值是否是 VarRef.

当一个 VarRef 被用作 COM 方法的参数时, 对象本身不会被传递. 取而代之的是, 它的值被复制到一个临时的 VARIANT, 它使用变体类型 VT_BYREF|VT_VARIANT 来传递. 当方法返回时, 新的值被分配给 VarRef.

缓存

尽管变量通常被认为是持有单个值, 而该值具有不同的类型(字符串, 数字或对象), 但在 "Value is " myNumber 和 MsgBox myNumber 等情况下, AutoHotkey 会自动在数字和字符串之间进行转换. 由于这些转换非常频繁, 所以每当将包含数字的变量转换为字符串时, 其结果都会 缓存 在该变量中.

目前, AutoHotkey v2 仅在为变量赋值纯数字时缓存纯数字, 而不是在读取它时缓存. 这保留了区分字符串和纯数字的能力(例如使用 Type 函数, 或者在向 COM 对象传递值时).

相关

  • 变量: 基本用法和示例.
  • 变量的容量和内存占用: 有关限制的详细信息.

函数

函数 是脚本 执行某些操作 的基本手段.

函数可以有很多不同的目的. 一些函数可能只是执行一个简单的计算, 而另一些可以立即看到效果, 比如移动一个窗口. AutoHotkey 的优势之一就是脚本可以轻松地自动执行其他程序, 并通过简单地调用几个函数执行许多其他常见任务. 有关示例, 请参阅函数列表.

在整篇文档中, 一些常见的词汇的使用方式对于没有经验的人来说可能并不是通俗易懂的. 下面是一些与函数相关的常用单词/短语:

调用函数

调用 函数会导致程序调用, 执行或计算它. 换句话说, 函数调用 暂时将控制权从脚本转移到函数. 函数完成其目的时, 它将控制权 返回 给脚本. 换句话说, 函数调用之后的任何代码都不会执行, 直到函数完成.

但是, 有时函数可以在用户看到它的效果之前完成. 例如, Send 函数 发送 键击, 但可能会在键击到达其目的地并返回其预期效果之前返回.

参数

通常函数接受 参数, 告诉它如何操作或操作什么. 每个参数都是一个值, 如字符串或数字. 例如, WinMove 移动一个窗口, 所以它的参数告诉它要移动哪个窗口以及移动到哪里. Parameter(参数) 也可以被称为 arguments(参数). 常用的缩写包括 param 和 arg.

传递参数

参数被 传递 给函数, 这意味着函数被调用时每个参数都会指定一个值. 例如, 可以 传递 键的名称给 GetKeyState 以确定该键是否被按下.

返回值

函数 返回 一个值, 所以函数的结果通常称为 返回值. 例如, StrLen 返回字符串中的字符数. 函数也可以在变量中存储结果, 比如当有多个结果时(参阅返回值).

命令

函数调用有时被称为 命令, 例如它 命令 程序执行特定操作. (由于历史原因, 命令 可以指代调用函数的特定样式, 其中括号被省略并且丢弃返回值. 但是, 这在技术上是一个函数调用语句.)

函数通常期望参数以特定的顺序写入, 因此每个参数值的含义取决于它在逗号分隔的参数列表中的位置. 有些参数可以省略, 在这种情况下参数可以留空, 但是其后面的逗号只能在所有剩余的参数都省略的情况下才能省略. 例如, ControlSend 的语法是:

ControlSend Keys , Control, WinTitle, WinText, ExcludeTitle, ExcludeText

方括号表示所包含的参数是可选的(方括号本身不应出现在实际的代码中). 但是, 通常还必须指定目标窗口. 例如:

ControlSend "^{Home}", "Edit1", "A"  ; 正确. 指定了控件.
ControlSend "^{Home}", "A"           ; 不正确: 参数不匹配.
ControlSend "^{Home}",, "A"          ; 正确. 省略控件.

方法

方法 是与特定对象或对象类型关联的函数. 要调用方法, 必须指定对象和方法名. 方法名称不能唯一标识函数; 相反, 方法调用时会发生什么取决于对象. 例如, x.Show() 可能会显示菜单, 显示 GUI, 引发错误或执行其他操作, 这取决于 x 是什么. 换句话说, 方法调用只是将消息传递给对象, 指示它执行某些操作. 有关详情, 请参阅对象协议和对象运算符.

控制流

控制流 是执行单个语句的顺序. 通常, 语句从上到下依次执行, 但控制流语句可以重写这一点, 例如, 指定语句重复执行语句, 或者仅在满足某一条件时才这样做.

语句

语句 只是语言中最小的独立元素, 表示一些要执行的操作. 在 AutoHotkey 中, 语句包括赋值, 函数调用和其他表达式. 但是, 指令, 双冒号热键和热字串标签, 以及没有赋值的声明都不是语句; 当程序首次启动时, 在脚本 执行 之前, 它们将被处理.

执行

实施, 执行, 求值, 使生效, 等等. 执行 基本上与非编程语言有相同的含义.

主体(正文)

控制流语句的 主体 是它所应用的语句或语句组. 例如, if 语句的主体仅在满足特定条件时执行.

例如, 请考虑以下简单的指令集:

  1. 打开记事本
  2. 等待记事本出现在屏幕上
  3. 输入 "Hello, world!"

我们一步一个脚印, 当一步完成时, 我们继续下一步. 同样, 程序或脚本中的控制通常从一个语句流向下一个语句. 但是如果我们想在一个现有的记事本窗口中输入呢? 考虑一下这套经过修改的指令:

  1. 如果(If) 记事本没有运行:
    1. 打开记事本
    2. 等待记事本出现在屏幕上
  2. 否则:
    1. 激活记事本
  3. 输入 "Hello, world!"

所以我们要么打开记事本, 要么激活记事本, 取决于它是否已经在运行. #1 是 条件语句, 也被称为 if 语句; 也就是说, 只有满足条件时, 我们才执行它的 主体(正文)(#1.1 - #1.2). #2 是 else 语句; 我们只有在前一个 if 语句(#1) 的条件不满足时才执行它的主体(#2.1). 根据条件, 控制 流 有两种方式: #1(如果为真) → #1.1 → #1.2 → #3; 或 #1(如果为假) → #2 (else) → #2.1 → #3.

上面的指令可以转换成下面的代码:

if (not WinExist("ahk_class Notepad"))
{
    Run "Notepad"
    WinWait "ahk_class Notepad"
}
else
    WinActivate "ahk_class Notepad"
Send "Hello, world{!}"

在我们书写的指令代码中, 我们使用了缩进和编号来对语句进行分组. 脚本工作略有不同. 尽管缩进使得代码更容易阅读, 但在 AutoHotkey 中, 它并不影响语句的分组. 作为替代, 如上所示, 语句通过将它们括在花括号中进行分组. 这被称为一个 块.

有关语法的详细信息 - 即如何在 AutoHotkey 中编写或识别控制流程语句 - 请参阅控制流.

细节

字符编码

字符串中的每个字符都可以用一个数字表示, 名为它的 序号 或 字符编码. 例如, 值 "Abc" 将被表示如下:

A | b | c
65 | 98 | 99 | 0

编码: 字符串的 编码 定义了符号如何映射到序数, 以及序数到字节. 尽管有许多不同的编码, 但是由于所有由 AutoHotkey 支持的编码都包含 ASCII 作为子集, 所以字符编码 0 到 127 总是具有相同的含义. 例如, 'A' 的字符编码总是 65.

空终止符: 每个字符串都以 "空终止符" 结束, 换句话说, 一个序数为零的字符标志着字符串的结束. 字符串的长度可以通过空终止符的位置推断出来. 为了提高性能, AutoHotkey 有时也存储长度, 并允许在字符串的长度范围内使用空终止符.

注意: 由于依赖于空终止符, 许多内置函数和大多数表达式运算符通常不支持包含空终止符的字符串, 而是只读到第一个空字符. 但是, 支持对此类字符串的基本操作; 例如, 串联, ==, !==, Chr(0), StrLen, SubStr, 赋值, 参数值和 return.

原生编码: 尽管 AutoHotkey 提供了使用各种编码处理文本的方法, 但是内置的命令和函数--在某种程度上包括语言本身--都假定字符串值是在一个特定的编码中. 这被称为 原生 编码. 原生编码取决于 AutoHotkey 的版本:

  • AutoHotkey 的 Unicode 版本使用 UTF-16. UTF-16 字符串中最小的元素是两个字节(16 位). 序号在 0 到 65535(U+FFFF) 范围内的 Unicode 字符是由一个与序号相等的单一的 16 位编码单元来表示, 而在 65536(U+10000) 到 1114111(U+10FFFF) 范围内的字符是由 代理项对 表示的; 也就是说, 需要在 0xD800 和 0xDFFF 范围内的两个 16 位编码单元来表示一个字符. (关于代理项对的进一步解释以及对它们进行编码或解码的方法, 请自行在网上搜索.)

  • AutoHotkey 的 ANSI 版本使用系统默认的 ANSI 代码页, 这取决于系统区域设置或 "非 Unicode 程序的语言" 系统设置. ANSI 字符串的最小元素是一个字节(8 位). 但是, 某些代码页包含由多个字节序列表示的字符(这些字符总是非 ASCII 字符).

注意: AutoHotkey v2 原生使用 Unicode, 并且没有 ANSI 版本.

字符: 一般来说, 本文档的其他部分使用的术语 "字符" 表示的是字符串的最小单位; ANSI 字符串的字节和 Unicode(UTF-16) 字符串的 16 位编码单元. 出于实际的原因, 字符串的长度和字符串中的位置是通过计数这些固定大小的单位来测量的, 尽管它们可能不是完整的 Unicode 字符.

FileRead, FileAppend, FileOpen 和 File 对象提供了读写具有特定编码的文件的文本的方法.

StrGet 和 StrPut 函数可用于在原生编码和某些其他指定编码之间转换字符串. 然而, 这些通常只在与数据结构和 DllCall 数结合使用时有用. 直接传入或传出 DllCall 的字符串可以通过使用 AStr 或 WStr 参数类型转换为 ANSI 或 UTF-16.

处理 AutoHotkey ANSI 和 Unicode 版本之间差异的技术可以在 Unicode 和 ANSI 下找到.

纯数字

纯 数字或 二进制 数字是以计算机的 CPU 可以直接使用的格式(例如执行数学运算) 存储在内存中的数字. 在大多数情况下, AutoHotkey 会自动根据需要在数字字符串和纯数字之间进行转换, 很少区分这两种类型. AutoHotkey 对纯数字主要使用两种数据类型:

  • 64 位有符号整数(int64).
  • 64 位二进制浮点数(IEEE 754 国际标准的 double 或 binary64 格式).

这些数据类型影响变量, 属性, 数组/映射元素和索引, 函数参数和返回值以及表达式中运算符的临时结果的纯数值的范围和精度. 数学运算符和函数执行 64 位整数或浮点运算. 位运算符执行 64 位整数操作.

换句话说, 脚本受以下限制的影响:

  • 整数必须在 64 位有符号整数范围内; 也就是说, -9223372036854775808(-0x8000000000000000 或 -263) 到 9223372036854775807(0x7FFFFFFFFFFFFFFF 或 263-1) 的范围内. 如果表达式中的整数常量超出此范围, 则只使用较低的 64 位(值被截断). 虽然可以在字符串中包含更大的值, 但是将字符串转换为数字的尝试(例如在数学运算中使用该字符串) 都会导致类似的截断.

  • 浮点数字通常支持 15 位精度.

注意: 二进制浮点格式不能精确地表示一些小数, 因此数字四舍五入到最接近的可表示数字. 这可能会导致意外结果. 例如:

MsgBox 0.1 + 0           ; 0.10000000000000001
MsgBox 0.1 + 0.2         ; 0.30000000000000004
MsgBox 0.3 + 0           ; 0.29999999999999999
MsgBox 0.1 + 0.2 = 0.3   ; 0(不相等)

解决这个问题的一个策略是避免直接比较, 而是比较相差. 例如:

MsgBox Abs((0.1 + 0.2) - (0.3)) < 0.0000000000000001

另一种策略是在比较之前显式地应用四舍五入, 例如将其转换为字符串. 在指定精确度时, 通常有两种方法可以做到这一点, 如下所示:

MsgBox Round(0.1 + 0.2, 15) = Format("{:.15f}", 0.3)

名称

AutoHotkey 使用一组相同的规则来命名各种东西, 包括变量, 函数, 窗口组, 类, 属性和方法. 规则如下.

大小写敏感性: ASCII 字符不区分大小写. 例如, CurrentDate 等同于 currentdate. 但是, 大写的非 ASCII 字符(如 'Ä') 不 被认为等同于他们的小写字母, 不管当前用户的区域设置如何. 这有助于脚本在多个语言环境中保持一致.

最大长度: 253 个字符.

允许的字符: 字母, 数字, 下划线(_) 和非 ASCII 字符; 然而, 只有属性名称可以以数字开头.

保留单词: as, and, contains, false, in, is, IsSet, not, or, super, true, unset, super. 这些单词保留给将来使用或其他特定用途.

声明关键字和控制流语句的名称也是保留的, 主要用于检测错误. 这包括: Break, Case, Catch, Continue, Else, Finally, For, Global, Goto, If, Local, Loop, Return, Static, Switch, Throw, Try, Until, While.

允许将属性, 方法和窗口组的名称作为保留字.

对象的引用

脚本仅能通过对象的 引用 间接与对象进行交互. 创建对象时, 对象是在您不能控制的地方创建的, 并给您一个引用. 将此引用传递给函数或将其存储在变量或其他对象中会创建对 同一 对象的新引用.

例如, 如果 myObj 包含对对象的引用, yourObj := myObj 将创建一个新的对同一对象的引用. 如 myObj.ans := 42 这样的改变会同时影响 myObj.ans 和 yourObj.ans, 因为它们都指向同一个对象. 但是, myObj := Object() 只影响变量 myObj, 不影响变量 yourObj, yourObj 仍然指向原始对象.

通过简单地使用赋值将其替换为任何其他数值, 可以释放引用. 只有在所有引用都已释放后, 才会删除对象; 不能显式删除对象, 也不应该去尝试这样做. (但是, 您可以删除对象的属性, 内容或相关资源, 如数组的元素, 与 Gui 关联的窗口, Menu 对象的项目, 等等.)

ref1 := Object()  ; 创建一个对象并储存第一个引用
ref2 := ref1      ; 创建一个对同一对象的新引用
ref1 := ""        ; 释放第一个引用
ref2 := ""        ; 释放第二个引用; 对象被删除

如果难以理解的话, 可以尝试将一个对象看作出租单位. 当你租一个单位时, 你会得到一个你可以用来访问单位的钥匙. 您可以获得更多钥匙并使用它们访问同一个设备, 但是当您使用完该设备时, 您必须将所有钥匙交还给租赁代理. 通常这个单位不会被 删除, 但也许租赁代理将有你留下的任何垃圾删除掉; 就像存储在对象中的任何值在对象被删除时被释放一样.


常见问题(FAQ) | AutoHotkey v2

常见问题(FAQ)

目录

一般故障排查

  • 如果 AutoHotkey 无法安装该怎么办?
  • 如何恢复 .ahk 文件的右键菜单选项?
  • 为什么我的脚本在前一个系统运行良好却无法工作于 Windows xxx?
  • 我该如何处理用户账户控制(UAC) 导致的问题?
  • 因为脚本出错而无法启动, 我不能通过托盘图标编辑我的脚本. 我该怎么办?
  • 如何查找代码中的错误并修复呢?
  • 为什么 Run 函数不能启动我的游戏或程序?
  • 为什么脚本中的非 ASCII 字符显示或发送不正确?
  • 为什么在某些游戏中热字串, Send 和 Click 不起作用?
  • 如何在玩游戏或平时 CPU 高负荷运行时改善性能?
  • 我的杀毒软件把 AutoHotkey 或已编译的脚本归为恶意软件. 它真的是病毒吗?

常见任务

  • 我可以在哪里找到官方发行版或更旧的版本?
  • 可以在 USB 驱动器中运行 AHK 代码吗?
  • 如何获取命令行操作的输出?
  • 如何让一个脚本关闭, 暂停, 挂起或重启其他的脚本?
  • 如何在不退出脚本的情况下停止重复的动作?
  • 如何在任意编辑器中获取上下文相关的 AutoHotkey 函数帮助?
  • 如何检测一个网页何时加载完毕?
  • 如何比较或操作日期与时间?
  • 如何发送当前的日期和/或时间?
  • 如何发送文本到不活跃或隐藏的窗口?
  • 如何控制 Winamp, 即使在它未激活时?
  • 如何改变 MsgBox 的按钮名称?
  • 如何改变默认编辑器, 即通过上下文菜单或托盘图标打开的那个?
  • 如何保存我的 GUI 控件的内容?
  • 我能使用 AHK 画点什么吗?
  • 如何在窗口出现, 关闭或变成[不]活跃时执行操作?

热键, 热字串和重映射

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

一般故障排查

如果 AutoHotkey 无法安装我该怎么办?

如果无法正常安装 AutoHotkey, 请参阅如何安装 AutoHotkey 获取更多帮助.

如何恢复 .ahk 文件的右键菜单选项?

通常情况下, 如果安装了 AutoHotkey, 右键单击 AutoHotkey 脚本文件(.ahk) 应该会提供以下选项:

  • Run script(运行脚本)
  • Compile script(编译脚本)(如果安装了 Ahk2Exe)
  • Edit script(编辑脚本)
  • Run as administrator(以管理员权限运行)
  • Run with UI access(以 UI Access 运行)(如果满足前提条件)

注意: 在 Windows 11 上, 其中一些选项通常被归入一个子菜单, 可以通过选择 "显示更多选项" 来访问.

有时这些选项会被当前用户配置文件中的设置覆盖, 例如是否使用 Open With(打开方式) 更改了打开 .ahk 文件的默认程序. 可以通过删除以下注册表键来解决此问题:

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ahk\UserChoice

这可以通过应用此注册表文件, 或通过运行 AutoHotkey 安装目录中的 UX\reset-assoc.ahk 来完成.

它可能需要修复默认的注册表值, 通过重新安装 AutoHotkey 或运行 AutoHotkey 安装目录中的 UX\install.ahk 来完成.

为什么我的脚本在前一个系统运行良好却无法工作于 Windows xxx?

这个问题有许多的影响因素, 例如:

  • 我已经升级了我的电脑或系统, 现在我的脚本无法工作.
  • 当程序以管理员权限运行时, 热键或热字串不工作.
  • 系统阻止自动化操作(例如, 磁盘管理忽略 Send).

当切换操作系统时, 发生的变动也许影响了你的脚本. 例如, 你的新电脑, 可能有不同的驱动或安装了其他的软件. 如果你升级了新版本的 AutoHotkey, 确认你之前使用的是哪个版本并检查更新历史和二进制兼容性.

也请参考以下问题:

我该如何处理用户账户控制(UAC) 导致的问题?

在默认情况下, UAC 保护 "提权" 程序(程序以管理员权限运行) 不被非提权程序自动化, 因为这将允许他们绕过安全限制. 热键也将被屏蔽, 因此, 非提权程序不能监视用于提权程序的输入.

UAC 也阻止了 SendPlay 和 BlockInput 的正常工作.

常见的解决方案如下:

  • 推荐: Run with UI Access(以 UI Access 访问权限运行). 这需要 AutoHotkey 安装在 Program Files 文件中. 有几种方法可以做到这一点, 包括:
    • 在资源管理器中右键单击脚本, 并选择 Run with UI access.
    • 使用 Run 带有 UIAccess 外壳动词, 例如 Run '*UIAccess "Your script.ahk"'.
    • 使用命令行, 例如 "AutoHotkey32_UIA.exe" "Your script.ahk"(但在必要时包括完整路径).
    • 通过选中 Launch Settings GUI 中对应的选项, 将脚本设置为在默认情况下使用 UI 访问运行.
  • 以管理员权限运行脚本. 注意这样的脚本中运行的任何程序也具有管理员权限.
  • 禁用本地安全策略 "以管理员核准模式运行所有管理员(Run all administrators in Admin Approval Mode)" (不推荐).
  • 完全禁用 UAC. 不推荐这样做, 在 Windows 8 或之后的系统中会导致系统出现一些问题, 例如无法运行 Edge 和应用商店以及其安装的程序.

因为脚本出错而无法启动, 我不能通过托盘图标编辑我的脚本. 我该怎么办?

首先您必须修复您脚本中的错误才能找回 AHK 的系统托盘图标. 这将需要找到脚本, 并在编辑器中通过托盘图标以外的其他方式打开它.

如果您直接运行 AutoHotkey 的可执行文件, 则脚本的名称取决于可执行文件. 例如, 如果您正在运行 AutoHotkey32.exe, 请在同一目录下查找 AutoHotkey32.ahk. 请注意, 根据您的系统设置, ".ahk" 部分可能被隐藏, 但文件应该有一个像 [H] 的图标.

您通常可以通过右键单击脚本文件并选择 Edit Script 来编辑脚本文件. 如果这不起作用, 您可以在记事本或其他编辑器中打开该文件.

通常, 您应该在任何您喜欢的地方创建脚本文件(something.ahk), 并运行该脚本文件, 而不是直接运行 AutoHotkey.

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

如何查找代码中的错误并修复呢?

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

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

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

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

如果你想要打开的程序位于 A_WinDir "\System32" 并且你是在 64 位系统中使用 32 位的 AutoHotkey, File System Redirector 将会产生干扰. 为避免该问题, 请使用 A_WinDir "\SysNative" 代替; 这是一个仅在 64 位系统上运行的 32 位程序可见的虚拟目录.

为什么脚本中的非 ASCII 字符显示或发送不正确?

简短的回答: 将脚本保存为 UTF-8.

非 ASCII 字符由不同的二进制值来表示, 这取决于所选择的编码. 为了让这些字符被正确的解释, 您的文本编辑器和 AutoHotkey 必须在 同一个代码页. AutoHotkey v2 默认所有的脚本文件都是 UTF-8, 尽管可以通过 /CP 命令行开关来重写.

要在记事本中保存为 UTF-8 文件, 请在另存为对话框的 编码 下拉菜单中选择 UTF-8 或 带有 BOM 的 UTF-8. 请注意, Windows 10 v1903 及以后版本的记事本默认为 UTF-8(不带 BOM).

要读取缺少字节顺序标记(BOM) 的其他 UTF-8 文件, 请使用 FileEncoding "UTF-8-RAW", FileRead 的 *P65001 选项, 或 FileOpen 的第三个参数"UTF-8-RAW". -RAW 后缀可以省略, 但是在这种情况下, 任何新创建的文件都会有一个 BOM.

请注意, 使用标准 INI 函数访问 INI 文件不支持 UTF-8; 它们必须保存为 ANSI 或 UTF-16.

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

不是所有的游戏都支持 AHK 发送键击和点击或获取像素颜色.

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

  • 通过 SendPlay 函数, SendMode Play 或热字串选项 SP 来使用 SendPlay.

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

; 或

#Hotstring SP
::btw::by the way

    不推荐的: 在 Windows 11 或更新的系统中, 或者如果启用了用户账户控制(UAC) 即使以管理员权限运行脚本, SendPlay 时可能会没有任何的效果.

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

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

  • 试试 ControlSend, 在其他 Send 模式无效时它可能可以:

    ControlSend "abc",, GameTitle

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

    Send "{KEY Down}{KEY Up}"

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

    Send "{KEY down}"
Sleep 10 ; 试试不同的毫秒数.
Send "{KEY up}"

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

如果脚本中的 Hotkeys, Clicks 或 Sends 在 CPU 高负荷运行时明显比正常情况下要慢, 提高脚本程序的优先级或许会有帮助. 要提高脚本进程的优先级, 在脚本开始的部分写入下面这行语句:

ProcessSetPriority "High"

我的杀毒软件把 AutoHotkey 或已编译脚本标记为恶意软件. 它真的是病毒吗?

尽管文件被感染确实是可能的, 但多数情况下这些警报都是 误报, 这意味着防病毒程序是错误的. 一个常见的建议是将文件上传到在线服务, 例如 virustotal 或 Jotti 看看其他杀毒软件的查杀结果. 如果有疑问, 您可以将该文件发送给您的杀毒软件供应商确认. 这也可能有助于我们和其他 AutoHotkey 用户, 因为供应商可能会确认这是误报和改善他们的产品与 AutoHotkey 的兼容性.

对于已压缩的编译脚本来说, 误报可能更为常见, 例如使用 UPX(AutoHotkey 1.0 默认, AutoHotkey 1.1 中移除) 或 MPRESS(在AutoHotkey 1.1 中可选). AutoHotkey 安装时不带有压缩程序, 编译脚本时也默认不压缩.

常见任务

我可以在哪里找到官方发行版或更旧的版本?

访问 AutoHotkey 下载页面.

可以在 USB 驱动器中运行 AHK 吗?

请参阅 AutoHotkey.exe 的可移植性.

如何检索命令行操作的输出?

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

RunWait A_ComSpec ' /c dir > C:\My Temp File.txt'
VarToContainContents := FileRead("C:\My Temp File.txt")
FileDelete "C:\My Temp File.txt"

要避免使用临时文件(特别是在输出比较大时), 可以考虑使用 Run 函数示例中展示的 Shell.Exec() 方法.

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

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

DetectHiddenWindows True  ; 许脚本隐藏的主窗口能被检测到.
SetTitleMatchMode 2  ; 避免需要指定以下文件的完整路径.
WinClose "ScriptFileName.ahk - AutoHotkey"  ; 更新它为脚本的实际名称(区分大小写).

其次 suspend 或 pause 另一个脚本, 请把上面脚本的最后一行替换为下列语句中的一行:

PostMessage 0x0111, 65305,,, "ScriptFileName.ahk - AutoHotkey"  ; Suspend(挂起).
PostMessage 0x0111, 65306,,, "ScriptFileName.ahk - AutoHotkey"  ; Pause(暂停).
PostMessage 0x0111, 65303,,, "ScriptFileName.ahk - AutoHotkey"  ; Reload(重载).

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

通过按下热键来暂停或继续整个脚本, 需要给 Pause 指定热键, 如此例所示:

^!p::Pause  ; 按下 Ctrl+Alt+P 暂停脚本. 再次按下恢复.

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

#MaxThreadsPerHotkey 3
#z::  ; Win+Z 热键(可根据您的喜好改变此热键).
{
    static KeepWinZRunning := false
    if KeepWinZRunning  ; 这表明一个潜在的线程已经正在下面的循环中运行了.
    {
        KeepWinZRunning := false  ; 向那个线程的循环发出停止的信号.
        return  ; 结束此线程, 这样才可以让下面的线程恢复并得知上一行所做的更改.

}
    ; 否则:
    KeepWinZRunning := true
    Loop
    {
        ; 以下四行是您要重复的动作(可根据您的需要修改它们):
        ToolTip "Press Win-Z again to stop this from flashing."
        Sleep 1000
        ToolTip
        Sleep 1000
        ; 但请不要修改下面的内容.
        if not KeepWinZRunning  ; 用户再次按下 Win-Z 来向循环发出停止的信号.
            break  ; 跳出此循环.
    }
    KeepWinZRunning := false  ; 复位, 为下一次使用热键做准备.
}
#MaxThreadsPerHotkey 1

如何在任意编辑器中获取上下文相关的 AutoHotkey 函数帮助?

为此 Rajat 创建了这个脚本.

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

对于 Internet Explorer, 可能最可靠的方法是使用 DllCall 和 COM 正如 www.autohotkey.com/board/topic/17715- 所演示的. 此外, 获取地址栏及状态栏相关内容的方法在 www.autohotkey.com/board/topic/17714- 中被提到.

旧的, 稳定性稍差的方法:下面示例中的技术对使用 MS Internet Explorer 打开大多数网页时都有效. 类似的方法可能也适用于其他浏览器:

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

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

DateAdd 函数能对 YYYYMMDDHH24MISS 格式表示的时间字符串加上或减去一些天数, 小时, 分钟或秒. 后面的例子从指定的时间中减去 7 天:

Result := DateAdd(VarContainingTimestamp, -7, "days")

要计算两个日期或时间之间的时间量, 请参阅 DateDiff, 其中给出了一个示例. 此外, 内置变量 A_Now 包含了当前本地时间. 最后, 这里有一些内置的 日期/时间变量, 也可以使用 FormatTime 函数来创建自定义格式的日期/时间字符串.

如何发送当前的日期和/或时间?

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

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

请使用 ControlSend.

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

请参阅自动化 Winamp.

如何改变 MsgBox 的按钮名称?

这里有个例子.

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

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

如何保存我的 GUI 控件的内容?

请使用 Gui.Submit. 例如:

MyGui := Gui()
MyGui.Add("Text",, "Enter some Text and press Submit:")
MyGui.Add("Edit", "vMyEdit")
MyGui.Add("Button",, "Submit").OnEvent("Click", Submit)
MyGui.Show()

Submit(*)
{
    Saved := MyGui.Submit(false)
    MsgBox "Content of the edit control: " Saved.MyEdit
}

我能使用 AHK 画点什么吗?

请参阅 tic 写的 GDI+ 标准库. 它可以通过一些基本方法以有限的方式使用 Gui.

如何在窗口出现, 关闭或变成[不]活跃时开始一个动作?

使用 WinWait, WinWaitClose 或 WinWait[Not]Active.

这里列出了用户自己的解决办法, 例如 OnWin.ahk 和 [How to] Hook on to Shell to receive its messages.

热键, 热字串和重映射

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

有几种方法可以让脚本(或任何程序) 在每次启动 PC 时自动启动. 最简单的方法是在开始菜单的启动文件夹中放置一个脚本的快捷方式:

  1. 找到脚本文件后选中它, 接着按下 Ctrl+C.
  2. 按下 Win+R 打开运行对话框, 然后输入 shell:startup 点击确定或按下 Enter. 这将打开当前用户的启动文件夹. 要打开所有用户的启动文件夹, 输入 shell:common startup(不过, 在这种情况下, 您必须以管理员权限进行).
  3. 在文件夹窗口里右击, 点击 "粘贴快捷方式". 脚本的快捷方式现在应该在启动文件夹中了.

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

鼠标左键和右键应该可以正常设置为热键(例如, 热键 #LButton:: 为 Win+左键). 同样地, 鼠标中键和鼠标滚轮的转动应该可以正常地设置为热键, 除非鼠标驱动直接控制这些按键.

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

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

如何将 tab 和空格键定义为热键?

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

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

这在重映射页面进行了描述.

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

像下面那样使用热键的内置变量:

~Ctrl::
{
    if (ThisHotkey = A_PriorHotkey && A_TimeSincePriorHotkey < 200)
        MsgBox "double-press"
}

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

首选的方法是使用 #HotIf. 例如:

#HotIf WinActive("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 键. 可以把它设成热键吗?

You can. 这个示例脚本将 000 键设成等号键. 你可以通过使用你的代码替换 Send "=" 这行来更改这个动作.


函数 - 定义 & 使用 | AutoHotkey v2

函数

目录

  • 介绍和简单示例
  • 参数
  • ByRef 参数
  • 可选参数
    • Unset 参数
  • 返回值给调用者
  • 可变参数函数
    • 可变参数函数调用
  • 局部和全局变量
    • 局部变量
    • 全局变量
    • 静态变量
    • 更多关于局部和全局
  • 动态调用函数
  • 短路型布尔值的计算
  • 嵌套函数
    • 静态函数
    • 闭包
  • Return, Exit 及一般说明
  • 样式和命名约定
  • 使用 #Include 在多个脚本间共享函数
  • 内置函数

介绍和简单示例

函数是可以通过 调用 来执行的可重用代码块. 函数可以选择接受参数(输入) 并返回值(输出). 参考下面的简单函数, 其接受两个数字并返回它们的和:

Add(x, y)
{
    return x + y
}

上面就是一个函数的 定义, 因为它创建了一个名称为 "Add"(不区分大小写) 的函数, 并且确立了调用它时必须准确地提供两个参数(x 和 y). 要调用此函数, 把它的结果通过 := 运算符赋值给变量. 例如:

Var := Add(2, 3)  ; 数字 5 将被保存到 Var.

当然, 函数调用时也可以不保存其返回值:

Add(2, 3)
Add 2, 3  ; 如果在行的开头使用, 括号可以省略.

不过这种情况下, 函数的任何返回值都会被丢弃; 所以除非函数还有除了返回值之外的功能, 否则这次调用毫无意义.

在表达式中, 函数调用 "计算出" 函数的返回值. 可以将返回值赋给如上所示的变量, 也可以像下面一样地直接使用:

if InStr(MyVar, "fox")
    MsgBox "变量 MyVar 的内容是单词 fox."

参数

定义函数时, 函数的参数都在其名称后的括号中列出(函数名和左括号之间不能有空格). 如果函数不接受任何参数, 请把括号内留空; 例如: GetCurrentTimestamp().

已知限制:

  • 如果一个参数在函数调用中被解析为一个变量(例如 Var 或 ++Var 或 Var*=2), 它左边或右边的其他参数可能在它被传递给函数前修改这个变量. 例如, 当 Var 初始为 0 时 MyFunc(Var, Var++) 会意外地传递 1 和 0, 因为在函数调用执行之前, 第一个 Var 不会被解引用. 因为这种行为是违反常规的, 所以可能在将来的版本中改变.

ByRef 参数

从函数的角度看, 参数本质上是局部变量, 除非它们被定义为 ByRef 如下例所示:

a := 1, b := 2
Swap(&a, &b)
MsgBox a ',' b

Swap(&Left, &Right)
{
    temp := Left
    Left := Right
    Right := temp
}

在上面的例子中, 使用 & 需要调用者传递一个 VarRef, 它通常对应于调用者的一个变量. 每个参数都成为 VarRef 所代表的变量的别名. 换句话说, 参数和调用者的变量都引用内存中相同的内容. 这样使得 Swap 函数可以通过移动 Left 的内容到 Right 中来改变调用者的变量, 反之亦然.

与之相比, 如果在上面的例子中没有使用 ByRef, 那么 Left 和 Right 将是调用者变量的副本, 因此 Swap 函数不会对外部产生任何影响. 然而, 函数可以改为显式地解引用每个 VarRef. 例如:

Swap(Left, Right)
{
    temp := %Left%
    %Left% := %Right%
    %Right% := temp
}

由于 return 只能返回一个值给函数的调用者, 所以可以使用 VarRef 返回更多的结果. 这是通过函数将调用者传递进来的变量的引用(通常为空值的) 赋值实现的.

传递大字符串给函数时, 使用 ByRef 提高了性能, 并且通过避免生成字符串的副本节约了内存. 同样地, 使用 ByRef 送回长字符串给调用者通常比类似 Return HugeString 的方式执行的更好. 然而, 函数接收到的不是对字符串的引用, 而是对 变量 的引用. 未来的改进可能会取代 ByRef 在这些方面的使用.

已知限制:

  • 不能将对象的属性(如 foo.bar), A_Clipboard(剪贴板) 或任何其他内置变量构造成一个 VarRef. 所以这些不能作为 ByRef 传递给函数.
  • 如果参数是可选的, 则无法确定参数引用的变量是新创建的局部变量还是调用者提供的变量. 一种替代方法是使用非 ByRef 参数, 但传递给它一个 VarRef, 并让函数显式地解引用它或将其传递给另一个函数的 ByRef 参数(不使用 & 操作符).

可选参数

在定义函数时, 可以把它的一个或多个参数标记为可选的.

在参数后追加 := 后跟文本的数字, 加引号的/原义的字符串, 如 "fox" 或 "", 或一个表达式, 该表达式应该在每次需要初始化参数时使用其默认值. 例如, X:=[] 每次都会创建一个新的 Array(数组).

附加 ? 或 := unset 来定义一个默认未设置的参数.

下面这个函数中的 Z 参数就是一个可选参数:

Add(X, Y, Z := 0) {
    return X + Y + Z
}

当调用者传递 三个 参数给上面的函数时, Z 的默认值被忽略. 但当调用者仅传递 两个 参数时, Z 自动接受默认值 0.

可选参数不能孤立地放在参数列表的中间. 换句话说, 在首个可选参数右边的所有参数都必须定义为可选的. 然而, 调用函数时可以省略参数列表中间的可选参数, 如下所示:

MyFunc(1,, 3)
MyFunc(X, Y:=2, Z:=0) {  ; 注意: 这里的 Z 必须是可选参数.
    MsgBox X ", " Y ", " Z
}

ByRef 参数也支持默认值; 例如: MyFunc(&p1 := "") {. 每当调用者省略这样的参数时, 函数会创建一个包含默认值的局部变量; 换句话说, 此时函数的行为就与 "&" 符号不存在时一样.

Unset 参数

要将参数标记为可选而不提供默认值, 请使用关键字 unset 或 ? 后缀. 在这种情况下, 只要省略了参数, 相应的变量就没有值. 请使用 IsSet 来确定参数是否被赋值, 如下所示:

MyFunc(p?) { ; 等同于 MyFunc(p := unset)
    if IsSet(p)
        MsgBox "Caller passed " p
    else
        MsgBox "Caller did not pass anything"
}

MyFunc(42)
MyFunc

当参数值为空时, 试图读取参数值将被视为错误, 这与任何未初始化变量一样. 即使参数没有值, 也要将可选参数传递给另一个函数, 可以使用 maybe 操作符(var?). 例如:

Greet(title?) {
    MsgBox("Hello!", title?)
}

Greet "Greeting"  ; 标题是 "Greeting"
Greet             ; 标题是 A_ScriptName

返回值给调用者

如介绍中所说, 函数可以返回一个值给调用者.

MsgBox returnTest()

returnTest() {
    return 123
}

如果要从函数中返回额外的结果, 可以使用 ByRef (&):

returnByRef(&A,&B,&C)
MsgBox A "," B "," C

returnByRef(&val1, &val2, val3)
{
    val1 := "A"
    val2 := 100
    %val3% := 1.1  ; 使用 %, 因为参数中省略了 &.
    return
}

可以使用对象和数组返回多个值, 甚至是已命名的值:

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
}

可变参数函数

定义函数时, 在最后一个参数后面写一个星号(*) 来标记此函数为可变参数的, 这样让它可以接收可变数目的参数:

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.Length 能被用于确定参数的数目.

尝试使用多于其接受的参数的方式来调用非可变参数函数被认为是错误的. 要允许函数接受任意数量的参数, 而 不 创建数组来存储多余的参数, 请将 * 写入最后一个参数(没有参数名).

注意: "可变" 参数只可以出现在显式参数(形参) 列表的末尾.

可变参数函数的调用

虽然可变参数函数可以 接受 可变数目的参数, 不过在函数调用中使用相同的语法可以把数组作为参数传递给 任何 函数:

substrings := ["one", "two", "three"]
MsgBox Join("`n", substrings*)

注意:

  • 该对象可以是一个数组, 任何其他类型的可枚举对象(任何带有 __Enum 方法的对象) 或枚举器. 如果对象不是一个数组, 那么每次调用 __Enum 计数为 1, 每次调用枚举器仅使用一个参数.
  • 没有值的数组元素(如 [,2] 中的第一个元素) 相当于省略了参数; 也就是说, 如果参数是可选的, 则使用它的默认值, 否则将抛出异常.
  • 当直接调用用户定义的函数时, 对象可以通过名称与函数参数相同的属性来提供参数值. 但是, 如上所述, 对象必须是可枚举的, 但枚举器(可以是对象本身) 可以返回零项. 位置参数优先于属性, 未使用的属性将被忽略. 调用方法或内置函数时, 不支持命名参数.
  • 这样的语法还可以用于调用对象的方法或检索对象的属性; 例如, Object.Property[Params*].

已知限制:

  • 只有最右边的那个参数才可以这样展开. 例如, 支持 MyFunc(x, y*), 但不支持 MyFunc(x*, y).
  • 在星号(*) 和结束参数列表的符号之间不能存在任何的非空白字符.
  • 函数调用语句不能是可变参数的; 也就是说, 参数列表必须用小括号括起来(或者属性用方括号括起来).

局部和全局变量

局部变量

局部变量是特定于单个函数的, 只在该函数内可见. 因此, 局部变量可能与全局变量具有相同的名称, 但有不同的内容. 不同的函数也可以安全地使用相同的变量名.

当函数返回值时, 所有非静态的局部变量都自动释放(变为空), 除了绑定到闭包或 VarRef(这样的变量在闭包或 VarRef 释放时被释放) 的变量.

像 A_Clipboard 和 A_TimeIdle 这样的内置变量永远不会是局部的(它们可以从任何地方访问), 并且不能被重新声明. (这不适用于内置类, 如 Object; 它们被预定义为全局变量.)

默认情况下, 函数是假定-局部的. 在假定-局部函数内访问或创建的变量默认为局部的, 但以下情况除外:

  • 全局变量只能被函数读取, 不能被赋值或使用引用运算符(&).
  • 嵌套函数可以引用由闭合它的函数创建的局部或静态变量.

默认值也可以被覆盖, 通过使用 local 关键字来声明变量, 或者通过改变函数的模式来覆盖(如下所示).

全局变量

假定-局部函数中的任何变量引用, 如果只是读取的话, 可以解析为全局变量. 然而, 如果一个变量在赋值中使用或使用引用操作符(&), 它默认是自动局部的. 这就允许函数读取全局变量或调用全局或内置函数, 而无需在函数内部声明, 同时当被赋值的局部变量的名称与全局变量的名称重合时, 可以保护脚本免受意外的副作用. 例如:

LogToFile(TextToLog)
{
    ; LogFileName 是之前在这个函数之外的某个地方被赋予的值.
    ; FileAppend 是一个包含内置函数的预定义全局变量.
    FileAppend TextToLog "`n", LogFileName
}

否则, 如果要在函数中引用一个现有的全局变量(或者创建一个新的变量), 在使用它之前先声明这个变量为全局变量. 例如:

SetDataDir(Dir)
{
    global LogFileName
    LogFileName := Dir . "\My.log"
    global DataDir := Dir  ; 声明与赋值相结合, 如下所述.
}

假定-全局模式: 如果函数需要访问或创建大量的全局变量, 通过在函数的首行使用单词 "global", 从而假定其所有变量都是全局的(参数除外). 例如:

SetDefaults()
{
    global
    MyGlobal := 33  ; 把 33 赋值给全局变量, 必要时首先创建这个变量.
    local x, y:=0, z  ; 在这种模式中局部变量必须进行声明, 否则会假设它们为全局的.
}

静态变量

静态变量总是隐式的局部变量, 但和局部变量的区别是它们的值在多次调用期间是记住的. 例如:

LogToFile(TextToLog)
{
    static LoggedLines := 0
    LoggedLines += 1  ; 保持局部的计数(它的值在多次调用期间是记住的).
    global LogFileName
    FileAppend LoggedLines ": " TextToLog "`n", LogFileName
}

静态变量可以在声明的同一行初始化, 方法是在它后面跟 := 和任意表达式. 例如: static X:=0, Y:="fox". 静态声明的计算与 local 声明相同, 只是在静态初始化器(或组合初始化器组) 被成功计算后, 它将有效地从控制流中移除, 并且不会再执行第二次.

可以将套嵌函数声明为静态, 以阻止他们捕获外部函数的非静态局部变量.

假定-静态模式: 函数的第一行是单词 "static", 将函数定义为假定-静态模式, 假定其所有未声明变量都是静态的(参数除外). 例如:

GetFromStaticArray(WhichItemNumber)
{
    static
    static FirstCallToUs := true  ; 每个静态声明初始化仍然只运行一次.
    if FirstCallToUs  ; 在首次调用时创建静态数组, 后续的调用时不再创建.
    {
        FirstCallToUs := false
        StaticArray := []
        Loop 10
            StaticArray.Push("Value #" . A_Index)
    }
    return StaticArray[WhichItemNumber]
}

在假定-静态模式中, 任何非静态变量都必须声明为局部或全局变量(与假定-局部模式的例外情况相同.)

关于局部和全局变量的更多信息

如下面的例子所示, 通过逗号分隔, 可以在同一行声明多个变量:

global LogFileName, MaxRetries := 5
static TotalAttempts := 0, PrevResult

通过在变量后面赋值, 变量可以在声明的同一行进行初始化. 与静态变量初始化不同, 局部和全局变量的初始化在每次调用函数时都执行. 换句话说, 像 local x := 0 和写成单独的两行的效果是一样的: local x 后面跟着 x := 0. 局部和全局初始化允许使用任何赋值运算符, 但是像 global HitCount += 1 这样的复合赋值需要变量之前已经被赋值.

因为单词 local, global 和 static 都是在脚本运行时立即处理的, 所以不能使用 If 语句有条件地声明变量. 换句话说, If 或 Else 的区块内的声明无条件对声明和函数的闭括号之间的所有行生效(但声明中包含的任何初始化仍然是有条件的). 像 global Array%i% 这样的动态声明是不可能的, 因为所有对 Array1 或 Array99 这样的变量的非动态引用都已经被解析为地址了.

动态调用函数

虽然函数调用表达式通常以原义的函数名称开头, 但调用的目标可以是任何产生函数对象的表达式. 在表达式 GetKeyState("Shift") 中, GetKeyState 实际上是一个变量引用, 尽管它通常指的是一个包含内置函数的只读变量.

如果一个函数调用的目标是在脚本运行时确定的, 而不是在脚本启动前确定的, 那么这个函数调用就被称为是 动态的. 与普通函数调用的语法相同; 唯一明显的区别是, 对于非动态调用, 某些错误检查在加载时进行, 而对于动态调用, 只有在运行时才进行.

例如, MyFunc() 将调用 MyFunc 包含的函数对象 , 它可以是一个函数的实际名称, 也可以只是一个被赋值到函数的变量.

其他表达式也可以作为函数调用的目标, 包括双重解引. 例如, MyArray[1]() 将调用 MyArray 的第一个元素所包含的函数, 而 %MyVar%() 将调用变量, 其 名称 包含在 MyVar 中. 换句话说, 首先对参数列表前面的表达式进行计算, 得到函数对象, 然后调用该对象.

如果目标值不是可以被调用的类型, 则抛出 Error:

  • 如果目标值不是可以被调用的类型, 则抛出 MethodError. 任何带有 Call 方法的值都可以被调用, 所以可以使用 HasMethod(value, "Call") 或 HasMethod(value) 来避免这个错误.
  • 传递过少或太多的参数, 这通常可以直接或通过调用 HasMethod(value,, N) 来检查函数的 MinParams, MaxParams 和 IsVariadic 属性来避免, 其中 N 是将传递给函数的参数的数量.
  • 传递变量引用(VarRef) 以外的东西给 ByRef 或 OutputVar 参数, 这可以通过使用 IsByRef 方法来避免.

在调用函数之前, 函数的调用者一般应该知道每个参数的含义以及有多少个参数. 但是, 对于动态调用来说, 函数通常是为了适应函数调用而编写的, 在这种情况下, 失败的原因可能是函数定义的错误而不是参数值的错误.

短路型布尔值的计算

当在表达式中使用 AND, OR 和三元运算符时, 它们会短路以提高性能(无论当前是否存在函数调用). 短路操作是通过不计算表达式中那些不影响最终结果的部分来进行优化运算. (译者注: 只要碰到了 true 或者等价于 true 的就短路, 只要短路了就不会继续往后执行了, 碰到 false 就短路的情况也是同样.) 为了说明这个概念, 请看这个例子:

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 的右侧调用从而提高性能. 这种技术也可以用来防止一个函数在它的一个参数会被传递一个它认为不合适的值(如空字符串) 时被调用.

三元条件运算符(?:) 也通过不计算丢弃的分支来实现短路.

嵌套函数

嵌套 函数是在另一个函数中定义的函数. 例如:

outer(x) {
    inner(y) {
        MsgBox(y, x)
    }
    inner("one")
    inner("two")
}
outer("title")

嵌套函数不能在直接包含它的函数外部通过名称访问, 但是可以在该函数内部的任何地方访问, 包括在其他嵌套函数内部(有例外).

默认情况下, 嵌套函数可以访问包围它的函数中的任何静态变量, 甚至是动态变量. 但是, 如果外部函数既没有声明也没有非动态赋值, 那么嵌套函数内部的非动态赋值通常会解析为局部变量.

默认情况下, 当满足以下要求时, 嵌套函数会自动 "捕获" 外部函数的非静态局部变量:

  1. 外部(outer) 函数必须以下列至少一种方式引用这个变量:
    1. 通过用 local 声明它, 作为一个参数, 或套嵌函数.
    2. 作为赋值或引用操作符(&) 的非动态目标.
  2. 内部(inner) 函数(或嵌套在其内部的函数) 必须非动态地引用变量.

捕获了变量的嵌套函数称为 closure(闭包).

外部函数的非静态局部变量不能被动态访问, 除非它们已经被捕获.

显式声明总是优先于包围它们的函数中的局部变量. 例如, local x 声明了一个当前函数的局部变量, 与外部函数中的任何 x 无关. 外部函数中的全局声明也会影响嵌套函数, 除非被显式声明覆盖.

如果函数声明为假定-全局, 那么在该函数 之外 创建的任何局部或静态变量都不能被该函数本身或其任何嵌套函数直接访问. 相比之下, 假定静态的嵌套函数仍然可以引用外部函数中的变量, 除非函数被声明为静态.

默认情况下, 函数是假定-局部的, 其嵌套函数也是如此, 即使是假定-静态函数中的函数也是如此. 但是, 如果外部函数是假定-全局, 那么嵌套函数默认情况下表现为假定-全局, 除非它们可以引用外部函数的局部和静态变量.

每个函数定义都创建一个包含函数本身的只读变量; 也就是说, 创建一个 Func 或闭包对象. 请参阅下面的例子来了解如何使用这个方法.

静态函数

任何嵌套函数不捕获变量的都是自动静态的; 也就是说, 对外部函数的每次调用都引用同一个 Func. 关键字 static 可用于显式声明嵌套函数为静态, 在这种情况下, 外部函数的任何非静态局部变量都会被忽略. 例如:

outer() {
    x := "outer value"
    static inner() {
        x := "inner value"  ; 创建一个从局部到内部的变量
        MsgBox type(inner)  ; 显示 "Func"
    }
    inner()
    MsgBox x  ; 显示 "outer value"
}
outer()

静态函数不能引用自身函数体之外的其他嵌套函数, 除非显式声明为静态. 注意, 即使函数是假定静态的, 非静态嵌套函数在引用函数参数时也可能成为闭包.

闭包

闭包 是与 自由变量 集绑定的嵌套函数. 自由变量是 outer 函数的局部变量, 嵌套函数也使用这些局部变量. 闭包允许一个或多个嵌套函数与 outer 函数共享变量, 即使 outer 函数返回后也是如此.

要创建一个闭包, 只需定义一个引用外部函数变量的嵌套函数. 例如:

make_greeter(f)
{
    greet(subject)  ; 这是 f 的闭包.
    {
        MsgBox Format(f, subject)
    }
    return greet  ; 返回闭包.
}

g := make_greeter("Hello, {}!")
g(A_UserName)
g("World")

闭包也可以与内置函数一起使用, 如 SetTimer 或 Hotkey. 例如:

app_hotkey(keyname, app_title, app_path)
{
    activate(keyname)  ; 这是 app_title 和 app_path 的闭包.
    {
        if WinExist(app_title)
            WinActivate
        else
            Run app_path
    }
    Hotkey keyname, activate
}
; Win+N 激活或启动 Notepad.
app_hotkey "#n", "ahk_class Notepad", "notepad.exe"
; Win+W 激活或启动 WordPad.
app_hotkey "#w", "ahk_class WordPadClass", "wordpad.exe"

如果一个嵌套函数捕获了外部函数的任何非静态局部变量, 那么它就自动成为一个闭包. 对应于闭包本身的变量(如 activate) 也是一个非静态局部变量, 所以任何引用闭包的嵌套函数都是自动闭包.

对外部函数的每次调用都会创建新的闭包, 与之前的任何调用不同.

最好不要将对闭包的引用存储在外部函数的自由变量中, 因为这将创建一个循环引用, 在释放闭包之前, 必须先打破这个循环(例如通过清除变量). 然而, 闭包可以安全地通过其原始变量来引用自身和其他闭包, 而不会产生有问题的循环引用. 例如:

timertest() {
    x := "tock!"
    tick() {
        MsgBox x           ; x 使其成为闭包.
        SetTimer tick, 0   ; 使用闭包的原始变量是安全的.
        ; SetTimer t, 0    ; 捕获 t 将创建循环引用.
    }
    t := tick              ; 这是可行的, 因为上面的代码没有捕获 t.
    SetTimer t, 1000
}
timertest()

外层函数每次被调用时, 其所有的自由变量都会被分配为一个集合. 这一组自由变量与函数的所有闭包相关联. 如果闭包的原始变量（上例中的 tick) 被同一函数中的另一个闭包捕获, 它的生命周期将与集合绑定. 只有当除了原始变量中的引用外, 闭包中不存在任何引用时, 集合才会被删除. 这样, 闭包之间就可以相互引用, 而不会造成有问题的引用循环.

未被其他闭包捕获的闭包可以先于集合删除. 当闭包存在时, 集合内的所有自由变量, 包括捕获的闭包, 都不能被删除.

Return, Exit 及一般说明

如果函数内的执行流在遇到 Return 前到达了函数的闭括号, 那么函数结束并返回空值(空字符串) 给其调用者. 当函数显式省略 Return 的参数时, 也返回空值.

当函数使用 Exit 终止当前线程时, 其调用者不会接收到返回值. 例如, 这个语句 Var := Add(2, 3) 中, 如果 Add() 退出了那么 Var 会保持不变. 如果因为 Throw 或运行时错误(如 运行一个不存在的文件), 也会发生同样的事情.

要使用一个或多个空值(空字符串) 调用函数, 可以使用空的引号对, 例如: FindColor(ColorName, "").

因为调用函数不会开启新线程, 所以函数对设置(如 SendMode 和 SetTitleMatchMode) 做出的任何改变对其调用者同样有效.

在函数中使用 ListVars 时, 它会显示函数的局部变量及其内容. 这样可以帮助调试脚本.

样式和命名约定

如果给复杂函数中的特定变量加上独特的前缀, 您可能会发现它们更易于阅读和维护. 例如, 在函数的参数列表中以 "p" 或 "p_" 开头命名每个参数, 可以让它们的性质一目了然, 尤其是当函数中有大量的局部变量吸引您的注意力的时候. 类似地, 前缀 "r" 或 "r_" 可用于 ByRef 参数, 而 "s" 或 "s_" 可用于静态变量.

在定义函数时可以选择使用 One True Brace(OTB) 样式. 例如:

Add(x, y) {
    return x + y
}

使用 #Include 在多个脚本间共享函数

可以使用 #Include 指令从外部文件中加载函数.

内置函数

如果脚本定义了与内置函数同名的函数, 那么内置函数会被覆盖. 例如, 脚本会调用它自己定义的 WinExist() 函数来代替标准的那个. 然而, 这样脚本将无法调用原来的函数.

在 DLL 文件中的外部函数可以使用 DllCall() 调用.

获取所有内置函数的列表, 请参阅函数列表.


高级热键功能 | AutoHotkey v2

高级热键功能

目录

  • 常规
    • 重映射容易按到但却很少使用的按键
    • 使用任意键作为修饰符
    • 让鼠标滚轮执行 Alt-Tab
    • 使键盘成为鼠标按键
    • 让你的热键是上下文相关的
    • 定义在键入时展开的缩写
  • 游戏
    • 减少手指的磨损
    • 创建鼠标热键
    • 创建 "穿透" 热键
    • 在屏幕上自动化游戏动作
    • 使用键盘钩子
  • 相关主题

常规

重映射容易按到但却很少使用的按键

键盘上一些很容易按到的键却不经常使用. 我们要让这些键变得更有用. 例如, 如果您很少使用右 Alt 键, 那么可以让它执行常用的操作:

RAlt::MsgBox "You pressed the right ALT key."

您甚至可以在保持右 Alt 键原来的功能的同时, 把它作为其他热键的 "前缀" 键来实现上述功能. 在下面的例子中, 右 Alt 作为前缀键, 这让它自动地像平常那样修饰其他 所有 的按键. 但如果您按下并放开右 Alt 期间没有按下其他键, 那么它的热键功能(上面的例子) 会立即生效:

RAlt & j::AltTab

使用任意键作为修饰符

修饰符不再局限于 Ctrl, Alt, Shift 和 Win; 您可以使用 任意 两个按键或鼠标按钮组成自定义热键. 例如: 按住 Numpad0 且按下 Numpad1 来执行热键(Numpad0 & Numpad1::); 按住 CapsLock并按下另一个键或点击鼠标右键(CapsLock & RButton::). 此时(运行热键时), CapsLock 键的状态(大写或小写) 不会发生改变. 有关详情, 请参阅自定义组合键.

让鼠标滚轮执行 Alt-Tab

使用鼠标滚轮(或您选择的其他任意键) 完全代替 Alt-Tab. 点击滚轮来显示窗口选择菜单, 转动滚轮来浏览菜单. 当 Alt-Tab 菜单没有出现时滚轮仍保持正常的功能. 语法:

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

使键盘成为鼠标按键

让键盘按键 成为 鼠标按钮, 或当您按住某个键或鼠标按钮时持续重复某个动作. 有关示例请参阅重映射页面.

让你的热键是上下文相关的

让最容易使用的热键根据不同的窗口类型执行适合的操作. 在下面的例子中, 右 Ctrl 键会根据活动窗口是记事本还是计算器执行不同的操作:

#HotIf WinActive("ahk_class Notepad")
RControl::Send "^s"  ; 在记事本中保存当前文件.

#HotIf WinActive("Calculator")
RControl::Send "^c!{tab}^v"  ; 复制计算器的结果到之前的活动窗口.

有关详情, 请参阅 #HotIf.

定义在键入时展开的缩写

也称为热字串. 不需要经过特殊的训练或脚本编写经验. 例如, 包含下列语句的脚本执行后, 在您输入 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 资源时, 这种方法会比其他方法响应的更及时. 使用钩子还可以解除在游戏中只有某些按键才可以 "映射" 到游戏动作上的限制.

相关主题

  • 热键
  • 热字串
  • 重映射按键


热键 - 定义 & 使用 | AutoHotkey v2

热键(鼠标, 控制器和键盘快捷键)

目录

  • 介绍和简单示例
  • 热键修饰符
  • 上下文相关的热键
  • 自定义组合键
  • 其他特性
  • 鼠标滚轮热键
  • 热键技巧和备注
  • Alt-Tab 热键
  • 命名的函数热键

介绍和简单示例

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

#n::
{
    Run "notepad"
}

在上文中, 大括号的作用是为热键定义一个函数主体. 左大括号也可以与双冒号指定在同一行, 以支持 OTB(One True Brace) 样式. 然而, 如果热键只需要执行一行, 那么这一行可以列在双冒号的右边. 换句话说, 大括号是隐式的:

#n::Run "notepad"

当热键被触发时, 热键的名称作为其第一个参数传递, 参数名为 ThisHotkey(不包括尾部的冒号). 例如:

#n::MsgBox ThisHotkey  ; 报告 #n

除了少数例外, 这与内置变量 A_ThisHotkey 相似. 该参数的名称(首个参数的名称, 例如 ThisHotkey) 可以通过使用命名函数来改变.

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

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

热键修饰符

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

符号 说明
#

Win (Windows 徽标键).

包含 Win 键的热键(例如 #a) 会等待 Win 键被释放后才发送任何包含 L 键击的文本. 这样避免了这种热键中的 Send 锁定 PC. 这种行为适用于除 SendPlay(这里不需要), 盲从模式和文本模式以外的所有发送模式.

注意: 按下包含 Win 键的热键可能会导致额外的模拟击键(默认为 Ctrl 键). 请参阅 A_MenuMaskKey.
!

Alt

注意: 按下包含 Alt 键的热键可能会导致额外的模拟击键(默认为 Ctrl 键). 请参阅 A_MenuMaskKey.
^ Ctrl
+ Shift
& 和符号可以用来组合任意两个按键或鼠标按钮, 让它们成为自定义热键. 有关详情, 请参阅下文.
< 成对按键左边的那个按键. 例如 <!a 相当于 !a, 但只有使用左边的 Alt 键才可以触发.
> 成对按键右边的那个按键.
<^>!

AltGr(译者注: 美式标准键盘上没有该键). 如果您键盘布局中含 AltGr 键而非右 Alt 键, 那么这一系列符号一般可用于表示 AltGr. 例如:

<^>!m::MsgBox "你按下的是 AltGr+m."
<^<!m::MsgBox "你按下的是 LeftControl+LeftAlt+m."

或者, 让 AltGr(alternate graph 或 alternate graphic) 本身成为热键, 请使用下面的热键(不像上面出现的任何热键):

LControl & RAlt::MsgBox "你按下的是 AltGr 本身."
*

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

*#c::Run "calc.exe"  ; Win+C, Shift+Win+C, Ctrl+Win+C, 等都会触发此热键.
*ScrollLock::Run "notepad"  ; 即使在按住其他修饰键时按下 ScrollLock 也会触发此热键.

通配符热键总是使用键盘钩子, 就像任何被通配符热键覆盖的热键一样. 例如, *a:: 的存在会导致 ^a:: 总是使用钩子.
~

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

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

与其他前缀符号不同, 可以在热键的某些变体中使用颚化符(波浪号) 前缀而其他的不使用. 然而, 如果应用于颚化符(波浪号) 前缀的任何自定义组合键没有被关闭或暂停, 它会影响那个前缀键在 所有 组合中的行为.

用于替代 alt-tab 的特殊按键总是忽略颚化符(波浪号) 前缀.

如果把颚化符(前缀键) 用在自定义修饰键中且此修饰键自身也作为热键, 则在按下此修饰键时会触发热键而不会被延迟到按键释放的时候. 例如, 上文中 ~RButton 热键在按下此按键时就会触发.

如果颚化符前缀只应用于自定义组合键, 而不应用于非组合热键, 按键的原生功能将持续被屏蔽. 例如, 下面的脚本, 按住 Menu 键将会一直显示一个工具提示而不会触发上下文菜单:

AppsKey::ToolTip "Press < or > to cycle through windows."
AppsKey Up::ToolTip
~AppsKey & <::Send "!+{Esc}"
~AppsKey & >::Send "!{Esc}"

如果键盘热键的一个变体具有颚化修饰符, 那么热键总是使用键盘钩子.
$

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

$ 前缀对于鼠标热键不起作用, 因为它们始终使用鼠标钩子. 它对于已经启用了键盘钩子的热键同样无效, 包括任何带有颚化符(~) 或通配符(*) 修饰的热键, key-up 热键以及自定义组合. 要确定特定热键是否使用键盘钩子, 请使用 ListHotkeys 查看.

#InputLevel 和 SendLevel 对 Send 函数是否触发热键和热字串提供了额外的控制功能.
UP

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

*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::)

"Up" 热键和其 key-down 副本(如果有的话) 总是使用键盘钩子.

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

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."
}

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

RWin::return

上下文相关的热键

#HotIf 指令可以用来让热键根据不同的条件执行不同的动作(或什么都不做). 例如:

#HotIf WinActive("ahk_class Notepad")
^a::MsgBox "你在记事本中按下了 Ctrl-A. 而在其他窗口中按下 Ctrl-A 将原样发送."
#c::MsgBox "你在记事本中按下了 Win-C."

#HotIf
#c::MsgBox "你在非记事本程序中按下了 Win-C."

#HotIf MouseIsOver("ahk_class Shell_TrayWnd") ; 有关 MouseIsOver, 请参阅 #HotIf 的示例 1.
WheelUp::Send "{Volume_Up}"     ; 在任务栏上滚动滚轮: 增加/减小音量.
WheelDown::Send "{Volume_Down}" ;

自定义组合键

通常快捷键组合由可选的前缀/修饰键(Ctrl, Alt, Shift 和 LWin/RWin) 和单个后缀键组成. 标准的修饰键就是这样设计的, 所以按下时通常没有立即效果.

两个按键(包括鼠标, 但不包括控制器按钮) 的自定义组合热键可以通过在它们之间使用 "&" 来定义. 因为它们是为与前缀键一起使用而设计的, 所以自定义组合有以下特殊行为:

  • 除非前缀键是标准的修饰键或可切换键(如 CapsLock), 否则前缀键将失去其原来的功能.
  • 如果前缀键还用作另一个热键中的后缀, 则默认情况下, 该热键在释放时触发, 如果它用于激活自定义组合, 则根本不会触发. 如果同时有 key-down 热键和 key-up 热键, 两个热键将同时被触发. 如果波浪号前缀

注意: 对于带有标准修饰键的组合, 通常最好使用标准语法. 例如, 使用 <+s:: 而不是 LShift & s::.

在下面的例子中, 你可以按住 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 时您又按下了其他按键的情况. 可以在其中某个热键前使用颚化符(波浪号) 前缀来避免这种行为.

修饰: 与普通热键不同的是, 自定义组合在默认情况下表现得就像拥有一个通配符(*) 修饰一样. 例如, 1 & 2:: 当按下 1 和 2 时, 无论 Ctrl 或 Alt 是否被按住都会触发, 然而 ^1:: 仅在 Ctrl+1 组合键时触发, 而 Ctrl+Alt+1 不会触发.

不支持组合三个或更多的键. 一般来说组合键支持你键盘上物理存在的所有按键, 都可以用 #HotIf 和 GetKeyState 探测状态, 但是也可能出现不一致的情况. 例如:

; 以任何顺序按下 AppsKey 和 Alt, 然后按下反斜杠键(/).
#HotIf GetKeyState("AppsKey", "P")
Alt & /::MsgBox "Hotkey activated."

; 如果对调 AppsKey 和 Alt, 则必须先按下 Alt(一次按一个):
#HotIf GetKeyState("Alt", "P")
AppsKey & /::MsgBox "Hotkey activated."

; 同时按下这三个键: [ & ] & \::
#HotIf GetKeyState("[") && GetKeyState("]")
\::MsgBox

键盘钩子: 涉及键盘键的自定义的组合键总是使用键盘钩子, 使用前缀键作为后缀的任何热键也是如此. 例如, a & b:: 导致 ^a:: 总是使用键盘钩子.

其他特性

NumLock, CapsLock 和 ScrollLock: 这些键可以被强制设置为 "AlwaysOn" 或 "AlwaysOff". 例如: SetNumLockState "AlwaysOn".

覆盖资源管理器热键: 系统的内置热键(如 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 可以支持转动滚轮来激发热键. 这里是一些鼠标滚轮热键的例子:

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."

如果鼠标支持它, 可以通过键名 WheelLeft 和 WheelRight 来检测水平滚动. 有些鼠标只有一个滚轮, 可以向上或向下滚动或向左或向右倾斜. 通常, 在这些情况下, 将滚轮固定在一侧时会重复发送 WheelLeft 或 WheelRight 信号, 以模拟连续滚动. 这通常会导致热键重复执行.

内置变量 A_EventInfo 包含了滚轮转动的格数, 通常为 120. 但是, A_EventInfo 在以下情况下可以大于或小于 120:

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

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

~LControl & WheelUp::  ; 向左滚动.
{
    Loop 2  ; <-- 增加这个值来加快滚动速度.
        SendMessage 0x0114, 0, 0, ControlGetFocus("A")  ; 0x0114 是 WM_HSCROLL, 它后面的 0 是 SB_LINELEFT.
}

~LControl & WheelDown::  ; 向右滚动.
{
    Loop 2  ; <-- 增加这个值来加快滚动速度.
        SendMessage 0x0114, 1, 0, ControlGetFocus("A")  ; 0x0114 是 WM_HSCROLL, 它后面的 1 是 SB_LINERIGHT.
}

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

热键技巧和备注

根据 NumLock 的状态, 每个小键盘上的按键可以运行两个不同的热键子程序. 或者, 小键盘上的按键也可以运行相同的热键子程序, 而不管 NumLock 的状态如何. 例如:

NumpadEnd::
Numpad1::
{
    MsgBox "This hotkey is launched regardless of whether NumLock is on."
}

如果波浪号(~) 与前缀键一起使用, 即使只是一次, 它会更改所有组合键的前缀键的行为. 例如, 在下面的两个热键中, 活动窗口都会接收到右键点击, 尽管只是其中一个热键使用了波浪号:

~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 函数可以临时禁用所有的热键, 但不包括您要排除的那些. 要获得更高的选择性, 请使用 #HotIf.

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

控制器热键当前不支持修饰符前缀(如 ^(Ctrl) 和 #(Win)). 但是, 您可以使用 GetKeyState 来模拟此效果, 如下例所示:

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

热键在继续之前可能需要等待自己的修饰键被释放. 请参考下面的例子:

^!s::Send "{Delete}"

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

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

如果形如 #z:: 这样的热键产生了类似 "Invalid Hotkey(无效热键)" 的错误, 那么您的系统键盘布局/语言可能不包含指定的字符(本例中为 "Z"). 尝试使用您键盘布局中您知道存在的其他字符.

只有在函数被命名的情况下, 脚本才能明确地调用热键的函数. 请参阅命名的函数热键.

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

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

Alt-Tab 热键

Alt-Tab 热键简化了新组合键到系统 Alt-Tab 热键的映射, 它被用来调用切换任务(激活窗口) 的菜单.

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

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

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

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

ShiftAltTab: 与上面相同, 只是在菜单中向后移动.

AltTabAndMenu: 如果 alt-tab 菜单可见, 则向前移动. 否则, 显示菜单.

AltTabMenu: 显示或隐藏 alt-tab 菜单.

AltTabMenuDismiss: 关闭 Alt-tab 菜单.

为了说明上述内容, 可以用鼠标滚轮完全代替 Alt-tab. 使用下面的热键, 点击鼠标中键显示菜单, 转动滚轮在菜单中导航:

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

要取消 Alt-Tab 菜单而不激活选择的窗口, 按下或发送 Esc. 在下面的例子中, 按住左 Ctrl 并按下 CapsLock 来显示菜单并在其中向前移动. 然后释放左 Ctrl 激活所选窗口, 或按下鼠标滚轮取消. 在运行这个例子之前, 定义 AltTabWindow 窗口组, 如下所示.

LCtrl & CapsLock::AltTab
#HotIf WinExist("ahk_group AltTabWindow")  ; 表示 alt-tab 菜单出现在屏幕上.
*MButton::Send "{Blind}{Escape}"  ; * 前缀允许它被触发, 无论 Alt 是否被按住.
#HotIf

如果脚本发送 {Alt Down}(例如调用 Alt-Tab 菜单), 那么也可能需要发送 {Alt Up}, 如下面的例子所示.

一般说明

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

无论是否使用 up 关键字, alt-tab 动作都可以在 key-down 和/或 key-up 生效, 并且不能与同一键上的其他动作相结合. 例如, 同时使用 F1::AltTabMenu 和 F1 up::OtherAction() 是不支持的.

自定义的 alt-tab 动作还可以通过热键创建. 由于不同版本的操作系统对 alt-tab 菜单的标识不同, 使用如下所示的窗口组可能会有帮助. 在上面和下面例子中使用 ahk_group AltTabWindow, 这个窗口组是在脚本启动时定义的. 另外, ahk_group AltTabWindow 也可以用适合你的系统的 ahk_class 来代替.

GroupAdd "AltTabWindow", "ahk_class MultitaskingViewFrame"  ; Windows 10
GroupAdd "AltTabWindow", "ahk_class TaskSwitcherWnd"  ; Windows Vista, 7, 8.1
GroupAdd "AltTabWindow", "ahk_class #32771"  ; 更早的系统, 或启用了经典的 alt-tab

在下面的例子中, 按下 F1 来显示菜单并向前移动. 然后可以按下 F2 来激活选择的窗口, 或按下 Esc 取消:

*F1::Send "{Alt down}{tab}" ; 在这种情况下需要星号.
!F2::Send "{Alt up}"  ; 释放 Alt 键, 激活选择的窗口.
#HotIf WinExist("ahk_group AltTabWindow")
~*Esc::Send "{Alt up}"  ; 取消菜单时, 自动释放 Alt 键.
;*Esc::Send "{Esc}{Alt up}"  ; 如果不使用(~), 则需要发送 Escape 键.
#HotIf

命名的函数热键

如果需要在不触发热键本身的情况下调用热键的函数, 则可以为一个或多个热键分配一个命名的函数, 只需在热键的双冒号之后简单地定义该函数即可, 例如:

; Ctrl+Shift+O 在资源管理器中打开包含的文件夹.
; Ctrl+Shift+E 打开文件夹并选中当前编辑的文件.
; 支持 SciTE(可能需要修改标题栏的设置).
^+o::
^+e::
    editor_open_folder(hk)
    {
        path := WinGetTitle("A")
        if RegExMatch(path, "\*?\K(.*)\\[^\\]+(?= [-*] )", &path)
            if (FileExist(path[0]) && hk = "^+e")
                Run Format('explorer.exe /select,"{1}"', path[0])
            else
                Run Format('explorer.exe "{1}"', path[1])
    }

如果脚本显式调用函数 editor_open_folder, 则必须传递值给第一个参数(hk).

热字串也可以这样定义. 可以将多个热键或热字串堆叠在一起来调用同一个函数.

在热键和函数之间只能有空格或注释.

命名函数还支持自我描述热键, 就像上面的代码其中函数名称描述了热键那样.

Hotkey 函数也可以关联函数或函数对象到一个热键.


热字串 - 定义 & 使用 | AutoHotkey v2

热字串

目录

  • 介绍和简单示例
  • 终止符
  • 选项
  • 长替换
  • 上下文相关的热字串
  • 自动更正
  • 备注
  • 命名的函数热字串
  • 热字串助手

介绍和简单示例

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

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

::btw::by the way

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

上面的 "by the way" 示例被称为自动替换热字串, 因为输入的文本被自动删除并替换为第二个双冒号后指定的字符串. 与之相比, 热字串还可以定义用来执行任何自定义动作, 如下例所示. 注意, 这些语句必须出现在热字串的函数主体中缩写的 下方:

::btw::
{
    MsgBox 'You typed "btw".'
}

:*:]d::  ; 此热串通过下面的语句用当前日期和时间替换 "]d".
{
  Send FormatTime(, "M/d/yyyy h:mm tt")  ;  看起来会像 9/1/2005 3:53 PM 这样
}

在上面的例子中, 大括号用于为每个热字符串定义函数体. 左大括号也可以与双冒号在同一行上指定, 以支持 OTB(One True Brace) 样式.

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

当一个热字串被触发时, 该热字串的名称作为它的第一个参数 ThisHotkey 传递(不包括后面的冒号). 例如:

:X:btw::MsgBox ThisHotkey  ; 报告 :X:btw

除了少数例外, 这类似于内置变量 A_ThisHotkey. 参数名可以通过使用命名函数来更改.

终止符

除非使用了星号选项, 否则您必须在热字串的缩写后输入一个 终止符 才能触发它. 终止符最初由以下字符组成: -()[]{}':;"/\,.?!`n`s`t(注意 `n 是 Enter, `s 是 Space, 而 `t 是 Tab). 这个字符集可以通过编辑下列的示例进行更改, 该示例为 所有 热字串设置新的终止符, 而不仅是在它下面的那些:

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

终止符也可以在脚本运行时通过调用 Hotstring 函数来进行更改, 如下例所示:

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

选项

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

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

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

* (星号): 不需要终止符(例如 Space, . 或 Enter) 来触发热字串. 例如:

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

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

? (问号): 即使热字串在另一个单词中也会被触发; 也就是说, 在它之前输入的字符是字母数字时. 例如, 如果 :?:al::airline 是热字串, 输入 "practical " 会产生 "practicairline ". 使用 ?0 来关闭此选项.

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

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

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

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

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

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

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

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

R: 发送替换文本的原始文本; 即, 不把 {Enter} 转换成 Enter, ^c 转换成 Ctrl+C, 等等. 使用 R0 来关闭此选项, 或用 T 来覆盖.

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

S 或 S0: 指定字母 S 使热字串免于 挂起. 指定 S0(S 与数字 0) 来移除豁免, 允许热字串被挂起. 当作为默认选项应用时, S 或 #SuspendExempt 将使热字串豁免; 也就是说, 要覆盖该指令, 必须在热字串中显式使用 S0.

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

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

如果未使用上面的任何一个选项, 则默认为 SendInput. 然而, 与 SI 选项不同的是, 在 SendInput 不可用时会使用 SendEvent 而不是 SendPlay.

T: 使用文本模式 发送替换文本. 也就是说, 按字符代码发送每个字符, 不转换 {Enter} 为 Enter, ^c 为 Ctrl+C, 等等. 不需要将每个字符转换为击键. 对于具有延续片段的热字符串, 此选项将自动生效. 使用 T0 或 R0 来关闭此选项, 或使用 R 来覆盖.

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

该选项不应该与 Hotstring 函数一起使用. 要使热字串触发时调用函数, 传递该函数的引用.

Z: 这个较少使用的选项会在每次热字串触发后重置热字串识别器. 换句话说, 脚本将开始等待一个全新的热字符串, 从而不考虑您之前键入的任何内容. 这可以防止触发不必要的热字串. 要说明这一点, 请参考以下热字串:

:b0*?:11::
{
    Send "xx"
}

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

长替换

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

::text1::
(
顶部和底部括号之间的任何文本都按原义处理.
默认情况下, 前一行和这一行之间的硬回车(Enter) 也会被保留下来.
    默认情况下, 这一行左边的缩进(tab) 被保留.
)

有关如何更改这些默认行为的信息, 请参阅延续片段. 延续片段的存在也会使热字串默认为文本模式. 覆盖此特性的唯一方法是在每个具有延续片段的热字串中指定相反的选项(例如 :t0:text1:: 或 :r:text2::).

上下文相关的热字串

使用 #HotIf 指令可以让选择的热字串产生上下文相关性. 这样的热字符串根据任意条件(比如活动窗口的类型) 来发送不同的替换, 执行不同的操作, 或者什么都不做. 例如:

#HotIf WinActive("ahk_class Notepad")
::btw::This replacement text will appear only in Notepad.
#HotIf
::btw::This replacement text appears in windows other than Notepad.

自动更正

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

下载: AutoCorrect.ahk (127 KB)

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

备注

目前不支持替换文本中使用表达式. 要解决此问题, 请不要让这样的热字串自动替换. 相反, 应该在热字符串的正文中使用 Send 函数, 或者与 X(执行) 选项一起使用.

要在替换后发送额外的空格或制表符, 请在替换的末尾包含转义序列 `s 或 `t, 例如 :*:btw::by the way`s.

对于一个不使用 Text 或 Raw 模式的自动替换热字符串, 单独发送 {, 或者只在前面加空格, 需要用一对大括号括起来, 例如 :*:brace::{{} 和 :*:space_brace:: {{}. 否则它将被解释为热字串函数的左大括号, 以支持 OTB(One True Brace) 样式.

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

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

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

虽然热字符串定义中的单冒号不需要转义, 除非它们位于双冒号分隔符之前, 但那些左边有空格或制表符的反引号和分号必须始终被转义. 有关完整列表, 请参阅转义序列.

尽管 Send 函数的特殊字符(如 {Enter}) 在自动替换文本中受到支持(除非使用 raw 选项), 但是热字串缩写本身并不使用此功能. 相反, 指定 `n 表示 Enter 键和 `t(或原义制表符) 表示 Tab(有关完整列表, 请参阅转义序列). 例如, 当您输入 "ab" 后跟着 tab 时, 会触发热字串 :*:ab`t::.

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

每个热字串缩写的长度不能超过 40 个字符. 如果超过了这个长度, 程序会发出警告. 相比之下, 当发送模式是默认的 SendInput 时, 热字串的替换文本的长度限制在 5000 个字符左右. 该限制可以通过切换到其他发送模式来消除, 或者通过在热字符串的主体中使用 SendPlay 或 SendEvent, 或者与 X(执行) 选项结合使用来消除.

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

为了识别热字串, 您输入的所有退格都会被考虑在内. 但是, 使用 ↑, →, ↓, ←, PgUp, PgDn, Home 和 End 在编辑器中导航会重置热字串识别进程. 换句话说, 它将开始等待一个全新的热字串.

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

只有在函数被命名的情况下, 脚本才能显式调用热字串的函数. 请参阅命名的热字串函数.

当输入被一个不可见的Input 钩子阻塞时, 热字串不受监控, 也不会被触发.

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

Suspend 函数可以暂时禁用所有热字串, 除了那些你豁免的. 为了更好的选择性, 请使用 #HotIf.

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

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

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

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

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

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

命名的函数热字串

如果需要在不触发热字串本身的情况下调用热字串的函数, 可以通过简单地在热键的双冒号后定义一个或多个热键来指定一个命名的函数, 如此例所示:

; 此示例还演示了在脚本中实现大小写一致性的一种方法.
:C:BTW::  ; 输入所有大写字母.
:C:Btw::  ; 只有第一个字母输入大写字母.
: :btw::  ; 输入任何其他组合.
    case_conform_btw(hs) ; hs 将保存触发该函数的热字符串的名称.
    {
        if (hs == ":C:BTW")
            Send "BY THE WAY"
        else if (hs == ":C:Btw")
            Send "By the way"
        else
            Send "by the way"
    }

如果函数 case_conform_btw 被脚本显式调用, 第一个参数(hs) 必须传递一个值.

热键也可以这样定义. 多个热键或热字串可以堆叠在一起来调用同一个函数.

热字串和函数名之间只能有空格或注释.

命名函数还鼓励自记录热字串, 就像上面的代码中函数名描述的热字串一样.

Hotstring 函数也可以关联函数或函数对象到一个热字串.

热字串助手

看看 Hotstring 函数页面的示例部分中的第一个示例, 如果您是深度的热字串用户, 那么它会很有用. 通过按下 Win+H(或您选择的其他热键), 可以把当前选择的文本转变成热字串. 例如, 如果您在文字处理软件中选择了 "by the way", 按下 Win+H 会提示您输入其缩写(例如 btw), 添加新热字串到脚本中并激活它.


按键列表(键盘, 鼠标和控制器) | AutoHotkey v2

按键列表(键盘, 鼠标和控制器)

目录

  • 鼠标
    • 常规按钮
    • 高级按钮
    • 滚轮
  • 键盘
    • 常规按键
    • 光标控制按键
    • 数字键盘
    • 功能按键
    • 修饰按键
    • 多媒体按键
    • 其他按键
  • 游戏控制器(游戏手柄, 操纵杆等)
  • 手持遥控
  • 特殊按键
  • CapsLock 和 IME

鼠标

常规按钮

名称 | 描述
LButton | 主鼠标按钮. 对应哪个物理按钮取决于系统设置; 默认情况下, 它是鼠标左键.
RButton | 副鼠标按钮. 对应哪个物理按钮取决于系统设置; 默认情况下, 它是鼠标右键.
MButton | 鼠标中键或滚轮

高级按钮

名称 | 描述
XButton1 | 鼠标的第四个按键. 通常和 Browser_Back 执行相同功能.
XButton2 | 鼠标的第五个按键. 通常和 Browser_Forward 执行相同功能.

Wheel

名称 | 描述
WheelDown | 向下转动鼠标滚轮(朝向您的方向).
WheelUp | 向上转动鼠标滚轮(远离您的方向).
WheelLeft WheelRight | 向左或向右滚动. 这些键可以用作热键, 用于某些(但并非所有) 带第二个滚轮或支持左右滚动的鼠标. 在某些情况下, 必须通过鼠标的自带软件包控制这个功能. 不论鼠标如何特殊, Send 和 Click 都能在支持它们的程序里水平滚动.

键盘

注意: 字母和数字按键的名称和单个字母或数字相同. 例如: b 表示按键 B, 而 5 表示按键 5.

虽然任何单个字符都可以用作键名, 但其含义(扫描码或虚拟键码) 取决于当前的键盘布局. 此外, 根据具体情况, 某些特殊字符可能需要转义或用大括号括起来. 字母 a-z 或 A-Z 可以用来指代相应的虚拟键码(通常是 vk41-vk5A), 即使它们不包含在当前的键盘布局中.

常规按键

名称 | 描述
CapsLock | CapsLock(大小写锁定键) 注意: Windows IME 可能会干扰 CapsLock 的检测和功能; 有关详情, 请参阅 CapsLock 和 IME.
Space | Space(空格键)
Tab | Tab(Tab 键)
Enter | Enter
Escape(或 Esc) | Esc
Backspace(或 BS) | Backspace

光标控制按键

名称 | 描述
ScrollLock | ScrollLock(滚动锁定键). 当按住 Ctrl 键时, ScrollLock 键会产生 CtrlBreak 的键码, 但可以通过扫描码与 Pause 区别开来.
Delete(或 Del) | Del
Insert(或 Ins) | Ins
Home | Home
End | End
PgUp | PgUp(向上翻页键)
PgDn | PgDn(向下翻页键)
Up | ↑(上方向键)
Down | ↓(下方向键)
Left | ←(左方向键)
Right | →(右方向键)

Numpad 按键

由于系统行为, 根据 NumLock 是 ON(开) 还是 OFF(关), 以下用斜杠分隔的键识别为不同的按键. 如果 NumLock 为 OFF(/ON) 但 Shift 按下, 系统将临时释放 Shift 并且就像 NumLock 为 ON(/OFF) 状态一样.

名称 | 描述
Numpad0 / NumpadIns | 0 / Ins
Numpad1 / NumpadEnd | 1 / End
Numpad2 / NumpadDown | 2 / ↓
Numpad3 / NumpadPgDn | 3 / PgDn
Numpad4 / NumpadLeft | 4 / ←
Numpad5 / NumpadClear | 5 / 通常什么都不做
Numpad6 / NumpadRight | 6 / →
Numpad7 / NumpadHome | 7 / Home
Numpad8 / NumpadUp | 8 / ↑
Numpad9 / NumpadPgUp | 9 / PgUp
NumpadDot / NumpadDel | . / Del
NumLock | NumLock(数字锁定键). 当按住 Ctrl 键时, NumLock 键会产生 Pause 的键码, 所以请使用 Pause 来代替 ^NumLock 作为热键.
NumpadDiv | /(除号)
NumpadMult | *(乘号)
NumpadAdd | +(加号)
NumpadSub | -(减号)
NumpadEnter | Enter

功能键

名称 | 描述
F1 - F24 | 在大多数键盘顶部的 12 个或更多的功能键.

修饰符键

名称 | 描述
LWin | 左边的 Win. 对应 <# 热键前缀.
RWin | 右边的 Win. 对应 ># 热键前缀. 注意: 与 Ctrl/Alt/Shift 不同, 没有一般的/中性的 "Win", 因为操作系统不支持. 然而, 带有 # 修饰符的热键可以触发由任一 Win 键触发.
Control (或 Ctrl) | Ctrl. 作为热键(Control::) 时在它弹起时触发, 不过如果加上波浪号前缀可以改变这种情况. 对应 ^ 热键前缀.
Alt | Alt. 作为热键(Alt::) 时在它弹起时触发, 不过如果加上波浪号前缀可以改变这种情况. 对应 ! 热键前缀.
Shift | Shift. 作为热键(Shift::) 时在它弹起时触发, 不过如果加上波浪号前缀可以改变这种情况. 对应 + 热键前缀.
LControl (或 LCtrl) | 左 Ctrl. 对应 <^ 热键前缀.
RControl (或 RCtrl) | 右 Ctrl. 对应 >^ 热键前缀.
LShift | 左 Shift. 对应 <+ 热键前缀.
RShift | 右 Shift. 对应 >+ 热键前缀.
LAlt | 左 Alt. 对应 <! 热键前缀.
RAlt | 右 Alt. 对应 >! 热键前缀. 注意: 如果您的键盘布局存在 AltGr 而不是 RAlt, 那么您完全可以根据这里描述的那样, 通过 <^>! 把它作为热键前缀使用. 此外, LControl & RAlt:: 可以把 AltGr 自身设置成热键.

多媒体键

下面列出的每个按键的功能可以通过修改 Windows 注册表进行替换. 这个表格中显示的是在 Windows 系统的大多数版本中每个按键的默认功能.

名称 | 描述
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 | 播放/暂停
Launch_Mail | 打开默认的电子邮件程序
Launch_Media | 打开默认的媒体播放器
Launch_App1 | 打开此电脑(以前是我的电脑或计算机)
Launch_App2 | 打开计算器

其他按键

名称 | 描述
AppsKey | Menu. 这是调用右键上下文菜单的按键.
PrintScreen | PrtScr(截屏键)
CtrlBreak | Ctrl+Pause 或 Ctrl+ScrollLock
Pause | Pause(暂停键) 或 Ctrl+NumLock. 当按住 Ctrl 键时, Pause 会产生 CtrlBreak 的键码, 而 NumLock 产生 Pause, 所以请使用 ^CtrlBreak 代替 ^Pause 来作为热键.
帮助 | Help(帮助键). 此键可能在大多数键盘上不存在. 它通常和 F1 不同.
Sleep | 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 方法的更多信息, 请参阅特殊按键.

警告: 只有 Send, GetKeyName, GetKeyVK, GetKeySC 和 A_MenuMaskKey 支持 VKnn 和 SCnnn 组合使用. 如果在任何其他情况下组合使用(或存在任何其他无效后缀), 则不能识别按键. 例如, vk1Bsc001:: 引发一个错误.

游戏控制器(游戏手柄, 操纵杆等)

注意: 由于历史原因, 以下按钮和控件名称以 Joy 开头, 这代表操纵杆. 然而, 它们通常也适用于其他游戏控制器, 如游戏手柄或方向盘.

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

例如, 当使用 Xbox Wireless/360 控制器时, JoyX/JoyY 是左摇杆, JoyR/JoyU 是右摇杆, JoyZ 是左右触发器, 而 JoyPOV 是方向键(D-pad).

多个控制器: 如果计算机上有多个控制器并且您想使用第一个外的其他控制器, 那么请在控制器名称的前面加上控制器的编号(最大为 16). 例如, 2joy1 表示第二个控制器的首个按钮.

注意: 如果您在使用脚本识别您的控制器时遇到问题, 曾有人报告说尽管只有一个控制器却需要指定大于 1 的控制器编号. 不清楚这种方法是如何得到的或是否正常, 不过请尝试在控制器测试脚本中使用控制器编号也许可以帮助确定这种方法是否适合您的系统.

另请参阅:

  • 控制器重映射: 使用控制器发送键击和鼠标点击的方法.
  • 控制器到鼠标的映射脚本: 把控制器作为鼠标使用.

手持遥控

通过 WinLIRC 客户端脚本响应手持遥控器的信号.

特殊按键

如果您的键盘或鼠标含有前面没有列出的按键, 那么使用下列步骤后您仍可能把它设为热键.

  1. 确保至少有一个使用键盘钩子的脚本正在运行. 打开脚本的主窗口并在菜单栏中选择 "View->Key history" 后您可以判断脚本是否使用了键盘钩子.
  2. 双击脚本的托盘图标来打开其主窗口.
  3. 按下您键盘上的其中一个 "神秘按键".
  4. 选择菜单项 "View->Key history"
  5. 向下滚动到页面的底部. 在底部附近的某个地方可以看到您按键的按下和弹起事件. 注: 一些按键不生成事件, 因此这里看不到它们的事件. 如果是这种情况, 那么您不能直接把此特殊按键设为热键, 因为您的键盘驱动或硬件在很低的的层面处理它, AutoHotkey 无法访问. 有关可能的解决方案, 请参阅下文.
  6. 如果检测到了您的按键, 请记下列表中第二列的 3 位十六进制值(例如 159).
  7. 要把此键定义为热键, 请参照此例:
    SC159::MsgBox ThisHotkey " was pressed." ; 替换 159 为您的按键的值.
    另请参阅 ThisHotkey.

反向: 要把其他键重映射 为 "神秘按键", 请参照此例:

; 把 159 替换为上面找到的值. 把 FF(如果需要) 替换为
; 按键的虚拟键, 它可以在按键历史屏幕的首列找到.
#c::Send "{vkFFsc159}" ; 有关详情, 请参阅 Send {vkXXscYYY}.

可供选择的解决方案: 如果您的按键或鼠标按钮没有在按键历史页面检测到, 那么下面的其中一种方法可能有帮助:

  1. 重新配置您鼠标或键盘的附带软件(有时可以在控制面板或开始菜单中访问) 来让 "神秘按键" 发送其他的键击. 然后可以在脚本中把这样的键击设置为热键. 例如, 如果您配置神秘按键来发送 Ctrl+F1, 然后在脚本中通过使用 ^F1:: 您可以把这个按键间接的设置为热键.

  2. 试试 AHKHID. 你还可以尝试以 RawInput*, USB HID 或 AHKHID 作为关键字在论坛进行搜索.

  3. 下面是最后的手段, 通常应该在其他所有方法都无效时才去尝试. 这是由于成功的机会很小且可能会引起难以取消的不必要的副作用:
    禁用或移除您键盘或鼠标的附带软件, 或者让它使用更标准的驱动, 例如操作系统内置的那个. 这里假设您特殊的键盘或鼠标使用自己的驱动并且您不使用其自带驱动和软件提供的功能.

CapsLock 和 IME

Windows IME 的某些配置(如, 日文输入与英文键盘) 使用 CapsLock 来切换模式. 在这种情况下, CapsLock 被 IME 压制, 并且无法被 AutoHotkey 检测到. 不过 Alt+CapsLock, Ctrl+CapsLock 和 Shift+CapsLock 等快捷键可以通过变通的方法禁用. 具体来说, 发送松开按键来修改 IME 的状态, 但通过给键盘钩子发送信号来抑制该事件, 从而防止任何其他影响. 可以使用以下函数来实现这一目的:

; 必须安装键盘钩子.
InstallKeybdHook
SendSuppressedKeyUp(key) {
    DllCall("keybd_event"
        , "char", GetKeyVK(key)
        , "char", GetKeySC(key)
        , "uint", KEYEVENTF_KEYUP := 0x2
        , "uptr", KEY_BLOCK_THIS := 0xFFC3D450)
}

将该函数复制到脚本中或保存为库文件夹中的 SendSuppressedKeyUp.ahk, 并在脚本中加入 #Include <SendSuppressedKeyUp>, 可以按照以下方式使用:

; 禁止 IME 的 Alt+key 快捷键.
~LAlt::SendSuppressedKeyUp "LAlt"

; 测试热键:
!CapsLock::MsgBox % A_ThisHotkey

; 重映射 CapsLock 为 LCtrl 以与 IME 兼容的方式.
*CapsLock::
{
    Send {Blind}{LCtrl DownR}
    SendSuppressedKeyUp "LCtrl"
}
*CapsLock up::
{
    Send {Blind}{LCtrl Up}
}


脚本语言 | AutoHotkey v2

脚本语言

一个 AutoHotkey 脚本从根本上说是使用 AutoHotkey 独有的自定义语言编写的程序要遵循的指令集合. 这种语言与其他几种脚本语言有一些相似之处, 但也有其独特的优势和缺陷. 本文档描述了该语言, 并试图指出常见的缺陷.

有关 AutoHotkey 所使用的各种概念的更一般的解释, 请参阅概念和约定.

目录

  • 常规约定
  • 注释
  • 表达式
    • 字符串 / 文本
    • 变量
    • 常量
    • 运算符
    • 函数调用
      • 函数调用语句
      • 可选参数
    • 对象的运算符
    • 表达式语句
  • 控制流语句
    • 控制流 vs. 其他语句
    • Loop 语句
    • 非控制流
  • 脚本的结构
    • 全局代码
    • 函数
    • #Include
  • 杂项
    • 动态变量
      • 伪数组
    • 标签

常规约定

名称: 变量和函数名称不区分大小写(例如, CurrentDate 等同于 currentdate). 有关详情(如最大长度和可用字符), 请参阅名称.

无类型变量: 变量没有显式定义的类型; 相反, 任何类型的值都可以存储在任何变量中(不包括常量和内置变量). 数字可能会自动转换为字符串(文本), 反之亦然, 这取决于实际情况.

声明是可选的: 除了在函数页面上注明的地方外, 变量不需要声明. 然而, 在给定一个变量的值之前, 试图读取该变量被视为一个错误.

空格通常被忽略: 缩进(前导空格) 对于编写可读代码非常重要, 但不是程序所需要的, 通常会被忽略. 在行尾的和表达式内的(引号之间的除外) 的空格和制表符 通常 会被忽略. 然而, 在一些情况下, 空格是重要的, 包括:

  • 函数和方法调用要求在函数/方法名称和 ( 之间没有空格.
  • 执行连接时需要空格.
  • 两个运算符之间可能需要空格, 以消除歧义.
  • 单行注释如果不在行首, 则需要前导空格.

换行符是有意义的: 换行符通常作为语句分隔符, 终止前一个函数或其他语句. (语句 只是语言中表示要执行某些操作的最小的独立元素.) 这个例外是行延续(请参见下文).

行延续: 长行可以分成一些小行, 以提高可读性和可维护性. 这是通过预处理实现的, 所以不属于这种语言的一部分. 有三种方法:

  • 延续前缀: 以表达式运算符(++ 和 -- 除外) 开头的行与前一行合并. 无论该行是否实际包含表达式, 都会合并行.
  • 延续闭环: 在大多数情况下, 括在 (), [] 或 {} 中的子表达式可以自动跨越多行.
  • 延续片段: 片段中的多行与片段上面那一行合并, 延续片段以 ( 开始, 以 ) 结束(两个符号必须出现在行的开头, 不计空格).

注释

注释 是脚本中被程序忽略的那部分文本. 它们通常用于添加解释或禁用部分代码.

可以通过在行的开头使用分号来注释脚本. 例如:

; 这一整行都是注释.

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

Run "Notepad"  ; 这是与函数调用在同一行上的注释.

此外, 可以使用 /* 和 */ 符号注释掉整块代码, 如下例所示:

/*
MsgBox "这行被注释(禁用) 掉了."
MsgBox "常见的错误:" */ " 这不会结束注释."
MsgBox "这行被注释掉了."
*/
MsgBox "这行没有被注释."
/* 这也是有效注释, 但是这一行不能有其他代码. */
MsgBox "这行没有被注释."

除了制表符和空格, /* 必须出现在行首, 而 */ 只能出现在行首或行尾. 省略 */ 也是有效的, 在这种情况下, 文件的其余部分将被注释掉.

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

表达式

表达式 是一个或多个值, 变量, 运算符和函数调用的组合. 例如, 10, 1+1 和 MyVar 都是有效的表达式. 通常, 表达式将一个或多个值作为输入, 执行一个或多个操作, 并生成一个值作为结果. 找出表达式值的过程被称为 计算. 例如, 表达式 1+1 计算 出数字 2.

简单的表达式可以拼凑在一起形成更复杂的表达式. 例如, 如果 Discount/100 将折扣百分比转换为分数, 1 - Discount/100 计算剩余金额的分数, 而 Price * (1 - Discount/100) 应用它来产生净价格.

值 是数字, 对象或字符串. 原义 值是在脚本中实际写入的值; 当您在查看代码时可以看到该值(文字).

字符串 / 文本

有关字符串的更一般的解释, 请参阅字符串.

字符串 或 字符组成的串, 只是一个文本值. 在表达式中, 原义的文本必须用引号引起来, 以区分变量名称或其他表达式. 这通常被称为 加引号的原义字符串, 或者为 加引号的字符串. 例如, "this is a quoted string" 和 'so is this'.

要在原义字符串中包含 真实的 引号字符, 请使用转义序列 `" 或 `', 或将字符括在相反类型的引号中. 例如: 'She said, "An apple a day."'.

加引号的字符串能包含其他的转义序列, 如 `t(制表符), `n(换行) 和 `r(回车).

变量

有关变量的基本解释和常规细节, 请参阅变量.

变量 可以简单地通过写变量的名称来用于表达式. 例如, A_ScreenWidth/2. 但是, 变量不能在加引号的字符串中使用. 作为替代, 变量和其他值可以通过名为 连接 的过程与文本组合起来. 有两种方法能用于 连接 表达式中的值:

  • 隐式连接: "The value is " MyVar
  • 显式连接: "The value is " . MyVar

隐式连接也被称为 自动连接. 在这两种情况下, 变量和点之前的空格都是必需的.

Format 函数也可以用于此目的. 例如:

MsgBox Format("You are using AutoHotkey v{1} {2}-bit.", A_AhkVersion, A_PtrSize*8)

要为变量赋值, 请使用 := 赋值运算符, 如 MyVar := "Some text".

表达式中的 百分号 用于创建动态变量引用, 但这些都是很少需要的.

常量关键字

常量就是一个不可改变的值, 给定一个符号名称. AutoHotkey 目前有以下常量:

名称 | 值 | 类型 | 描述
False | 0 | 整数 | 布尔值 false, 有时表示 "off", "no", 等等.
True | 1 | 整数 | 布尔值 true, 有时表示 "on", "yes", 等等.

与只读内置变量不同, 这些变量不能通过动态引用返回.

运算符

运算符 采用符号或符号组的形式(如 + 或 :=), 或者下列其中一个单词 and, or, not, is, in 或 contains. 它们将一个, 两个或三个值作为输入, 并返回一个值作为结果. 用作运算输入的值或子表达式称为 运算元.

  • 一元 运算符可以写在单个运算元的前面或后面, 这取决于运算符. 例如, -x 或 not keyIsDown.
  • 二元 运算符写在两个运算元之间. 例如, 1+1 或 2 * 5.
  • AutoHotkey 只有一个 三元 运算符, 它采用如下的形式 condition ? valueIfTrue : valueIfFalse.

一些一元和二元运算符共享相同的符号, 在这种情况下, 运算符的含义取决于它是写在两个值之前, 之后还是之间. 例如, x-y 执行减法, 而 -x 反转 x 的符号(从负值产生正值, 反之亦然).

除非在运算符表中另有规定, 否则优先级相等的运算符(如, 乘号(*) 和除号(/) 按从左到右的顺序计算. 相反, 诸如加(+) 之类的优先级较低的运算符在诸如乘(*) 之类的优先级较高运算符之后被计算. 例如, 3 + 2 * 2 作为 3 + (2 * 2) 计算. 括号可以用来覆盖优先级, 如以下示例所示: (3 + 2) * 2

函数调用

有关函数和相关术语的一般解释, 请参阅函数.

函数 接受可变数量的输入, 去执行一些动作或计算, 然后 return(返回) 一个结果. 函数的输入被称为参数(parameters 或 arguments). 一个函数被 called(调用), 只需写下目标函数, 后面的参数用括号括起来即可. 例如, 如果 Shift 键被按下, 则 GetKeyState("Shift") 返回(计算为) 1, 否则返回 0.

注意: 函数和左括号之间不能有任何空格.

对于刚接触编程的人来说, 括号的要求起初可能看起来很神秘或冗长, 但它们允许将函数调用与其他操作结合起来. 例如, 只有当两个键被物理按下时, 表达式 GetKeyState("Shift", "P") and GetKeyState("Ctrl", "P") 才会返回 1.

虽然函数调用表达式通常以原义的函数名开头, 但调用的目标可以是生成函数对象的任何表达式. 在表达式 GetKeyState("Shift") 中, GetKeyState 实际上是一个变量引用, 尽管它通常引用包含内置函数的只读变量.

函数调用语句

如果不需要函数的返回值, 并且函数名写在行首(或者在其他允许语句的上下文中, 如下面的 else 或 hotkey), 则可以省略括号. 在这种情况下, 行的其余部分作为函数的参数列表. 例如:

result := MsgBox("This one requires parentheses.",, "OKCancel")
MsgBox "This one doesn't. The result was " result "."

在同一上下文中调用方法时, 也可以省略圆括号, 但仅当目标对象是变量或直接命名的属性时才可以省略圆括号, 如 myVar.myMethod 或 myVar.myProp.myMethod.

与函数调用表达式一样, 函数调用语句的目标不一定是预定义的函数; 它可以是一个包含函数对象的变量.

函数调用语句可以跨越多行.

函数调用语句有以下限制:

  • 如果有一个返回值, 它总是被丢弃.
  • 与控制流语句一样, 它们不能在表达式中使用.
  • 当可选参数被省略时, 参数列表 末尾的 逗号也必须被省略, 以防止行延续.
  • 函数调用语句不能是变量, 尽管它们可以向一个可变函数传递固定数量的参数.

可选参数

可选参数可以简单地留空, 但是分隔逗号仍然是必需的, 除非所有后续参数也被省略. 例如, Run 函数可接受一至四个参数. 下列各项均有效:

Run "notepad.exe", "C:\"
Run "notepad.exe",, "Min"
Run("notepad.exe", , , &notepadPID)

在函数调用, 数组字面量或对象字面量中, 关键字 unset 可用于显式省略参数或值. Unset 表达式具有以下效果之一:

  • 对于用户定义的函数, 使用参数的默认值.
  • 对于内置函数, 该参数被认为被忽略了.
  • 对于数组字面量 如 [var?], 该元素被包含在数组的长度中, 但没有给出值.
  • 对于对象字面量 如 {x: y?}, 该属性不被分配.

Unset 关键字还可以在函数定义中使用, 表示参数是可选的, 但没有默认值. 当函数执行时, 如果省略了参数, 对应于该参数的局部变量将没有值.

Maybe 运算符(var?) 根据变量是否有值来传递或省略变量. 例如, Array(MyVar?) 等同于 Array(IsSet(MyVar) ? MyVar : unset).

对象的运算符

这里表达式中使用的其他符号不完全符合上面定义的任何类别, 或影响表达式其他部分的含义, 如下所述. 这些都以某种方式与 对象 有关. 对于每个构造所做的事情提供一个完整的解释, 需要引入更多的概念, 而这不属于本节的范围.

Alpha.Beta 通常称为 成员访问. Alpha 是一个普通变量, 可以用函数调用或其他一些返回对象的子表达式替换. 当计算时, 对象发送一个请求 "给我属性 Beta 的值", "在属性 Beta 中存储这个值" 或 "调用名为 Beta 的方法". 换句话说, Beta 是一个对对象有意义的名字; 它不是一个局部或全局变量.

Alpha.Beta() 是一个 方法调用. Alpha 作为参数隐式传递, 但这通常是隐藏的, 因为每个方法定义都隐式地定义了一个名为 this 的参数. 括号可在特定情况下省略; 请参阅函数调用语句.

Alpha.Beta[Param] 是成员访问的一种特殊形式, 其中包括了请求中的附加参数. Beta 只是一个简单的名称, Param 是一个普通的变量或子表达式, 或者是由逗号分隔的子表达式列表(与函数的参数列表中相同). 允许可变参数调用.

Alpha.%vBeta%, Alpha.%vBeta%[Param] 和 Alpha.%vBeta%() 也是成员访问, 但 vBeta 是一个变量或子表达式. 这允许在脚本运行时确定属性或方法的名称. 以这种方式调用方法时需要括号.

Alpha[Index] 通常调用 Alpha 的 __Item 属性, 将 Index 作为参数. 在这种情况下, Alpha 和 Index 都是变量, 几乎可以用任何子表达式替换. 此语法通常用于检索数组或 Map 中的元素. 对于 COM 对象, 按 ID(DISPID_VALUE) 调用 默认属性, 因此与显式指定 __Item 属性不同.

[A, B, C] 创建一个初始内容为 A, B 和 C(本例中的所有变量) 的数组, 其中 A 是元素 1.

{Prop1: Value1, Prop2: Value2} 创建一个对象, 其中 Prop1 和 Prop2 为原义的属性名. 稍后可以使用上面描述的 成员访问 语法检索值. 要将属性名作为表达式进行计算, 请用百分号将其括起来. 例如: {%NameVar%: ValueVar}.

MyFunc(Params*) 是一个可变函数调用. 星号必须紧接在函数参数列表末尾的右括号之前. Params 必须是返回数组或其他可枚举对象的变量或子表达式. 虽然在任何地方使用 Params* 都是无效的, 但它可以用在数组标识符([A, B, C, ArrayToAppend*]) 或属性参数列表(Alpha.Beta[Params*] 或 Alpha[Params*]) 中.

表达式语句

并不是所有的表达式都可以单独在一行上使用. 例如, 只包含 21*2 或 "Some text" 的行就没有任何意义. 表达式 语句 是一个单独使用的表达式, 通常利用它的附加作用. 大多数带有附加作用的表达式都可以这样使用, 所以一般不需要记住本节的细节.

以下类型的表达式可以用作语句:

赋值(如 x := y), 复合赋值(如 x += y) 和增量/减量运算符(如 ++x 和 x--).

已知限制: 对于 x++ 和 x--, 目前变量名和运算符之间不能有空格.

函数调用(如 MyFunc(Params)). 但是, 一个独立的函数调用不能跟随一个左大括号 {(在行尾或下一行), 因为它会与函数声明混淆.

方法调用(如 MyObj.MyMethod()).

使用方括号的成员访问(如 MyObj[Index]), 它可能有类似于函数调用的附加作用.

三元表达式(如 x? CallIfTrue() : CallIfFalse()). 但是, 使用下面的规则更安全; 也就是说, 始终将表达式(或条件) 括在括号中.

已知限制: 由于函数调用语句的模糊性, 以变量名和空格开头的条件(还包含其他操作符) 应该用圆括号括起来. 例如, (x + 1) ? y : z 和 x+1 ? y : z 是表达式语句, 但是 x + 1 ? y : z 是函数调用语句.

注意: 条件不能以 ! 或任何其他表达式运算符开头, 因为它将被解释为延续行.

以 ( 开始的表达式. 但是, 通常必须在同一行有一个匹配的 ), 否则该行将被解释为延续片段的开始.

以双百分号开始的表达式(如 %varname% := 1). 这主要是由于实现的复杂性.

为简单起见, 也允许以上面描述的任一表达式(但不包括下面描述的) 开始的表达式. 例如, MyFunc()+1 目前是允许的, 尽管 +1 没有效果, 其结果会被丢弃. 由于错误检查的增强, 这些表达式在将来可能会失效.

函数调用语句类似于表达式语句, 但在技术上不是纯表达式. 例如, MsgBox "Hello, world!", myGui.Show 或 x.y.z "my parameter".

控制流语句

有关控制流的一般说明, 请参阅控制流.

语句通过将他们括在大括号({}) 中(如 C, JavaScript 和类似语言) 组合成 块, 但通常大括号必须出现在行的开头. 控制流语句可以应用于整个块或者只是单一语句.

控制流程语句的主体总是 一组 语句. 块被视为一组语句, 就像控制流语句及其主体一样. 以下相关语句与其主体一起彼此分组: If 和 Else; Loop/For 和 Until 或 Else; Try 和 Catch 和/或 Else 和/或 Finally. 换句话说, 当这些语句组作为一个整体使用时, 并不总是需要用大括号括起来(但是, 为了清楚起见, 一些编码样式总是包含大括号).

控制流语句, 它具有一个主体, 因此必须总是跟着一个相关的语句或一组语句: If, Else, Loop, While, For, Try, Catch 和 Finally.

下面的控制流语句如下::

  • 一个块(用一对大括号表示) 将零个或多个语句组合为一个语句.
  • If 语句导致其主体被执行或不依赖条件. 其后可以跟一个 Else 语句, 只有当条件不满足时才执行.
  • Goto 跳转到指定的标签并继续执行.
  • Return 从一个函数返回.
  • 一个 Loop(循环) 语句(Loop, While 或 For) 重复执行其主体.
    • Break 退出(终止) 一个循环.
    • Continue 跳过当前循环迭代的其余部分, 并开始一个新的循环.
    • Until 直到表达式计算结果为 true 时, 循环终止. 表达式在每次迭代之后被计算.
  • Switch 将一个值与多个实例进行比较, 并执行第一个匹配的语句.
  • 异常处理:
    • Try 保护它的主体不受运行错误和 throw 语句抛出的值的影响.
    • 如果在 try 语句中抛出一个给定类型的异常, 则执行 Catch.
    • Else, 当使用在 catch 语句之后时, 只有在 try 语句中没有抛出异常时才会执行.
    • Finally 在当控制权从 try 或 catch 语句的主体转出时, 执行其主体.
    • Throw 抛出一个异常, 通过 try/catch 或 OnError, 或显示错误对话框来处理.

控制流与其他语句

控制流语句与函数调用语句在以下几个方面不同:

  • 块的左大括号可以写在 If, Else, Loop, While, For, Try, Catch 或 Finally 语句(基本上是任何具有主体的控制流语句) 同一行的末尾. 这被称为 One True Brace(OTB) 样式.
  • Else, Try 和 Finally 允许任何有效的语句在其右侧, 因为它们需要一个主体但没有参数.
  • If, While, Return, Until, Loop Count, For, Catch, Break, Continue, Throw 和 Goto 允许在名称后立即使用左括号, 将整个参数列表括起来. 虽然这些看起来像函数调用, 但它们不是, 也不能在表达式中间使用. 例如, if(expression).
  • 不能通过定义具有相同名称的函数来覆盖控制流语句.

Loop 语句

有几种类型的 loop 语句:

  • Loop Count 重复执行一个语句: 可以指定重复的次数(Count) 或直到遇到 Break.
  • Loop Reg 获取指定的注册表子键的内容, 每次一个项目.
  • Loop Files 获取指定的文件或文件夹, 每次一个.
  • Loop Parse 从一个字符串中获取子字符串(片段), 每次一个.
  • Loop Read 获取文本文件中的行, 每次一行.
  • While 重复执行一个语句, 一直到指定的表达式计算结果为假. 每次迭代(重复) 前计算表达式的结果.
  • For 对每一个值或枚举器返回的每对键值对执行一个语句, 如对象中的每对键值对.

Break 退出(终止) 一个循环, 有效地跳到循环主体后面的下一行.

Continue 跳过当前循环迭代的其余部分, 并开始一个新的循环.

Until 表达式计算结果为 true 时, 循环终止. 表达式在每次迭代之后被重新计算.

标签可以用来 "命名" Continue 和 Break 的循环. 这允许脚本轻松地继续或跳出任何数量的嵌套循环而不使用 Goto.

内置变量 A_Index 包含当前循环迭代的编号. 它在第一次执行循环主体时为 1. 第二次时为 2; 依次类推. 如果一个内部循环被外部循环包围, 则内部循环优先. A_Index 适用于所有类型的循环, 但在循环之外为 0.

对于某些循环类型, 其他内置变量返回有关当前循环项 (注册表键/值, 文件, 子字符串或文本行) 的信息. 这些变量的名称以 A_Loop 开头, 如 A_LoopFileName 和 A_LoopReadLine. 它们的值总是对应于最近开始的(但还没有停止) 循环的适应类型. 例如, A_LoopField 返回最里层解析循环中的当前子字符串, 即使它在文件或注册表循环中使用.

t := "column 1`tcolumn 2`nvalue 1`tvalue 2"
Loop Parse t, "`n"
{
    rowtext := A_LoopField
    rownum := A_Index  ; 保存这个用于下面的第二个循环中.
    Loop Parse rowtext, "`t"
    {
        MsgBox rownum ":" A_Index " = " A_LoopField
    }
}

循环变量也可以在循环主体外部使用, 例如在循环中调用的函数中.

非控制流

像指令, 标签, 双冒号热键和热字串标签, 和没有赋值的声明都会在脚本加载文件的时候被处理, 它们不受控制流的制约. 换句话说, 在脚本执行任何控制流程语句之前, 它们将无条件生效. 同样, #HotIf 指令不能影响控制流; 它只是设置代码中指定的任何热键和热字串的条件. 每次按下时都会计算热键的条件, 而不是在代码中遇到 #HotIf 指令时.

脚本的结构

全局代码

脚本加载完成后, 自动执行线程 从脚本的顶行开始执行, 一直到被指示停止为止, 比如通过 Return, ExitApp 或 Exit. 脚本的物理结束也作为 Exit.

全局代码, 或全局范围内的代码, 是任何不在函数或类定义内的可执行代码. 那里的任何变量引用都被称为全局的, 因为它们可以被任何函数(通过适当的声明) 访问. 这样的代码通常用于配置适用于每个新启动的线程的设置, 或者初始化热键和其他函数使用的全局变量.

在启动时执行的代码(在脚本启动时立即执行) 通常被放在文件的顶部. 然而, 这样的代码也可以放在整个文件中, 在函数和类定义之间(但不是在里面). 这是因为每当在执行过程中遇到的每个函数或类定义的主体都会被跳过. 在某些情况下, 脚本的整个目的可能用全局代码来执行.

相关: 脚本启动(自动执行线程)

子程序

子程序(也称为 sub 或 procedure) 是一个可重复使用的代码块, 可按需执行. 子程序是通过定义 函数 创建的(见下文). 这些术语通常可以在 AutoHotkey v2 中互换, 函数是子程序的唯一类型.

函数

相关: 函数(有关函数定义)

除了调用许多有用的预置函数外, 脚本还可以定义自己的函数. 这些函数一般有两种使用方式:

  1. 函数可以被脚本本身调用. 这种函数可能被用来避免重复, 使代码更容易管理, 或者可能用于其他目的.
  2. 函数可以被程序调用, 以响应一些事件, 例如用户按下热键. 例如, 每个热键都与一个函数相关联, 每当热键被按下时就会执行.

有多种方法可以定义一个函数:

  • 函数定义由名称, 括号和代码块组成. 这定义的函数, 可以通过带有名称的函数调用或函数调用语句来执行. 例如:
    SayHello()  ; 定义 SayHello 函数.
{
    MsgBox "Hello!"
}

SayHello  ; 调用 SayHello 函数.
  • 热键或热字串定义, 由热键或热字串和单条语句或代码块组成. 这种类型的函数不能直接调用, 而是在热键或热串被激活时执行. 例如:
    #w::Run "wordpad"  ; 按 Win-W 运行 Wordpad.
#n::  ; 按 Win-N 运行 Notepad.
{
    Run "notepad"
}
  • 胖箭头表达式定义了一个函数, 它计算表达式并返回其结果, 而不是执行一个代码块. 这种函数通常没有名称, 因为它们是直接传递给另一个函数的. 例如:
    SetTimer () => MsgBox("Hello!"), -1000  ; 1 秒后说 hello.
  • 胖箭头语法也可以在表达式之外使用, 作为普通函数或方法定义的简写. 例如, 下面相当于上面的 SayHello 定义, 只不过这个定义返回的是 "OK":
    SayHello() => MsgBox("Hello!")

函数中的变量默认为函数的局部变量, 除了以下情况:

  • 当函数是假设-全局.
  • 当一个变量被引用, 但没有被用作赋值或引用操作符(&var) 的目标.
  • 在嵌套函数中引用 outer 函数的局部变量.

函数可以选择接受参数. 参数是通过在括号内列出它们来定义的. 例如:

MyFunction(FirstParameter, Second, &Third, Fourth:="")
{
    ;...
    return "a value"
}

和函数调用一样, 函数名和左括号之间不能有空格.

右括号和左大括号之间的换行符是可选的. 两者之间可以有任意数量的空格或注释.

ByRef 标记(&) 表示调用者必须传递一个变量引用. 在函数内部, 任何对参数的引用都将实际访问调用者的变量. 这类似于省略 & 并在函数内部显式地去解引用参数(例如 %Third%), 但在这种情况下, 百分号被省略. 如果参数是可选的, 而调用者省略了它, 那么该参数将作为一个普通的局部变量.

可选参数通过在参数名称后面指定 := 和一个默认值, 该值必须是加引号的原义字符串, 数字, true, false 或 unset.

函数可以返回一个值. 如果不是, 则默认返回一个空字符串.

函数定义不需要在调用该函数之前.

有关详情, 请参阅函数.

#Include

#Include 指令使脚本的行为就像指定文件的内容出现在这个确切位置一样. 这通常用于将代码组织到单独的文件中, 或者使用其他用户编写的脚本库.

#Include 文件可以包含在脚本启动时要执行的全局代码, 但是和主脚本文件中的代码一样, 只有当自动执行线程在 #Include 指令之前没有被终止(比如用一个无条件的 Return) 才会执行这些代码. 如果任何代码由于之前的 Return 而无法执行, 默认会显示一个警告.

与 C/C++ 不同, 如果以前的指令已包含该文件, #Include 不做任何事情. 要多次包含同一文件的内容, 请使用 #IncludeAgain.

为了方便共享脚本, #Include 可以搜索一些标准位置的库脚本. 有关详情, 请参阅脚本库文件夹.

杂项

动态变量

动态变量引用 接受一个文本值, 并将其解释为变量的名称.

注意: 变量不能通过动态引用来 创建, 但是现有的变量可以被赋值. 这包括脚本中包含非动态引用的所有变量, 即使它们没有被赋值.

动态变量引用的最常见形式称为 双重引用 或 双重解引. 在执行双重引用之前, 目标变量的名称存储在第二个变量中. 然后可以通过使用双重引用将第二个变量间接地将值赋给目标变量. 例如:

target := 42
second := "target"
MsgBox  second   ; 普通(单重) 变量引用 => target
MsgBox %second%  ; 双重解引 => 42

目前, 在第二种情况下, second 必须总是包含一个变量名; 不支持任意表达式.

动态变量引用也可以采用一个或多个原义文本和一个或多个变量的内容, 并将它们组合在一起组成一个单一变量名. 在没有空格的情况下, 这只需简单地按顺序写入名称和百分号括起来的变量. 例如, MyArray%A_Index% 或 MyGrid%X%_%Y%. 这用于访问 伪数组, 如下所示.

这些技术也可以应用于对象的属性和方法. 例如:

clr := {}
for n, component in ["red", "green", "blue"]
    clr.%component% := Random(0, 255)
MsgBox clr.red "," clr.green "," clr.blue

伪数组

伪数组 实际上只是一堆分开的变量, 但是有一个命名模式, 可以像数组元素一样使用它. 例如:

MyArray1 := "A"
MyArray2 := "B"
MyArray3 := "C"
Loop 3
    MsgBox MyArray%A_Index%  ; 显示 A, 然后 B, 最后 C.

用于形成最终变量名的 "索引" 不一定是数字; 它可以是一个字母或关键字.

由于这些原因, 一般建议使用 Array 或 Map 来代替伪数组:

  • 由于单个元素只是普通的变量, 可以赋值或检索一个值, 但不能 remove 或 insert 元素.
  • 由于伪数组只是概念性的, 而不是单一的值, 所以不能将其传递给函数或从函数中返回, 也不能整体复制.
  • 伪数组不能被声明为一个整体, 所以一些 "元素" 可能会解析为全局(或捕获) 变量, 而另一些则不会.
  • 如果一个变量是非动态引用的, 而只是动态赋值的, 可能会显示一个加载时警告. 这种警告是一种非常有效的检测错误的方式, 所以不建议禁用它们.
  • 当前版本的语言不允许动态创建新变量. 部分原因是为了鼓励最佳做法, 部分原因是为了避免函数中动态和非动态变量引用之间的不一致.

标签

标签标识只是一行代码, 可以用作 Goto 的目标, 或指定一个循环来跳出或继续. 标签由一个名称后跟一个冒号组成:

this_is_a_label:

除了空格和注释外, 其他代码不能和标签写在同一行. 有关详情, 请参阅标签.


License | AutoHotkey v2

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 v2

对象

对象 组合了多个 属性 和 方法:

相关话题:

  • 对象: 对象的一般解释.
  • 对象协议: 关于脚本如何与对象交互的细节.
  • 函数对象: 可以被 调用 的对象.

IsObject 可以用来确定一个值是否为对象:

Result := IsObject(expression)

有关标准对象类型的列表, 请参阅内置类. 这包括两种基本类型:

  • AutoHotkey 对象是对象类的实例. 它们支持专用的属性, 并具有发现哪些属性存在的方法. 从对象中派生了数组(线性数组), 映射(关联数组) 和所有用户自定义的和内置的类.
  • COM 对象 如由 ComObject 创建的那些对象. 这些是由外部库实现的, 因此通常与 AutoHotkey 对象的行为不同. ComObject 通常表示实现 IDispatch 接口的 COM 或 "Automation" 对象, 但也用于包装特定类型的值以传递给 COM 对象和函数.

目录

  • 基本用法
    • 数组
    • 映射(关联数组)
    • 对象
    • 原义对象
    • 释放对象
  • 扩展用法
    • 数组嵌套
  • 自定义对象
    • Ad Hoc
    • Delegation
    • 创建基对象
    • 类
    • __Enum 方法
    • __Item 属性
    • 创建和销毁
    • 元函数
  • 原始值
    • 添加属性和方法
  • 实现
    • 引用计数
    • 对象的指针

基本用法

数组

创建数组:

MyArray := [Item1, Item2, ..., ItemN]
MyArray := Array(Item1, Item2, ..., ItemN)

检索项目(或 数组元素):

Value := MyArray[Index]

更改项目的值(Index(索引) 必须介于 1 和 Length(长度) 之间, 或等效的反向索引):

MyArray[Index] := Value

使用 InsertAt 方法在指定索引处插入一个或多个项目:

MyArray.InsertAt(Index, Value, Value2, ...)

使用 Push 方法追加一个或多个项目:

MyArray.Push(Value, Value2, ...)

使用 RemoveAt 方法移除项目:

RemovedValue := MyArray.RemoveAt(Index)

使用 Pop 移除最后一项:

RemovedValue := MyArray.Pop()

Length 返回数组中的项目数. 通过索引或 For-循环可以遍历数组的内容. 例如:

MyArray := ["one", "two", "three"]

; 从 1 依次递加到数组的项目数:
Loop MyArray.Length
    MsgBox MyArray[A_Index]

; 枚举数组内容:
For index, value in MyArray
    MsgBox "Item " index " is '" value "'"

; 同样的事情再来一次:
For value in MyArray
    MsgBox "Item " A_Index " is '" value "'"

映射(关联数组)

Map 或关联数组是包含一组键(每个键是唯一的) 和一组值的对象, 其中每个键和一个值关联. 键可以为字符串, 整数或对象, 而值可以为任何类型. 关联数组可以用如下方法创建:

MyMap := Map("KeyA", ValueA, "KeyB", ValueB, ..., "KeyZ", ValueZ)

检索一个项目, 其中 键 可以是变量或表达式:

Value := MyMap[Key]

赋值项目:

MyMap[Key] := Value

使用 Delete 方法移除项目:

RemovedValue := MyMap.Delete(Key)

枚举项目:

MyMap := Map("ten", 10, "twenty", 20, "thirty", 30)
For key, value in MyMap
    MsgBox key ' = ' value

对象

对象可以有 属性 和 项目(如, 数组元素). 项目可以使用 [] 来访问, 如前面几节所示. 属性通常通过在一个点后面加上一个标识符(只是一个名称) 来访问. 方法 是可以被调用的属性.

示例:

检索或设置一个原义名称为 Property 的属性:

Value := MyObject.Property
MyObject.Property := Value

检索或设置通过计算表达式或变量来确定名称的属性:

Value := MyObject.%Expression%
MyObject.%Expression% := Value

调用一个原义名称为 Method 的属性/方法:

ReturnValue := MyObject.Method(Parameters)

调用通过计算表达式或变量来确定名称的属性/方法:

ReturnValue := MyObject.%Expression%(Parameters)

在检索或赋值属性时, 有些属性可以接受参数:

Value := MyObject.Property[Parameters]
MyObject.Property[Parameters] := Value

对象可能支持索引: MyArray[Index] 实际上调用 MyArray 的 __Item 属性, 并将 Index 作为参数传递.

对象字面量(文本对象)

可以在表达式中使用对象字面量来创建即时生成的对象. 对象字面量由一对大括号({}) 包含一组以逗号分隔的名称-值对组成. 每一对都由一个字面的(未加引号) 属性名和一个值(子表达式) 组成, 它们之间用冒号(:) 分隔. 例如:

Coord := {X: 13, Y: 240}

这等同于:

Coord := Object()
Coord.X := 13
Coord.Y := 240

每个名称-值对都会导致一个值属性被定义, 但可以设置 Base(具有与普通赋值相同的限制).

名称替换允许通过计算表达式或变量来确定属性名称. 例如:

parts := StrSplit("key = value", "=", " ")
pair := {%parts[1]%: parts[2]}
MsgBox pair.key

释放对象

脚本不会显式的释放对象. 当到对象的最后一个引用被释放时, 会自动释放这个对象. 当某个保存引用的变量被赋为其他值时, 会自动释放它原来保存的引用. 例如:

obj := {}  ; 创建对象.
obj := ""  ; 释放最后一个引用, 因此释放对象.

类似地, 当属性或数组元素被赋为其他值或从对象中删除时, 存储在属性或数组元素中的引用将被释放.

arr := [{}]  ; 创建包含对象的数组.
arr[1] := {}  ; 再创建一个对象, 隐式释放第一个对象.
arr.RemoveAt(1)  ; 移除并释放第二个对象.

由于在释放一个对象时, 到这个对象的所有引用都必须被释放, 所以包含循环引用的对象无法被自动释放. 例如, 如果 x.child 引用 y 且 y.parent 引用了 x, 则清除 x 和 y 是不够的, 因为父对象仍然包含到这个子对象的引用, 反之亦然. 要避免此问题, 请首先移除循环引用.

x := {}, y := {}             ; 创建两个对象.
x.child := y, y.parent := x  ; 创建循环引用.

y.parent := ""               ; 在释放对象前必须移除循环引用.
x := "", y := ""             ; 如果没有上一行, 则此行无法释放对象.

想了解更多高级用法和细节, 请参阅引用计数.

扩展用法

数组嵌套

尽管不支持 "多维" 数组, 但是脚本可以组合多个数组或映射. 例如:

grid := [[1,2,3],
         [4,5,6],
         [7,8,9]]
MsgBox grid[1][3] ; 3
MsgBox grid[3][2] ; 8

自定义对象可以通过定义一个 __Item 属性来实现多维支持. 例如:

class Array2D extends Array {
    __new(x, y) {
        this.Length := x * y
        this.Width := x
        this.Height := y
    }
    __Item[x, y] {
        get => super.Has(this.i[x, y]) ? super[this.i[x, y]] : false
        set => super[this.i[x, y]] := value
    }
    i[x, y] => this.Width * (y-1) + x
}

grid := Array2D(4, 3)
grid[4, 1] := "#"
grid[3, 2] := "#"
grid[2, 2] := "#"
grid[1, 3] := "#"
gridtext := ""
Loop grid.Height {
    y := A_Index
    Loop grid.Width {
        x := A_Index
        gridtext .= grid[x, y] || "-"
    }
    gridtext .= "`n"
}
MsgBox gridtext

真实的脚本应执行错误检查并覆盖其他方法, 如 __Enum 以支持枚举.

自定义对象

创建自定义对象通常有两种方法:

  • 专用: 创建对象并添加属性.
  • 委托: 在共享 基对象 或类中定义属性.

元函数可用于进一步控制对象的行为方式.

注意: 在本节中, 对象 是 Object 类的任何实例. 本节不适用于 COM 对象.

专用

属性和方法(可调用属性) 通常可以随时添加到新对象中. 例如, 一个具有一个属性和一个方法的对象可以这样构造:

; 创建对象.
thing := {}
; 存储值.
thing.foo := "bar"
; 定义一个方法.
thing.test := thing_test
; 调用方法.
thing.test()

thing_test(this) {
   MsgBox this.foo
}

你可以类似地用 thing := {foo: "bar"} 创建上面的对象. 当使用 {property:value} 表示法时, 属性不能使用引号.

调用 thing.test() 时, thing 会自动被插入到参数列表的开始处. 按照约定, 函数是通过结合对象的 "类型" 和方法名来命名的, 但这不是必要条件.

在上面的示例中, test 在被定义后可能会被赋值到其他函数或值, 在这种情况下, 原始函数将丢失, 并且无法通过此属性进行调用. 另一种方法是定义一个只读方法, 如下所示:

thing.DefineProp('test', {call: thing_test})

另请参阅: DefineProp

委托

对象是 基于原型的. 也就是说, 没有在对象本身中定义的任何属性都可以在对象的基中定义. 这被称为 委托继承 或 差异继承, 因为对象可以只实现使其不同的部分, 而将其余部分委托给它的基.

虽然基对象通常也称为原型, 但我们使用 "类的原型" 来表示该类的每个实例所基于的对象, 而使用 "基" 来表示一个实例所基于的对象.

AutoHotkey 的对象设计主要受 JavaScript 和 Lua, 略带 C# 的影响. 我们使用 obj.base 代替 JavaScript 的 obj.__proto__ 和 cls.Prototype 代替 JavaScript 的 func.prototype. (使用类对象代替构造函数.)

对象的基也用于标识其类型或类. 例如, x := [] 创建 基于 Array.Prototype 的对象, 这意味着表达式 x is Array 并且 x.HasBase(Array.Prototype) 为 true, 而 type(x) 返回 "Array". 每个类的 Prototype 都是基于其基类的 Prototype, 所以 x.HasBase(Object.Prototype) 也为 true.

对象或派生类的任何实例都可以是基对象, 但只能将对象赋值为具有相同原生类型的对象的基. 这是为了确保内置方法始终能够识别对象的原生类型, 并且仅对具有正确二进制结构的对象进行操作.

基对象可以用两种不同的方式定义:

  • 通过创建一个普通对象.
  • 通过定义一个类. 每个类都有一个 Prototype 属性, 包含一个对象, 该类的所有实例都基于该对象, 而类本身成为任何直接子类的基对象.

基对象可以赋值到其他对象的基属性, 但通常在创建对象时隐式地设置该对象的基.

创建基对象

任何对象都可以用作具有相同原生类型的任何其他对象的基. 下面的例子基于在之前的专用的例子(运行前将两者结合):

other := {}
other.base := thing
other.test()

此时, other 从 thing 继承了 foo 和 test. 这种继承是动态的, 所以如果 thing.foo 被改变了, 这改变也会由 other.foo 表现出来. 如果脚本赋值给 other.foo, 值存储到 other 中并且之后对 thing.foo 任何改变都不会影响 other.foo. 当调用 other.test() 时, 它的 this 参数包含 other 而不是 thing 的引用.

类

在面向对象编程中, 类是一个可扩展的程序代码模板, 为状态(成员变量) 和行为实现(成员函数或方法) 提供初始值. Wikipedia

从根本上讲, 类 是具有某些共同属性或属性的一组或一类事物. 在 AutoHotkey 中, class 定义了该类实例共享的属性(以及方法, 这些方法是可调用的属性). 一个 实例 只是一个继承了类的属性的对象, 通常也可以被识别为属于该类(如表达式 instance is ClassName). 实例通常通过调用 ClassName() 创建.

由于对象是动态的且基于原型, 因此每个类都包含两部分:

  • 类具有原型对象, 该类的所有实例都基于该对象. 原型对象包含所有适用于该类实例的方法和动态属性. 这包括所有没有 static 关键字的属性和方法.
  • 类本身是一个对象, 只包含静态方法和属性. 这包括所有带有 static 关键字的的所有属性和方法, 以及所有嵌套的类. 这些不适用于特定实例, 可以通过按名称引用类本身来使用.

下面展示了类定义的大部分元素:

class ClassName extends BaseClassName
{
    InstanceVar := 表达式

    static ClassVar := 表达式

    class NestedClass
    {
        ...
    }

    Method()
    {
        ...
    }

    static Method()
    {
        ...
    }

    Property[Parameters] ; 仅在有参数时使用方括号.
    {
        get {
            return 属性的值
        }
        set {
            存储或以其他方式处理 值
        }
    }

     ShortProperty
    {
        get => 计算属性值的表达式
        set => 存储或以其他方式处理 值 的表达式
    }

     ShorterProperty => 计算属性值的表达式
}

加载脚本时, 它构造一个类对象并将其存储在全局常量(只读变量) ClassName 中. 如果存在 extends BaseClassName, 那么 BaseClassName 必须为另一个类的全名. 每个类的全名存储在 ClassName.Prototype.__Class.

因为类本身是通过一个变量来访问的, 类名不能在同一个上下文中同时用于引用类和创建一个单独的变量(比如保存类的一个实例). 例如, box := Box() 将无法工作, 因为 box 和 Box 都解析为同一事物. 试图以这种方式重新分配一个顶层(非嵌套) 类会导致加载时错误.

在本文档中, 单词 "class" 本身通常表示用 class 关键字构造的类对象.

类定义可以包含变量声明, 方法定义和嵌套的类定义.

实例变量

实例变量 是类的每个实例都拥有自己的副本. 它们被声明并且表现得像普通的赋值, 但 this. 前缀被忽略(仅限于类主体内时):

InstanceVar := Expression

每次使用 ClassName() 创建类的新实例时, 都会计算这些声明, 在所有基类声明被求值之后, 但在调用 __New 之前. 这是通过自动创建一个名为 __Init 的方法来实现的, 该方法包含对 super.__Init() 的调用, 并将每个声明插入其中. 因此, 单个类定义不能同时包含 __Init 方法和实例变量声明.

Expression 可以通过 this 访问其他实例变量和方法. 全局变量可以被读取, 但不能被赋值. 在表达式中的额外赋值(或使用引用操作符) 通常会在 __Init 方法中创建一个局部变量. 例如, x := y := 1 将会设置 this.x 和一个局部变量 y(一旦所有初始化器被计算, 这个变量就会被释放).

要访问实例变量, 总是要指定目标对象; 例如, this.InstanceVar.

支持形如 x.y := z 的声明语法, 但前提是 x 已在类中定义. 例如, x := {}, x.y := 42 声明了 x 并初始化了 this.x.y.

Static/Class 变量

静态/类变量属于类, 但是它们的值可以被子类继承. 和实例变量一样声明, 但使用 static 关键字:

static ClassVar := Expression

这些声明只在初始化类时被计算一次. 为此, 会自动定义一个名为 __Init 的静态方法.

每个声明都像普通的属性赋值一样, 以类对象为目标. Expression 与实例变量的解释相同, 除了 this 引用类本身.

如果要在其他任何地方给类变量赋值, 请始终指定类对象; 例如, ClassName.ClassVar := Value. 如果一个子类不拥有该名称的属性, Subclass.ClassVar 也可以用来检索值; 因此, 如果该值是对象的引用, 则默认情况下子类将共享该对象. 然而, Subclass.ClassVar := y 将值存储在 Subclass, 而不是 ClassName 中.

支持形如 x.y := z 的声明, 但前提是 x 已在类中定义. 如: static x:={},x.y:=42 声明了 x 并初始化了ClassName.x.y. 因为 Prototype 是在每个类中隐式定义的, static Prototype.sharedValue := 1 可以用来设置由类的所有实例动态继承的值(直到被实例本身的一个属性所覆盖)

嵌套类

嵌套类定义允许类对象与外部类的静态/类变量关联, 而不是与单独的全局变量关联. 在上面的例子中, class NestedClass 构造了一个类对象并将其存储在 ClassName.NestedClass. 子类可以继承 NestedClass 也可以用自己的嵌套类覆盖它(在这种情况下, 可以使用 WhichClass.NestedClass() 实例化任何合适的类).

class NestedClass
{
    ...
}

嵌套一个类并不意味着与外部类有任何特殊的关系. 嵌套类不会自动实例化, 嵌套类的实例也不会与外部类的实例有任何连接, 除非脚本显式地建立连接.

每个嵌套类定义都使用 get 和 call 访问函数生成动态属性, 而不是简单的值属性. 这是为了支持以下行为(其中类 X 包含嵌套类 Y):

  • X.Y() 不会将 X 传递给 X.Y.Call, 并最终传递给 __New, 否则会发生这种情况, 因为这是作为方法调用的函数对象的正常行为(这就是这里使用嵌套类的方式).
  • X.Y := 1 默认为错误(该属性为只读).
  • 第一次引用或调用类会使其初始化.

方法

方法定义看起来和函数定义相同. 每个方法定义都会创建一个 Func, 带有名为 this 的隐藏的第一个参数, 同时还定义了一个属性, 用于调用该方法或检索其函数对象.

有两种类型的方法:

  • 实例方法定义如下, 并附加到类的原型, 这使得它们可以通过类的任何实例进行访问. 当方法被调用时, this 引用类的一个实例.
  • 静态方法是在方法名之前加上独立的关键字 static 来定义的. 它们被附加到类对象本身, 但也被子类继承, 所以 this 要么引用类本身, 要么引用子类.

下面的方法定义创建了一个与 target.DefineProp('Method', {call: funcObj}) 相同类型的属性. 默认情况下, target.Method 返回 funcObj, 而试图赋值到 target.Method 会抛出错误. 这些默认值可以通过定义属性或调用 DefineProp 来覆盖.

Method()
{
    ...
}

胖箭头语法可以用来定义一个单行方法, 返回一个表达式:

Method() => Expression

Super

在方法或属性的 getter/setter 中, 关键字 super 可以代替 this 来访问在派生类中被重写的方法或属性的超类版本. 例如, 上面定义的类中的 super.Method() 通常会调用 BaseClassName 中定义的 Method 的版本. 注意:

  • super.Method() 总是调用与当前方法的原始定义相关联的类或原型对象的基, 即使 this 是从该类的 subclass 或其他一些完全的类派生出来的.
  • super.Method() 隐式地将 this 作为第一个(隐藏的) 参数.
  • 由于不知道 ClassName 在基对象链中的位置(或是否存), ClassName 本身被用作起点. 因此, super.Method() 主要等同于 (ClassName.Prototype.base.Method)(this)(但当 Method 是静态时, 没有 Prototype). 然而, ClassName.Prototype 在加载时被解析.
  • 如果该属性没有在超类中定义, 或者不能被调用, 则抛出错误.

关键字 super 后面必须有下列符号之一: .[(.

super() 等同于 super.call().

属性

属性定义创建一个动态属性, 它会调用一个方法, 而不是简单地存储或返回一个值.

Property[Parameters]
{
    get {
        return 属性值
    }
    set {
        存储或以其他方式处理 值
    }
}

Property 是用户定义的名称, 用于标识属性. 如, obj.Property 将调用 get, 而 obj.Property := value 将调用 set. 在 get 或 set 内, this 指向被引用的对象. set, value 中包含正要赋予的值.

参数可以通过将它们括在属性名称右侧的方括号中来定义, 并以相同的方式传递(但在无参数时应省略). 除了使用方括号这点不同, 属性参数的定义方法与方法参数相同 - 支持可选参数, ByRef 和可变参数.

如果调用了一个带参数的属性, 但没有定义任何参数, 参数将自动转发给 get 返回的对象的 __Item 属性. 例如, this.Property[x] 与 (this.Property)[x] 或 y := this.Property, y[x] 具有相同的效果. 空方括号(this.Property[]) 总是会导致调用 __Item 属性的 属性值, 但是像 this.Property[args*] 这样的可变数量调用只有在参数数为非零的情况下才会有这种效果.

静态属性可以在属性名之前加上独立的关键字 static 来定义. 在这种情况下, this 指的是类本身或子类.

set 的返回值会被忽略. 例如, val := obj.Property := 42 总是赋值 val := 42 不管该属性做什么, 除非它抛出异常或退出线程.

每个类可定义部分或完整的属性. 如果一个类覆盖了属性, 可用 super.Property 访问其基类中定义的属性. 如果没有定义 Get 或 Set, 则可以从基对象继承它. 如果没有定义 Get, 则属性可以返回从基继承的值. 如果在该类和所有基对象中没有定义 Set(或被继承的值属性所掩盖), 尝试设置该属性会导致抛出异常.

同时具有 get 和 set 的属性定义实际上创建了两个独立的函数, 它们不共享局部或静态变量或嵌套函数. 与方法一样, 每个函数都有一个名为 this 的隐藏参数, 而 set 有名为 value 的第二个隐藏参数. 任何显式定义的参数都在这些参数之后.

属性定义以与 DefineProp 相同的方式定义属性的 get 和 set 访问函数, 而方法定义则定义 call 访问函数. 任何类都可以包含同名的属性定义和方法定义. 如果调用一个没有 call 访问函数的属性(方法), 则以没有参数的方式调用 get, 然后将结果作为方法调用.

胖箭头属性

胖箭头语法可以用来定义 getter 或 setter 属性, 它返回一个表达式:

ShortProperty[Parameters]
{
    get => 计算属性值的表达式
    set => 存储或以其他方式处理 值 的表达式
}

当只定义 getter 时, 大括号和 get 可以省略:

ShorterProperty[Parameters] => 计算属性值的表达式

在这两种情况下, 除非定义了参数, 否则必须省略方括号.

__Enum 方法

__Enum(NumberOfVars)

当对象被传递给 for-loop 时, 将调用 __Enum 方法. 此方法应返回一个枚举器, 该枚举器将返回对象包含的项, 如数组元素. 如果未定义, 则不能将对象直接传递给 for-loop, 除非它具有枚举器-兼容的 Call(调用) 方法.

NumberOfVars 包含传递给 for-loop 的变量数量. 如果 NumberOfVars 为 2, 则期望枚举器将项的键或索引分配给第一个参数, 将值分配给第二个参数. 每个键或索引都应该作为 __Item 属性的参数而被接受. 这使基于 DBGp 的调试器能够通过调用枚举器列出它们之后可以获取或设置特定项.

__Item 属性

当索引操作符(数组语法) 与对象一起使用时, 将调用 _item 属性. 在下面的示例中, 属性被声明为静态的, 以便可以在 Env 类本身上使用索引运算符. 有关另一个例子, 请参阅 Array2D.

class Env {
    static __Item[name] {
        get => EnvGet(name)
        set => EnvSet(name, value)
    }
}

 Env["PATH"] .= ";" A_ScriptDir  ; 只影响此脚本和子进程.
MsgBox Env["PATH"]

__Item 实际上是一个默认属性名(如果已经定义了这样一个属性):

  • 当有参数时 object[params] 等同于 object.__Item[params].
  • object[] 等同于 object.__Item.

例如:

obj := {}
obj[] := Map()     ; 等同于 obj.__Item := Map()
obj["base"] := 10
MsgBox obj.base = Object.prototype  ; True
MsgBox obj["base"]                  ; 10

注意: 当显式属性名与空括号组合时, 如 obj.prop[], 它是作为两个独立的操作来处理的: 首先检索 obj.prop, 然后调用结果的默认属性. 这是语言语法的一部分, 所以不依赖于对象.

创建和销毁

每当使用 ClassName() 的默认实现创建对象时, 都会调用新对象的 __New 方法, 以便允许自定义初始化. 传递给 ClassName() 的任何参数都会被转发到 __New, 因此可能会影响对象的初始内容或如何构造它. 销毁对象时, 则调用 __Delete. 例如:

m1 := GMem(0, 10)
m2 := {base: GMem.Prototype}, m2.__New(0, 30)

; 注意: 对于一般的内存分配, 请使用 Buffer().
class GMem
{
    __New(aFlags, aSize)
    {
        this.ptr := DllCall("GlobalAlloc", "UInt", aFlags, "Ptr", aSize, "Ptr")
        if !this.ptr
            throw MemoryError()
        MsgBox "New GMem of " aSize " bytes at address " this.ptr "."
    }

    __Delete()
    {
        MsgBox "Delete GMem at address " this.ptr "."
        DllCall("GlobalFree", "Ptr", this.ptr)
    }
}

__Delete 不可被任何具有属性名 "__Class" 的对象所调用. 原型对象默认包含该属性.

如果在 __Delete 执行时抛出了异常或运行时错误, 并且未在 __Delete 中处理, 则它就像从一个新线程调用 __Delete. 也就是说, 显示一个错误对话框并 __Delete 返回, 但是线程不会退出(除非它已经退出).

如果脚本被任何方式直接终止, 包括托盘菜单或 ExitApp, 任何尚未返回的函数都没有机会返回. 因此, 这些函数的局部变量所引用的任何对象都不会被释放, 所以 __Delete 也不会被调用. 在这种情况下, 表达式求值栈上的临时引用也不会被释放.

当脚本退出时, 全局变量和静态变量所包含的对象会按照任意的, 实现定义的顺序自动释放. 当 __Delete 在这个过程中被调用时, 一些全局变量或静态变量可能已经被释放, 但对象本身包含的任何引用仍然有效. 因此 __Delete 最好是完全自包含的, 而不依赖于任何全局变量或静态变量.

类初始化

当对类的引用第一次计算时, 每个类都会被自动初始化. 例如, 如果 MyClass 还没有初始化, MyClass.MyProp 会导致类在属性被检索之前被初始化. 初始化包括调用两个静态方法: __Init 和 __New.

static __Init 是为每个类自动定义的, 并且如果指定了基类, 则始终以对基类的引用开始, 以确保它被初始化. 静态/类变量和嵌套类按照它们被定义的顺序进行初始化, 除非在前一个变量或类初始化期间引用了嵌套类.

如果类定义或继承了一个 static __New 方法, 则在 __Init 之后立即被调用. 需要注意的是, __New 可以为定义它的类调用一次, 而 为每个没有定义它的子类调用一次(或调用 super.__New()). 这可以用来为每个子类执行共同的初始化任务, 或者在使用子类之前以某种方式修改它们.

如果 static __New 不打算作用于派生类, 这可以通过检查 this 的值来避免. 在某些情况下, 使用方法删除本身就足够了, 比如用 this.DeleteProp('__New'); 然而, 如果一个子类嵌套在基类中, 或者在静态/类变量的初始化过程中被引用, 那么 __New 的第一次执行可能是针对一个子类.

一个类的定义也有引用类的效果. 换句话说, 当脚本启动期间执行达到类定义时, 除非脚本已经引用了该类, 否则会自动调用 __Init 和 __New. 但是, 如果执行被阻止到达类的定义, 例如通过 return 或无限循环, 那么只有当类被引用时才会被初始化.

一旦自动初始化开始, 它就不会再发生在同一个类上. 这通常不是一个问题, 除非多个类相互引用. 例如, 考虑下面的两个类. 当 A 先被初始化时, 计算 B.SharedArray (A1) 会导致 B 在检索和返回值之前被初始化, 但是 A.SharedValue (A3) 是未定义的并且不会导致 A 的初始化, 因为它已经在进行了. 换句话说, 如果 A 先被访问或初始化, 顺序是 A1 到 A3; 否则是 B1 到 B4:

MsgBox A.SharedArray.Length
MsgBox B.SharedValue

class A {
    static SharedArray := B.SharedArray   ; A1          ; B3
    static SharedValue := 42                            ; B4
}

class B {
    static SharedArray := StrSplit("XYZ") ; A2          ; B1
    static SharedValue := A.SharedValue   ; A3 (Error)  ; B2
}

元函数

class ClassName {
    __Get(Name, Params)
    __Set(Name, Params, Value)
    __Call(Name, Params)
}
Name

属性或方法的名称.

Params

参数数组. 这只包括 () 或 [] 之间的参数, 所以可能是空的. 元函数被期望处理诸如 x.y[z] 这样的情况, 其中 x.y 是未定义的.

Value

被赋值的值.

元函数定义了调用未定义的属性或方法时会发生什么. 例如, 如果 obj.unk 没有被赋值, 那么它会调用 __Get 元函数. 同样地, obj.unk := value 调用 __Set, 而 obj.unk() 调用 __Call.

属性和方法可以在对象本身或其任何基对象中定义. 通常, 要为每个属性调用一个元函数, 必须避免定义任何属性. 可以使用属性定义或 DefineProp 来覆盖内置属性(如 Base).

如果定义了一个元函数, 它必须执行任何所需的默认操作. 例如, 可能会出现以下情况:

  • Call: 抛出 MethodError.
  • 如果给出了参数, 则抛出异常(没有对象可将参数转发到).
  • Get: 抛出 PropertyError.
  • Set: 使用给定值定义一个新属性, 例如通过调用 DefineProp.

任意可调用对象可用作元函数, 通过将其赋值给相关属性.

在以下情况下, 不调用元函数:

  • x[y]: 使用不带属性名称的方括号仅会调用 __Item 属性.
  • x(): 调用对象本身仅会调用 Call 方法. 这包括内置函数(如 SetTimer 和 Hotkey) 进行的内部调用.
  • 对其他元函数或双下划线方法的内部调用不会触发 __Call.

动态属性

属性语法和 DefineProp 可用于定义属性, 这些属性在每次求值时计算出一个值, 但是必须预先定义每个属性. 相比之下, __Get 和 __Set 可用于实现只有在调用时才知道的属性.

例如, 可以创建 "代理" 对象, 该对象通过网络(或者是其他通道) 发送对属性的请求. 远程服务器将返回一个包含属性值的响应, 然后代理将把该值返回给调用者. 虽然每个属性名称都是提前知道的, 但也不必单独定义每个属性, 因为每个属性所做的事都一样(发送一个网络请求). 元函数接受属性名称作为参数, 所以是这种情况的最佳解决方案.

原始值

原始值, 如字符串和数字, 不能有自己的属性和方法. 然而, 原始值支持与对象相同类型的委托. 也就是说, 对原始值的任何属性或方法调用都被委托给预定义的原型对象, 也可以通过相应类的 Prototype 属性访问. 以下类与原始值相关:

  • 原始值 (继承 Any)
    • 数字
      • 浮点数
      • 整数
    • 字符串

虽然检查字符串的类型通常更快, 但是可以通过检查值是否具有给定的基来测试值的类型. 例如, 如果 n 是一个纯整数或浮点数, 则 n.HasBase(Number.Prototype) 或 n is Number 为真, 但如果 n 是一个数字字符串, 则不为真, 因为字符串不是从数字派生而来的. 相比之下, 如果 n 是数字或数字字符串, IsNumber(n) 为真.

ObjGetBase 和 Base 属性在适当的时候返回预定义的原型对象之一.

注意, 对于 AutoHotkey 的类型层次结构中的任何值, x is Any 通常为真, 而对于 COM 对象则为假.

添加属性和方法

通过修改该类型的原型对象, 可以为该类型的所有值添加属性和方法. 但是, 由于原始值不是对象并且不能具有自己的属性或方法, 因此原始原型对象不会从 Object.Prototype 派生. 换句话说, 默认情况下无法访问诸如 DefineProp 和 HasOwnProp 之类的方法. 可以间接调用它们. 例如:

DefProp := {}.DefineProp
DefProp( "".base, "Length", { get: StrLen } )
MsgBox A_AhkPath.length " == " StrLen(A_AhkPath)

尽管原始值可以从其原型继承值属性, 但是如果脚本尝试在原始值上设置值属性, 则会引发异常. 例如:

"".base.test := 1  ; 不要轻易尝试.
MsgBox "".test  ; 1
"".test := 2  ; 错误: 属性是只读的.

尽管可以使用 __Set 和属性设置器, 但它们没有用, 因为应将原始值视为不可变的.

实现

引用计数

当脚本不再引用对象时, AutoHotkey 使用基本的引用计数机制来自动释放对象所使用的资源. 理解这种机制对于正确管理对象的生命周期至关重要, 从而允许在不再需要时删除对象, 而不是在此之前删除对象.

每当存储引用时, 对象的引用计数就会增加. 当一个引用被释放时, 计数用于确定该引用是否是最后一个引用. 如果是, 则删除该对象; 否则, 计数递减. 下面的例子展示了在一些简单的情况下如何计算引用:

a := {Name: "Bob"}  ; Bob 的引用计数为 1
b := [a]            ; Bob 的引用计数增加到 2
a := ""             ; Bob 的引用计数减为 1
c := b.Pop()        ; Bob 被转换, 引用计数仍为 1
c := ""             ; Bob 被删除...

表达式中的函数, 方法或运算符返回的临时引用在表达式的计算完成或中止后释放. 在下面的例子中, 新的 GMem 对象只有在 MsgBox 返回后才被释放.

MsgBox DllCall("GlobalSize", "ptr", GMem(0, 20).ptr, "ptr")  ; 20

注意: 在本例中, .ptr 可以省略, 因为 Ptr 参数类型允许对象具有 Ptr 属性. 但是, 上面显示的模式甚至可以用于其他属性名.

如果希望在对象的最后一个引用被释放后运行一段代码, 可通过 __Delete 元函数实现.

引用计数的问题

仅仅依赖引用计数有时会造成 catch-22 的情况: 对象被设计为在删除时释放其资源, 但只有在其资源首次被释放时才会被删除. 具体来说, 当这些资源是其他对象或函数时, 通常会间接地保留对对象的引用.

循环引用 或 引用循环 是指对象直接或间接地引用自身. 如果作为循环一部分的每个引用都包含在计数中, 那么除非手动中断循环, 否则无法删除该对象. 例如, 下面的代码创建了一个引用循环:

parent := {}  ; parent: 1(引用计数)
child := {parent: parent}  ; parent: 2, child: 1
parent.child := child  ; parent: 2, child: 2

如果变量 parent 和 child 被重新赋值, 每个对象的引用计数将递减为 1. 脚本将无法访问这两个对象, 但不会删除它们, 因为最后的引用没有被释放.

循环通常不那么明显, 并且可能涉及多个对象. 例如, ShowRefCycleGui 演示了一个包含 Gui, MenuBar, Menu 和 closures 的循环. 如果处理程序对象有对图形用户界面的引用, 使用单独的对象处理图形用户界面事件也容易造成循环.

对对象的非循环引用也可能造成问题. 例如, 依赖于 SetTimer 或 OnMessage 等内置函数的对象通常会导致程序持有对该对象的间接引用. 这将防止对象被删除，这意味着它不能使用 __New 和 __Delete 来管理计时器或消息监视器.

下面是解决上述问题的几个策略.

避免循环: 如果引用循环有问题, 请避免创建它们. 例如, 不设置 parent.child 或 child.parent. 这往往不切实际, 因为相关对象可能需要一种相互引用的方法.

当为 OnEvent(Gui) 定义事件处理程序时, 避免在闭包或绑定函数中捕获源 Gui, 而是利用 Gui 或 Gui.Control 参数. 对于 Add(Menu) 和回调的 Menu 参数也是如此, 当然, 需要引用 Gui 的菜单项不能使用这种方法.

在某些情况下, 可以通过不依赖于计数引用的间接方法检索另一个对象. 例如, 保留一个 HWND 并使用 GuiFromHwnd(hwnd) 来检索一个 Gui 对象. 在窗口可见时, 保留引用对于防止删除是不必要的, 因为 Gui 本身可以处理这个问题.

中断循环: 如果脚本可以避免依赖引用计数, 而是直接管理对象的生命周期, 那么它只需要在对象被删除时打破这个循环:

child.parent := unset  ; parent: 1, child: 2
child := unset  ; parent: 1, child: 1
parent := unset  ; both deleted

Dispose: __Delete 在最后一个引用被释放时被调用, 因此人们可能会认为像 myGui := "" 这样的简单赋值是触发对象删除的清理步骤. 有时, 当不再需要对象时, 我们会显式地执行此操作, 但它既不可靠, 也不能真正显示代码的意图. 另一种模式是定义一个释放对象资源的 Dispose 或 Destroy 方法, 并将其设计为在第二次调用时不做任何事情. 然后也可以从 __Delete 调用它, 作为保护措施.

遵循此模式的对象在被 disposed 时仍然需要打破任何引用循环, 否则一些内存将不会被回收, 而且该对象引用的其他对象也不会调用 __Delete 方法.

在调用 Destroy 时, 由 Gui 对象的事件处理程序, 菜单栏或事件接收对象引起的循环会自动 "中断", 因为它释放了这些对象. (在 ShowRefCycleGui 示例中演示了这一点.) 然而, 这不会破坏脚本添加的新属性引起的循环, 因为 Destroy 并不会删除它们.

与 Dispose 模式类似, InputHook 有一个必须显式调用的 Stop 方法, 因此它不依赖于 __Delete 来表示其操作何时应该结束. 在操作时, 程序实际上保留了对对象的引用, 以防止对象被删除, 但这成为一种优势而不是缺陷: 事件回调仍然可以被调用, 并将接收 InputHook 作为参数. 当操作结束时, 如果脚本没有对 InputHook 的引用，则释放内部引用, 并删除 InputHook.

指针: 存储任意数量的指针值都不会影响对象的引用计数, 因为指针只是一个整数. 使用 ObjPtr 获取的指针可以通过将其传递给 ObjFromPtrAddRef 来生成引用. 必须使用该函数的 AddRef 版本, 因为当临时引用自动释放时, 引用计数将递减.

例如, 假设一个对象需要每秒更新一些属性. 计时器保存对回调函数的引用, 该回调函数将对象绑定为参数. 通常, 这将防止在删除计时器之前删除对象. 存储指针而不是引用允许对象在不考虑计时器的情况下被删除, 因此它可以通过 __New 和 __Delete 自动管理.

a := SomeClass()
Sleep 5500  ; 让计时器运行 5 次.
a := ""
Sleep 3500  ; 防止暂时退出以显示计时器已停止.

class SomeClass {
  __New() {
        ; 必须存储闭包, 以便以后可以删除计时器.
        ; 每次需要调用方法时, 合成一个计数引用.
        this.Timer := (p => ObjFromPtrAddRef(p).Update()).Bind(ObjPtr(this))
        SetTimer this.Timer, 1000
    }
  __Delete() {
        SetTimer this.Timer, 0
        ; 如果该对象被真正删除, 则所有属性将被删除
        ; 并调用以下 __Delete 方法.
        ; 这只是为了确认, 通常不会使用.
        this.Test := {__Delete: test => ToolTip("object deleted")}
    }
    ; 这只是为了演示计时器正在运行.
    ; 假设这个类还有其他用途.
    count := 0
  Update() => ToolTip(++this.count)
}

这种方法的缺点是指针不能直接作为对象使用, 并且不能被 Type 或调试器识别为对象. 脚本必须绝对确定在对象删除后不使用指针, 因为这样做是无效的, 并且结果将是不确定的.

如果在多个地方都需要指针引用, 那么封装它可能是有意义的. 例如, b := ObjFromPtrAddRef.Bind(ObjPtr(this)) 将产生一个 BoundFunc, 可以调用(b()) 来检索引用, 而 ((this, p) => ObjFromPtrAddRef(p)).Bind(ObjPtr(this)) 可以用作属性 getter(属性将返回一个引用).

未计数引用: 如果对象的引用计数包含引用, 则称其为 计数引用, 否则称其为 未计数引用. 后者的思想是允许脚本存储一个引用, 但不妨碍对象被删除.

注意: 这是关于对象的引用计数如何根据脚本的逻辑与给定引用相关, 并且不影响引用本身的性质. 程序仍然会尝试在正常情况下自动释放引用, 因此 弱引用 和 强引用 这两个术语并不合适.

计数引用可以通过简单地递减对象的引用计数变成未计数引用. 这 必须 在释放引用之前反转, 而释放引用 必须 在对象被删除之前发生. 由于未计数引用的目的是允许在不首先手动取消引用的情况下删除对象, 因此通常必须在该对象自己的 __Delete 方法中纠正计数.

例如, 上一个示例中的 __New 和 __Delete 可以用下面的方法代替.

  __New() {
        ; 必须存储 BoundFunc, 以便以后删除计时器.
        SetTimer this.Timer := this.Update.Bind(this), 1000
        ; 减少 ref 计数, 以补偿 Bind 执行的 AddRef.
        ObjRelease(ObjPtr(this))
    }
  __Delete() {
        ; 增加 ref 计数, 以便可以安全地释放 BoundFunc
        ; 中的 ref.
        ObjPtrAddRef(this)
        ; 删除计时器, 释放对 BoundFunc 的引用.
        SetTimer this.Timer, 0
        ; 释放 BoundFunc.
        ; 由于 BoundFunc 中的循环引用已被重新计算
        ; 这可能不会自动发生.
        this.Timer := unset
        ; 如果该对象真的被删除, 所有属性都将被删除
        ; 并将调用下面的 __Delete 方法.
        ;  这只是为了确认, 通常不会使用.
        this.Test := {__Delete: test => ToolTip("object deleted")}
    }

无论未计数的引用存储在何处以及它的用途如何, 通常都可以应用此方法. 关键是:

  • 存储引用 后 减少引用计数(释放).
  • 在取消引用 前 增加引用计数(AddRef).
  • 在 __Delete 返回之前显式取消对引用的设置(在调用它之前这样做是可以的).

引用计数的递增和递减次数必须与未计数的引用次数相同. 如果脚本不能准确地预测某个函数将存储多少引用, 那么这样做可能是不切实际的.

对象的指针

作为创建对象的一部分, 分配一些内存来保存对象的基本结构. 这个结构体本质上就是对象本身, 所以我们称它的地址为 指向对象的指针. 地址是一个整数值, 它对应于当前进程的虚拟内存中的一个位置, 并且只在对象被删除之前有效.

在一些罕见的情况中, 可能需要通过 DllCall 传递对象到外部代码或把它存储到二进制数据结构以供以后检索. 可以通过 address := ObjPtr(myObject) 来检索对象的地址; 不过, 这样实际上创建了一个对象的两个引用, 但程序只知道对象中的一个. 如果对象的最后一个 已知 引用被释放, 该对象将被删除. 因此, 脚本必须设法通知对象它的引用增加了. 可以这样做(下面两行是等同的):

ObjAddRef(address := ObjPtr(myObject))
address := ObjPtrAddRef(myObject)

脚本还必须在对象使用该引用完成时通知该对象:

ObjRelease(address)

一般来说, 对象地址的每个新副本都应该被视为对象的另一个引用, 所以脚本必须在获得副本之后立即调用 ObjRelease, 并在丢弃副本之前立即调用 ObjRelease. 例如, 每当通过类似 x := address 这样复制地址时, 就应该调用一次 ObjAddRef. 同样的, 当脚本使用 x 完时(或者用其他值覆盖 x), 就应该调用一次 ObjRelease.

要将地址转换为一个合适的引用, 请使用 ObjFromPtr 函数:

myObject := ObjFromPtr(address)

ObjFromPtr 假定 address 是一个引用计数, 并声称对它的所有权. 换句话说, myObject := "" 会导致原本由 address 代表的引用被释放. 之后, address 必须被认为是无效的. 如果要改用一个新的引用, 可以使用下面的一种方法:

ObjAddRef(address), myObject := ObjFromPtr(address)
myObject := ObjFromPtrAddRef(address)


内置的类 | AutoHotkey v2

内置的类

  • Any
    • Object
      • Array
      • Buffer
        • ClipboardAll
      • Class
      • Error
        • MemoryError
        • OSError
        • TargetError
        • TimeoutError
        • TypeError
        • UnsetError
          • MemberError
            • PropertyError
            • MethodError
          • UnsetItemError
        • ValueError
          • IndexError
        • ZeroDivisionError
      • File
      • Func
        • BoundFunc
        • Closure
        • Enumerator
      • Gui
      • Gui.Control
        • Gui.ActiveX
        • Gui.Button
        • Gui.CheckBox
        • Gui.Custom
        • Gui.DateTime
        • Gui.Edit
        • Gui.GroupBox
        • Gui.Hotkey
        • Gui.Link
        • Gui.List
          • Gui.ComboBox
          • Gui.DDL
          • Gui.ListBox
          • Gui.Tab
        • Gui.ListView
        • Gui.MonthCal
        • Gui.Pic
        • Gui.Progress
        • Gui.Radio
        • Gui.Slider
        • Gui.StatusBar
        • Gui.Text
        • Gui.TreeView
        • Gui.UpDown
      • InputHook
      • Map
      • Menu
        • MenuBar
      • RegExMatchInfo
    • Primitive
      • Number
        • Float
        • Integer
      • String
    • VarRef
    • ComValue
      • ComObjArray
      • ComObject
      • ComValueRef


程序的使用 | AutoHotkey v2

程序的使用

AutoHotkey 程序本身不做任何事情; 它需要一个脚本来告诉它该做什么. 脚本只是一个简单的以 .ahk 作为扩展名的文本文件, 其中包含了程序的指令, 像配置文件, 但功能更强大. 一个脚本可以执行一个动作然后退出, 但大多数脚本定义了一些热键, 当热键按下时, 热键后面跟着的一个或多个动作将会执行.

#z::Run "https://www.autohotkey.com"  ; Win+Z

^!n::  ; Ctrl+Alt+N
{
    if WinExist("Untitled - Notepad")
        WinActivate
    else
        Run "Notepad"
}

提示: 如果您的浏览器支持, 当你将鼠标悬停在代码块上面时, 您可以通过点击代码块右上角的按钮 ↓ 来下载任何代码块(如上面的代码块) 作为脚本文件.

目录

  • 创建脚本
  • 编辑脚本
  • 运行脚本
  • 托盘图标
  • 主窗口
  • 嵌入脚本
  • 命令行用法
  • AutoHotkey.exe 的可移植性
  • 启动器
  • Dash
  • 新建脚本
  • 安装
    • 以 UI 访问权限运行

创建脚本

有一些常见的方法来创建脚本文件:

  • 在记事本(或你选择的文本编辑器) 中, 使用 .ahk 文件扩展名保存文件. 在某些系统上, 您可能需要将文件名用引号括起来, 以确保编辑器不会添加其他扩展名(例如 .txt).

    如果文件包含非 ASCII 字符, 请确保将文件保存为带有 BOM(字节顺序标记) 的 UTF-8. 有关详情, 请参阅常见问题(FAQ).

  • 在资源管理器, 希望保存脚本的文件夹中的空白区域右键单击, 然后选择 新建 和 AutoHotkey Script. 然后, 您可以输入脚本的名称(注意, 如果 .ahk 扩展名可见时, 请不要删掉它).
  • 在 Dash, 选择 New script, 为脚本输入名称(不包括 .ahk 扩展名), 然后单击 Create 或 Edit. 可以在此窗口中配置用于创建脚本的模板和保存脚本的位置, 并根据需要将其设置为默认值.

有关如何编写脚本的详细信息, 请参阅脚本语言.

编辑脚本

要打开脚本进行编辑, 请右键单击脚本文件, 然后选择 Edit Script(编辑脚本). 如果脚本已经在运行, 您可以使用 Edit(编辑) 函数或右键单击脚本的托盘图标并选择 Edit Script(编辑脚本). 如果您还没有选择默认编辑器, 系统将提示您选择一个. 否则, 您可以在 Dash 中通过 Editor settings 更改默认编辑器. 当然, 您可以先打开文本编辑器, 然后像打开其他任何文本文件一样打开脚本.

编辑脚本保存后, 您必须运行或 reload(重新加载) 脚本以使更改生效. 正在运行的脚本通常可以通过其托盘菜单重新加载.

运行脚本

安装了 AutoHotkey 后, 有几种运行脚本的方法:

  • 双击资源管理器中的脚本文件(或脚本文件的快捷方式).
  • 在命令行中调用 AutoHotkey.exe, 并将该脚本的文件名(路径) 作为命令行参数.
  • 创建默认脚本后, 通过 "开始" 菜单中的快捷方式启动 AutoHotkey 以运行它.
  • 如果 AutoHotkey 固定在 Windows 7 或更高版本系统的任务栏或 "开始" 菜单上, 则可以通过程序跳转列表打开最近的或已固定的脚本.

大多数脚本只有在运行时才会起作用. 使用托盘菜单或 ExitApp 函数退出脚本. 当 Windows 关闭时, 脚本也被迫退出. 要将脚本配置为在用户登录后自动启动, 最简单的方法是在 Startup(启动) 文件夹中放置脚本文件的快捷方式.

脚本也可以编译; 即与 AutoHotkey 二进制文件结合在一起, 形成一个独立的可执行(.exe) 文件.

托盘图标

默认情况下, 每个脚本都将自己的图标添加到任务栏通知区域(通常称为托盘).

托盘图标通常看起来像这样:

green H icon | 默认的托盘图标.
green icon with a Pause symbol | 脚本暂停.
green icon with a transparent H | 脚本挂起.
green icon with a transparent Pause symbol | 脚本暂停和挂起.

右键单击托盘图标以显示托盘菜单, 默认情况下具有以下选项:

  • Open - (打开) - 打开脚本的主窗口.
  • Help - (帮助) - 打开 AutoHotkey 离线帮助文件.
  • Window Spy - (窗口监视器) - 显示关于窗口的各种信息.
  • Reload Script - (重载脚本) - 请参阅 Reload.
  • Edit Script - (编辑脚本) - 请参阅 Edit.
  • Suspend Hotkeys - (挂起热键) - Suspend 或取消挂起热键.
  • Pause Script - (暂停脚本) - Pause 或取消暂停脚本.
  • Exit - (退出) - 退出脚本.

默认情况下, 双击托盘图标显示脚本的主窗口.

可以自定义托盘图标和菜单的行为和外观:

  • A_TrayMenu 返回 Menu 对象, 可以用来自定义托盘菜单.
  • A_IconHidden 或 #NoTrayIcon 指令可用于隐藏(或显示) 托盘图标.
  • A_IconTip 可以为托盘图标分配新的工具提示文本.
  • TraySetIcon 可以用来改变图标.

主窗口

脚本的主窗口通常是隐藏的, 但可以通过托盘图标或下面列出的函数之一显示, 以获得对调试脚本有用的信息. View 菜单下的项目控制主窗口显示的内容:

  • Lines most recently executed - (最近执行的行) - 请参阅 ListLines.
  • Variables and their contents - (变量和它们的内容) - 请参阅 ListVars.
  • Hotkeys and their methods - (热键和它们的方法) - 请参阅 ListHotkeys.
  • Key history and script info - (按键历史和脚本信息) - 请参阅 KeyHistory.

已知问题: 当脚本显示消息框或其他对话框时, 菜单项下的键盘快捷键不起作用.

内置变量 A_ScriptHwnd 包含脚本主窗口的唯一 ID(HWND).

用 WinClose(甚至从另一个脚本或其他程序) 关闭这个窗口会导致脚本退出, 但大多数其他方法只是隐藏窗口并保持脚本运行.

最小化主窗口会使其自动隐藏. 这样做是为了防止将所有拥有的窗口(如 GUI 窗口或某些对话框窗口) 自动最小化, 但也有隐藏主窗口的任务栏按钮的效果. 要让主窗口正常最小化, 可以用 OnMessage 覆盖默认的处理方式. 例如:

; 这样可以防止主窗口在最小化时隐藏:
OnMessage 0x0112, PreventAutoMinimize ; WM_SYSCOMMAND = 0x0112
OnMessage 0x0005, PreventAutoMinimize ; WM_SIZE = 0x0005
; 这样可以防止拥有的 GUI 窗口(但不包括对话框) 自动最小化:
OnMessage 0x0018, PreventAutoMinimize
Persistent

PreventAutoMinimize(wParam, lParam, uMsg, hwnd) {
    if (uMsg = 0x0112 && wParam = 0xF020 && hwnd = A_ScriptHwnd) { ; SC_MINIMIZE = 0xF020
        WinMinimize
        return 0 ; 防止主窗口隐藏.
    }
    if (uMsg = 0x0005 && wParam = 1 && hwnd = A_ScriptHwnd) ; SIZE_MINIMIZED = 1
        return 0 ; 防止主窗口隐藏.
    if (uMsg = 0x0018 && lParam = 1) ; SW_PARENTCLOSING = 1
        return 0 ; 防止最小化拥有的窗口.
}

主窗口标题

脚本主窗口的标题会被 #SingleInstance 和 Reload 机制用来识别同一脚本的其他实例. 更改标题可防止脚本被这样识别. 默认的标题取决于脚本的加载方式:

加载于 | 标题表达式 | 示例
.ahk 文件 | A_ScriptFullPath " - AutoHotkey v" A_AhkVersion | E:\My Script.ahk - AutoHotkey v1.1.33.09
主资源(编译的脚本) | A_ScriptFullPath | E:\My Script.exe
任何其他资源 | A_ScriptFullPath " - " A_LineFile | E:\My AutoHotkey.exe - *BUILTIN-TOOL.AHK

下面的代码说明了如何由脚本本身决定默认的标题(但实际的标题可以用 WinGetTitle 来检索):

title := A_ScriptFullPath
if !A_IsCompiled
    title .= " - AutoHotkey v" A_AhkVersion
; 为了获得正确的结果, 必须由被执行的资源来计算,
; 而不是一个 #include(除非这个 #include 是由 Ahk2Exe 合并到脚本中的):
else if SubStr(A_LineFile, 1, 1) = "*" && A_LineFile != "*#1"
    title .= " - " A_LineFile

嵌入脚本

通过使用 Ahk2Exe 编译器, 可以将脚本嵌入到标准的 AutoHotkey 的 .exe 文件, 方法是将它们作为 Win32(RCDATA) 资源来添加. 要添加其他脚本, 请参阅 AddResource 编译器指令.

嵌入的脚本可以在命令行中指定, 也可以使用 #Include 在星号(*) 后跟资源名称. 对于一个整数 ID, 资源名称必须是一个哈希符号(#), 后面是一个十进制数字.

程序可以自动从以下资源加载脚本代码, 如果存在于文件中:

ID | Spec | 用法
1 | *#1 | 这是一种从 .exe 文件创建编译脚本的方法. 该脚本是自动执行的, 大多数命令行开关会被传递给脚本, 而不是由程序解释. 外部脚本和可选的嵌入式脚本可以通过使用 /script 开关来执行.
2 | *#2 | 如果存在, 该脚本会在程序加载的任何脚本之前自动 "included", 以及在 /include 指定的任何文件之前.

当主脚本的源是一个嵌入式资源时, 程序以 "编译脚本" 模式运行, 但 A_AhkPath 总是包含当前可执行文件的路径(与 A_ScriptFullPath 相同). 对于 *#1 以外的资源, 资源指定符会包含在主窗口的标题中, 以支持 #SingleInstance 和 Reload.

当从嵌入资源的代码中引用时, A_LineFile 包含一个星号(*) 后跟资源名称.

命令行用法

有关命令行用法, 请参阅向脚本传递命令行参数, 其中包括影响程序行为的命令行开关列表.

AutoHotkey.exe 的可移植性

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

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

启动器

启动器可以在一个系统上使用 v1 和 v2 版本的脚本, 并使用一个文件扩展名, 而不必偏好一个版本, 也不需要用不同的方法来启动脚本. 它通过检查脚本以找到所需版本的线索, 然后定位一个适当的 exe 来运行脚本.

如果脚本包含 #Requires 指令, 启动器将寻找满足需求的 exe. 否则, 启动程序可选地检查语法. 也就是说, 它检查只在两个主要版本之一中有效的模式. 它可能发现的一些常见模式包括:

  • v1: MsgBox, with comma, MsgBox % "no end percent" 和 Legacy = assignment.
  • v1: 没有大括号或函数定义的多行热键.
  • 常见指令如 #NoEnv 和 #If(v1) 或 #HotIf(v2).
  • v2: 通过括号延续或行末延续操作符明确使用行延续.
  • v2: 在表达式中明确使用 '单引号' 或 胖箭头 =>.

检测是保守的; 如果一个案例是模棱两可的, 通常应该被忽略.

在任何检测失败的情况下, 默认会显示一个菜单让用户选择一个版本. 这个默认值可以改变为启动 v1 或 v2.

已知限制:

  • 只检查主文件.
  • 由于在 v1 中包含像 /****/ 这样的行是合法的, 但在 v2 中行尾的 */ 只能关闭注释, 所以这样的行的存在可能会导致脚本的大部分被忽略(被启动器和 v1 解释器忽略).
  • 只检查语法, 不检查语义. 例如, xyz, 在 v2 中是无效的, 所以被认为是有效的 v1 命令. xyz 1 在 v2 中可能是一个函数语句, 但被认为也是有效的 v1 命令, 因此被忽略.
  • 由于被检测到的模式实际上是一个版本中的语法错误, 一个有实际语法错误或不正确的混合语法的脚本可能被错误地识别出来.

注意: 在主文件的顶部用 #Requires 声明所需的版本, 可以消除任何歧义.

启动设置

启动器可以通过启动设置GUI来启用、禁用或配置，该GUI可以通过dash访问 dash.

使用特定的解释器运行所有脚本 将禁用启动程序, 并允许用户选择使用哪个 exe 来运行所有脚本, 这是传统的方式. 请注意, 选择 v1 exe 将使其难以运行任何支持脚本, 除非通过开始菜单中的 "AutoHotkey" 快捷方式.

启动脚本时的自动检测版本 将激活启动器. 其他设置可以控制启动器如何选择要使用的解释器.

Criteria

当找到具有相同版本号的多个解释器时, 启动器可以根据预先确定的或用户定义的一组条件对它们进行排序. 这些条件可以表示为以逗号分隔的子字符串列表, 其中每个子字符串可以用 "!" 作为前缀来否定匹配. 根据匹配的子串来计算得分, 最左边的子串具有最高的优先级.

子字符串在文件的描述中匹配, 但 "UIA" 除外, 如果文件名包含 "_UIA", 则匹配.

例如, _H, 64, !ANSI 倾向于 AutoHotkey_H(如果可用), 64-位(如果与系统兼容), 最后是 Unicode 而不是 ANSI.

尽管启动器设置 GUI 提供带有选项的下拉列表, 如 "Unicode 32-bit", 但可以手动输入子字符串列表.

可以使用 /RunWith 启动器开关在命令行上指定其他(更高优先级的) 条件.

可以在脚本中使用 #Requires 指令指定条件, 可以作为需求(如果目标 AutoHotkey 版本支持), 也可以作为以 "prefer" 开头, 以句号或行尾结尾的注释添加到指令中. 例如:

#Requires AutoHotkey v1.1.35 ; prefer 64-bit, Unicode. 更多的注释内容.

Run *Launch

安装程序注册一个名为 "launch" 的隐藏 shell 动词, 它使用 /Launch 开关执行启动程序. 它可以通过以下示例使用:

pid := RunWait('*Launch "' PathOfScript '"')

与 .ahk 文件的默认操作相比:

  • /Launch 导致新启动脚本的进程 ID(PID) 作为启动器的退出码返回, 而通常情况下, 它会返回启动脚本的退出码. Run 的 OutputVarPID 参数返回启动器的 PID.
  • /Launch 使启动器在启动脚本后立即退出. 如果没有使用 /Launch, 启动器通常必须假定它的父进程可能正在执行 RunWait(PathOfScript) 之类的操作, 如果启动器在启动脚本之前退出, 将无法正常工作.

命令行用法

如果 .ahk 文件没有默认设置使用启动程序, 或者为了更好地控制其行为, 可以在命令行显式地执行启动程序. 如果编译了启动程序, 它的用法基本上与 AutoHotkey.exe 相同, 除了附加的启动程序开关. 否则, 命令行使用格式如下:

AutoHotkeyUX.exe launcher.ahk [Switches] [Script Filename] [Script Parameters]

通常, AutoHotkeyUX.exe 和 launcher.ahk 的路径使用全路径和双引号, 可以在 AutoHotkey 安装的 UX 子目录中找到. 一个适当版本的 AutoHotkey32.exe 或 AutoHotkey64.exe 可以用来代替 AutoHotkeyUX.exe(这只是一个副本).

Switches 可以是任何标准开关和以下启动器专用开关的混合:

开关 | 意义
/Launch | 导致启动器在启动脚本后立即退出, 而不是在后台等待它终止. 启动器的退出代码是新脚本进程的进程 ID(PID).
/RunWith criteria | 指定用于确定要使用哪个可执行文件来启动脚本的附加 criteria. 例如, /RunWith UIA.
/Which

使启动器识别它将使用的解释器并返回它, 而不是运行脚本.

如果由 #Requires 或语法(如果启用了语法检测) 标识, 启动器的退出代码是主版本号(1 或 2), 否则为 0.

Stdout 接收以下 UTF-8 字符串, 每个字符串以 `n 结尾:

  • 版本号. 如果检测到 #Requires, 则这是它指定的任何数字, 不包括 "v". 否则, 它是一个与退出码相同的整数, 除非没有检测到版本, 在这种情况下, 该值为 0 表示用户会被提示, 1 或 2 表示在 Launch Settings 中配置的用户首选版本.
  • 如果找到解释器 EXE, 将使用的解释器 EXE 的路径. 如果用户被提示或没有找到兼容的解释器, 则此选项为空.
  • 启动器将插入的任何额外的命令行开关, 如 /CP65001.

将来可能会返回更多的行.

Dash

Dash 提供了对支持脚本和文档的访问. 它可以在安装后通过开始菜单中的 "AutoHotkey" 快捷方式打开, 或从安装目录 UX\ui-dash.ahk 直接运行. 目前它仅仅是一个包含以下项目的菜单, 但是它可以扩展为活动脚本或其他方便的功能提供控制.

  • New script(新建脚本): 从模板创建新脚本.
  • Compile(编译): 打开 Ahk2Exe, 或提供自动下载和安装它.
  • Help files (F1) (帮助文件): 显示一个菜单, 其中包含关于 v1 和 v2 的帮助文件和在线文档, 以及安装目录中找到的任何其他 CHM 文件.
  • Window spy
  • Launch settings(启动设置): 配置启动器.
  • Editor settings(编辑设置): 设置 .ahk 文件的默认编辑器.

注意, 尽管开始菜单快捷方式启动了 Dash, 如果它被固定在任务栏上(或在Windows 7或10的开始菜单上), 跳转列表将包括任何最近使用 open, runas 或 UIAccess 动词启动的脚本(通常通过资源管理器上下文菜单或双击文件来访问). 可以固定脚本以便于访问.

新建脚本

新建脚本 GUI 可以通过开始菜单中的 Dash 访问, 也可以在资源管理器中的文件夹中右键单击并选择新建 → AutoHotkey Script. 可以使用它从预先安装的或用户定义的模板创建一个新的脚本文件, 并可选择打开它进行编辑.

在列表中右键点击一个模板, 可以得到以下选项:

  • Edit template(编辑模板): 在默认编辑器中打开模板. 如果是预安装的模板, 则创建一个可编辑的副本, 而不是打开原始的.
  • Hide template(隐藏模板): 将模板名称添加到一个模板列表中, 该模板将不会显示在 GUI 中. 要取消隐藏模板, 请从 HKCU\Software\AutoHotkey\New\HideTemplate 中删除对应的注册表值.
  • Set as default(设置为默认值): 设置默认选择的模板.

默认情况下, 除非按住 Ctrl 键，否则 GUI 会在创建文件后关闭.

其他设置可以通过 GUI 左下角的设置按钮来访问:

  • Default to Create(默认创建): 按 Enter 将激活 Create 按钮, 创建脚本并在资源管理器中选择它.
  • Default to Edit(默认编辑): :按 Enter 将激活 Edit 按钮, 这将创建脚本并在默认脚本编辑器中打开它.
  • Stay open(保持打开): 如果启用, 创建脚本后窗口不会自动关闭.
  • Set folder as default(设置文件夹为默认): 将当前文件夹设置为脚本的默认保存位置. 如果新建脚本窗口直接打开或通过 Dash 打开, 则使用默认位置; 当通过资源管理器上下文菜单调用新脚本时不使用它.
  • Open templates folder(打开模板文件夹): 打开存放用户定义模板的文件夹.

模板

模板文件从 UX\Templates (预安装的) 和 %A_MyDocuments%\AutoHotkey\Templates (用户自定义的) 中绘制, 使用用户定义的模板覆盖任何具有相同名称的预安装模板. 如果一个文件存在于 %A_WinDir%\ShellNew\Template.ahk, 它被显示为 "Legacy", 可以被用户定义的同名模板覆盖.

每个模板可以包含一个 INI 节, 如下所示:

/*
[NewScriptTemplate]
Description = Descriptive text
Execute = true|false|1|0
*/

如果如上面所示, INI 节以 /* 开始, 而以 */ 结束, 则它不包含在创建的文件中.

Description(描述) 是可选的. 除了文件名之外, 该项也显示在 GUI 中.

Execute(执行) 是可选的. 如果设置为 true, 执行模板脚本时 A_Args[1] 包含要创建的文件的路径, 而 A_Args[2] 包含 "Create" 或 "Edit", 这取决于用户单击的是哪个按钮. 模板脚本将创建文件并打开它进行编辑(如果适用的话). 如果模板脚本需要 #include 其他文件, 可以将它们放在子目录中, 以避免在模板列表中显示它们.

安装

这个安装程序和相关的脚本是为了允许多个版本的 AutoHotkey 共存. 安装程序提供的选项非常少, 因为大多数东西都可以在安装后进行配置. 只有以下选择必须在安装过程中做出:

  • 安装在哪里.
  • 是为所有用户还是为当前用户安装.

默认情况下, 安装程序将为所有用户安装到 "%A_ProgramFiles%\AutoHotkey". 这是推荐的, 因为 UI Access 选项要求程序安装在 Program Files 下. 如果安装程序还没有以管理员身份运行, 当点击安装按钮时, 它将尝试提升权限, 如按钮上的盾牌图标所显示的.

当前用户的安装不需要管理员权限，只要用户有对所选目录的写入权限。当前用户安装的默认目录是 "%LocalAppData%\Programs\AutoHotkey".

与 v1 同时安装

同时安装 v1 和 v2, 有两种方式:

  1. 首先安装 v1, 然后安装 v2. 在这种情况下, v1 的文件被留在安装目录的根部, 以避免破坏任何依赖其当前路径的外部工具或快捷方式.
  2. 将 v1 作为一个额外的版本来安装. 运行 v1.1.34.03 或更高版本的安装程序会有这个选项. 或者, 使用下面描述的 /install 开关. 每个版本都会安装到它自己的子目录中.

运行 v1.1.34.02 或更早的安装程序(或使用 v1.1.34.03 或更新的自定义安装程序) 将覆盖 v2 安装程序在注册表中设置的一些值, 如版本号, 卸载程序条目和文件类型注册的部分. 它还会注册 v1 版的卸载程序, 该程序无法正确卸载两个版本. 要重新注册 v2, 请重新运行任何 v2 安装程序或使用 AutoHotkey32.exe 或 AutoHotkey64.exe 运行 UX\install.ahk.

默认版本

与 v1 安装不同, 在安装期间不会选择默认版本. 缺省值由启动器更动态地处理, 并且可以为每个用户配置.

使用命令行

要从源目录中直接安装到 DESTINATION 目录, 请使用下面展示的 /installto 或 /to(这两个开关可以互换). 使用下载的 setup.exe 或从下载的 zip 或其他来源中提取的文件.

AutoHotkey_setup.exe /installto "%DESTINATION%"
AutoHotkey32.exe UX\install.ahk /to "%DESTINATION%"

要从 SOURCE(目录中应该有 AutoHotkey*.exe 文件) 安装额外的版本, 请在当前安装目录中执行以下命令(根据需要调整 AutoHotkey32.exe 的路径):

AutoHotkey32.exe UX\install.ahk /install "%SOURCE%"

上面的完整命令字符串在 HKLM\Software\AutoHotkey 或 HKCU\Software\AutoHotkey 下 InstallCommand 注册, 其中 %1 作为源目录的替代. 使用这个注册表值可能更具有前瞻性.

重新注册当前安装:

AutoHotkey32.exe UX\install.ahk

卸载:

AutoHotkey32.exe UX\install.ahk /uninstall

或者, 从以下注册表键中读取 QuietUninstallString 值, 并执行它:

HKLM\Microsoft\Windows\CurrentVersion\Uninstall\AutoHotkey
HKCU\Microsoft\Windows\CurrentVersion\Uninstall\AutoHotkey

使用 /silent 开关来抑制警告或确认对话框, 并防止在安装完成时显示 Dash. 以下操作可能会自动执行, 而且没有警告:

  • 终止脚本以允许 AutoHotkey*.exe 被覆盖.
  • 覆盖安装程序以前没有注册的文件, 或注册后修改的文件.

任务栏按钮

v2 安装程序没有提供分离任务栏按钮的选项. 以前, 这是通过将每个 AutoHotkey 可执行文件注册为宿主程序(IsHostApp) 来实现的, 但这种方法有局限性, 当安装多个版本时, 就变得不容易管理. 作为替代, 每个脚本应该设置其进程或窗口的 AppUserModelID 来控制分组.

以 UI Access 运行

当安装在 Program Files 时, 安装程序会创建一组额外的 AutoHotkey exe 文件, 可用于解决一些常见的 UAC 相关问题. 这些文件以 "_UIA.exe" 为后缀. 当管理员使用这些 UIA.exe 文件中的一个来运行脚本时, 脚本能够与以管理员权限运行的程序的窗口进行交互, 而不需要脚本本身以管理员权限来运行.

安装程序执行如下操作:

  • 复制每个 AutoHotkey*.exe 为 AutoHotkey*_UIA.exe.
  • 在每个 UIA 文件的嵌入式清单(manifest) 中设置 uiAccess 属性.
  • 创建名为 "AutoHotkey" 的自签名数字证书, 然后签名每个 UIA 文件.
  • 注册 UIAccess 外壳动词, 在资源管理器的上下文菜单中显示为 "Run with UI access"(以 UI 权限运行). 默认情况下, 这会执行启动器, 它会尝试选择一个适当的 UIA.exe 文件来运行脚本.

启动器也可以配置为默认情况下使用 UI 权限运行 v1 脚本, v2 脚本或两者, 但如果所选版本和构建不存在 UIA.exe 文件, 则此选项无效.

脚本需要其他脚本以 UI 权限运行, 可以简单地 Run(运行) 对应的 UIA.exe 文件加上正常的命令行参数. 另外, 如果注册了 UIAccess 外壳动词, 它可以通过 Run 使用. 例如: Run '*UIAccess "Script.ahk"'

已知限制:

  • UIA 只会影响信任区域的文件; 比如 Program Files 的子目录.
  • 如果没有注册程序发布者用于签名的数字证书, 那么 UIA.exe 文件不能在其他计算机上运行.
  • 由于安全限制, UIA.exe 文件无法通过 CreateProcess 启动. 不过可以用 ShellExecute 替代. 内置的 Run 命令将会自动尝试以这两种方式运行.
  • UIA.exe 文件不可修改, 否则无法通过文件的数字签名验证.
  • 由于 UIA 程序和其他程序具有不同的 "integrity level(可信级别)", 它们仅可通过其他的 "UIA 程序" 来注册对象. 比如, ComObjActive("Word.Application") 将会失败, 因为 Word 并不是一个 UI Access 标记的程序.
  • 由于安全限制, 脚本自身的窗口无法自动视为 "无 UIA 程序或脚本".
  • 运行使用鼠标钩子的 "非 UIA 脚本" 时(类似简单的出现了 InstallMouseHook 指令), 鼠标热键会在由 UIA 脚本创建的窗口中失效, 即使热键为 "UIA 脚本" 自身定义的. 可行的解决办法是: 确保 "UIA 脚本" 最后一个加载.
  • 如果新的父窗口总是在顶部, 而子窗口不是, UIA 会阻止 Gui 的 +Parent 选项在现有窗口上工作.

有关详情, 请参阅 Enable interaction with administrative programs 论坛存档贴


脚本 - 定义 & 使用 | AutoHotkey v2

脚本

相关话题:

  • 程序的使用: 在一般情况下, 如何使用 AutoHotkey.
  • 概念和约定: AutoHotkey 使用的各种概念的通俗解释.
  • 脚本语言: 有关语法的详细信息(如何编写脚本).

目录

  • 简介
  • 脚本启动(自动执行线程): 在启动脚本时会立即执行, 并更改默认设置.
  • 把过长的行分割成一系列短行: 这样可以提高脚本的可读性和可维护性.
  • 脚本库文件夹
  • 把脚本转换成 EXE(Ahk2Exe): 把 .ahk 脚本转换成可以在任何 PC 上运行的 .exe 文件.
  • 向脚本传递命令行参数: A_Args 变量包含了传入的参数.
  • 脚本文件代码页: 在脚本中可靠地使用非 ASCII 字符.
  • 调试脚本: 如何找出无法正常工作的脚本中的问题.

简介

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

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

脚本启动(自动执行线程)

脚本加载完成后, 自动执行线程在脚本的顶行开始执行, 直到被指示停止为止, 例如 Return, ExitApp 或 Exit. 脚本的物理结束也作为 Exit.

没有热键, 热字串, 可见的 GUI, 活动的计时器, 剪贴板监视器和 InputHook, 并且没有调用 Persistent 函数的脚本, 将在完成启动后终止. 否则, 它会以空闲状态继续运行, 从而对热键, 热字串, GUI 事件, 自定义菜单项目和计时器这些事件做出响应. 如果这些条件在启动完成后发生变化(例如, 禁用了最后一个计时器), 脚本可能会在最后一个正在运行的线程完成后或最后一个 GUI 关闭后退出.

每当任何新的线程被启动时(不管是由热键, 热字串, 计时器还是其他事件启动的) 以下设置都会从自动执行线程中复制. 如果自动执行线程中没有设置, 则使用标准的默认值(与下面每个页面中注明的一样): CoordMode, Critical, DetectHiddenText, DetectHiddenWindows, FileEncoding, ListLines, SendLevel, SendMode, SetControlDelay, SetDefaultMouseSpeed, SetKeyDelay, SetMouseDelay, SetRegView, SetStoreCapsLockMode, SetTitleMatchMode, SetWinDelay 和 Thread.

每个线程都会保留其自身的上述设置的集合, 此对这些设置所做的更改不会影响其他线程.

上述某个函数的 "默认设置" 通常指的是自动执行线程的当前设置, 该线程的起始值与程序定义的默认设置相同.

传统上, 脚本的顶部被称为 自动执行段. 然而, 自动执行线程并不限于脚本的顶部. 在自动执行线程上调用的任何函数也可能影响默认设置. 由于在执行过程中遇到指令和函数, 热键, 热字串和类定义时都会被跳过, 因此有可能将启动代码放在每个文件中. 例如, 一组热键使用的全局变量可能会被初始化在这些热键的上方(甚至下方), 而不是在脚本的顶部.

把长行分割成一系列短行

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

有三种方法, 通常可以组合使用:

  • 延续运算符(延续行): 以表达式运算符开始或结束一行, 将其连接到前或下一行.
  • 延续闭环(延续表达式): 在大多数情况下, 括在 (), [] 或 {} 中的子表达式可以自动跨越多行.
  • 延续片段: 标记一组要合并在一起的行, 并添加其他选项, 例如在行之间插入什么文本(或代码).

延续运算符: 以逗号或任何其他表达式运算符(除了 ++ 和 --) 开头的行会自动与其正上方的行合并. 同样, 以表达式运算符结尾的行会自动与它下面的行合并. 在以下示例中, 第二行被附加到第一行, 因为它以逗号开头:

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)

下面的例子等同于上面的例子:

FileAppend "This is the text to append.`n",   ; 这里允许注释.
    A_ProgramFiles "\SomeApplication\LogFile.txt"  ; 注释.

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)

虽然上面示例中使用的缩进是可选的, 但它可以显示出哪些行属于上一行从而提高代码清晰度. 此外, 可以在上述示例中的任何行的末尾或行与行之间添加空行或注释.

延续操作符不能与自动替换热字符或 #HotIf 以外的指令一起使用.

延续闭环: 如果一行中包含一个带有未闭合 (/[/{ 的表达式或函数/属性定义, 那么它将与后续的行连接, 直到左, 右括号的数量平衡为止. 换句话说, 在大多数情况下, 用小括号(圆括号), 中括号(方括号), 大括号(花括号) 括起来的子表达式可以自动跨越多行. 例如:

myarray := [
  "item 1",
  "item 2",
]
MsgBox(
    "The value of item 2 is " myarray[2],
    "Title",
    "ok iconi"
    )

延续表达式可以包含两种类型的注释.

延续表达式可以包含普通的延续片段. 因此, 与任何包含表达式的行一样, 如果一行以非转义的左括号(() 开头, 除非在同一行上有一个右括号()), 否则它将被视为延续片段的开头.

引号括起来的字符串不能单独使用此方法跨越多行. 然而, 请参阅上面的内容.

通过括起来的方式进行延续可以与延续运算符结合使用. 例如:

myarray :=  ; 赋值运算符会引起延续.
[  ; 方括号括起以下两行.
  "item 1",
  "item 2",
]

如果程序判定行末尾的大括号({) 应该被解释为块(OTB 样式) 的开头而不是对象标识符的开头, 则行末尾的大括号不会导致延续. 具体来说(按优先级降序排列):

  • 如果一个大括号前面有一个未闭合的 (/[/{, 那么它永远不会被解释为一个块的开始, 因为这会产生一个无效的表达式. 例如, 大括号在 If ({ 中是对象标识符的开始.
  • 对象标识符不能合法地跟随 ) 或 ], 因此, 如果大括号跟随这些符号中的任何一个(不包括空格), 它将被解释为块的开始(例如用于函数或属性定义).
  • 对于需要正文(主体)(因此支持 OTB) 的控制流语句, 仅当大括号前面有运算符时, 大括号才能成为对象标识符的开始, 如 := { 或 for x in {. 特别是, 大括号在 Loop { 中始终是块的开始, 而 If { 和 While { 始终是错误.

大括号可以安全地在任何不需要正文的函数调用, 表达式或控制流语句的行延续中使用. 例如:

myfn() {
    return {
        key: "value"
    }
}

延续片段: 此方法应该用于合并大量行或当这些行不适合其他方法时. 虽然这个方法对于自动替换热字符串特别有用, 但是它也可以用于任何表达式. 例如:

; 示例 #1 - inside a quoted/literal string:
Var := "
(
一行文字.
默认情况下, 行与行之间的硬回车(`n) 也会被储存.
    这一行用制表符缩进; 默认情况下, 该制表符也会被储存.
此外, "引号" 会在适当时自动转义.
)"

; 示例 #2 - outside a quoted/literal string:
Var :=
(
"Same as above, except that quote marks are not automatically escaped.
Specify variables as follows: " Var "
A line of text."
)

; 示例 #3:
FileAppend "
(
第 1 行的文字.
第 2 行的文字. 默认情况下, 行与行之间存在换行符(`n).
)", A_Desktop "\My File.txt"

; 示例 #4:
FormatStr := "
(
Another way of using variables with a continuation section.
Input value 1: {1}
Input value 2: {2}
)"
MsgBox Format(FormatStr, A_TickCount, A_Now)

在上面的示例中, 一系列的行在顶部和底部用一对括号括起来. 这被称为 延续片段. 注意, 右括号之后的任何代码也与其他行连接(没有任何分隔符), 但不包括左括号和右括号.

如果延续片段上面的行以命名字符串结束, 而延续片段没有从引号字符串开始, 则自动插入一个空格, 将名称与延续片段的内容分隔开.

如果延续片段以引号或原义字符开始, 引号将自动转义(即它们被解释为原义字符), 如上面的除 #2 以外的示例所示. 否则, 引号的作用与正常情况相同; 也就是说, 延续片段可以包含带引号字符串的表达式, 如上面的 示例 #2 所示.

默认情况下, 根据延续片段中第一行的缩进, 省略前导空格或制表符. 如果第一行混合有空格和制表符, 则只将第一种类型的字符视为缩进. 如果任何行缩进小于第一行或使用不同的字符, 则该行上的所有前导空格都保持原样.

默认情况下, 将忽略尾随空格或制表符.

延续片段的默认行为可以通过在该片段的左括号的右侧包含以下一个或多个选项来覆盖改写. 如果存在多个选项, 请使用空格将每个选项与前一个选项分开. 例如: ( LTrim Join|.

Join String: 指定行与行之间连接的方式. 如果没有使用此选项, 那么除最后一行外的其他行后面都会跟一个换行符(`n). 如果省略 String, 则行与行之间直接连接而不添加任何字符. 否则, 为 String 指定一个最多 15 个字符的字符串. 例如, Join`s 会在除最后一行外的每行末尾插入一个空格. 另一个例子是 Join`r`n, 它会在行与行之间插入 CR+LF. 同样地, Join| 会在行之间插入管道符. 要让延续片段的最后一行也以 String 结尾, 请在它的右括号上方添加一个空行.

LTrim: 删除每行开头的所有的空格和制表符. 由于默认的 "智能" 行为, 这通常是不必要的.

LTrim0 (LTrim 后跟一个 0): 关闭每行开头的空格和制表符的删除.

RTrim0 (RTrim 后跟一个 0): 关闭每行末尾的空格和制表符的删除.

Comments (或 Comment 或 Com 或 C): 在延续片段中允许分号注释(但不允许 /*..*/). 这些注释(以及它们左边的任何空格和制表符) 将完全从连接结果中省略, 而不是作为文本处理. 每个注释可以出现在一行的右侧, 也可以单独出现在新行上.

`(重音): 按按原义处理反引号, 而不是作为转义字符. 这还可以防止任何显式指定的转义序列(`r 和 `t) 的转换.

( 或 ): 如果左括号或右括号出现在初始左括号的右侧(作为 Join 选项的参数除外), 则该行将被重新解释为表达式, 而不是延续片段的开头. 这允许在行的开头使用 (x.y)[z]() 之类的表达式, 并且还允许多行表达式以 (( 或 (MyFunc( 在行的开头.

备注

除非指定了重音(`) 选项, 否则在延续片段内部支持诸如 `n(换行符) 和 `t(制表符) 之类的转义序列.

当 comment 选项不存在时, 分号和 /*..*/ 注释在延续片段的内部不受支持, 因为它们被视为原义文本. 但是, 注释可以包含在延续片段的底部和顶部行. 例如:

FileAppend "   ; 注释.
; 注释.
( LTrim Join    ; 注释.
     ; 本行 不是 注释; 它是原义的文字. 上面行包含 注释 的部分都是注释.
)", "C:\File.txt"   ; 注释.

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

因为右括号表示延续片段的结束, 所以要让某一行以原义的右括号开头, 需要在其前面加上重音符/反引号: `). 然而, 这不能与重音(`) 选项结合使用.

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

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

脚本库文件夹

库文件夹提供了一些标准位置来保存其他脚本通过 #Include 方式利用的共享脚本. 一个库脚本通常包含一个函数或类, 它被设计成以这种方式使用和重用. 将库脚本放置在其中的一个位置, 可以更容易地编写脚本, 这些脚本可以与他人共享, 并在多个设置中工作. 库的位置是:

A_ScriptDir "\Lib\"  ; 本地库.
A_MyDocuments "\AutoHotkey\Lib\"  ; 用户库.
"directory-of-the-currently-running-AutoHotkey.exe\Lib\"  ; 标准库.

库文件夹按照上面显示的顺序进行搜索.

例如, 如果一个脚本包含行 #Include <MyLib>, 程序就会在本地库中搜索一个名为 "MyLib.ahk" 的文件. 如果在那里没有找到, 它就会在用户库中搜索它, 直至在标准库中搜索. 如果仍然没有找到匹配, 并且库的名称包含下划线(例如 MyPrefix_MyFunc), 则程序只使用前缀(例如 MyPrefix.ahk) 再次搜索.

虽然按照惯例, 一个库文件通常只包含一个与其文件名同名的函数或类, 但它也可能包含只被它调用的私有函数. 然而, 这些函数应该有相当不同的名字, 因为它们仍然在全局命名空间中; 也就是说, 它们可以在脚本的任何地方被调用.

把脚本转换成 EXE(Ahk2Exe)

脚本编译器(由 fincs 提供, TAC109 的添加) 可单独下载.

脚本编译完成后, 就成了一个独立的可执行文件; 也就是说, 可以在没有安装 AutoHotkey 的机器上运行. 编译过程中会创建一个包含下列文件的可执行文件: AutoHotkey 解释器, 脚本, 脚本包含的任何文件, 以及通过 FileInstall 函数内嵌的任何文件. 可以使用编译器指令包含其他文件.

v1.1 和 v2 脚本使用相同的编译器. 编译器通过检查所提供的基文件的主版本来区分脚本版本.

编译器目录

  • 运行编译器
  • 基础可执行文件
  • 脚本编译器指令
  • 压缩编译的脚本
  • 背景信息

运行编译器

Ahk2Exe 的使用方法如下:

  • GUI 界面: 运行开始菜单中的 "Convert .ahk to .exe" 项目. (调用 GUI 后, 在窗口显示之前可能会有一个停顿; 有关详情, 请参阅背景信息.)

  • 右键点击: 在资源管理器中, 在任何一个 .ahk 文件上右键点击并选择 "Compile Script"(只有在安装 AutoHotkey 时选择了脚本编译器选项时才可用). 这样创建了与脚本具有相同的主文件名的 EXE 文件, 它稍后会出现在同一目录下. 注: EXE 文件的生成使用的是前面的方法 #1 中最后保存的自定义图标, .bin 文件以及压缩设置, 或者由脚本中任何相关的编译器指令指定.

  • 命令行: 编译器可以通过使用下面展示的参数从命令行中运行. 如果使用了任何命令行参数, 除非使用了 /gui, 否则脚本会立即编译. 除了必须的 /gui 或 /in 参数外(二选一), 所有参数都是可选的.

    参数对 | 释义
    /in script_name | 要编译的脚本的路径和名称. 如果使用任何其他参数, 这是强制性的, 除非使用了 /gui.
    /out exe_name | 要创建的 .exe 的路径/名称. 默认值是输入文件的 directory\base_name 加上 .exe 的扩展名, 或脚本中任何相关的编译器指令指定.
    /icon icon_name | 要使用的图标文件. 默认为 GUI 界面中最后保存的图标, 或脚本中任何 SetMainIcon 编译器指令指定.
    /base file_name | 要使用的基文件(一个 .bin 文件或 .exe 文件). 使用的基文件的主版本必须与编译的脚本的版本相同. 默认是 GUI 界面中保存的最后一个基文件名, 或脚本中的任何 Base 编译器指令指定.
    /resourceid name | 指定一个非标准的资源 ID, 用于使用 .exe 基文件编译的主脚本(请参阅嵌入式脚本). 数字型资源 ID 应该由一个哈希符号(#) 和一个十进制数字组成. 默认是 #1, 或脚本中的任何 ResourceID 编译器指令指定.
    /cp codepage | 覆盖用于读取脚本文件的默认代码页. 关于可能的值列表, 请参阅 Code Page Identifiers. 注意, Unicode 脚本应该以字节顺序标记(BOM) 开始, 因此不需要使用这个参数.
    /compress n | 是否压缩 exe 文件? 0 = 不压缩, 1 = 使用 MPRESS(如果存在), 2 = 使用 UPX(如果存在). 默认值是 GUI 界面中最后保存的设置.
    /gui | 显示 GUI 而不是立即编译. 其他参数可以用来覆盖上次在 GUI 中保存的设置. /in 在这种情况下是可选的.
    /silent [verbose] | 禁用所有的消息框并将错误输出到标准错误流(stderr); 如果 stderr 失败, 则输出到标准输出流(stdout). 其他信息也会输出到 stdout. 可以选择输入 verbose 这个单词, 把状态信息也输出到 stdout.
    不推荐:
    /ahk file_name     		编译脚本时使用的 AutoHotkey.exe 的 path\name.
    不推荐:
    /mpress 0or1     		使用 MPRESS 压缩 exe 文件? 0 = 不压缩, 1 = 压缩. 默认值是 GUI 界面中最后使用的设置.
    不推荐:
    /bin file_name     		要使用的 .bin 文件. 默认值是 GUI 界面中最后保存的 .bin 文件名.

    例如:

    Ahk2Exe.exe /in "MyScript.ahk" /icon "MyIcon.ico"

注意:

  • 包含空格的参数必须用双引号括起来.
  • 编译通常不会提高脚本的性能.
  • #NoTrayIcon 和 A_AllowMainWindow 会影响已编译脚本的行为.
  • 如果脚本以编译的形式运行, 则内置变量 A_IsCompiled 的值为 1. 否则为 0.
  • 传递参数到 Ahk2Exe 后, 它会在标准输出中写入表示编译过程成功与否的消息. 尽管此消息不会显示在命令提示符中, 但可以通过像重定向输出到文件的方法 "捕获".
  • 此外, 当编译出错时, Ahk2Exe 还能返回退出代码, 它可以指示编译的错误类型. 这些错误代码可以在 GitHub (ErrorCodes.md) 上找到.

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

基础可执行文件

每个编译的脚本 .exe 都是基于一个实现解释器的可执行文件. 包含在编译器目录中的基础文件的扩展名是 ".bin"; 这些版本的解释器不包含加载外部脚本文件的能力. 相反, 程序会寻找一个名为 ">AUTOHOTKEY SCRIPT<" 的 Win32(RCDATA) 资源并加载它, 如果没有找到, 则会失败.

标准的 AutoHotkey 可执行文件也可以作为编译脚本的基础, 通过嵌入一个 ID 为 1 的 Win32(RCDATA) 资源. (可以使用 AddResource 编译器指令添加其他脚本.) 这使得编译后的脚本 .exe 可以与 /script 开关一起使用, 以执行除主嵌入脚本之外的其他脚本. 有关详情, 请参阅嵌入式脚本.

脚本编译器指令

脚本编译器指令允许用户指定如何编译脚本的细节. 其中的一些功能是:

  • 能够改变版本信息(如名称, 描述, 版本...).
  • 能够为编译后的脚本添加资源.
  • 能够调整编译的一些杂项.
  • 能够从编译后的脚本中删除代码部分.

有关详情, 请参阅脚本编译器指令.

压缩编译的脚本

Ahk2Exe 可以选择使用 MPRESS 或 UPX 这两款免费软件来压缩编译后的脚本. 如果 MPRESS.exe 和/或 UPX.exe 已被复制到安装 AutoHotkey 的 "Compiler" 子文件夹中, 则可以通过 /compress 参数或 GUI 设置来压缩 .exe 文件.

MPRESS 官网(介绍与下载): http://www.matcode.com/mpress.htm
MPRESS 镜像: https://www.autohotkey.com/mpress/

UPX 官网(介绍与下载): https://upx.github.io/

注意: 压缩编译脚本可以保护脚本不被诸如记事本或 PE 编辑器这类的工具随意查看, 但并不能保护脚本源码不被专用的提取工具提取.

背景信息

支持以下文件夹结构, 其中 Ahk2Exe.exe 的运行版本在下面所示的第一个 \Compiler 目录中:

\AutoHotkey
   AutoHotkeyA32.exe
   AutoHotkeyU32.exe
   AutoHotkeyU64.exe
   \Compiler
      Ahk2Exe.exe  ; Ahk2Exe 的主版本
      ANSI 32-bit.bin
      Unicode 32-bit.bin
      Unicode 64-bit.bin
   \AutoHotkey v2.0-a135
      AutoHotkey32.exe
      AutoHotkey64.exe
      \Compiler
   \v2.0-beta.1
      AutoHotkey32.exe
      AutoHotkey64.exe

当 Ahk2Exe 启动时, 基文件搜索算法会运行很短的时间, 其工作原理如下:

在编译器的目录, 编译器的父目录和任何编译器同级的以 AutoHotkey 或 V 开头的目录中搜索符合的 AutoHotkey .exe 文件和所有的 .bin 文件, 但不在以 AutoHotkey_H 开头的目录中搜索. 递归搜索所选的目录. 任何找到的 AutoHotkey.exe 文件都被排除在外, 只留下诸如 AutoHotkeyA32.exe, AutoHotkey64.exe 等文件以及所有发现的 .bin 文件. 所有保留的 .exe 文件名称必须以 AutoHotkey 开头和文件描述包含 AutoHotkey 单词, 并且版本号必须 1.1.34+ 或 2.0-a135+.

一个成功的编译还需要一个 AutoHotkey 解释器的版本(作为一个工具), 并且使用类似的算法来选择一个版本. 在大多数情况下, 所使用的解释器的版本将与用户为编译所选择的基文件的版本相匹配.

向脚本传递命令行参数

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

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

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

CompiledScript.exe [Switches] [Script Parameters]

Switches(开关): 下列零个或多个:

开关 | 意义 | 支持编译脚本?
/force | 无条件强制启动, 忽略任何警告对话框. 和 #SingleInstance Off 的效果相同. | 支持
/restart | 指示脚本正在重新启动, 并尝试关闭脚本的上一个实例(这也能在脚本内部通过 Reload 函数实现). | 支持
/ErrorStdOut

/ErrorStdOut=Encoding

把阻止脚本运行的语法错误发送到标准错误流(stderr) 而不显示在对话框中. 有关详情, 请参阅 #ErrorStdOut.

可以选择指定编码. 例如, /ErrorStdOut=UTF-8 在将消息写入 stderr 之前将其编码为 UTF-8.

 不支持
/Debug | 连接到调试客户端. 有关详情, 请参阅交互调试. | 不支持
/CPn

覆盖用于读取脚本文件的默认代码页. 有关详情, 请参阅脚本文件代码页.

 不支持
/Validate

AutoHotkey 加载脚本, 然后退出而不是运行它.

默认情况下, 加载时的错误和警告会像往常一样显示. /ErrorStdOut 开关可以用来抑制或捕获任何错误信息.

如果脚本成功加载, 进程退出代码为零, 如果有错误, 则退出代码为非零.

 不支持
/iLib "OutFile"

过时的: 请使用 /validate 代替.

"OutFile" 必须指定, 但会被忽略. 在以前的 AutoHotkey 版本中, 自动导入文件的文件名被写入 OutFile 指定的文件中, 格式为 #Include 指令.

 不支持
/include "IncFile"

在主脚本之前 Include 一个文件. 这个方法只能包含一个文件. 当脚本被重新加载时, 这个开关会自动传递给新的实例.

 不支持
/script

当与基于 .exe 文件的编译脚本一起使用时, 这个开关会使程序忽略主嵌入脚本. 这允许编译后的脚本 .exe 执行外部脚本文件或除主脚本以外的嵌入式脚本. 其他通常不被编译脚本支持的开关也可以使用, 但必须列在这个开关的右边. 例如:

CompiledScript.exe /script /ErrorStdOut MyScript.ahk "Script's arg 1"

如果当前的可执行文件没有嵌入脚本, 这个开关是允许的, 但没有效果.

基于 .bin 文件的编译脚本不支持这个开关.

另请参阅: 基础可执行文件(Ahk2Exe)

 N/A

Script Filename: 如果不含 Script Parameters, 那么此参数可以省略. 如果省略, 它默认为 AutoHotkey 可执行文件的路径和名称, 将 ".exe" 替换为 ".ahk". 例如, 如果将 AutoHotkey.exe 重命名为 MyScript.exe, 它将尝试加载 MyScript.ahk. 如果你不带参数地运行 AutoHotkey32.exe, 它将尝试加载 AutoHotkey32.ahk.

为文件名指定星号(*) 以从标准输入(stdin) 读取脚本文本. 这也使以下内容生效:

  • 初始工作目录被当作 A_ScriptDir, 并用于定位本地库文件夹.
  • A_ScriptName 和 A_ScriptFullPath 都包含 "*".
  • #SingleInstance 默认是关闭的.

有关示例, 请参阅 ExecScript().

如果当前可执行文件有嵌入脚本, 此参数可以是星号, 后面跟着嵌入脚本的资源名或 ID. 对于编译脚本(例如, 如果存在 ID 为 #1 的嵌入式脚本), 此参数前必须有 /script 开关.

Script Parameters(脚本参数): 要传递给脚本的字符串, 每个参数用空格分隔. 任何包含空格的参数都应该用引号括起来. 如果要将空字符串作为参数传递, 请指定两个连续的引号. 原义引号可以通过在它前面加上反斜杠(\") 来传递. 因此, 任何在加引号参数的末尾的反斜杠(如 "C:\My Documents\") 都被当作原义的引号(就是说, 脚本将接收到字符串 C:\My Documents"). 要移除引号, 使用 A_Args[1] := StrReplace(A_Args[1], '"')

传入参数, 如果存在, 作为数组存储在内置变量 A_Args 中, 可以使用数组语法来访问. A_Args[1] 包含第一个参数. 下面的示例在传递给它的参数太少时退出脚本:

if A_Args.Length < 3
{
    MsgBox "脚本至少需要 3 个参数, 但它只接收到 " A_Args.Length " 个."
    ExitApp
}

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

for n, param in A_Args  ; 对每个参数进行循环:
{
    MsgBox "Parameter number " n " is " param "."
}

如果参数是文件名, 则可以使用以下示例将它们转换为大小写校正的长名称(与文件系统中存储的一致), 包括完整/绝对路径:

for n, GivenPath in A_Args  ; 对每个参数 (或拖放到脚本上的文件) 进行循环:
{
    Loop Files, GivenPath, "FD"  ; 包括文件和目录.
        LongPath := A_LoopFileFullPath
    MsgBox "The case-corrected long path name of file`n" GivenPath "`nis:`n" LongPath
}

脚本文件代码页

为了使非 ASCII 字符能够正确地从文件中读取, 文件保存时使用的编码(通常由文本编辑器) 必须与 AutoHotkey 读取文件时使用的编码一致. 如果不匹配, 字符将被错误地解码. AutoHotkey 使用以下规则来决定使用哪种编码:

  • 如果文件以 UTF-8 或 UTF-16(LE) 字节顺序标记开头, 则使用相应的代码页并且忽略 /CPn 开关.
  • 如果在命令行中传递了 /CPn 开关, 则使用代码页 n. 有关可能值的列表, 请参阅 Code Page Identifiers.
  • 在其他所有情况下, 使用 UTF-8(此默认值不同于 AutoHotkey v1).

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

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

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

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

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

调试脚本

内置函数(如 ListVars 和 Pause) 可以帮助你调试脚本. 例如, 把下面这两行临时插入精心选择的位置时, 可以在脚本中创建 "断点":

ListVars
Pause

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

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

下列函数也可以用于调试: ListLines, KeyHistory 和 OutputDebug.

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

交互调试

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

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

注意在已编译脚本中此功能是禁用的.

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

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

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

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

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

ScriptPath := "" ; 设置此变量为脚本的完整路径
A_DetectHiddenWindows := true
if WinExist(ScriptPath " ahk_class AutoHotkey")
    ; 可选参数:
    ;   wParam  = 调试器客户端的 IPv4 地址, 为 32 位整数.
    ;   lParam  = 调试器客户端正在侦听的端口.
    PostMessage DllCall("RegisterWindowMessage", "Str", "AHK_ATTACH_DEBUGGER")

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

脚本展示

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


帮助设置

指定在默认情况下, 帮助文件启动的设置. 这些设置是永久性的; 这适用于所有当前的和将来的对帮助文件的访问.

注意: 如果按下下面的按钮, ActiveX 会在 CHM 文件的目录中创建一个名为 'chm_config.js' 的配置文件, 其内容如下:

权限拒绝. 以管理员身份运行 CHM 文件或手动创建配置文件.


初学者向导 | AutoHotkey v2

AutoHotkey 初学者向导 作者 tidbit

目录

  1. 基础
    1. 下载和安装 AutoHotkey
    2. 如何创建一个脚本
    3. 如何在你的电脑上找到帮助文件
  2. 热键 & 热字串
    1. 按键和其神秘符号
    2. 窗口特定的热键/热字符串
    3. 一个脚本里使用多个热键/热字串
    4. 示例
  3. 发送按键
    1. 游戏
  4. 打开程序 & 网站
  5. 函数调用(有或没有参数)
    1. 代码块
  6. 变量
    1. 获取用户输入
    2. 其它示例?
  7. 对象
    1. 创建对象
    2. 使用对象
  8. 其它有用的东西
    1. 神秘的方括号 [ ]
    2. 查找你的 AHK 版本
    3. 尝试与错误
    4. 缩进
    5. 寻求帮助
    6. 其他链接

1 - 基础

在开始我们的旅程之前, 让我给你一些建议吧. 在本向导中, 你会看到大量的文字和代码. 为了更有效的学习, 建议你阅读这些文字并 尝试 这些代码. 然后, 再深入学习这些代码. 你可以复制并粘贴此页上的大多数示例. 如果你弄糊涂了, 试着再看一遍.

a. 下载并安装 AutoHotkey

如果你是在本地查看此文档, 你可能已经安装了 AutoHotkey 并且可以跳转到 b 部分.

在学习使用 AutoHotkey(AHK) 之前, 你需要下载它. 下载后, 你可能会需要安装它. 但这取决于你下载的版本. 对于本指南, 我们将使用安装版, 因为对于新手来说, 它最容易设置.

文字指导:

  1. 访问 AutoHotkey 主页: https://www.autohotkey.com/
  2. 点击下载. 你应该会看到 AutoHotkey 的每个主要版本的选项. 此文档是针对 v2 的, 因此选择 v2 选项或切换到 v1 文档.
  3. 下载的文件应该命名为 AutoHotkey_*_setup.exe 或类似的名称. 运行这个程序并单击 Install.
  4. 装完了? 棒极了! 我们接着往下看.

b. 如何创建一个脚本

Autohotkey 安装完成后, 你也许会想它能做些什么. AutoHotkey 不是魔法, 虽然我们都希望它是, 但它的确不是. 所以需要我们告诉它要去干什么. 而这个过程叫做 "写脚本".

文字指导:

  1. 右键点桌面空白处.
  2. 点击 "新建" 菜单.
  3. 点击里面的 "AutoHotkey Script" 新建一个脚本.
  4. 给脚本命名. 它必须带 .ahk 后缀. 例如: MyScript.ahk
  5. 找到刚刚新建的脚本并右键点击它.
  6. 点击 "Edit Script".
  7. 一个新窗口被弹出, 也许是记事本. 如果是这样就成功了!

    现在你已经创建了一个脚本, 我们需要加点内容到脚本中. 有关所有内置函数和变量的列表, 请参阅第 5 节.

    这是一个使用 Send 函数创建的一个包含热键的简单脚本, 当你按下热键后, 它会向窗口发送一段文字:

    ^j::
{
    Send "My First Script"
}

    稍后我们将进行更深入的研究. 在此之前, 我们先解释一下上面的代码:

    • ^j:: 是热键. ^ 代表 Ctrl, j 是字母 J. 任何在 :: 左边 的字符表示您需要按下的热键.
    • Send "My First Script" 表示如何 send(发送) 按键. Send 是函数, 任何在空格之后括在引号内的内容都将被键入.
    • { 和 } 标志着热键的开始和结束.
  8. 保存文件.
  9. 双击桌面上的文件来运行它, 打开记事本或者其它可以输入文字的地方然后按下 Ctrl 和 J.
  10. 太好了! 你的第一个脚本完成了. 给自己一些奖励, 然后返回阅读本教程的其余部分.

视频指导, 请在 YouTube 网站观看 Install and Hello World.

c. 如何在你的电脑上找到帮助文件

v2.0-a076 及以后版本的下载包含一个离线帮助文件, 与主程序位于同一压缩包中. 如果手动提取了这些文件, 那么帮助文件应该在你放置它的任何位置.

v2.0-beta.4 和以后版本包含安装脚本. 如果你已经使用这个来安装 AutoHotkey, 每个版本的帮助文件应该在安装 AutoHotkey 的位置的子目录中, 如 "C:\Program Files\AutoHotkey\v2.0-beta.7". 可能还有一个名为 "v2" 的符号链接指向最后安装的版本的子目录. 如果安装了 v1.x, 则根目录中可能还存在该版本的帮助文件.

寻找 AutoHotkey.chm 或一个名为 AutoHotkey 的文件, 图标上带有有一个黄色问号.

如果你不需要找到文件本身, 也有很多方法来启动它:

  • 通过当前运行脚本的托盘菜单中的 "Help" 菜单选项.
  • 通过当前运行脚本主窗口的 "Help" 菜单, 或在主窗口处于活动状态时按 F1.
  • 通过 Dash 的 "Help files (F1)" 选项 , 该选项可以用鼠标激活, 也可以在 Dash 激活时按 F1. Dash 可以通过开始菜单中的 "AutoHotkey" 快捷方式打开.

2 - 热键 & 热字串

什么是热键? 热键是一个发热的按键, 开个玩笑. 热键是用来触发某些动作的按键或组合按键. 例如:

^j::
{
    Send "My First Script"
}

什么是热字串? 当你键入它们时, 热字串主要用于扩展缩写(自动替换). 当然, 它也可以用来启动任何脚本动作. 例如:

::ftw::Free the whales

这两个例子的区别在于, 当你按下 Ctrl+J 时, 热键将会触发, 而热字串会将你输入的 "ftw" 转换为 "Free the whales".

"那么, 该如何创建一个热键?" 好问题. 热键是通过一对冒号(::) 创建的. 按键名或组合按键名必须在 :: 的 左边. 代码则跟在后面, 括在大括号里面.

注意: 当然也有例外情况, 但很多时候容易引起混乱, 所以在向导页中不会涉及到它, 至少不是现在.

Esc::
{
    MsgBox "Escape!!!!"
}

热字串在要触发的文本两边各有一对冒号(::). 替换后的文本在第二对冒号(::) 的 右边.

如上所述, 热字串也可以启动脚本动作. 和热键一样 "几乎能做任何事情".

::btw::
{
    MsgBox "You typed btw."
}

有一个好消息是: 你可以为每一个热键, 热字串, 标签以及许多我们尚未讨论的其他内容编写多行代码.

^j::
{
    MsgBox "Wow!"
    MsgBox "There are"
    Run "notepad.exe"
    WinActivate "Untitled - Notepad"  ; 无标题 - 记事本
    WinWaitActive "Untitled - Notepad"
    Send "7 lines{!}{Enter}"
    SendInput "inside the CTRL{+}J hotkey."
}

a. 键和其神秘符号

你可能会问"我怎么知道 ^ 代表 Ctrl?!". 好问题! 为了帮助你学习 ^ 和其它符号的意思, 注意看这个表:

符号 | 描述
# | Win(Windows 徽标键)
! | Alt
^ | Ctrl
+ | Shift
& | 用于连接两个按键(含鼠标按键) 合并成一个自定义热键.

(有关完整的符号列表, 请参阅热键页面)

此外, 对于所有/大多数能用于热键双冒号左边的热键名称, 请参阅按键列表.

你可以通过在两个按键(除控制器按键) 之间, 使用 & 来定义一个组合热键. 在下面的例子中, 你要按下Numpad0, 再按下Numpad1 或 Numpad2, 才能触发热键:

Numpad0 & Numpad1::
{
    MsgBox "You pressed Numpad1 while holding down Numpad0."
}

Numpad0 & Numpad2::
{
    Run "notepad.exe"
}

如果你想知道热字串是否和热键一样有很酷的修饰符, 答案是有!热字串的修饰符在第一对冒号(::) 之间, 例如. 例如:

:*:ftw::Free the whales

想要查看更多关于热键和热字串修饰符的信息和实例, 请参阅: 热键和热字串.

b. 窗口特定的热键/热字串

有时候你也许想要热键或热字串只在某些特定窗口上工作(或禁用). 要做到这一点, 您需要使用其中的任意一个 "高级" 命令, 在它们前面带有一个 #, 即 #HotIf, 结合内置函数 WinActive 或 WinExist:

#HotIf WinActive(WinTitle)
#HotIf WinExist(WinTitle)

这些特殊的命令(技术上称为 "指令") 可以创建对上下文敏感的热键和热字串. 只需为 WinTitle 指定窗口标题. 但在某些情况下, 你可能需要指定诸如 HWND, 组或类的条件. 如果想深入了解这些高级内容, 点这里: WinTitle 参数 & 上次找到的窗口.

#HotIf WinActive("Untitled - Notepad")
#Space::
{
    MsgBox "You pressed WIN+SPACE in Notepad."
}

要关闭后续热键或热字串的上下文敏感性, 请指定 #HotIf 指令, 但不带参数. 例如:

; Untitled - Notepad
#HotIf WinActive("Untitled - Notepad")
!q::
{
    MsgBox "You pressed ALT+Q in Notepad."
}

; 任何标题不是无标题 - 记事本的窗口
#HotIf
!q::
{
    MsgBox "You pressed ALT+Q in any window."
}

当 #HotIf 指令在脚本中从未使用, 所有的热键和热字串对所有窗口生效.

#HotIf 指令是与位置相关的: 它会影响脚本中实际在它下面的所有热键和热字串, 直到下一个 #HotIf 指令.

; 记事本
#HotIf WinActive("ahk_class Notepad")
#Space::
{
    MsgBox "You pressed WIN+SPACE in Notepad."
}
::msg::You typed msg in Notepad

; MSPaint
#HotIf WinActive("Untitled - Paint")
#Space::
{
    MsgBox "You pressed WIN+SPACE in MSPaint!"
}
::msg::You typed msg in MSPaint!

有关更深入的信息, 请查看 #HotIf 页面.

c. 一个文件包含多个热键/热字串

这是一些人的想法. 因此, 我在这里声明一下: AutoHotkey 有能力将 任意多 的热键和热字串放在一个文件中. 不管是 1 个, 还是 3253 个(或者更多).

#i::
{
    Run "https://www.google.com/"
}

^p::
{
    Run "notepad.exe"
}

~j::
{
    Send "ack"
}

:*:acheiv::achiev
::achievment::achievement
::acquaintence::acquaintance
:*:adquir::acquir
::aquisition::acquisition
:*:agravat::aggravat
:*:allign::align
::ameria::America

上面的代码是完全可以接受的. 多个热键, 多个热字串, 都包含在一个大的脚本文件里.

d. 示例

::btw::by the way  ; 当您按下一个默认的结束符时, 用"by the way"替换掉"btw".
:*:btw::by the way  ; 替换 "btw" 为 "By the way" 而不需要按下结束符.
^n::  ; CTRL+N 热键
{
    Run "notepad.exe"  ; 当你按下 Ctrl+N, 将启动记事本.
}  ; 热键内容结束, 这之后的内容将不会触发.
^b::  ; CTRL+B 热键
{
    Send "{Ctrl down}c{Ctrl up}"  ; 复制选定的文本. 也可以使用 ^c, 但这种方法更加可靠.
    SendInput "[b]{Ctrl down}v{Ctrl up}[/b]" ; 将选定的文本包装在 BBCode 标签中, 以便在论坛中以粗体显示.
}  ; 热键内容结束, 当按下热键时, 下面的代码将不会被执行.

3 - 发送按键

现在你决定发送(输入) 一些按键到一个程序中. 你可以使用 Send 函数. 该函数表示发送按键, 模拟打字或按键操作.

但是在我们准备使用 Send 之前, 还有一些常见问题要注意.

就像热键一样, Send 函数也有一些特殊的键. 这里列出 4 个最常见的特殊按键:

符号 | 描述
! | 发送 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.
^ | 发送 Ctrl(Ctrl) 键. 例如, Send "^!a" 会按下 Ctrl+Alt+A, 而 Send "^{Home}" 则发送 Ctrl+Home. 注意: ^A 在某些程序中产生与 ^a 不同的效果. 这是因为 ^A 表示按下 Ctrl+Shift+A 而 ^a 表示按下 Ctrl+A. 如果不确定, 请使用小写字母.
# | 发送 Win 键(带有 Windows logo 的按键), 因此 Send "#e" 会在按住 Win 键时按下字母 "e".

Send 页面中有个很大的表格展示了 AHK 内置的几乎所有特殊键. 请点击查看. 例如: {Enter} 和 {Space}.

警告: 这个表 不 适用于热键. 也就是说, 当你使用 Ctrl 或 Enter(或其它按键) 作为热键时, 不要将它们括在 {} 中.

一个例子显示了不应该对热键做的情景:

; 当你创建热键时...
; 错误的
{LCtrl}::
{
    Send "AutoHotkey"
}

; 正确的
LCtrl::
{
    Send "AutoHotkey"
}

很多人都有一个共同的问题, 他们认为大括号放在文档中仅仅是为了好玩. 而实际上 大括号是需要的. 它将告诉 AutoHotkey {!} 表示 "感叹号", 而不是要 "按下 Alt 键". 所以要仔细查看 Send 页上的特殊键表格, 确保在合适的地方加上大括号. 例如:

Send "This text has been typed{!}" ;  注意大括号中的感叹号? 这是因为, 如果没有 {}, AHK 将按下 Alt 键.

; 跟上面的例子类似, 只是这次是 Enter 键. AHK 将会输出 "Enter"
; 如果 Enter 没有加上 {} 的话.
Send "Multiple Enter lines have Enter been sent." ; 错误的
Send "Multiple{Enter}lines have{Enter}been sent." ; 正确的

另一个常见的错误是, 人们认为当使用 Send 函数时, 所有内容都需要加上大括号. 这是不对的. 如果不在特殊按键列表中, 没必要加大括号. 你 不 需要给普通字符, 数字加上括号, 甚至像 .(句点) 这些符号加上 {}. 而且, 当你在使用 Send 函数时, 你可以一次性发送多个字符, 数字或符号. 所以没有必要为每一个字符写上一条 Send 函数. 例如::

Send "{a}"       ; 错误的
Send "{b}"       ; 错误的
Send "{c}"       ; 错误的
Send "{a}{b}{c}" ; 错误的
Send "{abc}"     ; 错误的
Send "abc"       ; 正确的

想要表示按住或松开某个按键, 可以将这个键用花括号围起来, 同时加上单词 UP 或 DOWN. 例如:

; 下面这个例子表示按下一个键的时候再按下另一个键(或多个键)..
; 如果其中一个方法不奏效, 试试另一个.
Send "^s"                     ; 表示发送 CTRL+S
Send "{Ctrl down}s{Ctrl up}"  ; 表示发送 CTRL+S
Send "{Ctrl down}c{Ctrl up}"
Send "{b down}{b up}"
Send "{Tab down}{Tab up}"
Send "{Up down}"  ; 按下向上键.
Sleep 1000        ; 保持 1 秒.
Send "{Up up}"    ; 然后松开向上键.

现在你可能会想, "怎样才能让我在发送超长文本时保证可读性?". 很简单. 使用我们所说的延续片段. 只需要在新行指定一个开括号, 然后是内容, 最后在它自己的行上加上一个闭括号. 想了解更多信息, 请阅读延续片段.

Send "
(
Line 1
Line 2
Apples are a fruit.
)"

注意: Send 有几种不同的形式. 每种形式有其特性. 如果一种形式的 Send 函数不能满足你的需要, 可以试试另一种形式. 只需要将函数名称 "Send" 替换成接下来的其中一个: SendText, SendInput, SendPlay, SendEvent. 想要了解每一个命令的详细内容, 请阅读这里.

a. 游戏

非常重要: 一些游戏, 尤其是多人游戏, 使用反作弊程序, 例如 GameGuard, Hackshield, PunkBuster 等. 且不说绕开反作弊系统是违反游戏规定的, 绕开反作弊本身也不太容易实现.

如果游戏的反作弊系统导致你的热键, 热字串和 Send 函数失效, 你是不走运的. 然而有一些方法也许能提高在某些游戏中使用热键的可能性, 但没人能打包票一定能行. 所以, 尽可能尝试 所有 你能想到的办法, 不要轻易放弃.

还有一个关于 DirectX 的问题要注意. 当你在 DirectX 游戏中使用 AutoHotkey 碰到问题时, 试试 FAQ 页面中描述的情况. 当你使用 PixelSearch, PixelGetColor 或 ImageSearch 时, 你可能会碰到更多关于 DirectX 的问题. 画面颜色可能会变成黑色(0x000000), 不管你设置的是什么颜色. 如果可能的话, 试试用窗口模式运行游戏. 这样做能够解决一些 DirectX 问题.

没有万能的办法能确保 AutoHotkey 能运行在所有程序里. 如果你试了所有的办法还是不行, 也许 AutoHotkey 暂时无法满足你的需要.

4 - 打开程序 & 网页

想要打开诸如画图(mspaint.exe), 计算器(calc.exe), 脚本.ahk 或一个文件夹, 你可以使用 Run 函数. 你还可以用这个命令打开一个网址, 比如 https://www.autohotkey.com/. 如果你想打开一个已经安装好的程序, 也很简单, 就像这样:

; 运行一个程序. 注意, 大部分的程序可能需要完整路径:
Run A_ProgramFiles "\Some_Program\Program.exe"

; 打开一个网址:
Run "https://www.autohotkey.com"

打开一个网址. 如果您想了解更多这方面的知识, 请访问 Run 页面.

下面是一些示例:

; 一些程序并不需要完整路径, 如 Windows 标准程序:
Run "notepad.exe"
Run "mspaint.exe"

; 使用内置变量来打开 "我的文档":
Run A_MyDocuments

; 打开一些网页:
Run "https://www.autohotkey.com"
Run "https://www.google.com"

想要深入了解更多信息和示例, 请查看 Run 页面.

5 - 函数调用(有或没有参数)

在 AutoHotkey 中, 函数调用可以用或不用括号来指定. 通常只有在需要函数的返回值或函数名称没有写在行首时才需要使用括号.

所有内置函数的列表可以在这里找到.

典型的函数调用是这样的:

Function(Parameter1, Parameter2, Parameter3) ; 带括号
Function Parameter1, Parameter2, Parameter3  ; 不带括号

参数支持任何类型的表达式; 例如:

  1. 你可以使用运算:
    SubStr(37 * 12, 1, 2)
SubStr(A_Hour - 12, 2)
  2. 你可以在函数里面调用其他函数(注意, 这些函数调用必须用括号指定, 因为它们不在行首):
    SubStr(A_AhkPath, InStr(A_AhkPath, "AutoHotkey"))
  3. 文本前后需要加上双引号:
    SubStr("I'm scripting, awesome!", 16)

最常见的将函数的返回值赋值给变量的方式是这样的:

MyVar := SubStr("I'm scripting, awesome!", 16)

这不是赋值的唯一方法, 但这是最常用的. 您使用 MyVar 来存储函数的返回值, 即写在 := 运算符的右边. 有关详情, 请参阅函数.

简而言之:

; 这些是没有括号的函数调用:
MsgBox "This is some text."
StrReplace Input, "AutoHotKey", "AutoHotkey"
SendInput "This is awesome{!}{!}{!}"

; 这些是有括号的函数调用:
SubStr("I'm scripting, awesome!", 16)
FileExist(VariableContainingPath)
Output := SubStr("I'm scripting, awesome!", 16)

a. 代码块

代码块就是用一对大括号({ 和 }) 包围起来的代码行. 们将一段代码组合在一起, 这样 AutoHotkey 判断这些代码是一个整体. 它们通常与函数和控制流语句(如 If 和 Loop) 一起使用. 如果不使用大括号, 只调用块中的第一行.

在下面的代码中, 只有当 MyVar 等于 5 时, 才运行这两行代码:

if (MyVar = 5)
{
    MsgBox "MyVar equals " MyVar "!!"
    ExitApp
}

在下面的代码中, 只有当 MyVar 等于 5 时, 才能显示消息框. 脚本总是会终止退出, 而不管 MyVar 是否等于 5:

if (MyVar = 5)
    MsgBox "MyVar equals " MyVar "!!"
    ExitApp

这完全没问题, 因为 if-语句只有一行代码与之关联. 它和上面的完全一样, 但是我把第二行缩进了, 所以我们知道它和 if-语句是分开的:

if (MyVar = 5)
    MsgBox "MyVar equals " MyVar "!!"
MsgBox "我们在 if-语句的 '外部'. 我们不需要大括号, 因为 if-语句下面只有一行."

6 - 变量

变量就像一个包含信息的便利贴. 它可以用于函数或数学表达式中, 充当存储文本, 数字, 数据的作用. 如果没有变量, 程序和脚本将会非常乏味.

给变量赋值有很多方法, 我们将会讨论最常见的几种方法. 请特别留意冒号等号(:=).

文本赋值
MyVar := "Text"

这是给变量赋值最简单的方法. 只需输入文本并完成. 任何文本都需要加引号.

变量赋值
MyVar := MyVar2

和上面的方法类似, 只是你将一个变量所对应的值赋给了另一个变量.

数字赋值
MyVar := 6 + 8 / 3 * 2 - Sqrt(9)

感谢表达式, 你可以进行计算!

混合赋值
MyVar := "The value of 5 + " MyVar2 " is: " 5 + MyVar2

以上三个赋值的组合.

等号(=) 和它前面的符号, 如 := += -= .= 等等, 这些被称为赋值运算符, 并且总是需要一个表达式.

a. 获取用户输入

有时候你想让用户来选择某些值. 这可以有很多种方法, 但其中最简单的办法就是使用 InputBox. 下面的例子展示了如何向用户提出一系列问题并根据用户的输入完成一些事情:

OutputVar := InputBox("What is your first name?", "Question 1").Value
if (OutputVar = "Bill")
    MsgBox "That's an awesome name, " OutputVar "."

OutputVar2 := InputBox("Do you like AutoHotkey?", "Question 2").Value
if (OutputVar2 = "yes")
    MsgBox "Thank you for answering " OutputVar2 ", " OutputVar "! We will become great friends."
else
    MsgBox OutputVar ", That makes me sad."

b. 其它示例?

Result := MsgBox("Would you like to continue?",, 4)
if Result = "No"
    return  ; 如果选择 No, 则停止代码继续.
MsgBox "You pressed YES."  ; 否则, 用户选择了 YES.
Var := "text"  ; 赋值一些文本给一个变量.
Num := 6  ; 赋值一个数字给一个变量.
Var2 := Var  ; 赋值一个变量给另一个.
Var3 .= Var  ; 追加一个变量到另一个的末尾.
Var4 += Num  ; 将变量的值与另一个相加.
Var4 -= Num  ; 将变量的值减去另一个.
Var5 := SubStr(Var, 2, 2)  ; 变量在函数中.
Var6 := Var "Text"  ; 赋值一个变量给另一个变量并带有一些额外的文本.
MsgBox(Var)  ; 变量在函数中.
MsgBox Var  ; 同上.
Var := StrSplit(Var, "x")  ; 变量在函数中, 用作 InputVar 和 OutputVar.
if (Num = 6)  ; 检查变量是否等于一个数字.
if Num = 6  ; 同上.
if (Var != Num)  ; 检查变量是否等于另一个.
if Var1 < Var2  ; 检查一个变量是否小于另一个变量.

7 - 对象

对象是一种组织数据以实现更高效使用的方法. 对象基本上是变量的集合. 属于对象的变量称为 "属性". 对象还可能包含项, 例如数组元素.

您可能想要使用对象的原因有很多, 一些例子:

  • 当你需要描述一组有序列表时, 比如杂货店列表(这种情况最好使用索引数组)
  • 当你需要描述一个图形方格时, 比如一个棋盘游戏(这种情况最好使用嵌套对象)
  • 当你需要描述一组事物而每样事物都有自己的名称时, 比如描述水果的特性(这种情况最好使用关联数组)

a. 创建对象

我们有很多方法可以创建对象, 下面介绍最常用的几种方法:

方括号语法(Array)
MyArray := ["one", "two", "three", 17]

这将创建一个Array, 它表示项目列表, , 索引号从 1 开始连续递增. 在本例中, 值 "one" 存储在对象键 1(又叫做索引号1), 值 17 存储在对象键 4(又叫做索引号 4).

大括号语法
Banana := {Color: "Yellow", Taste: "Delicious", Price: 3}

这将创建一个 ad hoc 对象. 这是一种创建具有少量已知属性的对象的快速方法. 在这个例子中, 值 "Yellow" 存储在对象键 Color 中. 同样的, 值 3 存储在对象键 Price 中.

数组构造器
MyArray := Array("one", "two", "three", 17)

这种方式跟方括号语法形式一样. 它实际上是在调用 Array 类, 而不是函数.

Map 构造器
MyMap := Map("^", "Ctrl", "!", "Alt")

这将创建一个 Map, 或 关联数组. 在本例中, 值 "Ctrl" 与键 "^" 相关联, 值 "Alt" 与键 "!" 相关联. 通常用 Map() 创建空映射, 然后用项目填充.

其他构造器
Banana := Fruit()

创建给定类的对象(在本例中为 Fruit).

b. 使用对象

使用对象有很多方式, 包括检索值, 设置值, 添加更多的值等等.

设置值

方括号表示法
MyArray[2] := "TWO"
MyMap["#"] := "Win"

在映射或集合中设置数组元素或项目类似于给变量赋值. 只需在包含对象(数组, 映射或其他) 的变量后添加方括号. 括号之间的索引或键是一个表达式, 因此对于任何非数值的文字值必须使用双引号.

句点表示法
Banana.Consistency := "Mushy"

这个例子为 Banana 所包含的对象的属性赋一个新值. 如果属性不存在, 则创建它.

检索值

方括号表示法
Value := MyMap["^"]

此示例检索先前与键 "^" 相关联(映射到) 的值. 键通常包含在一个变量中, 如 MyMap[modifierChar].

句点表示法
Value := Banana.Color

这个例子检索对象 Banana 的 Color 属性.

增加新的键和值

方括号表示法
MyMap["NewerKey"] := 3.1415

想要直接添加一对键和值, 只需设置一个尚不存在的键即可. 但是, 请注意, 当赋值给 Array 时, 索引必须在 1 到数组当前长度的范围内. 不同的对象可能有不同的要求.

句点表示法
MyObject.NewProperty := "Shiny"

如前所述, 向尚未定义的属性赋值将创建一个新属性.

InsertAt(在..插入) 法
MyArray.InsertAt(Index, Value1, Value2, Value3...)

InsertAt 是一个用于在数组中的特定位置插入新值的方法, 但其他类型的对象也可以用这个名称定义方法.

Push(推送) 法
MyArray.Push(Value1, Value2, Value3...)

Push "追加" 值到数组 MyArray. 这是向数组中添加新元素的首选方法, 因为不能使用括号表示法在当前值范围之外赋值.

移除属性和项目

删除方法
RemovedValue := MyObject.Delete(AnyKey)

Array 和 Map 有 Delete 方法, 该方法从数组或映射中删除值. MyObject[AnyKey] 的前一个值将存储在 RemovedValue. 对于数组, 这使数组元素没有值, 并且不影响数组中的其他元素.

Pop(抛出) 法
MyArray.Pop()

此 Array 方法从数组中删除最后一个元素并返回其值. 数组的长度减 1.

RemoveAt(在..删除) 方法
RemovedValue := MyArray.RemoveAt(Index)
NumberOfRemovedKeys := MyArray.RemoveAt(Index, Length)

Array 有 RemoveAt 方法, 它删除一个数组元素或数组元素的范围. 移除元素右边的元素(如果有的话) 被移到左边以填充空出的空间.

8 - 其他有用的东西

亲爱的朋友, 当你阅读到这里, 说明快要结束我们这段旅程了. 我希望你有所收获. 最后, 我将告诉你一些我认为你可能有用的东西. 希望你过的愉快!

a. 神秘的 [ ]

在帮助文档中, 你可能会发现有两个符号([ 和 ]) 经常出现在几乎每一页开头的黄色代码框中. 方括号中的内容代表 可选的. 也就是说, 如果你不需要这些参数你完全可以不管它. 不过要强调一点, 当你在写代码时, 千万 不要 把 [ ] 也写上了.

例如, 在 ControlGetText 页面, 你可能会看到这段代码:

Text := ControlGetText(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

如果你愿意, 你可以简单地写成这样:

Text := ControlGetText(Control)

或者再加上一些细节:

Text := ControlGetText(Control, WinTitle)

如果你想只使用参数 ExcludeTitle 而不想使用参数 WinText 或 WinTitle 怎么办? 很简单!

Text := ControlGetText(Control,,, ExcludeTitle)

请注意, 你不能忽略参数, 只是需要将它们的位置留空. 如果你像下面这样忽略 WinTitle, WinText, 将会产生错误:

Text := ControlGetText(Control, ExcludeTitle)

b. 查找你的 AHK 版本

你可以运行下面的代码来查看你的 AHK 版本信息:

MsgBox A_AhkVersion

你也可以到开始菜单或安装路径下的帮助文件(AutoHotkey.chm) 中查找.

c. 尝试与错误

尝试和错误是非常普遍而高效的学习方法. 与动不动就问这问那相比, 有时候花点时间(也许是长年累月) 亲手尝试可能会学的更快.

如果你在尝试新东西的过程碰到错误, 不要紧, 就从解决这个错误开始. 尝试解决这个错误, 一次不行就两次. 多次尝试后还是解决不了, 可以打开帮助文件学习哪些能做哪些不能做, 然后修改你的代码再试试. 试试, 失败, 试试, 失败, 试试, 试试, 再试试, 失败, 失败, 成功!

这也是很多大师们的学习经历. 不过也不要害怕提问, 我们不会咬人(至少不会咬的太狠). 学习总需要时间慢慢积累, 大师也不是一天练成的.

"若最初你没有成功, 努力, 努力, 不断的努力." - 威廉 · 爱德华 · 希克森.

d. 缩进

缩进这个事非常重要! 你的代码没有它也能正常运行, 可是如果没有缩进会让阅读代码变成一件非常痛苦的事. 也许一小段代码(少于 25 行) 不用缩进也没有太大关系, 但是代码一旦增多, 缩进就非常有必要. 所以, 学习使用缩进越快越好. 缩进没有固定的风格, 但最好保持一种风格.

"什么是缩进?" 你可能会问? 简单的说就是在代码和页面边界保留一段距离, 这样可以区分这一段代码是属于哪一段代码. 有些人习惯使用 3, 4 个空格或 1 个 tab 来表示缩进, 每一级用一次缩进.

不用缩进:

if (car = "old")
{
MsgBox "The car is really old."
if (wheels = "flat")
{
MsgBox "This car is not safe to drive."
return
}
else
{
MsgBox "Be careful! This old car will be dangerous to drive."
}
}
else
{
MsgBox "My, what a shiny new vehicle you have there."
}

使用缩进:

if (car = "old")
{
    MsgBox "The car is really old."
    if (wheels = "flat")
    {
        MsgBox "This car is not safe to drive."
        return
    }
    else
    {
        MsgBox "Be careful! This old car will be dangerous to drive."
    }
}
else
{
    MsgBox "My, what a shiny new vehicle you have there."
}

关于缩进, 维基百科上缩进样式页面有很多风格示例. 建议选一种你喜欢的或你认为最容易阅读的风格来学习.

e. 寻求帮助

在你提问之前, 最好自己先研究一下或者自己先动手试着写代码. 如果自己实在得不到满意的结果, 请往下看.

  • 不要害怕提问, 即使是世界上最聪明的人也需要别人的帮助.
  • 不要害怕给别人看你写的代码, 就算你觉得代码有点弱智.
  • 将所有你尝试的代码都贴出来.
  • 假设 其他人 都是门外汉. 把你掌握的所有信息都教给我们这些门外汉. 帮助我们就是帮助你自己.
  • 耐心.
  • 礼貌.
  • 开放.
  • 友善.
  • 祝你好运!

如果你没有马上得到答案, 至少等一天再提问. 我们乐于助人, 但是我们也是在自己的空余时间里免费提供帮助. 也许我们正在工作, 睡觉, 玩游戏, 和家人在一起或太忙了, 没有时间帮忙p.

在等待帮助时, 你也可以试着自己动手解决. 独立解决问题的感觉相当不错.

f. 其他链接

常见问题(FAQ)


v1.0 到 v1.1 的更改 | AutoHotkey v2

v1.0 到 v1.1 的更改

本文档详细介绍了 AutoHotkey v1.0 和 v1.1 之间的变化, 这些变化可能会导致脚本的行为不同, 因此在阅读或更新旧代码时可能需要注意. 另请参阅: v1.1 到 v2.0 的更改.

AutoHotkey 1.1 也称为 "AutoHotkey_L", 而 AutoHotkey 1.0 则表示 "AutoHotkey Basic". AutoHotkey_L 的一些旧版本使用 1.0.* 版本号, 所以为了清晰, 这里的帮助中使用名称而不是版本号来区分 AutoHotkey 的两种分支.

目录

高度影响:

  • 不再允许的一些语法错误
  • FileRead 可能返回损坏的二进制数据
  • 变量和函数名中不允许使用 [, ] 或 ?
  • DPI 比例缩放对于 GUI 是默认开启的

中度影响:

  • Transform 的 Unicode 子命令在 Unicode 版本中不再可用
  • 运行 AutoHotkey.ahk 来代替 AutoHotkey.ini
  • SetFormat, Integer, H 区分大小写
  • A_LastError 会被更多的命令修改
  • MsgBox 的逗号智能处理更加一致
  • Gui 的选项覆盖额外的样式
  • ~颚化符(波浪号) 会影响自定义修饰键的工作方式
  • x & y:: 会使得 x:: 和 x up:: 都会在 x 释放时触发

低度影响:

  • If var is type 默认忽略系统区域设置
  • GroupActivate 设置 ErrorLevel 和 GroupAdd 的 Label 作用的差异
  • Run 和 RunWait 解释 Target 的差异
  • Control-Z 不会被解释为文件结束
  • A_IsCompiled 总是只读的
  • DllCall 在更多情况下尝试使用 A 或 W 后缀

语法错误

AutoHotkey_L 中不允许某些在 AutoHotkey Basic 中接受的语法错误. 识别出这些错误后, 其中大多数都很容易改正. 有些错误是在加载时检测到的, 必须在脚本运行前予以纠正. 其他的错误只有在脚本运行时满足特定条件时才会出现.

v2.0 版的错误检测一般来说更加稳健, 由于在错误检测和处理之外还有许多用法上的变化, 所以这里不列出 v1.0 版和 v1.1 版在错误检测方面的区别. 有关详情, 请参阅 v1.1 版的文档.

FileRead

在某些常见情况下, FileRead 会在代码页之间转换文本, 因此可能输出错误的二进制数据. 要在 v2.0 版中避免此问题, 请添加 RAW 选项或使用 FileOpen 代替.

变量和函数名称

字符 [, ] 和 ? 被保留在表达式中使用, 所以在变量名中不再合法. 因此, ?(在三元运算中使用) 不再需要在两边加上空格. 在变量名中使用这些字符的 v1.0 版本的代码在 v1.1 版本中会有新的解释, 因此可能不会被检测出错误.

相关: 对象的运算符, 名称(v1.1 到 v2.0 的更改)

DPI 缩放

DPI 缩放对于脚本 GUI 是默认开启的, 以确保它们根据系统 DPI 设置缩放. 如果启用, 并且系统 DPI 设置不是 96(100 %), 那么由 Gui 方法/属性接受或返回的位置和尺寸将与其他函数不兼容. 要禁用 DPI 缩放功能, 请使用 MyGui.Opt("-DPIScale").

Transform

一些 Transform 子命令被修改或不可用:

  • Transform, Unicode 只在 ANSI 版本的 AutoHotkey 中可用. 要将 Unicode 文本赋值到剪贴板, 请使用常规赋值. 另请参阅: StrPut/StrGet.
  • Transform, HTML 在 Unicode 版本的 AutoHotkey_L 中支持额外的功能.

Transform 本身在 v2.0 中被删除.

默认脚本

未指定脚本运行 AutoHotkey_L 时, 默认加载 .ahk 文件而不是 .ini. 这个文件的名称取决于当前执行程序的文件名. 有关详情, 请参阅 Script Filename.

SetFormat, Integer[Fast], H

使用大写字母 H 时, 十六进制数字中 A-F 也将为大写. AutoHotkey Basic 总是使用小写形式的数字.

SetFormat 本身在 v2.0 中被删除. Format("0x{:x}", n) 产生小写字母 a-f, 而 Format("0x{:X}", n) 产生大写字母 A-F.

A_LastError

现在后面的这些命令会设置 A_LastError 来辅助调试: FileAppend, FileRead, FileReadLine, FileDelete, FileCopy, FileMove, FileGetAttrib/Time/Size/Version, FileSetAttrib/Time, FileCreateDir, RegRead, RegWrite, RegDelete. 使用这些命令的其中任何一个会覆盖 A_LastError 之前的值.

对于 v2.0, A_LastError 也由 IniRead, IniWrite 和 IniDelete 设置.

MsgBox

v1.0 和 v1.1 中的 MsgBox 有 "智能逗号处理", 以避免在未加引号的文本中转义逗号. 这种处理方式在两个版本中略有不同, 在阅读 v1.0 版本的代码时, 可能需要考虑到极少数情况. v2.0 完全使用表达式语法, 因此不需要对逗号进行任何特殊处理.

GUI 的 Owner 选项

对 Gui 应用 +Owner 选项还会移除 WS_CHILD 样式并设置 WS_POPUP 样式. 这样会破坏在设置这些样式 之后 使用 +Owner 设置 Gui 的父窗口的脚本.

颚化符(~) 和自定义组合键

从 v1.1.14 起, 当一个按键作为修饰符用于自定义组合键时, 颚化符前缀会影响该热键的工作方式.

自定义组合键和 Down/Up 热键

除了使用颚化符前缀的情况, 对于自定义修饰键会同时定义按键按下和弹起热键, 它们在该按键释放时都会触发. 例如, x & y:: 会使得 x:: 和 x up:: 都会在 x 释放时触发, 而以前 x:: 是不会触发的.

If var is type

If var is type 在 v1.0 中默认将某些(可能是特有的区域) 非 ASCII 字符识别为字母/小写/大写, 而在 v1.1 中只有在使用 StringCaseSense, Locale 时才会如此. 同样, v2.0 版中的 IsType 函数只有在第二个参数是 "Locale" 时才会将非 ASCII 字符识别为字母.

窗口组

GroupActivate 只在 v1.1 中设置 ErrorLevel, 而不在 v1.0 或 v2.0 中设置.

GroupAdd 的 Label 参数在 v1.0 和 v1.1 中的表现不同, 但在 v2.0 中被删除.

Run / RunWait

AutoHotkey_L 对 Run 和 RunWait 命令解释 Target 参数的方式进行了一些改进. 这样能允许一些以前不工作的情况, 但在一些非常罕见的情况下, 也可能影响到已经在 AutoHotkey Basic 中正常工作的脚本. 新的行为如下:

  • 如果 Target 以引号开始, 则到下一个引号之间的所有内容被视为要执行的操作, 一般为可执行文件.
  • 否则首个以空格结束并且为一个现有文件或以 .exe, .bat, .com, .cmd 或 .hta 结尾的子字符串被视为操作. 这样就允许 .ahk, .vbs 或 .lnk 等文件类型接受参数, 同时仍然允许运行 "已知" 的可执行文件(例如 wordpad.exe), 而不像以前的版本那样需要绝对路径.

Control-Z

Loop Read 和 File.ReadLine 不再把字符 Ctrl+Z(0x1A) 解释为文件结束标记. 任何的 Ctrl+Z, 即使某一个恰好出现在文件末尾, 都原样加载. FileRead 已经忽略这个字符, 所以不受这个问题的影响.

A_IsCompiled

如果脚本没有被编译, A_IsCompiled 也会被定义; 它的值在 v1.1 中是 "", 在 v2.0 中是 0. 以前它是未定义的, 这意味着如果脚本没有被编译, 诸如 A_IsCompiled := 1 这样的赋值是有效的. 现在在所有的情况下都被视为一个只读的内置变量.

DllCall

当给 DllCall 的函数名不能被解析时, AutoHotkey_L 会自动在函数名上附加一个 "A"(ANSI) 或 "W"(Unicode), 而不管指定的是哪个 Dll. 相比之下, AutoHotkey Basic 仅对 User32.dll, Kernel32.dll, ComCtl32.dll 或 Gdi32.dll 中的函数添加 "A" 后缀.


v1.1 到 v2.0 的更改 | AutoHotkey v2

v1.1 到 v2.0 的更改

目录

  • 语言
    • 已删除旧式语法
    • 热键和热字串标签
    • 名称
    • 作用域
    • 变量
    • 表达式
    • 对象(其他)
    • 函数
    • 套嵌函数
    • 未分类
    • 延续片段
    • 延续行
    • 类型
  • 对象
    • 原始值
    • 属性和方法
    • 静态变量
    • 元函数
    • 数组
    • Map
    • 枚举器
    • 函数
    • COM 对象(ComObject)
    • 默认属性
    • Com 调用
  • 库
    • 删除的命令, 函数 & 指令
    • 重命名的命令, 函数 & 指令
    • 修改的命令, 函数 & 指令
    • 新函数
    • Static/Class 变量
    • 新指令
    • 内置变量
    • 内置对象
  • Gui
    • Gui 子命令
    • 事件
    • 删除的
    • 控件选项
    • GuiControlGet
    • GuiControl
    • 其他更改
  • 错误处理
    • 可继续错误
    • ErrorLevel
    • 表达式
    • 函数
    • Catch
  • 键盘, 鼠标, 热键和热字串
  • 其他
    • 持续运行
    • 线程
    • 默认设置
    • 命令行

语言

已删除旧式语法

删除原义(文本) 赋值: var = value

删除了所有旧式 If 语句, 仅保留 if 表达式, 它从不要求有括号(但允许有括号, 就像在任何表达式中一样).

删除 "命令语法". 已经没有了 "命令", 只有 函数调用语句, 它们只是没有括号的函数或方法调用. 这意味着:

  • 所有以前的命令现在都是函数(不包括控制流语句).
  • 如果不需要返回值, 所有的函数都可以不带括号调用(但是和以前一样, 表达式内的调用不能省略括号).
  • 所有参数都是表达式, 因此所有文本都是 "带引号的", 逗号不需要转义. 目前这不包括一些指令(它们既不是命令也不是函数).
  • 不管是否有括号, 参数都是一样的; 也就是说, 返回值没有输出变量, 因此如果省略括号, 它将被丢弃.
  • 正常的变量引用从不用百分号括起来(除了 #Include 和 #DllLoad). 使用连接或 Format 来包含文本中的变量.
  • 在函数名和参数之间没有逗号, 所以 WinMove(, y) = WinMove , y (省略 x). 为了清楚起见, 需要一个空格或制表符. 为了保持一致性, 指令也遵循新的约定(指令名称和参数之间不能有逗号).
  • 没有百分号-空格前缀来强制表达式. 表达式中没有引号的百分号只用于双解引/动态引用, 有奇数个百分号是一个语法错误.
  • 方法调用语句(省略括号的方法调用) 被限制为一个普通的变量, 后面跟着一个或多个用点分隔的标识符, 如 MyVar.MyProperty.MyMethod "String to pass".

从 v1 命令到函数的转换通常如下所示(但有些函数已经改变了, 下文会进一步说明):

  • 如果命令的第一个参数是一个输出变量, 而第二个参数不是, 它就会成为返回值, 并从参数列表中删除.
  • 其余的输出变量的处理方式与 ByRef 参数类似(其用法和语法已经改变), 只是它们允许引用可写的内置变量.
  • 失败时抛出异常, 而不是设置 ErrorLevel.
  • 以前通过 ErrorLevel 返回的值会通过其他方式返回, 替换为异常, 作废或者无返回值.

所有控制流语句也接受表达式, 除了下面提到的.

所有带参数的控制流语句(目前不包括两个单词的 Loop 语句) 都支持小括号包围其参数列表, 名称和小括号之间没有任何空格. 例如, return(var). 但是, 这些不是函数; 例如, x := return(y) 是无效的. If 和 While 已经支持这个.

Loop(除了 Loop Count) 后面现在有一个次要的关键字(Files, Parse, Read 或 Reg), 它不能被 "括起来" 或被变量包含. 目前, 关键字后面可以有一个逗号, 但这不是必须的, 因为这不是一个参数. OTB 被所有模式所支持.

Goto, Break 和 Continue 需要一个没有引号的标签名, 类似于 v1(goto label 跳转到 label:). 要动态地跳转到一个标签, 请在名称后面使用圆括号: goto(expression). 然而, 这不是一个函数, 不能在表达式中间使用. 圆括号可以与 Break 或 Continue 一起使用, 但在这种情况下, 参数必须是一个单一的原义数字或带引号的字符串.

Gosub 已被删除, 标签也不能再与 SetTimer 和 Hotkey 等函数一起使用.

  • 它们是多余的; 基本上只是一种有限的函数形式, 没有局部变量或返回值, 而且是在它们自己的独立命名空间中. 函数可以在以前使用标签子程序的任何地方使用(甚至在其他函数内部).
  • 函数不能重叠(但可以包含在一个函数中). 相反, 可以使用多个函数, 并从其他函数中调用. 使用函数参数取代 A_ThisLabel.
  • 与子程序不同, 如果忘记定义函数的 结尾, 通常会被提醒错误, 因为每个 { 必须有一个相应的 }. 与标签子程序相比, 识别一个函数的边界可能也更容易.
  • 函数可以放在自动执行部分而不中断它. 自动执行部分现在可以很容易地跨越整个脚本, 所以可以改称为全局代码, 在自动执行线程中执行.
  • 函数可能不太容易像 "goto" 一样被误用(用户循环跳转到当前子程序(循环子程序本身), 不可避免地耗尽堆栈空间并终止程序).
  • 如果没有接受标签或函数的函数(如 Hotkey), 就不会有那么多的歧义, 因为两者可以同时以相同的名称存在.
  • 对于标签的所有其余用途, 从一个函数内部引用一个全局标签是无效的. 因此, 标签查找可以被限制在局部标签列表中. 因此, 没有必要检查从函数内部到外部的无效跳转(从未支持过).

热键和热字串标签

热键和非自动替换热字串不再是标签; 相反, 它们(自动) 定义了一个函数. 对于多行热键, 使用大括号将热键的主体括起来, 而不是用 return(其是隐式的大括号的结束) 终止它. 要允许显式调用一个热键, 在 :: 和 { 之间指定 funcName(ThisHotkey) - 这在 v1.1.20+ 中也可以做到, 但现在有一个参数. 当函数定义不是显式的时, 参数被命名为 ThisHotkey.

注意: 热键函数默认是假定-局部的, 因此在没有声明的情况下不能赋值给全局变量.

名称

现在, 函数和变量名被放在一个共享的命名空间中.

  • 每个函数定义在当前空间内创建一个常量(只读变量).
  • 使用 MyFunc 代替 Func("MyFunc").
  • 当把函数传递给任何内置函数如 SetTimer 或 Hotkey 时, 使用 MyFunc 代替 "MyFunc". 不再支持传递名称(字符串).
  • 当按值调用函数时, 使用 myVar() 代替 %myVar%().
  • 当你只有一个函数名(字符串) 时, 要调用一个函数, 首先要使用一个双解引将名称解析为一个变量并检索其值(函数对象). %myVar%() 现在实际上是执行了一个双解引, 然后调用结果, 等同于 f := %myVar%, f(). 尽可能避免按名称(字符串) 来处理函数; 使用引用来代替.
    • ; 译者注: 添加一个 v2 示例来进行说明
myvar  := f
myvar2 := "f"
msgbox myvar(1,2)    ; 显示结果 3
msgbox %myvar2%(1,2) ; 显示结果 3

f(a,b)
{
return a+b
}

名称不能以数字开头, 也不能包含以前允许的下列字符: @ # $. 只允许使用字母, 数字, 下划线和非 ASCII 字符.

保留关键字: 声明关键字和控制流语句的名称不能作为变量, 函数或类的名称. 这包括 local, global, static, if, else, loop, for, while, until, break, continue, goto, return, switch, case, try, catch, finally 和 throw. 这样做的主要目的是为了检测错误, 如 if (ex) break.

保留关键字: as, and, contains, false, in, is, IsSet, not, or, super, true, unset. 这些词是为将来使用或其他特定目的而保留的, 即使没有歧义, 也不允许作为变量或函数名. 这主要是为了保持一致性: 在 v1 版本中, and := 1 被允许放在单独的行中, 但 (and := 1) 就不行了.

上面列出的词被允许作为属性或窗口组名称. 典型使用的属性名称前面都有 ., 这可以防止该词被解释为运算符. 相比之下, 关键字永远不会被解释为表达式中的变量或函数名. 例如, not(x) 等同于 not (x) 或 (not x).

许多类是预定义的, 与用户定义的类的方式相同, 这有效地保留了这些全局变量名. (然而, 下面描述的域的变更缓解了由此产生的大部分问题.) 关于类的列表, 请参阅内置的类.

作用域

超级-全局 变量已被删除(不包括内置变量, 因为它们不能被重新声明或隐藏, 所以不完全一样).

在假定-局部函数中, 如果给定的名称没有在声明中使用, 也没有作为非动态赋值或引用(&) 运算符的目标, 则它可能解析为一个现有的全局变量.

换句话说:

  • 函数现在可以在不声明的情况下读取全局变量.
  • 没有 global 声明的函数不能直接修改全局变量(消除了意外副作用的一个来源).
  • 在脚本中添加一个新的 class, 不太可能影响任何现有函数的行为, 因为类不是超全局的.
  • global 关键字目前在全局范围内使用时是多余的, 但为了清晰起见可以使用. 这样声明的变量现在不太可能与局部变量发生冲突(比如在手动组合脚本或使用 #Include 时), 因为它们不是超全局的. 另一方面, 也失去了一些便利.
  • 声明通常不需要那么多.

强制-局部 模式已被删除.

变量

局部静态变量在执行到它们时被初始化, 而不是在自动执行部分开始前按线性顺序执行. 每个初始化器在第二次到达时没有效果. 多个声明是允许的, 并且可以在不同时间为同一个变量执行. 这有多种好处:

  • 当静态初始化器用静态变量调用其他函数时, 由于函数定义的顺序, 初始化器尚未执行的风险较小.
  • 因为函数已经被调用, 所以参数, A_ThisFunc 和闭包都是可用的(以前不可用).
  • 静态变量可以被有条件地初始化, 增加了灵活性, 同时仍然只执行一次, 不需要 if IsSet().
  • 由于一个静态变量可能有多个初始化器, 所以允许联合赋值, 如 static x += 1. (这个改变稍微减少了代码的大小, 因为它已经被 local 和 global 所允许.)

注意: static init := somefunction() 不能再用于自动执行 somefunction. 然而, 由于现在可以完全避免基于标签和返回的子程序, 因此自动执行部分能够跨越整个脚本.

使用 local 声明一个变量不再使函数假定-全局.

双重引用现在与加载时解析的变量更加一致, 不再能够创建新的变量. 这避免了一些不一致的地方和常见的混淆点.

由于任何原因而失败的双重引用现在会抛出错误. 以前, 任何具有无效名称的情况都会默默地产生一个空字符串, 而其他情况会创建并返回一个空变量.

表达式

带引号的原义字符串可以用 "双引号" 或 '单引号' 书写, 但必须以相同的引号开始和结束. 原义引号的写法是在引号前加一个转义字符 - `" 或 `' - 或者使用相反类型的引号: '"42" is the answer'. 双重引号没有特殊意义, 而且会导致错误, 因为自动串联需要一个空格.

运算符 &&, ||, and 和 or 产生的值取决于结果, 与 JavaScript 和 Lua 类似. 例如, "" or "default" 产生 "default" 而不是 1. 需要纯布尔值(0 或 1) 的脚本可以使用类似 !!(x or y) 或 (x or y) ? 1 : 0 语句.

自动连接(串联) 现在要求在所有情况下至少有一个空格或制表符(v1 版的文档说 "应该有" 一个空格).

像 x(), y() 这样的多语句表达式的结果是最后一个(最右边) 子表达式, 而不是第一个(最左边的) 子表达式. 在 v1 和 v2 中, 子表达式是按从左到右的顺序计算的.

逗号后的等号不再是赋值: 在 x:=y, y=z 中的 y=z 是一个无效的比较而不是赋值.

:=, +=, -=, *=, /=, ++ 和 -- 具有一致的行为, 无论它们是单独使用还是与其他运算符结合使用, 例如 x := y, y += 2. 以前, 当表达式中出现错误或在数学运算中使用空白值时, 会出现不同的行为.

!= 现在总是不区分大小写的, 就像 = 一样, 而 !== 已经被添加为 == 的对应词.

<> 已被删除.

如果给定的是一个浮点数字, // 现在会抛出异常. 以前, 负浮点数和负整数之间的结果是不一致的.

现在如果给定的是浮点数, |, ^, &, << 和 >> 现在会抛出异常, 而不是截断为整数.

科学记数法可以在没有小数点的情况下使用(但还是会产生一个浮点数). 当数字字符串被转换为整数时, 也支持科学符号(例如, "1e3" 被解释为 1000 而不是 1).

函数调用现在几乎允许任何子表达式来指定要调用的函数, 只要在参数列表的开括号前没有空格或制表符. 例如, MyFunc() 将调用 MyFunc 的值, 不管它是函数的实际名称还是包含函数对象的变量, 而 (a?b:c)() 将根据 a 调用 b 或 c. 注意 x.y() 仍然是一个方法调用, 大致相当于 (x.y)(x), 但 a[i]() 现在相当于 (a[i])().

双重引用现在几乎允许任何表达式 (不仅仅是变量) 作为变量名的来源. 例如, DoNotUseArray%n+1% 和 %(%triple%)% 都是有效的. 双重引用语法现在也被用来解除对 VarRefs 的引用, 例如 ref := &var, value := %ref%.

表达式 funcName[""]() 和 funcName.() 不再按名称调用一个函数. 省略 .() 中的方法名称现在会导致加载时的错误信息. 函数应该通过引用来调用或处理, 而不是通过名字.

var := 没有 r-值时, 在加载时被视为错误. 在 v1 版中, 它相当于 var := "", 但如果与另一个表达式结合使用, 就会静默失败 - 例如: x :=, y :=.

当一个原义字符串后面跟了一个不确定的一元/二元运算符时, 在加载时就会报告错误. 例如, "new counter:" ++Counter 可能应该是递增和显示 Counter, 但从技术上讲, 它是无效的加法和一元加法.

word ++ 和 word -- 不再是表达式, 因为 word 可以是一个用户定义的函数(而且 ++/-- 后面可能有一个表达式, 产生一个变量引用). 要写一个独立的后增量或后减量表达式, 要么省略变量和运算符之间的空格, 要么用括号包住变量或表达式.

word ? x : y 仍然是一个三元表达式, 但是以单词开头的更复杂的情况, 如 word1 word2 ? x : y, 总是被解释为对 word1 的函数调用(即使不存在这样的函数). 要写一个具有复杂条件的独立的三元表达式, 请将条件放在括号里.

新的 is 运算符, 如 x is y 可以用来检查值 x 是否是类 y 的实例, y 必须是一个具有 Prototype 属性的对象(即一个类). 这包括原始值, 如 x is Integer(这严格来说是一种类型检查, 而 IsInteger(x) 检查的是潜在的转换).

关键词 contains 和 in 被保留下来供将来使用.

&var(取址) 已被 StrPtr(var) 和 ObjPtr(obj) 取代, 以更清楚地显示意图并加强错误检查. 在 v1 中, 取址返回 var 内部字符串缓冲的地址, 即使它包含一个数字(但不是一个对象). 它还用于检索一个对象的地址, 而得到一个错误类型的地址会产生可怕的后果.

&var 现在是引用运算符, 它与所有的 ByRef 和 OutputVar 参数一起使用, 以提高清晰度和灵活性(并使其他语言变化成为可能). 有关详情, 请参阅变量引用(VarRef).

字符串长度现在在表达式计算期间被缓存. 这提高了性能, 并允许字符串包含二进制零. 特别是:

  • 两个字符串的串联, 其中一个或两个都包含二进制零, 不再导致数据的截断.
  • 区分大小写的等号运算符(== 和 !==) 可以用来比较二进制数据. 其他比较运算符只能 "看到" 第一个二进制零.
  • 二进制数据可以从函数返回并分配给对象.

大多数函数仍然期待空终止字符串, 所以只能 "看到" 第一个二进制零. 例如, MsgBox 将只显示第一个二进制 0 之前的字符串部分.

*(deref) 运算符已经被删除. 请使用 NumGet 代替.

~(bitwise-NOT) 运算符现在总是将其输入作为 64 位有符号整数处理; 它不再将 0 到 4294967295 之间的值作为无符号 32 位处理.

新增 >>> 和 >>>= 用于逻辑右位移.

新增 胖箭头函数. 表达式 Fn(Parameters) => Expression 定义了一个名为 Fn 的函数(可以是空白), 并返回一个 Func 对象或闭包对象. 当调用时, 该函数计算 Expression 并返回结果. 当在另一个函数中使用时, Expression 可以引用外层函数的变量(这也可以通过普通的函数定义来实现).

胖箭头语法也可以用来定义方法和属性的获取器/设置器(在这种情况下, 方法/属性定义本身并不是一个表达式, 但其主体只是返回一个表达式).

在成员访问的左侧, 现在完全支持原义数字(点). 例如, 0.1 是一个数字, 但 0.min 和 0.1.min 访问的是 min 属性, 这可以由一个基对象来处理(请参阅原始值). 1..2 或 1.0.2 是数字 1.0, 后面是属性 2. 使用实例可能是实现测量单位, 原义版本号或范围.

x**y: 当 x 和 y 是整数, 并且 y 是正数, 如果在范围内, 幂运算符现在对所有输入都给出正确的结果, 以前由于内部使用浮点数, 一些精度会丢失. 溢出的行为未被定义.

对象(杂项)

另请参阅: 对象

现在, 使用 . 访问属性和使用 [] 访问数据(项, 数组和 Map 元素) 之间有了区别. 例如, dictionary["Count"] 可以返回 "Count" 的定义, 而 dictionary.Count 返回其中包含的单词数. 用户定义的对象可以通过定义 __Item 属性来利用这一点.

如果事先不知道属性或方法的名称, 可以(而且必须) 用百分号来访问它. 例如, obj.%varname%() 是 obj[varname]() 的 v2 等价物. [] 的使用是为数据(如数组元素) 保留的.

构造专用对象的原义语法基本上仍然是 {name: value}, 但由于普通对象现在只有 "属性" 而不是 "数组元素", 为了与在其他情况下访问属性的方式保持一致, 规则略有改变:

  • o := {a: b} 和以前一样使用名称 "a".
  • o := {%a%: b} 使用 a 的值作为属性名而不是将其作为一个变量名, 执行双重解引并使用结果变量的内容. 换句话说, 它与 o := {}, o.%a% := b 的效果相同.
    • ; 译者注: 添加一个 v2 示例来进行说明
Var  := "abc"
Val  := 123
Obj  := {%Var%: Val}
Obj2 := {Var: Val}
Msgbox  Obj.abc  ; 显示结果 123
Msgbox Obj2.Var  ; 显示结果 123
  • 在 : 左边的任何其他类型的表达式都是非法的. 例如, {(a): b} 或 {an error: 1}.

base.Method() 中的单词 "base" 的使用被替换为 super(super.Method()), 以更好地区分这两个概念:

  • super. 或 super[ 调用方法/属性的超类版本, 其中 "super-class" 是最初与当前函数定义相关联的原型对象的基.
  • super 是一个保留关键字; 试图在没有 . 或 [ 或 ( 后缀的情况下使用它, 或者在一个类之外使用, 会导致加载时错误.
  • base 是一个预定义的属性, 用于获取或设置对象的直接基对象(如 ObjGetBase/ObjSetBase). 它只是一个普通的属性名, 而不是保留的.
  • 当超类没有定义 x 时, 调用super.x 会产生一个错误, 而以前 base.x 是被忽略的(即使它是一个赋值).

调用用户定义的对象而不显式指定方法名现在会调用 "Call" 方法而不是 "" 方法. 例如, %Fn%() 以前调用 Fn.(), 但 v2 表达式 Fn() 调用 Fn.Call(). Func 对象不再实现无名方法. 在方法调用中省略方法名不再有效, 但是 Fn.%""%() 可以代替 Fn.().

this.Method() 调用 Fn.Call(this)(其中 Fn 是实现该方法的函数对象) 而不是 Fn[this]()(在 v1 中, 这将导致调用 Fn.__Call(this) 除非 Fn[this] 包含一个函数). 函数对象应该实现一个 Call 方法, 而不是 __Call, 后者只用于显式方法调用.

如果定义了 __New 方法但无法调用它(例如因为参数计数不正确), 或者如果传递了参数但没有定义 __New, Classname()(以前的 new Classname()) 现在不能创建对象.

在表达式中创建的对象或从函数返回的对象现在被保留到表达式计算完成, 然后释放. 这稍微提高了性能, 并允许在表达式中使用临时对象进行内存管理, 而不必担心对象被过早释放.

对象可以包含包含二进制零的字符串值(但不是键). 克隆对象可以保留字符串中的二进制数据, 最多可以保留字符串的存储长度(而不是其容量). 历史上, 在处理二进制数据或结构时, 写入的数据超过值的长度; 现在, 应该使用 Buffer 对象来代替.

诸如 x.y := z 这样的赋值表达式现在总是产生 z 的值, 不管 x.y 是如何实现的. 属性设置器的返回值现在被忽略了. 以前是这样:

  • 一些内置对象返回 z, 一些返回 x.y(如 c := GuiObj.BackColor := "red" 设置 c 为 0xFF0000), 还有一些返回不正确的值.
  • 用户定义的属性设置器可能返回了意外值或无法返回任何内容.

x.y(z) := v 现在是一个语法错误. 此前, 它等同于 x.y[z] := v. 一般来说, x.y(z)(方法调用) 和 x.y[z](参数化属性) 是两个不同的操作, 尽管如果 x 是一个 COM 对象, 它们可能是等同的(由于 COM 接口的限制).

将一个对象与另一个值串联或传递给 Loop, 目前被视为一个错误, 而以前该对象被视为一个空字符串. 这可能会更改为隐式调用 .ToString(). 使用 String(x) 将一个值转换为一个字符串; 如果 x 是一个对象, 这将调用 .ToString().

当一个对象通过 IDispatch(COM 接口) 被调用时, 任何不能被传回给调用者的未捕获的异常将导致错误对话框. (调用者可能会也可能不会在没有任何具体细节的情况下显示额外错误对话框). 这也适用于由于使用 ComObjConnect 而被调用的事件处理程序.

函数

函数不能再以超过其正式接受的参数来动态调用.

可变函数不受上述限制的影响, 但通常会在每次调用时创建一个数组来保存多余的参数. 如果不需要这个数组, 现在可以省略参数名以防止它被创建:

AcceptsOneOrMoreArgs(first, *) {
  ...
}

这可以用于不需要额外参数的回调.

可变函数调用现在允许任何可枚举的对象, 而以前它们需要一个具有连续数字键的标准对象. 如果枚举器每次迭代返回一个以上的值, 只使用第一个值. 例如, Array(mymap*) 创建一个包含 mymap 键的数组.

可变函数调用以前对命名参数的支持不完整. 这已经被禁用, 以消除正确实现命名参数的可能障碍.

用户定义的函数可以使用新的关键字 unset 作为参数的默认值, 以使参数在没有提供值的情况下被 "unset". 然后函数可以使用 IsSet() 来确定是否提供了一个值. unset 目前不允许在任何其他情况下使用.

当函数调用出现而没有定义时, 脚本不再从函数库(Lib) 文件夹中自动包含, 这是因为复杂性和潜在的事故增加(现在, MyFunc() 中的 MyFunc 可以是任何变量). #Include <LibName> 和以前一样工作. 在未来的版本中, 它可能会被模块支持所取代.

可变内置函数现在的 MaxParams 值等于 MinParams, 而不是一个任意的数字(如 255 或 10000). 使用 IsVariadic 属性来检测, 没有上限.

ByRef

ByRef 参数现在使用 &param, 而不是 ByRef 参数 来声明, 在用法上有一些区别.

ByRef 参数不再隐式地接受对调用者的变量的引用. 相反, 调用者必须用引用运算符(&var) 显式地传递一个引用. 这允许更多的灵活性, 例如在其他地方存储引用, 用可变函数接受引用, 用可变调用传递引用.

当一个参数被标记为 ByRef 时, 任何试图显式传递非 VarRef 值的行为都会导致抛出错误. 否则, 函数可以用 param is VarRef 检查引用, 用 IsSetRef(param) 检查目标变量是否有一个值, 并用 %param% 显式解除引用.

在递归调用时, ByRef 参数现在能够从同一函数的前一个实例中接收对局部变量的引用.

套嵌函数

一个函数可以被定义在另一个函数里面. 一个嵌套的函数可以自动从包围的函数中 "捕获" 非静态局部变量(在适当的条件下), 允许它们在包围的函数返回后使用.

新的 "胖箭头" => 运算符也可以用来创建嵌套函数.

有关详情, 请参阅套嵌函数.

未分类

当初始化一个已声明的变量或可选参数时, 必须用 := 来代替 =.

return %var% 现在做了一个双重引用; 以前它等同于 return var.

#Include 默认是相对于包含当前文件的目录而言的. 其参数现在可以选择用引号括起来.

#ErrorStdOut 的参数现在可以选择用引号括起来.

现在要求标签名称只能由字母, 数字, 下划线和非 ASCII 字符组成(与变量, 函数等相同).

函数中定义的标签具有局部空间(作用域); 它们只在该函数中可见, 并且不会与其他地方定义的标签冲突. 局部标签不可能被外部调用(即使通过内置函数). 可以使用嵌套函数来代替, 允许充分使用局部变量.

for k, v in obj:

  • 对象的调用方式已经改变. 请参阅下面的枚举器.
  • 在循环中断或完成后, 现在 k 和 v 将恢复到循环开始前的值.
  • 如果 obj 不是对象, 或者在检索或调用其枚举器时出现问题, 则抛出异常.
  • 最多可以使用 19 个变量.
  • 变量可以被省略.

转义逗号不再有任何意义. 以前, 如果在命令参数中没有括号的表达式中使用, `, 就会强制逗号被解释为多语句运算符, 而不是作为参数之间的分隔符. 它只对命令起作用, 不能用于函数或变量声明.

转义序列 `s 现在可以在支持 `t 的地方使用. 以前只允许 #IfWin 和 (Join.

*/ 现在可以放在行尾, 以结束多行注释, 以解决 /* */ 在其他语言中工作方式有关的一个常见的混淆点. 由于存在歧义的风险(例如以 */ 结尾的热字符串), 任何没有以 */ 结尾的 /* 不再被忽略(颠覆了(逆转) AHK_L 修订版 54 中的更改).

在支持的范围(64 位有符号整数) 之外的整数常量和数字字符串现在会溢出/环绕, 而不是被限制在最小/最大值上. 这与数学运算符一致, 因此 9223372036854775807+1 == 9223372036854775808(但两者都生成 -9223372036854775808). 这有利于对 64 位数值进行位操作.

对于数字字符串来说, 除了空格和制表符之外, 允许在数字前面添加空白字符的情况比较少. 一般的规则(在 v1 和 v2 中) 是只允许使用空格和制表符, 但在某些情况下, 由于 C 语言运行库的惯例, 允许使用其他空白字符.

Else 现在可以与 任意类型的循环 和 Catch 一起使用. 对于循环, 如果循环的迭代次数为零, 它将被执行. 对于 Catch, 如果在 Try 中没有抛出异常它将被执行(如果抛出任何错误或值, 即使没有与值的类别相匹配的 Catch 也不会被执行). 因此, 在不使用大括号的情况下 Else 的解释可能与以前的版本不同. 例如:

if condition
{
    while condition
        ; 每个迭代都会执行的语句
} ; 这些大括号现在是必须的, 否则 else 会与 while 相关联
else
    ; if condition 为 false 时, 执行的语句

延续片段

智能 LTrim: 默认行为是计算延续片段选项下面第一行的前导空格或制表符的数量, 并从此后的每一行中删除该数量的空格或制表符. 如果第一行中混合了空格和制表符, 只有第一种类型的字符被视为缩进. 如果任何一行的缩进幅度小于第一行, 或者使用了错误的字符, 则该行的所有前导空白将被原封不动地保留.

如果延续片段以引号字符串开始, 引号会被自动转义(即它们被解释为原义字符). 这就避免需要在多行字符串中转义引号(如果开始和结束的引号都在延续片段之外), 同时仍然允许多行表达式包含带引号字符串.

如果延续片段上方的行以一个名称字符结束, 并且该部分不以引号字符串开始, 则会自动插入一个空格, 以分隔名称和延续片段的内容. 这允许在 return, 函数调用语句等之后的多行表达式中使用一个延续片段. 它还可以确保变量名称不与其他标记(或名称) 连接, 造成无效的表达.

表达式中的换行字符(`n) 被当作空格处理. 这使得多行表达式可以使用默认选项(即省略 Join) 的延续片段来编写.

由于不再需要转义这些字符, 所以删除 , 和 % 选项.

如果 ( 或 ) 出现在延续片段潜在的选项中(除了作为 Join 选项的一部分), 整个行不会被解释为延续片段的开始. 换句话说, 像 (x.y)() 和 (x=y) && z() 这样的行会被解释为表达式. 多行表达式也可以在行首以开括号开始, 前提是在第一个物理行中至少有一个其他的 ( 或 ). 例如, 整个表达式可以用 (( ... )) 括起来.

不包括上述情况, 如果存在任何无效的选项, 会显示加载时错误, 而不是忽略无效的选项.

以 ( 开头的行和以 : 结尾的行不再因为看起来像一个标签而被排除为延续片段的开头, 因为 ( 在标签名称中不再有效. 这使得像 (Join: 这样的代码有可能是一个延续片段的开始. 然而, (: 是一个错误, 而 (:: 仍然是一个热键.

在表达式和函数/属性定义中支持一种新的延续行方法, 它利用了每个 (/[/{ 必须与相应的 )/]/} 相匹配这一事实. 换句话说, 如果一行包含一个未封闭的 (/[/{ 它将与后续的行连接, 直到开头和结尾符号的数量平衡. 如果没有其他未封闭的符号, 并且括号前面没有紧接着的运算符, 那么行末的括号 { 被认为是 OTB(而不是一个对象原义语法的开始).

延续行

现在, 对于将符号视为表达式运算符的上下文, 行延续更具选择性. 一般来说, 逗号和表达式运算符不能再用于文本上下文中的延续, 例如与热字符串或指令(除 #HotIf 外) 一起, 或在未封闭的引号字符串之后.

行延续现在对行末的表达式运算符有效.

is, in 和 contains 可以用于行延续, 尽管 in 和 contains 仍然被保留/尚未作为运算符实现.

and, or, is, in 和 contains 可以作为行延续运算符, 即使后面是赋值或其他二进制运算符, 因为这些不再是有效的变量名. 相比之下, v1 版对 and/or 后跟以下任一项都有例外: <>=/|^:,

当 . 被用于延续时, 如果在一行开始时 . 右边没有空格或制表符, 那么这两行就不再自动用空格分隔, 如 .VeryLongNestedClassName. 请注意 x .123 总是属性访问(而不是自动串联), 而 x+.123 在有或没有空格的情况下都可以工作.

类型

一般来说, v2 对任何依赖值的类型的代码产生更一致的结果.

在 v1 中, 一个变量可以同时包含一个字符串和一个缓存的二进制数字, 每当变量被用作数字时, 这个数字就会被更新. 由于这个缓存的二进制数是检测数值类型的唯一方法, 由表达式(如 var+1 或 abs(var)) 进行的内部缓存的副作用有效地改变了 var 的 "类型". v2 禁用了这种缓存, 因此 str := "123" 总是一个字符串 int := 123 总是一个整数. 因此, str 每次被用作数字时都需要进行转换(而不是只在第一次), 除非它最初被赋值为纯数字.

内置的 "变量" true, false, A_PtrSize, A_Index 和 A_EventInfo 总是返回纯整数, 而不是字符串. 在 v1 中, 由于某些优化, 它们有时会返回字符串, 而这些优化在 v2 中已经被取代了.

所有的原义数字在加载时都被转换为纯二进制数字, 而它们的字符串表示形式则被丢弃. 例如, MsgBox 0x1 等同于 MsgBox 1, 而 MsgBox 1.0000 等同于 MsgBox 1.0(因为浮点数的格式已经改变). 在变量中存储数字或从用户自定义函数中返回数字都会保留其纯数字状态.

现在浮点数的默认格式指定为 .17g (以前是 0.6f), 这在很多情况下更紧凑, 更准确. 默认值不能更改, 但可以用 Format 来获得不同的格式.

带引号的字符串和通过连接带引号的字符串产生的字符串不再无条件地被视为非数字. 相反, 它们被视为与存储在变量中或从函数中返回的字符串相同. 这有以下影响:

  • 带引号的文字 "0" 被认为是 false.
  • ("0xA") + 1 和 ("0x" Chr(65)) + 1 产生 11 而不是失败.
  • x[y:="0"] 和 x["0"] 现在的行为是一样的.

如果运算数都是字符串, 运算符 = 和 != 现在按字母顺序比较它们的运算数, 即使它们是数字字符串. 当两个运算数都是数字且至少有一个运算数是纯数字(不是字符串) 时, 仍然进行数字比较. 例如, 54 和 "530" 是数字比较, 而 "54" 和 "530" 是字母比较. 此外, 存储在变量中的字符串与原义字符串的处理没有区别.

关系运算符 <, <=, > 和 >= 如果与非数字字符串一起使用, 现在会出现异常. 以前, 它们根据两个输入是否为数字, 按字母顺序进行比较, 但带引号的字符串总是被认为是非数字的. 使用 StrCompare(a, b, CaseSense) 代替.

Type(Value) 返回下列字符串之一: 字符串, 整数, 浮点数, 或者一个对象的具体类.

Float(Value), Integer(Value) 和 String(Value) 将 Value 转换成相应的类型, 如果不能进行转换, 则抛出异常(例如 Integer("1z")). Number(Value) 转换为整数或浮点数. 如果 Value 是一个对象, String(Value) 调用 Value.ToString(). (在理想情况下, 这适用于任何从对象到字符串的隐式转换, 但目前的实现使其变得困难.)

对象

对象现在使用更结构化的类-原型方法, 将类/静态成员与实例成员分开. 许多内置方法和 Obj函数已经被移动, 重命名, 更改或删除.

  • 每个用户定义的或内置的类都是一个类对象(Class 的实例) 只公开使用 static 关键字定义的方法和属性(包括从基类继承的静态成员) 和嵌套类.
  • 每个类对象都有一个 Prototype 属性, 成为该类所有实例的 base. 类体内的所有非静态方法和属性定义都附着在原型对象上.
  • 实例化是通过调用静态方法 Call 来执行的, 如 myClass.Call() 或 myClass(). 这允许类完全覆盖构造行为(例如, 实现类工厂或单件, 或者构造一个原生数组或 Map 而不是一个对象), 尽管初始化通常仍应在 __New 中执行. 现在 __New 的返回值被忽略; 要覆盖返回值, 请在 Call 方法中这样做.

混合的对象类型已经被拆分成 Object, Array 和 Map(关联数组).

Object 现在是所有用户定义 和内置 对象的根类(这不包括 VarRef 和 COM 对象). 添加到 Object.Prototype 的成员被所有 AutoHotkey 对象继承.

运算符 is 的期望是一个类, 所以 x is y 在基对象链中检查 y.Prototype. 要检查 y 本身, 请调用 x.HasBase(y) 或 HasBase(x, y).

用户定义的类也可以显式地继承 Object, Array, Map 或其他一些内置类(尽管这样做并不总是有用), 如果没有指定, 那么 Object 就是默认的基类.

new 运算符已被删除. 取而代之的是省略该运算符, 如 MyClass(). 要 基于 一个不是类的对象的构造一个对象, 请使用 {} 或 Object()(或通过任何其它方法) 创建该对象, 并设置它的 base. __Init 和 __New 可以被显式调用, 但一般来说, 这仅适用于实例化类.

嵌套类的定义现在产生一个带有 get 和 call 访问函数的动态属性, 而不是一个简单的值属性. 这是为了支持以下行为:

  • Nested.Class() 不会将 Nested 传递给 Nested.Class.Call 并最终传递给 __New, 否则会发生这种情况, 因为这是作为方法调用的函数对象的正常行为(这是这里使用嵌套类的方式).
  • Nested.Class := 1 默认是一个错误(该属性是只读的).
  • 第一次引用或调用该类会使其初始化.

GetCapacity 和 SetCapacity 被删除.

  • ObjGetCapacity 和 ObjSetCapacity 现在只影响对象包含属性的容量, 而且预计不会被经常使用. 不支持设置属性, 数组元素或 Map 元素的字符串缓冲的容量; 对于二进制数据, 使用缓冲对象.
  • Array 和 Map 具有 Capacity 属性, 对应于对象的当前数组或 Map 分配的容量属性.

其他多余的 Obj函数(对应于 Object 的内置方法) 被删除. ObjHasOwnProp(以前的 ObjHasKey) 和 ObjOwnProps(以前的 ObjNewEnum) 被保留下来, 以便于安全检查重新定义了这些方法的对象(以及没有定义这些方法的原始原型). ObjCount 被 ObjOwnPropCount 取代(仅是一个函数, 适用于所有对象), Map 具有自己的 Count 属性.

ObjRawGet 和 ObjRawSet 合并为 GetOwnPropDesc 和 DefineProp. 添加它们的最初原因被其他变化所取代, 例如 Map 类型, 元函数工作方式的变化以及 DefineProp 本身在某些方面取代了元函数.

顶级类的定义现在创建了一个常量(只读变量); 也就是说, 现在对类名的赋值是一个错误, 而不是一个可选的警告, 除非是局部变量遮蔽了全局类(现在在函数内部赋值时默认发生).

原始值

原始值通过将方法和属性调用委托给基于其类型的原型对象来模拟对象, 而不是 V1 的 "默认基对象". Integer 和 Float 继承于 Number. String 和 Number 继承于 Primitive. Primitive 和 Object 继承于 Any. 这些都作为预定义的类存在.

属性和方法

与 v2.0-a104 到 v2.0-a127 不同, 方法是由属性定义的, 方法与属性是分开的. 然而, 与 v1 不同的是, 由类方法定义(或内置方法) 创建的属性默认为只读. 方法仍然可以通过分配新的值属性来创建, 这通常与 v1 中的作用相同.

Object 类定义了处理属性和方法的新方法: DefineProp, DeleteProp, GetOwnPropDesc, HasOwnProp, OwnProps. 为所有的值定义了额外的方法(除了 ComObjects): GetMethod, HasProp, HasMethod.

Object, Array 和 Map 现在是独立的类型, 数组元素与属性是分开的.

所有内置方法和属性(包括 base) 的定义方式与用户定义的相同. 这确保了行为的一致性, 并允许检测, 检索或重新定义内置和用户定义的成员.

如果属性不接受参数, 它们会自动传递给由该属性返回的对象(或者抛出).

试图检索一个不存在的属性对于所有类型的值或对象来说都被视为一个错误, 除非 __get 被定义. 然而, 在大多数情况下, 设置一个不存在的属性将创建它.

多维数组技巧被删除. x.y[z]:=1 不再在 x.y 中创建一个对象, 并且 x[y,z] 是一个错误, 除非 x.__item 处理两个参数(或者 x.__item.__item 处理, 等等.).

如果一个属性定义了 get 但没有 set, 赋值会抛出而不是覆盖该属性.

DefineProp 可以用来定义检索, 设置 或调用 特定的属性时会发生什么, 而不需要定义任何元函数. 类中的属性和方法定义使用相同的机制, 因此可以用相同的名称定义属性 getter/setter(获取器/设置器) 和方法.

{} 对象原义语法现在直接设置 自有属性 的值或对象的 base. 也就是说, __Set 和属性设置器不再被调用(通常只有在参数列表中设置了 base 时才有可能).

Static/Class 变量

Static/class 初始化器现在在 static __Init 方法的上下文中执行, 所以 this 指的是类, 初始化器可以创建局部变量. 它们在类第一次被引用时被计算(而不是在自动执行部分开始前被计算, 严格按照定义的顺序). 如果类没有被更早地引用, 它们会在执行过程中到达类定义时被计算, 所以全局变量的初始化可以先发生, 而不用把它们放到类中.

元函数

元函数被大大简化了; 它们的行为就像普通方法一样:

  • 它们在层次结构中被定义的位置并不重要.
  • 如果被覆盖, 基本版本不会被自动调用. 如果需要, 脚本可以调用 super.__xxx().
  • 如果定义了, 它必须执行默认的动作; 例如, 如果 __set 不存储值, 它就不被存储.
  • 行为不依赖于方法是否使用 return (但当然, __get 和 __call 仍然需要返回一个值).

方法和属性参数是以数组形式传递的. 这对链式基类/超类的调用进行了优化, 并且(与 MaxParams 验证相结合) 鼓励作者处理 args. 对于__set, 被分配的值被单独传递.

this.__call(name, args)
this.__get(name, args)
this.__set(name, args, value)

定义的属性和方法优先于元函数, 不管它们是否被定义在基对象中.

__Call 不会在内部调用 __Enum(以前的 _NewEnum) 或 Call 时被调用, 例如当一个对象被传递到 for-loop 或一个函数对象被 SetTimer 调用时.

当每个类被初始化时, 静态方法 __New 被调用, 如果由该类定义或从超类继承. 有关详情, 请参阅 Static/Class 变量(上面的) 和 Class 初始化.

Array

class Array extends Object

数组对象包含值的列表或序列, 第一个元素的索引为 1.

当分配或检索一个数组元素时, 索引的绝对值必须在 1 和数组的 Length 之间, 否则会产生一个异常. 一个数组可以通过适当的方法插入或删除元素, 或者通过分配 Length 来调整大小.

目前在访问元素时需要使用括号, 即 a.1 指的是一个属性, 而 a[1] 指的是一个元素.

负值可以用来做反向索引.

Clone, Delete, InsertAt, Pop, Push 和 RemoveAt 的用法基本没有变化. HasKey 被重命名为 Has. Length 现在是一个属性. 增加 Capacity 属性.

数组可以用 Array(values*) 或 [values*] 构建. 可变函数接收一个数组的参数, 数组也由几个内置函数创建.

For-loop 的用法是 for val in arr 或 for idx, val in arr, 其中 idx = A_Index 是默认的. 也就是说, 缺乏值的元素仍然被枚举, 如果只传递一个变量, 则不返回索引.

Map

Map 对象是一个关联数组, 其功能类似于 v1 的对象, 但没有那么多歧义.

  • Clone 的使用方法和以前一样.
  • Delete 一次只能删除一个键.
  • HasKey 被改名为 Has.
  • Count 现在是一个属性.
  • 新属性: Capacity, CaseSense
  • 新方法: Get, Set, Clear
  • 字符串键默认是区分大小写的, 并且不会被转换为整数.

目前 Float 键仍然被转换为字符串.

在访问元素时, 需要使用括号; 例如 a.b 指的是一个属性, 而 a["b"] 指的是一个元素. 与 v1 不同, 一个属性或方法不能通过分配一个数组元素而被意外地禁用.

如果试图检索一个不存在的元素的值, 就会抛出异常, 除非地图定义了一个 Default 属性. MapObj.Get(key, default) 可以用来为每个请求显式地提供一个默认值.

使用 Map(Key, Value, ...) 从一个键值对列表中创建一个 Map.

枚举器

枚举器模型的变更:

  • __Enum(n) 替换了 _NewEnum().
  • 所需的参数 n 包含 for-loop 中的变量数量, 以允许它影响枚举, 而不必将初始化推迟到第一个迭代调用.
  • Call() 替换了 Next(), 除了 ByRef 的工作方式不同外, 用法相同; 例如, 定义为 Call(&a) 的方法应该分配 a := next_value 而 Call(a) 将接收一个 VarRef, 所以应该分配 %a% := next_value.
  • 如果 __Enum 不存在, 则假定该对象是一个枚举器. 这允许直接使用函数对象(如闭包).

由于数组元素和属性现在是分开的, 所以枚举属性需要通过调用 OwnProps 显式地创建一个枚举器.

绑定函数

当绑定函数被调用时, 由调用者传递的参数将填补在创建绑定函数时被省略的位置. 例如, F.Bind(,b).Call(a,c) 调用 F(a,b,c), 而不是 F(,b,a,c).

COM 对象(ComObject)

COM 封装对象现在可以识别为几个不同类的实例, 这取决于它们的变体类型(和以前一样, 这影响它们支持哪些方法和属性) :

  • ComValue 是所有 COM 包装器对象的基类.
  • ComObject 是 VT_DISPATCH 的非空指针; 也就是说, 通常是一个有效的 COM 对象, 可以由脚本使用正常的对象语法来调用.
  • ComObjArray 用于 VT_ARRAY(SafeArrays).
  • ComValueRef 用于 VT_BYREF.

这些类可以用 obj is ComObject 和类似的手段来进行类型检查. 通过修改各自的原型对象, 可以为 ComValue, ComObjArray 和 ComValueRef(但不是 ComObject) 类型的对象定义属性和方法.

ComObject(CLSID) 创建 ComObject; 也就是说, 这是新的 ComObjCreate.

注意: 如果你正在更新旧的代码, 并且由于向 ComObject 传递一个整数而得到一个 TypeError, 你很可能应该调用 ComValue 来代替.

ComValue(vt, value) 创建一个封装对象. 它可以返回上面列出的任何类的实例. 这取代了 ComObjParameter(vt, value), ComObject(vt, value) 以及作为参数与 变体类型 和 value 一起使用的任何其他名称. value 被转换为适当的类型(按照 COM 惯例), 而不是要求一个具有正确二进制值的整数. 特别是, 当传递一个整数时, 以下的行为与以前不同. R4, R8, Cy, Date. 指针类型像以前一样允许一个纯整数地址, 或者一个对象/ComValue.

ComObjFromPtr(pdsp) 是一个类似于 ComObjEnwrap(dsp) 的函数, 但与 ObjFromPtr 一样, 它不调用指针上的 AddRef. 在 v1 中的等价物是 ComObject(9, dsp, 1); 在 v1 中省略第三个参数会引起 AddRef.

对于 ComValue 和 ComObjFromPtr, 请注意 AddRef 永远不会被自动调用; 在这方面, 它们的行为与 v1 中的 ComObject(9, value, 1) 或 ComObject(13, value, 1) 类似. 这并不一定意味着你在更新旧的脚本时应该添加 ObjAddRef(value) 因为许多脚本错误地使用了旧函数.

具有变体类型 VT_BYREF, VT_ARRAY 或 VT_UNKNOWN 的 COM 封装对象现在有一个 Ptr 属性, 相当于 ComObjValue(ComObj). 这允许它们以 Ptr 参数类型被传递给 DllCall 或 ComCall. 它还允许将对象直接传递给 NumPut 或 NumGet, 这可以与 VT_BYREF(访问调用者的类型变量), VT_ARRAY(访问 SAFEARRAY 字段) 或 VT_UNKNOWN(检索 vtable 指针) 一起使用.

具有变体类型 VT_DISPATCH 或 VT_UNKNOWN 和空接口指针的 COM 封装对象现在有一个 Ptr 属性, 可以被读取或分配. 一旦分配了一个非空的指针, 该属性就是只读的. 这是为了与 DllCall 和 ComCall 一起使用, 所以在函数返回后不需要手动包装指针.

ComObjArray 的枚举现在与 Array 一致; 例如 for value in arr 或 for index, value in arr, 而不是 for value, vartype in arr. index 索引的起始值是 ComObjArray(arr.MinIndex()) 的下限, 通常是 0.

整数类型 I1, I8, UI1, UI2, UI4 和 UI8 现在被转换为整数, 而不是字符串. 这些在 COM 调用中很少发生, 但这也适用于 VT_BYREF 包装器. VT_ERROR 不再被转换为整数, 而是产生一个 ComValue.

当属性或方法调用失败时, COM 对象不在设置 A_LastError.

默认属性

COM 对象可能有一个 "默认属性", 它有两种用途:

  • 对象的 value, 例如, 在 VBScript 中, MsgBox obj 通过调用其默认成员来计算该对象.
  • 一个集合的索引属性, 通常被命名为 Item 或 item.

AutoHotkey v1 没有默认属性的概念, 所以如果省略了属性名称, COM 对象包装器会调用默认属性; 即 obj[] 或 obj[,x].

然而, AutoHotkey v2 将属性与数组/Map/集合项分开, 为此 obj[x] 被映射到对象的默认属性(无论 x 是否存在). 对于 AutoHotkey 对象, 这就是 __Item.

一些代表数组或集合的 COM 对象不公开默认属性, 所以在 v2 中不能用 [] 来访问项目. 例如, JavaScript 数组对象和其他一些通常与 JavaScript 一起使用的对象将数组元素作为属性公开. 在这种情况下, arr.%i% 可以用来访问一个数组元素的属性.

当 AutoHotkey v2 的 Array 对象被传递给 JavaScript 时, 它的元素不能被 JavaScript 的 arr[i] 检索, 因为这将试图访问一个属性.

COM 调用

通过 IDispatch 接口对 AutoHotkey 对象的调用现在透明地支持 VT_BYREF 参数. 这最常被用于 COM 事件(ComObjConnect).

对于 VT_BYREF 参数, 一个未命名的临时 var 被创建, 其值从调用者的变量中复制, 并且一个 VarRef 被传递给 AutoHotkey 函数/方法. 返回时, 值从临时变量中复制到调用者的变量中.

一个函数/方法可以通过声明参数 ByRef(用 &) 或显式解引来赋值.

例如, VT_BYREF|VT_BOOL 类型的参数以前会收到一个 ComObjRef 对象, 并且会被赋值, 如 pbCancel[] := true 或 NumPut(-1, ComObjValue(pbCancel), "short"). 现在, 这个参数可以被定义为 &bCancel 并像 bCancel := true 那样赋值; 或者可以被定义为 pbCancel 并像 %pbCancel% := true 那样赋值.

库

删除的命令, 函数 & 指令

删除的 | 备注
Asc() | 请使用 Ord 代替.
AutoTrim | 请使用 Trim 代替.
ComObjMissing() | 改为连续写两个逗号.
ComObjUnwrap() | (如果需要, 请使用 ComObjValue 和 ObjAddRef.
ComObjEnwrap() | 如果需要, 请使用 ComObjFromPtr 和 ObjAddRef.
ComObjError() |
ComObjXXX() | 如果 XXX 是显式定义的 ComObj 函数以外的任何东西, 请使用 ComObjActive, ComValue 或 ComObjFromPtr 代替.
ControlSendRaw | 请使用 ControlSend "{Raw}" 或 ControlSendText 代替.
EnvDiv | 请使用 / 或 /= 代替, 例如 a /= b.
EnvMult | 请使用 * 或 *= 代替, 例如 a *= b.
EnvUpdate | 它的用处非常有限, 可以用一个简单的 SendMessage 代替: SendMessage(0x1A, 0, StrPtr("Environment"), 0xFFFF).
Exception | 请使用 Error 或一个适当的子类.
FileReadLine | 请使用 文件读取循环或 FileOpen 代替.
Func | 请使用 MyFunc 这样的直接引用代替.
Gosub |
Gui GuiControl GuiControlGet | 请参阅 Gui.
IfEqual | 请使用 If 和 = 代替, 例如 if a = b.
IfExist | 请使用 If 和 FileExist 代替, 例如 if FileExist(...).
IfGreater | 请使用 If 和 > 代替, 例如 if a > b.
IfGreaterOrEqual | Use If 和 >= 代替, 例如 if a >= b.
IfInString | 请使用 If 和 InStr 代替, 例如 if InStr(...).
IfLess | 请使用 If 和 < 代替, 例如 if a < b.
IfLessOrEqual | 请使用 If 和 <= 代替, 例如 if a <= b.
IfMsgBox | MsgBox 现在返回按钮名称.
IfNotEqual | 请使用 If 和 != 代替, 例如 if a != b.
IfNotExist | Use If 和 FileExist 代替, 例如 if not FileExist(...).
IfNotInString | 请使用 If 和 InStr 代替, 例如 if not InStr(...).
IfWinActive | 请使用 If 和 WinActive 代替, 例如 if WinActive(...).
IfWinExist | 请使用 If 和 WinExist 代替, 例如 if WinExist(...).
IfWinNotActive | 请使用 If 和 WinActive 代替, 例如 if not WinActive(...).
IfWinNotExist | 请使用 If 和 WinExist 代替, 例如 if not WinExist(...).
If between | 请参阅 If 示例 #5.
If in/contains | 请参阅 If 示例 #6.
If is | 请参阅 isXXX.
Input | 请使用 InputHook 代替.
IsByRef | 请参阅 ByRef 限制.
IsFunc |
Menu | 请使用 Menu/MenuBar 类, TraySetIcon, A_IconTip, A_IconHidden 和 A_AllowMainWindow.
MenuGetHandle | 请使用 Menu.Handle 代替.
MenuGetName | 没有菜单名称; MenuFromHandle 是最接近的替代方法.
Progress | 请使用 Gui 代替.
SendRaw | 请使用 Send "{Raw}" 或 SendText 代替.
SetBatchLines | -1 现在是默认行为.
SetEnv | 请使用 := 代替.
SetFormat | Format 可以用来格式化字符串.
SoundGet SoundSet | 请参阅 Sound 函数.
SoundGetWaveVolume SoundSetWaveVolume | 在平衡方面与 SoundGet 和 SoundSet 的行为略有不同, 但都没有保留平衡.
SplashImage | 请使用 Gui 代替.
SplashTextOn/Off | 请使用 Gui 代替.
StringCaseSense | != 不区分大小写( 但 !== 被添加为区分大小写的不相等), 并且 = 和 != 只忽略 ASCII 字符的大小写. 添加 StrCompare 用于使用任何模式比较字符串. 各种字符串函数现在都有一个 CaseSense 参数, 可用于指定是否区分大小写或区域设置模式.
StringGetPos | 请使用 InStr 代替.
StringLeft StringLen StringMid StringRight StringTrimLeft StringTrimRight | 请使用 SubStr 代替.
StringReplace | Use StrReplace 代替.
StringSplit | 请使用 StrSplit 代替.
Transform | 请使用数学函数和运算符代替. 有关 Transform Deref, 请参阅 RegExMatch 示例 #8. 有关 Transform HTML, 请参阅 HTML Entities Encoding.
VarSetCapacity | 对二进制数据/结构, 请使用 Buffer 对象, 对 UTF-16 字符串, 请使用 VarSetStrCapacity.
WinGetActiveStats | 请使用 WinGetTitle 和 WinGetPos 代替.
WinGetActiveTitle | 请使用 WinGetTitle 代替, 例如 WinGetTitle "A".
#CommentFlag |
#Delimiter |
#DerefChar |
#EscapeChar |
#HotkeyInterval | 请使用 A_HotkeyInterval 代替.
#HotkeyModifierTimeout | 请使用 A_HotkeyModifierTimeout 代替.
#IfWinActive #IfWinExist #IfWinNotActive #IfWinNotExist | 请参阅 #HotIf 优化.
#InstallKeybdHook | 请使用 InstallKeybdHook 代替.
#InstallMouseHook | 请使用 InstallMouseHook 代替.
#KeyHistory | 请使用 KeyHistory N 代替.
#LTrim | 如果需要, 请使用 LTrim 选项.
#MaxHotkeysPerInterval | 请使用 A_MaxHotkeysPerInterval 代替.
#MaxMem | 每个变量的最大容量现在没有限制.
#MenuMaskKey | 请使用 A_MenuMaskKey 代替.
#NoEnv | 现在是默认行为.

重命名的命令, 函数 & 指令

v1 Name | v2 Name
ComObjCreate() | ComObject, 它现在是一个类
ComObjParameter() | ComValue, 它现在是一个类
DriveSpaceFree | DriveGetSpaceFree
EnvAdd | DateAdd
EnvSub | DateDiff
FileCopyDir | DirCopy
FileCreateDir | DirCreate
FileMoveDir | DirMove
FileRemoveDir | DirDelete
FileSelectFile | FileSelect
FileSelectFolder | DirSelect
#If | #HotIf
#IfTimeout | HotIfTimeout
StringLower | StrLower 和 StrTitle
StringUpper | StrUpper 和 StrTitle
UrlDownloadToFile | Download
WinMenuSelectItem | MenuSelect
LV, TV 和 SB 函数 | GuiControl 的方法
File.__Handle | File.Handle

修改的命令, 函数 & 指令

关于这一节的标题: v2 中没有命令, 只有函数. 标题涉及两个版本.

当使用 SendEvent 方法发送 Alt 事件时, BlockInput 不再临时禁用. 这最初是为了解决 Windows XP 某些版本中的一个 bug, 其中 BlockInput 阻止了人工 Alt 事件.

Chr(0) 返回一个长度为 1 的字符串, 包含一个二进制零. 这是改进了对字符串中二进制零的支持的结果.

如果等待期过了, ClipWait 现在返回 0(false), 否则返回 1(true). ErrorLevel 被删除. 指定 0 不再等同于指定 0.5; 相反, 它产生尽可能短的等待.

ComObj(): 这个函数有一种通配符的名字, 允许许多不同的后缀. 有些名字通常用于特定类型的参数, 如 ComObjActive(CLSID), ComObjParameter(vt, value), ComObjEnwrap(dsp). 取而代之的是单独的函数/类, 不再有通配符名称. 有关详情, 请参阅 COM 对象(ComObject).

Control: 对 Control 函数, SendMessage 和 PostMessage 使用的 Control 参数做了一些修改:

  • 它现在可以接受 HWND(必须是一个纯整数) 或具有 Hwnd 属性的对象, 如 GuiControl 对象. HWND 可以识别一个控件或一个顶级窗口, 尽管后者通常只对少数几个函数才有意义(见下文).
  • 它不再是可选的, 除了可以操作顶级窗口的函数(ControlSend[Text], ControlClick, SendMessage, PostMessage) 或前面有其他可选的参数时(ListViewGetContent, ControlGetPos, ControlMove).
  • 如果省略, 就会使用目标窗口来代替. 这与之前 SendMessage/PostMessage 的行为相匹配, 并取代了 ControlSend 之前使用的 ahk_parent 特殊值.
  • 空白的值是无效的. 函数从不默认目标窗口的最顶层的控件.

ControlGetFocus 现在返回控件的 HWND, 而不是其 ClassNN, 并且当它成功确定窗口没有焦点控件时, 不再认为有错误.

ControlMove, ControlGetPos 和 ControlClick 现在使用客户端坐标(像 GuiControl) 而不是窗口坐标. 客户端坐标是相对于客户端区域的左上方而言的, 它不包括窗口的标题栏和边框. (控件只在客户端区域内渲染.)

ControlMove, ControlSend 和 ControlSetText 现在使用与其他 Control 函数一致的参数顺序; 即 Control, WinTitle, WinText, ExcludeTitle, ExcludeText 总是组合在一起(在参数列表的最后), 以帮助记忆.

CoordMode 不再接受 "Relative" 作为一种模式, 因为所有模式都是相对于某个东西的. 它与 "Window" 同义, 所以用它代替.

DllCall: 请参阅下面的 DllCall 部分.

如果没有被注册 "edit" shell 动词, Edit 以前有针对 .ini 文件类型的后备行为. 由于脚本文件不需要有 .ini 扩展名. AutoHotkey.ini 是旧版本 AutoHotkey 中的默认脚本名称.

如果脚本是从 stdin 中读取的, 那么现在 Edit 不会做任何事情, 而会尝试为 * 打开一个编辑器.

如果完全省略了 Value 参数, EnvSet 现在删除环境变量.

以前, 当脚本不是持续运行时, Exit 作为 ExitApp 使用, 即使有其他挂起的线程被调用 Exit 的线程打断. 现在它不再这样做了. 相反, 它总是正确地退出当前线程, 并且(如果不是持续运行的) 脚本只在最后一个线程退出后才终止. 这保证了 Finally 语句的执行和局部变量的释放, 这可能允许对局部变量所包含的任何对象调用 __delete .

FileAppend 默认为没有行末转换, 与 FileRead 和 FileOpen 一致. FileAppend 和 FileRead 都有一个单独的 Options 参数, 它取代了选项前缀, 并可能包括一个可选的编码名称(取代 FileRead 的 *Pnnn 选项). FileAppend, FileRead 和 FileOpen 使用 "`n" 来实现行末转换. FileAppend 和 FileRead 支持 "RAW" 选项来禁用编码转换(读/写二进制数据); FileRead 在这种情况下返回一个 Buffer 对象. 这取代了 *c(请参阅 ClipboardAll). FileAppend 可以接受一个类 Buffer 对象, 在这种情况下不进行转换.

如果源路径不包含 * 或 ? 并且没有找到文件, FileCopy 和 FileMove 现在抛出异常. 然而, 当源路径包含通配符时, 复制或移动零个文件仍然不被视为错误.

FileOpen 现在如果它不能打开文件, 则抛出异常. 否则, 在第一次尝试访问对象时就会抛出异常(如果脚本没有检查失败), 而不是在实际的失败点抛出异常.

File.RawRead: 当一个变量被直接传递时, 该变量的内部字符串缓冲的地址不再被使用. 因此, 一个包含地址的变量可以直接传递(而在 v1 版中, 类似 var+0 的东西是必须的).

对于由脚本分配的缓冲, 新的 Buffer 对象比变量更受欢迎; 可以使用任何对象, 但必须有 Ptr 和 Size 属性.

File.RawWrite: 和上面一样, 除了它可以接受一个字符串(或包含一个字符串的变量), 在这种情况下 Bytes 默认为字符串的字节大小. 字符串可以包含二进制的零.

File.ReadLine 现在总是支持 `r, `n 和 `r`n 作为行尾, 并且不再在返回值中包括行尾. 如果没有启用 EOL 转换, File.Read 仍会按原样返回给脚本.

FileEncoding 现在允许用数字来指定代码页, 而不使用 CP 前缀. 其参数不再为可选, 但任然可以显式的指定为空值.

FileExist 现在忽略了每个目录列表中隐含的 . 和 .., 因此当目录存在但为空时, FileExist("dir\*") 现在是 false, 而不是 true.

FileGetAttrib 和 A_LoopFileAttrib 现在对解析点或符号链接包含字母 "L".

如果源文件和目标文件是同一路径, 非编译脚本中的 FileInstall 不再尝试复制文件(在解析了相对路径之后, 因为源文件相对于 A_ScriptDir, 而不是 A_WorkingDir). 在 v1 中, 这导致 ErrorLevel 被设置为 1, 这通常不会被注意到. 试图通过两个不同的路径将一个文件复制到自身仍然会导致错误.

FileSelectFile(现在名为 FileSelect) 有两种多选模式, 可以通过选项 4 和 M 来访问. 选项 4 和相应的模式已经被删除; 它们已经有一段时间没有记录了. 当使用多选模式时, FileSelect 现在会返回一个路径的数组, 而不是像 C:\Dir`nFile1`nFile2 这样的字符串. 每个数组元素都包含一个文件的完整路径. 如果用户取消了, 数组就是空的.

FileSelect 现在使用 Windows Vista 及以后版本中的 IFileDialog API, 而不是以前的 GetOpenFileName/GetSaveFileName API. 这样就不需要使用与对话框改变当前工作目录有关的(内置) 解决方法.

当省略 Filter 时, FileSelect 默认不再有一个多余的 "Text Documents (*.txt)"/"文本文档(*.txt)" 过滤器.

FileSelect 不再从过滤器模式中剥离空格, 例如 pattern with spaces*.ext . 测试表明模式两侧的空格(例如 *.cpp; *.h) 中分号后的空格) 已经被操作系统忽略, 所以应该不会有负面影响.

FileSelect 现在可以通过 D 选项字母在 "选择文件夹" 模式下使用.

FileSetAttrib 现在可以在没有 +, - 或 ^ 前缀的情况下覆盖属性, 而不是什么都不做. 例如, FileSetAttrib(FileGetAttrib(file2), file1) 将 file2 的属性复制到 file1 中(添加 file2 有的属性并删除其没有的属性).

FileSetAttrib 和 FileSetTime: OperateOnFolders 和 Recurse 参数已被一个与 Loop Files 相同的 Mode 参数所取代. 例如, FileSetAttrib("+a", "*.zip", "RF")(只对 Files 进行递归操作).

GetKeyName 现在返回 VK 代码的非 Numpad 名称, 这些名称对应于 Numpad 和非 Numpad 键. 例如, GetKeyName("vk25") 返回 Left, 而不是 NumpadLeft.

GetKeyState 现在始终返回 1 或 0 来取代 On 和 Off.

GroupActivate 现在返回被选中激活的窗口的 HWND, 如果没有匹配的窗口(除了已经激活的窗口), 则返回 0, 而不是设置 ErrorLevel.

GroupAdd: 删除了 Label 参数和相关功能. 这是一种不直观的方式, 用于检测 GroupActivate 未能找到任何匹配的窗口; 应该改为使用 GroupActivate 的返回值来代替.

GroupDeactivate 现在以更接近 Alt+Esc 和 Alt+Shift+Esc 系统热键和任务栏的方式选择窗口. 具体而言,

  • 不计算拥有的窗口. 如果所有者窗口符合条件(与组不匹配), 所有者窗口或其拥有的一个窗口被激活; 以最后激活的为准. 一个由组成员拥有的窗口将不再被激活, 但将拥有的窗口本身添加到组中现在没有任何影响. (以前的行为是循环浏览每个拥有的窗口, 而从不激活其所有者.)
  • 任何被禁用的窗口都会被跳过, 除非其拥有的一个窗口最近比它更活跃.
  • 具有 WS_EX_NOACTIVATE 风格的窗口被跳过, 因为它们可能不应该被激活. 它们也会被 Alt+Esc 和 Alt+Shift+Esc 系统热键跳过.
  • 具有 WS_EX_TOOLWINDOW 但不具有 WS_EX_APPWINDOW 的窗口被从任务栏和 Alt-Tab 中省略, 因此被跳过.

Hotkey 不再默认为脚本中最底层 #HotIf(以前是 #If). 热键/热字串和 HotIf 线程默认为与热键相同的条件, 因此 Hotkey A_ThisHotkey, "Off" 会关闭当前热键, 即使它是上下文相关的. 所有其他线程默认为自动执行部分使用的最后一个设置, 它本身默认为没有条件(全局热键).

Hotkey 的 Action 参数现在需要一个函数对象或热键名称. 不再支持标签和函数名称. 如果指定了一个热键名称, 则使用该热键的原始函数; 而且与以前不同的是, 这与 #HotIf(以前的 #If) 一起工作.

  • 其他好处, 这消除了以下特殊字符串的歧义: On, Off, Toggle, AltTab, ShiftAltTab, AltTabAndMenu, AltTabMenuDismiss. 以前的行为是使用该名称的标签/函数(如果存在的话), 但只有在 Label 参数不包含变量引用或表达式的情况下.

Hotkey 和 Hotstring 现在支持选项 S 以使热键/热串免于暂停 Suspend(相当于新的 #SuspendExempt 指令), 以及选项 S0 以禁止免于暂停.

"Hotkey If" 和其他 If 子命令被替换为单独的函数: HotIf, HotIfWinActive, HotIfWinExist, HotIfWinNotActive, HotIfWinNotExist.

HotIf(以前的 "Hotkey If") 现在可以识别使用 and 或 or 运算符的表达式. 这在 v1 中不起作用, 因为这些运算符在加载时被替换为 && 或 ||.

Hotkey 不再有 UseErrorLevel 选项, 也不再设置 ErrorLevel. 失败时将抛出异常. 错误信息被改为恒定的(而且更短), 在 Exception.Extra 中包含了按键或热键的名称, 而异常的类别则表示失败的原因.

#HotIf(以前的 #If) 现在隐式地创建了带有参数(ThisHotkey) 的函数. 如同所有函数的默认情况一样, 这个函数是假设-本地的. 该表达式可以创建局部变量和读取全局变量, 但不能直接赋值给全局变量, 因为该表达式不能包含声明.

#HotIf 已经被优化, 因此对 WinActive() 或 WinExist() 的简单调用可以由钩子线程直接计算(就像 #IfWin 在 v1 中一样, 而 HotIfWin 仍然是). 这提高了性能, 并减少了脚本繁忙/无响应时出现问题的风险. 该优化适用于包含对 WinActive() 或 WinExist() 的单次调用, 最多有两个参数的表达式, 其中每个参数是一个简单的带引号的字符串, 结果可以选择用 ! 或 not. 例如, #HotIf WinActive("Chrome") 或 #HotIf !WinExist("Popup"). 在这些情况下, 具有任何给定标准组合的第一个表达式可以由表达式或窗口标准来确定. 例如, HotIf '!WinExist("Popup")' 和 HotIfWinNotExist "Popup" 指的是相同的热键变体.

KeyHistory N 调整按键历史缓冲的大小, 而不是显示按键历史. 这取代了 "#KeyHistory N".

ImageSearch 如果找到了图片, 则返回 1(true), 如果没有找到, 则返回 0(false), 如果不能进行搜索, 则抛出异常. 不设置 ErrorLevel.

IniDelete, IniRead 和 IniWrite 设置 A_LastError 为操作系统的 GetLastError() 函数的结果.

IniRead 抛出异常, 如果不能找到所请求的键, 段或文件, 并且省略了 Default 数. 如果 Default 被赋予一个值, 甚至是 "", 则不会抛出异常.

InputHook 将 Shift+Backspace 视为 Backspace, 而不是把它转录为 `b.

InputBox 进行了语法上的革新, 使其更容易使用(参数更少). 使用方法, 请参阅 InputBox.

InStr 的 CaseSensitive 参数已被 CaseSense 替换, 它可以是 0, 1 或 "Locale".

现在, InStr 在 Occurrence 为负数时从右向左搜索(以前会导致结果为 0), 如果在 Occurrence 为正数时使用负的 StartingPos 则不再从右向左搜索. (然而, 如果 StartingPos 是负的, 而 Occurrence 是省略的, 它仍然从右向左搜索.) 这有利于在循环中进行从右到左的搜索, 并允许在使用负的 StartingPos 的同时仍然从左到右搜索.

  • 例如, InStr(a, b,, -1, 2) 现在从左到右搜索. 如果要从右向左搜索, 请使用 InStr(a, b,, -1, -2).
  • 注意 StartingPos 为 -1 意味着 v2 中的最后一个字符, v1 中的倒数第二个字符. 如果上面的例子来自 v1(而不是 v2.0-a033 - v2.0-a136), 新代码应该是 InStr(a, b, -2, -2).

KeyWait 现在如果等待期过了就返回 0(false), 否则返回 1(true). 删除了 ErrorLevel.

MouseClick 和 MouseClickDrag 不再受交换鼠标按钮的系统设置的影响; "Left" 始终是主按钮, 而 "Right" 是副按钮.

MsgBox 的语法发生了变化, 以优先考虑其最常用的参数, 并提高了易用性. 有关使用情况, 请参阅下面的 MsgBox.

NumPut/NumGet: 当直接传递变量时, 不再使用该变量的内部字符串缓冲的地址. 因此, 一个包含地址的变量可以直接传递(而在 v1 中, 类似 var+0 的东西是必须的). 对于由脚本分配的缓冲, 新的 Buffer 对象比变量更优先; 任何对象都可以使用, 但必须有 Ptr 和 Size 属性.

NumPut 的参数被重新排序, 以允许一连串的值, 每个数字前面都有(现在是强制性的) 类型字符串. 例如: NumPut("ptr", a, "int", b, "int", c, addrOrBuffer, offset). 类型现在对于 NumGet 也是必须的. (与 DllCall 相比, NumPut 的输入参数对应于 dll 函数的参数, 而 NumGet 的返回类型参数对应于 dll 函数的返回类型字符串.)

使用 Object(obj) 和 Object(ptr) 在引用和指针之间的转换被转移到单独的函数, ObjPtrAddRef(obj) 和 ObjFromPtrAddRef(ptr). 这些函数也有不增加引用计数的版本: ObjPtr(obj) 和 ObjFromPtr(ptr).

OnClipboardChange 标签不再被自动调用, 如果它存在的话. 使用在 v1.1.20 版本中添加的 OnClipboardChange 函数来代替. 现在它需要一个函数对象, 而不是一个名称.

OnError 现在需要一个函数对象, 而不是一个名称. 另请参阅下面的: 错误处理.

OnExit 命令已被移除; 请使用 v1.1.20 中添加的 OnExit 函数. 现在它需要一个函数对象, 而不是一个名称. A_ExitReason 也被删除了; 它的值可以作为 OnExit 回调函数的一个参数使用.

OnMessage 不再具有传递函数名(字符串) 时使用的单函数每条消息模式; 它现在只接受一个函数引用. 使用 OnMessage(x, MyFunc) 其中 MyFunc 是原义上的函数名称, 但请注意, V1 的等价物是 OnMessage(x, Func("MyFunc")), 允许其他函数继续监视消息 x, 这与 OnMessage(x, "MyFunc") 不同. 要停止监测消息, 请使用 OnMessage(x, MyFunc, 0), 因为 OnMessage(x, "") 和 OnMessage(x) 现在是错误的. 失败时, OnMessage 抛出异常.

当在热键的第一行使用时, Pause 不再豁免于 #MaxThreadsPerHotkey, 所以 #p::Pause 不再适用于切换暂停. 因此, Pause() 现在只暂停当前线程(对于像 ListVars/Pause 这样的组合), 而 Pause(Value) 现在始终在底层线程上操作. Value 必须是 0, 1 或 -1. 第二个参数被移除.

PixelSearch 和 PixelGetColor 使用 RGB 值而不是 BGR, 以便与其他函数保持一致. 如果出现问题, 这两个函数都会抛出异常, 并且不再设置 ErrorLevel. 如果找到了颜色, PixelSearch 返回 1(true). PixelSearch 的慢速模式已被删除, 因为它在大多数现代系统上是不可用的, 因为它与桌面合成不兼容.

PostMessage: 请参阅下面的 SendMessage.

Random 已被重做, 以利用操作系统的随机数生成器, 取消了一些限制, 并使其使用起来更加方便.

  • 现在支持完整的 64 位有符号整数值范围(从 32 位增加).
  • 浮点数由 53 位的随机整数生成, 而不是 32 位的随机整数, 并且应该大于或等于 Min 且小于 Max(但是浮点数的舍入误差理论上可以产生等于 Max 的结果).
  • 这些参数已经可以以任何顺序指定, 但现在只指定第一个参数时, 会将其他边界默认为 0 而不是 2147483647. 例如, Random(9) 返回一个 0 到 9 之间的数字.
  • 如果省略了两个参数, 则返回值是一个介于 0.0(包括) 和 1.0(一般不包括) 之间的浮点数, 而不是 0 和 2147483647(包括) 之间的整数.
  • 系统会自动给随机数生成器播种, 不提供手动播种的方法, 所以无法替代 NewSeed 参数.

RegExMatch 选项 O 和 P 被删除; O(对象) 模式现在是强制性的. RegExMatch 对象现在支持枚举(for-loop). 匹配对象的语法已经改变:

  • __Get 被用来实现速记的 match.subpat 其中 subpat 是一个子模式/捕获组的名称. 因为如果一个属性被 inherited, __Get 不再被调用, 以下的子模式名称不能再使用速记语法: Pos, Len, Name, Count, Mark. (例如, match.Len 总是返回整个匹配的长度, 而不是一个捕获的字符串.)
  • 最初, 匹配对象有方法而不是属性, 这样属性就可以保留给子模式名称, 由于新的语言行为意味着 match.name 默认会返回一个函数, 方法已经被替换为或补充为属性:
    • Pos, Len 和 Name 现在是属性和方法.
    • Name 现在需要一个参数以避免混淆(match.Name 抛出一个错误).
    • Count 和 Mark 现在只是属性.
    • Value 已被删除; 使用 match.0 或 match[] 而不是 match.Value(), 和 match[N] 而不是 match.Value(N).

RegisterCallback 被重命名为 CallbackCreate 并被改为更好地利用闭包:

  • 它现在支持函数对象(而不再支持函数名称).
  • 删除了 EventInfo 参数(使用闭包或绑定函数代替).
  • 删除了可变参回调函数的特殊行为, 并增加了 & 选项(传递参数列表的地址).
  • 增加了 CallbackFree(Address), 以释放回调内存并释放关联的函数对象.

注册表函数(RegRead, RegWrite, RegDelete): 在 v1.1.21+ 中增加的新语法现在是唯一的语法. 根键和子键被合并. 不写 RootKey, SubKey, 而写 RootKey\SubKey. 要连接到一个远程注册表, 使用 \\ComputerName\RootKey\SubKey 而不是 \\ComputerName:RootKey, SubKey.

RegWrite 的参数被重新排序, 像 IniWrite 一样把 Value 放在前面(但这并不影响单参数模式, 其中 Value 是唯一参数).

当 KeyName 被省略, 并且当前的循环注册项目是一个子键时; RegDelete, RegRead 和 RegWrite 现在对该子键内的值进行操作; 即在这种情况下, KeyName 默认为 A_LoopRegKey "\" A_LoopRegName(注意, A_LoopRegKey 与 A_LoopRegSubKey 合并了). 以前它们的表现如下:

  • RegRead 读取一个与子键同名的值, 如果父键中存在这样的子键.
  • RegWrite 返回一个错误.
  • RegDelete 删除该子键.

RegDelete, RegRead 和 RegWrite 现在允许在省略 KeyName 时指定 ValueName:

  • 如果当前循环注册表项是一个子键, ValueName 默认为空(子键的默认值) 并且必须指定 ValueType.
  • 如果当前的循环注册表项是一个值, ValueName 和 ValueType 默认为该值的名称和类型, 但其中一个或两个可以被覆盖.

否则, 带有空白或省略 ValueName的 RegDelete 现在会删除键的默认值(而不是键本身), 以便与 RegWrite, RegRead 和 A_LoopRegName 一致. 短语 "AHK_DEFAULT" 不再有任何特殊含义. 要删除一个键, 请使用 RegDeleteKey(新).

RegRead 现在有一个 Default 参数, 像 IniRead 一样.

RegRead 有一个未记录的 5 参数模式, 即在输出变量之后指定值类型. 这已被删除.

如果脚本是从 stdin 读取的, 那么现在 Reload 将不做任何事情.

Run 和 RunWait 不再识别 UseErrorLevel 选项, 因为 ErrorLevel 已被删除. 使用 Try/Catch 代替. A_LastError 被无条件地设置, 并且可以在捕获/抑制异常后进行检查. RunWait 返回退出代码.

Send(及其变体) 现在以一种与热键和 Click 一致的方式解释 {LButton} 和 {RButton}. 也就是说, LButton 是主按钮, RButton 是次按钮, 即使用户通过系统设置交换了这些按钮.

SendMessage 和 PostMessage 现在要求 wParam 和 lParam 是整数或具有 Ptr 属性的对象; 如果它们被赋予一个非数字的字符串或浮点, 则抛出异常. 以前, 如果表达式以 " 开头, 则通过地址传递字符串, 但其他字符串被强制为整数. 传递一个变量的地址(以前是 &var, 现在是 StrPtr(var)) 不再更新变量的长度(使用 VarSetStrCapacity(&var, -1)).

SendMessage 和 PostMessage 现在在失败(或超时) 时抛出异常, 并且不设置 ErrorLevel. SendMessage 返回消息回复.

SetTimer 不再支持标签或函数名称, 但由于它现在接受表达式, 并且函数可以直接通过名称引用, 用法看起来非常相似: SetTimer MyFunc. 与所有其他接受对象的函数一样, SetTimer 现在允许返回对象的表达式(以前它需要一个变量引用).

Sort 得到了以下变化:

  • VarName 参数已被分成独立的输入/输出参数, 以增加灵活性. 现在的用法是 Output := Sort(Input [, Options, Callback]).
  • 当任何两个项目比较相等时, 项目的原始顺序将自动作为决定顺序的因素, 以确保结果更加稳定.
  • C 选项现在也接受相当于其他函数的 CaseSense 参数的后缀(除 CL 外): CLocale CLogical COn C1 COff C0. 特别是, 对 "logical" 比较模式的支持是新加入的.

Sound 函数: 修改了 SoundGet 和 SoundSet 以更好地匹配 Vista+ 声音 API 的功能, 放弃了对 XP 的支持.

  • 删除了不支持的控制类型.
  • 删除了传统的混音器组件类型.
  • 让组件通过名称和/或索引来引用.
  • 让设备通过名称-前缀和/或索引来引用.
  • 分成独立的音量和静音功能.
  • 增加了 SoundGetName 用于检索设备或组件名称.
  • 增加了 SoundGetInterface 用于检索 COM 接口.

StrGet: 如果 Length 是负数, 它的绝对值表示要转换的确切字符数, 包括字符串可能包含的任何二进制零值 - 换句话说, 结果总是一个正好是这个长度的字符串. 如果 Length 是正数, 转换后的字符串在第一个二进制 0 处结束, 就像在 v1 中一样.

StrGet/StrPut: Address 参数可以是一个具有 Ptr 和 Size 属性的对象, 比如新的 Buffer 对象. 读/写会自动受到 Size(单位为字节) 的限制. 如果还指定了 Length 它不能超过 Size(对于 UTF-16 来说乘以 2).

StrPut 的返回值现在是以字节为单位, 所以它可以直接传递给 Buffer().

StrReplace 现在有一个 CaseSense 参数来代替 OutputVarCount, 它被移到了一个参数的右边, Limit 在它后面.

Suspend: 在热键或热串的第一行调用 Suspend 不再自动使其免于挂起. 相反, 使用 #SuspendExempt 或 S 选项. "Permit" 参数值不再有效.

Switch 现在默认对字符串进行区分大小写的比较, 并且有一个 CaseSense 参数, 可以覆盖区分大小写的模式, 强制进行字符串(而不是数字) 比较. 以前, 只有当 StringCaseSense 被改为 On 时, 它才区分大小写.

SysGet 现在只有数字子命令; 它的其他子命令已经被分割成函数. 有关详情, 请参阅子命令.

TrayTip 的用法已改为 TrayTip [Text, Title, Options]. Options 是一个由零个或多个不区分大小写的选项组成的字符串, 以空格或制表符分隔. 选项是 Iconx, Icon!, Iconi, Mute 和/或任何数值, 如以前一样. 即使省略了 Text 也会显示(现在比 V1 版更难意外地显示). Timeout 参数不再存在(它在 Windows Vista 或更高版本中没有作用). 脚本现在可以结合使用 NIIF_USER(0x4) 和 NIIF_LARGE_ICON(0x20) 标记 (0x24) 来在通知中包含大版本的托盘图标. NIIF_USER(0x4) 也可以单独用于小图标, 但无法在所有操作系统中产生一致的结果.

#Warn UseUnsetLocal 和 UseUnsetGlobal 已经被删除, 因为现在读取一个未设置的变量会抛出错误. 可以使用 IsSet 来避免错误, 也可以使用 Try/Catch 或 OnError 来处理它.

添加了 #Warn VarUnset 它默认为 MsgBox. 如果没有禁用, 在变量从未被用作直接的, 非动态的赋值或引用运算符(&) 的目标, 或直接传递给 IsSet 时, 对于每个变量的第一个非动态引用会给出警告.

#Warn Unreachable 不再认为 Exit 调用后的行是不可达的, 因为 Exit 现在是一个普通函数.

#Warn 已被删除, 因为顶级类不再被赋值所覆盖. (然而, 它们现在可以被一个局部变量隐式地覆盖; 这可以被 #Warn LocalSameAsGlobal 检测到.)

WinActivate 现在在第一次尝试激活一个窗口失败后会发送 {Alt up} 测试表明这减少了任务栏按钮闪烁的情况. 有关详情, 请参阅相关文档.

WinClose 和 WinKill: 对于 SecondsToWait, 指定 0 不再等同于指定 0.5; 相反, 它会产生最短的等待时间.

WinSetTitle 和 WinMove 现在使用与其他 Win 函数一致的参数顺序; 即 WinTitle, WinText, ExcludeTitle, ExcludeText 总是组合在一起(在参数列表的最后), 以帮助记忆.

各种函数的 WinTitle 参数现在可以接受一个 HWND(必须是纯整数) 或一个具有 Hwnd 属性的对象, 如一个 Gui 对象. 在这种情况下, DetectHiddenWindows 会被忽略, 除了当与 WinWait 或 WinWaitClose 一起使用时.

WinMove 不再对原义单词 DEFAULT 进行特殊处理. 省略该参数或指定一个空字符串代替(这适用于 v1 和 v2).

WinWait, WinWaitClose, WinWaitActive 和 WinWaitNotActive 在等待结束(超时未过) 时返回非零值). ErrorLevel 被删除. WinWait 和 WinWaitActive 返回找到的窗口的 HWND. WinWaitClose 现在设置了最后找到的窗口, 所以如果 WinWaitClose 超时, 它返回 0(false), WinExist() 返回最后找到的窗口. 对于 Timeout, 指定 0 不再等同于指定 0.5; 相反, 它产生了尽可能短的等待.

未分类:

InStr, SubStr, RegExMatch 和 RegExReplace 的负的 StartingPos 被解释为从末尾开始的位置. 位置 -1 是最后一个字符, 位置 0 是无效的(而在 V1 中, 位置 0 是最后一个字符).

以前接受 On/Off 或 On/Off/Toggle(但不接受其他字符串) 的函数现在需要 1/0/-1 来代替. On 和 Off 通常会被替换成 True 和 False. 原先返回 On/Off 的变量现在返回 1/0, 这在表达式中更加有用.

  • #UseHook 和 #MaxThreadsBuffer 允许 1, 0, True 和 False. (不像其他的, 它们实际上不支持表达式.)
  • ListLines 允许省略或布尔值.
  • ControlSetChecked, ControlSetEnabled, Pause, Suspend, WinSetAlwaysOnTop 和 WinSetEnabled 允许 1, 0 和 -1.
  • A_DetectHiddenWindows, A_DetectHiddenText 和 A_StoreCapsLockMode 使用布尔值(相应的函数也是如此).

以下函数返回一个纯整数, 而不是十六进制字符串:

  • ControlGetExStyle
  • ControlGetHwnd
  • ControlGetStyle
  • MouseGetPos
  • WinActive
  • WinExist
  • WinGetID
  • WinGetIDLast
  • WinGetList (在数组中)
  • WinGetStyle
  • WinGetStyleEx
  • WinGetControlsHwnd(在数组中)

A_ScriptHwnd 返回纯整数.

DllCall

如果类型参数是变量, 该变量的内容总是被使用, 而不是它的名称. 换句话说, 不再支持不加引号的类型名 - 类型名必须用引号括起来.

当 DllCall 更新以 Str 或 Str 形式传递的变量的长度时, 它现在会检测字符串是否正确地空终止(可能表明发生了缓冲溢出), 如果是这样, 会以错误消息终止程序, 因为不能保证安全执行.

AStr(没有任何后缀) 现在是只输入的. 因为缓冲永远只和输入字符串一样大, 所以它通常对输出参数没有用. 如果 AutoHotkey 被编译为 ANSI, 这将适用于 WStr 而不是 AStr, 但官方的 v2 版本只被编译为 Unicode.

如果一个函数向 Str*, AStr* 或 WStr* 参数写入一个新的地址, DllCall 现在会将新的字符串分配给相应的变量(如果有的话), 而不是仅仅更新原始字符串的长度(可能没有变化). 这种类型的参数通常不是用来修改输入的字符串, 而是在新的地址传回一个字符串.

DllCall 现在为任何 Ptr 参数和 Function 参数接受一个对象; 该对象必须有一个 Ptr 属性. 对于脚本分配的缓冲, 新的 Buffer 对象优先于变量. 对于 Ptr*, 参数的新值被分配回对象的 Ptr 属性. 这允许诸如 DllCall(..., "Ptr*", unk := IUnknown()) 这样的结构, 与 DllCall(..., "Ptr*", punk), unk := IUnknown(punk) 相比, 减少了重复, 并且可以用来确保函数的任何输出被正确释放(即使由于 HRESULT 返回类型而抛出异常, 尽管通常在这种情况下函数不会输出一个非空指针).

DllCall 现在要求数字型参数的值必须是数字, 如果给出的是非数字或空字符串, 则会抛出异常. 特别是, 如果输出参数使用了 * 或 P 的后缀, 输出变量需要被初始化.

如果脚本传递一个包含数字的普通变量, 那么带有 * 或 P 后缀的数字参数的输出值(如果有的话) 会被忽略. 要接收输出值, 请传递一个 VarRef, 如 &myVar 或一个具有 Ptr 属性的对象.

如果函数失败, 新的 HRESULT 返回类型会抛出异常(int < 0 或 uint & 0x80000000). 这应该只用于实际返回 HRESULT 的函数.

Loop 子命令

子命令关键词必须按原义书写, 不能用引号括起来, 也不能是一个变量或表达式. 所有其他参数都是表达式. 所有循环子命令现在都支持 OTB.

已删除的:

Loop, FilePattern [, IncludeFolders, Recurse]
Loop, RootKey [, Key, IncludeSubkeys, Recurse]

使用下面的方法(在 v1.1.21 中添加) 来代替:

Loop Files, FilePattern [, Mode]
Loop Reg, KeyName [, Mode]

第二个单词后面的逗号现在是可选的.

A_LoopRegKey 现在包含根键和子键, 而 A_LoopRegSubKey 已被删除.

InputBox

InputBoxObj := InputBox([Prompt, Title, Options, Default])

Options 参数接受零个或多个不区分大小写的选项的字符串, 以空格或制表符为界, 类似于 Gui 控件选项. 例如, 这包括所有支持的选项: "x0 y0 w100 h100 T10.0 Password*". T 是超时, 而 Password 的用法与同等的 Edit 控件选项相同.

宽度和高度选项现在可以设置客户端区域的大小(不包括标题栏和窗口框架的区域), 因此对主题的依赖性较小.

如果 Title 参数是一个空字符串, 标题将是空白的. 它只有在完全省略时才默认为 A_ScriptName 与用户定义函数的可选参数一致.

InputBoxObj 是一个对象, 其属性是 Result(包含 "OK", "Cancel" 或 "Timeout") 和 Value.

MsgBox

Result := MsgBox([Text, Title, Options])

Options 参数接受由零个或多个不区分大小写的选项组成的字符串, 以空格或制表符为界, 类似于 Gui 控件选项.

  • Iconx, Icon?, Icon! 和 Iconi 设置图标.
  • Default 后面紧跟一个整数, 设置第 n 个按钮为默认值.
  • T 后面紧跟一个整数或浮点数, 设置超时, 单位是秒.
  • Owner 后跟 HWND 设置所有者, 覆盖 +OwnDialogs 选项.
  • 以下相互排斥的字符串之一设置按钮的选择: OK, OKCancel, AbortRetryIgnore, YesNoCancel, YesNo, RetryCancel, CancelTryAgainContinue, 或者只是用斜线分隔的首字母(o/c, y/n, 等等.), 或者只是没有斜线的首字母.
  • 任何数字值, 与 v1 中的相同. 数字值可以与字符串选项相结合, 或者 Options 可以是纯整数.

返回值是按钮的英语名称, 不带空格. 这些都是与 IfMsgBox 在 v1 中使用的字符串相同.

如果 Title 参数是一个空字符串, 标题将是空白. 只有当完全省略时, 它才默认为 A_ScriptName, 与用户定义的函数的可选参数一致.

子命令

Control, ControlGet, Drive, DriveGet, WinGet, WinSet 和 Process 的子命令已被替换为单独的函数, 而主命令已被删除. 一些函数的名称和用法已经改变. 新的用法如下所示:

; 其中 ... 表示可选的 Control, WinTitle, 等等.

Bool  := ControlGetChecked(...)
Bool  := ControlGetEnabled(...)
Bool  := ControlGetVisible(...)
Int   := ControlGetIndex(...)  ; 适用于 Tab, LB, CB, DDL
Str   := ControlGetChoice(...)
Arr   := ControlGetItems(...)
Int   := ControlGetStyle(...)
Int   := ControlGetExStyle(...)
Int   := ControlGetHwnd(...)

         ControlSetChecked(TrueFalseToggle, ...)
         ControlSetEnabled(TrueFalseToggle, ...)
         ControlShow(...)
         ControlHide(...)
         ControlSetStyle(Value, ...)
         ControlSetExStyle(Value, ...)
         ControlShowDropDown(...)
         ControlHideDropDown(...)
         ControlChooseIndex(Index, ...)  ; 同样涉及 Tab
Index := ControlChooseString(Str, ...)

Index := ControlFindItem(Str, ...)
Index := ControlAddItem(Str, ...)
           ControlDeleteItem(Index, ...)

Int   := EditGetLineCount(...)
Int   := EditGetCurrentLine(...)
Int   := EditGetCurrentCol(...)
Str   := EditGetLine(N [, ...])
Str   := EditGetSelectedText(...)
           EditPaste(Str, ...)

Str   := ListViewGetContent([Options, ...])

           DriveEject([Drive])
           DriveRetract([Drive])
           DriveLock(Drive)
           DriveUnlock(Drive)
           DriveSetLabel(Drive [, Label])

Str   := DriveGetList([Type])
Str   := DriveGetFilesystem(Drive)
Str   := DriveGetLabel(Drive)
Str   := DriveGetSerial(Drive)
Str   := DriveGetType(Path)
Str   := DriveGetStatus(Path)
Str   := DriveGetStatusCD(Drive)
Int   := DriveGetCapacity(Path)
Int   := DriveGetSpaceFree(Path)

; 其中 ... 表示可选的 WinTitle, 等等.

Int   := WinGetID(...)
Int   := WinGetIDLast(...)
Int   := WinGetPID(...)
Str   := WinGetProcessName(...)
Str   := WinGetProcessPath(...)
Int   := WinGetCount(...)
Array := WinGetList(...)
Int   := WinGetMinMax(...)
Array := WinGetControls(...)
Array := WinGetControlsHwnd(...)
Int   := WinGetTransparent(...)
Str   := WinGetTransColor(...)
Int   := WinGetStyle(...)
Int   := WinGetExStyle(...)

           WinSetTransparent(N [, ...])
           WinSetTransColor("Color [N]" [, ...]),
           WinSetAlwaysOnTop([TrueFalseToggle := 1, ...])
           WinSetStyle(Value [, ...])
           WinSetExStyle(Value [, ...])
           WinSetEnabled(Value [, ...])
           WinSetRegion(Value [, ...])

           WinRedraw(...)
           WinMoveBottom(...)
           WinMoveTop(...)

PID   := ProcessExist([PID_or_Name])
PID   := ProcessClose(PID_or_Name)
PID   := ProcessWait(PID_or_Name [, Timeout])
PID   := ProcessWaitClose(PID_or_Name [, Timeout])

         ProcessSetPriority(Priority [, PID_or_Name])

ProcessExist, ProcessClose, ProcessWait 和 ProcessWaitClose 不再设置 ErrorLevel; 相反, 它们返回 PID.

其他函数都不设置 ErrorLevel. 相反, 它们在失败时抛出异常. 在大多数情况下, 失败是因为没有找到目标窗口或控件.

HWND 和样式总是以纯整数形式返回, 而不是十六进制字符串.

ControlChooseIndex 允许 0 来取消对当前项目/所有项目的选择. 它取代了控件选择, 但也支持 Tab 控件.

ControlGet 被合并到 ControlGetIndex, 它也适用于 ListBox, ComboBox 和 DDL. 对于 Tab 控件, 如果没有选择 Tab, 它将返回 0(很少见, 但有效). ControlChooseIndex 不允许 Tab 控件使用 0, 因为应用程序往往不会处理它.

ControlGetItems 取代了 ListBox 和 ComboBox 的 ControlGet List. 它返回一个数组.

DriveEject 和 DriveRetract 现在使用 DeviceIoControl 而不是 mciSendString. DriveEject 能够弹出在资源管理器中有 "弹出" 选项的非 CD/DVD 驱动器(即可移动驱动器, 但不包括显示为固定磁盘的外部硬盘).

ListViewGetContent 取代了 ListView 的 ControlGet List, 目前的用法与以前相同.

WinGetList, WinGetControls 和 WinGetControlsHwnd 返回数组, 而不是以新行分隔的列表.

WinSetTransparent 将 "" 视为 "Off", 而不是 0(这将使窗口不可见且无法点击).

缩写的别名, 如 Topmost, Trans, FS 和 Cap 被删除.

以下函数以前是 SysGet 的子命令:

ActualN := MonitorGet([N, &Left, &Top, &Right, &Bottom])
ActualN := MonitorGetWorkArea([N, &Left, &Top, &Right, &Bottom])
Count   := MonitorGetCount()
Primary := MonitorGetPrimary()
Name    := MonitorGetName([N])

新的函数

Buffer([ByteCount, FillByte])(调用 Buffer 类) 创建并返回一个封装了 ByteCount 字节的内存块的 Buffer 对象, 只在 FillByte 被指定时才初始化. BufferObj.Ptr 返回地址, 而 BufferObj.Size 返回或设置字节大小(重新分配内存块). 任何具有 Ptr 和 Size 属性的对象都可以传递给 NumPut, NumGet, StrPut, StrGet, File.RawRead, File.RawWrite 和 FileAppend. 任何具有 Ptr 属性的对象都可以被传递给 DllCall 的 Ptr 类型, SendMessage 和 PostMessage 参数.

CaretGetPos([&OutputVarX, &OutputVarY]) 检索光标(文本插入点) 的当前坐标. 这确保了 X 和 Y 坐标总是匹配的, 并且没有缓存导致意外的行为(比如 A_CaretX/Y 返回一个不在当前 CoordMode 中的值).

ClipboardAll([Data, Size]) 创建一个包含剪贴板上所有内容的对象(可选择接受先前从剪贴板上获取的数据, 而不是使用剪贴板的当前内容). 读和写剪贴板文件数据的方法是不同的. 数据格式是一样的, 只是数据大小总是 32 位的, 这样数据就可以在 32 位和 64 位的构建之间移植. 详情见 v2 版文档.

ComCall(offset, comobj, ...) 等同于 DllCall(NumGet(NumGet(comobj.ptr) + offset * A_Index), "ptr", comobj.ptr, ...), 但返回类型默认为 HRESULT, 而不是 Int.

ComObject(以前是 ComObjCreate) 和 ComObjQuery 现在返回一个包装对象, 即使指定了一个 IID. ComObjQuery 允许第一个参数是任何具有 Ptr 属性的对象.

ControlGetClassNN 返回指定控件的 ClassNN.

ControlSendText 等同于 ControlSendRaw 但使用 Text 模式而不是 Raw 模式.

DirExist(FilePattern) 用法类似于 FileExist. 注意 通配符检查, 如 InStr(FileExist("MyFolder\*"), "D"), 其中 MyFolder 包含文件和子文件夹, 只告诉你 第一个 匹配的文件是否是一个文件夹, 而不是一个文件夹是否存在.

Float(Value): 请参阅类型.

InstallKeybdHook([Install, Force]) 和 InstallMouseHook([Install, Force]) 替换相应的指令, 为了提高稳定性.

Integer(Value): 请参阅类型.

IsXXX: 传统的命令 "if Var is Type" 已经被一系列的函数取代: IsAlnum, IsAlpha, IsDigit, IsFloat, IsInteger, IsLower, IsNumber, IsSpace, IsUpper, IsXDigit. 除了 sFloat, IsInteger 和 IsNumber 外, 如果参数不是字符串, 则会抛出异常, 因为隐式转换为字符串可能会导致反直觉的结果.

IsSet(Var), IsSetRef(&Ref): 如果变量已经被分配了一个值(即使该值是一个空字符串), 则返回 1(true), 否则返回 0(false). 如果是 0(false), 试图在表达式中读取该变量会出现错误.

Menu()/MenuBar() 返回一个新的 Menu/MenuBar 对象, 它有以下成员, 对应于 V1 Menu 子命令. 方法: Add, AddStandard, Check, Delete, Disable, Enable, Insert, Rename, SetColor, SetIcon, Show, ToggleCheck, ToggleEnable, Uncheck. 属性: ClickCount, Default, Handle(替换 MenuGetHandle). A_TrayMenu 也返回一个菜单对象. 没有 UseErrorLevel 模式, 没有全局菜单名称, 也没有显式删除菜单本身(当所有引用被释放时就会发生; Delete 等同于 v1 DeleteAll). 不支持标签, 只支持函数对象. AddStandard 方法添加了标准的菜单项, 并允许它们像自定义项一样被单独修改. 与 v1 不同, Win32 菜单只有在对象被删除时才会被销毁.

MenuFromHandle(Handle) 检索对应于 Win32 菜单句柄的菜单或 MenuBar 对象, 如果它是由 AutoHotkey 创建的.

Number(Value): 请参阅上面的类型.

Persistent([Persist]) 替换相应的指令, 增加灵活性.

RegDeleteKey([KeyName]) 删除一个注册表键. (RegDelete 现在只删除值, 除非在注册表循环中省略所有参数.)

SendText 等同于 SendRaw, 但使用 {Text} 模式而不是 {Raw} 模式.

StrCompare(String1, String2 [, CaseSense := false]) 返回 -1(String1 小于 String2), 0(相等) 或 1(大于). CaseSense 可以是 "Locale".

String(Value): 请参阅上面的类型.

StrPtr(Value) 返回字符串的地址. 与 v1 中的取址不同, 它可以用于原义字符串和临时字符串.

SysGetIPAddresses() 返回一个 IP 地址的数组, 相当于已经被删除的 A_IPAddress 变量. 每个对 A_IPAddress%N% 的引用都会检索所有的地址, 但只返回一个, 所以检索多个地址所花费的时间是指数级的. 返回的数组可以有零个或多个元素. .

TraySetIcon([FileName, IconNumber, Freeze]) 替换 "Menu Tray, Icon".

VarSetStrCapacity(&TargetVar [, RequestedCapacity]) 取代了 V1 的 VarSetCapacity, 但只用于 UTF-16 字符串(如优化重复连接); 因此 RequestedCapacity 和返回值的单位是字符而不是字节.

VerCompare(A, B) 使用与 #Requires 相同的算法对两个版本字符串进行比较.

WinGetClientPos([&OutX, &OutY, &OutWidth, &OutHeight, WinTitle, ...]) 检索窗口客户端区域的位置和大小, 以屏幕坐标表示.

新的指令

#DllLoad [FileOrDirName]: 在脚本开始执行前加载一个 DLL 或 EXE 文件.

内置变量

A_AhkPath 总是返回当前可执行文件/解释器的路径, 即使脚本已被编译. 以前, 如果使用 BIN 文件作为基础文件, 它会返回编译后的脚本的路径, 但 V2.0 版本不再包括 BIN 文件.

如果脚本没有被编译, A_IsCompiled 会返回 0 而不是 "".

A_OSVersion 总是返回格式为 major.minor.build 的字符串, 例如 6.1.7601 对应于 Windows 7 SP1. 由于只支持基于 NT 的系统, 因此删除了 A_OSType.

当 A_PriorHotkey 为 "" 时, A_TimeSincePriorHotkey 返回 "" 代替 -1 , 同样当 A_ThisHotkey 为空时, A_TimeSinceThisHotkey 返回空值.

所有内置的 "虚拟" 变量现在都有 A_ 前缀(具体细节见下文). 任何没有这个前缀的预定义变量(比如 Object) 都只是全局变量. 这种区别可能很重要, 因为目前不可能对一个虚拟变量进行引用(除非直接传递给一个内置函数); 然而, A_Args 不是一个虚拟变量.

返回数字的内置变量现在以整数, 而不是字符串的形式返回.

重命名:

  • A_LoopFileFullPath → A_LoopFilePath (如果 Loop 的参数是相对的, 则返回相对路径, 所以 "full path" 会产生误解)
  • A_LoopFileLongPath → A_LoopFileFullPath
  • Clipboard → A_Clipboard

删除的:

  • ClipboardAll(使用 ClipboardAll 函数代替)
  • ComSpec(使用 A_ComSpec)
  • ProgramFiles(使用 A_ProgramFiles)
  • A_AutoTrim
  • A_BatchLines
  • A_CaretX, A_CaretY(使用 CaretGetPos)
  • A_DefaultGui, A_DefaultListView, A_DefaultTreeView
  • A_ExitReason
  • A_FormatFloat
  • A_FormatInteger
  • A_Gui, A_GuiControl, A_GuiControlEvent, A_GuiEvent, A_GuiX, A_GuiY, A_GuiWidth, A_GuiHeight(全部替换为事件处理程序的参数)
  • A_IPAddress1, A_IPAddress2, A_IPAddress3, A_IPAddress4(使用 SysGetIPAddresses)
  • A_IsUnicode(v2 总是 Unicode; 它可以替换为 StrLen(Chr(0xFFFF)) 或用 global A_IsUnicode := 1 重新定义)
  • A_StringCaseSense
  • A_ThisLabel
  • A_ThisMenu, A_ThisMenuItem, A_ThisMenuItemPos(使用菜单项回调的参数)
  • A_LoopRegSubKey(A_LoopRegKey 现在包含根键和子键)
  • True 和 False(仍然存在, 但现在只是关键字, 而不是变量)

新增:

  • A_AllowMainWindow(读/写; 替换 "Menu Tray, MainWindow/NoMainWindow")
  • A_HotkeyInterval(替换 #HotkeyInterval)
  • A_HotkeyModifierTimeout(替换 #HotkeyModifierTimeout)
  • A_InitialWorkingDir(请参阅下面的默认设置)
  • A_MaxHotkeysPerInterval(替换 #MaxHotkeysPerInterval)
  • A_MenuMaskKey(替换 #MenuMaskKey)

以下内置变量可以被赋值:

  • A_ControlDelay
  • A_CoordMode..
  • A_DefaultMouseSpeed
  • A_DetectHiddenText(同样, 它现在返回 1 或 0, 而不是 "On" 或 "Off")
  • A_DetectHiddenWindows(同样, 它现在返回 1 或 0, 而不是 "On" 或 "Off")
  • A_EventInfo
  • A_FileEncoding(同样, 它现在返回 "CP0" 代替 "", 并允许在赋值时省略 "CP" 前缀)
  • A_IconHidden
  • A_IconTip(同样, 它现在总是反映 tooltip, 即使它是默认的或空的)
  • A_Index: 对于计数的循环, 修改它将影响执行多少次迭代. (内置变量的全局性质意味着枚举器函数可以设置索引, 以便 For 循环查看.)
  • A_KeyDelay
  • A_KeyDelayPlay
  • A_KeyDuration
  • A_KeyDurationPlay
  • A_LastError: 调用 Win32 SetLastError() 函数. 同样, 它现在返回一个无符号值.
  • A_ListLines
  • A_MouseDelay
  • A_MouseDelayPlay
  • A_RegView
  • A_ScriptName: 更改默认的对话框标题.
  • A_SendLevel
  • A_SendMode
  • A_StoreCapsLockMode(同样, 它现在返回 1 或 0, 而不是 "On" 或 "Off")
  • A_TitleMatchMode
  • A_TitleMatchModeSpeed
  • A_WinDelay
  • A_WorkingDir: 等同于调用 SetWorkingDir.

内置对象

现在, 文件对象在调用属性时严格要求使用属性语法, 在调用方法时严格要求使用方法语法. 例如, FileObj.Pos(n) 是无效的. 如果参数太少或太多, 或者只读属性被赋值, 则抛出异常.

File.Tell() 被删除.

Func.IsByRef() 现在可以与内置函数一起工作.

Gui

Gui, GuiControl 和 GuiControlGet 被 Gui() 和 Gui/GuiControl 对象所取代, 它们通常更灵活, 更一致, 更容易使用.

GUI 通常不是通过名字/数字编号来引用的(尽管它仍然可以用 GuiObj.Name 命名). 相反, GUI 对象(和窗口) 是通过实例化 Gui 类显式创建的, 如 GuiObj := Gui(). 这个对象具有取代 Gui 子命令的方法和属性. Gui.Add() 返回一个 GuiControl 对象, 该对象具有替代 GuiControl 和 GuiControlGet 命令的方法和属性. 人们可以将这个对象存储在一个变量中, 或者使用 GuiObj["Name"] 或 GuiCtrlFromHwnd 来检索这个对象. 每当调用一个事件处理程序(g-label 的替换) 时, 它也会作为一个参数被传递.

这些方法和属性的用法不是 1:1. 许多部分已经被修改, 以使其更加一致和灵活, 并修复错误或限制.

没有 "默认" GUI, 因为目标 Gui 或控制对象总是被指定的. LV/TV/SB 函数被替换为(控件对象的) 方法, 使得使用多个 ListViews/TreeViews 更加容易.

没有包含事件信息的内置变量. 这些信息被作为参数传递给处理事件的函数/方法, 包括源 Gui 或控件.

控件仍然可以被命名, 并且可以通过名字来引用, 但它只是一个名称(与 GuiObj["Name"] 和 Gui.Submit() 一起使用), 而不是一个关联变量, 所以不需要声明或创建一个全局或静态变量. 该值绝不会自动存储在变量中, 而是通过 GuiControl.Value 进行访问. Gui.Submit() 返回一个以控件名称作为键的新关联数组.

vName 选项现在只是将控件的名称设置为 Name.

+HwndVarName 选项已被删除, 改为使用 GuiControl.Hwnd.

不再有 "g-labels" 或标签/函数来自动处理 GUI 事件. 脚本必须通过调用 Gui 或 GuiControl 的 OnEvent 方法来注册每个感兴趣的事件. 例如, 脚本不会在 g-label 中检查 if (A_GuiEvent = "I" && InStr(ErrorLevel, "F", true)), 脚本将为 ItemFocus 事件注册处理程序: MyLV.OnEvent("ItemFocus", MyFunction). MyFunction 将仅为 ItemFocus 事件调用. 没有必要应用 AltSubmit 选项来启用其他事件.

数组被用于以前使用管道分隔的列表的地方, 例如在创建 ListBox 时, 在添加项目时, 或在检索选定的项目时, 为 ListBox 指定项目.

脚本可以定义一个 extends Gui 的类, 并处理它自己的事件, 使所有的 GUI 逻辑自成一体.

Gui 子命令

Gui New → Gui(). 传递空标题(不省略) 现在会导致空标题, 而不是默认标题.

Gui Add → Gui.Add() 或 Gui.AddControlType(); 例如 GuiObj.Add("Edit") 或 GuiObj.AddEdit().

Gui Show → Gui.Show(), 但它没有 Title 参数. 标题可以由 Gui() 的参数或通过 Gui.Title 属性来指定. 初始焦点仍然设置为具有 WS_TABSTOP 样式的第一个可输入控件(根据系统的默认消息处理), 除非是 Button 控件, 在这种情况下, 焦点现在转移到 Default(默认) 按钮上.

Gui Submit → Gui.Submit(). 除了 Submit() 创建并返回一个包含所有 "关联变量" 的新对象之外, 它的工作方式与以前类似.

Gui Destroy → Gui.Destroy(). 该对象仍然存在(直到脚本释放它), 但不能使用. 必须创建新的 GUI(如果需要). 删除对象时, 窗口也会被销毁, 但当窗口可见时, 该对象将 "保持活动状态".

Gui Font → Gui.SetFont(). 也可以使用 GuiControl.SetFont() 直接设置控件的字体.

Gui Color → Gui.BackColor 设置/返回背景颜色. 不支持 ControlColor(第二个参数), 但所有以前支持它的控件都可以使用 +Background 选项来设置背景. 与 Gui Color 不同, Gui.BackColor 不会影响 Progress 控件或禁用的/只读的 Edit, DDL, ComboBox 或 TreeView(带有 -Theme) 控件.

Gui Margin → Gui.MarginX 和 Gui.MarginY 属性.

Gui Menu → Gui.MenuBar 设置/返回使用 MenuBar() 创建的 MenuBar 对象.

Gui Cancel/Hide/Minimize/Maximize/Restore → 使用同名的 Gui 方法.

Gui Flash → Gui.Flash(), 但使用 false 代替 Off.

Gui Tab → GuiControl.UseTab(). 与以前一样, 默认匹配选项卡名称的前缀. 对于第二个参数传递 true 以匹配整个选项卡名称, 但与 v1 "Exact" 模式不同, 它不区分大小写.

事件

关于所有显式支持的 GUI 和 GUI 控件事件的细节, 请参阅事件(OnEvent).

Size 事件传递 0, -1 或 1(与 WinGetMinMax 一致) 而不是 0, 1 或 2.

ContextMenu 事件可以为每个控件注册, 也可以为整个 GUI 注册.

DropFiles 事件交换了 FileArray 和 Ctrl 参数, 以便与 ContextMenu 一致.

ContextMenu 和 DropFiles 事件使用客户端坐标, 而不是窗口坐标(Client 也是 v2 中的默认的 CoordMode).

删除了以下控件事件, 但检测它们只需将适当的数字通知代码(在 Windows SDK 中定义) 传递给 GuiControl.OnNotify() 即可: K, D, d, A, S, s, M, C, E 和 MonthCal 的 1 和 2.

Control 事件不传递事件名称作为参数(GUI 事件从未传递过).

自定义的 N 和 Normal 事件被 GuiControl.OnNotify() 和 GuiControl.OnCommand() 取代, 它们可以用于任何控件.

Link 的 Click 事件传递 "Ctrl, ID 或 Index, HREF", 而不是 "Ctrl, Index, HREF 或 ID", 如果注册了 Click 回调, 则不会自动执行 HREF.

ListView 的 Click, DoubleClick 和 ContextMenu(当由右键触发时) 事件现在报告被点击的项目(如果没有则为 0), 而不是焦点项目.

ListView 的 I 事件被拆分为多个命名事件, 除了 f(取消焦点)事件, 因为它被 F(ItemFocus) 所隐含, 所以被排除.

ListView 的 e(ItemEdit) 事件在用户取消时被忽略.

Slider 的 Change 事件比 V1 的 g-label 事件更稳定地被引发; 也就是说, 它不再默认忽略鼠标滚轮的变化. 有关详情, 请参阅检测更改(Slider).

BS_NOTIFY 样式现在会根据需要自动添加到 Button, CheckBox 和 Radio 控件. 它不再被默认应用于 Radio 控件.

Focus(以前的 F) 和 LoseFocus(以前的 f) 支持更多的(但不是全部) 控件类型.

使用 Edit.Value 或 Edit.Text 设置 Edit 控件的文本不会触发该控件的 Change 事件, 而 GuiControl 会触发该控件的 g-label.

LV/TV.Add/Modify 现在抑制了项目变更事件, 所以这类事件只能由用户操作或 SendMessage 引发.

删除的

+Delimiter
+HwndOutputVar (使用 Gui.Hwnd 或 GuiControl.Hwnd 代替)
+Label
+LastFoundExist
Gui GuiName: Default

控件选项

对 +/-Background 的解释和支持更加一致. 所有支持 "Gui Color" 的控件现在都支持 +BackgroundColor 和 +BackgroundDefault(-Background 相同), 而不仅仅是 ListView/TreeView/StatusBar/Progress.

当使用 xp/yp 或 xp+0/yp+0 时, Gui.Add 默认为 y+m/x+m, 而不是 yp/xp. 换句话说, 控件被放置在前一个控件的下面/右边, 而不是在完全相同的位置. 如果使用非零偏移, 行为与 v1 相同. 要使用完全相同的位置, 请同时指定 xp yp.

x+m 和 y+m 后面可以跟一个额外的偏移量, 如 x+m+10(x+m10 也是有效的, 但可读性差).

Choose 不再是指定 MonthCal 值的一个多余的(无文档) 方式. 就像以前一样, 使用 Text 参数.

GuiControlGet

空子命令

GuiControlGet 的空子命令有两种模式: 默认模式和文本模式, 其中第四个参数是单词 Text. 如果控件类型没有单一的 "value", GuiControlGet 默认为返回 GetWindowText 的结果(不一定是可见文本). 有些控件没有可见文本, 或者不支持检索它, 所以完全忽略了第四个参数. 相比之下, GuiControl.Text 会返回显示文本, 隐藏文本(与 ControlGetText 返回的文本相同) 或者什么都没有.

下表显示了 GuiControlGet 的每种模式和控件类型的最接近的等价属性或函数.

控件 | 默认 | 文本 | 注意
ActiveX | .Value | .Text | 文本处于隐藏状态. 见下文.
Button | .Text |  |
CheckBox | .Value | .Text |
ComboBox | .Text | ControlGetText() | 如果使用了 AltSubmit, 请使用 Value 而不是 Text(但如果 Text 与列表项目不匹配,则 Value 返回 0). Text 执行大小写更正, 而 ControlGetText 返回 Edit 区域的内容.
Custom | .Text |  |
DateTime | .Value |  |
DDL | .Text |  | 如果使用了 AltSubmit, 请使用 Value 而不是 Text.
Edit | .Value |  |
GroupBox | .Text |  |
Hotkey | .Value |  |
Link | .Text |  |
ListBox | .Text | ControlGetText() | 如果使用了 AltSubmit, 请使用 Value 而不是 Text. Text 返回所选项目的文本, 而 ControlGetText 返回隐藏文本. 见下文.
ListView | .Text |  | 文本处于隐藏状态.
MonthCal | .Value |  |
Picture | .Value |  |
Progress | .Value |  |
Radio | .Value | .Text |
Slider | .Value |  |
StatusBar | .Text |  |
Tab | .Text | ControlGetText() | 如果使用了 AltSubmit, 请使用 Value 而不是 Text. Text 返回所选选项卡的文本, 而 ControlGetText 返回隐藏文本.
Text | .Text |  |
TreeView | .Text |  | 文本处于隐藏状态.
UpDown | .Value |  |

ListBox: 对于多选 ListBox, Text 和 Value 返回数组, 而不是管道分隔的列表.

ActiveX: GuiControl.Value 每次都会返回相同的对象, 而 GuiControlGet 每次都会创建一个新的封装对象. 因此, 为了保持 ComObjConnect 连接处于活动状态, 不再需要保留对 ActiveX 对象的引用.

其他子命令

Pos → GuiControl.GetPos()

Focus → Gui.FocusedCtrl; 返回一个 GuiControl 对象而不是 ClassNN.

FocusV → GuiObj.FocusedCtrl.Name

Hwnd → GuiControl.Hwnd; 返回一个纯整数, 而不是十六进制的字符串.

Enabled/Visible/Name → 同名的 GuiCtrl 属性.

GuiControl

(空) 和 Text 子命令

下表显示了 GuiControl 的每种模式和控件类型的最接近的等效属性或方法.

控件 | (Blank) | Text | 注意
ActiveX | N/A |  | 命令没有效果.
Button | .Text |  |
CheckBox | .Value | .Text |
ComboBox | .Delete/Add/Choose | .Text |
Custom | .Text |  |
DateTime | .Value | .SetFormat() |
DDL | .Delete/Add/Choose |  |
Edit | .Value |  |
GroupBox | .Text |  |
Hotkey | .Value |  |
Link | .Text |  |
ListBox | .Delete/Add/Choose |  |
ListView | N/A |  | 命令没有效果.
MonthCal | .Value |  |
Picture | .Value |  |
Progress | .Value |  | 使用 += 运算符代替 + 前缀.
Radio | .Value | .Text |
Slider | .Value |  | 使用 += 运算符代替 + 前缀.
StatusBar | .Text 或 SB.SetText() |  |
Tab | .Delete/Add/Choose |  |
Text | .Text |  |
TreeView | N/A |  | 命令没有效果.
UpDown | .Value |  | 使用 += 运算符代替 + 前缀.

其他子命令

Move → GuiControl.Move(x, y, w, h)

MoveDraw → GuiControl.Move(x, y, w, h), GuiControl.Redraw()

Focus → GuiControl.Focus(), 现在使用 WM_NEXTDLGCTL 而不是 SetFocus, 因此聚焦 Button 可以暂时将其设置为默认值, 这与制表时的控件一致.

Enable/Disable → GuiControl.Enabled

Hide/Show → GuiControl.Visible

Choose → GuiControl.Choose(n), 其中 n 为纯整数. 不支持 |n 或 ||n 模式(如果需要, 使用 ControlChooseIndex 代替).

ChooseString → GuiControl.Choose(s), 其中 s 不是一个纯整数. 不支持 |n 或 ||n 模式(如果需要, 使用 ControlChooseString 代替). 如果字符串与多选列表框中的多个项目匹配, 这个方法将全部选择, 而不是只选择第一个.

Font → GuiControl.SetFont()

+/-Option → GuiControl.Opt("+/-Option")

其他更改

Progress Gui 控件不再具有默认的 PBS_SMOOTH 样式, 因此它们现在是根据系统的视觉样式来设计的.

当 DPI 大于 100 % 时, 默认的边距和控件尺寸(尤其是 Button 控件) 可能与 v1 版略有不同.

当图片控件无法通过 GuiCtrl.Value := "new image.png" 设置新图片时, 不再删除当前图片. 但是, 允许通过 GuiCtrl.Value := "" 删除当前图像.

现在可以省略 ListView.InsertCol() 的 ColumnNumber 参数, 这与指定比控件中当前列数更大的列数具有相同的效果.

错误处理

在退出脚本之前, OnError 现在被调用来处理关键性的错误. 尽管脚本可能不处于安全的执行状态, 但仍会进行尝试, 这与 OnExit 一致.

运行时错误不再将 Exception.What 设置为当前正在运行的用户定义的函数或子函数(但在调用 Error() 时仍会这样做, 但没有第二个参数). 这给了 What 一个更明确的目的: 函数名称表示该函数的失败(而不是调用该函数或计算其参数的失败). 对于表达式计算和控制流错误, What 是空白的(其他一些也可能是空白).

由运行时错误抛出的异常对象现在可以被识别为新的 Error 类或更具体的子类的实例. Error 对象有一个 Stack 属性, 包含一个堆栈跟踪. 如果 What 参数指定了一个正在运行的函数的名称, 那么现在会根据哪一行调用该函数来设置 File 和 Line .

Try-catch 语法已经改变, 允许脚本捕捉特定的错误类, 而不捕捉其他错误. 有关详情, 请参阅下文的 Catch 章节.

可继续错误(不中断脚本运行)

在大多数情况下, 错误对话框现在提供了继续当前线程的选项(而不是退出线程). COM 错误现在在选择不继续时退出线程(而不是退出整个脚本).

脚本不应依赖于此. 如果错误是由一个内置函数引发的, 继续会导致它返回 "". 如果错误是由表达式计算器引发的(比如无效的动态引用或除以 0), 表达式会被中止, 并返回 ""(如果用作控制流语句的参数).

在某些情况下, 代码不支持继续, 继续的选项不应该被显示. 对于旨在终止脚本的关键错误, 也不显示该选项.

OnError 回调现在接受第二个参数, 包含以下值之一:

  • Return: 返回 -1 将继续执行线程, 而 0 和 1 则和以前一样.
  • Exit: 不支持继续执行. 返回非零将停止进一步的处理, 但仍然退出线程.
  • ExitApp: 这是一个关键错误. 返回非零值会停止进一步的处理, 但脚本仍然被终止.

ErrorLevel

ErrorLevel 已经被删除. 脚本经常(也许通常) 是在没有错误检查的情况下编写的, 所以为错误设置 ErrorLevel 的策略经常让它们不被检测到. 即时的错误信息可能看起来有点对抗性, 但通常更有帮助.

在以前设置 ErrorLevel 以指示错误情况的地方, 会抛出异常, 并有一个(通常) 更有用的错误信息.

诸如 "Process Exist" 之类的命令使用它来返回一个值, 现在只是返回这个值(例如 pid := ProcessExist()) 或更有用的东西(例如 hwnd := GroupActivate(group)).

在某些情况下, ErrorLevel 被用于辅助返回值.

  • 使用 U 选项的 Sort 不再返回删除的重复数.
  • Input 命令将被删除. 它被 InputHook 所取代. 几行代码可以做一个简单的替换, 返回一个包含结果的 InputHook 对象, 而不是使用 ErrorLevel 和一个 OutputVar.
  • InputBox 返回一个带有 Result(OK, Cancel 或 Timeout) 和 Value 属性的对象.

以前在 ErrorLevel 中存储失败次数的文件函数现在在抛出的异常对象的 Extra 属性中抛出它.

SendMessage 超时通常是一种异常情况, 所以会导致抛出 TimeoutError. TargetError 和 OSError 可能会在其他条件下被抛出.

Run 和 Hotkey 函数的 UseErrorLevel 模式被移除. 这种模式早于 Try/Catch 添加到语言中. 菜单和 Gui 也有这种模式, 但被替换为对象(不使用 ErrorLevel).

表达式

与 v1 相比, 更多的语法错误会引发加载时错误, 如:

  • 空括号(与函数名相邻的除外); 例如 x ()
  • 前缀运算符使用错误或缺少操作数; 例如 x!
  • 少于两个操作数的二元运算符.
  • 少于三个操作数的三元运算符.
  • 赋值的目标不是一个可写的变量或属性.

当发生以下任何故障时, 会抛出异常(而不是忽略该故障或产生一个空字符串):

  • 试图对一个非数字值进行数学运算. (数字字符串是可以的.)
  • 除以 0 或其他无效/不支持的输入, 如 (-1)**1.5. 注意, 有些情况会被新检测为无效, 如 0**0 和 a<<b 或 a>>b, 其中 b 的范围不在 0..63.
  • 未能为内置函数的返回值, 串联或表达式的结果分配内存.
  • 堆栈下溢(通常由语法错误引起).
  • 试图向不是变量(或数组元素) 的东西赋值.
  • 试图向一个只读变量赋值.
  • 试图用一个空的名称进行双重解引, 如 fn(%empty%).
  • 未能执行动态函数调用或方法调用.
  • 一个方法/属性调用失败, 因为该值没有实现该方法/属性. (对于 v1 中的关联数组, 只有方法调用可以导致这种情况.)
  • 由于内存分配失败而导致对象分配失败.

上面的一些条件在 v1 中被检测到, 但在表达式中间没有被检测到; 例如, A_AhkPath := x 在 v1 中检测到, 但在 v2 中仅在 y := x, A_AhkPath := x 检测到.

独立使用运算符 +=, -=, -- 和 ++ 不再将空变量视为 0. 这与 v1 不同, 在 v1 中, 独立使用运算符时将空变量视为 0, 但在表达式中间或与多语句逗号一起使用时则不会.

函数

函数在失败时通常会抛出异常. 特别是:

  • 由于 DllCall, RegExMatch 和 RegExReplace 的不正确使用导致的错误由于其复杂性而相当常见, 而且(像许多错误一样) 如果立即显示错误信息, 则更容易发现和调试.

  • 如果数学函数的任何输入不是数字, 或者操作无效(如除以 0), 则抛出异常.

  • 带有 WinTitle 参数的函数(有例外, 如 WinClose 的 ahk_group 模式), 如果没有找到目标窗口或控件就会抛出.

对一些以前没有检测到的错误抛出了异常, 一些被错误地标记为错误的情况(以前是通过设置 ErrorLevel) 被修复.

某些 error 消息已经发生变化.

Catch

Catch 的语法已经更改, 以提供一种方法来捕获特定的错误类, 而不捕获其他的错误(将控制权转移到调用堆栈更上层的另一个 Catch, 或报告错误并退出线程). 以前这需要捕捉所有类型的抛出值, 然后检查类型并重新抛出. 例如:

; 旧的(使用废弃的 v2.0-a 规则进行演示, 因为 v1 没有 `is` 或 Error 类)
try
    SendMessage msg,,, "Control1", "The Window"
catch err
    if err is TimeoutError
        MsgBox "The Window is unresponsive"
    else
        throw err

; 新的
try
    SendMessage msg,,, "Control1", "The Window"
catch TimeoutError
    MsgBox "The Window is unresponsive"

变化:

  • catch 捕获一个错误实例.
  • catch as err 捕捉一个 Error 实例, 它被分配给 err.
  • catch ValueError as err 捕捉一个 ValueError 实例, 它被分配给 err.
  • catch ValueError, TypeError 捕捉任一类型错误.
  • catch ValueError, TypeError as err 捕获任一类型错误并将实例分配给 err.
  • catch Any 捕捉 anything.
  • catch (MyError as err) 允许使用括号, 就像大多数其他控制流语句一样.

如果使用 Try 而不使用 Finally 或 Catch 它的行为就像有一个空块的 catch 虽然这听起来像 v1, 但现在 catch 本身只抓取 Error 的实例. 在大多数情况下, Try 本身就是为了抑制一个 Error, 所以不需要做任何改变. 然而, v2 中直接等价于 v1 的 try something() 的代码如下所示:

try something()
catch Any
{}

优先考虑错误类型而不是输出变量名称可能会鼓励更好的代码; 按照预期处理预期的错误, 而不是压制或错误地处理本应报告的意外错误.

由于所有类型的值都可以被抛出, 任何类对过滤器来说都是有效的(例如 String 或 Map). 然而, 类的原型在加载时被解析, 必须被指定为一个完整的类名, 而不是一个任意的表达式(类似于 class x extends y 中的 y).

当 Catch 语句正在执行时, throw(没有参数) 可以用来重新抛出异常(避免了为此目的指定一个输出变量的需要). 这甚至在嵌套的 Try-Finally 中也被支持, 但在嵌套的 Try-Catch 中不支持. throw 不需要被 Catch 语句的主体所包含; 它可以被一个被调用的函数所使用.

在最后一个 Catch 之后可以有一个 Else; 如果在 Try 中没有抛出异常, 就执行它.

键盘, 鼠标, 热键和热字串

更少的 VK 到 SC 和 SC 到 VK 的映射是硬编码的, 在理论上提高了与非常规的自定义键盘布局的兼容性.

删除了 "Return" 和 "Break" 键的名称. 使用 "Enter" 和 "Pause" 代替.

现在总是通过从键盘布局 DLL 读取 KLLF_ALTGR 标志来检测每个键盘布局上是否存在 AltGr. (v1.1.28+ 版本已经使用了这种方法.) 通过键盘钩子检测 AltGr 的后备方法已经被删除.

鼠标滚轮热键将 A_EventInfo 设置为由鼠标驱动程序报告的滚轮延迟, 而不是除以 120. 一般来说, 它是 120 的倍数, 但一些鼠标硬件/驱动程序可能会以更高的分辨率报告滚轮运动.

热串现在将 Shift+Backspace 视为 Backspace, 而不是在热串缓冲内将其转录为 `b.

热字串使用第一对冒号(::) 作为分隔符, 而不是在出现多对冒号时使用最后一对. 换句话说, 在 v2 中, 冒号(与另一个冒号相邻时) 必须在触发文本中转义, 而在 v1 中, 它们必须在替换中转义. 请注意, 对于奇数的连续冒号, 以前的行为不认为最后的冒号是一对冒号的一部分. 例如, 对于 ::1:::2(1 → :2) 的行为没有变化, 但 ::3::::4 现在是 3 → ::4 而不是 3:: → 4.

热字串不再成对转义冒号, 这意味着现在可以在热串触发器的末尾转义一个冒号. 例如, ::5`:::6 现在是 5: → 6 而不是一个错误, 而 ::7`::::8 现在是 7: → :8 而不是 7:: → 8. 在这些情况下, 最好转义每个原义的冒号, 以避免混淆(但单个孤立的冒号不需要转义).

带有延续片段的热字串现在默认为文本模式而不是原始模式.

热键现在只在 Win/Alt 键在逻辑上是向下的并且热键需要 Win/Alt 键(带 #/! 或自定义前缀) 的情况下才会在释放时屏蔽. 也就是说, 不需要 Win/Alt 键的热键在 Win/Alt 键物理上处于关闭状态时不再掩盖 Win/Alt 向上. 这使得发送 {Blind}{LWin up} 的热键可以激活开始菜单(如果使用 AppsKey::RWin 这样的重映射键, 这已经是可能的).

其他

已放弃对 Windows 2000 和 Windows XP 的支持.

AutoHotkey 不再在启动时覆盖系统的 ForegroundLockTimeout 设置.

  • 这是通过调用带有 SPI_SETFOREGROUNDLOCKTIMEOUT 的 SystemParametersInfo 动作实现的, 它影响到当前用户会话的所有应用程序. 它在注销后不会持续存在, 但对一些用户来说仍是不受欢迎的.
  • 用户的错误报告(和常识) 表明, 如果它起作用, 它允许焦点被那些没有专门设计的程序窃取.
  • 在 Windows 10 上的一些测试表明, 它对任何事情都没有影响; 对 SetForegroundWindow 的调用总是失败的, 而 WinActivate 采用的其他变通方法是需要的, 并且无论超时与否都是有效的. SPI_GETFOREGROUNDLOCKTIMEOUT 是从一个单独的进程中使用的, 以验证该变化是否生效(它有时并不生效).
  • 它可以很容易地在脚本中被复制:
    DllCall("SystemParametersInfo", "int", 0x2001, "int", 0, "ptr", 0, "int", 2)

RegEx 换行匹配默认为 (*ANYCRLF) 和 (*BSR_ANYCRLF); `r 和 `n 被识别, 除了 `r`n 之外. `a 选项隐含地启用了 (*BSR_UNICODE).

正则调出现在可以是可变的. 通过 pcre_callout 变量指定的调出可以是任何可调用的对象, 或 pcre_callout 本身可以直接定义为函数(可能是嵌套函数). 随着函数和变量命名空间的合并, 诸如 (?C:fn) 这样的调出模式也可以指代包含函数对象的局部或全局变量, 而不仅仅是用户定义的函数.

从 stdin 读取的脚本(例如用 AutoHotkey.exe *) 不再包括 A_ScriptFullPath 中的初始工作目录或主窗口的标题, 但它被用作 A_ScriptDir 和定位本地 Lib 文件夹.

由自动执行线程改变的设置现在会立即成为默认设置(对于在此后启动的线程), 而不是在 100 ms 后, 当自动执行线程结束时再变成默认设置.

通过利用动态分配, 以下限制已被取消:

  • 行或延续片段最大长度为 16383 个字符.
  • 每个表达式最大 512 个标记(MAX_TOKENS).
    基于 MAX_TOKENS 确定大小的表达式计算器的内部数组现在是基于预先计算的所需大小的估计值, 因此性能应该是相似的, 但在大多数情况下堆栈的使用量会低一些. 这可能会增加用户定义的函数的最大递归深度.
  • 每个参数最多可以引用 512 个 var 或函数(但无论如何, MAX_TOKENS 对表达式的限制更大).
  • 每个函数最多可以调用 255 个指定的参数值(但无论如何 MAX_TOKENS 更有限制性).

ListVars 现在将静态变量与局部变量分开显示. 在函数中声明的全局变量也被列为静态变量(这是新的实现细节的副作用, 但被保留下来, 因为它在有许多全局变量的脚本中可能是有用的).

为了减少代码大小和维护成本, 删除了(未记录的) "lazy var". 这个优化改进了有超过 100,000 个变量的脚本的性能.

托盘菜单: 从 "Reload This Script" 和 "Edit This Script" 中删除了 "This", 以便与 "Pause Script" 和主窗口的菜单选项一致.

如果时间戳长度不是 4 到 14(包括) 之间的偶数, YYYYMMDDHH24MISS 时间戳值现在被认为是无效的.

持续运行

当至少满足以下条件之一时, 脚本 "持续运行":

  • 至少有一个热键或热字符串被脚本定义.
  • 至少有一个 Gui(或脚本的主窗口) 可见.
  • 至少有一个脚本的定时器目前是启用的.
  • 至少有一个 OnClipboardChange 的回调函数已经被设置.
  • 至少有一个 InputHook 是激活的.
  • 调用了 Persistent() 或 Persistent(true) 并且没有通过调用 Persistent(false) 来反转.

如果出现以下情况之一, 并且没有满足以上条件, 那么脚本就会终止.

  • 最后一个脚本线程结束了.
  • Gui 被关闭或销毁.
  • 脚本的主窗口被关闭(但销毁它将导致脚本退出, 而不考虑持续运行, 如前所述).
  • 一个没有 OnEnd 回调的 InputHook 结束.

为了灵活起见, OnMessage 并不能使脚本自动持续运行.

相比之下, 当以下情况中至少有一个为真时, v1 脚本就会 "持续运行":

  • 至少有一个热键或热字串被脚本定义.
  • Gui 或 OnMessage() 出现在脚本的任何地方.
  • 键盘钩子或鼠标钩子已被安装.
  • Input 已经被调用.
  • #Persistent 已经被使用.

线程

线程开始时的不间断超时为 17 ms, 而不是 15 ms. 15 太短了, 因为系统的 tick 计数是以 15 或 16 为最小单位更新的; 也就是说, 如果 tick 计数正好在错误的时刻更新, 线程就可能成为可中断的, 尽管几乎没有时间过去.

线程在开始时是不可中断的, 现在则保持这种状态, 直到至少执行了一行, 即使不可中断的超时时间首先到期(例如, 如果系统在线程开始后立即暂停进程, 以便将 CPU 时间给另一个进程).

#MaxThreads 和 #MaxThreadsPerHotkey 不再对任何第一行是下列函数之一的子程序设置异常: ExitApp, Pause, Edit, Reload, KeyHistory, ListLines, ListVars 或 ListHotkeys.

默认设置

  • #NoEnv 是默认行为, 所以该指令本身已经被删除. 如果等效的内置变量不可用, 请使用 EnvGet 代替.
  • SendMode 默认为输入(Input) 而不是事件(Event).
  • 标题匹配模式默认为 2 而不是 1.
  • 删除了 SetBatchLines, 因此所有脚本都以全速运行(等同于 v1 中的 SetBatchLines -1).
  • 工作目录默认为 A_ScriptDir. A_InitialWorkingDir 包含由启动 AutoHotkey 的进程设置的工作目录.
  • #SingleInstance 提示行为对所有脚本来说都是默认的; #SingleInstance 本身就会激活强制模式. #SingleInstance Prompt 也可以显式地使用, 以达到清晰的目的, 或者覆盖之前的指令.
  • CoordMode 默认为 Client(在 v1.1.05 版中加入), 而不是 Window.
  • 脚本文件(但不包括 由 脚本读取的文件) 的默认编码现在是 UTF-8 而不是 ANSI(CP0). 和以前一样, 这可以通过 /CP 命令行开关来覆盖.
  • #MaxMem 被移除, 并且不再限制变量的容量.

默认脚本

当启动 AutoHotkey 程序文件(如 AutoHotkey32.exe 或 AutoHotkey64.exe) 而没有指定脚本文件, 它不再搜索用户的文档文件夹中默认的脚本文件.

AutoHotkey 不计划通过直接启动程序文件来使用, 除非使用便携式副本. 通常不应该运行程序文件, 而应该运行 .ahk 文件.

如果要创建特定程序文件的快捷方式, 可以在快捷方式的目标后面附加一个空格和脚本的路径(通常用引号括起来).

命令行

命令行参数不再存储在一个编号化的伪数组全局变量中; 应该使用全局变量 A_Args(在 v1.1.27 中添加) 来代替.

删除了 /R 和 /F 开关. 使用 /restart 和 /force 代替.

当 AutoHotkey.exe 被用来检查脚本的语法错误时, 应该使用 /validate 来代替 /iLib, 因为函数库的自动包含机制被移除.

在以下任一情况下, /ErrorStdOut 现在被视为脚本的参数之一, 而不是内置的:

  • 当脚本是编译的, 除非使用了 /script.
  • 当它的后缀不是以 = 开头时(以前后缀是被忽略的).


变量和表达式 - 定义 & 使用 | AutoHotkey v2

变量和表达式

目录

  • 变量
  • 表达式
  • 表达式中的运算符
  • 内置变量
  • 变量的容量和占用内存

变量

有关一般说明和变量如何工作的详细信息, 请参阅变量.

给变量赋值: 要将字符串或数字存储在变量中, 使用冒号-等号运算符(:=) 后跟着数字, 加引号的字符串或其他类型的表达式. 例如:

MyNumber := 123
MyString := "这是原义字符串."
CopyOfVar := Var

变量不能被显式删除, 但是它的前一个值可以通过赋值一个新的值来释放, 比如一个空字符串:

MyVar := ""

变量也可以间接赋值, 通过获取它的引用, 并使用双重解引或将其传递给一个函数. 例如:

MouseGetPos &x, &y

读取一个未赋值的变量的值被视为一个错误. IsSet 可以用来检测这种情况.

检索变量的内容: 若要将变量的内容包含在字符串中, 请使用连接或 Format. 例如:

MsgBox "变量的值是 " . Var . "."
MsgBox "变量 Var 的值为 " Var "."
MsgBox Format("Var 的值为 {1}.", Var)

子表达式可以以同样的方式与字符串组合. 例如:

MsgBox("X 和 Y 的和是 " . (X + Y))

变量的比较: 请阅读下面表达式部分中关于不同类型比较的重要提示.

表达式

有关结构化概述和进一步说明, 请参阅表达式.

表达式用于对一系列变量, 原义字符串和/或原义数字执行一个或多个运算.

表达式中的普通单词被解释为变量名. 因此, 原义的字符串必须用单引号或双引号括起来, 以便与变量区分开来. 例如:

if (CurrentSetting > 100 or FoundColor != "Blue")
    MsgBox "设置太高或出现错误的颜色."

在上面的例子中, "Blue" 出现在引号中, 因为它是一个原义的字符串. 单引号(') 和双引号(") 的作用是相同的, 除了用单引号括起来的字符串可以包含原义双引号, 反之亦然. 因此, 要在原义字符串中包含 真实的 引号, 可以转义引号或将字符串括在相反类型的引号中. 例如:

MsgBox "她说, `"一天一个苹果.`""
MsgBox '她说, "一天一个苹果."'

空字符串: 若要在表达式中指定空字符串, 请使用一对空的双引号. 例如, 当 MyVar 非空时, 语句 if (MyVar != "") 的结果为真.

保存表达式的结果: 要把结果赋值给变量, 请使用冒号-等号运算符(:=). 例如:

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

布尔值: 若要计算表达式结果为真还是假时(如 IF-语句), 结果为空或零被视为假(false), 而其他所有结果都视为真(true). 例如, 仅当 ItemCount 为空或 0 时, 语句 if ItemCount 的结果才为假. 类似的, 表达式 if not ItemCount 将产生相反的结果.

诸如 NOT/>/=/< 之类的运算符自动生成一个真值或假值: 真值时结果为 1, 而假值时为 0. 然而, AND/OR 运算符总是生成一个输入值. 例如, 在以下表达式, 如果 A_Index 大于 5, 变量 Done 赋值为 1, 其他情况下为 FoundIt 的值:

Done := A_Index > 5 or FoundIt

如上所述, 可以通过将变量设为空或赋值为 0, 来使变量来保存假值. 利用这种特性, 可以使用简写语句 if Done 来检查变量 Done 是真还是假.

在表达式中, 关键字 true 和 false 解析为 1 和 0. 使用它们可以使脚本更易于阅读, 如以下示例所示:

CaseSensitive := false
ContinueSearch := true

整数和浮点数: 在表达式中, 如果数字包含小数点或科学计数符号, 则认为它们是浮点数; 否则, 否则视为整数. 对于大多数运算符 -- 如加法和乘法 -- 只要其中的一个输入是浮点数, 那么结果也将是浮点数.

在表达式和非表达式中, 整数都可以用十六进制或十进制格式书写. 十六进制数总是以前缀 0x 开头. 例如, Sleep 0xFF 等同于 Sleep 255. 浮点数可以选择用科学记数法书写, 带或不带小数点(例如 1e4 或 -2.1E-4).

在脚本开始执行之前, 在表达式中, 未加双引号的原义数字(如 128, 0x7F 和 1.0), 被转换为纯数字, 因此将数字转换为字符串可能会产生与原始文字值不同的值. 例如:

MsgBox(0x7F)  ; 显示 128
MsgBox(1.00)  ; 显示 1.0

表达式中的运算符

有关运算符的一般信息, 请参阅运算符.

除了下面提到的, 数学运算中涉及的任何空值(空字符串) 或非数字值都不会假定为零. 相反, 会抛出 TypeError. 如果未使用 Try, 默认情况下, 未处理的异常将导致一个错误对话框.

表达式运算符(按优先级降序排列)

运算符 | 描述
%Expr%

解引用或名称替换.

当 Expr 计算为 VarRef 时, %Expr% 访问相应的变量. 例如, x := &y 取 y 的引用并将其赋值给 x, 那么 %x% := 1 赋值给变量 y, 而 %x% 读取其值.

否则, 子表达式 Expr 的值被用作变量或属性的名称或部分名称. 这使得脚本可以引用一个变量或属性, 其名称是由计算 Expr 确定的, 它通常是另一个变量. 变量不能被动态创建, 但是如果一个变量已经在脚本中的某个地方被声明或被非动态引用, 那么它可以被动态赋值.

注意: 子表达式 Expr 的 结果 必须是要访问的变量或属性的名称或部分名称.

由于存在歧义, 百分号不能直接在 Expr 中使用, 但可以在括号中嵌套. 否则, Expr 可以是任何表达式.

如果有任何相邻的 %Expr% 序列和部分名称(它们之间没有任何空格或其他字符), 则将它们组合成一个单一的名称.

如果变量并不存在, 或者它未初始化并且它的值正在被读取, 则通常抛出一个 Error. 可以使用 or-maybe 运算符(??) 通过提供默认值来避免这种情况. 例如: %'novar'% ?? 42.

虽然这在历史上被称为 "双重解引", 但当 Expr 不包含一个变量(第一重解引), 以及当产生的变量是赋值的目标, 而不是解引用(第二重解引), 这个术语是不准确的.
x.y
x.%z% 		成员访问. 获取, 设置或调用对象 x 的属性, 其中 y 是个原义名称, 而 z 是一个计算结果为名称的表达式. 有关详情, 请参阅 对象语法.
var?

Maybe. 允许未设置的变量. 这只在将变量传递给可选参数, 数组元素或文本对象; 或直接赋值的右边时有效. 问号后面必须跟随下列符号之一(忽略空白): )]},:. 变量可以通过三元运算符或在 AND/OR 的右边有条件地传递.

变量通常是一个可选参数, 但可以是任何变量. 对于不是函数参数的变量, 如果有对该变量的其他引用但没有赋值, 在加载时仍然可能显示 VarUnset 警告.

该操作符目前仅支持变量. 要在更一般的情况下显式或有条件地省略参数, 请使用 unset 关键字.

另请参阅: unset(可选参数)
++
--

前置和后置的自增/自减. 从变量中增加或减去 1. 运算符可以放在变量名的前面或后面. 如果放在变量名的 前面, 则执行自增/减运算并把结果用于下一运算(在这种情况下结果是一个变量引用). 例如, Var := ++X 递增 X 然后将其值赋给 Var. 相反, 如果运算符放在变量名的 后面, 结果是在执行运算之前的 X 值. 例如, Var := X++ 递增 X, 但 Var 接收 X 在递增之前的值.

这些运算符还可以与对象的属性一起使用, 如 myArray.Length++ 或 --myArray[i]. 在这些情况下, 子表达式的结果总是一个数字, 而不是一个变量引用.
**

幂. 示例用法: Base**Exponent. 底数(Base) 和指数(Exponent) 都可以为小数. 如果 指数 为负数, 即使 底数 和 指数 都为整数, 结果也会被格式化为浮点数. 因为 ** 的优先级高于一元负号, 所以, -2**2 的计算过程和 -(2**2) 一样, 且得到结果 -4. 因此, 要计算原义负数的幂, 需要把它们包围在括号中, 如 (-2)**2.

幂运算符是右结合的. 例如, x ** y ** z 计算为 x ** (y ** z).

注意: 不支持 底数 为负数且 指数 为小数的情况, 如 (-2)**0.5; 尝试它将导致抛出异常. 但 (-2)**2 和 (-2)**2.0 都是支持的. 如果 底数 和 指数 都为 0, 结果未定义并抛出异常.
-
!
~
&

一元负号(-): 反转其运算元的符号.

一元正号(+): +N 等同于 -(-N). 应用于纯数字时无效, 但可用于将数字字符串转换为纯数字.

逻辑非(!): 如果运算元为空或 0, 那么逻辑非的结果为 1, 这表示 "true". 否则, 结果为 0(false). 例如: !x or !(y and z). 注意: 单词 NOT 和 ! 含义相同, 但 ! 优先级更高. 允许使用连续的一元运算符, 例如 !!Var, 因为它们是按从右到左的顺序计算.

按位非(~): 此运算符对运算元按位取反. 当使用 64 位有符号整数时, 正的输入值始终给出负的结果, 反之亦然. 例如, ~0xf0f 等于 -0xf10(-3856), 二进制等于 0xfffffffffffff0f0. 如果希望使用无符号的 32 位值, 可以使用 result & 0xffffffff 截断结果. 如果操作数是一个浮点值, 则抛出 TypeError.

引用(&): 创建一个 VarRef, 它是一个代表变量引用的值. VarRef 可以用来间接访问目标变量. 例如, ref := &target 接着的 %ref% := 1 将把值 1 赋值给 target. VarRef 通常会被传递给一个函数, 但也可以存储在一个数组或属性中. 另请参阅: Dereference, ByRef.

目前不支持对内置变量(如 A_Clipboard) 的引用, 除非是直接传递给内置函数的 OutputVar 参数.
*
/
//

乘(*): 如果两个输入都为整数, 则结果为整数; 否则结果为浮点数.

其他用途: 星号(*) 运算符也用于可变参数函数调用.

真除(/): 即使两个输入都是整数, 真除的结果也为浮点数. 例如, 3/2 结果为 1.5 而不是 1, 而 4/2 结果为 2.0 而不是 2.

整数除法(//): 如果两个输入都是整数, 那么双斜杠运算符使用高效的整数除法. 例如, 5//3 结果为 1 而 5//-3 结果为 -1. 如果任何一个输入为浮点格式, 则抛出 TypeError. 有关取模, 请参阅 Mod.

*= 和 /= 运算符是用变量的值乘以或除以另一个值的一种简写形式. 例如, Var*=2 和 Var:=Var*2 会得到相同的结果(不过前者执行的更好).

除数为零, 则导致抛出 ZeroDivisionError.
+
-

加(+) 和 减(-). 在相关的注释中, += 和 -= 运算符是变量增加或减少的一种简写形式. 例如, Var+=2 和 Var:=Var+2 会得到相同的结果(不过前者执行的更好). 类似地, 变量可以通过使用 Var++, Var--, ++Var 或 --Var 来增加或减少 1.

其他用途: 如果 + 或 - 符号前面没有一个值(或生成值的子表达式), 则将其解释为一元运算符.
<<
>>
>>>

按位左移(<<). 使用示例: Value1 << Value2. 这相当于 Value1 乘以 "2 的 Value2 次幂".

算术位右移(>>). 使用示例: Value1 >> Value2. 这相当于 Value1 除以 "2 的 Value2 次幂" 并将结果四舍五入到数轴左侧最接近的整数; 例如, -3>>1 结果为 -2.

逻辑位右移(>>>). 使用示例: Value1 >>> Value2. 与算术位右移不同, 这并不保留数字的符号. 例如, -1 与无符号的 64 位整数 0xffffffffffffffff 拥有相同的位表示, 因此 -1 >>> 1 结果为 0x7fffffffffffffff.

下面的内容适用于这三个运算符:

  • 如果任何一个输入是浮点数, 则抛出 TypeError.
  • 执行 64 位运算, 结果为 64 位有符号整数.
  • 如果 Value2 小于 0 或大于 63, 则抛出异常.
&
^
|

按位与(&), 按位异或(^) 和 按位或(|). 这三个运算符中, & 优先级最高, 而 | 优先级最低.

下面的内容适用于这三个运算符:

  • 如果其中一个输入是浮点数, 则抛出 TypeError.
  • 执行 64 位运算, 结果为 64 位有符号整数.

相关: 按位非(~)
.

连接. 每边至少有一个空格或制表符的句点(点) 用于将两个项组合成单个字符串. 您还可以省略句点以获得相同的结果(除非有歧义, 如 x -y, 或者右边的项有一个前导的 ++ 或 --). 当省略点时, 要合并的项之间必须至少有一个空格或制表符.

Var := "The color is " . FoundColor  ; 显式连接
Var := "The color is " FoundColor    ; 自动连接

还可以用来连接子表达式. 例如: Var := "The net price is " . Price * (1 - Discount/100).

以句点(或其他任何运算符) 开始的行会自动附加到上一行的末尾.

每个输入的整个长度会被使用, 即使它包含二进制零. 例如, Chr(0x2010) Chr(0x0000) Chr(0x4030) 生成以下字节的字符串(由于 UTF-16-LE 编码): 0x10, 0x20, 0, 0, 0x30, 0x40. 结果有一个额外的空结束符(二进制零), 它不包含在长度中.

其他用途: 如果句点右侧没有空格或制表符, 则将其解释为原义浮点数或成员访问. 例如, 1.1 和 (.5) 是数字, A_Args.Has(3) 方法调用, 而 A_Args.Length 是一个属性访问.
~= RegExMatch 的简写形式. 例如, "abc123" ~= "\d" 结果为 4(首个数字字符串的位置).
> <
>= <=

大于(>), 小于(<), 大于或等于(>=) 和 小于或等于(<=). 输入的数据是以数字方式进行比较的. 如果其中一个输入不是数字或数字字符串, 则抛出 TypeError.
=
==
!=
!==

不区分大小写的等号(=) / 不等号(!=) 和 区分大小写的等号(==) / 不等号(!==). 运算符 == 的行为和 = 是一样的, 除非其中一个输入不是数字(或都是字符串), 在这种情况下 == 总是区分大小写的, 而 = 总是不区分大小写的. != 和 !== 与其对应的没有 ! 的运算符是一样的, 只是其结果取反.

== 和 !== 运算符可用于比较包含二进制零的字符串. 除了 ~= 之外的所有其他比较运算符仅比较到第一个二进制零.

对于不区分大小写的比较, 只有 ASCII 字母 A-Z 才会被认为等同于它们的小写字母. 如果要根据当前用户区域规则进行比较, 请使用 StrCompare 并为 CaseSense 参数指定 "Locale".
IS
IN
CONTAINS

如果 Value 是 Class 的实例, 那么 Value is Class 结果为 1(true), 否则为 0(false). Class 必须是一个对象, 并具有自有 Prototype 属性, 但通常该属性是由类定义隐式定义的. 这个操作一般等同于 HasBase(Value, Class.Prototype).

in 和 contains 保留给将来使用.
NOT | 逻辑非. 除了优先级较低外, 其他的与 ! 运算符相同. 例如, not (x = 3 or y = 3) 等同于 !(x = 3 or y = 3).
AND
&&

这两个运算符都是逻辑与. 例如: x > 3 and x < 10.

在表达式中, 所有运算元都为 true, 则返回 最后的 运算元. 否则, 返回 第一个 为 false 的运算元. 换句话说, 只有当所有运算元都为 true 时, 结果才为 true. 布尔表达式需要进行求值优化(从左到右) 以提高性能.

在下面的例子中, 所有运算元都为真, 并都要进行计算:

A := 1, B := {}, C := 20, D := true, E := "str"
MsgBox(A && B && C && D && E) ; 显示 "str"(E).

在下面的例子中, 因为 B 为假, 所以只计算前两个运算元. 其余部分被忽略, 即 C 不递增:

A := 1, B := "", C := 0, D := false, E := "str"
MsgBox(A && B && ++C && D && E) ; 显示 ""(B).

以 AND 或 &&(或其他任何运算符) 开始的行会自动附加到上一行的末尾.
OR
||

这两个运算符都是逻辑或. 例如: x <= 3 or x >= 10.

在表达式中, 至少有一个运算元为 true, 则返回 第一个 为 true 的运算元. 否则, 返回 最后一个 为 false 的运算元. 换句话说, 只要有一个运算元为真, 结果就为真. 布尔表达式需要进行求值优化(从左到右) 以提高性能.

在下面的示例中, 至少有一个运算元为真. 直到 D(包括) 的所有运算元都要进行计算. E 被忽略, 并始终不会自增:

A := "", B := false, C := 0, D := "str", E := 20
MsgBox(A || B || C || D || ++E) ; 显示 "str"(D).

在下面的例子中, 所有运算元都为假, 并都要进行计算:

A := "", B := false, C := 0
MsgBox(A || B || C) ; 显示 "0"(C).

以 OR 或 ||(或其他任何运算符) 开始的行会自动附加到上一行的末尾.
??

Or maybe, 也称为合并运算符. 如果左操作数(必须是一个变量) 有一个值, 它就成为结果, 并跳过右分支. 否则, 右操作数将成为结果. 换句话说, A ?? B 的行为类似于 A || B (逻辑或), 除了条件是 IsSet(A).

这通常用于在已知变量或可选参数可能还没有值时提供默认值. 例如:

MsgBox MyVar ?? "Default value"

由于期望变量有时未初始化, 因此在这种情况下不会抛出错误. 与 IsSet(A) ? A : B 不同的是, 如果变量有其他引用但没有赋值, VarUnset 警告仍然可以在加载时显示.
?:

三元运算符. 此运算符是 if-else 语句的简写形式. 它计算左侧的条件来决定两个分支中哪个作为最终结果. 例如, var := x>y ? 2 : 3, 当 x 大于 y 时保存 2 到 Var; 否则保存 3. 为了提高性能, 只计算决定性的分支(请参阅求值优化).

另请参阅: maybe(var?), or-maybe(??)

注意: 当在行的开头使用时, 三元条件通常应该用括号括起来, 以减少与其他类型语句的歧义. 有关详情, 请参阅表达式语句.
:=
+=
-=
*=
/=
//=
.=
|=
&=
^=
>>=
<<=
>>>=

赋值. 对变量的内容进行运算, 然后把结果保存到同一个变量中. 最简单的赋值运算符为冒号等号(:=), 它把表达式的结果保存到变量中. 关于其他运算符的功能说明, 请参阅这个表格中它们的相关条目. 例如, Var //= 2 执行整数除法把 Var 除以 2, 然后把结果保存回 Var. 类似的, Var .= "abc" 为 Var := Var . "abc" 的一种简写形式.

与其他大多数运算符不同, 赋值运算是从右往左执行的. 因此, Var1 := Var2 := 0 这个语句中首先把 0 赋值给 Var2, 然后把 Var2 赋值给 Var1.

如果赋值作为某些其他运算符的输入, 它的值是变量本身. 例如, 如果 Var 的新增值大于 50, 表达式 (Var+=2) > 50 为真. 将赋值与引用操作符结合起来也是有效的, 如 &(Var := "initial value").

需要避免语法错误或提供更直观的操作时, 会自动提升赋值运算符的优先级. 另外, x==y && z:=1 计算为 x==y && (z:=1), 当 x 不等于 y 时进行短路计算. 例如: not x:=y 等同于 not (x:=y). 类似的, ++Var := X 等同于 ++(Var := X); 而 Z>0 ? X:=2 : Y:=2 等同于 Z>0 ? (X:=2) : (Y:=2).

目标变量可以通过将直接赋值(:=) 与 unset 关键字或 maybe(var?) 运算符联合使用来 un-set(取消设置). 例如: Var := unset, Var1 := (Var2?).

赋值还可以针对对象的属性, 如 myArray.Length += n 或 myArray[i] .= t. 当赋值给一个属性时, 子表达式的结果是赋值的值, 而不是变量引用.
() => expr

胖箭头函数. 定义一个简单的函数并返回一个 Func 或闭包对象. 将函数的参数列表(可以在前面加上函数名) 写在操作符的左边. 当函数被调用时(通过返回的引用), 它计算子表达式 expr 并返回结果.

下面两个例子是等价的:

sumfn := Sum(a, b) => a + b
Sum(a, b) {
    return a + b
}
sumfn := Sum

在这两种情况下, 函数都是在脚本启动时无条件定义的, 但是函数引用只有在赋值时才存储在 sumfn 中.

如果函数名被省略, 而参数列表只包含一个参数名, 则可以省略圆括号. 下面的例子定义了一个带有一个参数 a 的匿名函数, 并将其引用存储在变量 double 中:

double := a => a * 2

expr 中的变量引用的解析方法与完整函数定义中的方法相同. 例如, expr 可以引用 outer 函数的局部变量(就像在任何嵌套函数中一样), 在这种情况下, 每当计算胖箭头表达式时, 都会创建一个新的闭包并返回它. 因为不能使用声明, 所以该函数总是假定-局部的.

为函数指定名称允许递归地调用它或由其他嵌套函数调用它, 而无需在其内部存储对闭包的引用(从而创建有问题的循环引用). 它还有助于调试, 比如 Func.Name 或显示在调试器的调用堆栈上.

胖箭头语法也可以用来定义简写的属性和方法.
,

逗号(多语句). 逗号可以用来在单行中书写多个子表达式. 最常用于把多个赋值或函数调用聚集在一起. 例如: x:=1, y+=2, ++index, MyFunc(). 这样的语句按从左到右的顺序执行.

注意: 以逗号(或其他任何运算符) 开始的行会自动附加到上一行的末尾.

逗号还用于分隔函数调用的或控制流语句的参数. 若要在参数列表中包含多语句表达式, 请用一组额外的圆括号将其括起来. 例如, MyFn((x, y)) 计算 x 和 y, 但传递 y 作为 MyFn 的第一个也是唯一一个参数.

下面列出的子表达式类型覆盖计算的优先级/顺序:

表达式 描述
(表达式)

括号中包含的任何子表达式. 例如, (3 + 2) * 2 强制首先计算 3 + 2.

对于多语句表达式, 将返回 最后 一条语句的结果. 例如, (a := 1, b := 2, c := 3) 返回 3.

Mod()
Round()
Abs()

函数调用. 在函数名称或表达式与参数列表开头的左圆括号之间不能有空格. 有关详情, 请参阅函数调用.

(表达式) 不一定要用括号括起来, 但这样做可以消除歧义. 例如, (x.y)() 从一个属性中检索一个函数, 然后没有参数调用它, 而 x.y() 将隐式地传递 x 作为第一个参数.

(expression)()

x.y()

方法调用. 目标对象 x 是一个表达式, 而 y 是一个原义属性名称. 方法名的两边都不能有空格, 但是点前面可以有空格, 包括换行符.

对象 x 隐式地作为方法函数的第一个参数传递. 这通常对应于 this, 不应该在方法定义中显式定义, 但任何其他类型的函数定义必须在参数列表中考虑它.
Fn(Params*)

可变参数函数调用. Params 是一个可枚举的对象(具有 __Enum 方法的对象), 例如包含参数值的数组.
x[y]
[a, b, c]

项目访问. 使用参数 y(或代替 y 的多个参数) 获取或设置对象 x 的 __Item 属性(或默认属性). 这通常对应于集合中的数组元素或项目, 其中 y 是项目的索引或键. 项目可以在右方括号后使用任何赋值运算符来赋值. 例如, x[y] := z.

数组标识符(数组字面量). 如果左方括号前面没有值(或者一个产生值的子表达式), 它被解释为一个数组的开始. 例如, [a, b, c] 等同于 Array(a, b, c)(a, b 和 c 都是变量).

有关常见用法, 请参阅数组和 Map(映射).
{a: b, c: d}

对象标识符(对象字面量). 创建一个对象. 其中的每一对项目由一个原义的属性名称 a 和一个属性值表达式 b 组成. 例如, x := {a: b} 等同于 x := Object(), x.a := b. 可以在对象文本中设置 Base, 但是所有其他属性都设置为 自有的属性, 可能会覆盖从基对象继承的属性.

要使用动态属性名, 请将子表达式用百分号括起来. 例如: {%nameVar%: valueVar}.

内置变量

下面的变量被内置到程序中, 可以被任何脚本引用.

有关一般信息, 请参阅内置变量.

目录

  • 特殊字符: 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_ListLines, A_TitleMatchMode, (...更多...)
  • 用户空闲时间: A_TimeIdle, A_TimeIdlePhysical, A_TimeIdleKeyboard, A_TimeIdleMouse
  • 热键, 热字串和自定义菜单项: A_ThisHotkey, A_EndChar, (...更多...)
  • 操作系统和用户信息: A_OSVersion, A_ScreenWidth, A_ScreenHeight, (...更多...)
  • 杂项: A_Clipboard, A_Cursor, A_EventInfo, (...更多...)
  • Loop: A_Index, (...更多...)

特殊字符

变量 | 描述
A_Space | 包含单个空格字符.
A_Tab | 包含单个 tab(制表符) 字符.

脚本属性

变量 | 描述
A_Args | 包含一个命令行参数数组. 有关详情, 请参阅向脚本传递命令行参数.
A_WorkingDir

可以用来获取或设置脚本当前工作目录, 这是访问文件的默认路径. 除非是根目录, 否则不包含路径末尾的反斜杠. 两个示例: C:\ 和 C:\My Documents.

SetWorkingDir 也可以用来改变工作目录.

无论脚本是如何启动的, 脚本的工作目录默认为 A_ScriptDir.
A_InitialWorkingDir | 脚本的初始工作目录, 由它的启动方式决定. 例如, 如果它是通过快捷方式运行的 -- 比如在开始菜单 -- 它的初始工作目录是由快捷方式属性中的 "起始位置" 字段决定的.
A_ScriptDir

当前脚本所在目录的完整路径. 不包含最后的反斜杠(根目录同样如此).

如果脚本文字是从标准输入中读取的而不是从文件中读取的, 变量值为初始工作目录.
A_ScriptName

可用于获取或设置 MsgBox, InputBox, FileSelect, DirSelect 和 Gui 的默认标题. 如果脚本没有设置, 则默认为当前脚本的文件名, 不包括路径, 例如 MyScript.ahk.

如果从标准输入中读取而不是从文件中读取的脚本文本, 则该变量包含一个星号(*).

如果脚本是编译的或嵌入的, 这就是当前可执行文件的名称.
A_ScriptFullPath

当前脚本的完整路径, 例如 C:\Scripts\My Script.ahk

如果脚本文字是从标准输入中读取的, 而不是从文件中读取, 则该变量包含一个星号(*).

如果脚本是编译的或嵌入的, 这就是当前可执行文件的完整路径.
A_ScriptHwnd | 脚本的主窗口(隐藏的) 的唯一 ID(HWND/句柄).
A_LineNumber

脚本(或其 #Include 文件) 中正在执行的行的行号. 这个行号与 ListLines 显示的一致; 它对于错误报告非常有用, 比如这个例子: MsgBox "Could not write to log file (line number " A_LineNumber ")".

由于已编译脚本已经把它所有的 #Include 文件合并成一个大脚本, 所以它的行号可能与它在未编译模式运行时不一样.
A_LineFile

A_LineNumber 所属文件的完整路径和名称. 如果脚本是从外部文件加载的, 这等同于 A_ScriptFullPath, 除非该行属于脚本的 #Include 文件之一.

如果脚本是基于一个 .bin 文件 编译的, 这就是当前可执行文件的完整路径和名称, 等同于 A_ScriptFullPath.

如果脚本是嵌入的, A_LineFile 包含一个星号(*) 后面是资源名称; 例如 *#1

A_ThisFunc | 当前正在执行的自定义函数的名称(没有则为空); 例如: MyFunction. 另请参阅: Name 属性(Func)
A_AhkVersion | 包含了运行当前脚本的 AutoHotkey 主程序的版本号, 例如 1.0.22. 在已编译脚本中, 它包含了原来编译时使用的主程序的版本号. 格式化的版本号使得脚本可以使用 > 或 >= 来检查 A_AhkVersion 是否大于某个最小的版本号, 如这个例子所示: if (A_AhkVersion >= "1.0.25.07").
A_AhkPath

对于非编译的或嵌入的脚本: 实际运行当前脚本的 EXE 文件的完整路径和名称. 例如: C:\Program Files\AutoHotkey\AutoHotkey.exe

对于基于 .bin 文件的编译脚本, 该值是通过从注册表中读取安装目录并附加 "\AutoHotkey.exe" 来确定的. 如果没有安装 AutoHotkey, 该值为空. 等同于下面的例子:

InstallDir := RegRead("HKLM\SOFTWARE\AutoHotkey", "InstallDir", "")
AhkPath := InstallDir ? InstallDir "\AutoHotkey.exe" : ""

对于基于 .exe 文件的编译脚本, A_AhkPath 包含编译脚本的完整路径. 这可以与 /script 结合使用来执行外部脚本. 如果要找到已安装的 AutoHotkey 副本, 请按上面所示读取注册表.
A_IsCompiled | 如果当前运行的脚本为已编译 EXE 时, 此变量值为 1, 否则为 0(这会被视为 false).

日期和时间

变量 | 描述
A_YYYY

4 位数表示的当前年份(例如 2004). 与 A_Year 含义相同.

注意: 要检索符合您区域设置和语言的格式化时间或日期, 请使用 FormatTime()(时间和长日期) 或 FormatTime(, "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 | 使用当前用户语言表示的当前星期几的简称, 例如 Sun
A_WDay | 1 位数表示的当前星期经过的天数(1-7). 在所有区域设置中 1 都表示星期天.
A_YDay | 当前年份中经过的天数(1-366). 不会使用零对变量的值进行填充, 例如检索到 9, 而不是 009. 要检索零填充的值, 请使用: FormatTime(, "YDay0").
A_YWeek | 符合 ISO 8601 标准的当前的年份和周数(例如 200453). 要分离年份和周数, 请使用 Year := SubStr(A_YWeek, 1, 4) 和 Week := SubStr(A_YWeek, -2). A_YWeek 的准确定义为: 如果含有 1 月 1 日的星期内有四天或四天以上在新年里, 则它被认为是新年的第一个星期. 否则, 它为前一年的最后一个星期, 而下一星期为新年的第一个星期.
A_Hour | 在 24 小时制(例如, 17 表示 5pm) 中 2 位数表示的当前小时数(00-23). 要获取带 AM/PM 提示的 12 小时制的时间, 请参照此例: FormatTime(, "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 格式表示的当前本地时间.

注意: 可以使用 DateAdd 和 DateDiff 执行日期和时间的数学运算. 此外, FormatTime 可以根据您的区域设置或选项来格式化日期和/或时间.
A_NowUTC | 以 YYYYMMDDHH24MISS 格式表示的当前的协调世界时(UTC). UTC 本质上和格林威治标准时间(GMT) 一致.
A_TickCount

计算机自启动以来经过的毫秒数, 最多为 49.7 天. 通过把 A_TickCount 保存到变量中, 经过一段时间后从最近的 A_TickCount 值中减去那个变量, 可以计算出所经过的时间. 例如:

StartTime := A_TickCount
Sleep 1000
ElapsedTime := A_TickCount - StartTime
MsgBox ElapsedTime " milliseconds have elapsed."

如果您需要比 A_TickCount 的 10 ms 更高的精确度, 请使用 QueryPerformanceCounter()(一个高精度计时器).

脚本设置

变量 | 描述
A_IsSuspended | 如果脚本挂起时值为 1, 否则为 0.
A_IsPaused | 如果在当前线程之后的线程是暂停时值为 1, 否则为 0.
A_IsCritical | 如果当前线程的 Critical 关闭时, 则值为 0. 否则值为大于零的整数, 即为 Critical 使用的消息检查间隔. Critical 的当前状态可以通过 Old_IsCritical := A_IsCritical 然后是 Critical Old_IsCritical 来保存和恢复.
A_ListLines | 可用于获取或设置是否记录行. 可能的值是 0(禁用) 和 1(启用). 有关详情, 请参阅 ListLines.
A_TitleMatchMode | 可用于获取或设置标题匹配模式. 可能的值是 1, 2, 3 和 RegEx. 有关详情, 请参阅 SetTitleMatchMode.
A_TitleMatchModeSpeed | 可用于获取或设置标题匹配速度. 可能的值是 fast 和 slow. 有关详情, 请参阅 SetTitleMatchMode.
A_DetectHiddenWindows | 可用于获取或设置是否检测隐藏窗口. 可能的值是 0(禁止) 和 1(启用). 有关详情, 请参阅 DetectHiddenWindows.
A_DetectHiddenText | 可以用来获取或设置是否检测窗口中的隐藏文本. 可能的值是 0(禁止) 和 1(启用). 有关详情, 请参阅 DetectHiddenText.
A_FileEncoding | 可以用来获取或设置各种内置函数的默认编码. 有关详情, 请参阅 FileEncoding.
A_SendMode | 可用于获取或设置发送模式. 可能的值是 Event, Input, Play 和 InputThenPlay. 有关详情, 请参阅 SendMode.
A_SendLevel | 可用于获取或设置发送级别, 为 0 至 100 之间的整数, 包括 0 和 100. 有关详情, 请参阅 SendLevel.
A_StoreCapsLockMode | 可以用来获取或设置是否在 Send 后恢复 CapsLock 的状态. 可能的值是 0(禁止) 和 1(启用). 有关详情, 请参阅 SetStoreCapsLockMode.
A_KeyDelay A_KeyDuration | 可以用来获取或设置按键的延迟或持续时间, 单位为毫秒. 有关详情, 请参阅 SetKeyDelay.
A_KeyDelayPlay A_KeyDurationPlay | 可以用来获取或设置通过 SendPlay 模式发送的按键的延迟或持续时间, 单位为毫秒. 有关详情, 请参阅 SetKeyDelay.
A_WinDelay | 可用于获取或设置窗口函数的延迟, 单位为毫秒. 有关详情, 请参阅 SetWinDelay.
A_ControlDelay | 可用于获取或设置控件修改函数的延迟, 单位为毫秒. 有关详情, 请参阅 SetControlDelay.
A_MenuMaskKey | 控制哪个键被用来掩饰(屏蔽) Win 或 Alt 键松开事件. 有关详情, 请参阅 A_MenuMaskKey.
A_MouseDelay A_MouseDelayPlay | 可以用来获取或设置鼠标延迟, 单位为毫秒. 传统的 SendEvent 模式为 A_MouseDelay, 而 SendPlay 为 A_MouseDelayPlay. 有关详情, 请参阅 SetMouseDelay.
A_DefaultMouseSpeed | 可以用来获取或设置默认的鼠标速度, 从 0(最快) 到 100(最慢) 的整数. 有关详情, 请参阅 SetDefaultMouseSpeed.
A_CoordModeToolTip A_CoordModePixel A_CoordModeMouse A_CoordModeCaret A_CoordModeMenu | 可以用来获取或设置相对坐标的区域. 可能的值是 Window, Client 或 Screen. 有关详情, 请参阅 CoordMode.
A_RegView | 可用于获取或设置注册表视图. 可能的值是 32, 64 和 Default. 有关详情, 请参阅 SetRegView.
A_TrayMenu | 返回可用于修改或显示托盘菜单的菜单对象.
A_AllowMainWindow | 可以用来获取或设置是否允许通过托盘图标打开脚本的主窗口. 可能的值是 0(禁止) 和 1(允许). 如果脚本既不是编译的也不是嵌入的, 此变量默认为 1, 否则此变量默认为 0, 但可以通过给该变量赋值来改写它. 将其设置为 1 还可以恢复托盘菜单中的 "Open" 菜单项, 并启用主窗口的 View 菜单中的项目, 如 "Lines most recently executed", 这允许查看脚本的源代码和其他信息. 在脚本运行时遇到下列函数, 总是能够显示主窗口并选择相应的视图选项: ListLines, ListVars, ListHotkeys 和 KeyHistory. 设置为 1 并不妨碍主窗口被 WinShow 显示, 或者被 ControlGetText 或类似的方法检查, 但它确实阻止了脚本的源代码和其他信息通过主窗口暴露出来, 除非脚本调用了上述的某个函数.
A_IconHidden | 可以用来获取或设置是否隐藏托盘图标. 可能的值是 0(可见) 和 1(隐藏). 有关详情, 请参阅 #NoTrayIcon.
A_IconTip | 可用于获取或设置托盘图标的工具提示文字, 当鼠标悬停在其上时显示该文本. 如果为空, 则使用脚本的名称. 要创建多行工具提示, 请在每行之间使用换行符(`n), 例如 "Line1`nLine2". 只显示前 127 个字符, 并且文本在第一个制表符(如果存在) 处被截断. 在 Windows 10 及更早版本中, 若要显示包含 & 符号的工具提示文本, 请使用另外两个 & 符号来转义 & 符号. 例如, 指定 A &&& B 将在工具提示的文本中显示 "A & B".
A_IconFile | 如果通过 TraySetIcon 指定自定义的托盘图标时, 变量的值为图标文件的完整路径和名称, 否则为空.
A_IconNumber | 如果 A_IconFile 为空时, 值为空. 否则, 它的值为 A_IconFile 中的图标的编号(通常为 1).

用户空闲时间

变量 | 描述
A_TimeIdle

从系统最后一次接收到键盘, 鼠标或其他输入后所经过的毫秒数. 这可以用来判断用户是否离开. 用户的物理输入和由 任何 程序或脚本生成的模拟输入(例如 Send 或 MouseMove 函数) 会让此变量重置为零. 由于此变量的值趋向于以 10 的增量增加, 所以不应该判断它是否等于另一个值. 相反, 应该检查此变量是否大于或小于另一个值. 例如:

if A_TimeIdle > 600000
    MsgBox "The last keyboard or mouse activity was at least 10 minutes ago."
A_TimeIdlePhysical | 与上面类似, 但在安装了相应的钩子(键盘或鼠标) 后会忽略模拟的键击和/或鼠标点击; 即此变量仅对物理事件做出响应. (这样避免了由于模拟键击和鼠标点击而误以为用户存在.) 如果两种钩子都没有安装, 则此变量等同于 A_TimeIdle. 如果仅安装了一种钩子, 那么仅此类型的物理输入才会对 A_TimeIdlePhysical 起作用(另一种/未安装钩子的输入, 包括物理的和模拟的, 都会被忽略).
A_TimeIdleKeyboard | 如果安装了键盘钩子, 这是自系统上次接收物理键盘输入以来所经过的毫秒数. 否则, 这个变量就等于 A_TimeIdle.
A_TimeIdleMouse | 如果安装了鼠标钩子, 这是自系统上次收到物理鼠标输入以来所经过的毫秒数. 否则, 这个变量就等于 A_TimeIdle.

热键, 热字串和自定义菜单项

变量 | 描述
A_ThisHotkey | 最近执行的热键或非自动替换热字串(如果没有则为空), 例如 #z. 如果当前线程被其他热键或热字串中断, 那么此变量的值会变化, 所以一般情况下, 最好使用 ThisHotkey 参数. 首次创建热键时 -- 通过 Hotkey 函数或脚本中的双冒号语法 -- 其键名及其修饰符的顺序成为此热键的固定名称, 由热键的所有变体共享. 首次创建热字串时 -- 通过 Hotstring 函数或脚本中的双冒号标签 -- 它的触发字符串和选项字符序列成为该热字符串的永久名称.
A_PriorHotkey | 除了保存前一次热键的名称外, 其他的与上面相同. 如果没有它会为空.
A_PriorKey | 在最近一次键-按下或键-释放之前按下的最后一个键的名称, 如果在按键历史中找不到合适的键-按下则为空. 不包括由 AutoHotkey 脚本生成的所有输入. 要使用此变量, 首先必须安装键盘或鼠标钩子并且启用了key history(按键历史).
A_TimeSinceThisHotkey | 从 A_ThisHotkey 按下后到现在经过的毫秒数. 如果 A_ThisHotkey 为空, 则此变量的值为空.
A_TimeSincePriorHotkey | 从 A_PriorHotkey 按下后到现在经过的毫秒数. 如果 A_PriorHotkey 为空, 则此变量的值为 -1.
A_EndChar | 用户最近按下的触发了非自动替换热字串的终止字符. 如果不需要终止符(由于使用了 * 选项), 那么此变量将为空.
A_MaxHotkeysPerInterval | 可用于获取或设置在 A_HotkeyInterval 所定义的时间间隔内按下热键而不会触发警告对话框的最大数量. 有关详情, 请参阅 A_MaxHotkeysPerInterval.
A_HotkeyInterval | 可用于获取或设置 A_MaxHotkeysPerInterval 使用的时间间隔长度, 以毫秒为单位.
A_HotkeyModifierTimeout | 可用于获取或设置超时, 该超时影响带有以下热键修饰符的 Send 的行为: Ctrl, Alt, Win 和 Shift. 有关详情, 请参阅 A_HotkeyModifierTimeout.

操作系统和用户信息

变量 | 描述
A_ComSpec

包含与 ComSpec 环境变量相同的字符串, 通常是命令提示符可执行文件(cmd.exe) 的完整路径. 常与 Run/RunWait 一起使用. 例如:

C:\Windows\system32\cmd.exe
A_Temp

存放临时文件的文件夹的完整路径和名称. 它的值从下列的其中一个位置检索(按顺序): 1) 环境变量 TMP, TEMP 或 USERPROFILE; 2) Windows 目录. 例如:

C:\Users\<UserName>\AppData\Local\Temp
A_OSVersion

操作系统的版本号, 格式为 "major.minor.build". 例如, Windows 7 SP1 为 6.1.7601.

在 AutoHotkey 可执行文件或已编译脚本的属性中应用兼容性设置会导致系统报告不同的版本号, 这将体现在 A_OSVersion 中.
A_Is64bitOS | 当操作系统为 64 位则值为 1(true), 为 32 位则为 0(false).
A_PtrSize | 包含指针的大小值, 单位为字节. 值为 4(32 位) 或 8(64 位), 取决于运行当前脚本的执行程序的类型.
A_Language | 当前系统的默认语言, 值为这些 4 位数字编码的其中一个.
A_ComputerName | 在网络上看到的计算机名称.
A_UserName | 运行当前脚本的用户的登录名.
A_WinDir | Windows 目录. 例如: C:\Windows
A_ProgramFiles

Program Files 目录(例如 C:\Program Files 或 C:\Program Files (x86)). 这通常与 ProgramFiles 环境变量相同.

在 64-位系统(和非 32-位系统), 适用于下列内容:

  • 如果可执行文件(EXE) 以 32 位脚本运行的时候, A_ProgramFiles 返回路径为 "Program Files (x86)" 目录.
  • 对于 32 位的进程, ProgramW6432 环境变量指向 64 位 Program Files 目录的路径. 在 Windows 7 和更高版本上, 对于 64 位的进程也是这样设置的.
  • ProgramFiles(x86) 环境变量指向 32 位 Program Files 目录的路径.
A_AppData

当前用户的应用程序数据文件夹的完整路径和名称. 例如:

C:\Users\<UserName>\AppData\Roaming
A_AppDataCommon

所有用户的应用程序数据文件夹的完整路径和名称. 例如:

C:\ProgramData
A_Desktop

当前用户的桌面文件夹的完整路径和名称. 例如:

C:\Users\<UserName>\Desktop
A_DesktopCommon

所有用户的桌面文件夹的完整路径和名称. 例如:

C:\Users\Public\Desktop
A_StartMenu

当前用户的开始菜单文件夹的完整路径和名称. 例如:

C:\Users\<UserName>\AppData\Roaming\Microsoft\Windows\Start Menu
A_StartMenuCommon

所有用户的开始菜单文件夹的完整路径和名称. 例如:

C:\ProgramData\Microsoft\Windows\Start Menu
A_Programs

当前用户的开始菜单中程序文件夹的完整路径和名称. 例如:

C:\Users\<UserName>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
A_ProgramsCommon

所有用户的开始菜单中程序文件夹的完整路径和名称. 例如:

C:\ProgramData\Microsoft\Windows\Start Menu\Programs
A_Startup

当前用户的开始菜单中启动文件夹的完整路径和名称. 例如:

C:\Users\<UserName>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
A_StartupCommon

所有用户的开始菜单中启动文件夹的完整路径和名称. 例如:

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
A_MyDocuments

当前用户 "我的文档" 文件夹的完整路径和名称. 与大多数类似变量不同, 当此文件夹为驱动器的根目录时, 此变量的值不包含最后的反斜杠(例如, 它的值是 M: 而不是 M:\). 例如:

C:\Users\<UserName>\Documents
A_IsAdmin

如果当前用户有管理员权限, 则值为 1, 否则为 0.

要使脚本以管理员权限重新启动(或显示提示向用户请求管理员权限), 请使用 Run *RunAs. 但是请注意, 以管理员权限运行脚本会导致脚本启动的所有程序也以管理员权限运行. 对于可能的替代方案, 请参阅常见问题(FAQ).

A_ScreenWidth
A_ScreenHeight

主监视器的宽度和高度, 单位为像素(例如 1024 和 768).

要获取多显示器系统中其他显示器的尺寸, 请使用 SysGet.

要获取整个桌面(即使它横跨多个显示器) 的宽度和高度, 请使用下面的例子:

VirtualWidth := SysGet(78)
VirtualHeight := SysGet(79)

此外, 使用 SysGet 可以获取显示器的工作区域, 它比显示器的整个区域小, 因为它不包括任务栏和其他注册的桌面工具栏.
A_ScreenDPI | 沿屏幕宽度每逻辑英寸的像素数. 在具有多个显示监视器的系统中, 此值对于所有监视器都是相同的. 在大多数系统中该值为 96; 它取决于系统文本大小(DPI) 设置. 另请参阅 GUI 的 -DPIScale 选项.

杂项

变量 | 描述
A_Clipboard | 可用于获取或设置系统剪贴板的内容. 有关详情, 请参阅 A_Clipboard.
A_Cursor

当前显示的鼠标光标类型. 其值为下列单词的其中一个: AppStarting(程序启动, 后台运行--箭头+等待), Arrow(箭头, 正常选择--标准光标), Cross(十字, 精确选择), Help(帮助, 帮助选择--箭头+问号), IBeam(工字光标, 文本选择--输入), Icon, No(No, 不可用--圆圈加反斜杠), Size, SizeAll(所有尺寸, 移动--四向箭头), SizeNESW(东南和西北尺寸, 沿对角线调整 2--双箭头指向东南和西北), SizeNS(南北尺寸, 垂直调整--双箭头指向南北), SizeNWSE(西北和东南尺寸, 沿对角线调整 1--双箭头指向西北和东南), SizeWE(东西尺寸, 水平调整--双箭头指向东西), UpArrow(向上箭头, 候选--指向上的箭头), Wait(等待, 忙--沙漏或圆圈), Unknown(未知). 与 size-类型光标一起使用的缩略词是罗盘方向, 例如 NESW = NorthEast(东北)+SouthWest(西南). 手型指针(点击和抓取) 属于 Unknown 类别.
A_EventInfo

包含下列事件的额外信息:

  • 鼠标滚轮热键(WheelDown/Up/Left/Right)
  • OnMessage
  • Regular Expression Callouts

注意: 与类似 A_ThisHotkey 这样的变量不同, 每个线程保留自身的 A_EventInfo 值. 因此, 如果一个线程被另一个中断, 在这个线程恢复时它仍将看到这些变量的原来/正确的值.

脚本也可以设置 A_EventInfo, 但只能在指针可用的范围内接受无符号整数(32-bit 或 64-bit 取决于 AutoHotkey 的版本).
A_LastError

这通常是脚本调用某些函数后, 包括 DllCall, Run/RunWait, File/Ini/Reg 函数(在文档中) 和可能的其他函数, 系统 GetLastError() 函数的结果. A_LastError 是一个介于 0 和 4294967295 之间的数字(通常格式化为十进制, 而不是十六进制). 零(0) 表示成功, 但是任何其他数字都表示调用失败. 每个数字对应一个特定的错误条件. 要了解如何获得本地化的错误描述文本, 请参阅 OSError, 或在 www.microsoft.com 搜索 "系统错误代码", 以获得列表. A_LastError 是每个线程的设置; 也就是说, 被其他线程中断不能改变它.

给 A_LastError 赋值, 也会调用系统的 SetLastError() 函数.
True
False

包含 1 和 0. 它们可以用来使脚本更具可读性. 有关详情, 请参阅布尔值.

这些实际上是关键字, 而不是变量.

Loop

变量 | 描述
A_Index | 可用于获取或设置当前循环迭代的次数(64 位整数). 第一次循环体执行时, 它为 1. 第二次, 它的值为 2; 依次类推. 如果一个内循环被外循环包围, 那么内循环优先. A_Index 在所有类型的循环中都起作用, 但在循环语句外值为 0. 对于像 Loop 这样的计数循环, 更改 A_Index 会影响将要执行的迭代次数.
A_LoopFileName, 等 | 此变量和其他相关变量仅在文件循环中有效.
A_LoopRegName, 等 | 此变量和其他相关变量仅在注册表循环中有效.
A_LoopReadLine | 请参阅文件读取循环.
A_LoopField | 请参阅解析循环.

变量的容量和占用内存

  • 当赋值给变量比当前更长的内容时, 会自动分配额外的系统内存给这个变量.
  • 通过赋值为空, 可以释放大变量占用的内存, 例如 var := "".
  • 脚本可以创建的变量数量没有限制. 程序设计用来支持至少几百万的变量而不会出现明显的性能下降.
  • 接受数字输入的函数和表达式通常支持 15 位的浮点数精度. 对于整数, 可以支持 64 位有符号整数, 其范围从 -9223372036854775808(-0x8000000000000000) 到 9223372036854775807(0x7FFFFFFFFFFFFFFF). 任何超出此范围的整数常量都将回绕. 同样的, 整数的算数运算结果超出此范围时会溢出回绕(例如 0x7FFFFFFFFFFFFFFF + 1 = -0x8000000000000000).


How to Install AutoHotkey | AutoHotkey v2

如何安装 AutoHotkey

如果您还没有下载 AutoHotkey, 您可以从以下位置之一获得它:

  • https://www.autohotkey.com/ - 当您单击 Download(下载) 时, 会显示多个选项.
  • https://www.autohotkey.com/download/ - 主下载链接是当前的 exe 安装程序, 但也有链接到当前版本的 zip 包和旧版本的存档.

注意: 本教程适用于 AutoHotkey v2.

主下载的文件名为 AutoHotkey_2.0_setup.exe. 运行此文件开始安装 AutoHotkey.

如果您不是计算机的管理员, 则可能需要选择 Current user 选项.

否则, 推荐的选项已经填写, 因此只需单击 Install(安装).

对于 v1 版本的用户: AutoHotkey v2 包含一个启动器, 允许多个版本的 AutoHotkey 共存, 同时共享一个文件扩展名(.ahk). 没有必要将 AutoHotkey v1 和 v2 安装到不同的目录中, 目前也不支持.

如果是为 所有用户 安装, 则需要在出现的标准 UAC 提示中提供管理员同意(换句话说, 点击 Yes).

如果没有什么复杂的情况, AutoHotkey 现在已经安装好了!

一旦安装完成, Dash 会自动显示.

下一个步骤

程序的使用涵盖了如何使用 AutoHotkey 的基础知识.

考虑安装一个支持 AutoHotkey 的编辑器, 使编辑和测试脚本更加容易.

文档包含许多示例, 您可以按照如何运行示例代码中的描述进行测试.

这些教程侧重于特定的常见任务:

  • 如何运行程序
  • 如何编写热键
  • 如何发送击键

Tidbit 编写的 AutoHotkey 初学者向导涵盖了一系列的主题.

有问题?

如果您在安装 AutoHotkey 时遇到问题, 请尝试在论坛上搜索您的问题, 或开始一个新主题以获得帮助或报告问题.

Zip 安装程序

AutoHotkey 也可以从 zip 下载安装.

  1. 使用文件资源管理器打开 zip 文件(不需要解压缩), 或将 zip 文件的内容解压缩到临时目录.
  2. 运行 Install.cmd.
  3. 如果您收到类似 "The publisher could not be verified. Are you sure...?", 单击 Run.
  4. 继续如上所述的安装.

安全提示

您可能会收到一个或多个安全提示, 这取决于几个因素.

Web 浏览器

常见的网络浏览器可能会显示一个警告, 如 "AutoHotkey_2.0_setup.exe 已被阻止, 因为它可能会损害您的设备." 这是一个通用警告, 适用于任何 "commonly downloaded" 的可执行文件类型. 换句话说, 它经常发生在软件的新版本上, 直到更多的用户下载了特定的版本.

为了保持下载, 不同的浏览器使用不同的方法. 在显示下载的地方附近寻找一个菜单按钮, 或者尝试右键单击被阻止的下载.

由于反病毒程序误报, 下载可能会被阻止; 在这种情况下, 请参阅下面的防病毒.

谷歌安全浏览服务(也被其他浏览器使用)已知会显示关于 AutoHotkey 的错误警告. 有关详情, 请参阅 Safe Browsing.

SmartScreen

Microsoft Defender SmartScreen 可能会显示类似 "Windows protected your PC" 的提示. 对于开源开发人员和独立软件供应商(ISV) 的软件来说, 这是很常见的, 特别是在每个新版本发布后不久. 下面这篇由 Louis Kessler 撰写的博客文章很好地描述了这个问题: That’s not very Smart of you, Microsoft

若要继续安装, 请选择 More info 然后选择 Run anyway.

Antivirus

如果您的防病毒软件将下载标记为恶意下载, 请参考以下内容:

  • 常见问题: 我的防病毒程序标记 AutoHotkey 或编译脚本为恶意软件. 真的是病毒吗?
  • 向反病毒公司报告误报
  • 防病毒误报


How to Manage Windows | AutoHotkey v2

如何管理窗口

AutoHotkey 可以做的最简单和最有用的事情之一是允许您创建操作窗口的键盘快捷键(热键). 脚本可以激活, 关闭, 最小化, 最大化, 恢复, 隐藏, 显示或移动几乎任何窗口. 这是通过调用适当的 Win 函数来完成的, 通过标题或其他一些条件来指定窗口:

Run "notepad.exe"
WinWait "Untitled - Notepad"
WinActivate "Untitled - Notepad"
WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2, "Untitled - Notepad"

这个例子应该打开一个新的记事本窗口, 然后移动它来填充主屏幕的一部分(宽度的 ¼, 和高度的 ½). 要了解如何试用, 请参阅如何运行示例代码.

由于不是本篇文档的重点, 我们不会在这里详细讨论用于操作窗口的许多函数. 例如, 要最小化窗口而不是激活它, 请将 WinActivate 替换为 WinMinimize. 有关可以操作窗口或检索信息的函数列表, 请参阅 Win 函数.

本教程的大部分内容都是关于如何 识别 要在哪个窗口上进行操作, 因为这通常是最麻烦的部分. 例如, 上面的例子有一些问题:

  • 窗口的标题没有必要重复.
  • 该标题仅适用于 UI 语言设置为英语的系统.
  • 它可能会移动一个现有的无标题记事本窗口, 而不是新的.
  • 如果由于某种原因没有出现匹配的窗口, 脚本将无限期地停止运行.

在介绍了一些基本知识之后, 我们将逐个解决这些问题.

提示: AutoHotkey 自带一个名为 Window Spy 的脚本, 可以用来确认窗口的标题, 类和进程名. 当仅通过标题识别窗口不可行的时候, 通常会使用类名和进程名. 您可以在脚本的托盘菜单或 AutoHotkey Dash 中找到 Window Spy.

标题匹配

在通过标题指定窗口时, 有几件事需要知道:

  • 窗口标题始终区分大小写, 除非使用 RegEx 匹配模式和 i) 修饰符.
  • 默认情况下, 函数需要窗口标题的子字符串. 例如, "Notepad" 可以同时匹配 "Untitled - Notepad" 和 "C:\A\B.ahk - Notepad2". SetTitleMatchMode 可用于使函数期望前缀, 精确匹配或 RegEx 模式.
  • 默认情况下, 隐藏窗口将被忽略(WinShow 除外). DetectHiddenWindows 可以用来改变这一点.

有关详情, 请参阅匹配行为.

活动窗口

要引用活动窗口, 请使用字母 "A" 代替窗口标题. 例如, 这将最小化活动窗口:

WinMinimize "A"

最后找到窗口

当 WinWait, WinExist, WinActive, WinWaitActive 或 WinWaitNotActive 找到一个匹配的窗口时, 他们将其设置为最后找到的窗口. 大多数窗口函数允许省略窗口标题(和相关参数), 在这种情况下, 默认为最后找到的窗口. 例如:

Run "notepad.exe"
WinWait "Untitled - Notepad"
WinActivate
WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2

这样可以避免重复窗口标题, 从而节省了一些时间, 如果需要更改窗口标题, 则可以更容易地更新脚本, 并且可能使代码更易于阅读. 它确保脚本每次都在同一个窗口上操作, 即使有多个匹配的窗口, 或者在 "找到的" 窗口后窗口标题发生了变化, 也使脚本更加可靠. 它还使脚本更有效地执行, 但不是很多.

窗口类

窗口类是一组属性, 用作创建窗口的模板. 通常, 窗口类的名称与应用程序或窗口的用途有关. 当窗口存在时, 窗口的类永远不会改变, 因此当通过标题进行标识是不切实际或不可能的时候, 我们经常可以使用它来标识窗口.

例如, 我们可以使用窗口的类, 而不是窗口标题 "Untitled - Notepad", 在这种情况下, 不管 系统语言是什么, 它恰好是 "Notepad":

Run "notepad.exe"
WinWait "ahk_class Notepad"
WinActivate
WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2

窗口类通过使用单词 "ahk_class" 来区别于标题, 如上面所示. 若要组合多个条件, 请先列出窗口标题. 例如: "Untitled ahk_class Notepad".

相关: ahk_class

进程名称/路径

可以由创建它们的进程来识别窗口, 方法是使用单词 "ahk_exe" 后跟进程名称或路径. 例如:

Run "notepad.exe"
WinWait "ahk_exe notepad.exe"
WinActivate
WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2

相关: ahk_exe

Process ID (PID)

每个进程都有一个 ID 号, 该 ID 号在进程退出之前保持唯一. 我们可以使用这个来使我们的 Notepad 示例更加可靠, 确保它忽略除新进程创建的记事本窗口外的任何记事本窗口:

Run "notepad.exe",,, &notepad_pid
WinWait "ahk_pid " notepad_pid
WinActivate
WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2

我们需要连续三个逗号; 其中两个只是跳过 Run 函数的未使用的 WorkingDir 和 Options 参数, 因为我们想要的(OutputVarPID) 是第四个参数.

Ampersand(&) 是 引用操作符. 这用于 通过引用 将 notepad_pid 变量传递给 Run 函数(换句话说, 传递变量本身而不是它的值), 允许函数为变量分配一个新值. 然后 notepad_pid 成为实际进程 ID 的占位符.

字符串 "ahk_pid " 与 notepad_pid 变量所包含的进程 ID 相连接, 只需将它们按顺序写入, 并用空格分隔. 结果是一个类似 "ahk_pid 1040" 的字符串, 但是这个数字是不可预测的.

如果新进程可能创建多个窗口, 则可以通过用空格分隔窗口标题和其他条件来组合它们. 窗口标题必须始终排在前面. 例如: "Untitled ahk_class Notepad ahk_pid " notepad_pid.

相关: ahk_pid

窗口 ID(HWND)

每个窗口都有一个唯一的 ID 号, 直到窗口被销毁. 在编程术语中, 这被称为 "窗口句柄" 或 HWND. 尽管不像使用 最后找到的窗口 那样方便, 但窗口的 ID 可以存储在一个变量中, 以便脚本可以通过您选择的名称引用它, 即使标题发生了变化. 一次只能有一个 最后找到的窗口, 但是可以使用尽可能多的窗口 id 来创建变量名(也可以使用) 数组).

窗口 ID 由 WinWait, WinExist 或 WinActive 返回, 也可以来自其他来源. 可以重写记事本示例以利用这一点:

Run "notepad.exe"
notepad_id := WinWait("Untitled - Notepad")
WinActivate notepad_id
WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2, notepad_id

这将 WinWait 的返回值赋给变量 "notepad_id". 换句话说, 当 WinWait 找到窗口时, 它生成窗口的 ID 作为结果, 然后脚本将这个结果存储在变量中. "notepad_id" 只是我为这个例子创建的一个名称; 您可以使用任何对您有意义的变量名(在某些限制条件下).

注意, 我在窗口标题周围添加了圆括号, 紧跟 着函数名. 在函数调用语句中可以省略括号(也就是说, 函数调用在一行的最开始), 但在这种情况下, 您无法获得函数的返回值.

脚本还可以保留变量 notepad_id 以供以后使用, 例如关闭或重新激活窗口或将其移动到其他地方.

相关: ahk_id

Timeout

默认情况下, WinWait 将无限期地等待匹配的窗口出现. 您可以通过托盘图标打开脚本的主窗口来确定是否发生了这种情况(除非您已禁用它). 默认情况下, 窗口通常打开 ListLines. 如果 WinWait 仍在等待, 它将出现在行列表的最底部, 后面跟着它开始等待的秒数. 除非从"视图"菜单中选择"刷新", 否则数字不会更新.

试着运行这个例子并像上面描述的那样打开主窗口:

WinWait "Untitled - Notpad"  ; (故意输错)

如果脚本卡住等待窗口, 您通常需要退出或重新加载脚本来解除卡住. 为了防止这种情况发生(或再次发生), 您可以使用 WinWait 的timeout 参数. 例如, 这将等待最多 5 秒的窗口出现:

Run "notepad.exe",,, &notepad_pid
if WinWait("ahk_pid " notepad_pid,, 5)
{
    WinActivate
    WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2
}

If 语句下面的 block 只有在 WinWait 找到匹配的窗口时才会执行. 如果超时, 则跳过该块, 并在结束大括号之后继续执行(如果它之后有任何代码).

注意, 当我们想在表达式中使用函数的结果时(比如 if 语句的条件) "WinWait" 后面的括号是必需的. 您可以将函数调用本身视为函数结果的替代品. 例如, 如果 WinWait 在超时之前找到一个匹配, 结果是非零. if 1 将执行 If 语句下面的块, 而 if 0 将跳过它.

另一种书写方法是, 如果等待超时, 则提前返回(换句话说, abort). 例如:

Run "notepad.exe",,, &notepad_pid
if !WinWait("ahk_pid " notepad_pid,, 5)
    return
WinActivate
WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2

通过应用逻辑非运算符(! 或 not) 来反转结果. 如果 WinWait 超时, 则结果为 0. !0 的结果是 1, 所以当 WinWait 超时时, if 语句执行 return.

WinWait 的结果实际上是窗口的 ID(如上所述), 如果超时则为零. 如果你还想通过 ID 引用窗口, 你可以将结果赋值给一个变量, 而不是直接在 If 语句中使用它:

Run "notepad.exe",,, &notepad_pid
notepad_id := WinWait("ahk_pid " notepad_pid,, 5)
if notepad_id
{
    WinActivate notepad_id
    WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2, notepad_id
}

为了避免重复变量名, 你可以同时将结果赋值给一个变量, 并检查它是否为非零(true):

Run "notepad.exe",,, &notepad_pid
if notepad_id := WinWait("ahk_pid " notepad_pid,, 2)
{
    WinActivate notepad_id
    WinMove 0, 0, A_ScreenWidth/4, A_ScreenHeight/2, notepad_id
}

在这种情况下, 注意不要混淆 :=(赋值) 和 = 或 ==(比较). 例如, if myvar := 0 分配一个新值, 并且每次都给出相同的结果(false), 而 if myvar = 0 则将先前分配的值与 0 进行比较.

表达式(数学运算等.)

当您想要移动一个窗口时, 相对于它之前的位置或大小移动它或调整它的大小通常是有用的, 这可以通过使用 WinGetPos 函数来检索. 例如, 通过按住 RCtrl 并按方向键, 下面的热键可以在每个方向上移动活动窗口 10 个像素:

>^Left::    MoveActiveWindowBy(-10,   0)
>^Right::   MoveActiveWindowBy(+10,   0)
>^Up::      MoveActiveWindowBy(  0, -10)
>^Down::    MoveActiveWindowBy(  0, +10)

MoveActiveWindowBy(x, y) {
    WinExist "A"  ; 使活动窗口成为 "上次找到的窗口"
    WinGetPos &current_x, &current_y
    WinMove current_x + x, current_y + y
}

该示例定义了一个函数来避免代码多次重复. x 和 y 成为每个热键中指定的两个数字的占位符. WinGetPos 将当前位置存储在 current_x 和 current_y 中, 然后将其添加到 x 和 y 中.

像这样的简单表达式应该看起来相当熟悉. 有关详情, 请参阅表达式; 但是要注意, 有很多细节你可能不需要马上学习.


How to Run Example Code | AutoHotkey v2

如何运行示例代码

快速使用 AutoHotkey 最简单的方法是使用示例代码, 试用它并根据你的需要进行调整.

在本文档中, 代码块中有许多示例, 例如下面的代码块.

MsgBox "Hello, world!"

大多数(但不是全部) 示例可以按原样执行, 以演示它们的效果. 通常有两种方法可以做到这一点:

  1. 将代码下载为文件. 如果您的浏览器支持, 当鼠标悬停在代码块上时, 单击出现在代码块右上方的 ↓ 按钮, 您可以将任何代码块(如上面的代码块) 下载为脚本文件.
  2. 将代码复制到一个文件中. 通常最好是创建一个新文件, 这样现有代码就不会干扰到示例代码. 创建文件后, 打开它进行编辑, 并复制粘贴代码.

运行文件: 一旦你把代码放在一个脚本(.ahk) 文件中, 运行它通常只需双击该文件; 但还有其他方法.

分配热键

有时, 如果先将代码分配给热键, 测试代码会更容易. 例如, 考虑这段代码来最大化活动窗口:

WinMaximize "A"

如果您将其保存到一个文件中, 并通过双击该文件来运行该文件, 它可能会最大化包含该文件的文件资源管理器窗口. 你可以把它分配给一个热键来测试它在你想要的任何窗口上的效果. 例如:

^1::WinMaximize "A"

现在您可以激活 测试对象 并按 Ctrl+1 使其最大化.

有关热键的更多信息, 请参阅如何编写热键.

求助

如果你在脚本中犯了一个错误, 有时它会使计算机更难使用. 例如, 热键 n:: 将在你按下 N 时激活, 并阻止你输入该字符. 要撤消此操作, 只需退出脚本. 您可以通过右键单击脚本的托盘图标并选择 Exit 来做到这一点.

如果你发送了一个向下的键而不发送向上的键. 键就会 "卡在下面", 在这种情况下, 退出脚本还不够, 因为操作系统仍然认为键被按住了. 一般来说, 你可以通过物理按压来 "松开" 这个键.

如果脚本进入失控循环或难以停止, 您可以作为最后的手段注销或关闭计算机. 当你注销时, 在您的会话下运行的所有应用程序都将终止, 包括 AutoHotkey. 在某些情况下, 如果某个脚本或程序阻止关机, 您可能需要单击 "log off anyway" 或 "shut down anyway".

重新加载

启动脚本后, 对脚本文件的更改不会自动生效. 为了使它们生效, 必须重新加载脚本. 这可以通过脚本的托盘图标或 Reload 函数来完成, 您也可以从热键调用该函数. 在许多情况下, 也可以通过简单地再次运行脚本来实现, 但这取决于脚本的 #SingleInstance 设置.

正确的工具

学习编程通常是一个重复的过程; 取一些代码, 做一个小的更改, 测试代码, 清洗和重复. 如果您使用 支持 AutoHotkey 的文本编辑器. 这个过程会更快, 更高效. 不同的编辑器支持不同, 但最重要的特性是(在我看来):

  • 使用键盘快捷键(如 F5) 运行脚本的能力.
  • 语法高亮显示, 使代码更易于阅读(和编写).

有关建议, 请参阅支持 AutoHotkey 的编辑器或者访问 Editors 子论坛.


How to Run Programs | AutoHotkey v2

如何运行程序

AutoHotkey 可以做的最简单和最有用的事情之一是允许您创建启动程序的键盘快捷键(热键).

通过调用 Run 函数启动程序, 将程序的命令行作为参数 传递:

Run "C:\Windows\notepad.exe"

这个例子启动记事本. 想要了解如何试用, 请参阅如何运行示例代码.

在这个阶段, 我们还没有定义热键(换句话说, 分配了键盘快捷键), 所以指令是立即执行的. 在这种情况下, 脚本没有其他事情要做, 因此它自动退出. 如果你更喜欢在学习过程中创建有用的热键, 请先查看如何编写热键.

注意: Run 也可以用来打开文档, 文件夹和 URL.

要启动其他程序, 只需将上面示例中的路径替换为您希望启动的程序的路径. 有些程序已经在系统中注册了它们的路径, 在这种情况下, 你可以只传递程序的文件名, 带或(有时)不带 ".exe" 扩展名. 例如:

Run "notepad"

命令行参数

如果程序接受命令行参数, 它们可以作为 Run 函数的第一个参数的一部分传递. 下面的例子应该在记事本中打开 license.txt:

Run "notepad C:\Program Files\AutoHotkey\license.txt"

注意: 本例假设 AutoHotkey 安装在默认位置, 否则将显示错误.

简单, 是吧? 现在假设我们想要在写字板而不是记事本中打开文件.

Run "wordpad C:\Program Files\AutoHotkey\license.txt"

运行这段代码, 看看可以从结果中了解到什么.

好吧, 新代码不管用. 希望您没有立即关闭错误对话框; 错误对话框是编码过程的正常组成部分, 通常包含非常有用的信息. 这句话应该告诉我们一些事情:

  • 首先, 显而易见的是: 该程序无法启动.
  • 对话框显示 "Action" 和 "Params", 但是我们的整个命令行显示在 "Action" 旁边, 而 "Params" 是空的. 换句话说, Run 函数不知道程序名在哪里结束, 参数从哪里开始.
  • "The system cannot find the file specified(系统无法找到指定的文件)" (在英语系统上). 也许系统找不到 "wordpad", 但它真正的意思是没有 "wordpad C:\..." 这样的文件.

但是记事本为什么正常? 单独运行 "notepad" 或 "wordpad" 都可以, 但原因不同. 与 notepad.exe 不同, wordpad.exe 不能通过检查 PATH 环境变量中列出的每个目录来找到. 可以通过不同的方法来定位它，这需要 Run 函数来分离程序名称和参数.

所以在这种情况下, Run 函数需要一些帮助, 以以下任何或所有形式:

  • 显式地使用 ".exe" 扩展名.
  • 显式使用 wordpad.exe 的完整路径.
  • 程序名用引号括起来.

现在, 选择最简单的方法:

Run "wordpad.exe C:\Program Files\AutoHotkey\license.txt"

现在写字板启动, 但它显示错误: "C:\Program" wasn't found.

引号和空格

通常, 在向程序传递命令行参数时, 如果参数中包含空格, 则需要将每个参数用引号括起来. 这对于记事本来说是不必要的, 但是记事本是一般规则的一个例外. 一种天真的解决方法可能是简单地添加更多的引号:

Run "wordpad.exe "C:\Program Files\AutoHotkey\license.txt""

但这行不通, 因为默认情况下, 引号是用来表示原义文本的开始和结束. 那么, 我们如何在命令行中包含一个文字引号, 而不是让它结束命令行呢?

方法 1: 在每个文字引号前面加上 `(back-tick, 反引号或重音). 这被称为转义序列. 然后引号被包含在命令行中(即传递给 Run 函数的字符串), 而反勾号, 完成了它的目的, 被省略了.

Run "wordpad.exe `"C:\Program Files\AutoHotkey\license.txt`""

方法 2: 将命令行括在单引号而不是双引号中.

Run 'wordpad.exe "C:\Program Files\AutoHotkey\license.txt"'

当然, 在这种情况下, 文本中的任何 原义 单引号(或撇号) 都需要转义(`').

编写代码的方式会影响到 Run 函数中实际使用的引号. 在上面的两个例子中, the Run 函数接收字符串 wordpad.exe "C:\Program Files\AutoHotkey\license.txt". Run 函数要么将其拆分为 程序名 和 参数(其他所有内容), 要么将其留给系统. 在任何一种情况下, 如何解释剩余的引号完全取决于目标程序.

如果引号前面有反斜杠, 许多程序将其视为参数的一部分. 例如, Run 'my.exe "A\" B' 可能会生成一个值为 A" B 的参数, 而不是两个参数. 这取决于程序, 通常可以通过双反斜杠来避免, 如在 Run 'my.exe "A\\" B', 通常会产生两个参数(A\ 和 B).

大多数程序将引号解释为一种切换, 在 "空格结束参数" 和 "空格包含在参数中" 之间切换模式. 换句话说, Run 'my.exe "A B"' 通常相当于运行 Run 'my.exe A" "B'. 因此, 另一种避免使用斜杠的方法是引用 空格 而不是整个参数, 或者在斜杠之前结束引号, 如 Run 'my.exe "A"\ B'.

包括变量

命令行通常需要包含一些变量. 例如, "Program Files" 目录的位置可能因系统而异, 脚本可以通过使用 A_ProgramFiles 变量来考虑这一点. 如果变量包含整个命令行, 只需将变量传递给 Run 函数以执行它.

Run A_ComSpec  ; 启动命令提示符(几乎总是 cmd.exe).
Run A_MyDocuments  ; 打开用户的文档文件夹.

在带引号的字符串中 包含 变量是行不通的; 相反, 我们使用连接将文字字符串与变量连接在一起. 例如:

Run 'notepad.exe "' A_MyDocuments '\AutoHotkey.ahk"'

另一种方法是使用 Format 执行替换. 例如:

Run Format('notepad.exe "{1}\AutoHotkey.ahk"', A_MyDocuments)

注意: Format 可以同时执行其他格式化, 例如用 0 或空格填充, 或将数字格式化为十六进制而不是十进制.

运行的参数

除了要执行的命令行之外, Run 数还接受一些影响其行为的其他参数.

WorkingDir 指定新进程的工作目录. 如果您为程序指定了相对路径, 则它相对于此目录. 命令行参数中的相对路径通常也相对于该目录, 但这取决于程序.

Run "cmd", "C:\"  ; 在 C:\ 处打开命令提示符

选项 通常可以用来运行最小化或隐藏的程序, 而不是让它弹出在屏幕上, 但有些程序忽略它.

OutputVarPID 提供了进程 ID, 它通常与 WinWait 或 WinWaitActive 和 ahk_pid 一起使用, 以等待程序在屏幕上显示一个窗口, 或标识其中一个窗口. 例如:

Run "mspaint",,, &pid
WinWaitActive "ahk_pid " pid
Send "^e" ; Ctrl+E 打开映像属性对话框.

系统的动词

系统动词是系统或应用程序为特定文件类型注册的操作. 它们通常在资源管理器中文件的右键菜单中可用, 但它们的实际名称并不总是与菜单中显示的文本相匹配. 例如, AutoHotkey 脚本有一个 "edit" 动词, 用于在编辑器中打开脚本, 以及(如果安装了 Ahk2Exe) 一个 compiles 动词, 用于编译脚本.

"Edit" 是 Run 默认识别的常用动词列表之一, 因此只需将单词后跟空格和文件名, 如下所示:

Run 'edit ' A_ScriptFullPath  ; 通常等同于 Edit

任何在系统中注册的动词都可以使用 * 前缀执行, 如下所示:

Run '*Compile-Gui ' A_ScriptFullPath

如果安装了 Ahk2Exe, 这将打开预先选择当前脚本的 Ahk2Exe Gui.

环境

每当一个新进程启动时, 它通常会继承启动它的进程(父进程) 的 环境. 这基本上意味着所有脚本的环境变量都由使用 Run 启动的任何程序继承.

在某些情况下, 可以在启动程序之前使用 EnvSet 设置环境变量以影响程序的行为, 或将信息传递给程序. 脚本还可以使用 EnvGet 读取它可能从其父进程继承的环境变量.

在 64 位系统上, 脚本自身的环境很大程度上取决于运行它的 EXE 是 32 位还是 64 位. 32 位进程不仅具有不同的环境变量, 而且出于兼容性原因还具有文件系统重定向.

Run "cmd /k set pro"

上面的例子显示了一个命令提示符, 它打印所有以 "pro" 开头的环境变量. 如果您从 32 位脚本运行它, 您可能会看到 PROCESSOR_ARCHITECTURE=x86 和 ProgramFiles=C:\Program Files (x86). 虽然标题显示类似于 "C:\Windows\System32\cmd.exe", 这是一个谎言; 它实际上是 32 位版本, 它实际上位于 "C:\Windows\SysWow64\cmd.exe" 中.

在这种简单的情况下, 绕过 "System32" 重定向的最简单方法是使用 "SysNative". 但是, 这只能在 64 位系统上的 32 位进程中工作, 因此必须有条件地完成. 当以下示例在 64 位系统上执行时, 即使脚本是 32 位的, 它也会显示 64 位命令提示符:

if FileExist(A_WinDir "\SysNative")
    Run A_WinDir "\SysNative\cmd.exe /k set pro"
else
    Run "cmd /k set pro"


How to Send Keystrokes | AutoHotkey v2

如何发送击键

Send "Hello, world{!}{Left}^+{Left}"

发送击键(或简称键) 是自动化程序最常见的方法, 因为它是最常用的方法. 更直接的方法往往只适用于特定类型的应用程序.

学习如何发送 key 大致有两个部分:

  1. 如何编写代码, 以便程序知道要发送哪些 key.
  2. 如何使用可用的模式和选项来获得正确的最终结果.

重要的是要理解, 发送一个键并不能完美地复制物理按下键的行为, 即使您将其降低到人类的速度. 但在深入研究之前, 我们先了解一些基础知识.

尝试这些例子

如果您运行 SendText "Hi!" 这样的示例, 文本将立即发送到活动(聚焦)窗口, 这可能没有多大用处, 这取决于您如何运行示例. 通常更好的方法是定义一个热键, 运行示例来加载它, 然后在您想要测试它的效果时按下热键. 下面的一些例子将使用有编号的热键 ^1:: (Ctrl 和一个数字, 所以如果没有重复的例子, 你可以一次尝试多个例子), 但你可以根据自己的需要进行更改.

要了解如何自定义热键或创建自己的热键, 请参阅如何编写热键.

如果您不确定如何尝试这些示例, 请参阅如何运行示例代码.

如何编写代码

当发送按键时, 您通常希望发送按键或键组合以获得其效果(如 Ctrl+C 复制到剪贴板), 或键入一些文本. 键入文本更简单, 因此我们将从那里开始: 只需调用 SendText 函数, 将您想要发送的确切文本传递给它.

^1::SendText "To Whom It May Concern"

从技术上讲, SendText 实际上发送的是 Unicode 字符包, 而不是击键, 这使得它对于通常使用组合键(如 Shift+2 或 AltGr+a) 键入的字符更加可靠.

带引号的字符串的规则

SendText 逐字发送文本, 但请记住语言规则. 例如, 原义文本必须括在引号中(双引号 " 或单引号 '), 并且引号本身不会被 SendText 函数 "看到". 若要发送原义引号, 可以将其括在相反类型的引号中. 例如:

^2::SendText 'Quote marks are also known as "quotes".'

或者, 使用转义序列. 在带引号的字符串中, `" 转换为原义的 ", 而 `' 转换为原义的 '. 例如:

^3::{
    SendText "Double quote (`")"
    SendText 'Single quote (`')'
}

您还可以交替使用两种引号:

^4::SendText 'Double (") and' . " single (') quote"

这两个字符串在传递给 SendText 函数之前连接在一起(连接). 点(.) 可以省略, 但这会使一个结束和另一个开始的位置更难看到.

正如您在上面看到的, 转义字符 `(被称为 backquote, backtick, grave accent 和其他名称) 具有特殊含义, 因此如果您想发送该原义字符(或发送相应的按键), 则需要将其加倍, 如发送 Send "``". 其他常见的转义序列包括 `n 表示换行符(Enter) 和 `t 表示制表符. 有关详情, 请参阅转义序列.

发送键和组合键

SendText 最适合逐字发送文本, 但它不能发送不生成文本的键, 如 Left 或 Home. Send, SendInput, SendPlay, SendEvent 和 ControlSend 可以发送文本和组合键, 或者不产生文本的键. 为了完成所有这些操作, 它们为以下符号添加了特殊含义: ^!+#{}

前四个符号对应于标准修键, Ctrl(^), Alt(!), Shift(+) 和 Win(#). 它们可以组合使用, 但仅影响下一个键.

要按名称发送按键, 或发送上述任一符号的原义文本, 请将其括在大括号中. 例如:

  • ^+{Left} 生成 Ctrl+Shift+Left
  • ^{+}{Left} 生成 Ctrl++ 后跟字母 Left
  • ^+Left 生成 Ctrl+Shift+L 后跟原义字母 eft

当按下 Ctrl+Shift+" 时, 下面的示例发送两个引号, 然后将插入点向左移动, 准备在引号内键入内容:

^+"::Send '""{Left}'

对于 ^!+#{} 以外的任何单个字符, Send 将其转换为相应的组合键, 并按下并释放该组合键. 例如, Send "aB" 按下并释放 A, 然后按下并释放 Shift+B. 类似地, 在默认情况下, 用大括号括起来的任何键名都会被按下并释放. 例如, Send "{Ctrl}a" 会按下并释放 Ctrl, 然后按下并释放 A; 可能这并不是你想要的.

若要只按下(按住) 或释放某个键, 请将键名用大括号括起来, 后面跟着空格, 然后是单词 "down" 或 "up". 下面的例子使 Ctrl+CapsLock 切换 Shift:

*^CapsLock::{
    if GetKeyState("Shift")
        Send "{Shift up}"
    else
        Send "{Shift down}"
}

热键 vs. Send

警告: 热键和发送有一些您应该注意的差异.

尽管热键也使用符号 ^!+# 和相同的按键名称, 但有几个重要的区别:

  • Send 不支持其他热键修饰符号. 例如, >^a:: 对应于 RCtrl+A, 但要发送该组合, 您需要完整拼写出键名, 如 Send "{RCtrl down}a{RCtrl up}".
  • 按键名称从不括在热键中的大括号中, 但在 Send 中必须始终括在大括号中(如果长度超过一个字符).
  • Send 区分大小写. 例如, Send "^A" 发送 Ctrl 和 大写 "a" 的组合, 因此 Ctrl+Shift+A. 相比之下, ^a:: 和 ^A:: 是等价的.

这是因为 Send 有多种用途, 而热键针对组合键进行了优化.

在相关说明中, 热字符串专门用于检测文本输入, 因此符号 ^!+#{} 在热字符串触发文本中没有特殊含义. 但是, 热字符串的 replacement 文本使用与 Send 相同的语法(使用 T 选项 时除外). 每当在以下热字符串处于活动状态的情况下键入 "{" 时, 它都会发送 "}", 然后发送 Left, 以将插入点 移回括号之间:

:*?B0:{::{}}{Left}

Blind 模式

通常情况下, Send 假定您物理按住的任何修饰键都不应该与您要求它发送的键组合在一起. 例如, 如果你按住 Ctrl 并调用 Send "Hi", Send 会在发送 "Hi" 之前自动释放 Ctrl, 然后再按下它.

有时你想要的是将一些键与之前按下或发送的其他修饰符一起发送. 为此, 您可以使用 {Blind} 前缀. 在运行以下示例时, 尝试聚焦一个非空文本编辑器或输入字段, 并按住 Ctrl 或 Ctrl+Shift 的同时按住 1 或 2:

*^1::Send "{Blind}{Home}"
*^2::Send "{Blind}{End}"

有关 {Blind} 的详细情况, 请参阅 Blind 模式.

其他

Send 支持其他一些特殊的结构, 如:

  • {U+00B5} 按其序号值(字符代码)发送一个 Unicode 字符.
  • {ASC 0181} 发送 Alt+Numpad 序列.
  • {Click Options} 单击或移动鼠标.

有关完整列表, 请参阅按键名称.

模式和选项

发送一个键并不能完全复制物理按下键的行为. 操作系统提供了几种不同的发送按键的方法, 每种方法都有不同的注意事项. 有时候为了得到你想要的结果, 你不仅需要尝试不同的方法, 还需要调整时间.

主要方法有 SendInput, SendEvent 和 SendPlay. SendInput 通常是最可靠的, 因此默认情况下, Send 等同于 SendInput. SendMode 可以用来使 Send 与 SendEvent 或 SendPlay 同义. 文档详细描述了 SendInput 和 SendPlay 的其他优点和缺点, 但我建议当您使用 SendInput 时, 只尝试 SendEvent 或 SendPlay.

警告: SendPlay 不能在现代系统上工作, 除非你使用 UI 访问. 在 Windows 11 或更新的系统中, SendPlay 可能会没有任何效果.

另一个值得尝试的选项是 ControlSend. 这并不使用发送击键的正式方法, 而是直接将消息发送到您指定的窗口.主要的优点是窗口通常不需要处于活动状态来接收这些消息. 但由于它绕过了系统对键盘输入的正常处理, 有时它无法工作.

时间和延迟

有时你可以比人类更快地发送大量的击键, 有时你不能. 通常有两种情况可能需要延迟:

  • 按键应该触发目标应用中的某些更改(例如显示新控件或窗口), 并且在发生这种情况之前发送另一个按键会产生错误的效果.
  • 该应用程序无法跟上快速的击键流, 您需要将它们全部放慢.

对于第一种情况, 您可以简单地调用 Send, 接着 Sleep, 继续 Send, 依此类推.

对于第二种情况, 使用 SetKeyDelay. 此函数可以设置每次击键之间的延迟和击键的持续时间(即按下和松开键之间的延迟).

^1::{
    SetKeyDelay 75, 25  ; 75ms between keys, 25ms between down/up.
    SendEvent "You should see the keys{bs 4}text appear gradually."
}

警告: SendInput 不支持键延迟, 默认情况下 Send 也不支持.

为了使 SetKeyDelay 有效, 你通常必须使用 SendMode "Event" 或调用 SendEvent, SendPlay 或 ControlSend 代替 Send 或 SendText.

发送大量文本

发送多行文本的一种方法是使用延续片段:

SendText "
(
    Leading indentation is stripped out,
    based on the first line.
    Line breaks are kept
    unless you use the "Join" option.
)"

虽然它通常非常快, 但 SendText 仍然必须每次发送一个字符, 而 Send 通常需要发送至少两倍的消息(按下 和 松开键). 当发送大量文本时, 这会造成明显的延迟. 它也可能变得不可靠, 因为较长的延迟意味着与用户输入冲突, 键盘焦点转移或其他条件变化的风险更高.

一般来说, 将文本放在剪贴板上并 粘贴 会更快, 更可靠. 例如:

^1::{
    old_clip := ClipboardAll()  ; Save all clipboard content
    A_Clipboard := "
    (Join`s
        This text is placed on the clipboard,
        and will be pasted below by sending Ctrl+V.
    )"
    Send "^v"
    Sleep 500  ; Wait a bit for Ctrl+V to be processed
    A_Clipboard := old_clip  ; Restore previous clipboard content
}


How to Write Hotkeys | AutoHotkey v2

如何编写热键

热键是一个可以触发某个动作的键或组合键. 例如, Win+E 通常会启动文件资源管理器, 而 F1 通常会激活一个特定应用程序的帮助功能. AutoHotkey 有能力定义热键, 这些热键可以在任何地方使用, 或 只在特定的应用程序中使用, 执行任何你能用代码表达的动作.

定义热键最常见的方法是写下 热键的名称, 后面加上双冒号, 然后是动作:

#n::Run "notepad"

这个例子定义了一个热键, 每当你按下 Win+N 时运行记事本. 要了解如何试用, 请参阅如何运行示例代码.

有关运行程序的更多信息, 请参阅如何运行程序.

如果需要多行, 请使用大括号标记热键动作的开始和结束. 这就是所谓的块.

#n::
{
    if WinExist("ahk_class Notepad")
        WinActivate  ; Activate the window found above
    else
        Run "notepad"  ; Open a new Notepad window
}

开大括号也可以写在热键的同一行, 在 :: 之后.

双冒号热键后面的块隐式的是函数的主体, 但这只有在定义自己的变量时才重要. 现在, 只需知道块是用来将多行组合成一个动作或 语句 (有关详情, 请参阅控制流).

基本的快捷键

对于大多数热键, the 热键名称 由紧跟着单个字母或符号, 或键名的可选修饰符组成. 试着对上面的例子做以下修改:

  • 去掉 #, 每当你单独按下 N 时, 热键激活. 请记住, 如果出现错误, 您可以随时退出脚本.
  • 使用 ^(Ctrl), !(Alt) 或 +(Shift) 替换 #, 或者尝试各种组合.
  • 使用 <^ 替换 # 使其只在按下 左 Ctrl 键时激活, 或者 >^ 代表右 Ctrl 键, 或 同时 使用两个键.
  • 将 n 替换为任何其他字母或符号(除了 :).
  • 将 n 替换为按键列表中的任意名称.

注意::: 前面的最后一个字符永远不会被解释为修饰符.

使用这种形式的热键, 只有组合中的最后一个键可以按字面意思写成单个字符或将其名称完整地拼写出来. 例如:

  • #:: 将创建一个由哈希键(井号键 #)激活的热键, 或与该符号相关的任何组合(在美国布局中, 它是 Shift+3).
  • ##:: 会创建一个类似上面的热键, 但只有当你同时按住 Windows 键时才会激活.
  • LWin:: 将创建一个热键, 通过按住左边的 Windows 键而不使用任何其他修饰键来激活.

最常见的修饰符是 Ctrl(^), Alt(!), Shift(+) 和 Win(#).

符号 < 和 > 可以作为上述四个修饰符中任何一个的前缀, 以指定该键的左侧或右侧变体. 修饰符组合 <^>! 对应于 AltGr 键(如果你的键盘布局中存在), 因为操作系统将其作为 LCtrl 和 Alt 的组合来实现.

其他的修饰符是:

  • *(通配符) 允许热键激活, 即使你按住的修饰键不在热键符号中.
  • ~(非抑制) 防止热键阻塞该键的原生功能.
  • $(使用钩子) 防止在发送按键时出现无意义的循环, 并且在某些情况下使热键更可靠.

要使热键只在释放键时触发, 而不是在按下键时触发, 请使用 UP 后缀.

相关: 热键修饰符, 按键列表

上下文敏感的热键

#HotIf 指令可以用来指定激活热键必须满足的条件, 如:

  • 当您按下热键时, 某个特定应用程序的窗口处于活动状态.
  • 如果按下热键时, CapsLock 是打开的.
  • 可以用代码检测的任何其他条件.

例如:

#HotIf WinActive("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."

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

您可以通过编写一个表达式来定义条件, 每当您按下热键时, 该表达式都会被求值. 如果表达式的计算结果为 true, 则执行热键的操作.

通过为热键的每次出现或每个 热键变体 指定不同的条件, 同一热键可以使用多次. 当您按下热键时, 程序将执行满足条件的第一个热键变体, 或没有条件的热键变体(例如上面示例中的最终的 #c::).

如果不满足热键的条件, 并且热键没有无条件的变体, 则按键将传递到活动窗口, 就好像一开始就没有定义热键一样. 例如, 如果在运行上述示例时, Notepad 未处于 活动状态, 则 Ctrl+A 将执行其正常功能(可能是全选).

尝试对示例进行以下更改:

  • 将 WinActive 替换为 WinExist, 以便在记事本正在运行时激活热键, 即使记事本没有焦点也是如此.
  • 将条件替换为 GetKeyState("CapsLock", "T") 以便热键仅在 CapsLock 打开时激活.
  • 为其他窗口添加另一个 ^a 或 #c 热键, 例如您的 Web 浏览器或编辑器. 请注意, 我们使用 ahk_class 以便该示例适用于非英语系统, 但如果您需要, 您可以将其删除并使用窗口的标题.

正确识别您希望热键影响的窗口有时需要使用窗口标题以外的条件. 有关详情, 请参阅如何管理窗口.

相关: #HotIf, 表达式, WinActive

自定义组合

自定义组合 是一个热键, 它将两个通常不用于组合的键组合在一起. 例如, Numpad0 & Numpad1:: 定义了一个热键, 当你按住 Numpad0 并按下 Numpad1 时激活.

当您在自定义组合中使用一个键作为前缀时, AutoHotkey 假定您不希望激活该键的正常功能, 因为这将干扰它作为修饰键的使用. 有两种方法可以恢复按键的正常功能:

  1. 使用另一个热键, 如 Numpad0::Send "{Numpad0}" 来复制该键的原始功能. 默认情况下, 热键只有在你 释放 Numpad0 时才会激活, 而且只有在你没有同时按下 Numpad0 和 Numpad1 时才会激活.
  2. 在组合的前缀中加上波浪号(~), 如 ~Numpad0 & Numpad1::. 这可以防止 AutoHotkey 抑制 Numpad0 的正常功能, 除非你也定义了 Numpad0::, 在这种情况下, 波浪号允许后者的热键立即激活, 而不是当你释放 Numpad0 时.

注意: 自定义组合只支持两个键/鼠标按钮的组合, 不能与其他修饰符组合, 如 !#^+ 代表的 Alt, Win, Ctrl 和 Shift.

虽然 AutoHotkey 不能直接支持两个以上键的自定义组合, 但使用 #HotIf 也可以实现类似的结果. 如果你运行下面的例子, 按下 Ctrl+CapsLock+Space 或 Ctrl+Space+CapsLock 应该显示一条消息:

#HotIf GetKeyState("Ctrl")
Space & CapsLock::
CapsLock & Space::MsgBox "Success!"

在本例中, 有必要先按 Ctrl. 这样做的好处是, 如果你不按住 Ctrl, Space 和 CapsLock 会执行他们正常的功能.

相关: 自定义组合键

其他功能

AutoHotkey 的热键还有其他一些值得探索的功能. 虽然大多数应用程序都局限于组合 Ctrl, Alt, Shift, Win 与另一个键(通常不是键盘上的所有键都被支持), AutoHotkey 没有那么多限制. 如需进一步阅读, 请参阅热键.


#ClipboardTimeout - 语法 & 使用 | AutoHotkey v2

#ClipboardTimeout

更改首次尝试访问剪贴板失败后脚本继续尝试访问剪贴板的时间.

#ClipboardTimeout Milliseconds

参数

Milliseconds

类型: 整数

间隔长度, 以毫秒为单位. 指定 -1 表示持续访问剪贴板. 指定 0 表示只访问一次.

备注

如果在脚本中未指定此指令, 它将表现为设置为 1000 (毫秒).

一些应用程序让剪贴板长时间保持打开, 可能是要读写大量数据. 此时, 增加此设置的值会导致脚本在放弃和显示错误消息之前等待更长时间.

此设置适用于所有的剪贴板操作, 最简单的例子如下: Var := A_Clipboard 和 A_Clipboard := "New Text".

每当脚本在等待剪贴板变为可用时, 不能 启动新的线程并且计时器也不会运行. 但是, 如果用户按下了热键, 选择了自定义菜单项, 或执行 GUI 动作(如, 按下按钮), 这些事件会被缓冲至后面; 换句话说, 其子程序会在剪贴板变得可用后执行.

如果第一次尝试失败, 此指令 不会 导致重新尝试读取剪贴板数据.

和其他指令一样, #ClipboardTimeout 不能有条件地执行.

相关

A_Clipboard, Thread

示例

使脚本在放弃访问剪贴板并显示错误消息之前, 等待 2 秒而不是 1 秒.

#ClipboardTimeout 2000


#DllLoad - 语法 & 使用 | AutoHotkey v2

#DllLoad

在脚本开始执行之前加载 DLL 或 EXE 文件.

#DllLoad FileOrDirName

参数

FileOrDirName

类型: 字符串

文件或目录的路径, 如下所述. 不得 包含双引号(除了参数周围的一对可选双引号), 通配符(* 和 ?) 或除分号(`;) 外的转义序列.

内置变量可以用百分号括起来(例如, #DllLoad "%A_ScriptDir%"). 不属于有效变量引用的百分号按原义解释. 除了 A_Args 和内置类外, 所有内置变量都是有效的.

已知限制: 当编译脚本时, 变量由编译器计算, 结果可能与脚本最终执行时的返回值不同. 支持以下变量: A_AhkPath, A_AppData, A_AppDataCommon, A_ComputerName, A_ComSpec, A_Desktop, A_DesktopCommon, A_IsCompiled, A_LineFile, A_MyDocuments, A_ProgramFiles, A_Programs, A_ProgramsCommon, A_ScriptDir, A_ScriptFullPath, A_ScriptName, A_Space, A_StartMenu, A_StartMenuCommon, A_Startup, A_StartupCommon, A_Tab, A_Temp, A_UserName, A_WinDir.

文件: 要加载的 DLL 或 EXE 文件的绝对或相对路径. 如果指定了一个相对路径, 指令将使用与系统函数 LoadLibraryW 相同的搜索策略来搜索文件. 注意: SetWorkingDir 对 #DllLoad 没有影响, 因为 #DllLoad 是在脚本开始执行之前处理的.

目录: 指定目录而不是文件, 以改变随后出现的 #DllLoad 的搜索策略, 其不再需要指定 DLL 或 EXE 的绝对路径. 新的搜索策略与将 Directory 传递给系统函数 SetDllDirectoryW 相同. 如果省略此参数, 则恢复默认的搜索策略.

注意: 这个参数不是一个表达式, 但可以用引号括起来(可以是 '单引号' 或 "双引号").

备注

一旦 DLL 或 EXE 已由该指令加载, 它不能通过调用系统的函数 FreeLibrary 卸载. 当脚本终止时, 所有加载的文件都会自动卸载.

文件路径前面可以有选择地使用 *i 和一个空格, 这将导致程序忽略加载文件的任何失败. 只有当脚本在失败的情况下仍然能够执行时, 才应该使用这个选项, 例如, 如果 DLL 或 EXE 是非必要的, 或者如果脚本被设计为检测失败, 例如:

#DllLoad "*i MyDLL"
if !DllCall("GetModuleHandle", "str", "MyDLL")
    MsgBox "Failed to load MyDLL!"

如果 FileOrDirName 参数指定了一个没有路径的 DLL 名称, 并且文件名扩展名被省略, 则 .dll 将追加到文件名. 为了防止这种情况, 请在文件名后加上句点(.).

和其他指令一样, #DllLoad 不能有条件地执行.

相关

DllCall

示例

在脚本开始执行之前, 加载位于当前用户 "我的文档" 文件夹中的 DLL 文件.

#DllLoad "%A_MyDocuments%\MyDLL.dll"


#ErrorStdOut - 语法 & 使用 | AutoHotkey v2

#ErrorStdOut

把任何阻止脚本运行的语法错误发送到标准错误(stderr), 而不是显示一个对话框.

#ErrorStdOut Encoding

参数

Encoding

类型: 字符串

如果省略, 它默认为 CP0(系统默认的 ANSI 代码页). 否则, 请指定编码字符串指示如何对输出进行编码. 例如, #ErrorStdOut UTF-8 将错误信息编码为 UTF-8 然后再发送到 stderr. 无论捕获输出的程序是什么, 都必须支持 UTF-8, 并且在某些情况下可能需要配置为期望 UTF-8.

注意: 这个参数不是一个表达式, 但可以用引号括起来(可以是 '单引号' 或 "双引号").

备注

如果脚本中没有指定该指令, 则会在对话框中显示语法错误.

错误被写入 stderr, 而不是 stdout. 命令行和高级编辑器往往会同时显示这些信息.

这个指令可以让诸如 TextPad, SciTE, Crimson 和 EditPlus 这些高级编辑器在语法错误发生时跳到有问题的行. 由于必须将 #ErrorStdOut 指令添加到脚本中, 所以通常最好设置编辑器使用命令行开关 /ErrorStdOut 来启动任何 AutoHotkey 脚本(详情请参阅下面的设置说明).

因为 AutoHotkey 不是控制台程序, 所以错误将不会直接出现在命令行中. 这可以通过以下方法解决 1) 使用 Ahk2Exe ConsoleApp 指令编译脚本, 或 2) 通过管道或重定向捕获脚本的输出. 例如:

"C:\Program Files\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "My Script.ahk" 2>&1 |more
"C:\Program Files\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "My Script.ahk" 2>"Syntax-Error Log.txt"

你还可以使用操作系统内置的 clip 命令将输出直接管道传输到剪贴板. 例如:

"C:\Program Files\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "My Script.ahk" 2>&1 |clip

注意: 2>&1 将 stderr 重定向到 stdout, 而 2>Filename 只将 stderr 重定向到一个文件.

和其他指令一样, #ErrorStdOut 不能有条件地执行.

特定编辑器的设置说明

EditPlus:

  1. 在菜单栏选择 Tools(工具) > Configure User Tools(配置用户工具).
  2. 点击按钮: Add Tool(添加) > Program(应用程序)
  3. Menu Text(菜单文本): 你自己填写
  4. Command(命令): C:\Program Files\AutoHotkey\AutoHotkey.exe
  5. Argument(参数): /ErrorStdOut "$(FilePath)"
  6. Initial directory(初始目录): $(FileDir)
  7. Capture output(捕获输出): Yes

TextPad:

  1. 在菜单栏选择 Configure > Preferences.
  2. 展开 Tools(工具) 菜单.
  3. 点击 Add 按钮然后选择 "Program".
  4. 复制并粘贴(调整为您的 cmd.exe 路径): C:\Windows\System32\cmd.exe -- 然后点击 OK.
  5. 三击列表框中新添加的项(cmd.exe) 并将其重命名为您选择的自定义名称(如 Launch Script).
  6. 点击 Apply.
  7. 从左侧树列表中选择新增的项, 然后填写下列信息:
  8. Command(应该已经填好): cmd.exe(或者是它的完整路径)
  9. Parameters(调整为您的 AutoHotkey.exe 路径): /c ""C:\Program Files\AutoHotkey\AutoHotkey.exe" /ErrorStdOut "$File""
  10. Initial folder: $FileDir
  11. 选择下列框: 1) Run minimized; 2) Capture output.
  12. 点击 OK. 新添加的项就应该已经出现在 Tools 菜单中了.

相关

FileAppend(因为它也可以发送文本到 stderr 或 stdout)

示例

发送任何阻止脚本启动的语法错误到 stderr, 而不是显示一个对话框.

#ErrorStdOut


#HotIf - 语法 & 使用 | AutoHotkey v2

#HotIf

创建上下文相关的热键和热字串. 它们会根据表达式的结果执行不同的操作(或什么都不做).

#HotIf Expression

参数

Expression

类型: 布尔值

如果省略. 则随后创建的热键和热字串与上下文不相关. 否则, 请指定任何有效的表达式. 这将成为隐式函数的返回值, 该函数有一个参数(ThisHotkey). 该函数不能直接修改全局变量(因为它通常是假定-局部函数, 而且不能包含声明), 但可以调用其他函数来修改全局变量.

基本操作

#HotIf 指令设置表达式, 随后创建的热键和热字串将使用该表达式来确定是否应该激活它们. 当按下热键, 鼠标按钮或组合键, 或热字串缩写被键入 或者在程序需要知道热键或热字串是否处于活动状态时, 将对该表达式求值.

要生成上下文敏感的热键和热字串, 只需在它们前面加上 #HotIf 指令. 例如:

#HotIf WinActive("ahk_class Notepad") or WinActive(MyWindowTitle)
#Space::MsgBox "You pressed Win+Spacebar in Notepad or " MyWindowTitle
:X:btw::MsgBox "You typed btw in Notepad or " MyWindowTitle

#HotIf 指令是与位置相关的: 它会影响脚本中在它后面的所有热键和热字串, 直到下一个 #HotIf 指令.

注意: 与 if 语句不同, 大括号对 #HotIf 指令无效.

#HotIf 指令只影响通过双冒号语法创建的热键和热字串, 如 ^!c:: 或 ::btw::. 对于通过 Hotkey 或 Hotstring 函数创建的热键和热字串, 请使用 HotIf 函数.

要关闭热键的上下文相关性, 请指定不带任何表达式的 #HotIf 指令. 例如:

#HotIf

和其他指令一样, #HotIf 不能有条件地执行.

当通过 #HotIf 禁用鼠标或键盘热键时, 它会执行其原来的功能; 也就是说, 它传递到活动窗口, 就好像不存在热键一样. 但有一个例外: 控制器热键: 尽管 #HotIf 有效, 它始终不会阻止其他程序看到控制器按钮按下.

#HotIf 也可以用来改变普通按键(例如 Enter 或 Space) 的行为. 当某个特定窗口忽略该键或执行某些您认为不需要的操作时, 这是非常有用的. 例如:

#HotIf WinActive("Reminders ahk_class #32770")  ; Outlook 中的 "reminders" 窗口.
Enter::Send "!o"  ; 按下 "Enter" 打开 reminder, 而不是 snoozing.
#HotIf

变体(副本)

一个特定的热键或热字串在脚本中可以被创建多次, 如果每个定义有不同的 HotIf 条件. 这被称为 热键变体 或 热字串变体. 例如:

#HotIf WinActive("ahk_class Notepad")
^!c::MsgBox "You pressed Control+Alt+C in Notepad."
#HotIf WinActive("ahk_class WordPadClass")
^!c::MsgBox "You pressed Control+Alt+C in WordPad."
#HotIf
^!c::MsgBox "You pressed Control+Alt+C in a window other than Notepad/WordPad."

如果有多个变体符合触发条件, 那么仅触发最早创建的那个. 这种情况的例外是全局变体(不带 HotIf 条件的那个): 它的优先级总是最低的, 仅当其他变体都不触发时它才会被触发(此例外不适用热字串).

创建重复热键时, 修饰符的顺序(如 ^!+#) 没有关系. 例如, ^!c 等同于 !^c. 但是, 按键必须拼写一致. 例如, 为了这个目的时, Esc 不同于 Escape(尽管大小写无关). 最后, 任何带有通配符前缀(*) 的热键和不带通配符的热键是完全独立的; 例如, *F1 和 F1 都可以有他们各自的变体.

窗口组可以用来使热键或热字串为一组窗口执行. 例如:

GroupAdd "MyGroup", "ahk_class Notepad"
GroupAdd "MyGroup", "ahk_class WordPadClass"

#HotIf WinActive("ahk_group MyGroup")
#z::MsgBox "You pressed Win+Z in either Notepad or WordPad."

另外, 也可以通过 #HotIf WinActive("ahk_group MyGroup") 来使用窗口组.

要动态地创建热键或热字串变体(当脚本运行时), 请参阅 HotIf.

表达式的计算

当热键的按键, 鼠标或控制器按钮组合被按下或热字串缩写被输入时, #HotIf 表达式被计算以确定热或热字串键是否应该被激活.

注意: 脚本不应假定表达式只在热键的按键被按下时才被计算(见下文).

只要程序需要知道热键是否被激活, 表达式也可以被计算. 例如, #HotIf 表达式作用于一个自定义组合热键(如 a & b::), 当按下前缀按键(这个例子中的 a) 时, 表达式将会计算一次, 计算结果将决定组合热键是否起作用.

注意: 使用 #HotIf 时, 在脚本无响应时可能会导致输入滞后或破坏热键或热字串(见下文).

对于 #HotIf 指令还有一些注意事项:

  • 键盘或鼠标输入通常被缓冲(延迟), 直到表达式计算完成或超时.
  • 表达式的计算只能由脚本的主线程(在操作系统级别, 而不是准线程), 而不是由键盘/鼠标钩子直接执行. 如果脚本忙或者没有响应, 比如在进程中出现了 FileCopy, 那么表达式的计算就会被延迟, 并且可能会超时.
  • 如果达到系统定义的超时, 系统可能会停止通知脚本键盘或鼠标输入(有关详情, 请参阅 #HotIfTimeout).
  • 在计算表达式时, 发送击键或鼠标单击(例如, 从它调用的函数中), 可能会导致并发, 应该避免.

ThisHotkey, A_ThisHotkey 和 A_TimeSinceThisHotkey 是基于当前正在计算的 #HotIf 表达式的热键或非自动替换的热字串来设置的.

A_PriorHotkey 和 A_TimeSincePriorHotkey 暂时包含对应 "This" 变量的前一个值.

优化

为避免对 WinActive 或 WinExist 的简单调用而去计算表达式, 对 #HotIf 进行了优化, 从而降低了在这种情况下出现滞后或其他问题的风险. 具体来说:

  • 表达式必须包含一次对 WinExist 或 WinActive 的调用.
  • 每个参数必须是一个单引号的字符串, 并且不得使用超过两个参数.
  • 结果可以用 not 或 ! 进行反转, 但不能使用其他运算符.
  • 当表达式被预编译时, 空白和括号会被完全处理, 因此不会影响这种优化.

如果表达式符合这些条件, 则直接由程序计算, 不会出现在 ListLines 中.

在使用热键 或 Hotstring 函数修改现有的热键或热字串变体之前, 通常 HotIf 函数必须与原始表达式文本一起使用. 然而, 第一个具有给定组合条件的唯一表达式也可以被该条件引用. 例如:

HotIfWinExist "ahk_class Notepad"
Hotkey "#n", "Off"  ; 关闭热键.
HotIf 'WinExist("ahk_class Notepad")'
Hotkey "#n", "On"   ; 打开同一个热键.

#HotIf WinExist("ahk_class Notepad")
#n::WinActivate

注意, 任何变量的使用都会取消表达式的资格. 如果在创建热键或热字串后, 变量的值永远不会改变, 有两种策略可以最大限度地降低 #HotIf 的滞后风险或其他固有问题:

  • 使用 HotIfWin...(MyTitleVar) 来设置条件和 Hotkey(KeyName, Action) or Hotstring(String, Replacement) 来创建热键或热字串变体.
  • 使用常量表达式, 如 #HotIf WinActive("ahk_group MyGroup") 和并在脚本的其他地方使用 GroupAdd "MyGroup", MyTitleVar 定义窗口组.

备注

适当的时候, #HotIf 也会将前缀键恢复到它们的原生功能(如 a & b, 前缀键是热键中的 A). 当给定的前缀键没有启用热键时, 就会发生这种情况.

当 Gosub 或 Goto 用于跳转到一个热键或热字符串标签时, 它会跳转到最接近脚本顶部的变体.

当前被 #HotIf 禁用的热键, 它的按键或鼠标按钮在 KeyHistory 的 "Type" 列中显示时会带有 "#" 字符. 这可以帮助调试脚本.

Alt-tab 热键不受 #HotIf 影响: 它们对所有窗口都有效.

最后找到的窗口可以通过 #HotIf 来设置. 例如:

#HotIf WinExist("ahk_class Notepad")
#n::WinActivate  ; 激活由 WinExist() 找到的窗口.

相关

#HotIfTimeout 可以用于覆盖默认的超时时间值.

Hotkey 函数, 热键, Hotstring function, 热字串, Suspend, WinActive, WinExist, SetTitleMatchMode, DetectHiddenWindows

示例

创建只有在记事本处于活动状态时才生效的两个热键和一个热字符串, 而一个热键则适用于除记事本以外的任何窗口.

#HotIf WinActive("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.
#HotIf
#c::MsgBox "You pressed Win-C in a window other than Notepad."

允许在任务栏上滚动鼠标滚轮来调节音量.

#HotIf MouseIsOver("ahk_class Shell_TrayWnd")
WheelUp::Send "{Volume_Up}"
WheelDown::Send "{Volume_Down}"

MouseIsOver(WinTitle) {
    MouseGetPos ,, &Win
    return WinExist(WinTitle " ahk_id " Win)
}

在所有的编辑控件中的轻松删除单词的快捷键.

#HotIf ActiveControlIsOfClass("Edit")
^BS::Send "^+{Left}{Del}"
^Del::Send "^+{Right}{Del}"

ActiveControlIsOfClass(Cls) {
    FocusedControl := 0
    try FocusedControl := ControlGetFocus("A")
    FocusedControlClass := ""
    try FocusedControlClass := WinGetClass(FocusedControl)
    return (FocusedControlClass=Cls)
}

与上下文不相关的热键.

#HotIf
Esc::ExitApp

动态热键. 这个例子在运行前需要整和示例 #2.

NumpadAdd::
{
    static toggle := false
    HotIf 'MouseIsOver("ahk_class Shell_TrayWnd")'
    if (toggle := !toggle)
        Hotkey "WheelUp", DoubleUp
    else
        Hotkey "WheelUp", "WheelUp"
    return
    ; 嵌套函数:
    DoubleUp(ThisHotkey) => Send("{Volume_Up 2}")
}


#HotIfTimeout - 语法 & 使用 | AutoHotkey v2

#HotIfTimeout

设置计算单个 #HotIf 表达式可以使用的最大时间.

#HotIfTimeout Timeout

参数

Timeout

类型: 整数

全局有效的超时值, 单位为毫秒(ms).

备注

如果在脚本中未指定此指令, 则它的行为就像设置为 1000 (毫秒) 一样.

设置超时时间是为了防止表达式计算时间过长从而延迟了键盘输入. 如果超过了设定的超时值, 表达式会继续计算, 但键盘钩子将假定表达式结果为假而继续执行.

如果脚本中未使用此指令, 那么程序会默认设置为 1000.

注意系统使用它自己的超时时间, 系统超时值由以下注册表项中的 DWORD 类型值 LowLevelHooksTimeout 定义:

HKEY_CURRENT_USER\Control Panel\Desktop

如果超过了系统的超时时间, 那么系统可能会停止调用脚本的键盘钩子, 从而阻止钩子热键工作, 直到键盘钩子重新注册或脚本重新加载. 钩子 通常 可以通过挂起或取消挂起所有热键来重新注册.

微软的文档中关于超时的细节是不清楚的, 但是研究表明 Windows 7 和更高版本的情况是这样的: 如果没有定义 LowLevelHooksTimeout, 默认的超时时间是 300 ms. 钩子最多可以超时 10 次, 但如果超时第 11 次, 则会被自动移除.

如果一个给定的热键具有多个 #HotIf 变体, 超时可能会独立地应用到每个变体, 从而更有可能导致系统超时被超过. 这种情况可能会在以后的版本中进行修改.

和其他指令一样, #HotIfTimeout 不能有条件地执行.

相关

#HotIf

示例

将 #HotIf 超时设置为 10 ms, 而不是 1000 ms.

#HotIfTimeout 10


#Hotstring - 语法 & 使用 | AutoHotkey v2

#Hotstring

改变热字串的选项或终止符.

#Hotstring NoMouse
#Hotstring EndChars NewChars
#Hotstring NewOptions

参数

NoMouse

类型: 字符串

阻止鼠标点击重置热字串识别器, 如这里描述. 副作用是, 这样也阻止了热字串需要的鼠标钩子(尽管如果脚本因其他目的(如鼠标热键) 需要鼠标钩子, 它仍然会被安装). 在脚本的任意位置使用 #Hotstring NoMouse 会影响所有的热字串, 而不只是影响在它后面的那些.

EndChars NewChars

类型: 字符串

指定单词 EndChars 后跟着单个空格和新的终止符. 例如:

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

由于新的结束字符在整个脚本中都是全局有效的 -- 不管 EndChars 指令出现在哪里 -- 所以不需要多次指定 EndChars.

结束符的最大数目是 100. 超出此长度的字符被忽略.

要使制表符或空格符成为终止符, 请在列表中包含 `t 或 `s.

NewOptions

类型: 字符串

指定新选项, 如 Hotstring 选项中描述的那样. 例如: #Hotstring r s k0 c0.

与上面的 EndChars 不同, 当以这种方式使用时, #Hotstring 指令是与位置有关的. 换句话说, 脚本中的多个热字串可以具有不同的默认选项, 如下例所示:

::btw::by the way

#Hotstring r c  ; 后面的所有热字串会使用 "send raw" 且默认区分大小写.
::al::airline
::CEO::Chief Executive Officer

#Hotstring c0  ; 让从这里往后的所有热字串不区分大小写.

备注

和其他指令一样, #Hotstring 不能有条件地执行.

相关

热字串

当脚本运行时, 可以使用 Hotstring 函数更改热字串选项.


#Include / #IncludeAgain - 语法 & 使用 | AutoHotkey v2

#Include / #IncludeAgain

使脚本的行为与指定文件的内容位于此确切位置一样.

#Include FileOrDirName
#Include <LibName>
#IncludeAgain FileOrDirName

参数

FileOrDirName

类型: 字符串

文件或目录的路径, 如下所述. 不能 包含双引号(除了参数周围的一对可选的双引号之外), 通配符(* 和 ?) 或除分号(`;) 外的转义序列.

内置变量以通过将其括在百分号中来使用(例如, #Include "%A_ScriptDir%"). 不属于有效变量引用的百分号按原义解释. 所有包含字符串或数字的内置变量都是有效的.

已知限制: 编译脚本时, 变量由编译器计算, 并且可能与脚本最终执行时返回的值不同. 编译器支持以下变量: A_AhkPath, A_AppData, A_AppDataCommon, A_ComputerName, A_ComSpec, A_Desktop, A_DesktopCommon, A_IsCompiled, A_LineFile, A_MyDocuments, A_ProgramFiles, A_Programs, A_ProgramsCommon, A_ScriptDir, A_ScriptFullPath, A_ScriptName, A_Space, A_StartMenu, A_StartMenuCommon, A_Startup, A_StartupCommon, A_Tab, A_Temp, A_UserName, A_WinDir.

File: 要包含的文件的名称. 默认情况下, 相对路径是相对于包含 #Include 指令的文件目录的. 这个默认值可以通过使用下面描述的 #Include Dir 来覆盖. 注意: SetWorkingDir 对 #Include 没有效果, 因为 #Include 是在脚本开始执行之前处理的.

Directory: 指定目录而不是文件, 以更改当前文件中所有后续出现的 #Include 和 FileInstall 所使用的工作目录. 注意: 以这种方式更改工作目录不会影响脚本开始运行时的初始工作目录(A_WorkingDir). 要改变这一点, 请在脚本的顶部使用 SetWorkingDir.

注意: 这个参数不是一个表达式, 但可以用引号括起来(可以是 '单引号' 或 "双引号").

<LibName>

类型: 字符串

库文件或函数的名称. 例如, #Include <lib> 和 #Include <lib_func> 都会包含某个库文件夹中的 lib.ahk. 不允许变量引用.

可以指定子目录, 但需要注意的是, 第一个下划线可能被解释为脚本库文件夹下描述的分隔符, 例如, 如果没有找到 a_b\c.ahk, #Include <a_b\c> 将尝试 a.ahk.

备注

脚本表现得好像包含文件的内容实际出现在 #Include 指令的确切位置(就好像从包含的文件中复制粘贴过来一样). 因此, 它通常不能把两个孤立的脚本合并成一个可运行的脚本.

#Include 仅确保包含指定文件一次, 即使遇到多次重复的包含也是如此. 与之相比, #IncludeAgain 允许同一文件的多次包含, 而在所有其他方面与 #Include 相同.

可以在文件路径前加上 *i 和单个空格, 这会使程序忽略读取包含文件的任何失败. 例如: #Include "*i SpecialOptions.ahk". 此选项应该仅在包含的文件的内容对主脚本的操作可有可无的情况下才使用.

通过 ListLines 或菜单 View->Lines 在主窗口显示的行总是按照它们在自己的文件中的物理顺序进行编号的. 换句话说, 包含一个新文件将只改变主脚本文件那一行的编号, 即 #Include 行本身的行号(编译后的脚本除外, 它会在编译时把它们包含的文件合并成一个大的脚本).

#Include 常用来加载在外部文件中定义的函数.

和其他指令一样, 不能根据条件执行 #Include. 换句话说, 这个例子不会像预期的那样工作:

if (x = 1)
    #Include "SomeFile.ahk"  ; 不管 x 的值是什么此行都会执行.

相关

脚本库文件夹, 函数, FileInstall

示例

将指定文件的内容包含到当前脚本中.

#Include "C:\My Documents\Scripts\Utility Subroutines.ahk"

改变后续 #Includes 和 FileInstalls 的工作目录.

#Include "%A_ScriptDir%"

和上面一样, 但是使用显示命名的目录.

#Include "C:\My Scripts"


#InputLevel - 语法 & 使用 | AutoHotkey v2

#InputLevel

控制热键和热字串是否忽略模拟的键盘和鼠标事件.

#InputLevel Level

参数

Level

类型: 整数

如果省略, 则默认为 0. 否则, 指定一个介于 0 和 100 之间的整数.

备注

如果在脚本中未指定此指令, 则它的行为就像设置为 0 一样.

有关如何使用 SendLevel 和 #InputLevel 的说明, 请参阅 SendLevel.

此指令是与位置有关的: 它会作用于在它到下一个 #InputLevel 指令之间的所有热键和热字串. 如果未指定 #InputLevel 指令, 则热键和热字串的默认级别为 0.

热键的输入级别还可以用 Hotkey 函数来设置. 例如: Hotkey "#z", my_hotkey_sub, "I1"

热键或非自动替换型热字串的输入级别同时也作为由此热键或热字串生成的任何键击或按钮点击的默认发送级别. 因为键盘或鼠标重映射实际上是一对热键, 这样就可通过 #InputLevel 来让重映射触发其他热键.

早于 v1.1.06 的 AutoHotkey 版本会表现得就像 #InputLevel 0 和 SendLevel 0 那样.

和其他指令一样, #InputLevel 不能有条件地执行.

相关

SendLevel, 热键, 热字串

示例

使第一个热键 *Numpad0:: 触发第二个热键 ~LButton::. 如果省略或注释掉 #InputLevel 指令, 则不会出现这种情况.

#InputLevel 1
; 使用 SendEvent 可以触发脚本自己的热键.
*Numpad0::SendEvent "{Blind}{Click Down}"
*Numpad0 up::SendEvent "{Blind}{Click Up}"
#InputLevel 0
; Numpad0 或 LButton 都可以触发此热键:
~LButton::MsgBox "Clicked"


#MaxThreads - 语法 & 使用 | AutoHotkey v2

#MaxThreads

设置可同时存在的线程的最大数目.

#MaxThreads Value

参数

Value

类型: 整数

可以同时存在的线程的最大数量. 指定大于 255 的数字等同于指定 255.

备注

如果脚本中未使用此指令, 那么它会表现的就像此设置为 10 那样.

这个设置是全局的, 这意味着只需要指定一次(在脚本的任何位置) 就可以影响整个脚本的行为.

尽管可以把这个值设置为 1, 但不建议这么做, 因为每当脚本显示消息框或其他对话框时, 会阻止新的热键运行. 在其他线程休眠或等待时, 还会阻止计时器运行.

无论存在多少线程, OnExit 回调函数始终会被启动.

如果此设置小于 #MaxThreadsPerHotkey, 那么它会覆盖那个设置.

和其他指令一样, #MaxThreads 不能有条件地执行.

相关

#MaxThreadsPerHotkey, 线程, A_MaxHotkeysPerInterval, ListHotkeys

示例

允许最多 2 个而不是 10 个线程同时运行.

#MaxThreads 2


#MaxThreadsBuffer - 语法 & 使用 | AutoHotkey v2

#MaxThreadsBuffer

当某些或所有的热键达到 #MaxThreadsPerHotkey 限制时, 这个指令让它们缓冲而不是忽略键击.

#MaxThreadsBuffer Setting

参数

Setting

类型: 字符串或整数

如果省略, 则默认为 True. 否则, 指定以下值之一:

True 或 1: 从这里到下一个 #MaxThreadsBuffer False 指令间的所有热键子程序在它们的子程序数目达到 #MaxThreadsPerHotkey 限制时会缓存而不是忽略它们热键的键击.

False 或 0: 当运行的热键线程数已经达到最大数目(通常为 1, 不过可通过 #MaxThreadsPerHotkey 改变) 时, 热键的键击会被忽略.

备注

如果在脚本中未指定此指令, 则它的行为就像设置为 False 一样.

很少使用此指令, 因为这种类型的缓冲通常都弊大于利. 例如, 此设置为 ON 时, 如果您不小心按了两次热键, 会使该热键的子例程在其第一个线程完成时间少于 1 秒的情况下自动运行第二次(根据设计, 此类缓冲将在 1 秒后过期). 注意 AutoHotkey 中有多种其他方法可以缓冲热键(例如 Thread Interrupt 和 Critical). 只是这种特殊的方法可能是有害的, 所以默认设置为 OFF.

此指令主要用于增加键盘自动重复功能的响应性. 例如, 当您按下一个 #MaxThreadsPerHotkey 设置为 1(默认) 的热键时, 如果此热键的子程序正在运行中, 那么传入的键击会被忽略. 因此, 从子程序结束到下一次自动重复键击传入, 它可能需要等待 50 ms 或更多时间, 因为这是捕获到自动重复循环的键击的间隔. 为任何需要最好响应性的自动重复热键启用此指令可以避免这 50 ms 的延迟.

和所有的 # 指令一样, 这个指令不应该像函数那样放在脚本中(即它不需要被包含在子程序中). 相反, 应该把它放在您希望影响的首个热键之前.

和其他指令一样, #MaxThreadsBuffer 不能有条件地执行.

相关

#MaxThreads, #MaxThreadsPerHotkey, Critical, Thread (函数), 线程, Hotkey, A_MaxHotkeysPerInterval, #HotkeyInterval, ListHotkeys

示例

当达到 #MaxThreadsPerHotkey 限制时, 会使前两个热键缓冲而不是忽略按键.

#MaxThreadsBuffer True
#x::MsgBox "This hotkey will use this type of buffering."
#y::MsgBox "And this one too."
#MaxThreadsBuffer False
#z::MsgBox "But not this one."


#MaxThreadsPerHotkey - 语法 & 使用 | AutoHotkey v2

#MaxThreadsPerHotkey

设置每个热键或热字串可同时存在的最大线程数.

#MaxThreadsPerHotkey Value

参数

Value

类型: 整数

给定热键/热字串子例程可以启动的最大线程数(限制 255).

备注

如果脚本中未指定此指令, 则其行为就像设置为 1 一样.

此设置用于控制允许同时存在多少给定热键或热字串子例程的 "实例". 例如, 如果一个热键的最大线程数为 1, 并且在其子例程已经运行时再次按下该键, 则该键将被忽略. 这有助于防止意外按下两次. 但是, 如果您希望缓冲这些按键而不是忽略这些按键 -- 可能要增加键盘自动重复功能的响应性 -- 请使用 #MaxThreadsBuffer.

与 #MaxThreads 不同, 此设置 不是 全局的. 而是将其放置在您希望受到其影响的第一个热键之前, 这将导致所有后续的热键都使用该值, 直到遇到该指令的另一个实例为止.

如果 #MaxThreads 设置的值低于此设置, 则其优先.

和其他指令一样, #MaxThreadsPerHotkey 不能有条件地执行.

相关

#MaxThreads, #MaxThreadsBuffer, Critical, 线程, Hotkey, A_MaxHotkeysPerInterval, #HotkeyInterval, ListHotkeys

示例

最多允许 3 个线程同时进行, 而不是每个热键或热字串 1 个.

#MaxThreadsPerHotkey 3


#NoTrayIcon - 语法 & 使用 | AutoHotkey v2

#NoTrayIcon

禁止显示托盘图标.

#NoTrayIcon

在脚本的任何地方指定此参数将防止在启动脚本时显示该脚本的托盘图标(也适用于编译成 EXE 的脚本).

如果您在含热键的脚本中使用此指令, 那么可能需要为 ExitApp 函数绑定一个热键. 否则, 将没有简单的办法退出程序(在不重启计算机或强制关闭进程的情况下). 例如: #x::ExitApp.

托盘图标可以在脚本执行期间的任何时候消失或重新出现, 方法是为 A_IconHidden 赋值 true 或 false. 在脚本顶部使用 A_IconHidden := true 的唯一缺点是, 在脚本首次启动时, 托盘图标可能会短暂可见. 为了避免这种情况, 请使用 #NoTrayIcon.

当托盘图标隐藏时, 内置变量 A_IconHidden 的值为 1, 否则为 0, 并且可以为其赋值以显示或隐藏图标.

和其他指令一样, #NoTrayIcon 不能有条件地执行.

相关

Tray Icon, TraySetIcon, A_IconHidden, A_IconTip, ExitApp

示例

使脚本启动时没有托盘图标.

#NoTrayIcon


#Requires - 语法 & 使用 | AutoHotkey v2

#Requires

如果不符合版本要求, 则显示错误并退出.

#Requires Requirement

参数

Requirement

类型: 字符串

如果不是以单词 "AutoHotkey" 开头, 则显示错误消息并退出程序. 这将保证清晰, 并为将来的使用保留指令. AutoHotkey 的其他分支可能支持其他名称.

否则, 单词 "AutoHotkey" 后面应该跟下列任意组合, 并用空格或制表符分隔:

  • 一个可选的字母 "v" 后面跟着一个版本号. A_AhkVersion 必须大于或等于此版本, 但小于下一个主版本.
  • <, <=, >, >= 或 = 中的一个, 后面紧跟着可选的字母 "v" 和版本号. 例如, >=2-rc <2 允许 v2 的候选版本, 但不允许最终版本.
  • 以下单词之一, 用于限制可运行脚本的可执行文件(EXE) 的类型: "32-bit", "64-bit".

错误消息

显示的消息取决于解释该指令的 AutoHotkey 的版本.

对于 v2, AutoHotkey 的路径, 版本和构建总是显示在错误消息中.

如果脚本启动时使用的 AutoHotkey 版本不支持这个指令, 错误信息如下:

Line Text: #Requires %Requirement%
Error: This line does not contain a recognized action.

备注

由启动器在一个系统上使用 v1 和 v2 脚本, 建议您至少为 v1 脚本启动器添加 #Requires AutoHotkey v1, 而为 v2 脚本添加 #Requires AutoHotkey v2. 这将确保使用正确的版本来运行脚本.

如果脚本使用了在早期版本中不可用的语法或函数, 使用这条指令可以确保错误信息显示未满足的要求, 而不是显示任意的语法错误. 这不能用 if (A_AhkVersion <= "1.1.33") 这样的指令来做, 因为在脚本的其他地方出现语法错误会使脚本无法执行.

当分享一个脚本或在网上发布代码时, 使用这个指令可以让任何发现代码的人很容易地识别出它是为哪个版本的 AutoHotkey 准备的.

其他程序或脚本可以出于各种目的检查这个指令. 例如, 安装 AutoHotkey v2 自带的启动器可能会用它来决定启动哪个 AutoHotkey 可执行文件, 而脚本编辑器或相关工具可能会用它来决定如何解释或突出显示脚本文件.

版本字符串是以一系列点分隔的部分进行比较, 后面的连字符和预发布标识符是可选的.

  • 数值部分是以数字来比较的. 例如, v1.01 = v1.1, 但 a20 > a112.
  • 在相同的位置上, 数值部分总是被认为小于非数字部分.
  • 任何缺失的点定界部分都假定为零. 例如, v1.1.33-alpha 等同于 v1.1.33.00-alpha.0.
  • 非数字部分按字母顺序比较, 并区分大小写.
  • 预发布版本被认为比标准版本低. 例如, #Requires AutoHotkey v2 的脚本将不能在 v2.0-a112 上运行. 要允许预发布版本, 请在后缀中加入一个连字符. 例如: v2.0-.
  • 任何以 "+" 开头的后缀将被忽略.

尾部的 "+" 足以向读者表明可以接受更晚的版本, 但不是必须的.

和其他指令一样, #Requires 不能有条件地执行.

相关

#ErrorStdOut, VerCompare

示例

使脚本仅在 v2.0 上运行, 包括测试版.

#Requires AutoHotkey v2.0-a
MsgBox "This script will run only on v2.0, including alpha releases."

使脚本仅在 v2.0(包括预发布版本) 上运行.

#Requires AutoHotkey >=2.0- <2.1

使脚本仅在 64 位解释器(EXE) 下运行.

#Requires AutoHotkey 64-bit

使脚本仅在 64 位解释器(EXE) 2.0-rc 版本或更高版本下运行.

#Requires AutoHotkey v2.0-rc.2 64-bit


#SingleInstance - 语法 & 使用 | AutoHotkey v2

#SingleInstance

确定脚本已在运行时是否允许再次运行.

#SingleInstance ForceIgnorePromptOff

参数

ForceIgnorePromptOff

类型: 字符串

如果省略, 则默认为 Force. 否则, 请指定以下单词之一:

Force: 跳过对话框并自动替换旧实例, 效果类似于 Reload 函数.

Ignore: 跳过对话框并让旧实例继续运行. 换句话说, 试图启动已经运行的脚本会被忽略.

Prompt: 显示一个对话框, 询问是保留旧实例还是用新实例替换它.

Off: 允许一个脚本同时运行多个实例.

备注

如果脚本中未指定此指令, 则它的行为就像设置为 Prompt 一样.

当使用以下命令行开关时, 该指令将被忽略: /force /restart

和其他指令一样, #SingleInstance 不能有条件地执行.

限制

脚本以前的实例是通过搜索带有默认标题的主窗口来识别的. 因此, 在下列情况下, 可能找不到该脚本的先前实例:

  • 其主窗口的标题已经改变.
  • 它运行在不同版本的 AutoHotkey 上.
  • 它的主窗口不再是顶层的, 比如脚本使用 SetParent 把它的父窗口改成 NULL(0) 以外的窗口.

最多只能检测到一个先前的实例, 并向其发送消息要求其关闭. 因此, 以下的额外限制也适用:

  • 如果有多个实例(比如脚本的前几个实例使用了 #SingleInstance Off 模式), 则向最上面的匹配实例发送消息, 而其他实例则不被考虑.
  • 如果之前的实例运行的完整性级别高于新的实例(其中以管理员身份运行 > 以 UI 权限运行 > 正常运行), 由于安全限制, 它不能被关闭.

如果脚本的多个实例同时启动, 它们可能无法检测到彼此, 或者都针对同一个前一个实例. 这将导致脚本的多个实例启动.

相关

Reload

示例

跳过对话框, 自动替换旧实例.

#SingleInstance force


#SuspendExempt - 语法 & 使用 | AutoHotkey v2

#SuspendExempt

豁免后续热键和热字串的挂起.

#SuspendExempt Setting

参数

Setting

类型: 字符串或整数

如果省略, 则默认为 True. 否则, 指定以下原义值之一:

True 或 1 表示允许豁免后续热键.

False 或 0 表示禁用豁免.

备注

如果在脚本中未指定此指令, 则在挂起脚本时禁用所有热键或热字符串, 即使是那些调用 Suspend 函数的热键或热字符串.

可以通过 Suspend 函数, 或托盘图标或主窗口挂起热键和热字符串.

该指令不影响 Hotkey 或 Hotstring 函数, 它们可以使用 S 热键选项或 S 热字串选项来代替.

和其他指令一样, #SuspendExempt 不能有条件地执行.

相关

Suspend, 热键, 热字串

示例

本例中的第一个热键是用来切换暂停的. 为了防止这个热键在开启暂停后被暂停, 从而无法再关闭暂停, 必须将其豁免.

#SuspendExempt  ; 从 Suspend 中豁免以下热键.
#Esc::Suspend -1
#SuspendExempt False  ; 禁用下面任何热键/热字符串的豁免.
^1::MsgBox "This hotkey is affected by Suspend."


#UseHook - 语法 & 使用 | AutoHotkey v2

#UseHook

强制使用钩子实现全部或部分键盘热键.

#UseHook Setting

参数

Setting

类型: 字符串或整数

如果省略, 则默认为 True. 否则, 请指定以下文字值之一:

True 或 1: 将用键盘钩子来实现从这里到下一个 #UseHook False(如果有的话) 之间的所有键盘热键.

False 或 0: 用默认方法实现热键(不能使用 RegisterHotkey() 时, 才使用键盘钩子).

备注

如果没有在脚本中指定该指令, 则它的行为就像设置为 False 一样, 这意味着只要有可能都会用 windows API 函数 RegisterHotkey() 来实现键盘热键. 不过在一些情况下, 如果使用键盘钩子可能响应性更好.

切换此指令为 ON 相当于在每个受影响的热键定义中使用 $ 前缀.

与所有 # 指令一样 -- 只在脚本启动时处理一次 -- #UseHook 不应该像函数那样放在脚本中(即它不需要被包含在子程序中). 相反, 应该把它放在您希望影响的首个热键之前.

默认情况下, 使用键盘钩子的热键不会被 Send 函数的方法触发. 同样地, 鼠标热键也不会被像 Click 这样的内置函数触发, 因为所有的鼠标热键都使用鼠标钩子. 一种解决方法是命名热键的函数, 然后直接调用. 例如: Gosub #LButton.

#InputLevel 和 SendLevel 对 Send 函数是否触发热键和热字串提供了额外的控制功能.

如果脚本中未使用此指令, 那么它会表现的就像此设置为 OFF 那样.

和其他指令一样, #UseHook 不能有条件地执行.

相关

InstallKeybdHook, InstallMouseHook, ListHotkeys, #InputLevel

示例

使前两个热键使用键盘钩子.

#UseHook  ; 强制从这里往后的热键使用键盘钩子.
#x::MsgBox "This hotkey will be implemented with the hook."
#y::MsgBox "And this one too."
#UseHook False
#z::MsgBox "But not this one."


#Warn - 语法 & 使用 | AutoHotkey v2

#Warn

启用或禁用特定条件下的警告, 这些条件可能会产生错误, 例如书写错误或缺少 "全局" 声明.

#Warn WarningType, WarningMode

参数

WarningType

类型: 字符串

如果省略, 则默认为 All. 否则, 请指定要启用或禁用的警告类型.

VarUnset: 在脚本开始运行之前, 为每个从未以下列任何方式使用的变量的第一个引用显示一个警告:

  • 作为一个直接的, 非动态赋值的目标, 如 MyVar := "".
  • 与引用操作符一起使用(例如 &MyVar).
  • 直接传递给 IsSet(例如 IsSet(MyVar)).

LocalSameAsGlobal: 在脚本开始运行之前, 为每个名称与全局变量相同但 未声明 的局部变量显示一个警告. 这是为了防止在试图访问全局变量之前, 忘记在函数中声明全局变量而导致的错误. 如果该变量确实是计划作为局部变量来使用, 那么可以使用诸如 local x 或 static y 这样的声明来抑制该警告.

默认情况下, 这个警告是禁用的.

#Warn
g := 1
ShowG() {       ; 即使从未调用这个函数也会显示警告.
    ;global g   ; <-- 访问全局变量时需要这行.
    g := 2
}
ShowG
MsgBox g  ; 没有声明, 上面赋值的是局部变量 "g".

Unreachable: 在脚本开始运行之前, 对紧跟在同一嵌套层的 Return, Break, Continue, Throw 或 Goto 之后的每一行发出警告, 除非该行是一个标签的目标. 任何这样的行都不会被执行.

如果代码的目的是不可到达的 - 例如, 如果使用 return 暂时禁用一个代码块, 或者通过注释的方式暂时禁用热键或热字符串 - 可以考虑把不可到达的代码也注释掉. 另外, 也可以通过在第一行不可到达的代码上方定义一个标签来抑制警告.

All: 将给定的 WarningMode 应用于所有支持的警告类型.

WarningMode

类型: 字符串

如果省略, 则默认为 MsgBox. 否则, 请指定指示如何传递警告的值.

MsgBox: 显示一个描述警告的消息框. 请注意, 一旦消息框被删除, 脚本将照常继续.

StdOut: 将警告的描述发送到 stdout(程序的标准输出流), 以及文件名和行号. 这允许像 SciTE 这样的高级编辑器在不中断脚本的情况下捕获警告 - 用户可以在以后通过编辑器的输出窗格跳转到每个违规行.

OutputDebug: 将警告的描述发送到调试器上显示. 如果调试器不是活动的, 则没有效果. 有关详情, 请参阅 OutputDebug.

Off: 禁用给定 WarningType 的警告.

备注

如果该指令未在脚本中使用过, 所有的警告都是启用的并且使用 MsgBox 模式, 除了 LocalSameAsGlobal, 它是禁用的.

对产生 VarUnset, LocalSameAsGlobal 和 Unreachable 警告的检查是在所有指令被解析后, 但在脚本执行前进行的. 因此, 在脚本中的位置并不重要(而且, 像其他指令一样, #Warn 不能被有条件地执行).

然而, 多个 #Warn 指令的顺序是很重要的: 最后出现的设置给定警告的指令决定了该警告的模式. 因此, 例如, 下面两个语句的综合效果是启用除 LocalSameAsGlobal 以外的所有警告:

#Warn All
#Warn LocalSameAsGlobal, Off

相关

局部和全局变量

示例

禁用所有警告. 不推荐.

#Warn All, Off

启用每种警告并将它们显示到消息框中.

#Warn

对于每一个与全局变量同名的未声明的局部变量, 向 OutputDebug 发送一个警告.

#Warn UseUnsetLocal, OutputDebug


#WinActivateForce - 语法 & 使用 | AutoHotkey v2

#WinActivateForce

跳过温和的方法而直接使用强制的方法激活窗口.

#WinActivateForce

在脚本中的任何地方指定此项都将导致激活窗口的内置函数 -- 如 WinActivate, WinActivateBottom 和 GroupActivate -- 跳过激活窗口的 "温和" 的方法而直接使用更强制的方法激活窗口.

虽然这个指令通常不会改变窗口被激活的速度和可靠性, 但是它可能会阻止任务栏按钮在不同窗口相继被快速激活时的闪烁.

备注

和其他指令一样, #WinActivateForce 不能有条件地执行.

相关

WinActivate, WinActivateBottom, GroupActivate

示例

启用激活窗口的强制方法.

#WinActivateForce


A_Clipboard - 定义 & 使用 | AutoHotkey v2

A_Clipboard

A_Clipboard 是一个内置变量, 它包含当前 Windows 剪贴板中可以用文本形式表示的内容.

A_Clipboard 中的每行文本通常都是以回车和换行符(CR+LF) 结尾, 它们在脚本中表示为 `r`n. 文件(例如从资源管理器窗口中使用 Ctrl+C 复制的文件) 被视为文本: 每当在脚本中引用 A_Clipboard 时, 它们会被自动转换为它们的文件名(完整路径). 要逐个提取这些文件, 请参照此例:

Loop Parse A_Clipboard, "`n", "`r"
{
    Result := MsgBox("File number " A_Index " is " A_LoopField ".`n`nContinue?",, 4)
    if Result = "No"
        break
}

要按字母顺序排列文件名, 请使用 Sort 函数. 要把剪贴板中的文件名写入到文件中, 请使用 FileAppend A_Clipboard "`r`n", "C:\My File.txt". 要改变脚本持续尝试打开剪贴板的时间 -- 例如另一个程序在使用剪贴板的时候 -- 请使用 #ClipboardTimeout.

ClipWait 可用于检测剪贴板何时包含数据(可选包括非文本数据):

A_Clipboard := ""  ; 先让剪贴板为空, 这样可以使用 ClipWait 检测文本什么时候被复制到剪贴板中.
Send "^c"
ClipWait  ; 等待剪贴板中出现文本.
MsgBox "Control-C copied the following contents to the clipboard:`n`n" A_Clipboard

相关

  • ClipboardAll: 用于操作剪贴板上的所有内容(如图片和格式).
  • OnClipboardChange: 用于检测和响应剪贴板更改.

示例

赋予剪贴板全新的内容.

A_Clipboard := "my text"

清空剪贴板.

A_Clipboard := ""

将任何复制的文件, HTML 或其他格式的文本转换为纯文本.

A_Clipboard := A_Clipboard

追加一些文本到剪贴板.

A_Clipboard .= " Text to append."

把剪贴板中所有 ABC 替换为 DEF(同时把剪贴板的内容转换为纯文本).

A_Clipboard := StrReplace(A_Clipboard, "ABC", "DEF")

使用 AutoHotkey v1 编写的剪贴板实用工具:

  • Deluxe Clipboard: 提供不限数量的私有的命名的剪贴板, 可以用来复制, 剪切, 追加或剪切追加选中的文本.
  • ClipStep: 仅使用键盘上的 Ctrl-X-C-V 控制多个剪贴板.


A_HotkeyModifierTimeout - 语法 & 使用 | AutoHotkey v2

A_HotkeyModifierTimeout

A_HotkeyModifierTimeout 是一个内置变量, 可影响带有 Ctrl, Alt, Win 和 Shift 热键修饰符的 Send 的行为. 具体来说, 它定义了按下热键后, 热键的修饰符按键被认为仍被按住的时间. Send 使用它来决定是否在暂时释放修饰符按键后将其推回原位.

A_HotkeyModifierTimeout 可以用来获取或设置一个整数, 代表以毫秒为单位的时间间隔长度. 如果为 -1, 则永远不会超时(修饰符按键总是在 Send 后被再次按下). 如果为 0, 则始终超时(修饰符按键永远不会被再次按下).

默认设置为 50 毫秒(ms).

备注

此变量在以下情况下无效:

  • 热键通过 SendInput 或 SendPlay 方法发送键击. 这是因为这些方法将用户的物理按键操作和释放延迟到 Send 完成之后.
  • 脚本已经安装了键盘钩子(您可以通过主窗口中的 "View->Key history" 菜单项或 KeyHistory 函数来判断你的脚本是否使用了钩子). 这是因为钩子可以跟踪用户实际按住的修饰键(Alt, Ctrl, Shift 和 Win), 不需要使用超时.

为了说明此指令的效果, 请参考这个例子: ^!a::Send "abc".

执行 Send 函数时, 它会首先释放 Ctrl 和 Alt, 以便正确发送字符. 在发送所有键击后, 此函数不知道它是否可以安全的推回 Ctrl 和 Alt 到按下状态(以匹配用户是否仍然按下它们). 但是, 如果经过的时间少于指定的毫秒数, 则将假定用户尚未有释放键的机会, 因此它将推回它们以使其符合其物理状态. 否则, 修饰键将不会被推回按下状态, 用户必须再次按下它们来修饰同一个或其他的按键.

超时值应设置为小于用户通常在释放热键的修饰键之前按住它们的时间. 否则, 即使用户没有实际按下修饰键, 修饰键也可能恢复到向下位置(保持按下).

在下列情况中您可以减少或不使用此变量:

  • 通过调用 InstallKeybdHook 安装键盘钩子.
  • 使用 SendInput 或 SendPlay 方法而不使用传统的 SendEvent 方法.
  • 使用传统的 SendEvent 方法, 将 SetKeyDelay 减少到 0 或 -1, 这应该会有所帮助, 因为它可以更快地发送击键.

相关

GetKeyState

示例

将热键修饰符超时设置为 100 毫秒, 而不是 50 毫秒.

A_HotkeyModifierTimeout := 100


A_MaxHotkeysPerInterval / A_HotkeyInterval - 语法 & 使用 | AutoHotkey v2

A_MaxHotkeysPerInterval / A_HotkeyInterval

A_MaxHotkeysPerInterval 和 A_HotkeyInterval 是内置变量, 用于控制热键激活的速度, 超过该速度将显示警告对话框.

A_MaxHotkeysPerInterval 可用于获取或设置一个整数, 代表在不触发警告对话框的情况下, 在一定时间间隔内可以按下热键的最大数量.

A_HotkeyInterval 可以用来获取或设置一个整数, 代表以毫秒为单位的时间间隔长度.

A_MaxHotkeysPerInterval 的默认设置为 70 毫秒(ms), 而 A_HotkeyInterval 的默认设置为 2000 毫秒(ms).

备注

这些内置变量通常应该在脚本启动时被赋值(如果默认设置不合适的话), 但脚本可以在任何时候获取或设置它们的值.

注意不要使设置过于宽松, 因为如果您可能曾经不小心引入了无限循环的键击(通过会意外触发其他热键的 Send 函数), 那么您的电脑会因快速的键击事件流而无响应.

举个简单的例子, 热键 ^c::Send "^c" 会产生无限循环的键击. 要避免此问题, 添加 $ 前缀热键的定义(例如 $^c::), 这样 Send 函数就不会触发热键了.

除了无限循环之外, 还可能通过其他方式达到极限, 例如:

  • 当限制相对于重复按键速率来说太低时, 或者系统处于重载状态时, 重复按键.
  • 键盘或鼠标硬件发出的输入事件比典型的重复按键速率更快. 例如, 在某些鼠标上向左或向右倾斜滚轮会发出快速的事件, 可能会达到热键的极限, 如 WheelLeft:: 和 WheelRight::.

要完全停用警告对话框, 请使用 A_HotkeyInterval := 0.

示例

允许在 2000 毫秒内最多按下 200 个热键而不触发警告对话框.

A_HotkeyInterval := 2000  ; 此为默认值 (毫秒).
A_MaxHotkeysPerInterval := 200


A_MenuMaskKey - 语法 & 使用 | AutoHotkey v2

A_MenuMaskKey

A_MenuMaskKey 是一个内置变量, 它控制使用哪个键来掩饰(屏蔽) Win 或 Alt 键松开事件.

A_MenuMaskKey 可用于获取或设置一个十六进制的字符串, 表示 vkNNscNNN 序列, 用于标识虚拟键码(NN) (NNN). 如果为空, 表示禁用屏蔽.

脚本也可以指定一个按键名称, vkNN 序列或 scNNN 序列, 在这种情况下, 通常 VK 或 SC 码被保留为零, 直到按键被发送, 然后自动确定. 指定 "vk00sc000" 可禁用屏蔽, 等同于赋值 "".

不管如何赋值, 如果启用, 返回的字符串总是 vkNNscNNN 序列, 如果禁用, 则是空值. 所有的 vkNNscNNN 序列和所有非零的 vkNN 或 scNNN 序列都是允许的, 但一些组合可能无法抑制菜单. 任何其他无效的键都会导致抛出 ValueError.

默认的设置为 vk11sc01D(左 Ctrl 键).

备注

掩饰键会自动发送, 以防止开始菜单或活动窗口的菜单栏在未预期的时间激活.

此变量可用于将掩饰键更改为具有较少副作用的键. 好的候选者是通常不会有效果的虚拟按键代码, 例如 vkE8, 微软的文档将其称为 "未定义的", 或 vkFF, 它被保留为 "没有映射"(一个没有功能的键). 某些值, 如 0 VK 和非 0 SC, 可能无法抑制开始菜单. 按键码不需要匹配按键的存在.

注意: Microsoft 可以随时为未指定的键码指定一个效果. 例如, vk07 曾经是未定义的并且可以安全使用, 但从 Windows 10 1909 开始, 它就被保留为打开游戏栏.

这个设置是全局的, 也就是说, 只需要指定一次就可以影响整个脚本的行为.

Hotkeys: 如果是使用键盘钩子或鼠标钩子实现的热键, 则最终的按键可能对活动窗口和系统是不可见的. 如果系统 仅 检测到 Win 或 Alt 按下和松开, 而期间没有其他键按下, 通常会激活一个菜单. 为防止这种情况发生, 键盘或鼠标钩子可能会自动发送掩饰键.

如果满足以下所有条件, 则按下钩子热键将导致下一个 Alt 或 Win 的松开被屏蔽(发送掩饰键):

  • 热键原有功能被屏蔽(没有颚化符修饰键).
  • 当按下热键时, Alt 或 Win 逻辑上是按下的.
  • 修饰符键物理上被按下或热键需要修饰符是激活的. 例如, $#a:: 与 AppsKey::RWin 一起使用时, 当 Menu+A 按下时发送掩饰键, 但是 Menu 本身能打开开始菜单.
  • 当热键被按下时如果按下了 Ctrl 键, 则不会掩饰(屏蔽) Alt 键, 因为 Ctrl+Alt 不会激活菜单栏.
  • 如果最近的 Win 按下被 Ctrl, Shift 或 Alt 修饰, 则不会掩饰(屏蔽) Win, 因为在这些情况下, 开始菜单通常不会激活. 然而, 如果 Win 是最后一次物理按下的键, 其也会出现重复按键的情况, 所以很难预测最近一次的 Win 是 何时 按下的.
  • 要么是没有安装键盘钩子(如鼠标热键), 要么自最近一次 Alt 或 Win 按下之后没有其他(未被抑制的) 按下或松开事件发生. 请注意, 即使对于修饰键, 甚至在发送其他键之后, 重复按键也会发生, 但只发生在最后一次物理按下的键上.

如果没有安装键盘钩子, 鼠标热键会立即发送掩饰键.

带有颚化符修饰键的热键并不会阻止按键的原有功能, 因此不会引发掩饰键. 像 ~#a:: 这样的热键仍然屏蔽开始菜单, 因为系统检测到 Win 已经与另一个键组合使用. 但是, 鼠标热键和 Win 本身(~LWin:: 和 ~RWin::) 不会屏蔽开始菜单.

开始菜单(或活动窗口的菜单栏) 可以通过发送任何按键来屏蔽. 以下示例禁用左 Win 激活开始菜单的功能, 同时仍允许将其用于修饰键:

~LWin::Send "{Blind}{vkE8}"

Send: Send, ControlSend 和相关的经常释放修饰键作为其正常操作的一部分. 例如, 热键 <#a::SendText Address 通常必须在发送 Address 的内容之前释放左 Win, 之后再按下左 Win 键(以便其他 Win 组合继续工作). 在这种情况下, 可以发送掩码键, 以防止 Win 或 Alt 松开后激活菜单.

相关

有关背景信息, 请参阅这个帖子.

示例

基础用法.

A_MenuMaskKey := "vkE8"  ; 将掩码键改成未分配的按键, 如 vkE8 等.
#Space::Run A_ScriptDir  ; 额外的 Ctrl 键不会被触发.

展示该变量如何使 vkFF 代替 LControl 被发送.

A_MenuMaskKey := "vkFF"  ; vkFF 是未映射的.
#UseHook
#Space::
!Space::
{
    KeyWait "LWin"
    KeyWait "RWin"
    KeyWait "Alt"
    KeyHistory
}


Any - 方法 & 属性 | AutoHotkey v2

Any

Any 是位于 AutoHotkey 类型层次结构根部的类. 所有其他类型都是 Any 的子类型.

Any.Prototype 定义了适用于所有值和对象(目前不包括 ComValue 和衍生类型) 的方法和属性, 被覆盖改写的除外. 原型对象本身本质上是一个 Object, 但是没有 base, 因此不能识别为对象的实例.

目录

  • 方法:
    • GetMethod: 检索方法的实现函数.
    • HasBase: 如果指定的基对象在值的基对象链中, 则返回 true.
    • HasMethod: 如果该值具有使用此名称的方法, 则返回 true.
    • HasProp: 如果值具有使用此名称的属性, 则返回 true.
  • 属性:
    • Base: 检索值的基对象.
  • 函数:
    • ObjGetBase: 返回值的基对象.

方法

GetMethod

检索方法的实现函数.

Value.GetMethod(Name, ParamCount)

除非被覆盖, 否则这个方法完全相同于 GetMethod(Value, Name, ParamCount).

HasBase

如果指定的基对象在值的基对象链中, 则返回 true. 否则返回 false.

Value.HasBase(BaseObj)

除非被覆盖, 否则这个方法完全相同于 HasBase(Value, BaseObj).

HasMethod

如果该值具有使用此名称的方法, 则返回 true, 否则返回 false.

Value.HasMethod(Name, ParamCount)

除非被覆盖, 否则这个方法完全相同于 HasMethod(Value, Name, ParamCount).

HasProp

如果值具有使用此名称的属性, 则返回 true, 否则返回 false.

Value.HasProp(Name)

除非被覆盖, 否则这个方法完全相同于 HasProp(Value, Name).

属性

Base

检索值的基对象.

BaseObj := Value.Base

对于原始值, 返回值是与 Type(Value) 对应的预定义原型对象.

另请参阅: ObjGetBase, ObjSetBase, Obj.Base

函数

ObjGetBase

返回值的基对象.

BaseObj := ObjGetBase(Value)

不调用元函数或属性函数. 覆盖 Base 属性不会影响此函数的行为.

如果没有基, 则返回值为空字符串. 只有 Any 原型本身没有基.

另请参阅: Base, ObjSetBase, Obj.Base


Array 对象 - 方法 & 属性 | AutoHotkey v2

Array 对象

class Array extends Object

Array(数组) 对象包含值的列表或序列.

值由它们在数组中的位置(称为 数组索引) 来表示, 其中位置 1 是第一个元素.

数组通常是通过将值的列表括在方括号中来创建的. 例如:

veg := ["Asparagus", "Broccoli", "Cucumber"]
Loop veg.Length
    MsgBox veg[A_Index]

负索引可用于反向处理元素, 因此 -1 是最后一个元素, -2 是倒数第二个元素, 依此类推.

尝试使用超出范围的数组索引(例如零, 或者其绝对值大于数组的 Length) 被视为错误, 并将导致抛出 IndexError. 向数组添加新元素的最佳方法是调用 InsertAt 或 Push. 例如:

users := Array()
users.Push(A_UserName)
MsgBox users[1]

也可以通过为 Length 指定更大的值来扩展数组. 这些索引是有效的, 但是 Has 将显示新元素没有值. 元素没有值通常用于可变参数调用或可变参数函数, 但也可以被用于任何目的.

下面使用 "ArrayObj" 作为任何数组对象的占位符, 因为 "Array" 就是类本身.

除了从 Object 继承的方法和属性外, Array 对象还具有以下预定义的方法和属性.

目录

  • 静态方法:
    • Call: 创建一个包含指定值的新数组.
  • 方法:
    • Clone: 返回对象的一个浅拷贝.
    • Delete: 删除数组元素的值, 使索引不包含值.
    • Get: 返回给定索引的值或默认值.
    • Has: 如果 Index 有效且在该位置有一个值, 则返回非零数字.
    • InsertAt: 插入一个或多个值到给定位置.
    • Pop: 删除并返回最后的数组元素.
    • Push: 追加值到数组的末尾.
    • RemoveAt: 从数组中移除项目.
    • __New: 追加项目. 等同于 Push.
    • __Enum: 枚举数组元素.
  • 属性:
    • Length: 检索或设置数组的长度.
    • Capacity: 检索或设置数组的当前容量.
    • Default: 定义了当请求一个没有值的元素时返回的默认值.
    • __Item: 检索或设置数组元素的值.

静态方法

Call

创建一个包含指定值的新数组.

ArrayObj := Array(Value, Value2, ..., ValueN)
ArrayObj := Array.Call(Value, Value2, ..., ValueN)

参数由 __New 定义.

方法

Clone

返回对象的一个浅拷贝.

Clone := ArrayObj.Clone()

所有数组元素都被复制到新数组. 对象 引用 被复制(就像普通的赋值一样), 而不是对象本身.

根据 Obj.Clone 来复制自有的属性, 方法和基.

Delete

删除数组元素的值, 使索引不包含值.

RemovedValue := ArrayObj.Delete(Index)

参数

Index

类型: 整数

一个有效的数组索引.

返回值

类型: Any

此方法返回删除的值(如果没有, 则为空).

Delete 不影响数组的 Length(长度).

备注

此方法不影响数组的 Length.

如果 Index 超出范围, 则抛出 ValueError.

Get

返回给定索引处的值, 或默认值.

Value := ArrayObj.Get(Index , Default)

该方法执行如下操作:

  • 如果 Index 为零或超出范围, 则抛出 IndexError.
  • 返回 Index 处的值, 如果有(请参阅 Has).
  • 如果指定, 则返回 Default 参数的值.
  • 如果定义, 则返回 ArrayObj.Default 的值.
  • 抛出 UnsetItemError.

当 Default 被省略时, 它等价于 ArrayObj[Index], 除了没有调用 __Item.

Has

如果 Index 有效且在该位置有一个值, 则返回返回一个非零数字.

HasIndex := ArrayObj.Has(Index)

InsertAt

插入一个或多个值到给定位置.

ArrayObj.InsertAt(Index, Value1 , Value2, ... ValueN)

参数

Index

类型: 整数

插入 Value1 的位置. 随后的值插入到 Index+1, Index+2, 以此类推. 指定 0 为索引等同于指定 Length + 1.

Value1 ...

类型: Any

要插入的一个或多个值. 要插入数组值, 请将 theArray* 作为最后一个参数传递.

备注

InsertAt 对应 RemoveAt.

先前位于 Index 的项目或 Index 右侧的所有项目都移到右侧. 缺失的参数也会被插入, 但没有值. 例如:

x := []
x.InsertAt(1, "A", "B") ; =>  ["A", "B"]
x.InsertAt(2, "C")      ; =>  ["A", "C", "B"]

; 缺失的元素将保留:
x := ["A", , "C"]
x.InsertAt(2, "B")      ; =>  ["A", "B",    , "C"]

x := ["C"]
x.InsertAt(1, , "B")    ; =>  [   , "B", "C"]

如果 Index 小于 -ArrayObj.Length 或大于 ArrayObj.Length + 1, 则抛出 ValueError. 例如, 对于一个包含 3 个项目的数组, Index 必须介于-3 和 4 之间(包含).

Pop

删除并返回最后的数组元素.

RemovedValue := ArrayObj.Pop()

下面这些都是等同的:

RemovedValue := ArrayObj.Pop()
RemovedValue := ArrayObj.RemoveAt(ArrayObj.Length)
RemovedValue := ArrayObj.RemoveAt(-1)

如果数组为空(Length 为 0), 则抛出 Error.

Push

追加值到数组的末尾.

ArrayObj.Push(Value, Value2, ..., ValueN)

参数

Value ...

类型: Any

要插入一个或多个值. 要插入数组值, 请将 theArray* 作为最后一个参数传递.

RemoveAt

从数组中移除项目.

RemovedValue := ArrayObj.RemoveAt(Index)
ArrayObj.RemoveAt(Index, Length)

参数

Index

类型: 整数

要删除的值的索引.

Length

类型: 整数

如果省略, 则删除一个项目. 否则, 请指定要删除的值的范围的长度.

返回值

类型: Any

如果省略 Length, 返回删除的值(如果没有, 则返回空值). 否则就没有返回值.

备注

RemoveAt 对应 InsertAt.

如果 Index 和 Length 所表示的范围不完全在数组的当前范围内, 则抛出 ValueError.

Pos 侧的其余项将根据 Length 向左移动(如果省略则为 1). 例如:

x := ["A", "B"]
MsgBox x.RemoveAt(1)  ; A
MsgBox x[1]           ; B

x := ["A", , "C"]
MsgBox x.RemoveAt(1, 2)  ; 空值
MsgBox x[1]              ; C

__New

追加项目. 等同于 Push.

ArrayObj.__New(Value, Value2, ..., ValueN)

这个方法是为了支持 Call 而存在的, 并不打算直接调用. 请参阅构造和销毁.

__Enum

枚举数组元素.

For Value in ArrayObj
For Index, Value in ArrayObj

返回一个新的枚举器. 该方法通常不直接调用. 而是将数组对象被直接传递给 for-loop, 其调用一次 __Enum 然后循环的每次迭代都调用一次枚举器. 每次对枚举器的调用都会返回下一个数组元素. for-loop 的变量对应于枚举器的参数, 它们是:

Index

类型: 整数

数组索引, 通常与 A_Index 相同. 其仅在两参数模式下存在.

Value

类型: Any

值(如果没有, 则 Value 为未初始化值).

属性

Length

检索或设置数组的长度.

Length := ArrayObj.Length
ArrayObj.Length := Length

长度包含没有值的元素. 因增加长度而产生的索引是有效的, 但是新元素没有值(由 Has 反映出来). 减小长度将截断数组.

MsgBox ["A", "B", "C"].Length  ;  3
MsgBox ["A",    , "C"].Length  ;  3

Capacity

检索或设置数组的当前容量.

MaxItems := ArrayObj.Capacity
ArrayObj.Capacity := MaxItems

MaxItems 是一个整数, 表示数组在必须自动扩展之前可以包含的最大元素数量. 如果设置的值小于 Length, 则删除多的元素.

x := ["A", "B", "C"]
x.push("D")
MsgBox  x.Capacity  ;  6

x := ["A", "B", "C"]
x.push("D", "E", "F", "G")
MsgBox  x.Capacity  ;  7

Default

定义请求没有值的元素时返回的默认值.

ArrayObj.Default := Value

默认情况下, 该属性实际上不存在, 但是可以由脚本定义. 如果被定义, 如果请求的元素没有值, 它的值将由 __Item 或 Get 返回, 而不是抛出 UnsetItemError. 它可以通过任何常规方法实现, 包括动态属性或元函数, 但要确定查询的是哪个键, 则需要重写 __Item 或 Get.

设置默认值并不会在索引超出范围时防止抛出错误.

__Item

检索或设置数组元素的值.

Value := ArrayObj[Index]
Value := ArrayObj.__Item[Index]
ArrayObj[Index] := Value
ArrayObj.__Item[Index] := Value

Index 是一个表示有效的数组索引的整数; 即, 一个绝对值在 1 和 Length(包括) 之间的整数. 负索引可用于反向处理元素, 因此 -1 是最后一个元素, -2 是倒数第二个元素, 依此类推. 尝试使用超出范围的数组索引(例如零, 或者其绝对值大于数组的 Length(长度)) 被视为错误, 并将导致抛出 IndexError.

如上所示, 属性名 __Item 通常被省略, 但在覆盖属性时使用.


{...} (block) - 语法 & 使用 | AutoHotkey v2

{...} (区块)

区块是用大括号括起来的一个或多个语句. 通常与函数定义和控制流语句一起使用.

{
    语句
}

备注

区块用于将两行或多行语句绑定在一起. 它还可以用来改变 Else 语句从属于哪个 If 语句, 例如在此例中, 区块强制 Else 语句从属于第一个 If 语句, 而不是第二个:

if (Var1 = 1)
{
    if (Var2 = "abc")
        Sleep 1
}
else
    return

尽管区块可以在脚本中的任何位置使用, 不过目前它们仅在与函数定义, If, Else, Loop 语句, Try, Catch 或 Finally 一起使用时才有意义.

如果上面提到的任何控制流语句中仅含单行语句, 那么该语句可以不需要括在区块中(这对于函数定义不适用). 不过, 在某些情况下, 这样做可能会增强脚本的可读性和可维护性.

区块中可以为空(不含任何语句), 当您想注释区块中的内容而不移除区块时这很有用.

One True Brace(OTB, K&R 样式): 可以在以下位置选择使用 OTB 样式: 函数定义, If, Else, Loop, While, For, Try, Catch 和 Finally. 这种样式中区块的开括号与区块的控制语句在同一行, 而不是在其下一行. 例如:

MyFunction(x, y) {
    ...
}
if (x < y) {
    ...
} else {
    ...
}
Loop RepeatCount {
    ...
}
While x < y {
    ...
}
For k, v in obj {
    ...
}
Try {
    ...
} Catch Error {
    ...
} Finally {
    ....
}

同样地, 语句也可以放在大括号的后面(但不包括 One True Brace 样式的开括号). 例如:

if (x = 1)
{ MsgBox "这一行出现在左大括号的右边. 只要 IF 语句为真, 它就会执行."
    MsgBox "这是下一行."
} MsgBox "这一行出现在右大括号的右边. 它无条件地执行."

相关

函数定义, 控制流语句, If, Else, Loop 语句, Try, Catch, Finally

示例

通过将两个语句 MsgBox, "test1" 和 Sleep, 5 用大括号括起来, 如果 x 等于 1, If 语句同时执行这两个语句.

if (x = 1)
{
    MsgBox "test1"
    Sleep 5
}
else
    MsgBox "test2"


BlockInput - 语法 & 使用 | AutoHotkey v2

BlockInput

禁用或启用用户通过键盘和鼠标与计算机交互的能力.

BlockInput OnOff
BlockInput SendMouse
BlockInput MouseMove

参数

OnOff

类型: 字符串或整数

此模式无条件地阻塞所有用户输入. 指定下列值之一:

On 或 1(true): 阻止用户与计算机交互(鼠标和键盘输入都无效).

Off 或 0(false): 重新启用输入.

SendMouse

类型: 字符串

此模式仅在执行特定的发送和/或鼠标函数时阻塞用户输入. 指定下列单词的其中一个:

Send: 当 SendEvent 进行时(如果使用了 SendMode "Event", 包括 Send 和 SendText), 用户的键盘和鼠标输入将被忽略. 这样避免了用户的键击扰乱模拟键击流. 当 Send 结束时, 会重新启用输入(在之前没有使用 BlockInput "On" 阻塞的情况下).

Mouse: 当 Click, MouseMove, MouseClick 或 MouseClickDrag 进行时(仅对于传统的 SendEvent 模式), 用户的键盘和鼠标输入被忽略. 这样避免了用户的鼠标移动和点击扰乱模拟鼠标事件. 当鼠标命令结束时, 会重新启用输入(在之前没有使用 BlockInput "On" 阻塞的情况下).

SendAndMouse: 上面两种模式的组合.

Default: 同时关闭 Send 和 Mouse 模式, 但不改变当前输入阻塞的状态. 例如, 如果 BlockInput "On" 当前有效, 使用 BlockInput "Default" 不会将其关闭.

MouseMove

类型: 字符串

此模式仅阻止鼠标光标移动. 指定下列单词的其中一个:

MouseMove: 鼠标光标不会随用户对鼠标的物理移动而移动(DirectInput 应用程序可能是个例外). 脚本中首次使用此函数时, 会安装鼠标钩子(如果还没有安装). 鼠标钩子将保持安装, 直到下一次使用 Suspend 或 Hotkey 函数, 此时如果任何热键或热字符串不需要它, 它将被移除(请参阅 #Hotstring NoMouse).

MouseMoveOff: 允许用户移动鼠标光标.

备注

所有这三种 BlockInput 模式 (OnOff, SendMouse 和 MouseMove) 都是独立运行的. 例如, BlockInput "On" 会继续阻塞输入直到使用了 BlockInput "Off", 即使 SendMouse 中的一个单词也有效. 另一个例子是, 如果 BlockInput "On" 和 BlockInput "MouseMove" 都有效, 鼠标移动将被阻塞, 直到它们都被关闭.

注意: OnOff 和 SendMouse 模式将在 UAC 开启或脚本不是以管理员权限运行的时候失效. 更多详情, 请参阅 FAQ.

比起 BlockInput, 通常优先考虑使用 Send 的 SendInput 或 SendPlay 模式, 这样键击和鼠标点击会变得不可中断. 因为它们与 BlockInput 不一样, 这些模式不会丢弃发送期间用户输入的内容; 相反, 这些键击被缓冲起来在之后发送. 不使用 BlockInput 也避免了下文所描述的需要解决的粘滞按键问题.

如果在用户按住按键时启用 BlockInput, 可能会导致这些键 "卡住". 通过等待这些按键释放后才启用 BlockInput 可以避免此问题, 如本例所示:

^!p::
{
    KeyWait "Control"  ; 等待按键被释放. 为每个热键修饰符使用一次 KeyWait.
    KeyWait "Alt"
    BlockInput true
    ; ... 发送键击和鼠标点击 ...
    BlockInput false
}

BlockInput 生效时, 用户的输入被拦截, 不过 AutoHotkey 可以模拟键击和鼠标点击. 然而由于 Windows API 的特性, 按下 Ctrl+Alt+Del 将重新启用输入.

某些类型的钩子热键在 BlockInput 启用时仍然可以被触发. 例如包括 MButton(鼠标钩子) 和 LWin & Space(含有除修饰符 $# 外的显式前缀的键盘钩子).

当脚本关闭时会自动重新启用输入.

相关

SendMode, Send, Click, MouseMove, MouseClick, MouseClickDrag

示例

打开记事本, 并在 BlockInput 开启时通过发送 F5 粘贴时间/日期. 注意, BlockInput 可能只在脚本以管理员身份运行的情况下工作.

BlockInput true
Run "notepad"
WinWaitActive "ahk_class Notepad"
Send "{F5}" ; 粘贴时间和日期
BlockInput false


Break - 语法 & 使用 | AutoHotkey v2

Break

退出(终止) 任意类型的循环语句.

Break LoopLabel

参数

LoopLabel

如果省略或为 1, 则此语句适用于包含它的最内层循环. 否则, 请指定此语句应该应用于哪层循环; 可通过标签名称或数字嵌套层级来实现. 如果指定了标签, 标签必须直接指向循环语句.

LoopLabel 必须为常量值 - 不支持变量和表达式, 但括号中的单个原义数字或用圆括号括起来的字符串除外. 例如: break("outer")

备注

鼓励使用 Break 和 Continue 代替 Goto, 因为它们通常让脚本更容易阅读和维护.

相关

Continue, Loop, While-loop, For-loop, 区块, 标签

示例

如果 var 大于 25, 跳出循环.

Loop
{
    ; ...
    if (var > 25)
        break
    ; ...
    if (var <= 5)
        continue
}

从嵌套循环中退出 outer(外部) 循环.

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.


缓冲对象 - 定义 & 使用 | AutoHotkey v2

缓冲对象

class Buffer extends Object

封装一块内存, 用于高级技术, 如 DllCall, 结构体, StrPut 和原始文件 I/O.

缓冲对象通常通过调用 Buffer() 创建, 但也可以由使用了 "RAW" 选项的 FileRead 返回.

BufferObj := Buffer(ByteCount)

ClipboardAll 返回缓冲的子类, 也称为 ClipboardAll.

class ClipboardAll extends Buffer

下面使用 "BufferObj" 作为任何缓冲对象的占位符, 因为 "Buffer" 就是类本身.

除了从 Object 继承的方法和属性外, Buffer 对象还具有以下预定义的属性.

目录

  • 类缓冲对象
  • 静态方法:
    • Call: 创建新的缓冲对象.
  • 方法:
    • __New: 分配或重新分配缓冲, 并可选择将其填充.
  • 属性:
    • Ptr: 检索缓冲区的当前内存地址.
    • Size: 检索或设置缓冲区的大小, 以字节为单位.
  • 相关
  • 示例

类缓冲对象

一些内置函数接受缓冲对象来代替地址 - 请参阅相关部分以获取链接. 这些函数也接受任何具有 Ptr 和 Size 属性的其他对象, 但是程序针对原生的缓冲对象进行了优化.

在大多数情况下, 传递缓冲对象比传递地址更安全, 因为函数可以读取缓冲区大小以确保它不会尝试访问缓冲区之外的任何内存位置. 一个例外是 DllCall 调用程序之外的函数; 在这些情况下, 可能需要将缓冲区大小显式传递给函数.

静态方法

Call

创建新的缓冲对象.

BufferObj := Buffer(ByteCount, FillByte)
BufferObj := Buffer.Call(ByteCount, FillByte)

参数

ByteCount

类型: 整数

要分配的字节数. 对应于 Buffer.Size.

如果省略, 将创建一个 null(零) Ptr 和零 Size 的缓冲.

FillByte

类型: 整数

指定一个 0 到 255 之间的数字, 以将缓冲中的每个字节设置为该数字.

在不需要先读取缓冲而直接写入的情况下, 通常应将其省略, 因为它的时间开销与字节数成正比. 如果省略, 则不初始化缓冲的内存; 每个字节的值是任意的.

返回值

类型: Object

方法或函数返回一个 Buffer 对象.

备注

如果无法分配内存, 例如 ByteCount 意外地大, 或者系统虚拟内存不足, 则抛出 MemoryError.

参数是由 __New 定义的.

方法

__New

分配或重新分配缓冲, 并可选择将其填充.

BufferObj.__New(ByteCount, FillByte)

这个方法的存在是为了支持 Call, 通常不会直接调用. 请参阅创建和销毁.

指定 ByteCount 来分配, 重新分配或释放缓冲. 这等同于给 Size 赋值.

指定 FillByte 用给定的数字字节值填充缓冲, 覆盖任何现有内容.

如果两个参数都省略, 则此方法没有效果.

属性

Ptr

检索缓冲区的当前内存地址.

CurrentPtr := BufferObj.Ptr

CurrentPtr 是一个代表缓冲当前内存地址的整数. 当释放或重新分配给缓冲时, 此地址将变为无效. 不能使用无效地址. 在缓冲对象的引用计数达到零之前, 缓冲不会被释放, 但是当它的大小更改时, 会重新分配缓冲.

Size

检索或设置缓冲区的大小, 以字节为单位.

CurrentByteCount := BufferObj.Size
BufferObj.Size := NewByteCount

CurrentByteCount 和 NewByteCount 是整数, 代表缓冲的大小(单元为字节). 缓冲的地址通常会随着大小的改变而改变. 如果减小大小, 则缓冲中的数据将被截断, 但保留剩余的字节. 如果增加大小, 则保留所有数据并且任何新字节的值都是任意的(由于性能原因, 它们未初始化).

如果无法分配内存, 例如 NewByteCount 意外地大, 或者系统虚拟内存不足, 则抛出 MemoryError.

CurrentByteCount 总是它被赋予的确切值, 无论是由 __New 还是由以前的赋值.

缓冲的地址通常会随着大小的改变而改变. 如果减小大小, 则缓冲区中的数据将被截断, 但保留剩余的字节. 如果增加大小, 则保留所有数据并且任何新字节的值都是任意的(由于性能原因, 它们未初始化).

如果无法分配内存, 例如 ByteCount 意外地大, 或者系统虚拟内存不足, 则抛出 MemoryError.

这个属性总是返回它被赋予的确切值, 无论是由 __New 还是由以前的赋值.

相关

DllCall, NumPut, NumGet, StrPut, StrGet, File.RawRead, File.RawWrite, ClipboardAll

示例

通过 DllCall 使用 Buffer 从外部函数接收字符串.

max_chars := 11

; 为 wsprintf 的 Unicode 版本分配一个缓冲.
bufW := Buffer(max_chars*2)

; 使用 wsprintfW() 将一个 UTF-16 字符串打印到缓冲中.
DllCall("wsprintfW", "Ptr", bufW, "Str", "0x%08x", "UInt", 4919, "CDecl")

; 从 bufW 中检索字符串并显示出来.
MsgBox StrGet(bufW, "UTF-16")  ; 或者直接 StrGet(bufW).

; 分配一个缓冲区供 ANSI 版本的 wsprintf 使用.
bufA := Buffer(max_chars)

; 使用 wsprintfA() 将一个 ANSI 字符串打印到缓冲中.
DllCall("wsprintfA", "Ptr", bufA, "AStr", "0x%08x", "UInt", 4919, "CDecl")

; 从 bufA 中获取字符串(转换为本地格式), 并将其显示出来.
MsgBox StrGet(bufA, "CP0")


CallbackCreate - 语法 & 使用 | AutoHotkey v2

CallbackCreate

创建机器码地址, 当它被调用时会重定向到脚本中的函数.

Address := CallbackCreate(Function , Options, ParamCount)

参数

Function

类型: 函数对象

每当调用 Address 时会自动调用此函数对象. 此函数同时会接收到传递给 Address 的参数.

闭包或绑定函数可以用来区分多个回调函数调用相同的脚本函数.

回调函数保留对函数对象的引用, 并在脚本调用 CallbackFree 时释放它.

Options

类型: 字符串

如果为空或省略, 每次调用 Function 时, 都会启动一个新线程, 使用标准调用约定, 并将参数单独传递给 Function. 否则, 请指定一个或多个下列选项. 在选项间使用空格分隔(例如 "C Fast").

Fast 或 F: 避免每次调用 Function 时都启动新的线程. 尽管这样执行的更好, 但必须避免调用 Address 的线程发生变化(例如当回调函数被传入的消息触发). 这是因为 Function 能改变在它被调用时正在运行的线程的全局设置(例如 A_LastError 和上次找到的窗口). 有关详情, 请参阅备注.

CDecl 或 C: 让 Address 遵循 "C" 调用约定. 此选项通常省略, 因为在回调函数中使用标准调用约定更为常用. 64 位版本的 AutoHotkey 会忽略这个选项, 它使用 x64 调用约定.

&: 将参数列表的地址(单个整数) 传递给 Function, 而不是传递给各个参数. 可以使用 NumGet 检索参数值. 当使用标准的 32 位调用约定时, ParamCount 必须以 DWORDs 指定参数列表的大小(字节数除以 4).

ParamCount

类型: 整数

如果为空或省略, 则它默认为 Function.MinParams, 这通常是 Function 定义中强制参数的数目. 否则, 请指定 Address 的调用者会传递给它的参数数目. 在这两种情况中, 必须确保调用者准确传递此数目的参数.

返回值

类型: 整数

CallbackCreate 返回一个机器码地址. 此地址通常通过 DllCall 或使用 NumPut 放置在结构中传递给外部函数, 但也可以由 DllCall 直接调用. 将地址传递给 CallbackFree 将删除回调.

错误处理

在下列任何一种情况下, 此函数失败并抛出异常:

  • Function 不是对象, 或既没有 MinParams 属性, 也没有 Call 方法.
  • Function 具有 MinParams 属性, 该属性超过回调所提供的参数数量.
  • ParamCount 为负数.
  • ParamCount 省略, 并且: 1) Function 没有 MinParams 属性; 或 2) & 选项与标准 32 位调用约定一起使用.

Function 的参数

分配给回调地址的函数最多可以接受 31 个参数. 允许使用可选参数, 当多个调用者调用 Function 时, 这非常有用.

正确地解析参数需要了解 x86 调用约定是如何工作的. 由于 AutoHotkey 没有类型化参数, 因此假定回调的参数列表由整数组成, 可能需要进行一些重新解释.

AutoHotkey 32-bit: 所有传入参数都是无符号 32 位整数. 较小的类型被填充为 32 位, 而较大的类型被分割为一系列 32 位的参数.

如果传入的参数是一个有符号整数, 任何负数都可以通过下面的方法来表示:

; 方法 #1
if (wParam > 0x7FFFFFFF)
    wParam := -(~wParam) - 1

; 方法 #2: 依赖于 AutoHotkey 原生使用带符号的 64 位整数这一事实.
wParam := wParam << 32 >> 32

AutoHotkey 64-bit: 所有传入的参数都是有符号的 64 位整数. AutoHotkey 本身不支持无符号 64 位整数. 较小的类型被填充为 64 位, 而较大的类型总是通过地址传递.

AutoHotkey 32-bit/64-bit: 如果传入的参数是 8 位或 16 位(或 x64 上的 32 位), 则值的上位可能包含 "garbage" 可以使用 bitwise-and 进行过滤, 如下例所示:

Callback(UCharParam, UShortParam, UIntParam) {
    UCharParam &= 0xFF
    UShortParam &= 0xFFFF
    UIntParam &= 0xFFFFFFFF
    ;...
}

如果调用者希望传入参数是字符串, 那么它实际接收的是字符串的地址. 要获取这样的字符串, 请使用 StrGet:

MyString := StrGet(MyParameter)

如果某个传入参数为结构的地址, 则可以参照 DllCall 结构中描述的步骤提取其中的各个成员.

按址接收参数: 如果使用 & 选项, Function 接收第一个回调参数的 地址. 例如:

callback := CallbackCreate(TheFunc, "F&", 3)  ; 32 位中必须指定参数列表的大小.
DllCall(callback, "float", 10.5, "int64", 42)
TheFunc(params) {
    MsgBox NumGet(params, 0, "float") ", " NumGet(params, A_PtrSize, "int64")
}

32 位程序中的大多数回调都使用 stdcall 调用约定, 该约定需要固定数量的参数. 在这种情况下, 必须将 ParamCount 设置为参数列表的大小, 其中 Int64 和 Double 都计为两个 32 位参数. 使用 Cdecl 或 64 位调用约定时, ParamCount 无效.

Function 应该返回什么

如果 Function 使用不带任何参数的 Return, 或者指定空白值, 如 ""(或者根本不使用 Return), 则将 0 返回给回调的调用者. 否则, 函数应该返回一个整数, 然后将其返回给调用者. AutoHotkey 32-bit 将返回值截断为 32 位, 而 AutoHotkey 64-bit 则支持 64 位返回值. 不支持返回大于此值的结构(按值).

Fast vs. Slow

默认/慢速模式使该 Function 以默认值(如 SendMode 和 DetectHiddenWindows) 重新启动. 这些默认值可以在脚本启动中更改.

与之相比, 快速模式会继承在调用 Function 时正在运行的线程的全局设置. 而且, Function 对全局设置的任何修改(包括上次找到的窗口) 都会在当前线程生效. 因此, 快速模式应该只在确切知道 Function 会被哪个线程调用时才使用.

要避免被自己(或其他任何线程) 中断, 回调可以在它的首行使用 Critical. 但是, 通过小于 0x0312 消息达到的间接调用 Function 时, 这并不是完全有效的(增加 Critical 的 interval 也许有帮助). 而且, Critical 不会阻止 Function 执行一些可能导致间接调用它自己的动作, 例如调用 SendMessage 或 DllCall.

CallbackFree

删除回调函数并释放它对函数对象的引用.

CallbackFree(Address)

每次使用 CallbackCreate 都会分配少量内存(32 或 48 字节加上系统开销). 由于操作系统会在脚本退出时自动释放该内存, 因此任何分配了少量, 固定 数量的回调的脚本都不必显式释放内存.

但是, 如果回调函数持有的函数对象是动态的(例如, 闭包或绑定函数), 当不再需要回调函数时, 释放回调函数可能是特别重要的; 否则, 函数对象将不会被释放.

相关

DllCall, OnMessage, OnExit, OnClipboardChange, Sort 回调, Critical, PostMessage, SendMessage, 函数, Windows 消息, 线程

示例

显示所有顶层窗口的摘要.

EnumAddress := CallbackCreate(EnumWindowsProc, "Fast")  ; 快速模式是可以的, 因为它只会在这个线程中被调用.

DetectHiddenWindows True  ; 由于是快速模式, 所以此设置也会在回调中生效.

; 把控制传给 EnumWindows(), 它会重复调用回调:
DllCall("EnumWindows", "Ptr", EnumAddress, "Ptr", 0)
MsgBox Output  ; 显示由回调收集的信息.

EnumWindowsProc(hwnd, lParam)
{
    global Output
    win_title := WinGetTitle(hwnd)
    win_class := WinGetClass(hwnd)
    if win_title
        Output .= "HWND: " . hwnd . "`tTitle: " . win_title . "`tClass: " . win_class . "`n"
    return true  ; 告知 EnumWindows() 继续执行, 一直到枚举完所有的窗口.
}

演示如何在脚本中通过把 GUI 窗口的 WindowProc 重定向到新的 WindowProc 来子类化窗口. 此时, 文本控件的背景颜色被改变为自定义颜色.

TextBackgroundColor := 0xFFBBBB  ; BGR 格式的自定义颜色.
TextBackgroundBrush := DllCall("CreateSolidBrush", "UInt", TextBackgroundColor)

MyGui := Gui()
Text := MyGui.Add("Text",, "Here is some text that is given`na custom background color.")

; 64 位脚本必须调用 SetWindowLongPtr 代替 SetWindowLong:
SetWindowLong := A_PtrSize=8 ? "SetWindowLongPtr" : "SetWindowLong"

WindowProcNew := CallbackCreate(WindowProc)  ; 避免子类化中使用快速模式.
WindowProcOld := DllCall(SetWindowLong, "Ptr", MyGui.Hwnd, "Int", -4  ; -4 为 GWL_WNDPROC
    , "Ptr", WindowProcNew, "Ptr") ; 返回值必须设置为 "Ptr" 或 "UPtr" 而不是 "Int".

MyGui.Show()

WindowProc(hwnd, uMsg, wParam, lParam)
{
    Critical
    if (uMsg = 0x0138 && lParam = Text.Hwnd)  ; 0x0138 为 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)
}


CaretGetPos - 语法 & 使用 | AutoHotkey v2

CaretGetPos

检索插入符号的当前位置(文本插入点).

CaretFound := CaretGetPos(&OutputVarX, &OutputVarY)

参数

&OutputVarX, &OutputVarY

类型: VarRef

如果省略, 将不存储对应的值. 否则, 指定用于存储 X 和 Y 坐标的输出变量的引用. 检索到的坐标相对于活动窗口的客户端区域, 除非使用 CoordMode 或 A_CoordModeCaret 覆盖.

返回值

类型: 整数(布尔值)

如果没有活动窗口或无法确定插入符号位置, 则函数返回 0(false), 并且输出变量为空. 如果系统返回一个插入符号位置, 则函数返回 1(true), 但这并不一定意味着插入符号是可见的.

备注

如果不需要相应的信息, 可以省略任何输出变量.

请注意, 某些窗口(例如 MS Word 的某些版本) 报告的插入符号位置相同, 无论其实际位置如何.

相关

CoordMode, A_CoordModeCaret

示例

允许用户移动插入光标, 其当前位置显示在一个自动更新的工具提示中.

SetTimer WatchCaret, 100
WatchCaret() {
    if CaretGetPos(&x, &y)
        ToolTip "X" x " Y" y, x, y - 20
    else
        ToolTip "No caret"
}


Catch - 语法 & 使用 | AutoHotkey v2

Catch

指定在 Try 语句执行期间如果抛出值或错误时要执行的一或多条语句.

Catch ErrorClass as OutputVar
{
    语句
}

参数

ErrorClass

类型: Class

应该被捕获的值的类, 如 Error, TimeoutError 或 MyCustomError. 这也可以是一个以逗号分隔的类的列表. 类必须由其确切的全名指定, 而不是任意的表达式, 因为每个类的原型在加载时被解析. 任何内置的或用户定义的类都可以被使用, 即使它不是从 Error 派生的.

如果没有指定类, 默认是 Error.

要捕捉任何类, 请使用 Catch Any.

如果使用了无效的类名, 或者由于存在同名的局部变量而无法访问一个类, 则会显示加载时错误.

OutputVar

类型: 变量

存储抛出值的变量, 这通常是一个 Error 对象. 这不能是一个动态变量.

如果省略, 抛出的值不能被直接访问, 但仍然可以通过使用没有参数的 Throw 来重新抛出.

Statement(s)

抛出值或错误时执行的语句.

如果只使用一个语句, 一般不需要大括号. 有关详情, 请参阅 {...} (block).

备注

多个 Catch 语句可以一个接一个地使用, 每个语句指定一个不同的类(或多个类). 如果值不是任何一个列出的类的实例, 它就不会被这个 Try-Catch 捕获, 但可能会被调用堆栈中更高的一个捕获.

Catch 的每次使用都必须附属于(与之关联) 它上面的 Ty 语句. Catch 总是附属于它上面最近的未被认领的 Try 语句, 除非使用区块来改变这种行为.

参数列表可以选择括在括号中, 在这种情况下, catch 后的空格或制表符是可选的.

Catch 后面可以有 Else, 如果在相关的 Try 块中没有抛出异常, 则执行 Else.

可选使用 One True Brace(OTB) 样式. 例如:

try {
    ...
} catch Error {
    ...
}

加载时错误不能被捕获, 因为它们发生在 try 语句执行之前.

相关

Try, Throw, Error 对象, Else, Finally, 区块, OnError

示例

请参阅 Try.


Chr - 语法 & 使用 | AutoHotkey v2

Chr

返回与指定数字所表示的编码相对应的字符串(通常是单个字符).

String := Chr(Number)

参数

Number

类型: 整数

介于 0 和 0x10FFFF 之间的 Unicode 字符编码.

返回值

类型: 字符串

Number 对应的字符串. 这始终是单个 Unicode 字符, 但是出于实际原因, Unicode 补充字符(其中 Number 在 0x10000 到 0x10FFFF 之间) 被算作两个字符. 也就是说, StrLen 报告的返回值的长度可以是 1 或 2. 有关详情, 请参阅字符串编码.

如果 Number 为 0, 返回值是一个包含二进制空字符的字符串, 而不是一个空(零长度) 字符串. 可以安全地将其赋值给变量, 传递给函数或与另一个字符串连接. 然而, 一些内置函数可能只 "看见" 第一个空字符前面的那部分字符串.

备注

字符代码的范围和含义取决于使用的是哪种字符串编码. 目前所有 AutoHotkey v2 可执行文件都是为 Unicode 构建的, 因此这个函数总是接受 Unicode 字符编码, 并返回 Unicode(UTF-16) 字符串.

常用字符编码包括 9(制表符), 10(换行符), 13(回车), 32(空格), 48-57(数字 0-9), 65-90(大写字母 A-Z) 和 97-122(小写字母 a-z).

相关

Ord

示例

报告与字符编码 116 相对应的字符.

MsgBox Chr(116) ; 报告 "t".


Class 对象 - 方法 & 属性 | AutoHotkey v2

Class 对象

class Class extends Object

Class(类) 对象表示一个类定义; 它包含静态方法和属性.

每个类对象都基于其继承的任何类, 如果没有指定, 则基于 Object. Object 基于 Class.Prototype, 其又基于 Object.Prototype, 因此类可以从任何这些基对象继承方法和属性.

"静态" 方法和属性是类对象本身拥有的任何方法和属性(因此不适用于特定实例), 而类实例的方法和属性则由原型拥有.

下面使用 "ClassObj" 作为任何类对象的占位符, 因为 "Class" 就是类本身. 通常, 使用类定义中给出的名称来引用类对象.

目录

  • 方法:
    • Call: 构造类的新实例.
  • 属性:
    • Prototype: 检索或设置对象, 其类的所有实例都基于此.

方法

Call

构造类的新实例.

Obj := ClassObj(Params*)
Obj := ClassObj.Call(Params*)

静态方法通常从 Object, Array 或 Map 类继承. 它执行以下功能:

  • 分配内存并初始化对象的二进制结构, 这取决于对象的原生类型(例如, 它是数组还是映射, 或者只是一个对象).
  • 将新对象的基设置为 ClassObj.Prototype.
  • 如果新对象有 __Init 方法, 则调用它的 __Init 方法. 此方法由类定义自动创建; 它包含类主体中定义的所有实例变量初始化器.
  • 如果新对象有 __New 方法, 则调用它的 __New 方法. 所有传递给 Call 的参数都被转发到 __New.
  • 返回新对象.

Call 可以被通过定义静态方法(如 static Call()) 在类定义中重写. 这允许修改类或阻止构造新实例.

注意, Class()(在这种情况下使用原义的 "Class") 可用于构造基于 Class.Prototype 的新的 Class 对象. 但是, 新对象最初没有 Call 方法, 因为它不是 Object 的子类. 通过给 Base 赋值使其成为 Object 的子类, 或 Call 方法重新实现或从其他类中复制. 在使用标准的 Call 方法实例化原型之前, 还必须创建原型并将其赋值给该类.

属性

Prototype

检索或设置类的所有实例所基于的对象.

Proto := ClassObj.Prototype
ClassObj.Prototype := Proto

默认情况下, 类的原型包含类定义中定义的所有实例方法和动态属性, 可用于检索对方法, 或 getters/setters 属性的引用, 或定义一个新的. 脚本还可以定义新的值属性, 这些值充当所有实例的默认属性值.

类的 Prototype 通常基于其基类的 Prototype, 所以 ClassObj.Prototype.base == ClassObj.base.Prototype.

原型自动被定义为类定义创建的任何类对象的自身属性.


Click - 语法 & 使用 | AutoHotkey v2

Click

在指定坐标处点击鼠标按钮. 它还可以按住鼠标按钮, 转动鼠标滚轮或移动鼠标.

Click Options

参数

Options

指定一个或多个以下组件: Coords, WhichButton, ClickCount, DownOrUp 和/或 Relative. 如果省略所有项目, 在鼠标光标的当前位置执行单次左键点击.

组件可以分布在多个参数中, 也可以组合成一个或多个字符串. 每个参数可以是单个数字组件, 也可以是包含零个或多个组件的字符串, 其中每个组件与下一个组件之间至少用一个空格, 制表符和/或逗号分隔(所有组件都在字符串中). 例如, Click 100, 200, "R D" 等同于 Click "100 200 R D", 两者都有效. 空或省略的参数将被忽略, 额外的逗号也会被忽略.

警告: Click 100 200 等同于 Click "100200", 因为在调用函数之前, 这两个数字将被连接起来.

组件可以以任何顺序出现, 除了 ClickCount 必须出现在 Coords 的右边(如果存在).

Coords: 如果省略, 则使用鼠标的当前位置. 否则, 请指定在点击前, 鼠标光标要移动到的 X 和 Y 坐标. 例如, Click "100 200" 在特定位置点击鼠标左键. 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 更改了这个设置. 如果省略, 则使用光标的当前位置.

WhichButton: 如果省略, 默认为 Left(鼠标左键). 否则, 请指定 Left, Right, Middle(或只是这些名称的首字母); X1(第四个按钮) 或 X2(第五个按钮). 例如, Click "Right" 在鼠标光标的当前位置点击鼠标右键. Left 和 Right 对应鼠标的主按钮和次按钮. 如果用户通过系统设置交换了按钮, 按钮的物理位置被替换, 但效果保持不变.

WhichButton 也可以是 WheelUp(或 WU) 来向上转动滚轮(远离你), 或 WheelDown(或 WD) 来向下转动滚轮(朝向你). 也可以指定 WheelLeft(或 WL) 或 WheelRight(或 WR). ClickCount 为指定滚轮要转动的格数. 然而, 有些程序不接受鼠标滚轮转动的格数 ClickCount 大于 1 的情况. 对于这些程序, 可以通过 Loop 等方法多次使用 Click 函数.

ClickCount: 如果省略, 默认为 1. 否则, 请指定单击鼠标按钮或转动鼠标滚轮的次数. 例如, Click 2 在鼠标光标位置双击. 如果省略, 那么点击鼠标一次. 如果指定了 Coords, 那么 ClickCount 必须放在坐标后面. 指定零(0) 来移动鼠标而不进行点击; 例如, Click "100 200 0".

DownOrUp: 如果省略, 此时每次点击包括按下事件和接着的弹起事件. 否则, 指定单词 Down(或字母 D) 来按下鼠标按钮不放. 之后, 使用单词 Up(或字母 U) 来释放鼠标按钮. 例如, Click "Down" 按下鼠标左键不放.

Relative: 如果省略, 则将 X 和 Y 坐标使用为绝对位置. 否则, 指定单词 Rel 或 Relative 会把指定的 X 和 Y 坐标视为距离当前鼠标位置的偏移. 换句话说, 会把光标从当前位置往右移动 X 像素(负值则往左) 且往下移动 Y 像素(负值则往上).

备注

Click 函数使用 SendMode 设置的发送方法. 要忽略此模式进行特殊的点击, 使用带有 {Click} 的特定的 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 函数不会自动释放修饰键(Ctrl, Alt, Shift 和 Win). 例如, 如果现在 Ctrl 处于按下的状态, 那么 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"


ClipboardAll - 语法 & 使用 | AutoHotkey v2

ClipboardAll

创建一个包含剪贴板上的所有内容的对象(如图片和格式).

ClipSaved := ClipboardAll(Data, Size)

ClipboardAll 本身是一个派生自 Buffer 的类.

参数

省略这两个参数来检索剪贴板的当前内容. 否则, 指定一个或两个参数来创建包含给定二进制剪贴板数据的对象.

Data

类型: 对象或整数

类缓冲对象, 或为二进制数据地址的纯整数. 数据必须采用特定的格式, 因此通常源自之前对 ClipboardAll 的调用. 请参阅下面的示例 #2.

Size

类型: 整数

数据要使用的字节数. 当 Data 是对象时, 这是可选的.

返回值

类型: 对象

函数返回 ClipboardAll 对象的引用 , 它有两个属性(继承自 Buffer):

  • Ptr: 对象包含的数据的地址. 此地址在释放对象之前有效.
  • Size: 原始二进制数据的大小, 以字节为单位.

备注

内置变量 A_Clipboard 包含以纯文本形式表示的 Windows 剪贴板的当前内容.

ClipboardAll 函数最常用来保存剪贴板的内容, 以便脚本可以临时使用剪贴板进行操作. 当操作完成时, 脚本恢复原来的剪贴板内容, 如示例 #1 和示例 #2 所示.

如果 ClipboardAll 不能检索剪贴板上的一个或多个数据对象(格式), 它们将被省略, 但所有剩余的对象将被存储.

ClipWait 可用于检测剪贴板何时包含数据(可选包括非文本数据).

对象所包含的二进制数据由 4 字节格式类型, 接着 4 字节数据块大小, 而后是该格式的数据块组成. 如果剪贴板包含不止一种格式(几乎总是这样), 则重复这三项, 直到包含所有格式为止. 数据以 4 字节格式类型的 0 结束.

相关

A_Clipboard, ClipWait, OnClipboardChange, #ClipboardTimeout, Buffer

示例

使用变量保存和恢复剪贴板上的所有内容.

ClipSaved := ClipboardAll()   ; 把整个剪贴板保存到您选择的变量中.
; ... 这里临时使用剪贴板, 比如快速粘贴大量文本 ...
A_Clipboard := ClipSaved   ; 还原剪贴板. 注意这里使用 A_Clipboard(而不是 ClipboardAll).
ClipSaved := ""  ; 在剪贴板含有大量内容时释放内存.

使用文件保存和还原剪贴板上的所有内容.

; 选项 1: 删除任何现有文件, 然后使用 FileAppend.
FileDelete "C:\Company Logo.clip"
FileAppend ClipboardAll(), "Company Logo.clip" ; 文件扩展名无关紧要.

; 选项 2: 使用 FileOpen 的 overwrite 模式和 File.RawWrite.
ClipData := ClipboardAll()
FileOpen("Company Logo.clip", "w").RawWrite(ClipData)

要稍后将文件加载回剪贴板(或变量), 请遵循以下示例:

ClipData := FileRead("Company Logo.clip", "RAW")  ; 在这种情况下, FileRead 返回缓冲.
A_Clipboard := ClipboardAll(ClipData)  ; 将缓冲转换到 ClipboardAll 并赋值.


ClipWait - 语法 & 使用 | AutoHotkey v2

ClipWait

等待直到剪贴板包含数据.

Boolean := ClipWait(Timeout, WaitFor)

参数

Timeout

类型: 整数或浮点数

如果省略, 此命令将无限期等待. 否则, 它将等待不超过这个秒数的时间. 若要等待比秒更小的时间, 请指定一个浮点数, 例如, 0.25 等待最多 250 毫秒.

WaitFor

类型: 整数

如果省略, 则默认为 0(仅等待文本或文件). 否则, 请指定以下数字之一以表示要等待的内容:

0: 函数更具选择性, 明确地等待剪贴板中出现文本或文件("文本" 包含当您粘贴到记事本时会产生文本的任何内容).

1: 函数等待剪贴板中出现任何类型的数据.

其他值保留以供将来使用.

返回值

类型: 整数(布尔值)

如果函数超时, 返回 0(false), 否则(即剪贴板包含数据), 返回 1(true).

备注

使用此函数比您在一个循环中检查剪贴板是否为空要好. 这是由于此函数从不打开剪贴板, 因此执行地更好并且避免了对可能使用剪贴板的其他程序的干扰.

此函数把任何可转换成文本的内容(例如 HTML) 视为文本. 它也把文件( 例如从资源管理器窗口中通过 Ctrl+C 复制的文件) 视为文本. 每当在脚本中引用 Clipboard 变量时, 这些文件被自动转换成它们的文件名(完整路径). 有关详情, 请参阅 A_Clipboard.

当最后一个参数为 1 时, 剪贴板中出现任何数据, 就会满足函数的条件. 这种特性可以和 ClipboardAll 结合使用来保存像图片这样的非文本数据.

当函数处于等待状态时, 可以通过热键, 自定义菜单项或计时器启动新的线程.

相关

A_Clipboard, WinWait, KeyWait

示例

清空剪贴板, 将当前选区复制到剪贴板, 最多等待 2 秒, 直到剪贴板包含数据. 如果 ClipWait 超时, 将显示错误信息, 否则将显示剪贴板内容.

A_Clipboard := "" ; 清空剪贴板
Send "^c"
if !ClipWait(2)
{
    MsgBox "The attempt to copy text onto the clipboard failed."
    return
}
MsgBox "clipboard = " A_Clipboard
return


ComCall - 语法 & 使用 | AutoHotkey v2

ComCall

通过索引调用原生 COM 接口方法.

Result := ComCall(Index, ComObj , Type1, Arg1, Type2, Arg2, ReturnType)

参数

Index

类型: 整数

虚拟函数表中方法的索引(从零开始).

Index 对应于方法在原始接口定义中的位置. Microsoft 文档通常按字母顺序列出方法, 这是不相关的. 为了确定正确的索引, 请找到原来的接口定义. 这可能在头文件或类型库中.

考虑方法继承于的父接口是很重要的. 因为所有的 COM 接口最终都是从 IUnknown 派生出来的, 所以前三个方法总是 QueryInterface (0), AddRef (1) 和 Release (2). 例如, IShellItem2 是 IShellItem 的扩展, 它从索引 3 开始, 包含 5 个方法, 所以 IShellItem2 的第一个方法(GetPropertyStore) 的索引为 8.

提示: 对于微软定义的 COM 接口, 尝试在互联网或 Windows SDK 中搜索 "IInterfaceName Vtbl" - 例如, "IUnknownVtbl". Microsoft 自己的接口定义附带这个接口的虚拟函数表的纯-C 语言定义, 它以正确的顺序显式地列出了所有方法.

传递无效的索引可能会导致不确定的行为, 包括(但不限于) 程序终止.

ComObj

类型: 整数或对象

目标 COM 对象; 也就是说, 一个 COM 接口指针. 指针值可以直接传递, 也可以封装在带有 Ptr 属性的对象中, 如带有 VT_UNKNOWN 变量类型的 ComValue.

接口指针用于定位实现接口方法的虚拟函数的地址, 也作为参数传递. 这个参数通常不会在原生支持接口的语言中显式地出现, 而是在 C 言语风格的 "Vtbl" 定义中显示.

传递无效指针可能导致未定义的行为, 包括(但不限于) 程序终止.

Type1, Arg1

类型: 字符串

每一对值表示要传递给方法的单个参数. 对的数量是无限的. 有关 Type, 请参阅 DllCall 类型列表. 有关 Arg, 指定要传递给方法的值.

ReturnType

类型: 字符串

如果省略, 返回类型默认为 HRESULT, 这是 COM 接口方法最常用的返回类型. 任何指示失败的结果都会抛出 OSError; 因此, 除非实际的返回类型是 HRESULT, 否则不能省略返回类型.

如果方法是不返回值的类型(C 语言中的 void 返回类型), 则指定 "Int" 或不带任何后缀的其他数字类型(HRESULT 除外), 并忽略返回值. 在这种情况下, 由于返回值寄存器的内容是任意的, 所以如果省略了 ReturnType, 可能会也可能不会抛出异常.

否则, 指定 DllCall 类型列表中的一个参数类型. 支持星号后缀.

尽管 ComCall 和 DllCall 支持 Cdecl, 但它通常不在 COM 接口方法中使用.

返回值

类型: 字符串或整数

如果 ReturnType 是 HRESULT(或省略), 并且方法返回一个错误值(由 FAILED macro 定义), 则抛出 OSError.

否则, ComCall 将返回该方法返回的实际值. 如果方法是不返回值的类型(该返回类型在 C 语言中定义为 void), 则结果是未定义的, 应将其忽略.

备注

以下 DllCall 主题也适用于 ComCall:

  • 参数和返回值的类型
  • 错误
  • 原生异常和 A_LastError
  • 结构和数组
  • 已知限制
  • .NET Framework

相关

ComObject, ComObjQuery, ComValue, Buffer 对象, CallbackCreate

示例

从任务栏中删除活动窗口 3 秒钟. 可以与等效的 DllCall 示例进行比较.

/*
  ITaskbarList 虚拟函数列表中的方法:
    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 := ComObject(CLSID_TaskbarList, IID_ITaskbarList)

activeHwnd := WinExist("A")

ComCall(3, tbl)                     ; tbl.HrInit()
ComCall(5, tbl, "ptr", activeHwnd)  ; tbl.DeleteTab(activeHwnd)
Sleep 3000
ComCall(4, tbl, "ptr", activeHwnd)  ; tbl.AddTab(activeHwnd)

; 完成对象后, 只需将所有引用替换为
; 其他一些值(如果是局部变量, 就返回):
tbl := ""

演示一些包装 COM 接口的技术. 等同于上一个示例.

tbl := TaskbarList()

activeHwnd := WinExist("A")

tbl.DeleteTab(activeHwnd)
Sleep 3000
tbl.AddTab(activeHwnd)

tbl := ""

class TaskbarList {
   static IID := "{56FDF342-FD6D-11d0-958A-006097C9A090}"
   static CLSID := "{56FDF344-FD6D-11d0-958A-006097C9A090}"

   ; 在启动时调用, 以初始化类.
   static __new() {
       ; 获取 TaskbarList 的所有实例的基对象.
       proto := this.Prototype

       ; 绑定函数可用于预定义参数, 使
       ; 这些方法在不需要包装器函数的情况下更容易使用.
       ; HrInit 本身没有参数, 所以只绑定索引,
       ; 而调用者将隐式地提供 'this'.
       proto.HrInit := ComCall.Bind(3)

       ; 将参数留空, 让调用者提供一个值.
       ; 在本例中, 空白参数是 'this'(通常是隐藏的).
       proto.AddTab := ComCall.Bind(4,, "ptr")

       ; 可以使用对象或映射来减少重复.
       for name, args in Map(
           "DeleteTab", [5,,"ptr"],
           "ActivateTab", [6,,"ptr"],
           "SetActiveAlt", [7,,"ptr"]) {
           proto.%name% := ComCall.Bind(args*)
       }
   }

   ; 在新实例上由 TaskbarList() 调用.
   __new() {
        this.comobj := ComObject(TaskbarList.CLSID, TaskbarList.IID)
        this.ptr := this.comobj.ptr
       ; 通过 ITaskbarList 请求初始化.
       this.HrInit()
   }
}


ComObjActive - 语法 & 使用 | AutoHotkey v2

ComObjActive

检索注册的 COM 对象.

ComObj := ComObjActive(CLSID)

参数

CLSID

类型: 字符串

要检索的 COM 对象的 CLSID 或可读的 Prog ID.

返回值

类型: ComObject

该函数返回一个新的 COM 封装对象, 其变体类型为 VT_DISPATCH (9).

错误处理

失败时抛出异常.

相关

ComValue, ComObject, ComObjGet, ComObjConnect, ComObjFlags, ObjAddRef/ObjRelease, ComObjQuery, GetActiveObject (Microsoft Docs)

示例

如果 Microsoft Word 正在运行, 显示其活动文档的路径. 有关下面使用的 COM 对象和其属性的详情, 请参阅 Word.Application object (Microsoft Docs).

word := ComObjActive("Word.Application")
if !word
    MsgBox "Word isn't open."
else
    MsgBox word.ActiveDocument.FullName


ComObjArray - 语法 & 使用 | AutoHotkey v2

ComObjArray

创建用于 COM 的安全数组.

ArrayObj := ComObjArray(VarType, Count1 , Count2, ... Count8)

ComObjArray 本身是一个派生自 ComValue 的类, 但只用于创建或识别 SafeArray 封装对象.

参数
VarType

类型: 整数

数组的基类型(数组中每个元素的 VARTYPE). VARTYPE 被限制为变体类型的子集. 不能设置为 VT_ARRAY 或 VT_BYREF 标志. VT_EMPTY 和 VT_NULL 不是数组的有效基类型. 其他所有类型是合法的.

有关可用值的列表, 请参阅 ComObjType.

CountN

类型: 整数

每个维度的大小. 支持最多 8 维的数组.

返回值

类型: ComObjArray

函数返回一个包含新的安全数组的包装器对象.

方法

ComObjArray 对象支持下列方法:

  • .MaxIndex(n): 返回第 n 维的上界. 如果 n 省略, 默认为 1.
  • .MinIndex(n): 返回第 n 维的下界. 如果 n 省略, 默认为 1.
  • .Clone(): 返回数组的副本.
  • .__Enum(): 通常不由脚本调用; 允许 for-loop 与安全数组一起使用.

备注

ComObjArray 对象也可以由 COM 方法和 ComValue 返回. 脚本可以确定一个值是否是 ComObjArray, 如下所示:

; 检查类
if obj is ComObjArray
    MsgBox "Array subtype: " . ComObjType(obj) & 0xfff
else
    MsgBox "Not an array."

; 检查 VT_ARRAY
if ComObjType(obj) & 0x2000
    MsgBox "obj is a ComObjArray"

; 检查特定的数组类型
if ComObjType(obj) = 0x2008
    MsgBox "obj is a ComObjArray of strings"

可以支持多达 8 维的数组.

由于安全数组未被设计为支持多重引用, 故当一个安全数组被赋值为另一个安全数组的元素时, 会创建一个独立的副本. 不过, 仅当包装器对象含有 F_OWNVALUE 标志时才会发生这种情况, 这个标志表示它负责销毁此数组. 此标志可用 ComObjFlags 移除.

当被 COM 客户端调用的函数或方法返回一个带有 F_OWNVALUE 标志的安全数组时, 将建立并返回一个副本, 而原安全数组将自动销毁.

相关

ComValue, ComObjType, ComObjValue, ComObjActive, ComObjFlags, Array Manipulation Functions (Microsoft Docs)

示例

简单示例.

arr := ComObjArray(VT_VARIANT:=12, 3)
arr[0] := "Auto"
arr[1] := "Hot"
arr[2] := "key"
t := ""
Loop arr.MaxIndex() + 1
    t .= arr[A_Index-1]
MsgBox t

多维数组.

arr := ComObjArray(VT_VARIANT:=12, 3, 4)

; 获取数组的维数:
dim := DllCall("oleaut32\SafeArrayGetDim", "ptr", ComObjValue(arr))

; 得到每个维度的边界:
dims := ""
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 - 语法 & 使用 | AutoHotkey v2

ComObjConnect

将 COM 对象的事件源连接到脚本, 使事件能够被处理.

ComObjConnect ComObj , PrefixOrSink

参数

ComObj

类型: ComObject

产生事件的对象.

如果对象不支持 IConnectionPointContainer 接口, 或无法获取对象类的类型信息, 将显示一条错误信息. 可通过 try/catch 禁止或处理此错误信息.

如果对象支持, 使用 IProvideClassInfo 接口以接收此对象类的类型信息. 否则, ComObjConnect 尝试通过对象的 IDispatch 接口以接收类型信息, 这可能不可靠.

PrefixOrSink

类型: 字符串或对象

如果省略, 则对象为 "disconnected"; 即脚本将不再接收其事件通知. 否则, 当事件发生时, 指定一个用于确定调用哪个全局函数的前缀字符串, 或者一个事件接收对象, 为要处理的每个事件定义一个静态方法.

注意: 在此模式下不支持嵌套函数, 因为名称可能在当前函数返回后解析. 要使用嵌套函数或闭包, 请将它们附加到一个对象上, 并按照下面的描述传递该对象.

用法

为了有效地使用 ComObjConnect, 您必须首先在脚本中编写函数来处理任何感兴趣的事件. 这些函数或 "事件处理程序", 具有下列结构:

PrefixEventName([Params..., ComObj])
{
    ... 事件处理代码 ...
    return ReturnValue
}

如果是字符串, Prefix 应该与 PrefixOrSink 参数相同; 否则, 它应该被省略. EventName 应该替换为函数应该处理的任何事件的名称.

Params 对应于事件拥有的任何参数. 如果事件没有参数, 则应该完全忽略 Params. ComObj 是一个额外的参数, 它包含对传递给 ComObjConnect 的原始封装对象的引用, 它从未被包含在 COM 事件的文档中. "ComObj" 应该替换为在您的脚本上下文中更有意义的名称.

注意, 事件处理程序可能有返回值. 要返回特定的 COM 类型的值, 使用 ComValue(). 例如, return ComValue(0,0) 返回一个 VT_EMPTY 类型的变体, 相当于从一个 JavaScript 函数返回 undefined(或没有返回).

调用 ComObjConnect(yourObject, "Prefix") 来启用事件处理.

调用 ComObjConnect(yourObject) 来断开对象(停止处理事件).

如果参数的数目未知, 可以使用可变参数函数.

事件接收

如果 PrefixOrSink 是一个对象, 则每当引发事件时, 就会调用该对象的相应方法. 虽然对象可以动态构造, 但 PrefixOrSink 更典型的做法是引用一个类或类的实例. 在这种情况下, 方法的定义如上所示, 但没有 Prefix.

与对方法的任何调用一样, 方法的(通常是隐藏的) this 参数包含对方法调用所通过的对象的引用; 即事件接收器对象, 而不是 COM 对象. 这可用于为事件处理程序提供上下文, 或在它们之间共享值.

要捕获所有事件而不为每个事件定义方法, 请定义 __Call 元函数.

如果 COM 对象释放连接, ComObject 会自动释放它对 PrefixOrSink 的引用. 例如, Internet Explorer 在退出时就会这样做. 如果脚本不保留自己对 PrefixOrSink 的引用, 它可以使用 __Delete 来检测何时发生这种情况. 如果该对象由远程进程托管, 并且该进程意外终止, 则系统可能需要几分钟才能释放连接.

备注

脚本必须保留对 ComObj 的引用, 否则它将自动释放, 并与其 COM 对象断开连接, 从而阻止任何进一步的事件被检测到. 没有标准的方法来检测何时不再需要连接, 所以脚本必须通过调用 ComObjConnect 手动断开连接.

可能需要使用 Persistent 函数, 以便在脚本监听事件时保持脚本运行.

失败时抛出异常.

相关

ComObject, ComObjGet, ComObjActive, WScript.ConnectObject (Microsoft Docs)

示例

启动 Internet Explorer 的实例, 并将事件连接到相应的前缀为 "IE_" 的脚本函数. 有关 COM 对象和下面使用的 DocumentComplete 事件的详情, 请参阅 InternetExplorer object (Microsoft Docs).

ie := ComObject("InternetExplorer.Application")

; 将事件连接到相应的 "IE_" 为前缀的脚本函数.
ComObjConnect(ie, "IE_")

ie.Visible := true  ; 此语句在 IE7 中无法正常执行.
ie.Navigate("https://www.autohotkey.com/")
Persistent

IE_DocumentComplete(ieEventParam, &url, ieFinalParam) {
    ; IE 传递的 url 作为 VARIANT 的引用, 因此在上面使用 &url
    ; 以便下面的代码可以自然地引用它，而不是使用 %url%.
    s := ""
    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 (ComObjValue(ieEventParam) == ComObjValue(ieFinalParam))
        s .= "Both wrapper objects refer to the same IDispatch instance.`n"
    MsgBox s . "Finished loading " ie.Document.title " @ " url
    ie.Quit()
    ExitApp
}


ComObject - 语法 & 使用 | AutoHotkey v2

ComObject

创建 COM 对象.

ComObj := ComObject(CLSID , IID)

ComObject 本身是一个派生自 ComValue 的类, 但只用于创建或识别 COM 对象.

参数

CLSID

类型: 字符串

要创建的 COM 对象的 CLSID 或可读的 Prog ID.

IID

类型: 字符串

如果省略, 则默认为 "{00020400-0000-0000-C000-000000000046}"(IID_IDispatch). 否则, 指定要返回的接口的标识符. 在大多数情况下, 它是省略的.

返回值

类型: Object

该函数返回一个 COM 包装器对象, 其类型取决于 IID 参数.

IID | Class | 变体类型 | 描述
IID_IDispatch | ComObject | VT_DISPATCH (9) | 允许脚本使用普通的对象语法来调用对象的属性和方法.
任意其他 IID | ComValue | VT_UNKNOWN (13) | 只提供一个 Ptr 属性, 允许对象被传递给 DllCall 或 ComCall.

错误处理

失败时抛出异常, 例如参数无效或对象不支持由 IID 指定的接口.

相关

ComValue, ComObjGet, ComObjActive, ComObjConnect, ComObjArray, ComObjQuery, ComCall, CreateObject (Microsoft Docs)

示例

有关 v1.1 更多的示例列表, 请参阅: 这个论坛主题.

启动 Internet Explorer 实例, 使其可见并导航到一个网站.

ie := ComObject("InternetExplorer.Application")
ie.Visible := true  ; 此语句在 IE7 中无法正常执行.
ie.Navigate("https://www.autohotkey.com/")

检索桌面当前壁纸的路径.

AD_GETWP_BMP := 0
AD_GETWP_LAST_APPLIED := 0x00000002
CLSID_ActiveDesktop := "{75048700-EF1F-11D0-9888-006097DEACF9}"
IID_IActiveDesktop := "{F490EB00-1240-11D1-9888-006097DEACF9}"
cchWallpaper := 260
GetWallpaper := 4

AD := ComObject(CLSID_ActiveDesktop, IID_IActiveDesktop)
wszWallpaper := Buffer(cchWallpaper * 2)
ComCall(GetWallpaper, AD, "ptr", wszWallpaper, "uint", cchWallpaper, "uint", AD_GETWP_LAST_APPLIED)
Wallpaper := StrGet(wszWallpaper, "UTF-16")
MsgBox "Wallpaper: " Wallpaper


ComObjFlags - 语法 & 使用 | AutoHotkey v2

ComObjFlags

获取或改变控制 COM 包装器对象行为的标志.

Flags := ComObjFlags(ComObj , NewFlags, Mask)

参数

ComObj

类型: Object

COM 包装器对象. 有关详情, 请参阅 ComValue.

NewFlags

类型: 整数

由 Mask 标识的 flags 的新值, 或要添加或删除的 flags.

Mask

类型: 整数

更改 flags 的位掩码.

返回值

类型: 整数

此函数返回指定 COM 对象的当前标志(如果指定, 在应用 NewFlags 之后).

错误处理

如果 ComObj 不是 COM 包装对象, 则抛出 TypeError.

Flags

Flag 效果
1

F_OWNVALUE

SafeArray: 如果设置了 flag, 则在释放包装对象时, 会销毁 SafeArray. 由于 SafeArrays 没有引用计数机制, 因此, 如果将带有 flag 的 SafeArray 赋值给另一个 SafeArray 的元素, 则会创建一个单独的副本.

BSTR: 如果设置了 flag, 则在释放包装对象时, 会释放 BSTR. 当 BSTR 作为由 ComValue(如 ComValue(8, "example")) 执行的类型转换的结果被分配时, 该 flag(标志) 被自动设置.

备注

如果省略 Mask, 则 NewFlags 指定需要添加的(正数) 或移除的(负数) flags. 例如, ComObjFlags(obj, -1) 移除 F_OWNVALUE flag. 不要为 Mask 指定 0 或 1 以外的任何值; 所有其他位保留供将来使用.

相关

ComValue, 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"


ComObjFromPtr - 语法 & 使用 | AutoHotkey v2

ComObjFromPtr

包装一个原始 IDispatch 指针(COM 对象), 以供脚本使用.

ComObj := ComObjFromPtr(DispPtr)

参数

DispPtr

类型: 整数

IDispatch 或派生接口的一个非空接口指针.

返回值

类型: ComObject

返回一个包含变体类型 VT_DISPATCH 和给定指针的封装对象.

封装一个 COM 对象可以使脚本更自然地使用对象语法与之交互. 然而, 大多数脚本都不需要手动操作, 因为 ComObject, ComObjActive, ComObjGet 和任何返回对象的 COM 方法都会自动创建一个包装对象.

备注

封装器对象在适当的时候承担自动释放指针的责任. 函数查询对象的 IDispatch 接口; 如果返回一个接口, DispPtr 将被立即释放. 因此, 如果脚本打算在调用此函数后使用指针, 它必须先调用 ObjAddRef(DispPtr) first.

已知限制: 每次包装 COM 对象时, 都会创建新的包装器对象. 如 obj1 == obj2 和 arr[obj1] := value 这样的比较和赋值运算, 将这两个包装器对象视为唯一的, 即使它们包含相同的 COM 对象.

相关

ComObject, ComValue, ComObjGet, ComObjConnect, ComObjFlags, ObjAddRef/ObjRelease, ComObjQuery, GetActiveObject (Microsoft Docs)


ComObjGet - 语法 & 使用 | AutoHotkey v2

ComObjGet

返回对 COM 组件提供的对象的引用.

ComObj := ComObjGet(Name)

参数

Name

类型: 字符串

要检索的对象的显示名称. 有关详情, 请参阅 MkParseDisplayName (Microsoft Docs).

返回值

类型: ComObject

此函数返回新的 COM 包装对象, 其变体类型为 VT_DISPATCH (9).

错误处理

失败时抛出异常.

相关

ComObject, ComObjActive, ComObjConnect, ComObjQuery, CoGetObject (Microsoft Docs)

示例

按下 Shift+Esc 来显示活动窗口进程的命令行. 有关 Win32_Process, 请参阅 Microsoft Docs.

+Esc::
{
    pid := WinGetPID("A")
    ; 获取 WMI 服务对象.
    wmi := ComObjGet("winmgmts:")
    ; 执行查询以获取匹配进程.
    queryEnum := wmi.ExecQuery(""
        . "Select * from Win32_Process where ProcessId=" . pid)
        ._NewEnum()
    ; 获取首个匹配进程.
    if queryEnum(&proc)
        MsgBox(proc.CommandLine, "Command line", 0)
    else
        MsgBox("Process not found!")
}


ComObjQuery - 语法 & 使用 | AutoHotkey v2

ComObjQuery

查询 COM 对象的接口或服务.

InterfaceComObj := ComObjQuery(ComObj, SID, IID)
InterfaceComObj := ComObjQuery(ComObj, IID)

参数

ComObj

类型: 对象, 或整数

COM 包装器对象, 接口指针或一个具有 Ptr 属性的对象, 该属性返回一个接口指针. 有关详情, 请参阅 ComValue.

IID

类型: 字符串

格式为 "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" 的接口标识符(GUID).

SID

类型: 字符串

与 IID 格式相同的服务标识符.

返回值

类型: Object

这个函数返回一个类型依赖于 IID 参数的 COM 包装器对象.

IID | Class | Variant 类型 | 描述
IID_IDispatch | ComObject | VT_DISPATCH (9) | 允许脚本使用正常的对象语法调用对象的属性和方法.
任意其他 IID | ComValue | VT_UNKNOWN (13) | 只提供 Ptr 属性, 该属性允许将对象传递给 DllCall 或 ComCall.

错误处理

失败时抛出异常, 例如接口不受支持.

备注

在此函数使用两个参数时, 它相当于 IUnknown::QueryInterface. 如果同时指定了 SID 和 IID, 那么它会内部查询 IServiceProvider 接口, 然后调用 IServiceProvider::QueryService.

ComCall 可以用来调用原生接口方法.

相关

ComCall, ComObject, ComObjGet, ComObjActive

示例

确定对象的类名.

obj := ComObject("Scripting.Dictionary")

MsgBox "Interface name: " ComObjType(obj, "name")

IID_IProvideClassInfo := "{B196B283-BAB4-101A-B69C-00AA00341D07}"

; 请求对象的 IProvideClassInfo 接口.
try
    pci := ComObjQuery(obj, IID_IProvideClassInfo)
catch
{
    MsgBox "IProvideClassInfo interface not supported."
    return
}

; 调用 GetClassInfo 来获取 ITypeInfo 接口的指针.
ComCall(3, pci, "ptr*", &ti := 0)

; 封装 ti 以确保自动清理.
ti := ComValue(13, ti)

; 调用 GetDocumentation 来获取对象的完整类型名称.
ComCall(12, ti, "int", -1, "ptr*", &pname := 0, "ptr", 0, "ptr", 0, "ptr", 0)

; 转换 BSTR 指针为可用的字符串.
name := StrGet(pname, "UTF-16")

; 清理.
DllCall("oleaut32\SysFreeString", "ptr", pname)
pci := ti := ""

; 显示类型名称!
MsgBox "Class name: " name

自动化现有的 Internet Explorer 窗口.

sURL := "https://www.autohotkey.com/boards/"
if WebBrowser := GetWebBrowser()
    WebBrowser.Navigate(sURL)

GetWebBrowser()
{
    ; 获取指向顶部 IE 窗口的文档对象的原始指针.
    static msg := DllCall("RegisterWindowMessage", "Str", "WM_HTML_GETOBJECT")
    lResult := SendMessage(msg, 0, 0, "Internet Explorer_Server1", "ahk_class IEFrame")
    if !lResult
        return  ; 未找到 IE.
    static IID_IHTMLDocument2 := GUID("{332C4425-26CB-11D0-B483-00C04FD90119}")
    static VT_UNKNOWN := 13
    DllCall("oleacc\ObjectFromLresult", "Ptr", lResult
        , "Ptr", IID_IHTMLDocument2, "Ptr", 0
        , "Ptr*", pdoc := ComValue(VT_UNKNOWN, 0))

    ; 查询 WebBrowserApp 服务. 在这种特殊情况中,
    ; SID 和 IID 相同, 但不总是如此.
    static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}"
    static SID_SWebBrowserApp := IID_IWebBrowserApp
    pweb := ComObjQuery(pdoc, SID_SWebBrowserApp, IID_IWebBrowserApp)

    ; 为了便于使用, 将 WebBrowser 对象返回为 IDispatch.
    ; 这只是因为 IWebBrowserApp 是由 IDispatch 派生出来的.
    ; pweb 会自动释放它的 ptr, 所以用 AddRef 来计数.
    ObjAddRef(pweb.ptr)
    static VT_DISPATCH := 9
    return ComValue(VT_DISPATCH, pweb.ptr)
}

GUID(sGUID) ; 转换字符串为二进制的 GUID 并返回其缓冲.
{
    GUID := Buffer(16, 0)
    if DllCall("ole32\CLSIDFromString", "WStr", sGUID, "Ptr", GUID) < 0
        throw ValueError("Invalid parameter #1", -1, sGUID)
    return GUID
}


ComObjType - 语法 & 使用 | AutoHotkey v2

ComObjType

从 COM 对象检索类型信息.

Info := ComObjType(ComObj , InfoType)

参数

ComObj

类型: Object

包含 COM 对象或类型化值的包装器对象. 有关详情, 请参阅 ComValue.

InfoType

类型: 字符串

如果省略, 整数变量类型码, 其指示了 COM 包装器对象所包含的值的类型. 否则, 请指定以下字符串之一, 指示要检索的类型信息:

Name: 对象默认接口的名称.

IID: 对象默认接口的全局唯一标识符(GUID).

Class: 对象的类名. 注意, 这不同于 Prog ID(Prog ID 是用于在系统注册表或 ComObject 中标识类的名称).

CLSID: 对象的类的全局唯一标示符(GUID). 类通常由 CLSID 在 HKCR\CLSID 注册表项下注册.

返回值

类型: 整数或字符串

返回值依赖于 InfoType 的值. 如果参数无效或指定的类型信息无法取回, 则返回空字符串.

Variant(变体) 类型常量

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  ; 错误码(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 对象包装器.

如果 InfoType 是 "Name" 或 "IID", 则通过 IDispatch::GetTypeInfo 接口方法检索类型信息. ComObj 的变体类型必须是 VT_DISPATCH.

如果 InfoType 是 "Class" 或 "CLSID", 则通过 IProvideClassInfo::GetClassInfo 接口方法检索类型信息. ComObj 的变体类型必须是 VT_DISPATCH 或 VT_UNKNOWN, 该对象必须实现 IProvideClassInfo 接口(有些对象没有实现).

相关

ComObjValue, ComValue, ComObject, ComObjGet, ComObjActive

示例

报告 COM 对象的各种类型信息.

d := ComObject("Scripting.Dictionary")
MsgBox
(
    "Variant type:`t" ComObjType(d) "
    Interface name:`t" ComObjType(d, "Name") "
    Interface ID:`t" ComObjType(d, "IID") "
    Class name:`t" ComObjType(d, "Class") "
    Class ID (CLSID):`t" ComObjType(d, "CLSID")
)


ComObjValue - 语法 & 使用 | AutoHotkey v2

ComObjValue

检索存储在 COM 包装器对象中的值或指针.

Value := ComObjValue(ComObj)

参数

ComObj

类型: Object

包含 COM 对象或类型化值的包装器对象. 有关详情, 请参阅 ComValue.

返回值

类型: 整数

函数返回 64 位有符号整数.

错误处理

如果 ComObj 不是 COM 包装对象, 则抛出 TypeError.

备注

此函数并非计划用于一般用途.

调用 ComObjValue 等同于 variant.llVal, 这里 ComObj 被视为 VARIANT 结构. 使用此函数的脚本必须注意到包装器对象包含的值类型以及对它应该如何处理. 例如, 如果返回接口指针, 则不应该调用 Release, 不过根据脚本对指针进行的操作, 可能需要 AddRef.

相关

ComObjType, ComObject, ComObjGet, ComObjActive


ComValue - 语法 & 使用 | AutoHotkey v2

ComValue

包装一个值, 安全数组或 COM 对象, 以供脚本使用或传递给 COM 方法.

ComObj := ComValue(VarType, Value , Flags)

ComValue 本身是一个派生自 Any 的类, 但只用于创建或识别 COM 封装对象.

参数

VarType

类型: 整数

表示值类型的整数. 类型列表见 ComObjType.

Value

类型: Any

要包装的值.

如果这是一个纯整数且 VarType 不是 VT_R4, VT_R8, VT_DATE 或 VT_CY, 则直接使用其值; 特别是 VT_BSTR, VT_DISPATCH 和 VT_UNKNOWN 可以用一个指针值来初始化.

在任何其他情况下, 使用与普通 COM 方法调用相同的规则将值复制到临时 VARIANT 中. 如果源变量类型不等于 VarType, 则通过调用 wFlags 值为 0 的 VariantChangeType 来尝试转换. 如果转换失败, 则抛出异常.

Flags

类型: 整数

影响包装器对象行为的标志; 有关详情, 请参阅 ComObjFlags.

返回值

类型: Object

此函数返回包含变体类型和值或指针的封装对象, 尤其是 ComValue, ComValueRef, ComObjArray 或 ComObject.

该对象有多个用途:

  1. 某些 COM 方法可能需要特定类型的值, 这些值在 AutoHotkey 中没有直接等效的值. 此函数允许在将值传递给 COM 方法时指定值的类型. 例如, ComValue(0xB, -1) 创建一个表示 COM 布尔值为 true 的对象.
  2. 通过封装 COM 对象或 SafeArray, 脚本可以使用对象语法更自然地与其交互. 但是, 大多数脚本不需要手动执行此操作, 因为封装对象是由 ComObject, ComObjArray, ComObjActive, ComObjGet 和任何返回对象的 COM 方法自动创建的.
  3. 封装 COM 接口指针允许脚本利用自动引用计数. 接口指针可以在返回到脚本时立即包装(通常是从 ComCall 或 DllCall 返回), 避免在稍后的某个点需要显式释放它.

Ptr

如果一个封装对象的 VarType 是 VT_UNKNOWN(13) 或包含 VT_BYREF(0x4000) 或 VT_ARRAY(0x2000) 标志, 则 Ptr 属性可用于检索对象, 类型化变量或安全数组的地址. 这允许将 ComObject 本身传递给任何具有 "Ptr" 类型的 DllCall 或 ComCall 参数, 但也可以显式地使用. 例如, 在这些情况下, ComObj.Ptr 等同于 ComObjValue(ComObj).

如果一个封装对象的 VarType 是 VT_UNKNOWN(13) 或 VT_DISPATCH(9) 并且封装指针为 null(0), 则可以使用 Ptr 属性来检索当前的 null 值, 或者为封装对象赋值一个指针. 一旦被赋值(如果非-null), 当封装对象被释放时, 指针将被自动释放. 这可以与类型为 "Ptr*" 或 "PtrP" 的 DllCall 或 ComCall 输出参数一起使用, 以确保指针会被自动释放, 例如当发生错误时. 有关示例, 请参阅 ComObjQuery.

如果一个包装器对象的 VarType 是 VT_DISPATCH(9) 并且为 null(0) 指针值赋值为非-null 指针值, 其类型从 ComValue 变为 ComObject. 包装对象的属性和方法变得可用, 而 Ptr 属性变为不可用.

ByRef

如果包装器对象的 VarType 包含 VT_BYREF(0x4000) 标志, 可以用空的方括号对 [] 来读写引用的值.

当创建一个引用, Value 须为变量的内存地址, 或足够存储指定类型的值的缓冲. 例如, 下面的代码可以用来创建一个 VBScript 函数可以写入的变量:

vbuf := Buffer(24, 0)
vref := ComValue(0x400C, vbuf.ptr)  ; 0x400C 为 VT_BYREF 与 VT_VARIANT 组合而得.

vref[] := "in value"
sc.Run("Example", vref)  ; sc  应像下面例子一样进行初始化.
MsgBox vref[]

请注意, 尽管在通过 vref[] 或 COM 方法分配新值时, 任何先前的值都会被释放, 但最终的值不会被自动释放. 释放该值需要知道它是哪种类型. 因为在这种情况下它是 VT_VARIANT, 它可以通过用 DllCall 调用 VariantClear 来释放, 或者使用更简单的方法: 分配一个整数, 如 vref[] := 0.

如果方法接受如上所示的 VT_BYREF 和 VT_VARIANT 的组合, 可以使用 VarRef 代替. 例如:

some_var := "in value"
sc.Run("Example", &some_var)
MsgBox some_var

然而, 有些方法需要更特定的变体类型, 如 VT_BYREF | VT_I4. 在这种情况下, 必须使用上面所示的第一种方法, 用适当的变体类型替换 0x400C.

一般说明

当此函数用于包装 IDispatch 或 IUnknown 接口指针(以整数形式传递) 时, 包装器对象负责在适当的时候自动释放指针. 因此, 如果脚本打算在调用这个函数之后使用指针, 它必须首先调用 ObjAddRef(DispPtr). 相比之下, 如果 Value 本身是 ComValue 或 ComObject, 则没有必要这样做.

从 VT_UNKNOWN 到 VT_DISPATCH 的转换会导致对 IUnknown::QueryInterface 的调用, 这可能会产生一个不同于原来的接口指针, 并且如果对象没有实现 IDispatch, 会抛出异常. 相反, 如果 Value 是整数, 且 VarType 为 VT_DISPATCH, 则直接使用该值, 因此必须是一个 idispatch 兼容的接口指针.

可以使用 ComObjType 检索包装器对象的 VarType.

可以使用 ComObjValue 检索包装器对象的 Value.

已知限制: 每次包装 COM 对象时, 都会创建新的包装器对象. 如 obj1 == obj2 和 arr[obj1] := value 这样的比较和赋值运算, 将这两个包装器对象视为唯一的, 即使它们包含相同的变体类型和值.

相关

ComObjFromPtr, ComObject, ComObjGet, ComObjConnect, ComObjFlags, ObjAddRef/ObjRelease, ComObjQuery, GetActiveObject (Microsoft Docs)

示例

传递 VARIANT ByRef 给 COM 函数.

#Requires AutoHotkey v2 32-bit ; 32-bit for ScriptControl.
code := "
(
Sub Example(Var)
    MsgBox Var
    Var = "out value!"
End Sub
)"
sc := ComObject("ScriptControl"), sc.Language := "VBScript", sc.AddCode(code)

; 示例: 传递 VARIANT ByRef 至 COM 方法.
var := ComVar()
var[] := "in value"
sc.Run("Example", var.ref)
MsgBox var[]

; 同样的事情, 但更直接:
variant_buf := Buffer(24, 0)  ; 使 VARIANT 的缓冲足够大.
var := ComValue(0x400C, variant_buf.ptr)  ; 引用 VARIANT.
var[] := "in value"
sc.Run("Example", var)  ; 传递 VT_BYREF ComValue 本身, 没有 [] 或 .ref.
MsgBox var[]
; 如果 VARIANT 包含一个字符串或对象, 必须显式地释放它
; 通过调用 VariantClear 或赋值一个纯数字值:
var[] := 0

; 当方法接受 VT_BYREF|VT_VARIANT 时的最简单方法:
var := "in value"
sc.Run("Example", &var)
MsgBox var

; ComVar: 一个可以用来传递一个值 ByRef 的对象.
;   this[] 检索值.
;   this[] := Val 设置值.
;   this.ref 检索一个 ByRef 对象, 用于传递给一个 COM 方法.
class ComVar {
    __new(vType := 0xC) {
        ; 为 VARIANT 分配内存, 以保存我们的值.
        ; 即使在 vType != VT_VARIANT 时也会使用 VARIANT, 这样 VariantClear 就可以被 __delete 使用.
        this.var := Buffer(24, 0)
        ; 创建一个可以用来传递变量 ByRef 的对象.
        this.ref := ComValue(0x4000|vType, this.var.ptr + (vType=0xC ? 0 : 8))
        ; 存储 VariantClear 的变体类型(如果不是 VT_VARIANT).
        if vType != 0xC
            NumPut "ushort", vType, this.var
    }
    __item {
        get => this.ref[]
        set => this.ref[] := value
    }
    __delete() {
        DllCall("oleaut32\VariantClear", "ptr", this.var)
    }
}


Continue - 语法 & 使用 | AutoHotkey v2

Continue

跳过当前循环语句的剩余部分并继续下一次循环.

Continue LoopLabel

参数

LoopLabel
如果省略或为 1, 此语句应用于它所在的最内层循环. 否则, 指定该语句应该应用于哪个循环; 这是通过标签名或嵌套层级的数值来实现的. 如果指定了标签, 则它必须直接指向循环语句.

LoopLabel 必须为常量, 不支持变量和表达式, 但括号中的单个原义数字或用圆括号括起来的字符串除外, 例如: continue("outer").

备注

Continue 的行为如同直接到达了循环的闭括号:

  1. 它跳过了循环体的剩余部分.
  2. 计算循环的 Until 表达式(如果有).
  3. 它让 A_Index 加 1.
  4. 检查循环条件(如果有) 判断是否满足. 如果满足, 开始新的循环; 否则循环结束.

鼓励使用 Break 和 Continue 代替 Goto 因为它们通常让脚本更容易阅读和维护.

相关

Break, Loop, Until, While-loop, For-loop, 区块, 标签

示例

显示 5 次消息框, 为从 6 到 10 的每个数字显示一次. 注意 Loop 的前 5 次循, Continue 语句会使得循环在到达 MsgBox 行前重新开始.

Loop 10
{
    if (A_Index <= 5)
        continue
    MsgBox A_Index
}

从内嵌循环内部直接继续新的外层(outer) 循环.

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 命令.
}


控件函数列表 | AutoHotkey v2

控件函数

用于检索有关控件的信息, 或对控件进行各种操作的函数. 单击函数名查看详细信息.

函数 | 描述
ControlAddItem | 添加指定的字符串作为 ListBox(列表框) 或 ComboBox(组合框) 底部的新条目.
ControlChooseIndex | 将列表框, 组合框或标签页控件中的选择设置为第 N 项.
ControlChooseString | 将 ListBox 或 ComboBox 中的选择设置为其开头部分与指定字符串匹配的第一个条目.
ControlClick | 发送鼠标按钮或鼠标滚轮事件到控件.
ControlDeleteItem | 从 ListBox 或 ComboBox 中删除指定的条目.
ControlFindItem | 返回与指定字符串完全匹配的 ListBox 或 ComboBox 的条目的编号.
ControlFocus | 设置输入焦点到窗口的指定控件上.
ControlGetChecked | 如果选中复选框或单选按钮, 则返回非零值.
ControlGetChoice | 返回列表框或组合框中当前选定项的名称.
ControlGetClassNN | 返回指定控件的 ClassNN(类名和序号).
ControlGetEnabled | 如果指定的控件是启用的, 则返回非零值.
ControlGetFocus | 如果有, 则获取目标窗口中具有输入焦点的控件.
ControlGetHwnd | 返回指定控件的唯一 ID.
ControlGetIndex | 返回 ListBox, ComboBox 或 Tab 控件中当前选中的条目或标签的索引.
ControlGetItems | 返回 ListBox, ComboBox 或 DropDownList 中的项目/行数组.
ControlGetPos | 获取控件的位置和大小.
ControlGetStyle ControlGetExStyle | 返回表示指定控件样式或扩展样式的整数.
ControlGetText | 从控件检索文本.
ControlGetVisible | 如果指定的控件可见, 则返回非零值.
ControlHide | 隐藏指定控件.
ControlHideDropDown | 隐藏 ComboBox 控件的下拉列表.
ControlMove | 移动或调整控件.
ControlSend ControlSendText | 向窗口或控件发送模拟的击键或文本.
ControlSetChecked | 打开(选中) 或关闭(取消选中) 复选框或单选按钮.
ControlSetEnabled | 启用或禁用指定的控件.
ControlSetStyle ControlSetExStyle | 分别更改指定控件的样式或扩展样式.
ControlSetText | 更改控件的文本.
ControlShow | 如果指定的控件先前是隐藏的, 则显示该控件.
ControlShowDropDown | 显示 ComboBox 控件的下拉列表.
EditGetCurrentCol | 返回编辑控件中插入点所在的列号.
EditGetCurrentLine | 返回编辑控件中插入点所在的行号.
EditGetLine | 返回 Edit 控件中指定行的文本.
EditGetLineCount | 返回 Edit 控件的行数.
EditGetSelectedText | 返回 Edit 控件中选定的文本.
EditPaste | 将指定的字符串粘贴到 Edit 控件中的插入符号(文本插入点) 处.
ListViewGetContent | 返回列表视图中的项目/行列表.

Control 参数

操作单个控件的函数有一个名为 Control 的参数, 该参数支持几种不同的方法来识别控件. Control 参数可以是以下参数之一:

ClassNN(字符串): 控件的 ClassNN(类名和实例号), 可以通过 Window Spy 来确定. 例如 "Edit1" 是类名为 "Edit" 的第一个控件.

Text(字符串): 控件的文本. 匹配行为由 SetTitleMatchMode 决定.

HWND(整数): 控件的 HWND, 通常通过 ControlGetHwnd, MouseGetPos 或 DllCall 检索. 这也适用于隐藏控件, 即使 DetectHiddenWindows 关闭. 任何后续的窗口参数都被忽略.

Object: 具有 Hwnd 属性的任何类型的对象, 如 GuiControl. 如果对象没有 Hwnd 属性, 则抛出 PropertyError, 或不返回纯整数, 则抛出 TypeError. 任何后续的窗口参数都将被忽略.

省略: 一些函数可以操作控件或顶级窗口. 省略 Control 参数会导致函数使用目标窗口(由 WinTitle 指定) 而不是它的一个控件. 例如, ControlSend 可以直接发送键盘消息到窗口.

错误处理

通常情况下, 可能会抛出以下错误之一:

  • TargetError: 找不到目标窗口或控件.
  • Error 或 OSError: 在执行该函数的目的时出现了问题, 例如检索设置或应用更改.
  • ValueError 或 TypeError: 检测到无效参数.

备注

为了提高可靠性, 在每次使用更改控件的控件函数(除了 ControlSetStyle 和 ControlSetExStyle 外) 之后, 会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

要发现鼠标当前悬停的控件的 ClassNN 或 HWND, 请使用 MouseGetPos.

要检索窗口中所有控件的数组, 请使用 WinGetControls 或 WinGetControlsHwnd.

相关

SetControlDelay, 窗口函数, GuiControl 对象(用于由脚本创建的控件)


ControlAddItem - 语法 & 使用 | AutoHotkey v2

ControlAddItem

添加指定的字符串作为 ListBox(列表框) 或 ComboBox(组合框) 底部的新条目.

ControlAddItem String, Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

String

类型: 字符串

要添加的字符串.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

函数返回新项目的索引, 其中 1 是第一项, 2 是第二项, 以此类推.

错误处理

如果找不到窗口或控件, 或者控件的类名不包含 "Combo" 或 "List", 则抛出 TargetError.

如果项目无法添加, 则抛出 Error 或 OSError.

备注

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlDeleteItem, ControlFindItem, Add 方法(GuiControl 对象), 控件函数


ControlChooseIndex - 语法 & 使用 | AutoHotkey v2

ControlChooseIndex

将列表框, 组合框或标签页控件中的选择设置第 N 项.

ControlChooseIndex N, Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

N

类型: 整数

项目的索引, 其中 1 是第一项, 2 是第二项, 以此类推. 若要选择 ListBox 或 ComboBox 中的所有条目, 则指定 0.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 或者控件的类名不包含 "Combo", "List" 或 "Tab", 则抛出 TargetError.

如果无法应用更改, 则抛出 Error 或 OSError.

备注

要选择 多选 列表框中的所有项目, 请遵循以下示例:

PostMessage(0x0185, 1, -1, "ListBox1", WinTitle)  ; 选择列表框所有项. 0x0185 是 LB_SETSEL.

与 GuiControl.Choose() 不同, 此函数引发 Change 或 DoubleClick 事件.

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlGetIndex, ControlChooseString, Choose 方法(GuiControl 对象), 控件函数


ControlChooseString - 语法 & 使用 | AutoHotkey v2

ControlChooseString

将 ListBox 或 ComboBox 中的选择设置为其前导部分与指定字符串匹配的第一个条目.

ControlChooseString String, Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

String

类型: 字符串

要选择的字符串. 搜索不区分大小写. 例如, 如果一个 ListBox/ComboBox 包含项目 "UNIX Text", 指定单词 unix(小写) 足以选中它.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

函数返回选中项目的索引, 其中 1 是第一项, 2 是第二项, 以此类推.

错误处理

如果找不到窗口或控件, 或者控件的类名不包含 "Combo" 或 "List", 则抛出 TargetError.

如果无法应用更改, 则抛出 Error 或 OSError.

备注

与 GuiControl.Choose() 不同, 此函数引发 Change 或 DoubleClick 事件.

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlChooseIndex, ControlGetChoice, Choose 方法(GuiControl 对象), 控件函数


ControlClick - 语法 & 使用 | AutoHotkey v2

ControlClick

发送鼠标按钮或鼠标滚轮事件到控件.

ControlClick Control-or-Pos, WinTitle, WinText, WhichButton, ClickCount, Options, ExcludeTitle, ExcludeText

参数

Control-or-Pos

类型: 字符串, 整数或对象

如果省略, 则目标窗口本身将被点击. 否则, 使用以下模式之一.

模式 1(位置): 指定相对于目标窗口客户端区域左上角的 X 和 Y 坐标. X 坐标必须在 Y 坐标之前, 并且它们之间必须至少有一个空格或制表符. 例如: X55 Y33. 如果在指定的坐标上有一个控件, 它将在这些确切的坐标上发送点击事件. 如果没有控件, 目标窗口本身将被发送事件(根据窗口的性质, 可能没有效果).

注意: 在模式 1 中, 会忽略 Options 参数中的 X 和 Y 字母选项.

模式 2(控件): 指定控件的 ClassNN, 文本或 HWND, 或一个具有 Hwnd 属性的对象. 有关详情, 请参阅控件的参数.

默认情况下, 模式 2 优先于模式 1. 例如, 在一种不太可能发生的情况中某个控件的文本或 ClassNN 格式为 "Xnnn Ynnn", 那么此时会使用模式 2. 要覆盖此行为而无条件使用模式 1, 请在 Options中加上单词 Pos, 如下例所示: ControlClick "x255 y152", WinTitle,,,, "Pos".

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

WhichButton

类型: 字符串

如果为空或省略, 默认为 Left(鼠标左键). 否则, 指定要单击的按钮或鼠标滚轮的旋转/推入方向.

鼠标按钮: Left, Right, Middle(或这些单词的首字母); X1(第四个按钮) 或 X2(第五个按钮).

鼠标滚轮: 指定 WheelUp 或 WU 使滚轮向上转动(远离你); 指定 WheelDown(或 WD) 使滚轮向下转动(朝向你). 指定 WheelLeft(或 WL) 或 WheelRight(或 WR) 分别向左或向右滚动滚轮. ClickCount 是转动滚轮的格数.

ClickCount

类型: 整数

如果省略, 默认为 1. 否则, 请指定单击鼠标按钮或转动鼠标滚轮的次数.

Options

类型: 字符串

如果为空或省略, 则每次点击由 "按下" 事件后接着 "弹起" 事件组成, 并且在模式 2 生效时发生在控件的中心. 否则, 请指定一个或多个下列选项组成的系列. 例如: "d x50 y25"

NA: 也许可以提高可靠性. 请参阅后面的可靠性.

D: 按住鼠标按钮不放(即生成按下事件). 如果 D 和 U 选项都没有, 则会发送完整的点击事件(按下事件和弹起事件).

U: 释放鼠标按钮(即生成弹起事件). 此选项不能和 D 选项同时使用.

Pos: 在 Options 的任意位置指定单词 Pos, 这样会无条件使用 Control-or-Pos 参数中描述的 X/Y 位置模式.

X n: 指定 n 为要点击的相对于控件左上角的 X 坐标. 如果未指定, 则在控件的水平中心点击.

Y n: 指定 n 为要点击的相对于控件左上角的 Y 坐标. 如果未指定, 则在控件的垂直中心点击.

X 和 Y 选项中使用十进制(不是十六进制数) 数字.

错误处理

在以下情况下会抛出异常:

  • TargetError: 找不到目标窗口.
  • TargetError: 找不到目标控件, 且 Control-or-Pos 没有指定有效的位置.
  • OSError(非常罕见): X 或 Y 位置被省略, 且无法确定控件的位置.
  • ValueError 或 TypeError: 检测到无效参数.

可靠性

要提高可靠性, 尤其是在 ControlClick 期间用户同时在使用鼠标, 请尝试下面的一种或两种方法也许会有所帮助:

1) 在 ControlClick 前, 使用 SetControlDelay -1. 这样可以避免在点击时按住鼠标, 减少对用户使用鼠标的干扰.

2) 在第六个参数(Options) 中指定字符串 NA, 如下所示:

SetControlDelay -1
ControlClick "Toolbar321", WinTitle,,,, "NA"

NA 选项可以避免激活目标窗口, 同时避免混淆它和脚本的输入, 这样可以防止鼠标实际移动产生的冲突(但通常只在目标窗口不活动时). 然而, 此方法不是对所有的窗口和控件都有效.

备注

并非所有的应用程序都遵守 ClickCount 大于 1 的方式来转动鼠标滚轮. 对于这些应用, 使用 Loop 来转动多个格数, 例如这个例子转动 5 格:

Loop 5
    ControlClick Control, WinTitle, WinText, "WheelUp"

相关

SetControlDelay, 控件函数, Click

示例

点击 OK 按钮.

ControlClick "OK", "Some Window Title"

在坐标上进行点击. 注意 X 和 Y 之间没有逗号.

ControlClick "x55 y77", "Some Window Title"

使用 NA 模式在相对于命名控件的坐标处进行点击.

SetControlDelay -1  ; 可以提高可靠性, 减少副作用.
ControlClick "Toolbar321", "Some Window Title",,,, "NA x192 y10"


ControlDeleteItem - 语法 & 使用 | AutoHotkey v2

ControlDeleteItem

从 ListBox 或 ComboBox 中删除指定的条目.

ControlDeleteItem N, Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

N

类型: 整数

项目的索引, 其中 1 是第一项, 2 是第二项, 以此类推.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 或者控件的类名不包含 "Combo" 或 "List", 则抛出 TargetError.

如果项目无法删除, 则抛出 Error 或 OSError.

备注

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlAddItem, ControlFindItem, Delete 方法(GuiControl 对象), 控件函数


ControlFindItem - 语法 & 使用 | AutoHotkey v2

ControlFindItem

返回与指定字符串完全匹配的 ListBox 或 ComboBox 的条目编号.

FoundItem := ControlFindItem(String, Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

String

类型: 字符串

要查找的字符串. 搜索不区分大小写. 与 ControlChooseString 不同, 条目的整个文本必须匹配, 而不仅仅是开头部分.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

此函数返回 ListBox 或 ComboBox 中与 String 完全匹配的条目的编号. 控件中首个条目为 1, 第二个为 2, 依此类推. 如果没有找到匹配, 则抛出异常.

错误处理

如果找不到窗口或控件, 或者控件的类名不包含 "Combo" 或 "List", 则抛出 TargetError.

如果找不到项目, 则抛出 Error.

备注

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlAddItem, ControlDeleteItem, 控件函数


ControlFocus - 语法 & 使用 | AutoHotkey v2

ControlFocus

设置输入焦点到窗口的指定控件上.

ControlFocus Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

备注

要让设置生效, 控件所在的窗口一般不能处于最小化或隐藏状态.

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或者给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

当控件被聚焦以响应用户输入(例如按 Tab 键) 时, 对话管理器应用附加效果, 这些效果独立于具有焦点的控件. 这些效果不是由 ControlFocus 应用的, 因此以下限制适用:

  • 聚焦按钮不会自动使其成为默认按钮, 这与通过用户输入对焦按钮通常会发生的情况不同. 默认按钮通常可以通过按 Enter 来激活.
  • 如果先前的用户输入导致默认按钮被临时更改, 聚焦非按钮控件不会自动将默认高亮显示恢复到实际的默认按钮. 按 Enter 键可以激活默认按钮, 即使它没有突出显示.
  • 聚焦编辑控件不会自动选择其文本. 相反, 插入点(插入) 通常位于控件上次有焦点时的位置.

WM_NEXTDLGCTL 消息可以用来聚焦控件并应用这些附加效果. 例如:

WinExist("A") ; 将最后找到的窗口设置为活动窗口
hWndControl := ControlGetHwnd("Button1")  ; 获取第一个按钮的 HWND
SendMessage 0x0028, hWndControl, True  ; 0x0028 对应 WM_NEXTDLGCTL

相关

SetControlDelay, ControlGetFocus, 控件函数

示例

设置焦点到 OK 按钮上.

ControlFocus "OK", "Some Window Title"


ControlGetChecked - 语法 & 使用 | AutoHotkey v2

ControlGetChecked

如果选中复选框或单选按钮, 则返回非零值.

IsChecked := ControlGetChecked(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数(布尔值)

如果选中 checkbox 或 radio 按钮, 则此函数返回 1(true), 否则返回 0(false).

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果消息不能被发送到控件, 则抛出 OSError.

相关

ControlSetChecked, Value 属性(GuiControl 对象), 控件函数


ControlGetChoice - 语法 & 使用 | AutoHotkey v2

ControlGetChoice

返回 ListBox 或 ComboBox 中当前选择的条目的名称.

Choice := ControlGetChoice(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

此函数返回 ListBox 或 ComboBox 中当前选择的条目的名称.

错误处理

如果找不到窗口或控件, 或者控件的类名不包含 "Combo" 或 "List", 则抛出 TargetError.

失败时抛出 Error.

备注

要获取所选项目的位置, 请遵循以下示例(仅使用前两行中的其中一行):

ChoicePos := SendMessage(0x0188, 0, 0, "ListBox1", WinTitle)  ; 0x0188 为 LB_GETCURSEL (对于 ListBox).
ChoicePos := SendMessage(0x0147, 0, 0, "ComboBox1", WinTitle)  ; 0x0147 为 CB_GETCURSEL (对于 DropDownList 或 ComboBox).
ChoicePos += 1  ; 从基于 0 转换到基于 1, 这样首个条目被称为 1, 而不是 0.
; 如果没有选择项目, ChoicePos 现在为 0.

相关

ControlChooseIndex, ControlChooseString, Value 属性(GuiControl 对象), Choose 方法(GuiControl 对象), 控件函数


ControlGetClassNN - 语法 & 使用 | AutoHotkey v2

ControlGetClassNN

返回指定控件的 ClassNN(类名和编号).

ClassNN := ControlGetClassNN(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

函数返回指定控件的 ClassNN(类名和编号).

错误处理

如果在确定目标窗口或控件时出现问题, 则抛出 TargetError.

如果不能确定 ClassNN, 则抛出 Error 或 OSError.

备注

控件的 ClassNN 是其窗口类的名称, 后跟着它在顶级窗口中的编号. 例如, "Edit1" 是窗口上的第一个 Edit 控件, 而 "Button12" 是第十二个按钮.

控件的 ClassNN 也可以通过 Window Spy, MouseGetPos 或 WinGetControls 来确定.

某些类名称包含数字, 这些数字不属于控件的序号. 例如, "SysListView321" 是窗口的第一个 ListView 控件, 而不是第 321 个. 若要检索没有序号的类名, 请将控件的 HWND 传递给 WinGetClass.

相关

WinGetClass, WinGetControls, ClassNN 属性(GuiControl 对象), MouseGetPos, 控件函数

示例

检索当前具有焦点控件的 ClassNN.

classNN := ControlGetClassNN(ControlGetFocus("A"))


ControlGetEnabled - 语法 & 使用 | AutoHotkey v2

ControlGetEnabled

如果指定的控件是启用的, 则返回非零值.

IsEnabled := ControlGetEnabled(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数(布尔值)

如果指定的控件是启用的, 此函数返回 1(true), 否则返回 0(false).

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

相关

ControlSetEnabled, WinSetEnabled, Enabled 属性(GuiControl 对象), 控件函数


ControlGetFocus - 语法 & 使用 | AutoHotkey v2

ControlGetFocus

如果有, 则获取目标窗口中具有输入焦点的控件.

HWND := ControlGetFocus(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

此函数返回具有输入焦点的控件的窗口句柄(HWND).

如果目标窗口的控件都没有焦点, 则返回 0.

错误处理

如果在确定目标窗口或控件时出现问题, 则抛出 TargetError.

如果在确定焦点时出现问题, 则抛出 OSError.

备注

通过此函数检索的控件是具有键盘焦点的控件, 即, 如果用户键入任何键盘, 将接收击键的控件.

目标窗口必须处于活动状态才能具有焦点控件, 但是即使是活动窗口也可能没有焦点控件.

相关

ControlFocus, 控件函数

示例

报告活动窗口的焦点控件的 HWND 和 ClassNN.

FocusedHwnd := ControlGetFocus("A")
FocusedClassNN := ControlGetClassNN(FocusedHwnd)
MsgBox 'Control with focus = {Hwnd: ' FocusedHwnd ', ClassNN: "' FocusedClassNN '"}'


ControlGetHwnd - 语法 & 使用 | AutoHotkey v2

ControlGetHwnd

返回指定控件的唯一 ID.

Hwnd := ControlGetHwnd(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

此函数返回指定控件的窗口句柄(HWND).

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

备注

控件的 HWND 通常与 PostMessage, SendMessage 和 DllCall 一起使用. 另外, 还可以通过 MouseGetPos 来获取控件的 HWND. 最后, 控件的 HWND 可以直接在 WinTitle 参数中使用. 这也适用于隐藏控件, 即使 DetectHiddenWindows 为 Off.

相关

WinGetID, Hwnd 属性(GuiControl 对象), 控件函数

示例

示例 #1

检索记事本的 Edit 控件的唯一 ID.

editHwnd := ControlGetHwnd("Edit1", "ahk_class Notepad")


ControlGetIndex - 语法 & 使用 | AutoHotkey v2

ControlGetIndex

返回 ListBox, ComboBox 或 Tab 控件中当前选中的条目或标签的索引.

Index := ControlGetIndex(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

此函数返回当前选择条目或标签页索引. 第一个条目或选项卡是 1, 第二个是 2, 依此类推. 如果未选择任何条目或选项卡, 则返回值为 0.

错误处理

如果找不到窗口或控件, 或者控件的类名不包含 "Combo", "List" 或 "Tab", 则抛出 TargetError.

如果消息不能被发送到控件, 则抛出 OSError.

备注

要改为发现 Tab 控件中存在多少个标签(页面), 请遵循以下示例:

TabCount := SendMessage(0x1304,,, "SysTabControl321", WinTitle)  ; 0x1304 为 TCM_GETITEMCOUNT.

相关

ControlChooseIndex, ControlGetChoice, ControlChooseString, Value 属性(GuiControl 对象), Choose 方法(GuiControl 对象), 控件函数

示例

检索第一个 Tab 控件的活动标签页序号.

WhichTab := ControlGetIndex("SysTabControl321", "Some Window Title")
MsgBox "Tab #" WhichTab " is active."


ControlGetItems - 语法 & 使用 | AutoHotkey v2

ControlGetItems

返回 ListBox, ComboBox 或 DropDownList 中项目/行数组.

Items := ControlGetItems(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: Array

函数返回项目/行的数组.

错误处理

如果找不到窗口或控件, 或者控件的类名不包含 "Combo" 或 "List", 则抛出 TargetError.

失败时抛出 Error, 例如, 如果消息返回错误码或不能被发送.

备注

有些应用程序私自存储了它们的项目数据, 这使得它们的文本无法被检索. 在这种情况下, 通常不会抛出异常, 但所有检索到的字段都是空的.

相关

ListViewGetContent, WinGetList, 控件函数

示例

逐个访问项目.

for item in ControlGetItems("ComboBox1", WinTitle)
    MsgBox "Item number " A_Index " is " item

通过索引访问特定的项目.

items := ControlGetItems("ListBox1", WinTitle)
MsgBox "The first item is " items[1]
MsgBox "The last item is " items[-1]


ControlGetPos - 语法 & 使用 | AutoHotkey v2

ControlGetPos

获取控件的位置和大小.

ControlGetPos &OutX, &OutY, &OutWidth, &OutHeight, Control, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

&OutX, &OutY

类型: VarRef

如果省略, 将不存储对应的值. 否则, 请指定用于存储 Control 左上角的 X 和 Y 坐标(英寸) 的输出变量的引用. 这些坐标相对于目标窗口的客户端区域, 因此与 ControlMove 使用的坐标相同.

&OutWidth, &OutHeight

类型: VarRef

如果省略, 将不存储对应的值. 否则, 请指定用于存储 Control 的宽度和高度(单位为英寸) 的输出变量的引用.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数. 该参数是必需的; 也就是说, 不能省略.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

备注

与更改控件的函数不同, ControlGetPos 没有自动延迟(不受 SetControlDelay 影响).

相关

ControlMove, WinGetPos, 控件函数

示例

持续地更新和显示当前鼠标光标下的控件的名称和位置.

Loop
{
    Sleep 100
    MouseGetPos ,, &WhichWindow, &WhichControl
    try ControlGetPos &x, &y, &w, &h, WhichControl, WhichWindow
    ToolTip WhichControl "`nX" X "`tY" Y "`nW" W "`t" H
}


ControlGetStyle / ControlGetExStyle - 语法 & 使用 | AutoHotkey v2

ControlGetStyle / ControlGetExStyle

返回表示指定控件样式或扩展样式的整数.

Style := ControlGetStyle(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)
ExStyle := ControlGetExStyle(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

这些函数返回指定控件样式或扩展样式.

错误处理

失败时, 或者找不到窗口或控件, 则抛出 TargetError.

备注

有关样式的部分列表, 请参阅样式列表.

ControlGetExStyle 只检索一般的扩展样式, 如 WS_EX_CLIENTEDGE(0x200). 要检索控件特定的扩展样式, 请使用 SendMessage, 例如 SendMessage(0x1037, 0, 0, MyListView) 其中 0x1037 为 LVM_GETEXTENDEDLISTVIEWSTYLE. 对于通过 AutoHotkey 创建的 ListView, 这个例子返回 48(0x30), LVS_EX_FULLROWSELECT(0x20) 和 LVS_EX_HEADERDRAGDROP(0x10) 的组合, 前提是扩展的 ListView 样式没有事先改变.

相关

ControlSetStyle / ControlSetExStyle, WinGetStyle / WinGetExStyle, 样式列表, 控件函数


ControlGetText - 语法 & 使用 | AutoHotkey v2

ControlGetText

检索控件的文本.

Text := ControlGetText(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

函数返回指定控件的文本.

错误处理

失败时, 或者找不到窗口或控件, 则抛出 TargetError.

备注

注意: 要获取列表视图, 列表框或组合框的文本, 请使用 ListViewGetContent 或 ControlGetItems.

如果获取的文本看起来像被截短了(不完整), 可能需要通过 SendMessage 发送 WM_GETTEXT 消息来检索文本. 因为某些应用程序不能正确响应 WM_GETTEXTLENGTH 消息, 所以这是必要的, 否则会导致 AutoHotkey 把输出变量设得过小以致无法保存所有的文本.

如果目标控件(例如打开大文档的编辑器) 包含大量文本, 则此函数可能会使用大量的 RAM. 但是, 变量的内存在使用后可以通过将其赋值为空来释放, 例如 Text := "".

从大多数控件类型检索的文本使用回车和换行符(`r`n) 而不是单独的换行符(`n) 来表示每行的结尾.

不必执行 SetTitleMatchMode "Slow", 因为 ControlGetText 始终使用慢速模式检索文本(因为它适用于更广泛的控件类型).

若要检索窗口中所有控件的数组, 请使用 WinGetControls 或 WinGetControlsHwnd.

相关

ControlSetText, WinGetText, 控件函数

示例

从记事本的编辑控件中获取当前文本, 并将其存储在 Text. 这个例子在 Windows 11 或更高版本系统可能会失败, 因为它需要经典版本的记事本.

Text := ControlGetText("Edit1", "Untitled -")

从主窗口的编辑控件检索和报告当前文本.

ListVars
WinWaitActive "ahk_class AutoHotkey"
MsgBox ControlGetText("Edit1") ; 使用上面找到的窗口.


ControlGetVisible - 语法 & 使用 | AutoHotkey v2

ControlGetVisible

如果指定的控件可见, 则返回非零值.

IsVisible := ControlGetVisible(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数(布尔值)

如果指定的控件可见, 此函数返回 1(true), 否则返回 0(false).

错误处理

失败时, 或者找不到窗口或控件, 则抛出 TargetError.

相关

ControlHide, ControlShow, Visible 属性(GuiControl 对象), 控件函数


ControlHide - 语法 & 使用 | AutoHotkey v2

ControlHide

隐藏指定控件.

ControlHide Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 或无法应用更改, 则抛出 TargetError.

备注

如果还希望阻止控件的快捷键(带下划线的字母) 起作用, 请通过 ControlSetEnabled 禁用该控件.

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlShow, ControlGetVisible, WinHide, Visible 属性(GuiControl 对象), 控件函数


ControlHideDropDown - 语法 & 使用 | AutoHotkey v2

ControlHideDropDown

隐藏 ComboBox 控件的下拉列表.

ControlHideDropDown Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果消息不能被发送到控件, 则抛出 OSError.

备注

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlShowDropDown, 控件函数

示例

请参阅 ControlShowDropDown 页面的示例 #1.


ControlMove - 语法 & 使用 | AutoHotkey v2

ControlMove

移动控件或调整其大小.

ControlMove X, Y, Width, Height, Control, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

X, Y

类型: 整数

如果任一坐标省略, 那么控件在这个维度(坐标轴) 中的位置将保持不变. 否则, 请指定控件新位置的左上角的 X 和 Y 坐标(单位为像素). 这里的坐标相对于目标窗口的工作区的左上角; 可以使用 ControlGetPos 来确定它们.

Width, Height

类型: 整数

如果任一省略, 那么控件在这个维度(坐标轴) 中的尺寸将保持不变. 否则, 请指定控件的新宽度和高度(单位为像素).

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数. 该参数是必需的; 也就是说, 不能省略.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果控件的当前位置无法确定, 则抛出 OSError.

备注

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或者给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlGetPos, WinMove, SetControlDelay, 控件函数

示例

演示如何在脚本等待用户输入时操作输入框的 OK 按钮.

SetTimer ControlMoveTimer
IB := InputBox(, "My Input Box")

ControlMoveTimer()
{
    if !WinExist("My Input Box")
        return
    ; 否则上面设置为 "上次找到的" 窗口:
    SetTimer, 0
    WinActivate
    ControlMove 10,, 200,, "OK"  ; 将 OK 按钮移动到左边并增加其宽度.
}


ControlSend / ControlSendText - 语法 & 使用 | AutoHotkey v2

ControlSend / ControlSendText

发送模拟键盘输入或文本到窗口或控件.

ControlSend Keys , Control, WinTitle, WinText, ExcludeTitle, ExcludeText
ControlSendText Keys , Control, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Keys

类型: 字符串

要发送的按键的序列(有关详情, 请参阅 Send 函数). 发送字符的速率由 SetKeyDelay 决定.

与 Send 函数不同, ControlSend 不能发送鼠标点击. 请使用 ControlClick 来发送.

Control

类型: 字符串, 整数或对象

如果省略此参数, 击键将直接发送到目标窗口, 而不是它的一个控件(有关示例, 请参阅 Automating Winamp). 否则, 请指定控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

备注

不像 Send, ControlSend 忽略 SendMode. 它使用操作系统的 PostMessage 函数来发布键盘消息.

ControlSendText 类似于 ControlSend, 除了它发送 Keys 参数中的单个字符, 而不把 {Enter} 转换成 Enter, 把 ^c 转换成 Ctrl+C, 等等. 有关详情, 请参阅文本模式. 在 ControlSend 中, 使用 {Raw} 或 {Text} 也是有效的.

如果省略 Control 参数, 该函数将尝试直接发送至目标窗口的最上面的控件(通常是正确的控件), 如果没有控件, 则发送至窗口本身. 如果一个窗口看起来根本没有任何控件, 或者只是为了方便且不必担心发送到哪个控件, 那么这个函数就很有用.

默认情况下, 修饰键(Ctrl, Alt, Shift 和 Win) 会像正常情况下一样由 SendEvent 函数发送. 这使得命令提示符和其他控制台窗口能够正确检测大写字母, 控制字符等. 它还可以在其他方面提高可靠性.

然而, 在某些情况下, 这些修饰符事件可能会干扰活动窗口, 特别是当用户在 ControlSend 期间正在进行输入, 或者正在发送 Alt 键时(因为 Alt 会激活活动窗口的菜单栏). 可以通过显式发送修饰符按下和弹起事件来避免这种情况, 如本例所示:

ControlSend "{Alt down}f{Alt up}", "Edit1", "Untitled - Notepad"

上面的方法也允许在工作站被锁定(由登录提示保护) 时发送修饰键(Ctrl, Alt, Shift 和 Win).

当在命令提示符等控制台窗口中使用 ControlSend 时, 应避免使用 BlockInput. 这是因为它可能会阻止大写和修饰键(如 Ctrl) 的正常工作.

SetKeyDelay 的值决定了按键的发送速度. 如果目标窗口无法可靠地接收按键, 请尝试通过 SetKeyDelay 的第二个参数来增加按下的持续时间, 如下面的例子所示:

SetKeyDelay 10, 10
SetKeyDelay 0, 10
SetKeyDelay -1, 0

如果目标控件是一个 Edit 控件(或类似的控件), 下面的方法通常比 ControlSend 更可靠和更快:

EditPaste("This text will be inserted at the caret position.", ControlName, WinTitle)
ControlSetText("This text will entirely replace any current text.", ControlName, WinTitle)

ControlSend 通常不能操纵窗口的菜单栏. 要解决这个问题, 可以使用 MenuSelect. 如果由于菜单栏的性质而无法做到这一点, 你可以尝试按照 SendMessage 教程来发现对应于所需菜单项的消息.

相关

SetKeyDelay, 转义序列(例如 `n) , 控件函数, Send, 自动化 Winamp

示例

打开记事本(最小化的) 并发送一些文本. 这个例子在 Windows 11 或更高版本系统可能会失败, 因为它需要经典版本的记事本.

Run "Notepad",, "Min", &PID  ; 最小化运行记事本.
WinWait "ahk_pid " PID  ; 等待记事本进程的出现.
; 将文本发送到不活动的记事本编辑控件.
; 省略了第三个参数, 因此使用最后一个找到的窗口.
ControlSend "This is a line of text in the notepad window.{Enter}", "Edit1"
ControlSendText "Notice that {Enter} is not sent as an Enter keystroke with ControlSendText.", "Edit1"

Msgbox "Press OK to activate the window to see the result."
WinActivate "ahk_pid " PID  ; 显示结果.

打开命令提示符并向它发送一些文本. 这个例子在 Windows 11 或更高版本系统可能会失败, 因为它需要经典版本的命令提示符.

SetTitleMatchMode 2
Run A_ComSpec,,, &PID  ; 打开命令提示符.
WinWait "ahk_pid " PID  ; 等待它的出现.
ControlSend "ipconfig{Enter}",, "cmd.exe"  ; 直接发送到命令提示符窗口.

创建一个带有编辑控件的 GUI, 并向它发送一些文本.

MyGui := Gui()
MyGui.Add("Edit", "r10 w500")
MyGui.Show()
ControlSend "This is a line of text in the edit control.{Enter}", "Edit1", MyGui
ControlSendText "Notice that {Enter} is not sent as an Enter keystroke with ControlSendText.", "Edit1", MyGui


ControlSetChecked - 语法 & 使用 | AutoHotkey v2

ControlSetChecked

打开(选中) 或关闭(取消选中) 复选框或单选按钮.

ControlSetChecked NewSetting, Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

NewSetting

类型: 整数

下列值之一:

  • 1 或 True 打开设置
  • 0 或 False 关闭设置
  • -1 切换设置(将其设置为与当前状态相反的状态)
Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果消息不能被发送到控件, 则抛出 OSError.

备注

为了确保正确的功能, 此函数还将输入焦点设置到此控件.

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlGetChecked, Value 属性(GuiControl 对象), 控件函数


ControlSetEnabled - 语法 & 使用 | AutoHotkey v2

ControlSetEnabled

启用或禁用指定的控件.

ControlSetEnabled NewSetting, Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

NewSetting

类型: 整数

下列值之一:

  • 1 或 True 打开设置
  • 0 或 False 关闭设置
  • -1 切换设置(将其设置为与当前状态相反的状态)
Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

备注

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlGetEnabled, WinSetEnabled, Enabled 属性(GuiControl 对象), 控件函数


ControlSetStyle / ControlSetExStyle - 语法 & 使用 | AutoHotkey v2

ControlSetStyle / ControlSetExStyle

分别更改指定控件的样式或扩展样式.

ControlSetStyle Value, Control , WinTitle, WinText, ExcludeTitle, ExcludeText
ControlSetExStyle Value, Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Value

类型: 整数或字符串

传递一个正整数来完全覆盖窗口的样式; 也就是说, 设置它的值为 Value.

要添加, 删除或切换样式, 请分别传递一个以加号(+), 减号(-) 或插入符号(^) 前缀的数字字符串. 新样式值的计算如下所示(其中 CurrentStyle 可以通过 ControlGetStyle, ControlGetExStyle, WinGetStyle or WinGetExStyle 检索):

操作 前缀 示例 公式
添加 + "+0x80" NewStyle := CurrentStyle | Value
删除 - "-0x80" NewStyle := CurrentStyle & ~Value
切换 ^ "^0x80" NewStyle := CurrentStyle ^ Value

如果 Value 是一个负整数, 它将被视为与对应的数字字符串相同.

要在表达式中原义使用 + 或 ^ 前缀, 前缀或值必须用引号括起来. 例如: ControlSetStyle("+0x80") 或 ControlSetStyle("^" StylesToToggle). 这是因为表达式 +123 产生 123(没有前缀), 而 ^123 是一个语法错误.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果样式不能被改变, 则抛出 OSError. 部分改变被视为是成功的.

备注

有关样式的部分列表, 请参阅样式列表.

某些样式更改要求使用 WinRedraw 重新绘制整个窗口.

ControlSetExStyle 只改变一般的扩展样式, 如 WS_EX_CLIENTEDGE(0x200). 要更改控件特定的扩展样式, 请使用 SendMessage, 例如 SendMessage(0x1036, 0, 0x1, MyListView) 其中 0x1036 为 LVM_SETEXTENDEDLISTVIEWSTYLE, 而 0x1 为 LVS_EX_GRIDLINES. 注意, 当使用 AutoHotkey 创建 ListView 时, 扩展的 ListView 样式也可以使用 LV 选项指定.

相关

ControlGetStyle / ControlGetExStyle, WinSetStyle / WinSetExStyle, 样式列表, 控件函数

示例

设置记事本编辑控件的 WS_BORDER 样式为其相反的状态.

ControlSetStyle("^0x800000", "Edit1", "ahk_class Notepad")


ControlSetText - 语法 & 使用 | AutoHotkey v2

ControlSetText

更改控件的文本.

ControlSetText NewText, Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

NewText

类型: 字符串

设置到控件的新文本.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

备注

大多数控件类型使用回车和换行符(`r`n) 而不是单独的换行符(`n) 来表示每行的结尾. 要转换包含 `n 字符的文本块, 请参照此例:

MyVar := StrReplace(MyVar, "`n", "`r`n")

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或者给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

SetControlDelay, ControlGetText, 控件函数

示例

更改记事本编辑控件的文本. 这个例子在 Windows 11 或更高版本系统可能会失败, 因为它需要经典版本的记事本.

ControlSetText("New Text Here", "Edit1", "Untitled -")

更改主窗口编辑控件的文本.

ListVars
WinWaitActive "ahk_class AutoHotkey"
ControlSetText "New Text Here", "Edit1" ; 使用上面找到的窗口.


ControlShow - 语法 & 使用 | AutoHotkey v2

ControlShow

如果指定的控件先前是隐藏的, 则显示该控件.

ControlShow Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 或无法应用更改, 则抛出 TargetError.

备注

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlHide, ControlGetVisible, WinShow, Visible 属性(GuiControl 对象), 控件函数


ControlShowDropDown - 语法 & 使用 | AutoHotkey v2

ControlShowDropDown

显示 ComboBox 控件的下拉列表.

ControlShowDropDown Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果消息不能被发送到控件, 则抛出 OSError.

备注

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlHideDropDown, 控件函数

示例

打开运行对话框, 显示其下拉列表 2 秒, 然后关闭对话框.

Send "#r"  ; 打开运行对话框.
WinWaitActive "ahk_class #32770"  ; 等待对话框出现.
ControlShowDropDown "ComboBox1"  ; 显示下拉列表. 省略第二个参数, 以便使用最后找到的窗口.
Sleep 2000
ControlHideDropDown "ComboBox1"  ; 隐藏下拉列表.
Sleep 1000
Send "{Esc}"  ; 关闭对话框窗口.


CoordMode - 语法 & 使用 | AutoHotkey v2

CoordMode

为多个内置函数设置坐标模式, 相对于活动窗口还是屏幕.

CoordMode TargetType , RelativeTo

参数

TargetType

类型: 字符串

指定以下单词之一, 以指示要作用的目标的类型:

ToolTip: 作用于 ToolTip.

Pixel: 作用于 PixelGetColor, PixelSearch 和 ImageSearch.

Mouse: 作用于 MouseGetPos, Click 和 MouseMove, MouseClick 和 MouseClickDrag.

Caret: 作用于 CaretGetPos.

Menu: 作用于 Menu.Show 方法, 当为其指定坐标时.

RelativeTo

类型: 字符串

如果省略, 默认为 Screen. 否则, 请指定下列单词之一, 以指示 TargetType 关联的区域:

Screen: 坐标相对于桌面(整个屏幕).

Window: 坐标相对于活动窗口.

Client: 坐标相对于活动窗口的工作区, 其中不包括标题栏, 菜单栏(如果它含有标准菜单栏) 和边框. Client 坐标模式较少依赖于操作系统版本和主题.

返回值

类型: 字符串

函数返回以前的设置: Screen, Window 或 Client.

备注

如果没有使用 CoordMode, 默认模式为 Client; 即除了另外注明的那些外的所有内置函数(例如 WinMove 和 InputBox) 都使用相对于活动窗口的坐标模式.

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

内置变量 A_CoordMode 包含当前的设置.

相关

Click, MouseMove, MouseClick, MouseClickDrag, MouseGetPos, PixelGetColor, PixelSearch, ToolTip, Menu.Show

示例

把工具提示放置在绝对的屏幕坐标上.

CoordMode "ToolTip", "Screen"

和上面一样的效果, 因为 "Screen" 是默认的.

CoordMode "ToolTip"


Critical - 语法 & 使用 | AutoHotkey v2

Critical

防止当前线程被其他线程中断, 或使其能够被中断.

Critical OnOffNumeric

参数

OnOffNumeric

类型: 字符串或整数

如果参数为空或省略, 默认为 On. 否则, 请指定以下之一:

On: 设置当前线程为关键的, 这意味着它不会被其他线程中断.

Off: 当前线程立即成为可中断的, 无论 Thread Interrupt 的设置如何. 有关详情, 请参阅 Critical Off.

(数字): 指定一个正数来打开 Critical, 但同时也会改变检查内部消息队列的时间间隔. 有关详情, 请参阅消息检查间隔. 指定 0 关闭 Critical. 指定 -1 将启用 Critical, 但禁用消息检查.

返回值

类型: 整数

函数返回以前的设置(值 A_IsCritical 将在调用函数之前返回); 如果 Critical 为 Off, 则为 0, 否则为大于零的整数.

关键线程的行为

Critical 线程是 不可中断的; 有关详情, 请参阅线程.

关键线程在显示 MsgBox 或其他对话框时, 会变成可中断的. 但是, 与 Thread Interrupt 不同, 在用户解除对话框后这个线程会再恢复为关键的.

Critical Off

当缓冲的事件等待启动新的线程时, 使用 Critical "Off" 不会导致立即中断当前线程, 而会经过平均 5ms 才发生中断. 这会导致在中断前有超过 99.999 % 的可能执行了至少一行 Critical "Off" 后面的代码. 可通过使用像 Sleep -1 或 WinWait 一个尚不存在的窗口这样的延迟手段立即产生强制中断.

Critical "Off" 会取消当前线程的不可中断性周期, 即使该线程不是关键线程, 因此会让像 Size 这样的事件更快或更可预测地被处理.

Thread 设置

如何保存和还原当前的 Critical 设置, 请参阅 A_IsCritical. 但是, 由于 Critical 是特定于线程的设置, 因此当关键线程结束时, 底层/恢复的线程(如果有的话) 将自动是非关键线程. 因此, 不需要在结束线程之前执行 Critical "Off".

如果在自动执行线程中没有使用 Critical, 所有的线程将会以非关键线程启动(尽管 Thread Interrupt 的设置仍然有效). 相比之下, 如果自动执行线程打开了 Critical 但随后并没有关闭过它, 每个新启动的线程(如 热键, 自定义菜单项或计时器子程序) 都会以关键线程方式启动.

函数 Thread NoTimers 类似于 Critical, 除了它仅阻止被计时器中断.

消息检查间隔

指定一个正数作为首个参数(例如 Critical 30) 将会打开 Critical, 但同时也会改变检查内部消息队列的最小时间间隔(以 ms 毫秒计). 如果未指定该参数, 在 Critical 打开的状态下, 默认为 16 ms, 在 Critical 关闭状态下, 每 5 ms 检查一次. 延长时间间隔会推迟消息/事件的到达, 给出更多的时间让当前线程结束. 这会减少某些 OnMessage 回调和 GUI events 因为 "线程已运行" 而丢失的可能性. 然而, 像 Sleep 和 WinWait 这样的等待型函数则无视此设定而照常检查消息(一个解决办法是 DllCall("Sleep", "UInt", 500)).

此设置影响如下:

  • 抢先消息检查, 可能发生在每一行代码执行之前.
  • 在 Send, 文件和下载操作期间定期检查消息.

当脚本暂停或等待时, 它不会影响消息检查的频率.

因为系统滴答计数的间隔通常为 15.6 毫秒, 所以最小增量值通常至少为 15 或 16. 自上次检查以来的持续时间必须 超过 设置的间隔, 以便进行另一次检查. 例如, 设置为 16 要求滴答计数更改为 17 或更大. 由于消息检查可以在 15.6 毫秒窗口内的任何时间发生, 因此在 1 到 16 之间的任何设置都可以允许在单个间隔内进行两次消息检查.

注意: 将消息检查间隔设置的太大会减少对多种事件的响应能力, 例如 GUI 窗口的重绘.

Critical -1 开启 Critical, 但禁用消息检查. 这并不妨碍程序在执行睡眠, 延迟或等待时检查消息. 在分派消息可能会干扰当前执行的代码的情况下, 例如在 OnMessage 回调期间处理某些类型的消息时, 它非常有用.

相关

Thread (函数), 线程, #MaxThreadsPerHotkey, #MaxThreadsBuffer, OnMessage, CallbackCreate, Hotkey, Menu 对象, SetTimer

示例

按下热键显示工具提示 3 秒. 由于 Critical, 在此期间启动的任何新线程(例如再次按下热键) 将被推迟, 直到工具提示消失.

#space::  ; Win+Space 热键.
{
    Critical
    ToolTip "No new threads will launch until after this ToolTip disappears."
    Sleep 3000
    ToolTip  ; 关闭提示.
    return  ; 从热键子程序中返回. 根据定义, 要恢复的任何底层线程都是非关键的.
}


DateAdd - 语法 & 使用 | AutoHotkey v2

DateAdd

从日期-时间值中添加或减去时间.

Result := DateAdd(DateTime, Time, TimeUnits)

参数

DateTime

类型: 字符串

YYYYMMDDHH24MISS 格式的日期-时间戳.

Time

类型: 整数或浮点数

要添加的时间, 以整数或浮点数表示. 指定一个负数以执行减法.

TimeUnits

类型: 字符串

Time 参数的单位. TimeUnits 可以是下列字符串之一(也可以是其第一个字母): Seconds(秒), Minutes(分), Hours(小时) 或 Days(天).

返回值

类型: 字符串

此函数返回一个 YYYYMMDDHH24MISS 格式的数字字符串. 此字符串不应视为数字(不应对其进行数学运算或进行数字比较).

备注

内置变量 A_Now 包含了 YYYYMMDDHH24MISS 格式的当前本地时间.

要计算两个时间戳之间的时间量, 请使用 DateDiff.

如果 DateTime 包含无效的时间戳或 1601 年之前的年份, 则抛出 ValueError.

相关

DateDiff, FileGetTime, FormatTime

示例

计算从现在起 31 天后的日期时间.

later := DateAdd(A_Now, 31, "days")
MsgBox FormatTime(later)


DateDiff - 语法 & 使用 | AutoHotkey v2

DateDiff

比较两个日期-时间并返回它们的差异值.

Result := DateDiff(DateTime1, DateTime2, TimeUnits)

参数

DateTime1
DateTime2

类型: 字符串

YYYYMMDDHH24MISS 格式的日期-时间戳.

如果 DateTime1 早于 DateTime2, 则结果为负数.

如果其中一个参数是空字符串, 则使用当前本地日期和时间(使用 A_Now).

TimeUnits

类型: 字符串

测量差异所用的单位. TimeUnits 可以是下列字符串之一(也可以是其第一个字母): Seconds(秒), Minutes(分), Hours(小时) 或 Days(天).

返回值

类型: 整数

此函数返回两个时间戳之间的差值, 单位由 TimeUnits 指定. 结果总是 向下 取整. 例如, 如果两个时间戳之间的实际差为 1.999 天, 那么运算的结果将为 1 天. 如果需要更高的精度, 请在 TimeUnits 指定 Seconds 并把结果除以 60.0, 3600.0 或 86400.0(以得到更精确的分钟数, 小时数或天数).

备注

内置变量 A_Now 包含了 YYYYMMDDHH24MISS 格式的当前本地时间.

要精确地测出两个事件之间所经过的时间, 请使用 A_TickCount 方法, 因为它提供了毫秒级的精度.

要从时间戳中添加或减去特定的 Seconds(秒), Minutes(分), Hours(小时) 或 Days(天), 可以使用 DateAdd(减法是通过加上负数来实现的).

如果 DateTime 包含一个无效的时间戳或年份早于 1601, 则抛出 ValueError.

相关

DateAdd, FileGetTime, FormatTime

示例

计算两个时间戳之间的天数, 并报告结果.

var1 := "20050126"
var2 := "20040126"
MsgBox DateDiff(var1, var2, "days")  ; 结果将是 366, 因为 2004 是个闰年.


DetectHiddenText - 语法 & 使用 | AutoHotkey v2

DetectHiddenText

设置在查找窗口时是否 "看见" 隐藏的文本. 这将影响 WinExist 和 WinActivate 等窗口命令.

DetectHiddenText Mode

参数

Mode

类型: 布尔值

指定以下值之一:

如果为 true, 检测隐藏文本.

如果为 false, 不检测隐藏文本.

返回值

类型: 整数(布尔值)

函数返回以前的设置: 0(false) 或 1(true).

备注

如果没有使用 DetectHiddenText, 默认设置为 1(true)

"隐藏的文本" 是一个指窗口中那些不可见控件的术语. 因此, 他们的文本被认为是 "隐藏的". 当您想检测多窗格窗口或多选项卡式对话框中不同窗格的差异时, 可能需要关闭 DetectHiddenText. 使用 Window Spy 来确定当前活动窗口的哪些文本被隐藏. 所有接受 WinText 参数的内置函数都受到此设置的影响, 包括 WinActivate, WinActive, WinWait 和 WinExist.

内置变量 A_DetectHiddenText 包含了当前的设置(1 或 0).

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

DetectHiddenWindows

示例

关闭检测隐藏文本.

DetectHiddenText False


DetectHiddenWindows - 语法 & 使用 | AutoHotkey v2

DetectHiddenWindows

设置脚本是否可以 "看见" 隐藏的窗口.

DetectHiddenWindows Mode

参数

Mode

类型: 布尔值

指定以下值之一:

如果为 true, 能检测到隐藏窗口.

如果为 false, 不能检测隐藏窗口, 除了 WinShow 函数.

返回值

类型: 整数(布尔值)

函数返回以前的设置: 0(false) 或 1(true).

备注

如果没有使用 DetectHiddenWindows, 则默认设置为 0(false).

在某些情况下, 打开 DetectHiddenWindows 可能会使脚本编写变得困难, 因为有些隐藏的系统窗口可能意外地匹配上您想要操作的另一个窗口的标题或文本. 因此在大多数脚本中应该让此设置保持关闭. 然而, 当您希望直接操作隐藏窗口而不想首先使用 WinShow 显示这些窗口时, 则需要打开此设置.

除 WinShow 外的所有窗口函数都会受此设置的影响, 包括 WinActivate, WinActive, WinWait 和 WinExist. 与之相比, 即使没有检测隐藏窗口, WinShow 始终能显示隐藏窗口.

在以下情况下, 不需要开启 DetectHiddenWindows:

  • 当使用纯 HWND(作为一个整数或带有 HWND 属性的对象), 如在 WinShow(A_ScriptHwnd) 或 WinMoveTop(myGui), 除了 WinWait 或 WinWaitClose.
  • 当通过 ahk_id 方法 或作为最后一个窗口访问控件或子窗口时.
  • 当通过 +LastFound 选项访问 GUI 窗口时.

通过 ahk_id 方法或作为最后找到的窗口访问控件或子窗口时, 无需打开 DetectHiddenWindows. 通过 +LastFound 选项访问 GUI 窗口时, 同样是不需要的.

Cloaked(非显示) 窗口被视为隐藏的. 在 Windows 8 中引入的 Cloaked 窗口是指处于非活动状态的虚拟桌面或 UWP 应用程序的窗口, 这些窗口被挂起是为了提高性能, 或更确切地说是减少内存消耗. 在 Windows 10 中, 这些进程在任务管理器中以绿色的叶子指示. 此类窗口在视图中是隐藏的, 但是可能仍具有 WS_VISIBLE 窗口样式.

内置变量 A_DetectHiddenWindows 包含了当前设置(1 或 0).

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

DetectHiddenText

示例

打开检测隐藏窗口.

DetectHiddenWindows True


DirCopy - 语法 & 使用 | AutoHotkey v2

DirCopy

复制文件夹, 及其所有子文件夹和文件(类似于 xcopy) 或归档文件(如ZIP) 的全部内容.

DirCopy Source, Dest , Overwrite

参数

Source

类型: 字符串

源目录的名称(不含末尾的反斜杠), 如果未指定绝对路径, 则假定在 A_WorkingDir 中. 例如: C:\My Folder

如果操作系统支持, Source 也可以是归档文件的路径, 在这种情况下, 其内容将被复制到目标目录. 总是支持 ZIP 文件. TAR 文件至少需要 Windows 10 (1803) build 17063. RAR, 7z, gz 和其他至少需要 Windows 11 23H2(使用了 libarchive, 其中列出了所有支持的格式).

Dest

类型: 字符串

目标目录的名称(不含末尾的反斜杠), 如果未指定绝对路径, 则假定在 A_WorkingDir 中. 例如: C:\Copy of My Folder

Overwrite

类型: 整数

如果省略, 则默认为 0. 否则, 指定下列数字之一, 指示是否覆盖已存在的文件:

0: 不覆盖现有的文件. 如果已经存在以 Dest 为名称的文件或目录, 则操作会失败并且没有任何效果.

1: 覆盖现在的文件. 但是, 不会删除在 Dest 中没有被 Source 目录中文件覆盖的其他子目录或文件.

其他值保留供将来使用.

错误处理

如果发生错误, 则抛出异常.

但是, 如果源目录包含任何由 PageName.htm 的文件和相应的名称为 PageName_files 的目录组成的保存的网页, 那么即使复制成功也可能抛出异常.

备注

如果目标目录的结构不存在, 则可行时会进行创建.

由于该操作将以递归方式复制文件夹及其所有子文件夹和文件, 因此将文件夹复制到自身内部某个位置的结果是不确定的. 要解决此问题, 请先将其复制到自身外部, 然后使用 DirMove 将其复制移动到所需位置.

DirCopy 只复制单个文件夹. 若要复制文件夹中的内容(它的所有文件和子文件夹, 而不复制文件夹本身), 请参阅 FileCopy 的示例部分.

相关

DirMove, FileCopy, FileMove, FileDelete, 文件循环, DirSelect, SplitPath

示例

复制目录到新位置.

DirCopy "C:\My Folder", "C:\Copy of My Folder"

提示用户复制文件夹.

SourceFolder := DirSelect(, 3, "Select the folder to copy")
if SourceFolder = ""
    return
; 否则继续.
TargetFolder := DirSelect(, 3, "Select the folder IN WHICH to create the duplicate folder.")
if TargetFolder = ""
    return
; 否则继续.
Result := MsgBox("A copy of the folder '" SourceFolder "' will be put into '" TargetFolder "'. Continue?",, 4)
if Result = "No"
    return
SplitPath SourceFolder, &SourceFolderName  ; 仅从它的完整路径中提取文件夹名称.
try
    DirCopy SourceFolder, TargetFolder "\" SourceFolderName
catch
    MsgBox "The folder could not be copied, perhaps because a folder of that name already exists in '" TargetFolder "'."
return


DirCreate - 语法 & 使用 | AutoHotkey v2

DirCreate

创建文件夹.

DirCreate DirName

参数

DirName

类型: 字符串

要创建的目录的名称, 如果没有指定绝对路径, 则假定该目录位于 A_WorkingDir.

错误处理

如果发生错误, 则抛出 OSError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

函数还将创建在 DirName 中指定的所有父目录(如果它们还不存在的话).

相关

DirDelete

示例

创建一个新的目录, 必要时包括其父目录.

DirCreate "C:\Test1\My Images\Folder2"


DirDelete - 语法 & 使用 | AutoHotkey v2

DirDelete

删除文件夹.

DirDelete DirName , Recurse

参数

DirName

类型: 字符串

要删除的目录名, 如果未指定绝对路径, 则假定在 A_WorkingDir 中.

Recurse

类型: 布尔值

如果省略, 它默认为 0(false).

如果为 false, 不 移除 DirName 中包含的文件和子目录. 此时如果 DirName 不是空的, 则不进行操作并且抛出异常.

如果为 true, 移除所有文件和子目录(类似于 Windows 命令 "rmdir /S").

错误处理

如果发生错误, 则抛出异常.

相关

DirCreate, FileDelete

示例

删除目录, 但仅限于空目录.

DirDelete "C:\Download Temp"

删除目录, 包括其中的文件和子目录.

DirDelete "C:\Download Temp", 1


DirExist - 语法 & 使用 | AutoHotkey v2

DirExist

检查文件夹是否存在并返回其属性.

AttributeString := DirExist(FilePattern)

参数

FilePattern

类型: 字符串

单文件夹的名称或通配符模式, 如 "C:\Program*". 如果未指定绝对路径, 则假定 FilePattern 位于 A_WorkingDir 中.

支持星号(*) 和问号(?) 作为通配符. * 匹配零个或多个字符, 而 ? 匹配任何单个字符. 使用示例:

  • * 匹配所有文件夹.
  • gr?y 匹配 gray 和 grey.
  • *report* 匹配任何包含单词 "report" 的文件夹名称.

返回值

类型: 字符串

函数返回第一个符合条件的文件夹的属性. 这个字符串是 ASHDOC 的一个子集, 其中每个字母的意思如下:

  • A = ARCHIVE(存档)
  • S = SYSTEM(系统)
  • H = HIDDEN(隐藏)
  • D = DIRECTORY(目录)
  • O = OFFLINE(离线)
  • C = COMPRESSED(压缩)

因为这个函数只检查文件夹是否存在, 所以 "D" 总是出现在返回值中. 如果没有找到文件夹, 则返回一个空字符串.

备注

注意, 在包含文件和子文件夹的 MyFolder 中诸如 DirExist("MyFolder\*") 之类的搜索只告诉您文件夹是否存在. 如果您想检查文件 和 文件夹是否存在, 请使用 FileExist.

与 FileGetAttrib 不同, DirExist 支持通配符模式, 如果存在匹配的文件夹, 它总是返回一个非空值.

由于空字符串被视为 "false", 所以函数的返回值总是可以用作准布尔值. 例如, 如果文件夹存在, 语句 if DirExist("C:\MyFolder") 为 true(真), 反之为 false(假).

由于 FilePattern 可能包含通配符, 因此 DirExist 可能不适合验证要与其他函数或程序一起使用的文件夹路径. 例如, DirExist("Program*") 可能会返回属性, 尽管 "Program*" 不是一个有效的文件夹名称. 在这种情况下, 应当先考虑使用 FileGetAttrib.

相关

FileExist, FileGetAttrib, 文件循环

示例

如果文件夹确实存在, 会显示一个消息框.

if DirExist("C:\Windows")
    MsgBox "The target folder does exist."

如果至少有一个程序文件夹存在, 则显示一个消息框.

if DirExist("C:\Program*")
    MsgBox "At least one program folder exists."

如果文件夹 不 存在, 则显示一个消息框.

if not DirExist("C:\Temp")
    MsgBox "The target folder does not exist."

展示如何检查文件夹的指定属性.

if InStr(DirExist("C:\System Volume Information"), "H")
    MsgBox "The folder is hidden."


DirMove - 语法 & 使用 | AutoHotkey v2

DirMove

移动文件夹, 及其所有子文件夹和文件. 它也可以重命名一个文件夹.

DirMove Source, Dest , OverwriteOrRename

参数

Source

类型: 字符串

源目录的名称(不含末尾的反斜杠), 如果未指定绝对路径, 则假定在 A_WorkingDir 中. 例如: C:\My Folder

Dest

类型: 字符串

目标目录的名称(不含末尾的反斜杠), 如果未指定绝对路径, 则假定在 A_WorkingDir 中. 例如: D:\My Folder.

注意: Dest 是目录在移动后使用的实际路径和名称; 它 不是 Source 移动到的目录(下面提到的已知限制除外).

OverwriteOrRename

类型: 字符串

如果省略，则默认为 0. 否则, 指定以下值之一, 来指示是否覆盖或重命名现有文件:

0: 不覆盖现有的文件. 如果 Dest 作为文件或目录已经存在, 则操作失败.

1: 覆盖现在的文件. 但是, Dest 中的任何文件或子文件夹如果在 Source 中没有对应文件都不会被删除. 已知限制: 如果 Dest 已作为文件夹存在, 并且与 Source 在同一个卷上, 则将 Source 移入其中而不是覆盖它. 为了避免这种情况, 请参阅下一个选项.

2: 与上面的模式 1 相同, 只是没有限制.

R: 重命名目录而不移动它. 尽管普通的重命名和移动具有相同的效果, 但如果您想要 "完全成功或完全失败" 的结果时它就会有用; 即您不希望由于 Source 或其中的某个文件被锁定(在使用中) 而只是部分移动成功. 尽管这种方法不能移动 Source 到另一个卷中, 但它可以移动到同一个卷中的其他任何目录. 如果 Dest 作为文件或目录已经存在, 则操作失败.

错误处理

如果发生错误, 则抛出异常.

备注

DirMove 移动单个文件夹到新位置. 要移动整个文件夹中的内容(它的所有文件和子文件夹, 不包括文件夹本身), 请参阅 FileMove 的示例部分.

如果源和目标在不同的卷或 UNC 路径中, 则会执行复制/删除操作而不进行移动.

相关

DirCopy, FileCopy, FileMove, FileDelete, File-loops, DirSelect, SplitPath

示例

移动目录到新驱动器.

DirMove "C:\My Folder", "D:\My Folder"

简单地重命名.

DirMove "C:\My Folder", "C:\My Folder (renamed)", "R"

只有在同一个卷上, 文件夹可以被 "重命名到" 另一个位置.

DirMove "C:\My Folder", "C:\New Location\My Folder", "R"


DirSelect - 语法 & 使用 | AutoHotkey v2

DirSelect

显示可以让用户选择文件夹的标准对话框.

SelectedFolder := DirSelect(StartingFolder, Options, Prompt)

参数

StartingFolder

类型: 字符串

如果为空或省略, 则对话框的初始选择为用户的我的文档文件夹或可能是此电脑(以前是我的电脑或计算机)). 可以指定 CLSID 文件夹, 如 "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"(即此电脑) 来从特定的专用文件夹开始导航.

否则, 此参数最常见的用法是星号后面紧跟着初始选择的驱动器或文件夹的绝对路径. 例如, "*C:\" 会初始选择 C 驱动器. 同样地, "*C:\My Folder" 会初始选择这个特殊的文件夹.

星号表示允许用户从起始文件夹向上导航(接近根目录). 如果没有星号, 则强制用户在 StartingFolder(或 StartingFolder 自身) 中选择文件夹. 省略星号的一个好处是最初 StartingFolder 会显示为树形展开状态, 这样可以节省用户点击前面加号的时间.

如果有星号, 向上导航也可以选择限制在桌面以外的文件夹中. 这是通过在星号前面加上最顶层文件夹的绝对路径, 后面正好是一个空格或制表符来实现的. 例如, "C:\My Folder *C:\My Folder\Projects" 将不允许用户导航到比 C:\My Folder 更上级的文件夹(不过初始选择可以是 C:\My Folder\Projects):

Options

类型: 整数

如果省略, 则默认为 1. 否则, 请指定下列数字的之一:

0: 禁用下面所有选项.

1: 提供允许用户新建文件夹的按钮.

加 2 到上面的数字来提供允许用户输入文件夹名称的编辑区域. 例如, 此参数值为 3 表示同时提供编辑区域和 "新建文件夹" 按钮.

加 4 到上面的数字来忽略 BIF_NEWDIALOGSTYLE 属性. 加 4 确保了 DirSelect 即使在像 WinPE 或 BartPE 这样的预安装环境中也能正常工作. 然而, 这样阻止了 "新建文件夹" 按钮的出现.

如果用户在编辑区域中输入了无效的文件夹名称, 则 SelectedFolder 会被设置为在导航树中选择的文件夹而不是用户输入的内容.

Prompt

类型: 字符串

如果为空或省略, 则默认为 "Select Folder - " A_ScriptName(即当前脚本的名称). 否则, 指定显示在窗口中用来提示用户操作的文本.

返回值

类型: 字符串

此函数返回用户选择的文件夹的完整路径和名称. 如果用户取消对话框(即不希望选择文件夹), 则返回空字符串. 如果用户选择根目录(如 C:\), 则返回值将包含末尾的反斜杠. 如果不希望这样, 则使用如下方法移除它:

Folder := RegExReplace(DirSelect(), "\\$")  ; 移除末尾的反斜杠, 如果存在.

如果系统拒绝显示对话框, 也会返回一个空字符串, 但这是非常罕见的.

备注

文件夹选择对话框通常看起来像这样:

GUI 窗口可以使用 +OwnDialogs 选项的方法来显示模式文件夹选择对话框. 模式对话框在其消失之前会阻止用户与 GUI 窗口进行交互.

相关

FileSelect, MsgBox, InputBox, ToolTip, GUI, CLSID List, DirCopy, DirMove, SplitPath

此外, 操作系统提供了标准的对话框让用户选取字体, 颜色或图标. 这些对话框可以通过 DllCall 与 comdlg32\ChooseFont, comdlg32\ChooseColor 或 shell32\PickIconDlg 的组合来显示. 请在论坛中搜索示例.

示例

允许用户选择一个文件夹, 并提供一个编辑字段和 "新建文件夹" 按钮.

SelectedFolder := DirSelect(, 3)
if SelectedFolder = ""
    MsgBox "You didn't select a folder."
else
    MsgBox "You selected folder '" SelectedFolder "'."

CLSID 例子. 允许用户选择此电脑(以前是我的电脑或计算机) 目录下的文件夹.

SelectedFolder := DirSelect("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}")  ; 我的电脑.


DllCall - 语法 & 使用 | AutoHotkey v2

DllCall

调用 DLL 文件中的函数, 例如标准的 Windows API 函数.

Result := DllCall("DllFile\Function" , Type1, Arg1, Type2, Arg2, "Cdecl ReturnType")

参数

[DllFile\]Function

类型: 字符串或整数

DLL 或 EXE 文件名后面跟着一个反斜杠和函数名. 例如: "MyDLL\MyFunction"(文件扩展名省略时默认为 ".dll"). 如果未指定绝对路径, 则假定 DllFile 在系统的 PATH 指定的路径或 A_WorkingDir 中. 注意, DllCall() 需要带反斜杠(\) 的路径. 不支持正斜杠(/).

当调用位于 User32.dll, Kernel32.dll, ComCtl32.dll 或 Gdi32.dll 中的函数时, 可以省略 DllFile. 例如, "User32\IsWindowVisible" 和 "IsWindowVisible" 产生相同的结果.

如果使用指定的名称无法找到函数, 则自动附加 "W"(Unicode) 前缀. 例如, "MessageBox" 等同于 "MessageBoxW".

当 重复 调用 DLL 时, 通过预先加载此 DLL 文件可以显著改善执行效率.

此参数也可以仅是一个表示需调用函数的内存地址的整数. 如 COM 和 CallbackCreate 提供的地址.

如果该参数是一个对象, 则使用该对象的 Ptr 属性的值. 如果不存在这样的属性, 则抛出 PropertyError.

Type1, Arg1

类型: 字符串

这样的每对数据表示需传递给函数的单个参数. 参数的个数没有限制. 关于 Type, 请参阅请参阅下面的类型表. 关于 Arg, 指定传递给函数的值.

Cdecl ReturnType

类型: 字符串

通常省略单词 Cdecl, 因为大多数函数使用标准调用约定而不是 "C" 调用约定(像 wsprintf 这样接受可变数目参数的函数在这点上是个例外). 注意, 不支持大多数面向对象的 C++ 函数使用的 thiscall 约定.

如果此参数存在, 那么单词 Cdecl 应该在返回值类型前列出(如果有). 在单词间使用空格或 tab 分隔. 例如: "Cdecl Str".

因为在 64 位代码中不存在单独的 "C" 调用约定, 所以在 AutoHotkey 的 64 位版本中可以使用 Cdecl 但没有效果.

ReturnType: 如果函数返回 32 位的有符号整型(Int), BOOL, 或没有返回值, 则 ReturnType 可以省略. 否则, 需要指定下面类型表中参数类型的其中一个. 还支持星号后缀.

返回值

类型: 字符串或整数

DllCall 返回 Function 返回的实际值. 如果 Function 属于不返回值的类型, 则结果为指定返回类型的未定义值(默认为整数).

参数和返回值的类型

类型 | 描述
Str

一个字符串, 如 "Blue" 或 MyVar, 或 VarRef(如 &MyVar). 如果被调用的函数修改了字符串, 并且参数是裸变量或 VarRef, 那么它的内容将被更新. 例如, 下面的调用将把 MyVar 的内容转换为大写字母: DllCall("CharUpper", "Str", MyVar).

如果函数的设计存储长度大于参数的输入值(或者参数仅用于输出), 建议创建一个缓冲, 使用 Ptr 类型传递, 然后使用 StrGet 在函数返回后检索字符串, 如 wsprintf 示例所示.

否则, 请在调用函数之前确保变量足够大. 这可以通过调用 VarSetStrCapacity(&MyVar, 123) 来实现, 其中 123 是 MyVar 肯定能够容纳的 16 位单位(通俗地讲就是字符) 的数量. 如果变量返回时不是以空终止符结尾的, 则会显示一条错误消息, 并且由于内存可能由于缓冲溢出而损坏导致程序退出. 这通常表明变量的容量不足.

Str 参数不能是计算结果为数字(例如 i+1) 这样的表达式. 如果如此, 则不会调用函数并抛出 TypeError.

很少使用的 Str* 参数类型传递包含字符串地址的临时变量的地址. 如果传递了 VarRef, 如果函数将新地址写入临时变量, 则将新字符串复制到脚本变量. 它可以用在期望 "TCHAR **" 或 "LPTSTR *" 类型参数的函数中. 但是, 如果函数分配了内存并希望调用者释放它(例如通过调用 CoTaskMemFree), 则必须改用 Ptr* 参数类型.

注意: 在将字符串传递给函数时, 请注意函数所期望的字符串的 type(类型).
WStr | 由于 AutoHotkey 原生使用 UTF-16, 因此 WStr(宽字符串) 等同于 Str.
AStr

AStr 导致输入值自动转换为 ANSI. 由于用于此转换的临时内存仅足够容纳转换后的输入字符串, 因此函数写入其的任何值都将被丢弃. 要接收 ANSI 字符串作为输出参数, 请遵循以下示例:

buf := Buffer(length)  ; 分配临时缓冲.
DllCall("Function", "ptr", buf)  ; 传递缓冲给函数.
str := StrGet(buf, "cp0")  ; 从缓冲接收 ANSI 字符串.

还支持很少使用的 AStr* 参数类型, 其行为与 Str* 类型类似, 不同之处在于, 所有新字符串都将从 ANSI 转换为原生格式, UTF-16.

有关等效的 Win32 类型和其他详细信息, 请参阅二进制兼容性.
Int64 | 64 位整数, 其范围是 -9223372036854775808(-0x8000000000000000) 到 9223372036854775807(0x7FFFFFFFFFFFFFFF).
Int

32 位整数(最常用的整数类型), 其范围是 -2147483648(-0x80000000) 到 2147483647(0x7FFFFFFF). Int 有时也被称为 "Long".

在函数期望 BOOL 类型的参数中也应该使用 Int(BOOL 值应该是 1 或 0).

无符号的 Int(UInt) 也经常使用, 例如用作 DWORD.
Short | 16 位整数, 其范围是 -32768(-0x8000) 到 32767(0x7FFF). 无符号 Short(UShort) 能用于期望 WORD 的函数中.
Char | 8 位整数, 其范围是 -128(-0x80) 到 127(0x7F). 无符号 character(UChar) 能用于期望 BYTE 的函数中.
Float | 32 位浮点数, 具有 6 位精度.
Double | 64 位浮点数, 具有 15 位精度.
Ptr

指针大小的整数, 等同于 Int 或 Int64, 具体取决于运行脚本的 exe 是 32 位还是 64 位. Ptr 应该用于指向数组或结构(如 RECT* 或 LPPOINT) 以及几乎所有句柄(如 HWND, HBRUSH 或 HBITMAP) 的指针. 如果参数是指向简单数值的指针( 如 LPDWORD 或 int*), 通常应该使用 * 或 P 后缀代替 "Ptr".

如果将对象传递给 Ptr 参数, 则使用该对象的 Ptr 属性的值. 如果不存在此类属性, 则抛出 PropertyError. 通常, 该对象是 Buffer 对象.

如果将对象传递给 Ptr* 参数, 则在调用之前将检索对象的 Ptr 属性值, 并将包含该值的临时变量的地址传递给函数. 函数返回后, 新值将分配回该对象的 Ptr 属性.

Ptr 也可以和 * 或 P 后缀一起使用; 此时它应该用在通过 LPVOID* 或类似类型输出指针的函数中.

UPtr 也是有效的, 但有以下限制:

  • 由于 AutoHotkey 不支持无符号 64 位整数, 因此在 32 位版本中只能使用无符号整数.
  • 对象不支持.

注意: 要传递 NULL 句柄或指针, 请传递整数 0.
* 或 P
(后缀)

在上述任何类型上附加一个星号(星号前可选的空格), 以表示传递参数的地址而不是值本身(必须将被调用的函数设计为接受该参数). 由于此类参数的值可能会被函数修改, 每当传递一个 VarRef 作为参数时, 变量的内容将在函数返回后被更新. 例如, 以下调用将通过地址将 MyVar 的内容传递给 MyFunction, 但还将更新 MyVar 以反映 MyFunction 对它所做的任何更改: DllCall("MyDll\MyFunction", "Int*", &MyVar).

通常, 星号可用于参数类型或返回类型以 "LP" 开头的函数. 最常见的示例是 LPDWORD, 它是指向 DWORD 的指针. 由于 DWORD 是 32 位无符号整数, 因此请使用 "UInt*" 或 "UIntP" 表示 LPDWORD. 星号不能用于字符串类型(如 LPTSTR), 指向结构的指针(如 LPRECT) 或数组; 对于这些, 应使用 "Str" 或 "Ptr", 具体取决于您传递的是字符串, 地址或 Buffer.

注意: "Char*" 与 "Str" 不同, 因为 "Char*" 传递一个 8 位数字的地址, 而 "Str" 传递一系列字符的地址, 该字符可以是 16 位(Unicode) 或 8 位("AStr"), 具体取决于 AutoHotkey 的版本. 同样, "UInt*" 传递的是 32 位数字的地址, 因此如果函数期望值的数组或大于 32 位的结构, 则不应使用 "UInt*".

由于 AutoHotkey 中的变量没有固定类型, 因此传递给函数的地址指向临时内存, 而不是调用者的变量.
U (前缀)

在上述任一整数类型加上字母 U 前缀, 以将其解释为无符号整数(UInt64, UInt, UShort 和 UChar). 严格来说, 这仅对返回值和星号变量才是必需的, 因为按值传递的参数是无符号的还是有符号的(Int64 除外) 都无关紧要.

如果为无符号参数指定了负整数, 则该整数将被转换到无符号域中. 例如, 当 -1 作为 UInt 发送时, 它将被转换成 0xFFFFFFFF.

不支持函数产生的 无符号 64 位整数. 因此, 要使用大于或等于 0x8000000000000000 的数字, 请省略 U 前缀并将从函数接收的任何负值解释为大整数. 例如, 如果将函数设计为产生 UInt64, 则将函数产生的 -1(Int64 类型), 实际上将产生 0xFFFFFFFFFFFFFFFF.
HRESULT

32 位整数. 这通常与 COM 函数一起使用, 并且仅作为返回类型有效, 没有任何前缀或后缀. 错误值(由 FAILED macro 定义) 永远不会返回; 而是抛出一个 OSError. 因此, 成功时, 返回值范围是 0 到 2147483647.

HRESULT 是 ComCall 的默认返回类型.

错误

DllCall 会在下列任何一种情况下抛出 Error:

  • OSError: 使用 HRESULT 返回类型, 函数返回一个错误值(由 FAILED macro 定义). Exception.Extra 包含十六进制错误码.
  • TypeError: [DllFile\]Function 参数是一个浮点数. 需要字符串或正整数.
  • ValueError: 返回的类型或指定的参数的类型无效.
  • TypeError: 参数传递了一个意外类型的值. 例如, 将计算结果为数字的表达式传递给字符串(str) 参数, 将非数字字符串传递给数值参数, 或者将对象传递给 非 Ptr 类型的参数.
  • Error: 无法访问或加载指定的 DllFile. 如果没有明确指明 DllFile 的路径, 则该文件必须存在于系统的 PATH 或 A_WorkingDir 中. 如果用户没有访问文件的权限, 或者 AutoHotkey 是 32 位而 DLL 是 64 位(反之亦然), 也都可能发生此错误.
  • Error: 在 DLL 中找不到指定的函数.
  • Error: 该函数已被调用, 但由于致命异常而中止. Exception.Extra 包含异常代码. 例如, 0xC0000005 表示 "访问冲突". 在这种情况下, 线程将中止(如果没有使用 try 的话), 但是仍将更新所有星号变量. 致命异常的一个例子是取消引用无效指针(如 NULL(0)). 由于 Cdecl 函数永远不会产生下一段中描述的错误, 因此当传递给它的参数太少时, 它可能会生成异常.
  • Error: 该函数已被调用, 但传递了太多或太少的参数. Exception.Extra 包含参数列表不正确的字节数. 如果为正, 则传递了太多的参数(或参数太大), 或者调用需要 CDecl. 如果为负, 则传递的参数太少. 应该纠正这种情况, 以确保函数的可靠运行. 出现此错误也可能表示抛出了异常. 请注意, 由于使用 x64 调用约定, 因此 64 位版本永远不会引发此错误.

原生异常和 A_LastError

尽管有内置的异常处理机制, 仍可能因使用 DllCall 使脚本崩溃. 当函数不直接生成异常但产生不适当的数据时, 如无效的指针或未终止的字符串, 可能会发生这种情况. 如果脚本向其传递了不合适的值, 如无效的指针或容量不足的 "str", 则可能不是函数的错误. 当脚本指定了不适当的参数类型或返回类型时, 如声明函数产生的普通整数是星号变量或 str, 脚本也可能崩溃.

内置变量 A_LastError 包含操作系统的 GetLastError() 函数的结果.

性能

当需要重复调用一个 DLL 时, 预先明确装载它可以显著提高执行效率(对于标准的 DLL 文件如 User32 这是没有必要的, 因为它是常驻的). 这种做法避免了 DllCall 每次都需要在内部调用 LoadLibrary 和 FreeLibrary. 例如:

hModule := DllCall("LoadLibrary", "Str", "MyFunctions.dll", "Ptr")  ; 避免在循环中使用 DllCall 来加载库.
Loop Files, "C:\My Documents\*.*", "R"
    result := DllCall("MyFunctions\BackupFile", "Str", A_LoopFilePath)
DllCall("FreeLibrary", "Ptr", hModule)  ; 为了释放内存, 在使用 DLL 后需要进行卸载.

通过预先查找函数的地址甚至可以获得更快的性能. 例如:

; 在下面的示例中, 如果 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)

如果 DllCall 的首个参数是原义的字符串如 "MulDiv" 并且包含了函数的 DLL 在脚本开始前已正常装载了, 或者已成功通过 #DllLoad 加载, 那么此字符串会自动被解析为函数地址. 这种内置的优化比上面显示的示例更有效.

最后, 当将字符串变量传递给不会改变字符串长度的函数时, 通过将变量按地址传递(例如 StrPtr(MyVar)), 而不是以 "str" 的形式传递, 可以提高性能(特别是当字符串很长时). 后面的例子把字符串转换成大写: DllCall("CharUpper", "Ptr", StrPtr(MyVar), "Ptr").

结构和数组

结构是内存中连续存储的 成员(空间) 的集合. 大多数成员倾向于是整数.

接受结构(或内存块数组) 地址的函数可以通过某种方式分配内存并将内存地址传递给函数来调用. Buffer 对象被推荐用于此目的. 一般使用以下步骤:

1) 调用 MyStruct := Buffer(123, 0) 来分配一个缓冲来保存结构体的数据. 将 123 替换为至少与结构大小一样大的数字, 以字节为单位. 指定零作为最后一个参数是可选的; 它将所有成员初始化为二进制零, 这通常用于避免在下一步中频繁调用 NumPut.

2) 如果目标函数使用结构中的初始值, 请调用 NumPut("UInt", 123, MyStruct, 4) 初始化任何不为零的成员. 将 123 替换为要放入目标成员的整数(或指定 StrPtr(Var) 来存储字符串的地址). 将 4 替换为目标成员的偏移量(有关 "offset" 的说明, 请参阅步骤 #4). 将 "UInt" 替换为适当的类型, 如果成员是指针或句柄, 则如 "Ptr".

3) 调用目标函数, 将 MyStruct 作为 Ptr 参数传递. 例如, DllCall("MyDll\MyFunc", "Ptr", MyStruct). 该函数将检查和/或更改一些成员. DllCall 会自动使用缓冲的地址, 通常使用 MyStruct.Ptr 来检索.

4) 使用 MyInteger := NumGet(MyStruct, 4, "UInt") 从结构中检索任何所需的整数. 将 4 替换为结构中目标构件的偏移量. 第一个成员的偏移量始终为 0. 第二个成员的偏移量为 0 加第一个成员的大小(通常为 4). 第二个成员之后的成员是前一个成员的偏移量加上前一个成员的大小. 大多数成员 -- 如 DWORD, Int 和其他类型的 32 位整数 -- 的大小为 4 个字节. 将 "UInt" 替换为适当的类型, 如果成员是指针或句柄, 则将其省略.

有关实际用法, 请参阅结构示例.

已知限制

当一个变量的字符串地址(例如 StrPtr(MyVar)) 被传递给一个函数, 并且该函数改变了变量内容的长度时, 那么后面使用这个变量可能出现错误. 要解决此问题, 有下面几种方法: 1) 将 MyVar 作为 "Str" 参数传递, 而不是 Ptr/地址; 2) 在调用 DllCall 后, 调用 VarSetStrCapacity(&MyVar, -1) 来更新变量的内部存储长度.

由函数保存到变量中的任何二进制零都可以作为终止符, 防止大多数内置函数访问或更改零右边的所有数据. 但是, 这样的数据可以使用 StrPtr 检索字符串的地址, 并将其传递给其他函数, 例如 NumPut, NumGet, StrGet, StrPut, 以及 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 中一般可以通过 ComObject, ComObjGet 或 ComObjActive 以及内置的对象语法进行访问.

不支持 IDispatch 的 COM 对象可以通过从对象接口的虚拟函数表中获取函数的地址用于 DllCall 中. 有关详情, 请参阅下面的示例. 但是, 通常最好使用 ComCall 来简化此过程.

.NET 框架

.NET Framework 库由被称为公共语言运行时(CLR) 的 "虚拟机" 来执行. 在这种情况下, .NET DLL 文件的格式与常规 DLL 文件的格式不同, 并且通常不包含 DllCall 能够调用的任何函数.

但是, AutoHotkey 可以通过 COM 可调用包装器来使用 CLR. 除非该库也已注册为通用 COM 组件, 否则必须先通过 DllCall 手动初始化 CLR 本身. 有关详情, 请参阅 .NET Framework Interop.

相关

二进制兼容性, 缓冲对象, ComCall, PostMessage, OnMessage, CallbackCreate, Run, VarSetStrCapacity, 函数, SysGet, #DllLoad, Windows API Index

示例

调用 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", 1)

调用 API 函数 "IsWindowVisible" 来判断记事本窗口是否可见.

DetectHiddenWindows True
if not DllCall("IsWindowVisible", "Ptr", WinExist("Untitled - Notepad"))  ; WinExist 返回 HWND.
    MsgBox "The window is not visible."

调用 API 的 wsprintf() 函数来给数字 432 加上前导零以填充到 10 个字符的长度(0000000432).

ZeroPaddedNumber := Buffer(20)  ; 确保缓冲足够大以便容纳新的字符串.
DllCall("wsprintf", "Ptr", ZeroPaddedNumber, "Str", "%010d", "Int", 432, "Cdecl")  ; 需要 Cdecl 调用约定.
MsgBox StrGet(ZeroPaddedNumber)

; 此外, 使用 Format 函数配合 0 标志可以达到同样的效果:
MsgBox Format("{:010}", 432)

演示 QueryPerformanceCounter(), 它提供了比 A_TickCount 的 10 ms 更高的精确度.

DllCall("QueryPerformanceFrequency", "Int64*", &freq := 0)
DllCall("QueryPerformanceCounter", "Int64*", &CounterBefore := 0)
Sleep 1000
DllCall("QueryPerformanceCounter", "Int64*", &CounterAfter := 0)
MsgBox "Elapsed QPC time is " . (CounterAfter - CounterBefore) / freq * 1000 " ms"

按下热键临时减慢鼠标移动速度, 这样有助于准确定位. 按住 F1 来降低鼠标速度. 释放后则恢复原来的速度.

F1::
F1 up::
{
    static SPI_GETMOUSESPEED := 0x70
    static SPI_SETMOUSESPEED := 0x71
    static OrigMouseSpeed := 0

    switch ThisHotkey
    {
    case "F1":
        ; 获取鼠标当前的速度以便稍后恢复:
        DllCall("SystemParametersInfo", "UInt", SPI_GETMOUSESPEED, "UInt", 0, "Ptr*", &OrigMouseSpeed, "UInt", 0)
        ; 现在在倒数第二个参数中设置较低的速度 (范围为 1-20, 10 是默认值):
        DllCall("SystemParametersInfo", "UInt", SPI_SETMOUSESPEED, "UInt", 0, "Ptr", 3, "UInt", 0)
        KeyWait "F1"  ; 这里避免了由于键盘的重复特性导致再次执行 DllCall.

    case "F1 up":
        DllCall("SystemParametersInfo", "UInt", SPI_SETMOUSESPEED, "UInt", 0, "Ptr", OrigMouseSpeed, "UInt", 0)  ; 恢复原始速度.
    }
}

监视活动窗口并显示其焦点控件中的垂直滚动条的位置(实时更新).

SetTimer WatchScrollBar, 100

WatchScrollBar()
{
    try FocusedHwnd := ControlGetFocus("A")
    if !FocusedHwnd  ; 没有焦点控件.
        return
    ; 在工具提示中显示垂直或水平滚动条的位置:
    ToolTip(DllCall("GetScrollPos", "Ptr", FocusedHwnd, "Int", 1))  ;  最后一个参数 1 表示 SB_VERT, 而 0 表示 SB_HORZ.
}

写入一些文本到文件, 然后从文件读取回内存. 在同时读取或写入多个文件时, 使用这种方法可以改善性能. 此外, 使用 FileOpen 可以实现同样的目的.

FileName := FileSelect("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 !hFile
{
    MsgBox "Can't open '" FileName "' for writing."
    return
}
TestString := "This is a test string.`r`n"  ; 通过这种方式写入内容到文件时, 要使用 `r`n 而不是 `n 来开始新行.
StrSize := StrLen(TestString) * 2
DllCall("WriteFile", "Ptr", hFile, "Str", TestString, "UInt", StrSize, "UIntP", &BytesActuallyWritten := 0, "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 !hFile
{
    MsgBox "Can't open '" FileName "' for reading."
    return
}
; 为要读取的字符串分配一块内存:
Buf := Buffer(StrSize)
DllCall("ReadFile", "Ptr", hFile, "Ptr", Buf, "UInt", Buf.Size, "UIntP", &BytesActuallyRead := 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", hFile)  ; 关闭文件.
MsgBox "The following string was read from the file: " StrGet(Buf)

当您按下 Win+C 时, 隐藏鼠标光标. 稍后若要显示光标, 请再次按下热键.

OnExit (*) => SystemCursor("Show")  ; 确保到脚本退出时鼠标光标是显示的.

#c::SystemCursor("Toggle")  ; Win+C 热键用来切换鼠标光标的显示和隐藏.

SystemCursor(cmd)  ; cmd = "Show|Hide|Toggle|Reload"
{
    static visible := true, c := Map()
    static sys_cursors := [32512, 32513, 32514, 32515, 32516, 32642
                         , 32643, 32644, 32645, 32646, 32648, 32649, 32650]
    if (cmd = "Reload" or !c.Count)  ; 在请求或首次调用时进行重载.
    {
        for i, id in sys_cursors
        {
            h_cursor  := DllCall("LoadCursor", "Ptr", 0, "Ptr", id)
            h_default := DllCall("CopyImage", "Ptr", h_cursor, "UInt", 2
                , "Int", 0, "Int", 0, "UInt", 0)
            h_blank   := DllCall("CreateCursor", "Ptr", 0, "Int", 0, "Int", 0
                , "Int", 32, "Int", 32
                , "Ptr", Buffer(32*4, 0xFF)
                , "Ptr", Buffer(32*4, 0))
            c[id] := {default: h_default, blank: h_blank}
        }
    }
    switch cmd
    {
      case "Show": visible := true
      case "Hide": visible := false
      case "Toggle": visible := !visible
      default: return
    }
    for id, handles in c
    {
        h_cursor := DllCall("CopyImage"
            , "Ptr", visible ? handles.default : handles.blank
            , "UInt", 2, "Int", 0, "Int", 0, "UInt", 0)
        DllCall("SetSystemCursor", "Ptr", h_cursor, "UInt", id)
    }
}

结构的例子. 把 RECT 结构的地址传递给 GetWindowRect(), 它会把窗口的左, 上, 右和下边的位置(相对于屏幕) 存入结构的成员中.

Run "Notepad"
WinWait "Untitled - Notepad"  ; 这里同时设置了 "上次找到的窗口" 以用于下面的 WinExist.
Rect := Buffer(16)  ; RECT 结构由四个 32 位整数组成(即 4*4=16).
DllCall("GetWindowRect", "Ptr", WinExist(), "Ptr", Rect)  ; WinExist 返回 HWND.
L := NumGet(Rect, 0, "Int"), T := NumGet(Rect, 4, "Int")
R := NumGet(Rect, 8, "Int"), B := NumGet(Rect, 12, "Int")
MsgBox Format("Left {1} Top {2} Right {3} Bottom {4}", L, T, R, B)

结构的例子. 把 RECT 结构的地址传递给 FillRect(), 这个结构表示需要临时描绘为红色的屏幕区域.

Rect := Buffer(16)  ; 设置容量为 4 个 4 字节整型.
NumPut( "Int", 0                  ; 左
      , "Int", 0                  ; 上
      , "Int", A_ScreenWidth//2   ; 右
      , "Int", A_ScreenHeight//2  ; 下
      , Rect)
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 := DateDiff(A_Now, A_NowUTC, "Seconds")  ; 取整后秒数会更精确.
    UTC_Delta := Round(-UTC_Delta/60)  ; 取整到最近的分钟数以确保精度.
    YYYYMMDDHHMISS := DateAdd(YYYYMMDDHHMISS, UTC_Delta, "Minutes")  ; 对本地时间应用偏移来转换到 UTC.

    SystemTime := Buffer(16)  ; 此结构由 8 个 UShort 组成(即 8*2=16).

    NumPut( "UShort", SubStr(YYYYMMDDHHMISS, 1, 4)  ; YYYY(年)
          , "UShort", SubStr(YYYYMMDDHHMISS, 5, 2)  ; MM(月, 01-12)
          , "UShort", 0                             ; Unused(周几)
          , "UShort", SubStr(YYYYMMDDHHMISS, 7, 2)  ; DD(日)
          , "UShort", SubStr(YYYYMMDDHHMISS, 9, 2)  ; HH(小时, 00-24)
          , "UShort", SubStr(YYYYMMDDHHMISS, 11, 2) ; MI(分钟)
          , "UShort", SubStr(YYYYMMDDHHMISS, 13, 2) ; SS(秒)
          , "UShort", 0                             ; Unused(毫秒)
          , SystemTime)

    return DllCall("SetSystemTime", "Ptr", SystemTime)
}

更多结构的例子:

  • 请参阅 WinLIRC 客户端脚本演示来学习如何使用 DllCall 来创建到 TCP/IP 服务器的连接并从那里接收数据.
  • 操作系统提供了标准的对话框, 提示用户选取字体, 颜色或图标. 这些对话框使用了结构, 并通过 DllCall 与 comdlg32\ChooseFont, comdlg32\ChooseColor 或 shell32\PickIconDlg 的组合来显示. 请在论坛中搜索示例.

从任务栏移除活动窗口 3 秒. 可以对比一下等同效果的 ComCall 示例.

/*
  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 := ComObject(CLSID_TaskbarList, IID_ITaskbarList)

activeHwnd := WinExist("A")

DllCall(vtable(tbl.ptr,3), "ptr", tbl)                     ; tbl.HrInit()
DllCall(vtable(tbl.ptr,5), "ptr", tbl, "ptr", activeHwnd)  ; tbl.DeleteTab(activeHwnd)
Sleep 3000
DllCall(vtable(tbl.ptr,4), "ptr", tbl, "ptr", activeHwnd)  ; tbl.AddTab(activeHwnd)

; 非包装接口指针必须手动释放.
ObjRelease(tbl.ptr)

vtable(ptr, n) {
    ; NumGet(ptr, "ptr") 返回对象的虚函数表(简称为 vtable) 的地址
    ; 表达式的其余部分从
    ; vtable 中获取第 n 个函数的地址.
    return NumGet(NumGet(ptr, "ptr"), n*A_PtrSize, "ptr")
}


Download - 语法 & 使用 | AutoHotkey v2

Download

从互联网下载文件.

Download URL, Filename

参数

URL

类型: 字符串

要下载的文件的 URL. 例如, "https://someorg.org" 可能会获取到该组织的欢迎页面.

Filename

类型: 字符串

指定要在本地创建的文件的名称, 如果没有指定绝对路径, 则假定该文件位于 A_WorkingDir. 任何现有文件都将被新文件 覆盖.

该函数下载为一个文件, 要下载为变量, 请参阅下面的示例.

错误处理

失败时抛出异常.

备注

此函数下载到文件. 要下载到变量, 请参阅下面的示例. 其他方法, 请参阅以下论坛主题: www.autohotkey.com/forum/topic10466.html

即使远程文件不存在, 下载也可能会成功. 这是因为许多 Web 服务器发送错误页面来代替丢失的文件. 该错误页面将代替 Filename 保存.

防火墙或存在多个网络适配器可能导致此函数失败. 此外, 某些网站可能会阻止此类下载.

缓存: 默认情况下, 直接从远程服务器检索 URL(即, 不从 Internet Explorer 的缓存检索). 要允许缓存, 请在 URL 之前加 *0 后跟一个空格; 例如: "*0 https://someorg.org". 星号后的 0 可以用任何有效的 dwFlags 数字代替; 有关详情, 请在 www.microsoft.com 搜索 InternetOpenUrl.

代理: 如果在 Microsoft Internet Explorer 的设置中配置了代理服务器, 则将使用它.

还支持 FTP 和 Gopher URL. 例如:

Download "ftp://example.com/home/My File.zip", "C:\My Folder\My File.zip"  ; 匿名登录.
Download "ftp://user:pass@example.com:21/home/My File.zip", "C:\My Folder\My File.zip"  ; 以特定用户身份登录.
Download "ftp://user:pass@example.com/My Directory", "C:\Dir Listing.html"  ; 获取一个 HTML 格式的目录列表.

相关

FileRead, FileCopy

示例

下载文本文件.

Download "https://www.autohotkey.com/download/2.0/version.txt", "C:\AutoHotkey Latest Version.txt"

下载 zip 文件.

Download "https://someorg.org/archive.zip", "C:\SomeOrg's Archive.zip"

下载文本到变量.

whr := ComObject("WinHttp.WinHttpRequest.5.1")
whr.Open("GET", "http://autohotkey.com/download/2.0/version.txt", true)
whr.Send()
; 使用 'true'(上面) 和调用下面的函数, 允许脚本保持响应.
whr.WaitForResponse()
version := whr.ResponseText
MsgBox version

发出异步 HTTP 请求.

req := ComObject("Msxml2.XMLHTTP")
; 打开启用异步的请求.
req.open("GET", "https://www.autohotkey.com/download/2.0/version.txt", true)
; 设置回调函数.
req.onreadystatechange := Ready
; 发送请求. Ready() 将在其完成后被调用.
req.send()
/*
; 如果你要一直等待到下载完毕, 就不需要 onreadystatechange 了.
; 设置 async=true 和像这样等待, 可以在下载过程中允许脚本保留响应
; 而 async=false 将使脚本无响应.
while req.readyState != 4
    sleep 100
*/
Persistent

Ready() {
    if (req.readyState != 4)  ; 没有完成.
        return
    if (req.status == 200) ; OK.
        MsgBox "Latest AutoHotkey version: " req.responseText
    else
        MsgBox "Status " req.status,, 16
    ExitApp
}


驱动器函数列表 | AutoHotkey v2

驱动器函数

用于检索有关计算机驱动器的各种类型的信息, 或对驱动器执行各种操作的函数. 点击函数名获取详细信息.

函数 | 描述
DriveEject | 弹出指定 CD/DVD 驱动器的托盘, 或弹出可移动驱动器.
DriveGetCapacity | 返回包含指定路径的驱动器的总容量, 单位为 mb(兆字节).
DriveGetFileSystem | 返回指定驱动器的文件系统的类型.
DriveGetLabel | 返回指定驱动器的卷标.
DriveGetList | 返回一串字母, 系统中的每个驱动器字母对应一个字符.
DriveGetSerial | 返回指定驱动器的卷序列号.
DriveGetSpaceFree | 包含指定路径的驱动器的空闲磁盘空间, 单位为 mb(兆字节).
DriveGetStatus | 返回包含指定路径的驱动器的状态.
DriveGetStatusCD | 返回指定 CD/DVD 驱动器的媒体状态.
DriveGetType | 返回包含指定路径的驱动器类型.
DriveLock | 阻止指定驱动器的弹出功能正常工作.
DriveRetract | 收回指定 CD/DVD 驱动器的托盘.
DriveSetLabel | 更改指定驱动器的卷标签.
DriveUnlock | 恢复指定驱动器的弹出功能.

错误处理

失败时抛出异常.

相关

所有函数列表

示例

允许用户选择一个驱动器来分析它.

folder := DirSelect( , 3, "Pick a drive to analyze:")
if not folder
    return
MsgBox
(
    "All Drives: " DriveGetList() "
    Selected Drive: " folder "
    Drive Type: " DriveGetType(folder) "
    Status: " DriveGetStatus(folder) "
    Capacity: " DriveGetCapacity(folder) " MB
    Free Space: " DriveGetSpaceFree(folder) " MB
    Filesystem: " DriveGetFilesystem(folder) "
    Volume Label: " DriveGetLabel(folder) "
    Serial Number: " DriveGetSerial(folder)
)


DriveEject / DriveRetract - 语法 & 使用 | AutoHotkey v2

DriveEject / DriveRetract

弹出或收回指定 CD/DVD 驱动器的托盘. DriveEject 也可以弹出一个可移动驱动器.

DriveEject Drive
DriveRetract Drive

参数

Drive

类型: 字符串

如果省略, 则默认为通过从 A 到 Z 的迭代找到的第一个 CD/DVD 驱动器(如果没有找到驱动器, 则抛出异常). 否则, 请指定驱动器的字母, 后面跟着可选的冒号或冒号和反斜杠. 例如, "D", "D:" 或 "D:\".

这也可以是一个设备路径, 形式为 \\?\Volume{...}, 可以通过在命令行运行 mountvol 来发现. 在这种情况下, 不需要为驱动器分配一个盘符字母.

错误处理

如果检测到失败, 则抛出异常.

这两个函数可能无法在网络驱动器或资源管理器中没有 "弹出" 选项的任何驱动器上工作. 底层的系统函数并不总是报告失败, 所以可能会或不会抛出异常.

备注

在允许脚本继续之前, 函数会等待弹出或收回完成.

可以通过测量函数完成所需的时间来判断之前的托盘状态, 如下例所示.

弹出一个可移动驱动器通常相当于在资源管理器中使用 "弹出" 上下文菜单选项, 但是如果文件正在使用不会显示警告. 与安全移除硬件选项不同, 这只卸载由 Drive 参数标识的卷, 而不是整个设备.

DriveEject 和 DriveRetract 对应于 IOCTL_STORAGE_EJECT_MEDIA 和 IOCTL_STORAGE_LOAD_MEDIA 控制代码, 它们也可能对 CD/DVD 以外的驱动器类型产生影响, 比如磁带驱动器.

相关

DriveGetStatusCD, 驱动器函数

示例

弹出(打开) 首个 CD/DVD 驱动器.

DriveEject()

收回(关闭) 第一个 CD/DVD 驱动器的托盘.

DriveRetract()

弹出所有可移动驱动器(CD/DVD 驱动器除外).

Loop Parse DriveGetList("REMOVABLE")
{
    if MsgBox("Eject " A_LoopField ":, even if files are open?",, "y/n") = "yes"
        DriveEject(A_LoopField)
}
else
    MsgBox "No removable drives found."

定义一个热键, 根据函数完成的时间, 将托盘切换到相反的状态(打开或关闭).

#c::
{
    DriveEject
    ; 如果函数快速完成, 则托盘已经处于弹出状态.
    ; 在这种情况下, 收回托盘:
    if (A_TimeSinceThisHotkey < 1000)  ; 如果需要, 可调整这个时间.
        DriveRetract
}


DriveGetCapacity - 语法 & 使用 | AutoHotkey v2

DriveGetCapacity

返回包含指定路径的驱动器的总容量, 单位为 mb(兆字节).

Capacity := DriveGetCapacity(Path)

参数

Path

类型: 字符串

驱动器包含的任意路径(也可能对 UNC 路径和映射驱动器有效).

返回值

类型: 整数

函数返回包含 Path 的驱动器的总容量, 单位为 mb(兆字节).

错误处理

失败时抛出异常.

备注

一般来说, Path 可以是任意路径. 由于 NTFS 支持挂载卷和目录连接, 具有相同驱动器号的不同路径可以产生不同数量的容量.

相关

DriveGetSpaceFree, 驱动器函数

示例

有关此函数的演示, 请参阅驱动器函数页面的示例 #1.


DriveGetFileSystem - 语法 & 使用 | AutoHotkey v2

DriveGetFileSystem

返回指定驱动器的文件系统的类型.

FileSystem := DriveGetFileSystem(Drive)

参数

Drive

类型: 字符串

驱动器字母后跟着冒号和可选的反斜杠, 或 UNC 名称, 如 "\server1\share1".

返回值

类型: 字符串

函数返回 Drive 的文件系统的类型. 可能的由系统定义的值; 它们包括(但不限于) 以下内容: NTFS, FAT32, FAT, CDFS(通常表示 CD), 或 UDF(通常表示 DVD).

错误处理

失败时例如驱动器不包含格式化的媒体, 则抛出异常.

相关

驱动器函数

示例

有关此函数的演示, 请参阅驱动器函数页面的示例 #1.


DriveGetLabel - 语法 & 使用 | AutoHotkey v2

DriveGetLabel

返回指定驱动器的卷标.

Label := DriveGetLabel(Drive)

参数

Drive

类型: 字符串

驱动器字母后跟着冒号和可选的反斜杠, 或 UNC 名称, 如 "\server1\share1".

返回值

类型: 字符串

函数返回 Drive 的卷标.

错误处理

失败时抛出异常.

相关

DriveSetLabel, 驱动器函数

示例

有关此函数的演示, 请参阅驱动器函数页面的示例 #1.


DriveGetList - 语法 & 使用 | AutoHotkey v2

DriveGetList

返回一串字母, 系统中的每个驱动器字母对应一个字符.

List := DriveGetList(DriveType)

参数

DriveType

类型: 字符串

如果省略, 则检索所有类型的驱动器. 否则, 指定为下列单词的其中一个来获取该特定类型的驱动器: CDROM, REMOVABLE, FIXED, NETWORK, RAMDISK, UNKNOWN.

返回值

类型: 字符串

函数返回系统中的驱动器字母, 取决于 DriveType. 例如: ACDEZ.

相关

驱动器函数

示例

有关此函数的演示, 请参阅驱动器函数页面的示例 #1.


DriveGetSerial - 语法 & 使用 | AutoHotkey v2

DriveGetSerial

返回指定驱动器的卷序列号.

Serial := DriveGetSerial(Drive)

参数

Drive

类型: 字符串

驱动器字母后跟着冒号和可选的反斜杠, 或 UNC 名称, 如 "\server1\share1".

返回值

类型: 整数

函数返回 Drive 的卷序列号. 有关如何将其转换为十六进制, 请参阅 Format.

错误处理

失败时抛出异常.

相关

驱动器函数

示例

有关此函数的演示, 请参阅驱动器函数页面的示例 #1.


DriveGetSpaceFree - 语法 & 使用 | AutoHotkey v2

DriveGetSpaceFree

包含指定路径的驱动器的空闲磁盘空间, 单位为 mb(兆字节).

FreeSpace := DriveGetSpaceFree(Path)

参数

Path

类型: 字符串

驱动器包含的任意路径(也可能对 UNC 路径和映射驱动器有效).

返回值

类型: 整数

函数包含 Path 的驱动器的空闲磁盘空间, 单位为 mb(兆字节)(四舍五入到最近的兆字节).

错误处理

失败时抛出异常.

备注

一般来说, Path 可以是任意路径. 由于 NTFS 支持挂载卷和目录连接, 具有相同驱动器号的不同路径可以产生不同数量的空闲空间.

相关

DriveGetCapacity, 驱动器函数

示例

检索并报告包含 A_MyDocuments 的驱动器的空闲磁盘空间.

FreeSpace := DriveGetSpaceFree(A_MyDocuments)
MsgBox FreeSpace " MB"


DriveGetStatus - 语法 & 使用 | AutoHotkey v2

DriveGetStatus

返回包含指定路径的驱动器的状态.

Status := DriveGetStatus(Path)

参数

Path

类型: 字符串

驱动器包含的任意路径(也可能对 UNC 路径和映射驱动器有效).

返回值

类型: 字符串

函数返回包含 Path 的驱动器的状态:

状态 | 说明
Unknown | 可能表示未格式化/RAW 文件系统.
Ready | 这是最常见的.
NotReady | 典型的可移动驱动器未包含媒体.
Invalid | Path 不存在或网络驱动器目前无法访问, 等等.

错误处理

失败时抛出异常.

备注

一般来说, Path 可以是任意路径. 由于 NTFS 支持挂载卷和目录连接, 具有相同驱动器号的不同路径可以产生不同的结果.

相关

驱动器函数

示例

有关此函数的演示, 请参阅驱动器函数页面的示例 #1.


DriveGetStatusCD - 语法 & 使用 | AutoHotkey v2

DriveGetStatusCD

返回指定 CD/DVD 驱动器的媒体状态.

CDStatus := DriveGetStatusCD(Drive)

参数

Drive

类型: 字符串

如果省略, 则使用默认的 CD/DVD 驱动器. 否则, 请指定驱动器字母后跟着冒号.

返回值

类型: 字符串

函数返回 Drive 的媒体状态:

状态 | 意义
not ready | 驱动器未准备好被访问, 可能因为正忙于写入操作. 已知限制: 当驱动器里是 DVD 而不是 CD 时, 也会出现 "未准备好" 的情况.
open | 驱动器里没有光盘, 或者托盘已弹出.
playing | 驱动器正在播放光盘.
paused | 之前播放的音频或视频现在已暂停.
seeking | 驱动器正在寻道.
stopped | 驱动器里有 CD 但当前没有进行访问.

错误处理

失败时抛出异常.

备注

函数可能对网络驱动器或非-CD/DVD 驱动器没有效果. 如果因为这种或其他原因失败了, 则抛出异常.

如果托盘刚被关闭, 可能会在函数完成前出现一些延迟.

相关

DriveEject, 驱动器函数

示例

有关此函数的演示, 请参阅驱动器函数页面的示例 #1.


DriveGetType - 语法 & 使用 | AutoHotkey v2

DriveGetType

返回包含指定路径的驱动器类型.

DriveType := DriveGetType(Path)

参数

Path

类型: 字符串

驱动器包含的任意路径(也可能对 UNC 路径和映射驱动器有效).

返回值

类型: 字符串

函数返回包含 Path 的驱动器类型: Unknown, Removable, Fixed, Network, CDROM 或 RAMDisk. 如果 Path 无效(例如, 因为驱动器不存在), 返回值是一个空字符串.

备注

一般来说, Path 可以是任意路径. 由于 NTFS 支持挂载卷和目录连接, 具有相同驱动器号的不同路径可以产生不同的结果.

相关

驱动器函数

示例

有关此函数的演示, 请参阅驱动器函数页面的示例 #1.


DriveLock - 语法 & 使用 | AutoHotkey v2

DriveLock

阻止指定驱动器的弹出功能正常工作.

DriveLock Drive

参数

Drive

类型: 字符串

驱动器字母后跟着冒号和可选的反斜杠(也可能对 UNC 路径和映射驱动器有效).

错误处理

失败时如 Drive 不存在或不支持锁定功能, 则抛出异常.

备注

大多数驱动器不能 "在锁定之后打开". 然而, 在驱动器打开时进行锁定可能会导致驱动器在关闭后立即进入锁定状态.

函数对不支持锁定的驱动器(如大多数只读驱动器) 没有效果.

要解除驱动器的锁定, 调用 DriveUnlock. 如果使用脚本锁定驱动器后这个脚本退出了, 那么那个驱动器会保持锁定状态, 直到另一个脚本或程序对它进行解锁, 或系统重新启动.

相关

DriveUnlock, 驱动器函数

示例

锁定 D 盘.

DriveLock("D:")


DriveSetLabel - 语法 & 使用 | AutoHotkey v2

DriveSetLabel

更改指定驱动器的卷标签.

DriveSetLabel Drive , NewLabel

参数

Drive

类型: 字符串

驱动器字母后跟着冒号和可选的反斜杠(也可能对 UNC 路径和映射驱动器有效).

NewLabel

类型: 字符串

如果省略, 驱动器将没有标签. 否则, 请指定要设置的新标签.

错误处理

失败时抛出异常.

相关

DriveGetLabel, 驱动器函数

示例

更改 C 驱动器的卷标.

DriveSetLabel "C:", "Seagate200"


DriveUnlock - 语法 & 使用 | AutoHotkey v2

DriveUnlock

恢复指定驱动器的弹出功能.

DriveUnlock Drive

参数

Drive

类型: 字符串

驱动器字母后跟着冒号和可选的反斜杠(也可能对 UNC 路径和映射驱动器有效).

错误处理

失败时抛出异常.

备注

如果驱动器被多次锁定(至少适用于某些驱动器), 则需要多次调用该函数. 例如, 如果调用了三次 DriveLock("D:"), 那么需要调用 DriveUnlock("D:") 三次以解锁. 由于这种情况以及无法判断某个驱动器当前是否锁定的事实, 使用变量来记录它的锁定状态通常是有用的.

相关

DriveLock, 驱动器函数

示例

解锁 D 盘.

DriveUnlock("D:")


Edit - 语法 & 使用 | AutoHotkey v2

Edit

在默认编辑器中打开当前脚本进行编辑.

Edit

Edit 函数使用注册表中与 "edit" 操作关联的编辑器(如果没有则为记事本) 打开当前脚本进行编辑. 然而, 如果已经有一个编辑器窗口中打开了这个脚本(根据窗口标题判断), 那么会激活这个窗口而不打开编辑器的新实例.

在 Dash 中可以通过 Editor settings 来更改由 "edit" 动作执行的默认程序, 脚本或命令行.

此函数在已编译脚本中执行将没有效果.

相关提示, 可以在多种编辑器中启用 AutoHotkey 语法高亮. 此外, 通过这个例子可以在任何编辑器中激活 AutoHotkey 命令的上下文相关帮助. 最后, 通过使用像 boiler 写的脚本或 Helgef 写的脚本这些几乎可以在任何编辑器上工作的自动完成工具可以提升您的效率. 它监视您的输入并显示菜单和参数列表, 帮助您输入某些内容以及提醒您参数的顺序.

相关

Reload, 编辑脚本, 支持 AutoHotkey 的编辑器

示例

打开当前脚本进行编辑.

Edit

如果您编辑器的命令行用法像这样 Editor.exe "Full path of script.ahk", 可以使用以下方法将其设置为 ahk 文件的默认编辑器. 当您运行这个脚本时, 它会提示您选择您的编辑器可执行文件.

Editor := FileSelect(2,, "Select your editor", "Programs (*.exe)")
if Editor = ""
    ExitApp
RegWrite Format('"{1}" "%L"', Editor), "REG_SZ", "HKCR\AutoHotkeyScript\Shell\Edit\Command"


EditGetCurrentCol - 语法 & 使用 | AutoHotkey v2

EditGetCurrentCol

返回插入符号(文本插入点) 在的 Edit 控件中的列号.

CurrentCol := EditGetCurrentCol(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

此函数返回插入符号(文本插入点) 所在的 Edit 控件中的列号. 首列为 1. 如果控件中选择了文本, 则返回值是选择开始的列号.

错误处理

失败时, 或者找不到窗口或控件, 则抛出异常.

相关

EditGetCurrentLine, EditGetLineCount, EditGetLine, EditGetSelectedText, EditPaste, 控件函数


EditGetCurrentLine - 语法 & 使用 | AutoHotkey v2

EditGetCurrentLine

返回插入符号(插入点) 在的 Edit 控件中的行号.

CurrentLine := EditGetCurrentLine(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

返回插入符号(插入点) 在的 Edit 控件中的行号. 首列为 1. 如果控件中选择了文本, 则返回值是选择开始的行号.

错误处理

失败时, 或者找不到窗口或控件, 则抛出异常.

相关

EditGetCurrentCol, EditGetLineCount, EditGetLine, EditGetSelectedText, EditPaste, 控件函数


EditGetLine - 语法 & 使用 | AutoHotkey v2

EditGetLine

返回 Edit 控件中指定行的文本.

Line := EditGetLine(N, Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

N

类型: 整数

行号. 行 1 为首行.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

此函数返回 Edit 控件中第 N 行的文本. 根据控件的特性, 字符串可能以回车(`r) 或回车+换行(`r`n) 结束.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果 N 超出范围或是其他无效值, 则抛出 ValueError.

如果消息不能被发送到控件, 则抛出 OSError.

相关

EditGetCurrentCol, EditGetCurrentLine, EditGetLineCount, EditGetSelectedText, EditPaste, 控件函数

示例

获取记事本 Edit 控件的第一行.

line1 := EditGetLine(1, "Edit1", "ahk_class Notepad")


EditGetLineCount - 语法 & 使用 | AutoHotkey v2

EditGetLineCount

返回 Edit 控件的行数.

LineCount := EditGetLineCount(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

此函数返回 Edit 控件的行数. 所有的 Edit 控件至少含有一行, 即使控件是空的.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果消息不能被发送到控件, 则抛出 OSError.

相关

EditGetCurrentCol, EditGetCurrentLine, EditGetLine, EditGetSelectedText, EditPaste, 控件函数


EditGetSelectedText - 语法 & 使用 | AutoHotkey v2

EditGetSelectedText

返回 Edit 控件中选定的文本.

SelectedText := EditGetSelectedText(Control , WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

此函数返回 Edit 控件中选定的文本. 如果没有选择文本, 则返回空字符串. 某些类型的控件, 如 RichEdit20A 在某些情况下可能无法获取到正确的文本(例如 Metapad).

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果获取文本时出现问题, 则抛出 Error 或 OSError.

相关

EditGetCurrentCol, EditGetCurrentLine, EditGetLineCount, EditGetLine, EditPaste, 控件函数


EditPaste - 语法 & 使用 | AutoHotkey v2

EditPaste

将指定的字符串粘贴到 Edit 控件中的插入符号(文本插入点) 处.

EditPaste String, Control , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

String

类型: 字符串

要粘贴的字符串.

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果消息不能被发送到控件, 则抛出 OSError.

备注

效果类似于按下 Ctrl+V 粘贴, 但是此功能不会影响剪贴板的内容或要求控件具有键盘焦点.

为了提高可靠性, 每次使用此函数后都会自动执行延迟. 该延迟可以通过 SetControlDelay 或给 A_ControlDelay 赋值来更改. 有关详情, 请参阅 SetControlDelay 备注.

相关

ControlSetText, 控件函数


Else - 语法 & 使用 | AutoHotkey v2

Else

如果相关联语句的主体没有执行, 指定一个或多个语句去执行.

Else 语句
Else
{
    语句
}

备注

Else 的每次使用都必须附属于(与之关联的) 其上方的 If, Catch, For, Loop 或 While 语句. Else 始终附属于其上方最近的且无主的语句, 除非使用区块来改变该行为. Else 语句执行的条件取决于关联语句:

  • If 表达式: 表达式计算为假.
  • For, Loop(任何类型), While: 循环的迭代次数为零.
  • Loop Read: 如上所述, 但是 Else 的存在也可以防止在没有找到文件或路径时抛出错误. 因此, 如果文件为空或不存在, Else 就会执行.
  • Try...Catch: 在 Try 块中没有抛出异常.

Else 可以在同一行上紧跟着任何其他的单个语句. 这通常用于 "else if" 梯形结构(请参阅底部的例子).

如果 Else 拥有多行, 那么这些行必须用大括号括起来(创建一个区块). 但是, 如果只有一行属于 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 语句的常见用法. 本例执行如下:

  1. 如果记事本存在:
    1. 激活它
    2. 发送字符串 "This is a test." 然后是 Enter.
  2. 否则(即如果记事本不存在):
    1. 激活另一个窗口
    2. 在坐标 100, 200 处左击
if WinExist("Untitled - Notepad")
{
    WinActivate
    Send "This is a test.{Enter}"
}
else
{
    WinActivate "Some Other Window"
    MouseClick "Left", 100, 200
}

展示 Else 语句可以使用的不同的样式.

if (x = 1)
    firstFunction()
else if (x = 2) ; "else if" 类型
    secondFunction()
else if x = 3
{
    thirdFunction()
    Sleep 1
}
else defaultFunction()  ; 即任何单个语句都可以和 Else 放在同一行.

如果一个循环的迭代次数为零, 则执行一些代码.

; 显示文件或 Internet Explorer 窗口/标签页.
for window in ComObject("Shell.Application").Windows
    MsgBox "Window #" A_Index ": " window.LocationName
else
    MsgBox "No shell windows found."


枚举器对象 - 定义 & 使用 | AutoHotkey v2

枚举器对象

枚举器是函数对象的一种类型, 可以反复调用以枚举值序列.

枚举器的存在主要是为了支持 For-循环, 通常不会直接调用. For-循环文档详细描述了调用枚举器的过程. 该脚本可以实现一个枚举器来控制在循环的每次迭代中将哪些值指派给了 for-循环的变量.

内置的枚举器是 Enumerator 类的实例(其由 Func 派生), 但任何函数对象都有可能与 for-loop 一起使用.

目录

  • 方法:
    • Call: 检索枚举中的下一个或多个项目.
  • 相关

方法

Call

检索枚举中的下一个或多个项目.

Boolean := Enum.Call(&OutputVar1 , &OutputVar2)
Boolean := EnumFunction(&OutputVar1 , &OutputVar2)

参数

&OutputVar1, &OutputVar2

类型: VarRef

一个或多个供枚举器指派值的输出变量的引用.

返回值

类型: 整数(布尔值)

成功时, 此方法返回 1(true), 没有项目剩余时, 则返回 0(false).

一个简单的函数定义可以用来创建一个枚举器; 在这种情况下, Call(调用) 方法是隐式的.

当定义你自己的枚举器时, 参数的数量应该与预期传递给 For-循环的变量数量相匹配(在 "in" 关键字之前). 这通常是 1 或 2, 但一个 For-循环最多可以接受 19 个变量. 要允许该方法接受不同数量的变量, 请声明可选参数.

当 For-循环试图调用方法时, 如果变量比参数多(传递的参数太多, 定义的参数太少) 或者变量比强制参数少, 就会抛出异常.

相关: For-loop, OwnProps, __Enum (Array), __Enum (Map)


EnvGet - 语法 & 使用 | AutoHotkey v2

EnvGet

检索指定环境变量的值.

Value := EnvGet(EnvVar)

参数

EnvVar

类型: 字符串

环境变量的名称. 例如: "Path".

返回值

类型: 字符串

函数返回 EnvVar 的值. 如果 EnvVar 为空或不存在, 则返回空字符串.

备注

操作系统限制每个环境变量的文本最多为 32 KB.

此函数的存在是因为普通脚本变量没有存储在环境变量中. 这是因为性能会变差, 也因为操作系统将环境变量限制为 32 KB.

相关

EnvSet, Run / RunWait

示例

检索一个环境变量的值, 并将其存储在 LogonServer.

LogonServer := EnvGet("LogonServer")

检索并报告 "Program Files" 目录的路径. 有关替代方法, 请参阅 RegRead 示例 #2.

ProgramFilesDir := EnvGet(A_Is64bitOS ? "ProgramW6432" : "ProgramFiles")
MsgBox "Program files are in: " ProgramFilesDir

检索并报告当前用户的本地 AppData 目录.

LocalAppData := EnvGet("LocalAppData")
MsgBox A_UserName "'s Local directory is located at: " LocalAppData


EnvSet - 语法 & 使用 | AutoHotkey v2

EnvSet

将值写入指定的环境变量中.

EnvSet EnvVar , Value

参数

EnvVar

类型: 字符串

环境变量的名称, 例如 "Path".

Value

类型: 字符串

如果省略, 则删除环境变量. 否则, 请指定要写入的值.

错误处理

失败时抛出 OSError.

备注

操作系统限制每个环境变量的文本最多为 32 KB.

此函数创建或改变的环境变量只有由此脚本通过 Run 或 RunWait 运行的程序才可以访问. 有关详情, 请参阅环境变量.

此函数的存在是因为普通脚本变量没有存储在环境变量中. 这是因为性能会变差, 也因为操作系统将环境变量限制为 32 KB.

相关

EnvGet, Run / RunWait

示例

将一些文字写入环境变量中.

EnvSet "AutGUI", "Some text to put in the environment variable."


Error 对象 | AutoHotkey v2

Error 对象

class Error extends Object

Error(错误) 对象是由内置代码在运行时发生错误时抛出的, 也可由脚本显式抛出. 以下是标准属性.

目录

  • 标准属性
  • Error()
  • Error 类型
  • 相关

标准属性

Message: 错误消息.

What: 引起异常的原因. 这通常是一个函数的名称, 但对于由表达式中的错误而抛出的异常(例如在非数字值上使用数学运算符), 则为空白.

Extra: 与错误有关的字符串值(如果有). 如果这个值可以转换为非空字符串, 标准错误对话框会显示一行 "Specifically:" 后面跟着这个字符串.

File: 包含发生错误的行或构造错误对象的脚本文件的完整路径.

Line: 错误发生的行号, 或者错误对象被构造的行号.

Stack: 代表 Error 对象被构造时的调用栈的字符串. 每一行的格式如下:

File (Line) : [What] SourceCode`r`n
代表对函数 What 的调用. File 和 Line 表示该堆栈深度下的当前脚本行. SourceCode 是该行源代码的近似值, 就像 ListLines 中显示的那样.
> What`r`n
表示线程的启动, 通常是它上面的函数调用的直接原因.
... N more
表示堆栈跟踪被截断, 还有 N 个堆栈条目没有显示. 目前 Stack 属性不能超过 2047 个字符.

注意: 标准错误对话框要求 Message, Extra, File 和 Line 都是自有值属性.

Error()

创建 Error 对象.

NewError := Error(Message , What, Extra)

Error 可以用 Error 类型中列出的某个子类替换, 尽管一些子类可能会采用不同的参数.

这些参数直接对应于上面描述的属性, 但对于覆盖 __New 方法的 Error 子类来说, 参数可能有所不同.

Message 和 Extra 被转换为字符串. 如果一个异常抛出而且没有被捕获, 则会通过一个错误对话框来显示它们.

What 指示错误的来源. 它可以是任意字符串, 但应该是负整数或正在运行的函数的名称. 指定 -1 表示当前函数, -2 表示调用它的函数, 依此类推. 如果脚本被编译或者该值不能识别有效的堆栈帧, 那么该值将被转换为字符串并赋值给 NewError.What. 否则, 将使用标识的堆栈帧来确定其他属性:

  • NewError.What 包含函数的名称.
  • NewError.Line 和 NewError.File 表示 调用 函数的行.
  • NewError.Stack 包含部分堆栈跟踪, 在顶部指示堆栈帧.

使用 What 参数可以允许复杂函数使用帮助函数来执行其工作或参数验证, 同时从任何报告的错误信息中忽略这些内部细节. 例如:

MyFunction(a, b) {
    CheckArg "a", a
    CheckArg "b", b
    ;...
    CheckArg(name, value) {
        if value < 0
            throw ValueError(name " is negative", "myfunction", value)
    }
}

try
    MyFunction(1, -1)  ; err.Line 显示为这一行.
catch ValueError as err
    MsgBox Format("{1}: {2}.`n`nFile:`t{3}`nLine:`t{4}`nWhat:`t{5}`nStack:`n{6}"
        , type(err), err.Message, err.File, err.Line, err.What, err.Stack)
try
    SomeFunction()
catch as e
    MsgBox(type(e) " in " e.What ", which was called at line " e.Line)

SomeFunction() {
    throw Error("Fail", -1)
}

Error 类型

Error 的以下子类是预定义的:

  • MemoryError(内存错误): 内存分配失败.
  • OSError(系统错误): 对 Win32 函数的内部函数调用失败. Message 包括操作系统生成的错误码和描述. OSErrors 有一个额外的 Number 属性, 其中包含错误代码. 调用 OSError(Code), 其中 Code 是数字, 根据给定的 OS(系统) 定义的错误代码设置 Number 和 Message. 如果省略 Code, 则默认为 A_LastError. 例如, OSError(5).Message 返回 "(5) 禁止访问."
  • TargetError(目标错误): 函数由于找不到目标而失败. Message 指示目标的类型, 例如窗口, 控件, 菜单或状态栏.
  • TimeoutError(超时错误): SendMessage 超时.
  • TypeError(类型错误): 意外的值类型被用作函数, 属性赋值或其他操作的输入. 通常 Message 指示预期的和实际的类型, 而 Extra 包含一个表示错误值的字符串.
  • ValueError(值错误): 意外的值被用作函数, 属性赋值或其他操作的输入. 通常 Message 指示哪个期望值被打破, 而 Extra 包含一个表示错误值的字符串.
  • UnsetError: 尝试读取变量, 属性或项的值, 但没有值.
    • MemberError(成员错误)
      • PropertyError
      • MethodError
    • UnsetItemError
  • ValueError: 一个意外的值被用作函数, 属性赋值或其他操作的输入. 通常 Message 表示哪个期望不和预期, 而 Extra 包含一个表示错误值的字符串.
    • IndexError(索引错误): 对象的 __Item 属性的 index 参数无效或超出范围.
  • ZeroDivisionError(零除错误): 在表达式或 Mod 函数中试图除以零.

也可以使用基 Error 类来抛出 Error.

相关

Throw, Try, Catch, Finally, OnError


Exit - 语法 & 使用 | AutoHotkey v2

Exit

退出当前线程.

Exit ExitCode

参数

ExitCode

类型: 整数

如果省略, 则默认为 0(零一般用来表示成功). 否则, 请指定一个介于 -2147483648 和 2147483647 之间的整数, 在脚本退出时返回给它的调用者. 此代码可以被任何调用脚本的程序访问, 例如另一个脚本(使用 RunWait) 或批处理(.bat) 文件.

备注

Exit 函数只终止当前线程. 换句话说, 由菜单, 计时器或热键子例程直接或间接调用的函数堆栈全部都会像遇到 Return 那样立即被返回. 如果直接在这样的函数中使用 -- 或者在全局代码中使用 -- Exit 等同于 Return.

如果脚本不是持续运行的, 并且这是最后一个线程, 那么脚本将在线程退出后终止.

使用 ExitApp 来完全终止持续运行的脚本.

相关

ExitApp, OnExit, 函数, Return, 线程, Persistent

示例

在这个例子中, Exit 函数终止 call_exit 函数以及调用函数.

#z::
{
    call_exit
    MsgBox "This MsgBox will never happen because of the Exit."
    call_exit()
    {
        Exit ; 终止当前函数以及调用它的函数.
    }
}


ExitApp - 语法 & 使用 | AutoHotkey v2

ExitApp

终止脚本.

ExitApp ExitCode

参数

ExitCode

类型: 整数

如果省略, 则默认为 0(零一般用来表示成功). 否则, 请指定一个介于 -2147483648 和 2147483647 之间的整数, 在脚本退出时返回给它的调用者. 此代码可以被任何调用脚本的程序访问, 例如另一个脚本(使用 RunWait) 或批处理(.bat) 文件.

备注

这等同于从脚本的托盘菜单或主菜单中选择了 "Exit".

任何由 OnExit 注册的函数在脚本终止之前都会被调用. 如果这样的函数返回一个非零整数, 脚本不会终止; 作为代替, 当前线程退出就像调用了 Exit 一样.

终止脚本并不等同于退出每个线程. 例如, Finally 块不会被执行, 而对于局部变量所包含的对象 __Delete 不会被调用.

在不是持续运行的脚本中, ExitApp 通常是不必要的.

相关

Exit, OnExit, Persistent

示例

按下热键来终止当前脚本.

#x::ExitApp  ; Win+X


文件对象 - 方法 & 属性 | AutoHotkey v2

文件对象

class File extends Object

提供文件输入/输出的接口, 例如读取或写入文本或检索其长度. FileOpen 返回此类型的对象.

下面使用 "FileObj" 作为任何文件对象的占位符, 因为 "File" 就是类本身.

除了从 Object 继承的方法和属性外, File 对象还具有以下预定义的方法和属性.

目录

  • 方法:
    • Read: 从文件中读取字符串, 并向后移动文件指针.
    • Write: 写入字符串到文件, 并向后移动文件指针.
    • ReadLine: 从文件中读取一行文本, 并向后移动文件指针.
    • WriteLine: 将一行文本写入文件, 并向后移动文件指针.
    • ReadNumType: 从文件中读取指定类型的数据, 并向后移动文件指针.
    • WriteNumType: 写入指定类型的数据到文件, 并向后移动文件指针.
    • RawRead: 从文件读取原始的二进制数据到内存, 并向后移动文件指针.
    • RawWrite: 写入原始的二进制数据到文件, 并向后移动文件指针.
    • Seek: 移动文件指针.
    • Close: 关闭文件, 将缓存中的所有数据写入磁盘并释放共享锁定.
  • 属性:
    • Pos: 获取或设置文件指针的位置.
    • Length: 获取或设置文件的大小.
    • AtEOF: 获取一个非零数字当文件指针到达文件的末尾时.
    • Encoding: 获取或设置此文件对象使用的编码.
    • __Handle: 获取用于 DllCall() 的系统文件句柄.

方法

Read

从文件读取字符串并向前移动文件指针.

String := FileObj.Read(Characters)

参数

Characters

类型: 整数

如果省略, 则读取文件的剩余部分并作为单个字符串返回. 否则, 请指定需读取的最大字符数. 如果 File 对象创建于非搜寻设备(例如控制台缓冲区或管道) 的句柄, 省略此参数可能引起执行方法失败或仅返回当前可用的数据.

返回值

类型: 字符串

此方法返回读取的字符串.

Write

写入字符串到文件并向前移动文件指针.

BytesWritten := FileObj.Write(String)

参数

String

类型: 字符串

要写入的字符串.

返回值

类型: 整数

此方法返回写入的字节数(不是字符数).

ReadLine

从文件中读取一行文本并使文件指针向前移动.

TextLine := FileObj.ReadLine()

返回值

类型: 字符串

此方法返回一行文本, 不包括行结束符.

备注

可以读取长达 65,534 个字符的行. 如果一个行的长度超过这个长度, 则该行的其余部分将通过对此方法的后续调用返回.

WriteLine

将一行文本写入文件, 并向后移动文件指针.

BytesWritten := FileObj.WriteLine(String)

参数

String

类型: 字符串

如果为空或省略, 则写入空行. 否则, 请指定要写入的字符串, 根据打开文件时使用的 EOL 标志, 字符串后面总是跟着 `n 或 `r`n.

返回值

类型: 整数

此方法返回写入的字节数(不是字符数).

ReadNumType

从文件中读取指定类型的数据并使文件指针向前移动.

Num := FileObj.ReadNumType()

NumType 可以是 UInt, Int, Int64, Short, UShort, Char, UChar, Double 或 Float. 这些类型名称的含义与 DllCall 中的相同.

返回值

类型: 整数, 浮点数或字符串(空)

如果读取成功, 此方法返回一个数字, 否则为空字符串.

备注

如果读出的字节数为非零, 但小于 NumType 的大小, 那么缺失的字节数被假定为零.

WriteNumType

写入指定类型的数据到文件并使文件指针向前移动.

BytesWritten := FileObj.WriteNumType(Num)

NumType 可以是 UInt, Int, Int64, Short, UShort, Char, UChar, Double 或 Float. 这些类型名称的含义与 DllCall 中的相同.

参数

Num

类型: 整数或浮点数

写入的数字.

返回值

类型: 整数

此方法返回写入的字节数. 例如, 写入成功时, FileObj.WriteUInt(42) 返回 4.

RawRead

从文件读取原始的二进制数据到内存并向前移动文件指针.

BytesRead := FileObj.RawRead(Buffer , Bytes)

参数

Buffer

类型: 对象或整数

将接收数据的类缓冲对象或内存地址.

建议读入缓冲. 如果省略 Bytes, 它默认为缓冲的大小. 如果 Bytes 超过缓冲的大小, 则抛出异常.

如果传递一个内存地址, 则 Bytes 也必须指定.

Bytes

类型: 整数

要读取的最大字节数. 这是可选的, 当 Buffer 是一个对象或字符串变量(不推荐); 否则, 它是必需的.

返回值

类型: Integer

此方法返回读取的字节数.

RawWrite

写入原始的二进制数据到文件并向前移动文件指针.

BytesWritten := FileObj.RawWrite(Data , Bytes)

参数

Data

类型: 对象, 字符串或整数

类缓冲对象或包含二进制数据的字符串, 或内存地址. 如果指定了一个对象或字符串, Bytes 是可选的, 默认为缓冲或字符串的大小. 否则, 必须指定 Bytes.

Bytes

类型: 整数

要写入的字节数. 当 Data 是一个对象或字符串时, 这是可选的; 否则, 它是必需的.

返回值

类型: 整数

此方法返回写入的字节数.

Seek

移动文件指针.

IsMoved := FileObj.Seek(Distance , Origin)

参数

Distance

类型: 整数

要移动的距离, 单位为字节. 较小的值更接近文件的开始处.

Origin

类型: 整数

如果省略, 当 Distance 为负数时, 默认为 2, 其他情况, 为 0. 否则, 请指定以下数字之一, 以指示文件指针开始移动的起点:

  • 0(SEEK_SET): 文件的开始处. Distance 必须为零或更大.
  • 1(SEEK_CUR): 文件指针的当前位置.
  • 2(SEEK_END): 文件的末尾. Distance 通常应该为负数.

返回值

类型: 整数(布尔值)

此方法返回 1(true), 如果成功, 否则为 0(false).

备注

如果 Distance 不是负数, 并且 Origin 省略或为 0(SEEK_SET) 时, 此方法等同于 FileObj.Pos := Distance.

Close

关闭文件, 将缓存中的任何数据写入磁盘, 并释放共享锁.

FileObj.Close()

虽然在释放对象时文件会自动关闭, 但建议尽快关闭文件.

属性

Pos

检索或设置文件指针的位置.

CurrentPos := FileObj.Pos
FileObj.Pos := NewPos

CurrentPos 和 NewPos 是从文件开始的字节偏移量, 其中 0 是第一个字节. 当向文件写入数据或从文件中读取数据时, 文件指针自动移动到该数据之后的下一个字节.

此方法等同于 FileObj.Seek(NewPos).

Length

获取或设置文件的大小.

CurrentSize := FileObj.Length
FileObj.Length := NewSize

CurrentSize 和 NewSize 是文件的大小, 单位为字节.

此属性应该仅用于真实的文件. 如果 File 对象创建于管道的句柄, 那么它可能返回管道内部缓冲区中当前可用的数据量, 但不能保证一定如此.

AtEOF

当文件指针到达文件末尾时, 返回非零数字, 否则为零.

IsAtEOF := FileObj.AtEOF

此属性应该仅用于真实的文件. 如果 File 对象创建于非寻址设备(例如控制台缓冲区或管道) 的句柄, 那么返回的值可能没有意义, 因为这些设备逻辑上没有 "文件末尾".

Encoding

检索或设置此文件对象使用的文本编码.

CurrentEncoding := FileObj.Encoding
FileObj.Encoding := NewEncoding

NewEncoding 可以是一个数字代码页标识符(请参阅 Microsoft Docs) 或以下字符串之一.

CurrentEncoding 为以下字符串之一:

  • UTF-8: Unicode UTF-8, 相当于 CP65001.
  • UTF-16: Unicode UTF-16 小端字节顺序标识, 相当于 CP1200.
  • CPnnn: 带有数字标识符 nnn 的编码页.

CurrentEncoding 不会返回带 -RAW 后缀的值, 不论文件如何被打开或是否包含字节顺序标识(BOM). 设置 NewEncoding 不会增加或移除 BOM, 因为 BOM 通常在文件建立时就被写入其中了.

设置 NewEncoding 为 UTF-8-RAW 或 UTF-16-RAW 合法, 但 -RAW 后缀将被忽略. 这仅适用于 FileObj.Encoding, 而不会影响 FileOpen.

Handle

返回用于 DllCall 的系统文件句柄. 请参阅 CreateFile.

Handle := FileObj.Handle

文件对象使用内部缓冲区读取或写入. 如果数据已经被写入对象的内部缓冲区, 则在返回句柄前会确保把数据写入磁盘. 如果缓冲区中包含从文件读取的数据, 则会把数据丢弃且文件指针的实际位置被重设为由 Pos 属性表示的逻辑位置.


FileAppend - 语法 & 使用 | AutoHotkey v2

FileAppend

在文件末尾处追加(写入) 文本或二进制数据(如果有必要, 首先创建文件).

FileAppend Text , Filename, Options

参数

Text

类型: 字符串或对象

指定要追加到文件的文本或文本二进制数据. 文本可以包含换行符(`n) 来开始新行. 此外, 一个长行可以使用延续片段的方法分成较短的几行.

可以传递类似类缓冲的对象来附加文本二进制数据. 如果创建了一个文件, 只有在 选项 中指定了 "UTF-8" 或 "UTF-16" 时, 才会写入字节顺序标记(BOM). 不管 选项 是什么, 都会忽略默认编码, 对象所包含的数据按原样写入. 可以使用任何实现 Ptr 和 Size 属性的对象.

如果 Text 为空, 则创建一个文件名为 Filename 的空白文件(但如果文件已经存在, 则更新其修改时间).

Filename

类型: 字符串

如果省略, 则使用括在 file-reading 循环最内层的输出文件(如果可用). 否则, 请指定要追加内容的文件名, 如果未指定绝对路径, 则假定在 A_WorkingDir 中. 目标目录必须已经存在.

标准输出(stdout): 在 Filename 指定星号(*) 可以把 Text 发送到标准输出(stdout). 这样文本可以重定向到文件, 指向另一个 EXE 的管道或被高级文本编辑器捕获. 例如, 在命令提示符中输入后面的例子是有效的:

"%ProgramFiles%\AutoHotkey\AutoHotkey.exe" "My Script.ahk" >"Error Log.txt"

然而, 发送到标准输出的文本将不会出现在运行它的命令提示符中. 解决此问题的方法是 1) 使用 Ahk2Exe ConsoleApp 指令编译脚本, 或 2) 把脚本的输出通过管道传递给另一个命令或程序. 例如:

"%ProgramFiles%\AutoHotkey\AutoHotkey.exe" "My Script.ahk" |more
For /F "tokens=*" %L in ('""%ProgramFiles%\AutoHotkey\AutoHotkey.exe" "My Script .ahk""') do @Echo %L

在 Filename 指定两个星号(**) 可以把 Text 发送到标准错误输出(stderr).

Options

类型: 字符串

零个或多个以下字符串. 使用单个空格或制表符将每个选项与下一个选项分开. 例如: "`n UTF-8"

Encoding: 如果文件缺少 UTF-8 或 UTF-16 字节顺序标记, 则指定 FileEncoding 接受的任何编码名称(不包括空字符串) 以使用该编码. 如果省略, 默认为 A_FileEncoding(除非 Text 是对象, 在这种情况下不写入字节顺序标记).

RAW: 指定单词 RAW(不区分大小写) 按原样将 Text 包含的确切字节写入文件, 不进行任何转换. 此选项覆盖以前指定的任何编码, 反之亦然. 如果 Text 不是对象, 由于使用 UTF-16 字符串, 数据大小总是 2 字节的倍数.

`n(换行符): 如果回车符不存在, 则在每个换行符(`n) 之前插入回车符(`r). 换句话说, 将转换 `n 为 `r`n. 这种转换通常不会影响性能. 如果不使用此选项, 则不会更改 Text 中的行尾.

错误处理

失败时抛出 OSError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

要覆盖现有的文件, 请在使用 FileAppend 前用 FileDelete 删除它.

追加文本后目标文件会自动关闭(除非在文件读取/写入循环中以单参数模式使用 FileAppend).

追加模式的 FileOpen 比 FileAppend 提供了更多的控制性并且允许文件保持打开状态而不是每次都要打开和关闭文件. 一旦以追加模式打开文件后, 请使用 FileObj.Write(Str) 来追加字符串. 文件对象通过 RawWrite/RawRead 或 WriteNum/ReadNum 也支持二进制 I/O.

相关

FileEncoding, FileOpen/文件对象, FileRead, 文件读取循环, IniWrite, FileDelete, OutputDebug, 延续片段

示例

必要时创建一个文件, 并附加一行.

FileAppend "Another line.`n", "C:\My Documents\Test.txt"

使用延续片段来提高可读性和可维护性.

FileAppend "
(
一行文字.
默认情况下, 前一行和这一行之间的硬回车(Enter) 将被写进文件.
    这一行缩进了一个制表符; 默认情况下, 该制表符也将被写入文件.
)", A_Desktop "\My File.txt"

演示如何使用操作系统内置的 FTP 命令自动进行 FTP 上传.

FTPCommandFile := A_ScriptDir "\FTPCommands.txt"
FTPLogFile := A_ScriptDir "\FTPLog.txt"
try 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 Format('{1} /c ftp.exe -s:"{2}" >"{3}"', A_ComSpec, FTPCommandFile, FTPLogFile)
FileDelete FTPCommandFile  ; 为确保安全进行删除.
Run FTPLogFile  ; 显示日志进行复查.


FileCopy - 语法 & 使用 | AutoHotkey v2

FileCopy

复制一个或多个文件.

FileCopy SourcePattern, DestPattern , Overwrite

参数

SourcePattern

类型: 字符串

单个文件或文件夹的名称, 或通配符模式(如 "C:\Temp\*.tmp"). 如果未指定绝对路径, 则假定 SourcePattern 在 A_WorkingDir 中.

支持星号(*) 和问号(?) 作为通配符. * 匹配零个或多个字符, 而 ? 匹配任何单个字符. 使用示例:

  • *.* 或 * 匹配所有文件.
  • *.htm 匹配扩展名为 .htm, .html 等的文件.
  • *. 匹配没有扩展名的文件.
  • log?.txt 匹配如 log1.txt 但不匹配 log10.txt.
  • *report* 匹配任何包含单词 "report" 的文件名.
DestPattern

类型: 字符串

目标的名称或模式, 如果未指定绝对路径, 则假定 SourcePattern 在 A_WorkingDir 中.

如果星号存在, 则将文件名中的第一个星号(*) 替换为不包含其扩展名的源文件名, 而将最后一个句号 (.) 后的第一个星号替换为源文件的扩展名. 如果有星号, 但省略了扩展名, 则使用源文件的扩展名.

要执行简单地复制 -- 保留现有的文件名 -- 只需指定文件夹名, 如下面功能几乎等同的两个例子所示:

FileCopy "C:\*.txt", "C:\My Folder"
FileCopy "C:\*.txt", "C:\My Folder\*.*"

目标目录必须已经存在. 如果 My Folder 不存在, 上面第一个示例将使用 "My Folder" 作为目标文件名, 而第二个示例不会复制任何文件.

Overwrite

类型: 整数

如果省略，则默认为 0. 否则, 指定以下数字之一, 以指示是否覆盖已存在的文件:

0: 不覆盖现有的文件. 如果 DestPattern 作为文件或目录已经存在, 则操作会失败且没有任何效果.

1: 覆盖现在的文件. 但是, 不会删除在 DestPattern 中没有被 SourcePattern 目录中文件覆盖的其他子目录或文件.

错误处理

如果有文件复制失败, 则抛出 Error, 并且它的 Extra 属性设置为失败次数. 如果没有找到文件, 只有当 SourcePattern 缺少通配符 * 和 ? 时, 才会抛出错误. 换句话说, 复制一个通配符模式, 如 "*.txt", 当它不与任何文件匹配时, 被视为成功.

与 FileMove 不同, 即使在覆盖模式生效的情况下, 复制一个文件来覆盖它自己始终被视为错误.

如果找到了文件, 则 A_LastError 会被设置为 0(零) 或最近一次操作失败时调用操作系统 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

备注

FileCopy 只复制文件. 要复制整个文件夹中的内容(它的所有文件和子文件夹), 请参阅下面的示例部分. 要复制单个文件夹(及其子文件夹), 请使用 DirCopy.

在遇到错误后操作仍会继续进行.

相关

FileMove, DirCopy, DirMove, FileDelete

示例

复制文件并保留原来的文件名.

FileCopy "C:\My Documents\List1.txt", "D:\Main Backup\"

复制文件到同一个文件夹并改变文件名.

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 文件夹中且
; 返回无法复制的文件/文件夹的数目.
{
    ErrorCount := 0
    ; 首先复制所有文件(不是文件夹):
    try
        FileCopy SourcePattern, DestinationFolder, DoOverwrite
    catch as Err
        ErrorCount := Err.Extra
    ; 现在复制所有文件夹:
    Loop Files, SourcePattern, "D"  ; D 表示 "只检索文件夹".
    {
        try
            DirCopy A_LoopFilePath, DestinationFolder "\" A_LoopFileName, DoOverwrite
        catch
        {
            ErrorCount += 1
            ; 报告每个出现问题的文件夹名称.
            MsgBox "Could not copy " A_LoopFilePath " into " DestinationFolder
        }
    }
    return ErrorCount
}


FileCreateShortcut - 语法 & 使用 | AutoHotkey v2

FileCreateShortcut

创建快捷方式(.lnk) 文件.

FileCreateShortcut Target, LinkFile , WorkingDir, Args, Description, IconFile, ShortcutKey, IconNumber, RunState

参数

Target

类型: 字符串

快捷方式引用的文件的名称, 除非文件集成到了系统中(如 Notepad.exe), 否则应该包含绝对路径. 创建快捷方式时它指向的文件不一定需要存在; 但是, 如果不存在, 某些系统可能会以意想不到的方式改变路径.

LinkFile

类型: 字符串

要创建的快捷方式文件名, 如果未指定绝对路径则假定在 A_WorkingDir. 必须确保扩展名为 .lnk. 目标目录必须已经存在. 如果文件已经存在, 则它会被覆盖.

WorkingDir

类型: 字符串

如果为空或省略, 则 LinkFile 的 "起始位置" 字段为空, 而当快捷方式启动时, 系统会提供默认的工作目录. 否则, 指定在启动快捷方式时 Target 的当前工作目录.

Args

类型: 字符串

如果为空或省略, 则不带参数来启动 Target. 否则, 请指定启动快捷方式时要传递给 Target 的参数. 参数之间使用空格分隔. 如果某个参数包含空格, 则要把它括在双引号中.

Description

类型: 字符串

如果为空或省略, 则 LinkFile 将没有备注. 否则, 请指定描述快捷方式的备注(由操作系统用于显示在 ToolTip(工具提示) 中, 等等.)

IconFile

类型: 字符串

如果为空或省略, 则 LinkFile 将使用 Target 的图标. 否则, 请指定显示在 LinkFile 中图标的完整路径和名称. 它必须为必须为 .ICO 文件或者 EXE 或 DLL 文件中的首个图标.

ShortcutKey

类型: 字符串

如果为空或省略, 则 LinkFile 将没有快捷键. 否则, 请指定单个字母, 数字或在按键列表中的单个按键的名称(可能不支持鼠标按钮或其他非标准的按键). 不要 包含修饰符. 目前, 所有创建的快捷键都使用 Ctrl+Alt 作为修饰键. 例如, 如果在此参数中指定字母 B, 则快捷键将为 Ctrl+Alt+B.

IconNumber

类型: 整数

如果省略, 则默认为 1. 否则, 在 IconFile 中指定要使用图标的编号. 例如, 2 表示第二个图标.

RunState

类型: 整数

如果省略, 则默认为 1. 否则, 指定下列数字之一, 最小化或最大化运行 Target. :

  • 1 = 正常
  • 3 = 最大化
  • 7 = 最小化

错误处理

失败时抛出异常.

备注

如果 Target 在系统的 PATH 环境变量包含的某个文件夹中, 则可以不包含路径.

只有把快捷方式文件放在桌面或开始菜单的某个位置, 这样新建快捷方式的快捷键(ShortcutKey) 才会生效. 如果您选择的快捷键已经在使用中, 那么您新建的快捷方式具有优先权.

创建到 URL 的快捷方式的另一种方法是下面这个例子, 其中创建了特殊的 URL 快捷方式. 根据您的需要改变前两个参数:

IniWrite "https://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", "https://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 - 语法 & 使用 | AutoHotkey v2

FileDelete

永久删除一个或多个文件.

FileDelete FilePattern

参数

FilePattern

类型: 字符串

单个文件的名称, 或通配符模式(如 "C:\Temp\*.tmp"). 如果未指定绝对路径, 则假定 FilePattern 在 A_WorkingDir 中.

支持星号(*) 和问号(?) 作为通配符. * 匹配零个或多个字符, 而 ? 匹配任何单个字符. 使用示例:

  • *.* 或 * 匹配所有文件.
  • *.htm 匹配扩展名为 .htm, .html 等的文件.
  • *. 匹配没有扩展名的文件.
  • log?.txt 匹配如 log1.txt 但不匹配 log10.txt.
  • *report* 匹配任何包含单词 "report" 的文件名.

要删除整个文件夹及其所有子文件夹和文件, 请使用 DirDelete.

错误处理

若要发送文件到回收站, 请使用 FileRecycle 函数.

如果有文件删除失败, 则抛出 Error, 并且它的 Extra 属性设置为失败次数. 删除像 "*.tmp" 这样的通配符模式, 即使它不匹配任何文件也被视为是成功的.

如果找到了文件, 则 A_LastError 会被设置为 0(零) 或最近一次操作失败时调用操作系统 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

备注

要删除只读文件, 请首先移除它的只读属性. 例如: FileSetAttrib "-R", "C:\My File.txt".

相关

FileRecycle, DirDelete, FileCopy, FileMove

示例

删除目录中的所有 .tmp 文件.

FileDelete "C:\temp files\*.tmp"


FileEncoding - 语法 & 使用 | AutoHotkey v2

FileEncoding

为 FileRead, Loop Read, FileAppend 和 FileOpen 设置默认编码.

FileEncoding Encoding

参数

Encoding

类型: 字符串或整数

指定以下值之一:

CP0 或空字符串: 系统默认的 ANSI 代码页. 见下文注释.

UTF-8: Unicode UTF-8, 等同于 CP65001.

UTF-8-RAW: 像上面一样, 但创建新文件时不写入字节顺序标记.

UTF-16: Unicode UTF-16 带小端字节顺序标识, 等同于 CP1200.

UTF-16-RAW: 像上面一样, 但创建新文件时不写入字节顺序标记.

CPnnn: 带数值标识符 nnn 的代码页. 请参阅代码页标识符.

nnn: 数字代码页标识符.

返回值

类型: 字符串

函数返回以前的设置.

备注

如果没有使用 FileEncoding, 则默认编码为 CP0.

CP0 不能普遍标识单个代码页; 相反, 它对应于系统默认的 ANSI 代码页, 这取决于系统区域设置或系统设置的 "非 unicode 程序的语言". 要获取实际代码页编号, 请调用 DllCall("GetACP").

内置变量 A_FileEncoding 包含了当前的默认编码设置.

每个新启动的线程(如热键, 自定义菜单项或计时器子例程) 都使用此函数的默认设置重新启动. 这个默认设置可以通过在脚本启动中使用此函数来改变.

如果文件中存在 UTF-8 或 UTF-16 字节顺序标识, 则不会使用默认编码, 除非文件以只写访问打开(即文件的先前内容被丢弃).

相关

FileOpen, StrGet, StrPut, 读取二进制数据


FileExist - 语法 & 使用 | AutoHotkey v2

FileExist

检查文件或目录是否存在并返回它的属性.

AttributeString := FileExist(FilePattern)

参数

FilePattern

类型: 字符串

单个文件或文件夹的名称, 或通配符模式, 如 "C:\Temp\*.tmp". 如果未指定绝对路径, 则假定 FilePattern 位于 A_WorkingDir 中.

支持星号(*) 和问号(?) 作为通配符. * 匹配零个或多个字符, 而 ? 匹配任何单个字符. 使用示例:

  • *.* 或 * 匹配所有文件.
  • *.htm 匹配扩展名为 .htm, .html 等的文件.
  • *. 匹配没有扩展名的文件.
  • log?.txt 匹配如 log1.txt 但不匹配 log10.txt.
  • *report* 匹配任何包含单词 "report" 的文件名.

返回值

类型: 字符串

函数返回第一个匹配文件或文件夹的属性. 这个字符串是 RASHNDOCTL 的子集, 其中每个字母的意思如下:

  • R = READONLY(只读)
  • A = ARCHIVE(存档)
  • S = SYSTEM(系统)
  • H = HIDDEN(隐藏)
  • N = NORMAL(普通)
  • D = DIRECTORY(目录)
  • O = OFFLINE(离线)
  • C = COMPRESSED(压缩)
  • T = TEMPORARY(临时)
  • L = REPARSE_POINT(通常是一个符号链接)

如果文件没有任何属性(罕见), 则返回 "X". 如果文件不存在则返回空字符串.

备注

注意, 在包含文件和子文件夹的 MyFolder 中像这样的通配符检查 InStr(FileExist("MyFolder\*"), "D") 只告诉您 第一个 匹配的文件是否是一个文件夹, 而不是一个文件夹是否存在. 要检查后者, 请使用 DirExist, 例如: DirExist("MyFolder\*").

与 FileGetAttrib 不同, FileExist 支持通配符模式, 如果存在匹配的文件, 它总是返回一个非空值.

由于空字符串被视为 "false", 所以函数的返回值总是可以用作准布尔值. 例如, 如果文件存在, 语句 if FileExist("C:\My File.txt") 为真(true), 否则返回假(false).

由于 FilePattern 可能包含通配符, 因此 FileExist 可能不适合验证将与其他函数或程序一起使用的文件路径. 例如, FileExist("*.txt") 可能会返回属性即使 "*.txt" 不是有效的文件名. 在这种情况下, FileGetAttrib 是首选.

相关

DirExist, FileGetAttrib, File-loops

示例

如果 D 盘确实存在, 则显示一个消息框.

if FileExist("D:\")
    MsgBox "The drive exists."

如果目录中至少有一个文本文件存在, 则显示一个消息框.

if FileExist("D:\Docs\*.txt")
    MsgBox "At least one .txt file exists."

如果文件 不 存在, 则显示一个消息框.

if not FileExist("C:\Temp\FlagFile.txt")
    MsgBox "The target file does not exist."

展示如何检查文件的指定属性.

if InStr(FileExist("C:\My File.txt"), "H")
    MsgBox "The file is hidden."


FileGetAttrib - 语法 & 使用 | AutoHotkey v2

FileGetAttrib

报告文件或文件夹是否为只读, 隐藏等.

AttributeString := FileGetAttrib(Filename)

参数

Filename

类型: 字符串

如果省略, 则使用最内层文件循环的当前文件. 否则, 指定目标文件的名称, 如果未指定绝对路径则假定在 A_WorkingDir 中. 与 FileExist 和 DirExist 不同, 这必须是一个真正的文件名, 而不是一个模式.

返回值

类型: 字符串

函数返回文件或文件夹的属性. 这个字符串是 RASHNDOCTL 的子集, 其中每个字母的意思如下:

  • R = READONLY(只读)
  • A = ARCHIVE(存档)
  • S = SYSTEM(系统)
  • H = HIDDEN(隐藏)
  • N = NORMAL(普通)
  • D = DIRECTORY(目录)
  • O = OFFLINE(离线)
  • C = COMPRESSED(压缩)
  • T = TEMPORARY(临时)
  • L = REPARSE_POINT(通常是符号链接)

错误处理

失败时抛出 OSError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

要检查检索的字符串中是否存在特定属性, 请参阅下面的示例 #2.

另外, 要检索文件的 8.3 短名称, 请遵循以下示例:

Loop Files, "C:\My Documents\Address List.txt"
    ShortPathName := A_LoopFileShortPath  ; 将产生类似于 C:\MYDOCU~1\ADDRES~1.txt 的路径

可以使用类似的方法获得 8.3 短名称对应的长名称.

相关

FileExist, DirExist, FileSetAttrib, FileGetTime, FileSetTime, FileGetSize, FileGetVersion, 文件循环

示例

存储一个目录的属性字母到 OutputVar. 注意, 现有的目录总是有属性字母 D.

OutputVar := FileGetAttrib("C:\New Folder")

检查检索的字符串中是否存在隐藏属性.

if InStr(FileGetAttrib("C:\My File.txt"), "H")
    MsgBox "The file is hidden."


FileGetShortcut - 语法 & 使用 | AutoHotkey v2

FileGetShortcut

获取快捷方式(.lnk) 文件的信息, 例如其目标文件.

FileGetShortcut LinkFile , &OutTarget, &OutDir, &OutArgs, &OutDescription, &OutIcon, &OutIconNum, &OutRunState

参数

LinkFile

类型: 字符串

要分析的快捷方式文件名, 如果未指定绝对路径则假定在 A_WorkingDir. 必须确保扩展名为 .lnk.

&OutTarget

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定用来存储快捷方式目标的变量的引用(不包含它可能含有的任何参数). 例如: C:\WINDOWS\system32\notepad.exe

&OutDir

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定用来保存快捷方式工作目录的变量的引用. 例如: C:\My Documents. 如果在字符串中存在像 %WinDir% 这样的环境变量, 那么解决它们的一种方法是使用 StrReplace. 例如: OutDir := StrReplace(OutDir, "%WinDir%", A_WinDir)

&OutArgs

类型: VarRef

>如果省略, 则不存储相应的值. 否则, 请指定用来保存快捷方式参数的变量的引用(如果没有则为空).

&OutDescription

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定用来保存快捷方式注释的变量的引用(如果没有则为空).

&OutIcon

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定用来保存快捷方式图标文件名的变量的引用(如果没有则为空).

&OutIconNum

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定用来保存快捷方式图标在图标文件中编号的变量的引用(如果没有则为空). 这个值通常为 1, 表示首个图标.

&OutRunState

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定用来存储快捷方式初始运行方式的变量的引用, 其值为下列数字的其中一个:

  • 1 = 普通
  • 3 = 最大化
  • 7 = 最小化

错误处理

失败时抛出 OSError.

备注

如果不需要相应的信息, 则可以省略输出变量.

相关

FileCreateShortcut, SplitPath

.

示例

允许用户选择一个 .lnk 文件来显示其信息.

LinkFile := FileSelect(32,, "Pick a shortcut to analyze.", "Shortcuts (*.lnk)")
if LinkFile = ""
    return
FileGetShortcut LinkFile, &OutTarget, &OutDir, &OutArgs, &OutDesc, &OutIcon, &OutIconNum, &OutRunState
MsgBox OutTarget "`n" OutDir "`n" OutArgs "`n" OutDesc "`n" OutIcon "`n" OutIconNum "`n" OutRunState


FileGetSize - 语法 & 使用 | AutoHotkey v2

FileGetSize

获取文件的大小.

Size := FileGetSize(Filename, Units)

参数

Filename

类型: 字符串

如果省略, 则使用最内层文件循环的当前文件. 否则, 请指定目标文件的名称, 如果未指定绝对路径, 则假定在 A_WorkingDir 中.

Units

类型: 字符串

如果为空或省略, 则默认为 B. 否则, 请指定以下字母之一, 以便以特定单位返回结果:

  • B = 字节
  • K = 千字节
  • M = 兆字节

返回值

类型: 整数

函数返回指定文件的大小(向下取整到最近的整数).

错误处理

失败时抛出 OSError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

支持任意大小的文件, 包括超过 4 GB 的文件, 都支持 Units 为字节.

如果目标文件为目录, 则报告操作系统看到的它的大小(在所有情况中可能都是零).

要计算文件夹及其所有文件的大小, 请参照此例:

FolderSize := 0
WhichFolder := DirSelect()  ; 提示用户选择一个文件夹.
Loop Files, WhichFolder "\*.*", "R"
    FolderSize += A_LoopFileSize
MsgBox "Size of " WhichFolder " is " FolderSize " bytes."

相关

FileGetAttrib, FileSetAttrib, FileGetTime, FileSetTime, FileGetVersion, 文件循环

示例

读取以字节为单位的大小, 并将其存储在 Size.

Size := FileGetSize("C:\My Documents\test.doc")

读取以千字节为单位的大小, 并将其存储在 Size.

Size := FileGetSize("C:\My Documents\test.doc", "K")


FileGetTime - 语法 & 使用 | AutoHotkey v2

FileGetTime

获取文件或文件夹的时间戳.

Timestamp := FileGetTime(Filename, WhichTime)

参数

Filename

类型: 字符串

如果省略, 则使用最内层文件循环的当前文件. 否则, 请指定目标文件或文件夹的名称, 如果未指定绝对路径, 则假定在 A_WorkingDir 中.

WhichTime

类型: 字符串

如果为空或省略, 则默认为 M. 否则, 指定以下字母之一来设置应该更改的时间戳:

  • M = 修改时间
  • C = 创建时间
  • A = 上次访问时间

返回值

类型: 字符串

函数返回 YYYYMMDDHH24MISS 格式的数字字符串. 这个时间是您的本地时间, 不是 UTC/GMT. 此字符串不应视为数字, 即不应对其进行数学运算或进行数值比较.

错误处理

失败时抛出 OSError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

有关日期和时间的说明, 请参阅 YYYYMMDDHH24MISS.

相关

FileSetTime, FormatTime, FileGetAttrib, FileSetAttrib, FileGetSize, FileGetVersion, 文件循环, DateAdd, DateDiff

示例

获取修改时间, 并将其存储在 Timestamp.

Timestamp := FileGetTime("C:\My Documents\test.doc")

获取创建时间, 并将其存储在 Timestamp.

Timestamp := FileGetTime("C:\My Documents\test.doc", "C")


FileGetVersion - 语法 & 使用 | AutoHotkey v2

FileGetVersion

检索文件的版本.

Version := FileGetVersion(Filename)

参数

Filename

类型: 字符串

如果省略, 则将使用括在 File-Loop 最内层的当前文件. 否则, 请指定目标文件的名称. 如果未指定完整路径, 则此函数使用系统 LoadLibrary 函数所指定的搜索顺序.

返回值

类型: 字符串

函数返回指定文件的版本号.

错误处理

失败时抛出 OSError, 例如文件缺少版本信息.

A_LastError 设置为操作系统 GetLastError() 函数的结果.

备注

大多数非可执行文件(甚至一些 exe 文件) 都没有版本, 因此会抛出错误.

相关

FileGetAttrib, FileSetAttrib, FileGetTime, FileSetTime, FileGetSize, 文件循环

示例

读取文件的版本, 并将其存储在 Version.

Version := FileGetVersion("C:\My Application.exe")

检索位于 AutoHotkey 安装目录下的文件 "AutoHotkey.exe" 的版本, 并将其存储在 Version.

Version := FileGetVersion(A_ProgramFiles "\AutoHotkey\AutoHotkey.exe")


FileInstall - 语法 & 使用 | AutoHotkey v2

FileInstall

在已编译的脚本中包含指定的文件.

FileInstall Source, Dest , Overwrite

参数

Source

类型: 字符串

要添加到已编译可执行文件中的文件名. 如果没有指定绝对路径, 则假定该文件位于(或相对于) 脚本自己的目录中.

这个参数必须是一个带引号的字符串(不是变量或任何其他表达式), 并且必须列在函数名 FileInstall 的右边(即, 不能在它下面使用的延续行上).

Dest

类型: 字符串

当从可执行文件中提取 Source 时, 为其创建的文件的名称. 如果没有指定绝对路径则假定在 A_WorkingDir. 目标目录必须已经存在.

Overwrite

类型: 整数

如果省略, 则默认为 0. 否则, 请指定以下数字之一, 指示是否覆盖已存在的文件:

0: 不覆盖现有的文件. 如果 Dest 已经存在, 则操作会失败并且没有任何效果.

1: 覆盖现有的文件.

其他值保留供将来使用.

错误处理

失败时抛出异常.

任何不能将文件写到目的地的情况都被认为是失败. 例如:

  • 目标文件已经存在, 并且 Overwrite 参数为 0 或省略.
  • 由于权限错误, 或由于文件正在使用, 目标文件无法打开.
  • 目标路径无效或指定了一个不存在的文件夹.
  • 源文件不存在(只针对未编译的脚本).

备注

当 Ahk2Exe 在编译脚本的过程中读取对这个函数的调用时, Source 所指定的文件会被添加到所生成的编译脚本中. 之后, 当编译后的脚本 EXE 运行并执行对 FileInstall 的调用时, 该文件会从 EXE 中提取并写入 Dest 指定的位置.

在编译过程中, 添加到脚本中的文件既不会被压缩也不会被加密, 但编译的脚本 EXE 可以通过使用 Ahk2Exe 中适当的选项进行压缩.

如果在普通(未编译) 脚本中使用此函数, 则会简单地复制一个副本 -- 这有助于测试最终将被编译的脚本. 如果完整的源路径和目标路径相同, 则不进行任何操作, 因为尝试将文件复制到其当前位置将导致错误. 路径在使用 GetFullPathName 展开后与 lstrcmpi 进行比较.

相关

FileCopy, #Include

示例

在脚本的编译版本中包含一个文本文件. 之后, 当编译后的脚本被执行时, 包含的文件会被解压缩到另一个位置, 并使用指定的名字. 如果这个位置上已经有这个名字的文件, 它将被覆盖.

FileInstall "My File.txt", A_Desktop "\Example File.txt", 1


FileMove - 语法 & 使用 | AutoHotkey v2

FileMove

移动或重命名一个或多个文件.

FileMove SourcePattern, DestPattern , Overwrite

参数

SourcePattern

类型: 字符串

单个文件的名称或通配符模式, 例如 "C:\Temp\*.tmp". 如果没有指定绝对路径, 则假定 SourcePattern 在 A_WorkingDir 中.

支持星号(*) 和问号(?) 作为通配符. * 匹配零个或多个字符, 而 ? 匹配任何单个字符. 使用示例:

  • *.* 或 * 匹配所有文件.
  • *.htm 匹配扩展名为 .htm, .html 等的文件.
  • *. 匹配没有扩展名的文件.
  • log?.txt 匹配如 log1.txt 但不匹配 log10.txt.
  • *report* 匹配任何包含单词 "report" 的文件名.
DestPattern

类型: 字符串

目标的名称或模式, 如果没有指定绝对路径, 则假定在 A_WorkingDir 中.

如果星号存在, 则将文件名中的第一个星号(*) 替换为不包含其扩展名的源文件名, 而将最后一个句号(.) 后的第一个星号替换为源文件的扩展名. 如果有星号, 但省略了扩展名, 则使用源文件的扩展名.

要执行简单地移动 -- 保留现有文件名 -- 只需指定文件夹名, 如下面功能几乎等同的两个例子所示:

FileMove "C:\*.txt", "C:\My Folder"
FileMove "C:\*.txt", "C:\My Folder\*.*"

目标目录必须已经存在. 如果 My Folder 不存在, 上面第一个示例将使用 "My Folder" 作为目标文件名, 而第二个示例不会移动任何文件.

Overwrite

类型: 整数(布尔值)

如果省略，则默认为 0. 否则, 指定以下数字之一, 指示是否覆盖现有文件:

0: 不覆盖现有的文件. 如果 DestPattern 作为文件或目录已经存在, 则操作会失败且没有任何效果.

1: 覆盖现在的文件. 但是, 不会删除在 DestPattern 中没有被 SourcePattern 目录中文件覆盖的其他子目录或文件.

错误处理

如果有文件移动失败, 则抛出 Error, 并且它的 Extra 属性设置为失败次数. 如果没有找到文件, 只有当 SourcePattern 缺少通配符 * 和 ? 时, 才会抛出异常. 换句话说, 移动一个通配符模式, 如 "*.txt", 当它不与任何文件匹配时, 被视为成功.

与 FileCopy 不同, 移动一个文件来覆盖它自己总被认为是成功的, 即使在覆盖模式没有生效的情况下.

如果找到了文件, 则 A_LastError 会被设置为 0(零) 或最近一次操作失败时调用操作系统 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

备注

FileMove 只移动文件. 要移动整个文件夹的内容(它的所有文件和子文件夹), 请参阅下面的示例部分. 要移动或重命名单个文件夹, 请使用 DirMove.

在遇到错误后操作仍会继续进行.

尽管此函数可以移动文件到不同的卷, 但这样的操作会比在相同卷上消耗更多的时间. 这是由于在相同卷上类似于重命名, 因此快速得多.

相关

FileCopy, DirCopy, DirMove, 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 文件夹中且
; 返回无法移动的文件/文件夹的数目.
{
    ErrorCount := 0
    if DoOverwrite = 1
        DoOverwrite := 2  ; 请参阅 DirMove 了解模式 2 与模式 1 的区别.
    ; 首先移动所有文件(不是文件夹):
    try
        FileMove SourcePattern, DestinationFolder, DoOverwrite
    catch as Err
        ErrorCount := Err.Extra
    ; 现在移动所有文件夹:
    Loop Files, SourcePattern, "D"  ; D 表示 "只获取文件夹".
    {
        try
            DirMove A_LoopFilePath, DestinationFolder "\" A_LoopFileName, DoOverwrite
        catch
        {
            ErrorCount += 1
            ; 报告每个出现问题的文件夹名称.
            MsgBox "Could not move " A_LoopFilePath " into " DestinationFolder
        }
    }
    return ErrorCount
}


FileOpen - 语法 & 使用 | AutoHotkey v2

FileOpen

打开文件, 从其中读取特定内容和/或将新内容写入其中.

FileObj := FileOpen(Filename, Flags , Encoding)

参数

Filename

类型: 字符串或整数

要打开文件的路径, 如果未指定绝对路径则假定在 A_WorkingDir 中.

如下所示, 指定一个(或两个) 星号来打开标准输入(input)/输出(output)/错误(error) 流:

FileOpen("*", "r")   ; 标准输入
FileOpen("*", "w")   ; 标准输出
FileOpen("**", "w")  ; 标准错误
Flags

类型: 字符串

表示所需的访问模式的字符串, 后面跟着其他选项(中间有可选的空格或制表符); 或数字标志的组合(总和). 支持的值在下表中描述.

Encoding

类型: 字符串或整数

如果省略, 将使用默认编码(由 FileEncoding 或 CP0 设置). 如果为空, 则默认为 CP0(系统默认的 ANSI 代码页). 否则, 指定用于文本 I/O 的编码或代码页, 例如 "UTF-8", "UTF-16", "CP936" 或 936.

如果文件包含 UTF-8 或 UTF-16 字节顺序标记(BOM), 或者如果使用 h(句柄) 标记, 则该参数和默认编码将被忽略, 除非文件以只写访问方式打开(即文件的先前内容被丢弃).

Flags

访问模式(互斥的)

Flag | 十进制 | 十六进制 | 描述
r | 0 | 0x0 | 读取: 当文件不存在时失败.
w | 1 | 0x1 | 写入: 创建新文件, 覆盖任意已存在的文件.
a | 2 | 0x2 | 追加: 如果文件不存在则创建新文件, 否则移动文件指针到文件末尾.
rw | 3 | 0x3 | 读取/写入: 当文件不存在时创建新文件.
h |  |  | 表示 Filename 是包装在对象中的文件句柄. 忽略共享模式标志, 并且不检查句柄表示的文件或流的字节顺序标记. 当文件对象销毁时, 当文件对象销毁时, 文件句柄 不会 自动关闭并且调用 File.Close 没有效果. 注意当 Filename 是非搜寻设备(例如管道或通信设备) 的句柄时, 不应该使用 File.Seek, File.Pos 和 File.Length.

共享模式标志

Flag | 十进制 | 十六进制 | 描述
-rwd |  |  | 为读取, 写入和/或删除访问进行文件锁定. 可以使用 r, w 和 d 的任意组合. 指定 - 相当于指定 -rwd. 如果完全省略, 默认为共享所有访问.
 | 0 | 0x0 | 如果 Flags 是数值的, 缺少共享模式标志会让文件被锁定.
 | 256 | 0x100 | 共享 读取 访问.
 | 512 | 0x200 | 共享 写入 访问.
 | 1024 | 0x400 | 共享 删除 访问.

行结束符(EOL) 选项

Flag | 十进制 | 十六进制 | 描述
`n | 4 | 0x4 | 读取时把 `r`n 替换为 `n 而写入时把 `n 替换为 `r`n.
`r | 8 | 0x8 | 读取时把单独的 `r 替换为 `n.

返回值

类型: Object

返回值是一个封装文件打开句柄的新文件对象. 使用此对象的方法和属性来访问文件的内容.

错误

如果文件不能打开, 则抛出 OSError.

备注

File.ReadLine 始终支持 `n, `r`n 和 `r 作为行结束符, 并且不将它们包含在返回值中, 无论是否使用 `r 或 `n 选项. 这些选项仅影响 File.Read 返回的或由 File.Write 或 File.WriteLine 写入的文本中的行结束符的转换.

当创建 UTF-8 或 UTF-16 文件时, 会写入字节顺序标记(BOM) 到文件中, 除非 Encoding 或默认编码(由 FileEncoding 设置) 是 "UTF-8-RAW" 或 "UTF-16-RAW".

当以读取方式打开含有 UTF-8 或 UTF-16 字节顺序标记(BOM) 的文件时, 会把文件指针放置到这个标志后, 来从输出中排除 BOM. 因此, 在刚刚打开这样的文件时 File.Pos 可能为 3 或 2.

如有必要, 可使用 FileObj.Read(如 FileObj.Read(0)) 刷新写缓冲区. 请参阅下面的示例 #3.

相关

FileEncoding, 文件对象, FileRead

示例

写入一些文本到文件, 然后从文件读取回内存(它提供了与这个 DllCall 示例相同的功能).

FileName := FileSelect("S16",, "Create a new file:")
if (FileName = "")
    return
try
    FileObj := FileOpen(FileName, "w")
catch as Err
{
    MsgBox "Can't open '" FileName "' for writing."
        . "`n`nError " Err.Extra ": " Err.Message
    return
}
TestString := "This is a test string.`r`n"  ; 通过这种方式写入内容到文件时, 要使用 `r`n 而不是 `n 来开始新行.
FileObj.Write(TestString)
FileObj.Close()

; 现在已经把内容写入文件了, 把它们读取回内存中.
try
    FileObj := FileOpen(FileName, "r-d") ; 读取文件 ("r"), 共享除了删除 ("-d") 外的所有访问权限
catch as Err
{
    MsgBox "Can't open '" FileName "' for reading."
        . "`n`n" Type(Err) ": " Err.Message
    return
}
CharsToRead := StrLen(TestString)
TestString := FileObj.Read(CharsToRead)
FileObj.Close()
MsgBox "The following string was read from the file: " TestString

以只读模式打开脚本并读取它的首行.

Script := FileOpen(A_ScriptFullPath, "r")
MsgBox Script.ReadLine()

演示标准 input/output 流的用法.

; 打开控制台窗口以进行此次演示:
DllCall("AllocConsole")
; 打开应用程序的 stdin/stdout 流.
stdin  := FileOpen("*", "r")
stdout := FileOpen("*", "w")
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


FileRead - 语法 & 使用 | AutoHotkey v2

FileRead

检索文件的内容.

Text := FileRead(Filename , Options)

参数

Filename

类型: 字符串

要读取的文件的名称, 如果未指定绝对路径, 则假定在 A_WorkingDir 中.

Options

类型: 字符串

以下字符串的零个或多个, 使用单个空格或制表符将每个选项与下一个选项分开. 例如: "`n m5000 UTF-8"

Encoding: 如果文件缺少 UTF-8 或 UTF-16 字节顺序标记, 则指定 FileEncoding 接受的任何编码名称(不包括空字符串) 以使用该编码. 如果省略, 默认为 A_FileEncoding.

RAW: 指定单词 RAW(不区分大小写) 以原始二进制数据读取文件内容, 并返回缓冲对象而不是字符串. 此选项覆盖以前指定的任何编码, 反之亦然.

m1024: 如果省略此选项, 则读取整个文件, 不过如果内存不足, 则显示错误消息并退出线程(使用 Try 可以避免这种情况). 否则, 请把 1024 替换为十进制或十六进制表示的字节数. 如果文件大于此字节数, 那么只读取其前面部分.

注意: 此选项可能导致最后一行以单独的回车符(`r) 而不是 `r`n 结束.

`n(换行符): 把所有的回车换行符(`r`n) 替换为换行符(`n). 不过, 这种转换会降低性能而且往往不必要. 例如, 包含 `r`n 的文本已经以正确的格式添加到 Gui Edit 控件中. 下面的解析循环将正确工作, 不管每一行的结尾是 `r`n 还是 `n: Loop Parse, MyFileContents, "`n", "`r".

返回值

类型: 字符串或Object

函数返回指定文件的内容. 如果 RAW 选项有效且文件可以打开, 则返回值为缓冲对象; 否则, 返回字符串. 如果文件不存在或由于其他原因无法打开, 则返回一个空字符串.

错误处理

如果打开或读取文件有问题, 则抛出 OSError.

如果文件大小超过 4 Gb, 则会引发 MemoryError, 除非存在 *m 选项, 在这种情况下, 将加载文件前面的部分. 如果程序无法分配足够的内存来包含请求的数据量, 也会抛出 MemoryError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

读取二进制数据

使用 RAW 选项时, 返回值为缓冲对象, 其中包含文件的原始, 未修改的内容. 对象的 Size 属性返回读取的字节数. NumGet 或 StrGet 用于从缓冲中检索数据. 例如:

buf := FileRead(A_AhkPath, "RAW")
if StrGet(buf, 2, "cp0") == "MZ"  ; 看起来像一个可执行文件...
{
    ; 从 COFF 文件头中读取机器类型.
    machine := NumGet(buf, NumGet(buf, 0x3C, "uint") + 4, "ushort")
    machine := machine=0x8664 ? "x64" : machine=0x014C ? "x86" : "unknown"
    ; 显示机器类型和文件大小.
    MsgBox "This " machine " executable is " buf.Size " bytes."
}
buf := ""

读取二进制数据通常需要这个选项, 因为默认情况下, 从文件中读取的任何字节都被解释为文本, 并且可以从源文件的编码(如选项中指定的或通过 A_FileEncoding) 转换为脚本的原生编码, UTF-16. 如果数据不是 UTF-16 文本, 这种转换通常会以不希望的方式更改数据.

有关 RAW 选项的另一个演示, 请参阅保存和恢复剪贴板.

最后, 使用 FileOpen 和 File.RawRead 或 File.ReadNum 可以在无需首先读取整个文件到内存中的情况下读取二进制数据.

备注

当需要读取文件的全部或大部分内容到内存时, 使用 FileRead 比文件读取循环执行地更好.

如果担心使用太多的内存, 可以预先用 FileGetSize 来检查文件的大小.

FileOpen() 比 FileRead 提供了更高级的功能, 例如在文件的指定位置读取或写入数据时无需把整个文件读取到内存中. 请参阅文件对象了解函数列表.

相关

FileEncoding, FileOpen/File Object, file-reading loop, FileGetSize, FileAppend, IniRead, Sort, Download

示例

读取文本文件到 MyText.

MyText := FileRead("C:\My Documents\My File.txt")

快速对文件的内容进行排序.

Contents := FileRead("C:\Address List.txt")
if not ErrorLevel  ; 加载成功.
{
    Contents := Sort(Contents)
    FileDelete "C:\Address List (alphabetical).txt"
    FileAppend Contents, "C:\Address List (alphabetical).txt"
    Contents := "" ; 是否内存.
}


FileRecycle - 语法 & 使用 | AutoHotkey v2

FileRecycle

如果可能, 发送文件或目录到回收站, 或永久删除该文件.

FileRecycle FilePattern

参数

FilePattern

类型: 字符串

单个文件的名称或通配符模式, 如 "C:\Temp\*.tmp". 如果 FilePattern 未指定绝对路径则, 则假定在 A_WorkingDir 中.

支持星号(*) 和问号(?) 作为通配符. * 匹配零个或多个字符, 而 ? 匹配任何单个字符. 使用示例:

  • *.* 或 * 匹配所有文件.
  • *.htm 匹配扩展名为 .htm, .html 等的文件.
  • *. 匹配没有扩展名的文件.
  • log?.txt 匹配如 log1.txt 但不匹配 log10.txt.
  • *report* 匹配任何包含单词 "report" 的文件名.

要回收整个目录, 请指定不包含末尾反斜杠的目录名.

错误处理

失败时抛出 OSError.

备注

实际使用 SHFileOperation 进行操作. 如果由于文件过大而无法存放到回收站, 那么此功能还会永久地删除文件; 另外, 在此之前会显示警告.

如果由于其他原因无法回收该文件, 则可能会永久删除该文件而不会发出警告, 例如:

  • 该文件位于可移动驱动器上.
  • 回收站已被禁用, 例如通过 NukeOnDelete 注册表值.

相关

FileRecycleEmpty, FileDelete, FileCopy, FileMove

示例

将目录中的所有 .tmp 文件发送到回收站(如果可能).

FileRecycle "C:\temp files\*.tmp"


FileRecycleEmpty - 语法 & 使用 | AutoHotkey v2

FileRecycleEmpty

清空回收站.

FileRecycleEmpty DriveLetter

参数

DriveLetter

类型: 字符串

如果省略, 则清空所有驱动器的回收站. 否则, 请指定驱动器字母, 例如 "C:\".

错误处理

失败时抛出异常.

相关

FileRecycle, FileDelete, FileCopy, FileMove

示例

清空 C 盘的回收站.

FileRecycleEmpty "C:\"


FileSelect - 语法 & 使用 | AutoHotkey v2

FileSelect

显示可以让用户打开或保存文件的标准对话框.

SelectedFile := FileSelect(Options, RootDir\Filename, Title, Filter)

参数

Options

类型: 字符串或整数

如果省略, 则默认为 0, 这等同于下面的任意选项都没有指定. 否则, 指定下面列出数字或字母之一, 可选择在后面加一个数字. 例如, "M", 1 和 "M1" 都是有效的(但不相同).

D: 选择文件夹(目录). 指定字母 D, 允许用户选择文件夹而不是文件. 该对话框具有与选择文件时相同的大部分功能, 但不支持过滤器(Filter 必须为空或省略).

M: 多选. 指定字母 M 让用户可以使用 Shift+点击, Control+点击或其他方法来选择多个文件. 在这种情况下, 返回值是一个数组不是一个字符串. 要提取单个文件, 请参阅本页底部的示例.

S: 保存对话框. 指定字母 S 让对话框显示保存按钮代替打开按钮.

可以使用以下数字. 要使其中多个数字生效, 请将它们相加. 例如, 要使用 1 和 2, 请指定数字 3.

1: 文件必须存在
2: 路径必须存在
8: 提示创建新文件
16: 提示覆盖文件
32: 选择快捷方式本身(.lnk 文件) 而不解析为它们的目标. 此选项也避免了通过文件夹快捷方式跳转到那个文件夹的情况.

由于 "提示覆盖" 选项只有保存对话框支持, 因此在没有 "提示创建" 选项的情况下指定该选项也会使 S 选项生效. 同样, 当 S 选项存在时, "提示创建" 选项也没有效果. 指定数字 24 可以启用对话框支持的任何一种提示类型.

RootDir\Filename

类型: 字符串

如果省略或为空, 则起始目录将为默认值, 这可能操作系统版本有关(它很可能是之前使用 FileSelect 时用户最近选择的目录). 否则, 请指定下列的一个或两个:

RootDir: 根(起始) 目录, 如果未指定绝对路径, 则假定为 A_WorkingDir 中的子文件夹.

Filename: 初始显示对话框时在编辑区域的默认文件名. 只显示单独的文件名(不带路径). 要让对话框正确显示, 请确保不包含非法字符(例如 /<|:").

示例:

"C:\My Pictures\Default Image Name.gif"  ; RootDir 和 Filename 都存在.
"C:\My Pictures"  ; 仅 RootDir 存在.
"My Pictures"  ; 仅 RootDir 存在, 且它相对于当前工作目录.
"My File"  ; 仅 Filename 存在(但如果已存在 "My File" 的文件夹, 则它会被认为是 RootDir).
Title

类型: 字符串

如果为空或省略, 则默认为 "Select File - " A_ScriptName(即当前脚本的名称). 否则, 指定文件选择窗口的标题.

Filter

类型: 字符串

如果为空或省略, 对话框将显示所有类型的文件. 并在 "文件类型" 下拉列表中提供 "所有文件 (*.*)" 选项.

否则, 请指定一个字符串来指示对话框显示的文件类型, 例如 "文本文档 (*.txt)". 要在过滤器中包含多个文件扩展名, 请使用分号分隔它们, 例如 "Audio (*.wav; *.mp2; *.mp3)". 在这个例子中, "文件类型" 下拉列表中有指定的字符串和 "所有文件 (*.*)" 作为选项.

如果存在 “D” 选项, 该参数必须为空或省略.

返回值

类型: 字符串或数组

如果没有启用多选, 此函数将返回用户选择的单个文件的完整路径和名称.

如果使用了 M 选项(多选), 此函数将返回一个项目数组, 其中每个项目是一个文件的完整路径和名称. 本页底部的示例演示了如何逐个提取文件. 如果用户取消对话框, 则数组为空(零项).

备注

文件选择对话框通常看起来像这样:

GUI 窗口可以使用 +OwnDialogs 选项的方法来显示模式文件夹选择对话框. 模式对话框在其消失之前会阻止用户与 GUI 窗口进行交互.

相关

DirSelect, MsgBox, InputBox, ToolTip, GUI, CLSID List, parsing loop, SplitPath

此外, 操作系统提供了标准的对话框, 提示用户选取字体, 颜色或图标. 这些对话框可以通过 DllCall 与 comdlg32\ChooseFont, comdlg32\ChooseColor 或 shell32\PickIconDlg 的组合来显示. 请在论坛中搜索示例.

示例

允许用户选择当前存在的 .txt 或 .doc 文件.

SelectedFile := FileSelect(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

允许用户选择多个当前存在的文件.

SelectedFiles := FileSelect("M3")  ; M3 = 选择多个现有文件.
if SelectedFiles.Length = 0
{
    MsgBox "The dialog was canceled."
    return
}
for FileName in SelectedFiles
{
    Result := MsgBox("File #" A_Index " of " SelectedFiles.Length ":`n" FileName "`n`nContinue?",, "YN")
    if Result = "No"
        break
}

允许用户选择文件夹.

SelectedFolder := FileSelect("D", , "Select a folder")
if SelectedFolder = ""
    MsgBox "The dialog was canceled."
else
    MsgBox "The following folder was selected:`n" SelectedFolder


FileSetAttrib - 语法 & 使用 | AutoHotkey v2

FileSetAttrib

改变一个或多个文件或文件夹的属性. 支持通配符.

FileSetAttrib Attributes , FilePattern, Mode

参数

Attributes

类型: 字符串

要改变的属性. 例如, "+HA-R".

要方便地打开, 关闭或切换属性, 请分别在以下一个或多个属性字母前加上加号(+), 减号(-) 或脱字符(^):

  • R = 只读
  • A = 存档
  • S = 系统
  • H = 隐藏
  • N = 普通(仅在单独使用此属性时才有效)
  • O = 离线
  • T = 临时

如果属性字母没有前缀符号, 文件属性将被替换为给定的属性. 请参阅示例 #5. 要删除所有属性, 请单独使用 "N".

FilePattern

类型: 字符串

如果省略, 则使用最内层文件循环的当前文件. 否则, 指定单个文件或文件夹的名称, 或通配符模式, 如 "C:\Temp\*.tmp". 如果未指定绝对路径, 则假定 FilePattern 在 A_WorkingDir 中.

支持星号(*) 和问号(?) 作为通配符. * 匹配零个或多个字符, 而 ? 匹配任何单个字符. 使用示例:

  • *.* 或 * 匹配所有文件.
  • *.htm 匹配扩展名为 .htm, .html 等的文件.
  • *. 匹配没有扩展名的文件.
  • log?.txt 匹配如 log1.txt 但不匹配 log10.txt.
  • *report* 匹配任何包含单词 "report" 的文件名.
Mode

类型: 字符串

如果为空或省略, 则默认仅对文件进行操作, 子目录不被递归. 否则, 请指定一个或更多的下列字母:

  • D = 包含目录(文件夹).
  • F = 包含文件. 如果同时省略 F 和 D, 则仅包含文件而不包括目录.
  • R = 递归子文件夹, 以便其中包含的文件和文件夹在匹配 FilePattern时进行操作. 所有子文件夹都将被递归, 而不仅仅是那些名称匹配 FilePattern 的子文件夹. 如果省略 R, 则不包含子目录中的文件和目录.

错误处理

如果有文件更改失败, 则抛出 Error, 并且它的 Extra 属性设置为失败次数.

如果找到了文件, 则 A_LastError 会被设置为 0, 或上次失败后立即获得操作系统的 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

Remarks

此函数无法改变文件的压缩状态.

相关

FileGetAttrib, FileGetTime, FileSetTime, FileGetSize, FileGetVersion, 文件循环

示例

打开所有文件和目录的 "只读" 和 "隐藏" 属性(子目录不会被递归到).

FileSetAttrib "+RH", "C:\MyFiles\*.*", "DF"  ; +RH 等同于 +R+H

切换单个文件夹的 "隐藏" 属性.

FileSetAttrib "^H", "C:\MyFiles"

关闭单个文件的 "只读" 属性并打开 "存档" 属性.

FileSetAttrib "-R+A", "C:\New Text File.txt"

递归 C 驱动器上的所有 .ini 文件并打开它们的 "存档" 属性.

FileSetAttrib "+A", "C:\*.ini", "R"

将 file2 的属性复制到 file1, 即添加 file2 有的属性, 删除 file2 没有的属性.

FileSetAttrib(FileGetAttrib(file2), file1)


FileSetTime - 语法 & 使用 | AutoHotkey v2

FileSetTime

改变一个或多个文件或文件夹的时间戳. 支持通配符.

FileSetTime YYYYMMDDHH24MISS, FilePattern, WhichTime, Mode

参数

YYYYMMDDHH24MISS

类型: 字符串

如果为空或省略, 则它默认为当前本地日期和时间. 否则, 指定操作使用的时间(格式, 请参阅备注). 不支持 1601 以前的年份.

FilePattern

类型: 字符串

如果省略, 则使用文件循环最内层的当前文件. 否则, 指定单个文件或文件夹的名称或者通配符模式, 例如 "C:\Temp\*.tmp". 如果未指定绝对路径, 则假定 FilePattern 在 A_WorkingDir 中.

支持星号(*) 和问号(?) 作为通配符. * 匹配零个或多个字符, 而 ? 匹配任何单个字符. 使用示例:

  • *.* 或 * 匹配所有文件.
  • *.htm 匹配扩展名为 .htm, .html 等的文件.
  • *. 匹配没有扩展名的文件.
  • log?.txt 匹配如 log1.txt 但不匹配 log10.txt.
  • *report* 匹配任何包含单词 "report" 的文件名.
WhichTime

类型: 字符串

如果为空或省略, 则默认为 M. 否则, 指定以下字母之一来设置应该更改的时间戳:

  • M = 修改时间
  • C = 创建时间
  • A = 上次访问时间
Mode

类型: 字符串

如果为空或省略, 则仅对文件进行操作, 子目录不被递归. 否则, 请指定一个或多个下列字母:

  • D = 包含目录(文件夹).
  • F = 包含文件. 如果同时省略 F 和 D, 则仅包含文件而不包括目录.
  • R = 子文件夹被递归到其中, 这样包含在其中的文件和文件夹如果匹配 FilePattern, 则对它们进行操作. 所有子文件夹都将被递归到其中, 而不仅仅是那些名称匹配 FilePattern 的子文件夹. 如果省略 R, 则不包含子目录中的文件和目录.

注意: 如果 FilePattern 是单个文件夹, 而不是通配符模式, 则无论该设置如何, 它都将始终被操作.

错误处理

如果有文件更改失败, 则抛出 Error, 并且它的 Extra 属性设置为失败次数.

如果找到了文件, 则 A_LastError 会被设置为 0(零) 或最近一次操作失败时调用操作系统 GetLastError() 函数的结果. 否则 A_LastError 包含了没有找到文件原因的错误码.

备注

文件的上次访问时间在 FAT16 & FAT32 卷上可能不如在 NTFS 卷上精确.

YYYYMMDDHH24MISS 格式中元素表示的含义分别为:

Element | 描述
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 包含了当前的协调世界时.

注意: 可以通过 DateAdd 和 DateDiff 对日期-时间值进行比较和加减. 此外, 最后不要使用大于或小于来比较时间, 除非它们的字符串长度相同. 这是因为此时它们被视为数字进行比较; 例如, 20040201 数值上总是小于(但时间顺序上较后) 200401010533. 所以应该使用 DateDiff 来计算出它们之间的时间差是正数还是负数.

相关

FileGetTime, FileGetAttrib, FileSetAttrib, FileGetSize, FileGetVersion, FormatTime, 文件循环, DateAdd, DateDiff

示例

设置所有匹配文件的修改时间为当前时间.

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", "DF"


Finally - 语法 & 使用 | AutoHotkey v2

Finally

确保在 Try 语句完成之后总是执行一条或多条语句.

Finally Statement
Finally
{
    语句
}

备注

每次使用 Finally 都必须附属于(与之关联) 它上面的 Try 语句(在任何可选的 Tatch 和/或 Tlse 之后). Tinally 总是附属于它上面且离它最近的无主 Try 语句, 不过可以使用区块改变这种行为.

Try 语句的行为取决于 Tatch 或 Tinally 是否存在. 有关详情, 请参阅 Try.

不能使用 Goto, Break, Continue 和 Return 退出 Finally 区块, 因为这需要在 Try 区块里禁止任何控制流指令. 例如, 如果 Try 语句中使用 return 42, 值 42 将会在 Finally 区块执行后被返回. 如果使用上述语句之一来试图跳出 Finally 区块, 将会在加载时或运行时被检测为错误.

如果脚本被任何方式直接终止, 包括托盘菜单, ExitApp, Finally 语句不会被执行.

可以在 Finally 语句中使用 One True Brace(OTB) 样式. 例如:

try {
    ...
} finally {
    ...
}

try {
    ...
} catch {
    ...
} else {
    ...
} finally {
    ...
}

相关

Try, Catch, Else, Throw, 区块

示例

详细演示 Finally 的行为.

try
{
    ToolTip "Working..."
    Example1()
}
catch as e
{
    ; 关于 e 对象的更多细节, 请参阅 Error.
    MsgBox(Type(e) " thrown!`n`nwhat: " e.what "`nfile: " e.file
        . "`nline: " e.line "`nmessage: " e.message "`nextra: " e.extra,, 16)
}
finally
{
    ToolTip ; 隐藏工具提示
}

MsgBox "Done!"

; 此函数包含了清理代码的 Finally 区块
Example1()
{
    try
        Example2()
    finally
        MsgBox "This is always executed regardless of exceptions"
}

; 当系统分钟数为奇数时此函数执行会报错
Example2()
{
    if Mod(A_Min, 2)
        throw Error("That's odd...")
    MsgBox "Example2 did not fail"
}


Float - 语法 & 使用 | AutoHotkey v2

Float

将数字字符串或整数值转换为浮点数.

FltValue := Float(Value)

返回值

类型: 浮点数

函数返回将 Value 转换为纯浮点数(类型名称为 "Float") 的结果, 或 Value 本身(如果它已经是正确的类型).

备注

如果值无法转换, 则抛出 TypeError.

要确定一个值是否可以转换为浮点数, 使用 IsNumber 函数.

Float 实际上是一个类, 但可以作为一个函数被调用. Value is Float 可以用来检查一个值是否是一个纯浮点数.

相关

Type, Integer, Number, String, 值, 表达式, Is 函数


For Loop - 语法 & 使用 | AutoHotkey v2

For-loop

对对象中的每对键值对重复执行一或多条语句.

For Value1, Value2 in Expression

参数

Value1, Value2

类型: 变量

用于存储枚举器在每次迭代开始时返回的值的变量. 这些值的性质由枚举器定义, 枚举器由 Expression 决定. 这些变量不能是动态的.

当循环中断或完成时, 这些变量将恢复到原来的值. 如果一个循环变量是 ByRef 参数, 那么目标变量不受循环的影响. 引用该变量(如果是局部变量) 的闭包也不受影响, 并将仍保持为它在循环外的值.

注意: 即使定义在循环主体内, 引用循环变量的嵌套函数也不能看到或改变当前迭代的值. 相反, 要显式传递变量或将其值绑定到一个参数.

如果被枚举器支持, 最多支持 19 个变量.

变量可以被省略. 例如, for , value in myMap 仅用第二个参数调用 myMap 的枚举器, 而省略其第一个参数. 如果枚举器是用户定义的, 并且参数是强制性的, 那么就会像往常一样抛出异常. 如果没有变量或逗号, 传递给 __Enum 的参数数为 0; 否则为 1 加上存在的逗号数.

Expression

类型: 对象

结果为可枚举对象的表达式, 或包含可枚举对象的变量.

备注

可以选择将参数列表括在括号中. 例如: for (val in myarray)

枚举过程如下:

  • 在循环开始之前, 计算 Expression 以确定目标对象.
  • 调用对象的 __Enum 方法以检索 枚举器 对象. 如果不存在这样的方法, 则假定对象本身是枚举器对象.
  • 在每次迭代开始时, 调用枚举器以检索下一个值或下一对值. 如果返回 false(0 或空字串), 则循环终止.

尽管不完全等同于 for 循环, 下面演示了这个过程:

_enum := Expression
try _enum := _enum.__Enum(2)
while _enum(&Value1, &Value2)
{
    ...
}

与上面的代码一样, 如果 Expression 或 __Enum 产生了一个不能被调用的值, 则抛出异常.

在枚举属性, 方法或数组元素时, 插入或删除该类型的项目通常是不安全的. 这样做可能导致某些项目被多次跳过或枚举. 一种解决方法是建立要删除的项目列表, 然后在第一个循环完成后使用第二个循环删除这些项目.

for 循环后通常跟着区块, 这是构成循环 主体 的语句的集合. 不过, 在单语句的循环中可以不使用区块(用于此目的时 "if" 与其相匹配的 "else" 一起被视为单语句). 可以选择使用 One True Brace(OTB) 样式, 这样允许左大括号在同一行而不是在其下面. 例如: for x, y in z {.

和所有的循环一样, 可以使用 Break, Continue 和 A_Index.

循环后面可以有一个可选的 Else 语句, 如果循环的迭代次数为零, 则执行 Else 语句.

COM 对象

因为 Value1 和 Value2 是直接传递给枚举器的, 所以它们的值取决于被枚举的对象类型. 对于 COM 对象, Value1 包含由 IEnumVARIANT::Next() 返回的值, 而 Value2 包含了表示其变体类型的数字. 例如, 用于 Scripting.Dictionary 对象时, 每个 Value1 包含字典中的键, 而 Value2 通常为 8(对于字符串) 和 3(对于整数). 有关类型代码表, 请参阅 ComObjType.

枚举 SafeArray 时, Value1 包含了当前元素, 而 Value2 包含其变体类型.

相关

Enumerator 对象, OwnProps, While-loop, Loop, Until, Break, Continue, 区块

示例

列出对象的自有属性.

colours := {red: 0xFF0000, blue: 0x0000FF, green: 0x00FF00}
; 上面的表达式可以直接代替下面的 "colours":
s := ""
for k, v in colours.OwnProps()
    s .= k "=" v "`n"
MsgBox s

列出所有打开的资源管理器和 Internet Explorer 窗口, 使用 Shell 对象.

windows := ""
for window in ComObject("Shell.Application").Windows
    windows .= window.LocationName " :: " window.LocationURL "`n"
MsgBox windows

将枚举器定义为胖箭头函数. 返回斐波那契数列中的数字, 无限次或直到停止.

for n in FibF()
    if MsgBox("#" A_Index " = " n "`nContinue?",, "y/n") = "No"
        break

FibF() {
    a := 0, b := 1
    return (&n) => (
        n := c := b, b += a, a := c,
        true
    )
}

将枚举器定义为类. 与前面的示例相同.

for n in FibC()
    if MsgBox("#" A_Index " = " n "`nContinue?",, "y/n") = "No"
        break

class FibC {
    a := 0, b := 1
    Call(&n) {
        n := c := this.b, this.b += this.a, this.a := c
        return true
    }
}


Format - 语法 & 使用 | AutoHotkey v2

Format

根据格式字符串格式化一个可变数量的输入值.

String := Format(FormatStr , Values...)

参数

FormatStr

类型: 字符串

格式字符串由原义文本和占位符组成, 其形式为 {Index:Format}.

Index 是一个整数, 表示要使用的那个输入值, 其中 1 是第一个值.

Format 是一个可选的格式指定器, 如下文所述.

省略索引可以使用序列中的下一个输入值(即使先前已经被使用过). 例如, "{2:i} {:i}" 会将第二个和第三个输入值格式化成十进制整数, 用空格隔开. 如果省略了 Index, 仍然必须在 Format 前面加上 :. 指定空大括号, 将使用默认格式处理下一个输入值: {}

使用 {{} 和 {}} 来包含字符串中的原义括号. 任何其他无效的占位符都会被包含在结果中.

不允许在大括号中包含空格符(除非作为标志).

Values

类型: 字符串, 整数或浮点数

将要格式化的输入值. 每个值都是一个独立的参数. 第一个值的索引为 1.

要传递一个数组值, 可以使用可变函数调用:

arr := [13, 240]
MsgBox Format("{2:x}{1:02x}", arr*)

返回值

类型: 字符串

该函数返回指定字符串的格式化版本.

格式指定器

每个格式指定器可以按顺序包含以下几个部分(不含空格):

Flags Width .Precision ULT Type

Flags: 从下面的标志表中选择零个或多个标志来影响输出的对齐方式和前缀.

Width: 十进制整数, 控制格式化值的最小宽度, 以字符为单位. 默认情况下, 值是右对齐的, 使用空格进行填充. 这可以通过使用 -(左对齐) 和 0(前缀 0) 标志来覆盖.

.Precision: 十进制整数, 控制要输出的字符串, 小数位数或有效数字的最大位数, 取决于输出类型. 输出类型(Type) 的最前面必须是小数点. 指定精度可能会导致输出值被截断(或四舍五入) 或补全的方式. 输出类型以及每种类型受到精度值的影响如下(有关不同输出类型的解释, 参见下表):

  • f, e, E: Precision 指定小数点后的位数. 默认值为 6.
  • g, G: Precision 指定最大的有效数字数. 默认值为 6.
  • s: Precision 指定要打印的最大字符数. 超过这个数字的字符不会被打印.
  • 对于整数类型(d, i, u, x, X, o), Precision 的作用类似于前缀为 0 默认值为 1 的 Width.

ULT:: 指定应用于字符串值的大小写转换 -- U(大写), L(小写) 或 T(标题). 仅对 s 类型有效. 例如 {:U} 或 {:.20Ts}. 也支持小写字母 l 和 t, 但 u 被保留给无符号整数.

Type: 下面类型表中一个指示输入值将被如何解析的字符. 如果省略, 默认为 s.

Flags

标志 | 含义
- | 在给定位宽下使结果左对齐(不足位宽的右侧部分补以空格). 例如, Format("{:-10}", 1) 返回 1 . 如果省略, 结果将在给定的位宽内右对齐.
+ | 如果输出值是带符号的类型, 则使用符号(+ 或 -) 作为前缀. 例如, Format("{:+d}", 1) 返回 +1. 如果省略, 仅在输出值是负数时显示符号(-).
0 | 如果 width 以 0 为前缀, 前导 0 将被添加直至最小宽度. 例如, Format("{:010}", 1) 返回 0000000001. 若同时使用 0 和 -, 则前者将被忽略. 如果 0 被指定为整数格式(i, u, x, X, o, d) 且同时带有精度指示 - 例如, {:04.d} - 此时的 0 会被忽略. 如果省略, 不填充.
(空格) | 当输出值有符号且为正数时, 以 单个 空格为前缀来修饰. 如果空格 和 + 同时出现时, 空格将被忽略. 例如, Format("{: 05d}", 1) 返回 0001. 如果省略, 无空格.
# | 当 # 和 o, x 或 X 格式一起使用时, 此标志使用 0, 0x 或 0X 的形式分别修饰任意非零的输出值. 例如, Format("{:#x}", 1) 返回 0x1. 当 # 和 e, E, f, a, A 格式一起使用时, 此标志强制使输出值包含小数点. 例如, Format("{:#.0f}", 1) 返回 1.. 当 # 和 g 或 G 一起使用时, 此标志强制使输出值包含小数点并保留末尾的 0. 当 # 和 c, d, i, u 或 s 格式一起使用时会被忽略.

Types

类型字符 | 参数 | 输出格式
d 或 i | 整数 | 有符号整数. 例如, Format("{:d}", 1.23) 返回 1.
u | 整数 | 无符号整数.
x 或 X | 整数 | 无符号十六进制整数; 由 x 的大小写形式决定输出值是 "abcdef" 还是 "ABCDEF" 的形式, 仅当使用了 # 标志时, 0x 前缀才会包含到输出值中, 如 {:#x}. 要总是包含前缀, 请使用 0x{:x} 或类似的. 例如, Format("{:X}", 255) 返回 FF.
o | 整数 | 无符号八进制整数. 例如, Format("{:o}", 255) 返回 377.
f | 浮点数 | 形如 [ - ]dddd.dddd 的有符号数值, dddd 可以是一位或多位十进制数字. 小数点前的数字位数取决于整数部分的大小, 小数点后的数字位数取决于需求的精度. 例如, Format("{:.2f}", 1) 返回 1.00.
e | 浮点数 | 形如 [ - ]d.dddd e [符号]dd[d] 的有符号值, 这里的 d 是一位数字, dddd 是一位或多位数字, dd[d] 是两或三位数字, 取决于输出格式的定义和指数的大小, 这里的 符号 是 + 或 -. 例如, Format("{:e}", 255) 返回 2.550000e+02.
E | 浮点数 | 等同于 e 格式, 但结果中指数部分显示的是 E 而不是 e.
g | 浮点数 | 以 f 或 e 格式显示带符号的值, 以给定值和精度更紧凑的为准. e 格式只在值的指数小于 -4 或大于或等于 precision 参数时使用. 尾部的零被截断, 小数点只在后面有一个或多个数字时才会出现.
G | 浮点数 | 等同于 g 格式, 但引入指数时的 e 将被 E 代替(在适当的地方).
a | 浮点数 | 形如 [?]0xh.hhhh p±dd 的有符号十六进制双精度浮点值, 其中 h.hhhh 的小数部分是十六进制数值(使用小写字母), 而 dd 是代表指数的一个或多个数字, 精度指定了小数点后的位数. 例如, Format("{:a}", 255) 返回 0x1.fe00000000000p+7.
A | 浮点数 | 等同于 a 格式, 但当引入指数时使用 P, 而不是 p.
p | 整数 | 将参数显示为十六进制的内存地址. 例如, Format("{:p}", 255) 返回 00000000000000FF.
s | 字符串 | 输出字符串. 如果输入值是数值, 该输入值会在 Width 和 Precision 生效前, 自动转换为字符串.
c | 字符编码 | 按照编码顺序输出一个单字符, 类似于 Chr(n). 如果输入值不在预期范围内将被回转. 例如, Format("{:c}", 116) 返回 t.

备注

不同于 printf, 不支持大小指定符. 所有的整数和浮点数输入值都是 64 位的.

相关

FormatTime

示例

演示不同的用法.

s := ""
; 简单替换
s .= Format("{2}, {1}!`r`n", "World", "Hello")
; 填充空格
s .= Format("|{:-10}|`r`n|{:10}|`r`n", "Left", "Right")
; 十六进制
s .= Format("{1:#x} {2:X} 0x{3:x}`r`n", 3735928559, 195948557, 0)
; 浮点数
s .= Format("{1:0.3f} {1:.10f}", 4*ATan(1))

ListVars  ; 用 AutoHotkey 的主窗口显示等宽文本.
WinWaitActive "ahk_class AutoHotkey"
ControlSetText(s, "Edit1")
WinWaitClose


FormatTime - 语法 & 使用 | AutoHotkey v2

FormatTime

将 YYYYMMDDHH24MISS 时间戳转换为指定的日期/时间格式.

String := FormatTime(YYYYMMDDHH24MISS, Format)

参数

YYYYMMDDHH24MISS

类型: 字符串

如果为空或省略, 则默认为当前本地日期和时间. 否则, 请指定 YYYYMMDDHH24MISS 格式时间戳的全部或前面的部分.

Format

类型: 字符串

如果为空或省略, 则它默认为时间后跟着长日期, 并且会对它们根据当前用户区域设置进行格式化. 例如: 4:55 PM Saturday, November 27, 2004

否则, 请指定一个或多个下面的日期-时间格式以及在它们之间的任何原义空格和标点(逗号不需要转义; 它们可以正常使用). 在下面的例子中, 请注意 M 必须为大写: M/d/yyyy h:mm tt

返回值

类型: 字符串

该函数返回指定时间戳的转换版本.

如果 YYYYMMDDHH24MISS 包含无效的日期和/或时间部分 -- 例如非闰年的 2 月 29 日 -- 那么日期和/或时间将从返回值中省略. 虽然只支持 1601 年到 9999 年之间的年份, 但只要时间部分有效, 仍然可以为更早的年份生成格式化的时间.

如果 Format 包含超过 2000 个字符, 则返回一个空字符串.

日期格式(区分大小写)

Format | 描述
d | 不含前导零的天数(1 – 31)
dd | 含前导零的天数(01 – 31)
ddd | 在当前的用户语言里星期几的简称(例如, 周一)
dddd | 在当前的用户语言里星期几的全称(例如, 星期一)
M | 不含前导零的月份(1 – 12)
MM | 含前导零的月份(01 – 12)
MMM | 在当前的用户语言里月份的简称(例如, 一月)
MMMM | 在当前的用户语言里月份的全称(例如, 一月)
y | 不含世纪的年份, 不含前导零(0 – 99)
yy | 不含世纪的年份, 含前导零(00 – 99)
yyyy | 含世纪的年份. 例如: 2005
gg | 当前用户区域设置的时代/纪元字符串(如果没有则为空)

时间格式(区分大小写)

Format | 描述
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 | 描述
(空) | 留空 Format 来生成时间后跟着长日期. 例如, 在某些区域设置中它可能看起来像这样 4:55 PM Saturday, November 27, 2004(译者注: 显示的内容与顺序与系统设置有关, 中文: 下午 4:55 星期六,2004年11月27日)
Time | 当前用户区域设置的时间表示, 例如 5:26 PM(译者注: 显示的内容与顺序与系统设置有关, 中文: 下午 5:26)
ShortDate | 当前用户区域设置的短日期表示, 例如 02/29/04(译者注: 显示的内容与顺序与系统设置有关, 中文: 2004/2/29 )
LongDate | 当前用户区域设置的长日期表示, 例如 Friday, April 23, 2004(译者注: 显示的内容与顺序与系统设置有关, 中文: 星期五,2004年4月23日)
YearMonth | 当前用户区域设置的年份和月份格式, 例如 February, 2004(译者注: 显示的内容与顺序与系统设置有关, 中文: 2004年2月)
YDay | 不含前导零的年份的天数(1 – 366)
YDay0 | 含前导零的年份的天数(001 – 366)
WDay | 星期的天数(1 – 7). 星期天为 1.
YWeek | ISO 8601 中规定的完全年份和周数. 例如: 200453. 如果含有 1 月 1 日的星期有四天以上在新年里, 则它被认为是新年的第一星期. 否则, 它为前一年的最后一个星期, 而下一星期为新年的第一星期. 因此, 1 月 4 日和首个星期四总是在第一周.

附加选项

下列选项可以紧跟在 YYYYMMDDHH24MISS 时间戳后(如果没有时间戳, 它们也可以单独使用). 在下面的例子中, 请注意最后的四项间没有逗号:

OutputVar := FormatTime("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 代码页而不是区域设置代码页进行字符串转换.

注意: Dn 和 Tn 可以使用多次以使多个选项生效, 例如: FormatTime("20040228 D2 D4 T1 T8")

备注

您希望从 Format原义转换到最终字符串中的字母和数字应该用单引号括起来, 如此例所示: "'Date:' MM/dd/yy 'Time:' hh:mm:ss tt".

相反, 非字母数字字符(例如空格, tab, 换行符(`n), 斜杠, 冒号, 逗号和其他标点) 不需要包围在单引号中. 例外情况是单引号字符本身: 要产生原义的单引号, 请使用四个连续的单引号(''''), 不过如果它们已经包含在一对外部引号中则仅使用连续的两个就行了.

如果 Format 同时包含日期和时间元素, 则它们不能混用. 换句话说, 这个字符串应该分成两半: 一半时间, 一半日期. 例如, 包含 "hh yyyy mm" 的格式字符串不会产生期望的结果, 因为它在两个时间元素间包含日期元素.

当 Format 包含数值的天数(d 或 dd) 后跟着月份的全称(MMMM), 则使用月份名称的所有格形式(如果当前语言有所有格形式).

相关提示, 可以使用 DateAdd 和 DateDiff 对日期和时间进行加减和比较.

相关

要进行反向的转换 -- 即, 从 格式化的日期/时间 转换到 YYYYMMDDHH24MISS 格式 -- 请参阅论坛帖子.

另请参阅: Gui DateTime 控件, Format, 内置的日期和时间变量, FileGetTime

示例

演示不同的用法.

TimeString := FormatTime()
MsgBox "The current time and date (time first) is " TimeString

TimeString := FormatTime("R")
MsgBox "The current time and date (date first) is " TimeString

TimeString := FormatTime(, "Time")
MsgBox "The current time is " TimeString

TimeString := FormatTime("T12", "Time")
MsgBox "The current 24-hour time is " TimeString

TimeString := FormatTime(, "LongDate")
MsgBox "The current date (long format) is " TimeString

TimeString := FormatTime(20050423220133, "dddd MMMM d, yyyy hh:mm:ss tt")
MsgBox "The specified date and time, when formatted, is " TimeString

MsgBox FormatTime(200504, "'Month Name': MMMM`n'Day Name': dddd")

YearWeek := FormatTime(20050101, "YWeek")
MsgBox "January 1st of 2005 is in the following ISO year and week number: " YearWeek

改变文件的日期-时间戳.

FileName := FileSelect(3,, "Pick a file")
if FileName = "" ; 用户没有选取文件.
    return
FileTime := FileGetTime(FileName)
FileTime := FormatTime(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 := DateAdd(time, NumberOfSeconds, "Seconds")
    return NumberOfSeconds//3600 ":" FormatTime(time, "mm:ss")
    /*
    ; 和上面方法不同的是, 这里不支持超过 24 小时的秒数:
    return FormatTime(time, "h:mm:ss")
    */
}


Func 对象 - 方法 & 属性 | AutoHotkey v2

Func 对象

class Func extends Object

表示可自定义或内置的函数, 并提供一个接口来调用, 将参数与其绑定, 以及检索它或它的参数的信息.

有关其他可以像函数一样调用的对象的信息, 请参阅函数对象.

Closure 类继承 Func, 但没有定义任何新的属性.

对于脚本中的每个内置函数或函数定义, 都有一个相应的只读变量, 其中包含一个 Func 对象. 这个变量直接用于调用函数, 但它的值也可以被读取, 以检索函数本身, 作为一个值. 例如:

InspectFn StrLen
InspectFn InspectFn

InspectFn(fn)
{
    ; 显示所传函数的信息.
    MsgBox fn.Name "() is " (fn.IsBuiltIn ? "built-in." : "user-defined.")
}

下面使用 "FuncObj" 作为任何 Func 对象的占位符, 因为 "Func" 就是类本身.

除了从 Object 继承的方法和属性外, Func 对象还具有以下预定义的方法和属性.

目录

  • 方法:
    • Call: 调用函数.
    • Bind: 绑定参数到函数.
    • IsByRef: 确定参数是否为 ByRef 类型.
    • IsOptional: 确定参数是否是可选的.
  • 属性:
    • Name: 返回函数的名称.
    • IsBuiltIn: 如果为内置函数, 则返回 1(true), 否则返回 0(false).
    • IsVariadic: 如果函数为可变参数, 则返回 1(true), 否则返回 0(false).
    • MinParams: 返回所需参数的数量.
    • MaxParams: 对于用户定义函数返回正式声明的参数数目, 对于内置函数返回最大的参数数目.

方法

Call

调用一个函数.

FuncObj(Param1, Param2, ...)
FuncObj.Call(Param1, Param2, ...)

参数

Param1, Param2, ...

参数和返回值由函数定义.

备注

调用一个值时, "Call" 方法是隐式的, 所以不需要显式指定.

Bind

为函数绑定参数.

BoundFunc := FuncObj.Bind(Param1, Param2, ...)

参数

Param1, Param2, ...

任意数量的参数.

返回值

类型: Object

此方法返回一个绑定函数对象.

IsByRef

确定一个参数是否为 ByRef(按地址传递) 类型.

Boolean := FuncObj.IsByRef(ParamIndex)

参数

ParamIndex

类型: 整数

如果省略, Boolean 表示此函数是否含有 ByRef 参数. 否则, 请指定基于 1 的参数索引.

返回值

类型: 整数(布尔值)

如果参数为 ByRef, 此方法返回 1(true), 否则为 0(false). 如果 ParamIndex 无效, 则抛出异常.

IsOptional

确定一个参数是否是可选的.

Boolean := FuncObj.IsOptional(ParamIndex)

参数

ParamIndex

类型: 整数

如果省略, Boolean 表示此函数是否含有可选参数. 否则, 请指定基于 1 的参数索引.

返回值

类型: 整数(布尔值)

如果参数可选, 此方法返回 1(true) , 否则为 0(false). 如果 ParamIndex 无效, 则抛出异常.

备注

如果此函数是可变参数的, 那么参数可以不进行正式声明. 支持内置函数.

属性

Name

返回函数的名称.

FunctionName := FuncObj.Name

IsBuiltIn

内置函数返回 1(true), 否则返回 0(false).

Boolean := FuncObj.IsBuiltIn

IsVariadic

如果函数为可变参数时返回 1(true), 否则返回 0(false).

Boolean := FuncObj.IsVariadic

MinParams

返回函数必要参数的数目.

ParamCount := FuncObj.MinParams

MaxParams

对于用户定义函数返回正式声明的参数数目, 对于内置函数返回最大的参数数目.

ParamCount := FuncObj.MaxParams

如果函数是可变参数的, ParamCount 表示函数在不考虑 "variadic*" 可变参数的情况下可接受的最大参数数目.


GetKeyName - 语法 & 使用 | AutoHotkey v2

GetKeyName

检索按键的名称或文本.

Name := GetKeyName(KeyName)

参数

KeyName

类型: 字符串

这可以是键盘上的任何单个字符, 也可以是按键列表中的一个键名. 例如: B, 5, LWin, RControl, Alt, Enter, Escape.

或者, 可以指定显式虚拟键码(如 vkFF), 或显式扫描码(如 sc01D), 或 VK 和 SC 的组合(按该顺序, 如 vk1Bsc001). 请注意, 这些代码必须是十六进制的.

返回值

类型: 字符串

函数返回指定按键的名称, 如果按键无效或没有名称, 则返回空白.

相关

GetKeyVK, GetKeySC, GetKeyState, Key List

示例

检索并报告 Esc 的英文名称.

MsgBox GetKeyName("Esc") ; 显示 Escape
MsgBox GetKeyName("vk1B") ; 也显示 Escape


GetKeySC - 语法 & 使用 | AutoHotkey v2

GetKeySC

检索按键的扫描码.

SC := GetKeySC(KeyName)

参数

KeyName

类型: 字符串

按键列表中的任意单个字符或一个按键的名称. 例如: B, 5, LWin, RControl, Alt, Enter, Escape.

或者, 可以指定显式虚拟键码(如 vkFF), 或显式扫描码(如 sc01D), 或 VK 和 SC 的组合(按该顺序, 如 vk1Bsc001). 请注意, 这些代码必须是十六进制的.

返回值

类型: 整数

函数返回指定按键的扫描码, 如果按键无效或没有扫描码, 则返回 0.

备注

在用 Hotkey 或 GetKeyState 等内置函数使用扫描码之前, 必须首先将其转换为十六进制格式, 例如使用 Format("vk{:X}", vk_code). 相比之下, 通过 DllCall 调用的外部函数通常直接使用数字值.

如果 KeyName 对应于虚拟键码或单个字符, 该函数将通过调用特定的系统函数(该函数引用脚本当前的键盘布局) 来将该值映射到扫描码. 这可能与活动窗口的键盘布局不同.

如果 KeyName 是 A-Z 范围内的 ASCII 字母, 并且在键盘布局中没有映射, 则使用 vk41-vk5A 范围内相应的虚拟键作为备用.

有些键盘布局没有定义虚拟键码到扫描码的 1:1 映射. 当可能有多种解释时, 底层系统函数很可能根据键盘布局中定义的顺序选择一种, 这并不总是最常见或最合理的选择.

相关

GetKeyVK, GetKeyName, GetKeyState, Key List, Format

示例

检索并报告左 Ctrl 的十六进制扫描码.

sc_code := GetKeySC("LControl")
MsgBox Format("sc{:X}", sc_code) ; 报告 sc1D


GetKeyState - 语法 & 使用 | AutoHotkey v2

GetKeyState

根据指定的键盘按键或鼠标/控制器按钮是上还是下, 返回 1 (true) 或 0(false). 也检索控制器状态.

IsDown := GetKeyState(KeyName , Mode)

参数

KeyName

类型: 字符串

此参数可以是键盘中任何的单个字符或按键列表中的其中一个键名, 如一个鼠标/控制器按键. 例如: B, 5, LWin, RControl, Alt, Enter, Escape, LButton, MButton, Joy1.

或者, 可以指定明确的虚拟键代码, 例如 vkFF. 这在按键没有名字的罕见情况下很有用. 这种按键的代码可以通过按键列表页底部的步骤来确定. 请注意, 这个代码必须是十六进制的.

已知限制: 此函数不能区分两个共享相同虚拟键代码的键, 例如 Left 和 NumpadLeft.

Mode

类型: 字符串

获取控制器状态时, 此参数被忽略.

如果省略, 则默认获取按键的逻辑状态. 这是操作系统和活动窗口所认为的按键所处的状态, 但可能和按键的物理状态不一致.

否则, 请指定以下字母之一:

P: 获取物理状态( 即用户是否实际按住了按键). 按键或鼠标按键的物理状态通常和逻辑状态一致, 除非安装了键盘和/或鼠标钩子, 在这种情况下, 它将准确反映出用户是否按下了按键或鼠标按键(只要在脚本执行时按键正被按住). 您可以通过 KeyHistory 函数或菜单项来确定脚本中是否使用了钩子. 您可以通过调用 #InstallKeybdHook 和/或 #InstallMouseHook 函数来强制安装钩子.

T: 获取切换状态. 对于除 CapsLock, NumLock 和 ScrollLock 以外的键, 当脚本启动时, 切换状态一般为 0, 并且在进程之间不同步.

返回值

类型: 整数(布尔值), 浮点数, 整数或字符串(空值)

对于键盘键和鼠标按钮, 如果键位向下(或切换开启), 该函数返回 1(true) 如果键位向上(或切换关闭), 该函数返回 0(false).

当 KeyName 是手柄的轴, 如 JoyX, 函数返回一个 0 到 100 之间的浮点数, 用于指示手柄的位置为该轴运动范围的百分比. 这个测试脚本可以用来分析你的控制器.

当 KeyName 是 JoyPOV 时, 函数返回一个 0 到 35900 之间的整数. 许多控制器使用与下列近似的 POV 值:

  • -1: 没有角度
  • 0: 向前 POV
  • 9000(即 90 度): 向右 POV
  • 27000(即 270 度): 向左 POV
  • 18000 (即 180 度): 向后 POV

当 KeyName 为 JoyName, JoyButtons, JoyAxes 或 JoyInfo, 检索值将是控制器的名称, 按钮数量, 轴数量或功能. 有关详情, 请参阅游戏控制器.

当 KeyName 是无法检测到的控制器的按钮或控制键时, 函数返回空字符串.

错误处理

如果检测到无效参数, 则抛出 ValueError, 例如当前键盘布局中不存在 KeyName.

备注

为了等待按键或鼠标/控制器按钮进入新的状态, 通常使用 KeyWait 代替 GetKeyState 的循环会更简单.

带有不常见键盘驱动的系统更新按键的状态可能比较慢, 尤其是像 CapsLock. 这样按键的切换状态. 在按键状态改变后立即对其状态进行检查的脚本可以预先使用 Sleep, 以便系统有时间更新按键的状态.

有关对控制器使用, 请参阅控制器重映射页面和控制器到鼠标的映射脚本.

相关

GetKeyVK, GetKeySC, GetKeyName, KeyWait, Key List, Controller remapping, KeyHistory, InstallKeybdHook, InstallMouseHook

示例

检索鼠标右键的当前状态.

state := GetKeyState("RButton")

检索首个控制器的第二个按钮的当前状态.

state := GetKeyState("Joy2")

检查是否至少有一个 Shift 被关闭.

if GetKeyState("Shift")
    MsgBox "At least one Shift key is down."
else
    MsgBox "Neither Shift key is down."

读取 CapsLock 的当前切换状态.

state := GetKeyState("CapsLock", "T")

重映射. (此示例仅用于说明, 因为内置的重新映射功能更容易使用.) 在下面的热键中, 按下 NumpadAdd 时, 鼠标按钮被按住, 这有效地将 NumpadAdd 变成了一个鼠标按键. 该方法还可以用于重复操作, 而用户正在按住一个键或按键.

*NumpadAdd::
{
    MouseClick "left",,, 1, 0, "D"  ; 按住鼠标左键.
    Loop
    {
        Sleep 10
        if !GetKeyState("NumpadAdd", "P")  ; 按键已经被释放, 所以退出循环.
            break
        ; ... 此处放置您想要重复的任何动作.
    }
    MouseClick "left",,, 1, 0, "U"  ; 释放鼠标按钮.
}

使控制器按钮的行为取决于操纵杆轴的位置.

joy2::
{
    JoyX := GetKeyState("JoyX")
    if JoyX > 75
        MsgBox "Action #1 (button pressed while stick was pushed to the right)."
    else if JoyX < 25
        MsgBox "Action #2 (button pressed while stick was pushed to the left)."
    else
        MsgBox "Action #3 (button pressed while stick was centered horizontally)."
}

请参阅控制器重映射页面和控制器到鼠标的映射脚本的其他示例.


GetKeyVK - 语法 & 使用 | AutoHotkey v2

GetKeyVK

检索按键的虚拟键码.

VK := GetKeyVK(KeyName)

参数

KeyName

类型: 字符串

按键列表中的任意单个字符或一个按键的名称. 例如: B, 5, LWin, RControl, Alt, Enter, Escape.

或者, 可以指定显式虚拟键码(如 vkFF), 或显式扫描码(如 sc01D), 或 VK 和 SC 的组合(按该顺序, 如 vk1Bsc001). 请注意, 这些代码必须是十六进制的.

返回值

类型: 整数

函数返回指定按键的虚拟键码, 如果按键无效或没有虚拟键码, 则返回 0.

备注

在用 Hotkey 或 GetKeyState 等内置函数使用虚拟键码之前, 必须首先将其转换为十六进制格式, 例如使用 Format("vk{:X}", vk_code). 相比之下, 通过 DllCall 调用的外部函数通常直接使用数字值.

如果 KeyName 对应于扫描码或单个字符, 该函数将通过调用特定的系统函数(该函数引用脚本当前的键盘布局) 来将该值映射到虚拟键码. 这可能与活动窗口的键盘布局不同.

如果 KeyName 是 A-Z 范围内的 ASCII 字母, 并且在键盘布局中没有映射, 则使用 vk41-vk5A 范围内相应的虚拟键作为备用.

有些键盘布局没有定义虚拟键码与扫描码的 1:1 映射. 当可能有多种解释时, 底层系统函数很可能根据键盘布局中定义的顺序选择一种, 这并不总是最常见或最合理的选择.

相关

GetKeySC, GetKeyName, GetKeyState, Key List, Format

示例

检索并报告 Esc 的十六进制虚拟键码.

vk_code := GetKeyVK("Esc")
MsgBox Format("vk{:X}", vk_code) ; 报告 vk1B


GetMethod - 语法 & 使用 | AutoHotkey v2

GetMethod

检索方法的实现函数.

Method := GetMethod(Value , Name, ParamCount)

参数

Value

类型: Any

除了 ComObject 之外的任何类型的任何值.

Name

类型: 字符串

省略此参数, 对 Value 本身进行验证, 如果成功, 则返回 Value. 否则, 请指定要检索的方法的名称.

ParamCount
类型: 整数

如果省略(或者参数数没有被验证), 则会对 Call 方法进行基本检查, 以验证该对象可调用的.

否则, 请指定将被传递给方法或函数的参数数量. 如果指定, 可以查询该方法的 MinParams, MaxParams 和 IsVariadic 属性, 以验证它是否可以接受这个参数指定的数量. 如果这些属性不存在, 参数数就不会被验证.

这个计数不应该包括隐含的 this 参数.

返回值

类型: 函数对象

函数返回包含方法实现的函数对象, 如果省略了 Name, 则返回 Value 本身.

错误

如果没有找到该方法或在没有调用属性获取器(getter) 的情况下不能被检索到, 则抛出 MethodError.

如果尝试验证, 可能会因为查询方法的属性而抛出异常. 如果验证失败, 则抛出 ValueError 或 MethodError.

备注

方法可以通过以下方式来定义:

  • 一个具有 call 访问函数的动态属性. 这包括:
    • 任何由类中的方法定义创建的属性.
    • 通过向 DefineProp 传递 {Call: fn} 这样的描述符创建的任何属性, 其中 fn 实现了方法.
    • 任何预定义/内置的方法.
  • 对象或其基对象之一的自有值属性, 其中的值是一个函数对象.
  • 一个带有 getter 的动态属性, 它返回一个函数对象. GetMethod 不支持这种情况.
  • 在 __Call 元函数中进行处理. 这种方式实现的方法不能被检测到, 甚至可能没有对应的函数对象, 所以不受 GetMethod 的支持.

当调用函数对象时, 需要为通常隐藏的 this 参数提供一个值. 例如, Method(Value, Parameters*).

尽管 GetMethod 的标准实现有上述限制, 但如果使用 Value.GetMethod(Name) 而不是 GetMethod(Value, Name), 对象 Value 可以定义自己的 GetMethod 的实现.

GetMethod(Value, "Call", N) 不等同于 GetMethod(Value,, N), 因为 Call 方法将函数对象本身作为参数, 而且其用法可能与 Value 的用法不同. 例如, Func.Prototype.Call 是一个单一的方法, 适用于所有内置和用户定义的函数, 因此必须接受任何数量的参数.

相关

Objects, HasMethod, HasBase, HasProp

示例

检索并报告有关 GetMethod 方法的信息.

method := GetMethod({}, "GetMethod")  ; 这也是一种方法.
MsgBox method.MaxParams  ; 接受 2 个参数, 包括 'this'.
MsgBox method = GetMethod  ; 在这种情况下, 实际上是同一个对象.


Goto - 语法 & 使用 | AutoHotkey v2

Goto

跳转到指定的标签并继续执行.

Goto Label
Goto("Label")

参数

Label

类型: 字符串

要跳转到的标签的名称.

备注

仅当圆括号使用时, Label 可以是变量或表达式. 例如, Goto MyLabel 和 Goto("MyLabel") 都跳转到 MyLabel:.

在使用动态标签(即返回标签名称的变量或表达式) 时, 性能会略有下降, 因为必须每次 "查找" 目标标签, 而不是在首次加载脚本时只 "查找" 一次. 如果标签不存在, 将显示一个错误对话框. 要避免此问题, 请预先调用 IsLabel(). 例如:

if IsLabel(VarContainingLabelName)
    Goto(VarContainingLabelName)

不鼓励使用 Goto, 因为它通常让脚本不容易阅读且难以维护. 考虑使用 Else, 区块, Break 和 Continue 来代替 Goto.

相关

Return, IsLabel, Else, 区块, Break, Continue

示例

跳转到名为 "MyLabel" 的标签并继续执行.

Goto MyLabel
; ...
MyLabel:
Sleep 100
; ...


GroupActivate - 语法 & 使用 | AutoHotkey v2

GroupActivate

激活由 GroupAdd 定义的窗口组中的下一个窗口.

HWND := GroupActivate(GroupName , Mode)

参数

GroupName

类型: 字符串

要激活的组的名称, 和原来由 GroupAdd 定义的一样.

Mode

类型: 字符串

如果为空或省略, 激活组中最早的窗口. 否则, 请指定以下字母:

R: 最新的窗口(最近激活的窗口) 被激活, 但仅当函数运行时组中没有活动的成员时才会激活. "R" 在临时切换到处理不相关任务的情况下非常有用. 当您使用 GroupActivate, GroupDeactivate 或 GroupClose 返回到目标组时, 会激活您最近工作的窗口而不是最早的窗口.

返回值

类型: 整数

该函数返回所选窗口的HWND(唯一 ID), 如果没有找到匹配的窗口进行激活, 则返回 0. 如果当前激活的窗口是唯一匹配的窗口, 则返回值为 0.

备注

此函数使匹配组窗口规格之一的第一个窗口被激活. 再次使用它将激活系列中的下一个窗口, 依此类推. 通常, 将其分配给一个热键, 以便通过按下该热键自动遍历窗口.

每个窗口都是根据窗口组作为一个整体来评估的, 而不区分窗口规格. Mode 影响整个组的激活顺序.

在某些系统中, 当一个窗口在其他窗口激活后立即被激活时, 任务栏按钮可能会开始闪烁(取决于操作系统和设置). 为防止这种情况, 请使用 #WinActivateForce.

关于窗口组的更多细节, 请参阅 GroupAdd.

相关

GroupAdd, GroupDeactivate, GroupClose, #WinActivateForce

示例

激活窗口组中最新的窗口(最近活动的窗口).

GroupActivate "MyGroup", "R"


GroupAdd - 语法 & 使用 | AutoHotkey v2

GroupAdd

增加窗口规格到窗口组, 必要时创建组.

GroupAdd GroupName , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

GroupName

类型: 字符串

要向其中添加此窗口规范的组的名称. 如果组不存在, 则会创建它. 组名不区分大小写.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 尽管 DetectHiddenWindows, DetectHiddenText 和 SetTitleMatchMode 不会直接影响此函数的行为, 但它们会影响其他组函数(例如 GroupActivate 和 GroupClose). 它们还会影响其他任何函数的 WinTitle 参数中 ahk_group 的使用.

备注

每使用此函数一次则添加一条新规则到组中. 换句话说, 一个组由窗口规格的集合组成而不是固定的窗口列表. 后面当类似 GroupActivate的函数使用组时, 会使用这些规则中的每一条检查桌面上的每个窗口. 如果窗口匹配组里的其中一条规则, 则它被视为一个匹配.

窗口组的典型用法是将相关窗口收集绑定在一起, 这可用于包含许多相关窗口的任务或有许多子窗口的程序. 例如, 如果您频繁地工作在一个图形程序或文本编辑器的多个实例时, 您可以使用热键通过 GroupActivate 来切换此程序的每一个实例(每次一个), 而不需要使用 alt-tab 或任务栏按钮找到它们.

由于每组中的条目仅需要添加一次, 所以此函数通常使用在脚本启动时. 添加重复的条目到组中会被忽略.

要在一个组中包含 所有 窗口(除了特殊的 Program Manager 窗口), 请使用这个例子:

GroupAdd "AllWindows"

通过在 WinTitle 参数中指定 ahk_group MyGroupName, 所有的窗口函数都可以操作窗口组. 函数 WinMinimize, WinMaximize, WinRestore, WinHide, WinShow, WinClose 和 WinKill 会对一个组中的 所有 窗口进行操作. 要仅对顶层窗口进行操作, 请参照此例:

WinHide WinExist("ahk_group MyGroup")

与之相比, 其他的窗口函数(例如 WinActivate 和 WinExist) 只对组中的顶层窗口进行操作.

相关

GroupActivate, GroupDeactivate, GroupClose

示例

按下热键可以遍历所有打开的 MSIE 窗口.

; 在全局代码中, 启动时计算:
GroupAdd "MSIE", "ahk_class IEFrame" ; 只添加 Internet Explorer 窗口到该组.

; 设置一个热键激活该组, 它会遍历
; 打开的所有 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"

; 设置一个热键访问每个 Outlook 窗口(每次一个).
Numpad5::GroupActivate "mail"


GroupClose - 语法 & 使用 | AutoHotkey v2

GroupClose

关闭刚刚被 GroupActivate 或 GroupDeactivate 激活的活动窗口. 接着激活系列中的下一个窗口. 它还可以关闭组中所有窗口.

GroupClose GroupName , Mode

参数

GroupName

类型: 字符串

GroupAdd 最初定义的组的名称.

Mode

类型: 字符串

如果为空或省略, 函数关闭活动窗口并激活组中最老的窗口. 否则, 请指定以下字母之一:

R: 最新的窗口(最近激活的窗口) 被激活, 但仅当函数运行时组中没有活动的成员时才会激活. "R" 在临时切换到处理不相关任务的情况下非常有用. 当您使用 GroupActivate, GroupDeactivate 或 GroupClose 返回组时, 会激活您最近工作的窗口而不是最老的窗口.

A: 关闭组的所有成员. 这等同于 WinClose "ahk_group GroupName".

备注

当 Mode 参数不是 "A" 时, 则此函数的行为取决于之前对 GroupName 操作的函数是 GroupActivate 还是 GroupDeactivate. 如果是 GroupDeactivate, 则仅当活动窗口 不是 组的成员时此函数才关闭活动窗口(否则它什么都不做). 如果是 GroupActivate 或者没有, 则仅当活动窗口 是 组的成员时此函数才关闭活动窗口(否则它什么都不做). 这种特性允许分配一个热键到 GroupClose 来配合 GroupName 的 GroupActivate 或 GroupDeactivate 热键.

当活动窗口关闭时, 系统通常会激活下一个最近的活动窗口. 如果新激活的窗口与刚刚关闭的窗口匹配相同的窗口规范, 则它将保持激活状态, 即使默认 Mode 通常指示下一个应该激活 最老的 窗口. 如果新激活的窗口与组的 任何 窗口规范匹配, 则保持激活状态.

关于窗口组的更多细节, 请参阅 GroupAdd.

相关

GroupAdd, GroupActivate, GroupDeactivate

示例

关闭由 GroupActivate 或 GroupDeactivate 激活的活动窗口, 并激活窗口组中最新的窗口(最近活动的窗口).

GroupClose "MyGroup", "R"


GroupDeactivate - 语法 & 使用 | AutoHotkey v2

GroupDeactivate

类似于 GroupActivate, 不同的是它激活 不 在组中的下一个窗口.

GroupDeactivate GroupName , Mode

参数

GroupName

类型: 字符串

目标组的名称, 最初由 GroupAdd 定义.

Mode

类型: 字符串

如果为空或省略, 函数将激活最老的非成员窗口. 否则, 请指定以下字母:

R: 最新的非成员窗口(最近激活的窗口) 被激活, 但仅当函数运行时该组的成员处于活动状态时才会激活. "R" 在临时切换到处理不相关任务的情况下非常有用. 当您使用 GroupActivate, GroupDeactivate 或 GroupClose 返回组时, 会激活您最近工作的窗口而不是最老的窗口.

备注

GroupDeactivate 会激活 不 匹配组中任何窗口规格的首个窗口. 再次使用 GroupDeactivate 将激活系列窗口中的下一个. 通常给 GroupDeactivate 分配一个热键, 以便使用热键自动遍历窗口.

此函数可用于您拥有几乎总是在运行的常用窗口集合时. 通过把这些窗口添加到一个组中, 您可以使用 GroupDeactivate 访问每个不常用窗口并决定是否关闭它. 此函数可以让您快速清理桌面, 比手动快得多.

GroupDeactivate 选择窗口的方式类似于 Alt+Shift+Esc 系统热键. 具体来说:

  • 子窗口, 如某些对话框和工具窗口, 不会被计算在内. 但是, 如果父窗口符合激活条件, 则会激活最近激活的子窗口, 除非父窗口最近是激活的. 这是通过调用 GetLastActivePopup 来确定的.
  • 具有 WS_EX_TOPMOST 或 WS_EX_NOACTIVATE 样式的窗口将被跳过.
  • 具有 WS_EX_TOOLWINDOW 样式但没有 WS_EX_APPWINDOW 样式的窗口将被跳过. (这些窗口通常也会从 Alt-Tab 和任务栏中省略.)
  • 被禁用的窗口会被跳过, 除非它拥有的窗口(比如模式对话框) 比窗口本身更早被激活.
  • 隐藏或 cloaked 的窗口会被跳过.
  • 桌面会被跳过.

虽然由于 WS_EX_TOPMOST 样式任务栏被跳过, 但如果没有其他符合条件的窗口并且活动窗口与组匹配, 任务栏就会被激活.

关于窗口组的更多细节, 请参阅 GroupAdd.

相关

GroupAdd, GroupActivate, GroupClose

示例

激活不属于窗口组成员的最老窗口.

GroupDeactivate "MyFavoriteWindows"  ; 访问非收藏的窗口来清理桌面


Gui 对象 - 方法 & 属性 | AutoHotkey v2

Gui 对象

class Gui extends Object

提供一个接口, 用于创建窗口, 添加控件, 修改窗口和检索有关窗口的信息. 这些窗口可以用作数据输入表单或自定义用户界面.

Gui 对象可以通过 Gui() 来创建, 也可以通过 GuiFromHwnd 来检索.

下面使用 "MyGui" 作为任何 Gui 对象的占位符(和示例中的变量名), 因为 "Gui" 就是类本身.

除了从 Object 继承的方法和属性外, Gui 对象还具有以下预定义的方法和属性.

目录

  • 静态方法:
    • Call: 创建新的窗口.
  • 方法:
    • Add: 创建一个新控件并将其添加到窗口中.
    • Destroy: 删除窗口.
    • Flash: 闪烁窗口及其任务栏按钮.
    • GetClientPos: 检索窗口客户端区域的位置和大小.
    • GetPos: 检索窗口的位置和大小.
    • Hide: 隐藏窗口.
    • Maximize: 打开并最大化窗口.
    • Minimize: 打开并最小化窗口.
    • Move: 移动和/或调整窗口的大小.
    • OnEvent: 注册一个函数或方法, 当给定的事件被触发时调用.
    • Opt: 为窗口的外观和行为设置各种选项和样式.
    • Restore: 取消最小化或取消最大化并显示窗口.
    • SetFont: 设置随后创建的控件的字体, 大小, 样式, 和文本颜色.
    • Show: 显示窗口. 它还可以最小化, 最大化或移动窗口.
    • Submit: 从命名的控件中收集值, 并将它们组合成一个对象. 可选择性地隐藏窗口.
    • __Enum: 遍历窗口的控件.
    • __New: 构造一个新的 Gui 实例.
  • 属性:
    • BackColor: 检索或设置窗口的背景色.
    • FocusedCtrl: 检索窗口的焦点控件的 GuiControl 对象.
    • Hwnd: 检索窗口的窗口句柄(HWND).
    • MarginX: 检索或设置两侧与随后创建控件之间的水平边距的大小.
    • MarginY: 检索或设置两侧与随后创建控件之间的垂直边距的大小.
    • MenuBar: 检索或设置窗口的菜单栏.
    • Name: 检索或设置窗口的自定义名称.
    • Title: 检索或设置窗口的标题.
    • __Item: 检索与指定名称, 文本, ClassNN 或 HWND 关联的 GuiControl 对象.
  • 常规:
    • 键盘导航
    • 窗口外观
    • 常规备注
    • 相关
    • 示例

静态方法

Call

创建一个新的窗口.

MyGui := Gui(Options, Title, EventObj)
MyGui := Gui.Call(Options, Title, EventObj)

参数

Options

类型: 字符串

Gui.Opt 支持的任何选项.

Title

类型: 字符串

如果省略, 则默认为 A_ScriptName. 否则, 请指定窗口的标题.

EventObj

类型: 对象

一个 "事件接收器", 或绑定事件的对象. 如果指定了 EventObj, 那么 OnEvent, OnNotify 和 OnCommand 可以用来注册 EventObj 的方法, 以便在事件发生时被调用.

返回值

类型: Object

此方法返回一个 Gui 对象.

方法

Add

添加新的控件到窗口.

GuiCtrl := MyGui.Add(ControlType , Options, Text)
GuiCtrl := MyGui.AddControlType(Options, Text)

参数

ControlType

类型: 字符串

下列的其中一个: ActiveX, Button, CheckBox, ComboBox, Custom, DateTime, DropDownList(或 DDL), Edit, GroupBox, Hotkey, Link, ListBox, ListView, MonthCal, Picture(或 Pic), Progress, Radio, Slider, StatusBar, Tab, Tab2, Tab3, Text, TreeView, UpDown

例如:

MyGui := Gui()
MyGui.Add("Text",, "Please enter your name:")
MyGui.AddEdit("vName")
MyGui.Show()
Options

类型: 字符串

如果为空或省略, 则该控件从其默认值开始. 否则, 指定以下一个或多个选项和样式, 每个选项和样式之间使用一个或多个空格或制表符分隔.

控件的位置和大小

如果在 Options 中省略了某些尺寸和/或坐标, 则会根据前一个控件确定它的位置, 根据控件的类型和内容确定它的大小.

支持下列选项:

R n: 文本的行数(其中 n 为任意数字, 甚至可以为浮点数, 如 r2.5). R 通常比指定 H(高度) 更合适. 如果同时指定 R 和 H 选项, 则 R 优先考虑. 对于 GroupBox, 此选项设置是指在框内保留空间的控件数量. 对于 DropDownList, ComboBox 和 ListBox, 它是指在控件的列表部分内一次可见的项目数(但对于 DropDownList 和 ComboBoxit 通常最好省略 R 和 H 选项, 因为弹出列表会自动利用用户桌面的可用高度). 对于其他控件类型, R 是指可视的容纳在控件内的文本行数.

W n: 宽度(其中 n 为任意数字, 单位为像素). 如果省略, 对于某些控件则根据其内容自动计算宽度. Tab 默认为 30 倍的当前字体大小加上 3 倍的行边距; 垂直进度条默认为两倍的当前字体大小, 水平进度条, 水平滑动条, DropDownList, ComboBox, ListBox, GroupBox, Edit 和 Hotkey: 15 倍的当前字体大小(GroupBox 除外, 其默认宽度为 18 倍, 这样可以显示内部的边距).

H n: 高度(其中 n 为任意数字, 单位为像素). 如果同时省略 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(其中 n 为任意数字, 单位为像素) 用来设置控件的宽度和/或高度等于前一个添加控件的宽度或高度, 可以使用加号或减号进行调整. 例如, wp 将设置控件的宽度等于之前的控件, 而 wp-50 则设置宽度为之前的控件宽度减去 50 像素.

X n, Y n: X-坐标, Y-坐标(where n is any number in pixels). 例如, 指定 x0 y0 将把控件放置到窗口工作区的左上角, 窗口工作区是在标题栏和菜单栏(如果有) 下面的区域.

X+n, Y+n (其中 n 可以为任意数字, 单位为像素): 可以包括一个可选的加号, 以相对于前一个添加的控件的右边缘或底边缘(分别) 定位一个控件. 例如, 指定 y+10 将把控件放置在前一个控件底部下面 10 个像素的位置, 而不使用标准的填充间距. 同样地, 指定 x+10 将把控件放置在前一个控件右边缘的右边 10 个像素的位置. 由于负数如 x-10 表示绝对的位置, 因此要使用负的位置偏移, 需要在前面加上一个加号. 例如: x+-10.

对于 X+ 和 Y+, 可以用字母 M 来代替窗口的当前边距. 例如, x+m 使用前一个控件的右边缘位置加上标准填充间隔. xp y+m 将控件放置于前一个之下, 而单独指定一个相对的 X 坐标(使用 XP 或 X+), 相当于默认情况下隐式的 yp.

XP±n, YP±n (其中 n 可以为任意数字, 单位为像素) 可以用来指定控件相对于前一个控件左上角的位置, 此选项常用于 GroupBox 中的封装控件.

XM±n and YM±n (其中 n 可以为任意数字, 单位为像素)可以用来将一个控件分别定位在窗口的最左边和最上面的边距, 并可选带有一个正/负号来调整.

XS±n and YS±n (其中 n 可以为任意数字, 单位为像素): 这些与 XM 和 YM 类似, 只是它们是相对于前一个选项中带有 Section 单词的控件所保存的坐标(窗口的第一个控件总是开始一个新列, 即使这个单词没有在其选项中指定). 例如:

MyGui := Gui()
MyGui.Add("Edit", "w600")  ; 在窗口的顶部添加一个非常宽的编辑控件.
MyGui.Add("Text", "Section", "First Name:")  ; 保存此控件位置并定义一个新控件段.
MyGui.Add("Text",, "Last Name:")
MyGui.Add("Edit", "ys")  ; 在此控件段中开始一个新列.
MyGui.Add("Edit")
MyGui.Show()

XS 和 YS 后面可以跟着一个加号/减号和一个数字. 并且, 还可以在控件的选项中同时指定单词 Section 和 XS/YS; 这样可以让当前控件使用之前的控件段, 但为后续控件定义一个新段.

省略 X, Y 的其中一个或同时省略, 有助于 GUI 布局自动调整, 以适应将来可能对控件大小或字体所做的任何更改. 相比之下, 为每个控件指定绝对位置可能需要手动移动正在放大或缩小的控件下面和/或右侧的所有控件的位置.

如果 X 和 Y 都被省略, 控件将使用标准填充距离(当前边距) 被放置在前一个控件的下面. 连续的 Text 或 Link 控件被赋予额外的垂直填充, 因此在 Edit, DDL 或类似尺寸的控件列后来被添加到它们的右边的情况下, 它们通常会更好地对齐. 要只使用标准的垂直边距, 请指定 y+m 或任何 X 值.

如果只省略了一个组件, 它的默认值取决于使用哪个选项来指定其他组件:

指定了 X | Y 的默认值
Xn 或 XM | 在所有之前控件的下方(最大 Y 范围加边距).
XS | 在最近一次使用 Section 选项后的所有之前控件的下方.
X+n 或 XP+非零值 | 等同于前一个控件的顶部边缘(YP).
XP 或 XP+0 | 前一个控件的下方(底部边缘加上边距).
指定了 Y | X 的默认值
Yn 或 YM | 在所有之前控件的右边(最大 X 范围加边距).
YS | 自最近一次使用 Section 选项以来, 所有先前控件的右边.
Y+n 或 YP+非零值 | 等同于前一个控件的左边缘(XP).
YP or YP+0 | 前一个控件的右边(右边缘加上边距).

存储和响应用户的输入

V: 设置控件的名称. 在字母 V 后指定一个名称, V 不包含在名称中. 例如, 指定 vMyEdit 会将控件命名为 "MyEdit".

Events: 事件处理程序(如当用户点击或更改控件时自动调用的函数) 不能在控件的 Options 中进行设置. 而是, 使用 OnEvent 可以为每个感兴趣的事件注册一个回调函数或方法.

控件的常用样式和选项

注意: 选项前的符号省略时, 默认为加号; 例如, Wrap 等同于 +Wrap. 相反地, -Wrap 将去除自动换行属性.

AltSubmit: 使用替代的提交方法. 对于 DropDownList, ComboBox, ListBox 和 Tab, 会让 Gui.Submit 保存选择项目的位置而不是其文本. 如果没有选择项目, 则对于 ComboBox 命令保存选项项目的位置而不是其文本. 如果没有选择项目, 则对于 ComboBox 会保存其编辑区域的文本.

C: 文本颜色(对按钮和状态栏控件无效). 指定字母 C 后面紧跟着颜色名称(请参阅颜色图表) 或 RGB 值(0x 前缀可以省略). 例如: cRed, cFF2211, c0xFF2211, cDefault.

Disabled: 让可输入型控件变为灰色禁用状态, 这样可以防止取得焦点或用户改变其内容. 以后可以使用 GuiControl.Enabled 来启用控件. 注意: 要让编辑控件为只读状态, 请指定字符串 ReadOnly 代替. 并且, 还可以在单词 Disabled 后紧跟着 0 或 1 来表示控件的初始状态(0 为启用而 1 为禁用). 换句话说, Disabled 和 "Disabled" VarContainingOne 是一样的.

Hidden: 让控件初始为隐藏状态. 以后可以使用 GuiControl.Visible 来让它显示. 可以在单词 Hidden 后跟着 0 或 1 来表示初始状态(0 为可见而 1 为隐藏). 换句话说, Hidden 和 "Hidden" VarContainingOne 是一样的.

Left: 在控件的可用宽度内左对齐控件的文本. 该选项会影响以下控件: Text, Edit, Button, CheckBox, Radio, UpDown, Slider, Tab, Tab2, GroupBox, DateTime.

Right: 在控件的可用宽度内右对齐控件的文本. 对于复选框和单选按钮, 此选项也同时把框放置在控件的右边而不是左边. 该选项会影响以下控件: Text, Edit, Button, CheckBox, Radio, UpDown, Slider, Tab, Tab2, GroupBox, DateTime, Link.

Center: 在控件的可用宽度内居中对齐控件的文本. 该选项会影响以下控件: Text, Edit, Button, CheckBox, Radio, Slider, GroupBox.

Section: 定义一个新的控件段并保存当前控件的位置, 以便以后使用上面描述的 XS 和 YS 定位选项.

Tabstop: 使用 -Tabstop(负 Tabstop) 可以让用户按 Tab 导航时跳过输入型控件.

Wrap: 让控件的文本自动换行. 因为几乎所有类型的控件初始状态都启用了自动换行, 所以需要通过 -Wrap 禁用它.

VScroll: 当控件支持时为其提供一个垂直滚动条.

HScroll: 当控件支持时为其提供一个水平滚动条. 这个段落的剩余部分仅适用于 ListBox. 水平滚动宽度默认为 ListBox 宽度的 3 倍. 要使用其他的滚动宽度, 请在单词 HScroll 后紧跟着一个数字表示. 例如, HScroll500 将在 ListBox 中使用 500 像素的滚动栏宽度. 但是, 如果指定的滚动宽度小于 ListBox 的宽度, 则不显示滚动条(不过在这种含有 HScroll 的情况下, 可以在之后通过 MyScrollBar.Opt("+HScroll500"), 来添加水平滚动条, 否则是无法添加的).

控件的不常用选项和样式

BackgroundTrans: 使用透明的背景, 允许任何位于 Text, Picture 或 GroupBox 后面的控件显示出来. 例如, 在 Picture 控件上显示一个透明背景的 Text 可以让文字看起来就像图片的一部分. 以后可以使用 GuiCtrl.Opt("+Background") 移除此选项. 有关透明图像的更多信息, 请参阅 Picture 控件的 AltSubmit 部分. 已知限制: 对包含了 ListView 的 Tab 控件内的其他控件, BackgroundTrans 可能无法正确应用. 如果控件类型不支持这个选项, 则抛出错误.

Background Color: 更改控件的背景色. 用颜色名称(请参阅颜色图表) 或 RGB 值(0x 前缀可以省略) 替换 Color. 例如: BackgroundSilver, BackgroundFFDD99. 如果不使用这个选项, 或 +Background 不带后缀使用, Text, Picture, GroupBox, CheckBox, Radio, Slider, Tab 或 Link 控件使用 Gui.BackColor 设置的背景色(如果没有设置或其他控件类型, 则为系统默认的背景色). 指定 BackgroundDefault 或 -Background 会应用系统的默认背景色. 例如, 控件可以通过 LV.Opt("+BackgroundDefault") 恢复到系统的默认颜色. 如果控件类型不支持这个选项, 则抛出错误.

Border: 为控件增加一个细边框. 对于大多数控件不需要使用此选项, 因为它们已经含有特定于类型的边框. 添加边框到 现有 控件时, 可能需要给控件的宽度和高度增加 1 个像素.

Redraw: 当与 GuiControl.Opt 一起使用时, 该选项通过向控件发送 WM_SETREDRAW 消息来启用或禁用控件的重绘(可视化更新). 有关详情, 请参阅 Redraw.

Theme: 使用此选项可以让新建的控件忽略窗口当前的主题设置. 它对于现有控件没有效果; 不过, 这种情况可能在将来的版本中改变. 请参阅 GUI 的 +/-Theme 选项了解详情.

(未命名样式): 在十进制或十六进制的样式编号前加上加号或减号表示添加或删除此样式. 如果省略了符号, 则默认为加号.

(未命名扩展样式): 在字母 E 和十进制或十六进制的扩展样式编号前加上加号或减号表示添加或删除此扩展样式. 如果省略了符号, 则默认为加号. 例如, E0x200 表示添加 WS_EX_CLIENTEDGE 样式, 它可以为图片和其他控件增加一个下沉的边框样式. 这里没有列出其他的扩展样式编号(因为它们极少使用), 有关完整列表, 前参阅 Extended Window Styles | Microsoft Docs.

Text
根据指定的控件类型, 可以是字符串, 数字或数组.

返回值

类型: Object

此方法返回一个 GuiControl 对象.

Destroy

移除窗口及其所有控件, 并释放其占用的内存和系统资源.

MyGui.Destroy()

如果没有使用 MyGui.Destroy(), 那么当 Gui 对象被删除时, 窗口会被自动销毁(详见通用备注). 当脚本退出时, 所有的 GUI 窗口都会被自动销毁.

Flash

闪烁任务栏中的窗口按钮.

MyGui.Flash(Blink)

参数

Blink

类型: 布尔值

如果省略, 默认为 1(true)

如果为 true, 任务栏中的窗口按钮将闪烁. 这是通过反转窗口的标题栏和/或任务栏按钮(如果有的话) 的颜色来实现的.

如果为 false, 可恢复标题栏和任务栏按钮的原始颜色(但实际行为可能因操作系统版本而异).

在下面的例子中, 窗口将闪烁三次, 因为每对闪烁都会反转, 然后恢复其外观:

Loop 6
{
    MyGui.Flash()
    Sleep 500  ; 这个时间值十分敏感, 改变它可能引起异常.
}

GetClientPos

检索窗口客户端区域的位置和大小.

MyGui.GetClientPos(&X, &Y, &Width, &Height)

参数

&X, &Y

类型: VarRef

如果省略, 则不存储相应的值. 否则, 指定对输出变量的引用, 以存储控件左上角的 X 和 Y 坐标(以像素为单位).

&Width, &Height

类型: VarRef

如果省略, 则不存储相应的值. 否则, 指定对输出变量的引用, 以存储控件的宽度和高度.

Width 是客户端左右两侧的水平距离, 而 height 是上下两侧的垂直距离(以像素为单位).

备注

客户端区域是窗口中可以包含控件的部分. 它不包括窗口的标题栏, 菜单(如果它有标准的) 和边框. 与 Gui.GetPos 返回的值相比, 客户端区域的位置和大小对操作系统版本和主题的依赖性较小.

与 WinGetClientPos, 不同, 该方法将 DPI 缩放应用于 Width 和 Height(除非使用了 -DPIScale 选项).

GetPos

检索窗口的位置和大小.

MyGui.GetPos(&X, &Y, &Width, &Height)

参数

&X, &Y

类型: VarRef

如果省略, 则不存储相应的值. 否则, 指定对输出变量的引用, 以存储窗口左上角在屏幕坐标中的 X 和 Y 坐标(以像素为单位).

&Width, &Height

类型: VarRef

如果省略, 则不存储相应的值. 否则, 指定对输出变量的引用, 以存储窗口的宽度和高度.

Width 是窗口左右两侧的水平距离, 而 height 是上下两侧的垂直距离(以像素为单位).

备注

由于此方法返回的坐标包括窗口的标题栏, 菜单和边框, 因此它们可能取决于操作系统版本和主题. 为了在不同的系统中获得更一致的值, 可以考虑使用 Gui.GetClientPos 代替.

与 WinGetPos 不同, 该方法将 DPI 缩放应用于 Width 和 Height(除非使用了 -DPIScale 选项).

Hide

隐藏窗口.

MyGui.Hide()

Maximize

取消隐藏窗口(如有必要) 并将其最大化.

MyGui.Maximize()

Minimize

取消隐藏窗口(如有必要) 并将其最小化.

MyGui.Minimize()

Move

移动和/或调整窗口的大小

MyGui.Move(X, Y, Width, Height)

Parameters

X, Y

类型: 整数

如果省略其中任何一个, 则不会更改在该维度中的位置. 否则, 指定窗口新位置左上角在屏幕坐标中的 X 和 Y 坐标.

Width, Height

类型: 整数

如果省略其中任何一个, 则不会更改该维度中的大小. 否则, 指定窗口的新宽度和高度(以像素为单位).

备注

与 WinMove 不同, 该方法将 DPI 缩放应用于 Width 和 Height(除非使用了 -DPIScale 选项).

示例

MyGui.Move(10, 20, 200, 100)
MyGui.Move(VarX+10, VarY+5, VarW*2, VarH*1.5)

; 左右两边扩大 10 个像素.
MyGui.GetPos(&x,, &w)
MyGui.Move(x-10,, w+20)

OnEvent

注册一个函数或方法, 当给定的事件被触发时调用.

MyGui.OnEvent(EventName, Callback , AddRemove)

有关详情, 请参阅 OnEvent.

Opt

为窗口的外观和行为设置各种选项和样式.

MyGui.Opt(Options)

参数

Options

类型: 字符串

以下零个或多个选项和样式, 每个选项和样式之间用一个或多个空格或制表符分隔.

处于性能原因, 最好在一行中设置所有选项, 并在创建窗口之前(即在使用 MyGui.Add 等其他方法之前) 进行设置.

这个参数的效果是累加的; 也就是说, 它只改变那些明确指定的设置, 而其他所有选项则保持不变.

在选项前指定加号表示增加此选项, 而减号表示移除它. 例如: MyGui.Opt("+Resize -MaximizeBox").

AlwaysOnTop: 使窗口保持在所有其他窗口的顶部, 这与 WinSetAlwaysOnTop 的效果相同.

Border: 为窗口增加细边框. 此选项不常用.

Caption(默认具有此选项): 为窗口增加标题栏和粗边框. 当从将使用 WinSetTransColor 的窗口中移除标题时, 只有在设置 TransColor 后才能移除.

Disabled: 禁用窗口, 阻止用户和窗口中的控件交互. 此选项常用于含有子窗口的窗口(请参阅 Owner).

DPIScale: 使用 MyGui.Opt("-DPIScale") 禁用 DPI 缩放, 它默认是启用的. 如果启用了 DPI 缩放, 传递给或从 Gui 和 GuiControl 的方法/属性获取的坐标和大小会根据屏幕 DPI 自动缩放. 例如, 对于 144(150 %) 的 DPI, MyGui.Show("w100") 会让 Gui 宽度为 150(100 * 1.5) 像素, 如果通过鼠标或 WinMove 将窗口大小调整为 200 像素宽, 会导致 MyGui.GetClientPos(,,&W) 设置 W 为 133(200 // 1.5). A_ScreenDPI 包含了系统当前 DPI.

DPI 缩放只适用于 Gui 和 GuiControl 方法/属性, 所以直接来自其他来源的坐标, 如 ControlGetPos 或 WinGetPos 将无法使用. 有很多方法可以处理这个问题:

  • 尽可能避免使用硬编码坐标. 例如, 使用 XP, XS, XM 和 X+M 选项来定位控件, 并以文本的行数而不是像素来指定高度.
  • 根据需要, 启用(Gui.Opt("+DPIScale")) 和禁用(Gui.Opt("-DPIScale")) 缩放. 更改这个设置并不会影响已经设置过的坐标或大小.
  • 手动缩放坐标. 例如, x*(A_ScreenDPI/96) 将 x 从逻辑/GUI 坐标转换为物理/非 GUI 坐标.

LastFound: 设置窗口为上次找到的窗口(对于 GUI 线程这是不必要的, 因为它自动设置了), 这样允许类似 WinGetStyle 和 WinSetTransparent 这样的函数对此窗口进行操作, 即使它当前为隐藏状态(即不需要使用 DetectHiddenWindows). 需要在显示窗口之前改变其属性时, 这是非常有用的. 例如:

MyGui.Opt("+LastFound")
WinSetTransColor(CustomColor " 150", MyGui)
MyGui.Show()

MaximizeBox: 启用标题栏上的最大化按钮. 下面的 Resize 也含有此效果.

MinimizeBox (默认含有此选项): 启用标题栏上的最小化按钮.

MinSize 和 MaxSize: 限定窗口的最小尺寸和最大尺寸, 例如当用户拖动窗口边框改变其大小的时候. 指定 +MinSize 和/或 +MaxSize(如没有后缀) 来使用窗口当前尺寸作为限制大小(如果没有窗口当前尺寸, 则使用首次 MyGui.Show 时显示的大小). 还可以在后面加上宽度, 跟着 X 和高度; 例如: Gui.Opt("+Resize +MinSize640x480"). 它们指定了以像素为单位的窗口工作区(不包括边框, 标题栏和菜单栏). 指定每个数字为十进制, 而不是十六进制.

可以省略高度或宽度, 使其保持不变(例如 +MinSize640x 或 +MinSizex480). 此外, 可以多次指定 Min/MaxSize 以便在一个维度上使用窗口的当前尺寸, 在另一个维度上使用显式尺寸. 例如, +MinSize +MinSize640x 表示最小高度限制为窗口当前的大小, 而最小宽度限制为 640.

如果从没有使用 MinSize 和 MaxSize, 则使用操作系统的默认值(同样地, 可以使用 MyGui.Opt("-MinSize -MaxSize") 恢复为默认值). 注意: 窗口必须有 +Resize, 以允许用户调整大小.

OwnDialogs: MyGui.Opt("+OwnDialogs") 应该在每个线程中指定(如 Button 控件的事件处理函数) 随后显示的 MsgBox, InputBox, FileSelect 和 DirSelect 对话框应该由窗口拥有. 这类对话框成为模式对话框, 这意味着用户不能与 GUI 窗口进行交互, 直到解除对话框. 相反, ToolTip 窗口即使有拥有者, 也不会成为模式的; 它们只是会一直停留在其拥有者之上. 在这两种情况下, 任何拥有的对话框或窗口都会在其 GUI 窗口被销毁时自动销毁.

一般情况下打开这个设置后不需要再切换到关闭, 因为它不影响其他线程. 但是, 如果一个线程需要显示从属和非从属对话框, 则可以使用 MyGui.Opt("-OwnDialogs") 关闭此设置.

Owner: 使用 +Owner 可以让当前窗口从属于另一个窗口. 从属的窗口默认不显示在任务栏, 并且它总是显示在其父窗口的上面. 只要父窗口是由同一个脚本(即 拥有同样的进程 ID) 创建的, 当其父窗口销毁时, 它也被自动销毁. +Owner 可以在父窗口创建之前或之后使用. 两种方法可以使用 +Owner, 如下所示:

MyGui.Opt("+Owner" OtherGui.Hwnd)  ; 让 GUI 成为 OtherGui 的子窗口.
MyGui.Opt("+Owner")  ; 让 GUI 成为脚本主窗口的子窗口, 这样可以阻止其任务栏按钮的显示.

+Owner 后面可以紧跟着任何顶级窗口的 HWND.

在某个从属窗口显示时要防止用户与其父窗口交互, 请使用 MyGui.Opt("+Disabled"). 禁用父窗口. 之后(当子窗口取消或销毁时), 通过 MyGui.Opt("-Disabled"). 来重新启用父窗口. 在取消或销毁子窗口前这样做可以让父窗口自动恢复有效.

Parent: 使用 +Parent 后面紧跟着任何窗口或控件的 HWND, 将其作为这个窗口的父窗口. 要恢复 Gui 为顶级窗口, 请使用 -Parent. 在窗口创建后此选项也有效. 已知限制:

  • 如果新的父窗口总是在顶部, 而子窗口不是, Running with UI access 阻止 +Parent 选项在现有窗口上工作.
  • 如果父窗口是外部的, +Parent 选项可能在 GUI 创建过程中失败, 但可能在 GUI 创建后工作. 这是由于样式应用方式的不同.

Resize: 此选项允许用户重新调整窗口的大小并启用标题栏上的最大化按钮. 要禁用最大化按钮, 请指定 +Resize -MaximizeBox.

SysMenu(默认含有此选项): 指定 -SysMenu(负 SysMenu) 可以删除点击窗口左上角时弹出的系统菜单和图标. 同时也删除标题栏上的最小化, 最大化和关闭按钮.

Theme: 通过指定 -Theme, 可以让随后在窗口中创建的所有控件具有经典主题的外观. 之后要创建其他使用当前主题的控件时, 请使用 +Theme 把设置切换回来. 注意: 如果经典主题有效, 这个选项就没有效果. 最后, 每个控件在创建时, 可以通过在其选项中指定 +Theme 或 -Theme 来改变该设置.

ToolWindow: 让窗口显示细标题栏, 同时去除任务栏按钮. 无论是否存在 WS_MAXIMIZEBOX 和 WS_MINIMIZEBOX 样式, 这总是隐藏了最大化和最小化按钮.

(未命名样式): 在十进制或十六进制的样式编号前加上加号或减号表示添加或删除此样式.

(未命名扩展样式): 在字母 E 和十进制或十六进制的扩展样式编号前加上加号或减号表示添加或删除此扩展样式. 例如, +E0x40000 表示添加 WS_EX_APPWINDOW 样式, 此样式让窗口显示任务栏按钮. 这里没有列出其他的扩展样式编号(因为它们极少使用), 有关完整列表, 请参阅 Extended Window Styles | Microsoft Docs.

Restore

显示窗口(如有必要) 并取消最小化或最大化.

MyGui.Restore()

SetFont

为在此处之后创建的控件设置字体字型, 大小, 样式和/或颜色.

MyGui.SetFont(Options, FontName)

参数

Options

类型: 字符串

零个或多个选项. 每个选项要么是一个字母后面紧跟着一个值, 要么是一个单词. 若要指定多个选项, 请在每个选项之间使用空格. 例如: cBlue s12 bold.

支持以下单词: bold, italic, strike, underline 和 norm. Norm 将字体恢复到标准的粗细, 并关闭斜体, 删除和下划线(但保留现有的颜色和大小). 可以使用 norm 去除所有属性然后有选择的设置其他属性. 例如, 指定 norm italic 将设置字体为标准然后增加斜体属性.

C: 颜色名称(请参阅颜色图表) 或 RGB 值 -- 或指定单词 Default 来恢复到系统默认颜色(大多数系统的默认颜色为黑色). 例如: cRed, cFFFFAA, cDefault. 注意: Button 和状态栏不遵循自定义颜色. 此外, 可以通过包含 C 选项创建带有字体颜色的特殊控件不会受到当前选项的影响. 例如: MyGui.Add("Text", "cRed", "My Text").

S: 尺寸(单位为磅). 例如: s12(指定十进制, 而不是十六进制)

W: 粗细, 这是介于 1 和 1000 之间的数字(400 为标准大小而 700 为粗体). 例如: w600(指定十进制, 而不是十六进制)

Q: 文本渲染质量. 例如: q3. Q 后应跟着下表中的一个数字:

数字 | Windows 常量 | 描述
0 | DEFAULT_QUALITY | 字体的外观并不重要.
1 | DRAFT_QUALITY | 字体的外观不如使用 PROOF_QUALITY 值时重要.
2 | PROOF_QUALITY | 字体的字符质量比逻辑字体属性的精确匹配更重要.
3 | NONANTIALIASED_QUALITY | 字体从不进行抗锯齿处理, 即不进行字体平滑处理.
4 | ANTIALIASED_QUALITY | 如果字体支持抗锯齿, 并且字体大小不是太小或太大, 那么字体是抗锯齿或平滑的.
5 | CLEARTYPE_QUALITY | 如果设置, 则使用 ClearType 抗锯齿方法渲染文本(在可能的情况下).

关于这些值含义的更多细节, 请参阅 Microsoft Docs: CreateFont.

由于默认设置通常是最好的品质, 所以这个功能往往用于在特殊情况时禁用抗锯齿效果, 这样可以让文本更清晰.

FontName

类型: 字符串

FontName 可以是任意字体的名称, 例如字体表的其中一个. 如果省略 FontName 或此字体在系统中不存在, 则使用之前的字体字型(如果没有, 则使用系统默认的 GUI 字型). 即使某些系统缺少首选字体, 这种特性也可以让窗口在多个系统上具有类似的字体. 例如, 按顺序执行下列命令, 则 Verdana 字体优先于 Arial, 而 Arial 字体优先于 MS Sans Serif:

MyGui.SetFont(, "MS Sans Serif")
MyGui.SetFont(, "Arial")
MyGui.SetFont(, "Verdana")  ; 优选字体.

备注

省略两个参数可以让字体恢复为系统默认的 GUI 字型, 大小和颜色. 否则, 任何未指定的字体属性将从之前的字体中复制.

相关提示, 操作系统提供了标准的对话框, 提示用户选取字体, 颜色或图标. 这些对话框可以通过 DllCall 与 comdlg32\ChooseFont, comdlg32\ChooseColor 或 shell32\PickIconDlg 的组合来显示. 请在论坛中搜索示例.

Show

默认情况下, 这将使窗口可见, 取消最小化(如果需要) 并激活它.

MyGui.Show(Options)

参数

Options

类型: 字符串

省略后面的 X, Y, W 和 H 选项则让窗口保持原来的大小和位置. 如果之前没有设置过位置, 则在后面提到的 X 和/或 Y 选项没有指明的坐标上窗口将自动居中. 如果之前没有设置过大小, 则窗口会根据它所包含控件的大小和位置自动调整大小.

在 Options 中可以包含零个或多个下列字符串(指定每一个数字为十进制, 而不是十六进制):

W n: 指定 n 为窗口工作区的宽度(单位为像素), 窗口工作区指除了窗口边框, 标题栏和菜单栏的区域.

H n: 指定 n 为窗口工作区的高度, 单位为像素.

X n: 指定 n 为窗口在屏幕中的 X-坐标, 单位为像素. 0 表示屏幕最左边首列可见像素的位置.

Y n: 指定 n 为窗口在屏幕中的 Y-坐标, 单位为像素. 0 表示屏幕最左边首列可见像素的位置.

Center: 让窗口在屏幕的水平和垂直方向上居中.

xCenter: 让窗口在屏幕的水平方向上居中. 例如: MyGui.Show("xCenter y0").

yCenter: 让窗口在屏幕的垂直方向上居中.

AutoSize: 根据窗口当前包含的可见控件调整窗口的大小. 这常在添加新控件, 调整现有控件的大小或隐藏/显示现有控件后用来调整窗口的大小. 例如: MyGui.Show("AutoSize Center").

还可能存在以下情况之一:

Minimize: 最小化当前窗口并激活其下方的窗口.

Maximize: 最大化并激活窗口.

Restore: 必要时, 将窗口取消最小化或最大化(还原窗口). 如有必要, 还将显示并激活窗口.

NoActivate: 当窗口处于最小化或最大化状态时, 还原窗口. 窗口显示但不进行激活.

NA: 显示窗口但不进行激活. 如果窗口处于最小化状态, 那么它仍保持这种状态, 但可能提升它的 z 顺序(这是在 alt-tab 选择器中看到的顺序). 如果窗口之前是隐藏的, 则此参数可能会让它显示在当前仍处于活动状态的窗口上面.

Hide: 隐藏窗口并激活其下方的窗口. 这与 MyGui.Hide 的功能相同, 只是它允许移动或调整隐藏窗口的大小, 而不显示它. 例如: MyGui.Show("Hide x55 y66 w300 h200").

Submit

从命名的控件中收集值, 并将它们组合成一个对象. 可选择隐藏窗口.

NamedCtrlValues := MyGui.Submit(Hide)

参数

Hide

类型: 布尔值

如果省略, 则默认为 true.

如果为 true, 则窗口将被隐藏.

如果为 false, 则窗口不会被隐藏.

返回值

类型: Object

此方法返回一个对象, 其中每个命名控件包含一个自己的属性, 如 NamedCtrlValues.%GuiCtrl.Name% := GuiCtrl.Value, 但下列例外情况除外. 只有具有输入能力的控件支持 GuiControl.Value, 并被赋予名称的控件才会被包含在内. 使用 NamedCtrlValues.NameOfControl 来检索一个单独的值或 OwnProps 来枚举所有的值.

对于 DropDownList, ComboBox, ListBox 和 Tab, 如果控件 没有 AltSubmit 选项, 或者如果 ComboBox 的文本与列表项不匹配, 则存储所选项目/Tab 的文本而不是其位置编号. 否则, 将存储 Value(项目的位置编号).

如果单选组中只有一个 Radio 按钮有名称, 则 Submit 将存储当前选中的按钮的编号, 而不是控件的 Value. 1 是第一个单选按钮(根据原来的创建顺序), 2 是第二个, 以此类推. 如果没有选择按钮, 则存储 0.

因为它们不具备输入功能, 排除以下控件: Text, Pic, GroupBox, Button, Progress, Link, StatusBar.

也不包括: ListView, TreeView, ActiveX, Custom.

__Enum

枚举窗口的控件.

For Ctrl in MyGui
For Hwnd, Ctrl in MyGui

返回一个新的枚举器. 这个方法通常不被直接调用. 取而代之的是, Gui 对象被直接传递给 for-loop, 其调用 __Enum 一次, 然后在循环的每次迭代中调用枚举器一次. 每次调用枚举数都会返回下一个控件. For-loop 的变量对应于枚举数的参数, 它们是:

Hwnd

类型: 整数

控件的 HWND. 这只存在于双参数模式中.

Ctrl

类型: Object

控件的 GuiControl 对象.

例如:

For Hwnd, GuiCtrlObj in MyGui
    MsgBox "Control #" A_Index " is " GuiCtrlObj.ClassNN

__New

构造一个新的 Gui 实例.

MyGui.__New(Options, Title, EventObj)

Gui 子类可以覆盖 __New 并调用 super.__New(Options, Title, this) 来处理它自己的事件. 在这种情况下, 主窗口的事件(如关闭) 不会传递一个显式的 Gui 参数, 因为 this 已经包含了对 Gui 的引用.

为了调用事件处理程序, Gui 会保留对 EventObj 的引用, 并在窗口销毁时释放该引用. 如果 EventObj 本身包含对 Gui 的引用, 这通常会创建一个循环引用, 从而阻止 Gui 被自动销毁. 不过, 如果 EventObj 本身就是 Gui, 则会出现一个例外, 以避免在这种情况下出现循环引用.

如果窗口已经被构造或销毁, 则抛出异常.

属性

BackColor

检索或设置窗口的背景色.

CurrentColor := MyGui.BackColor
MyGui.BackColor := NewColor
是此属性之前设置的当前颜色的 6-位 RGB 值, 如果使用的是默认颜色, 则是一个空字符串.

NewColor 是 16 种主要 HTML 颜色名称之一, 十六进制 RGB 颜色值(0x 前缀可以省略), 纯数字 RGB 颜色值, 或者对于默认颜色指定单词 Default(或空字符串). 例如: "Silver", "FFFFAA", 0xFFFFAA, "Default", "".

默认情况下, 窗口的背景颜色为系统按钮的颜色.

菜单栏及其子菜单的颜色可以这样改变: MyMenuBar.SetColor("White").

要让窗口的背景透明, 请使用 WinSetTransColor. 然而, 如果在进行这样的操作前没有使用 Gui.BackColor 为窗口设置自定义的颜色, 那么按钮也将变成透明的. 要避免此问题, 应首先为窗口设置自定义的颜色, 然后让此颜色透明. 例如:

MyGui.BackColor := "EEAA99"
WinSetTransColor("EEAA99", MyGui)

此外, 如果要移除背景透明的窗口的边框和标题栏, 使用下面的方法: MyGui.Opt("-Caption")

为了阐明上面的情况, 请参阅此页面底部的屏幕显示(OSD) 的例子.

FocusedCtrl

检索窗口的焦点控件的 GuiControl 对象.

GuiCtrlObj := MyGui.FocusedCtrl

注意: 为了达到效果, 一般不能将窗口最小化或隐藏.

Hwnd

检索窗口的窗口句柄(HWND).

CurrentHwnd := MyGui.Hwnd

GUI 的 HWND, 通常与 PostMessage, SendMessage 和 DllCall 一起使用. 它也可以直接用于 WinTitle 参数中.

MarginX

检索或设置边和后续创建的控件之间的水平边距大小.

CurrentValue := MyGui.MarginX
MyGui.MarginX := NewValue

CurrentValue 是当前水平边距的像素数.

NewValue 是在自动定位任何没有明确 X 坐标的控件时, 在窗口左右两边留出的空间像素数. 同时, 边距也被用来确定自动定位的控件之间的水平距离. 最后, 在第一次使用 MyGui.Show 计算窗口的大小时(当没有指定明确的大小时), 会考虑到边距.

如果脚本没有设置, 首次调用 Gui.Add 或 Gui.Show 时或 Gui.MarginX 或 Gui.MarginY 检索时(以先出现的为准), MarginX 默认为当前字体高度的 1.25 倍.

MarginY

检索或设置边和后续创建的控件之间的垂直边距大小.

CurrentValue := MyGui.MarginY
MyGui.MarginY := NewValue

CurrentValue 是当前垂直边距的像素数.

NewValue 是在自动定位任何没有明确 Y 坐标的控件时, 在窗口的顶部和底部留出的空间像素数. 同时, 边距也被用来确定自动定位的控件之间的垂直距离. 最后, 在第一次使用 MyGui.Show 计算窗口的大小时(当没有指定明确的大小时), 会考虑到边距.

如果脚本没有设置, 首次调用 Gui.Add 或 Gui.Show 时或 Gui.MarginX 或 Gui.MarginY 检索时(以先出现的为准), MarginY 默认为当前字体高度的 0.75 倍.

MenuBar

检索或设置窗口的菜单栏.

CurrentBar := MyGui.MenuBar
MyGui.MenuBar := NewBar

CurrentBar 和 NewBar 是由 MenuBar() 创建的 MenuBar 对象. 例如:

FileMenu := Menu()
FileMenu.Add("&Open`tCtrl+O", (*) => FileSelect())  ; 关于 Ctrl+O 请参阅后面的备注.
FileMenu.Add("E&xit", (*) => ExitApp())
HelpMenu := Menu()
HelpMenu.Add("&About", (*) => MsgBox("Not implemented"))
Menus := Menu()
Menus.Add("&File", FileMenu)  ; 附加上面的两个子菜单.
Menus.Add("&Help", HelpMenu)
MyGui := Gui()
MyGui.MenuBar := Menus
MyGui.Show("w300 h200")

注意在上面的首行中 &Open 后面跟着 Ctrl+O(它们之间有一个 tab). 这表示用户可以按下快捷键代替选择菜单项来执行操作. 如果这样的快捷键中只使用了标准的修饰键名称 Ctrl, Alt 和 Shift, 那么它会被自动注册为这个 GUI 的 键盘快捷键. 不含修饰键的单字母快捷键是区分大小写的, 且可以使用不常见的方法触发, 例如 IME 或 Alt+NNNN.

如果特殊的按键组合没有自动生效, 请使用上下文相关热键. 然而, 这样的热键一般不能使用 Send 触发, 并且比起标准的键盘快捷键它们更可能和其他脚本产生冲突.

要移除窗口当前的菜单栏, 请使用 MyGui.MenuBar := ""(即, 赋值一个空字符串).

Name

检索或设置窗口的自定义名称.

CurrentName := MyGui.Name
MyGui.Name := NewName

Title

检索或设置窗口的标题.

CurrentTitle := MyGui.Title
MyGui.Title := NewTitle

__Item

检索与指定名称, 文本, ClassNN 或 HWND 关联的 GuiControl 对象.

GuiCtrlObj := MyGui[Name]
GuiCtrlObj := MyGui.__Item[Name]

键盘导航

使用 Tab 可以在 GUI 窗口中导航, 它会移动键盘焦点到下一个可输入型控件中(跳过移除了 Tabstop 样式的控件). 导航的顺序由控件添加的顺序决定. 当首次显示一个窗口时, 键盘焦点将在首个具有 Tabstop 样式(默认情况下大多数类型的控件都具有) 的可输入型控件上, 除非该控件是一个 Button, 并且有一个默认按钮, 在这种情况下, 后者会具有焦点.

可以在某些控件的名称中包含和符号(&) 来创建此控件的键盘快捷键, 在控件名称中的快捷键字母会加上下划线显示(取决于系统设置). 用户可以通过按下 Alt 和相应的字符来触发这样的快捷键. 对于按钮, 复选框和单选按钮, 按下相应的快捷键等于点击了按钮. 对于 GroupBox 和 Text 控件, 按下相应的快捷键则移动键盘焦点到此控件后(不是指位置, 是创建顺序) 首个具有 tabstop 样式的可输入型控件中. 然而, 如果多个控件含有相同的快捷键, 则按下此快捷键会让键盘焦点在这些控件中交替.

要在上面提及类型的控件中显示一个原义的和符号, 请指定两个连续的和符号, 如此例所示: MyGui.Add("Button",, "Save && Exit").

窗口外观

对于其图标, GUI 窗口使用创建窗口时有效的托盘图标. 因此, 要想拥有不同的图标, 请在创建窗口前更改托盘图标. 例如: TraySetIcon("MyIcon.ico"). 也可以为一个窗口拥有一个不同于其小图标的大图标(大图标显示在 alt-tab 任务切换器中). 这可以通过 LoadPicture 和 SendMessage 来实现; 例如:

iconsize := 32  ; alt-tab 任务切换器中图标的理想尺寸在不同版本的系统中有所不同.
hIcon := LoadPicture("My Icon.ico", "Icon1 w" iconsize " h" iconsize, &imgtype)
MyGui := Gui()
SendMessage(0x80, 1, hIcon, MyGui)  ; 0x80 是 WM_SETICON; 1 表示 ICON_BIG(vs. 0 表示 ICON_SMALL).
MyGui.Show()

由于操作系统的限制, Checkbox, Radio button 和 GroupBox 控件中的文本不是使用默认颜色时将显示为经典主题外观.

相关主题: 窗口的边距.

备注

使用 GuiControl 对象对 GUI 窗口中的单个控件进行操作.

每个 GUI 窗口最多可以包含 11,000 个控件. 然而, 当控件数量超过 5000 时需要谨慎, 因为此时某些类型的控件可能让系统不稳定.

当 Gui 对象被删除时, GUI 窗口会自动销毁, 当它的引用计数达到零时, 就会发生这种情况. 然而, 这通常不会在窗口可见时发生, 因为 Show 会自动增加引用计数. 当窗口可见时, 用户可以与之交互并触发由脚本处理的事件. 当用户关闭窗口或窗口被 Hide 隐藏, Show 或 Submit, 这个额外的引用就会被释放.

为了保持 GUI 窗口的 "活力" 而不调用 Show 或保留对其 Gui 对象的引用, 脚本可以使用 ObjAddRef 增加对象的引用计数(在这种情况下, 当不再需要该窗口时, 必须调用 ObjRelease). 例如, 当使用一个隐藏的 GUI 窗口来接收消息时, 或者当窗口被 "外部" 的方法, 如 WinShow 显示时(由这个脚本或任何其他脚本), 就可以这样做.

如果脚本不是因为任何其他原因而持续运行, 它将在最后一个可见的 GUI 关闭后退出; 或者是在最后一个线程完成时退出, 或者是在没有线程运行时立即退出.

相关

GuiControl 对象, GuiFromHwnd, GuiCtrlFromHwnd, 控件类型, ListView, TreeView, Menu 对象, Control 函数, MsgBox, FileSelect, DirSelect

示例

创建弹窗.

MyGui := Gui(, "Title of Window")
MyGui.Opt("+AlwaysOnTop +Disabled -SysMenu +Owner")  ; +Owner 避免显示任务栏按钮.
MyGui.Add("Text",, "Some text to display.")
MyGui.Show("NoActivate")  ; NoActivate 让当前活动窗口继续保持活动状态.

创建一个要求输入姓名的简单输入框.

MyGui := Gui(, "Simple Input Example")
MyGui.Add("Text",, "First name:")
MyGui.Add("Text",, "Last name:")
MyGui.Add("Edit", "vFirstName ym")  ; ym 选项开始一个新的控件列.
MyGui.Add("Edit", "vLastName")
MyGui.Add("Button", "default", "OK").OnEvent("Click", ProcessUserInput)
MyGui.OnEvent("Close", ProcessUserInput)
MyGui.Show()

ProcessUserInput(*)
{
    Saved := MyGui.Submit()  ; 将命名控件的内容保存到一个对象中.
    MsgBox("You entered '" Saved.FirstName " " Saved.LastName "'.")
}

创建带有多个选项卡的选项卡控件, 每个选项卡包含不同的控件与之交互.

MyGui := Gui()
Tab := MyGui.Add("Tab3",, ["First Tab", "Second Tab", "Third Tab"])
MyGui.Add("CheckBox", "vMyCheckBox", "Sample checkbox")
Tab.UseTab(2)
MyGui.Add("Radio", "vMyRadio", "Sample radio1")
MyGui.Add("Radio",, "Sample radio2")
Tab.UseTab(3)
MyGui.Add("Edit", "vMyEdit r5")  ; r5 表示 5 行的高度.
Tab.UseTab()  ; 即后续添加的控件将不属于前面那个选项卡控件.
Btn := MyGui.Add("Button", "default xm", "OK")  ; xm 把它放置在左下角.
Btn.OnEvent("Click", ProcessUserInput)
MyGui.OnEvent("Close", ProcessUserInput)
MyGui.OnEvent("Escape", ProcessUserInput)
MyGui.Show()

ProcessUserInput(*)
{
    Saved := MyGui.Submit()  ; 将命名控件的内容保存到一个对象中.
    MsgBox("You entered:`n" Saved.MyCheckBox "`n" Saved.MyRadio "`n" Saved.MyEdit)
}

创建一个显示目录中的文件的列表框.

MyGui := Gui()
MyGui.Add("Text",, "Pick a file to launch from the list below.")
LB := MyGui.Add("ListBox", "w640 r10")
LB.OnEvent("DoubleClick", LaunchFile)
Loop Files, "C:\*.*"  ; 根据您的需要改变此文件夹和通配符模式.
    LB.Add([A_LoopFilePath])
MyGui.Add("Button", "Default", "OK").OnEvent("Click", LaunchFile)
MyGui.Show()

LaunchFile(*)
{
    if MsgBox("Would you like to launch the file or document below?`n`n" LB.Text,, 4) = "No"
        return
    ; 否则, 尝试运行此文件:
    try Run(LB.Text)
    if A_LastError
        MsgBox("Could not launch the specified file. Perhaps it is not associated with anything.")
}

当鼠标移动到特定的控件上时显示相关帮助(使用工具提示).

MyGui := Gui()
MyEdit := MyGui.Add("Edit")
; 在自定义属性中存储工具提示文本:
MyEdit.ToolTip := "This is a tooltip for the control whose name is MyEdit."
MyDDL := MyGui.Add("DropDownList",, ["Red", "Green", "Blue"])
MyDDL.ToolTip := "Choose a color from the drop-down list."
MyGui.Add("CheckBox",, "This control has no tooltip.")
MyGui.Show()
OnMessage(0x200, On_WM_MOUSEMOVE)

On_WM_MOUSEMOVE(wParam, lParam, msg, Hwnd)
{
    static PrevHwnd := 0
    if (Hwnd != PrevHwnd)
    {
        Text := "", ToolTip() ; 关闭之前的工具提示.
        CurrControl := GuiCtrlFromHwnd(Hwnd)
        if CurrControl
        {
            if !CurrControl.HasProp("ToolTip")
                return ; 此控件没有工具提示.
            Text := CurrControl.ToolTip
            SetTimer () => ToolTip(Text), -1000
            SetTimer () => ToolTip(), -4000 ; 移除工具提示.
        }
        PrevHwnd := Hwnd
    }
}

使用透明窗口进行屏幕显示(OSD).

MyGui := Gui()
MyGui.Opt("+AlwaysOnTop -Caption +ToolWindow")  ; +ToolWindow 避免显示任务栏按钮和 alt-tab 菜单项.
MyGui.BackColor := "EEAA99"  ; 可以是任何 RGB 颜色(下面会变成透明的).
MyGui.SetFont("s32")  ; 设置大字体(32 磅).
CoordText := MyGui.Add("Text", "cLime", "XXXXX YYYYY")  ; XX & YY 用来自动调整窗口大小.
; 让此颜色的所有像素透明且让文本显示为半透明(150):
WinSetTransColor(MyGui.BackColor " 150", MyGui)
SetTimer(UpdateOSD, 200)
UpdateOSD()  ; 立即进行第一次更新而不等待计时器.
MyGui.Show("x0 y400 NoActivate")  ; NoActivate 让当前活动窗口继续保持活动状态.

UpdateOSD(*)
{
    MouseGetPos &MouseX, &MouseY
    CoordText.Value := "X" MouseX ", Y" MouseY
}

在背景图像上移动的进度条.

MyGui := Gui()
MyGui.BackColor := "White"
MyGui.Add("Picture", "x0 y0 h350 w450", A_WinDir "\Web\Wallpaper\Windows\img0.jpg")
MyBtn := MyGui.Add("Button", "Default xp+20 yp+250", "Start the Bar Moving")
MyBtn.OnEvent("Click", MoveBar)
MyProgress := MyGui.Add("Progress", "w416")
MyText := MyGui.Add("Text", "wp")  ; wp 表示 "使用之前的宽度".
MyGui.Show()

MoveBar(*)
{
    Loop Files, A_WinDir "\*.*", "R"
    {
        if (A_Index > 100)
            break
        MyProgress.Value := A_Index
        MyText.Value := A_LoopFileName
        Sleep 50
    }
    MyText.Value := "Bar finished."
}

创建简单的图像查看器.

MyGui := Gui("+Resize")
MyBtn := MyGui.Add("Button", "default", "&Load New Image")
MyBtn.OnEvent("Click", LoadNewImage)
MyRadio := MyGui.Add("Radio", "ym+5 x+10 checked", "Load &actual size")
MyGui.Add("Radio", "ym+5 x+10", "Load to &fit screen")
MyPic := MyGui.Add("Pic", "xm")
MyGui.Show()

LoadNewImage(*)
{
    Image := FileSelect(,, "Select an image:", "Images (*.gif; *.jpg; *.bmp; *.png; *.tif; *.ico; *.cur; *.ani; *.exe; *.dll)")
    if Image = ""
        return
    if (MyRadio.Value)  ; 按实际大小显示图像.
    {
        Width := 0
        Height := 0
    }
    else ; 选择了第二个单选按钮: 按照屏幕的大小显示图像.
    {
        Width := A_ScreenWidth - 28  ; 减去的 28 是用来显示边框和内边缘的空间.
        Height := -1  ; "保持高宽比" 应该是最好的.
    }
    MyPic.Value := Format("*w{1} *h{2} {3}", Width, Height, Image)  ; 载入图像.
    MyGui.Title := Image
    MyGui.Show("xCenter y0 AutoSize")  ; 调整窗口以适应图片尺寸.
}

创建带有菜单栏的简单文本编辑器.

; 创建 MyGui 窗口:
MyGui := Gui("+Resize", "Untitled")  ; 使窗口可以调整大小.

; 为菜单栏创建子菜单:
FileMenu := Menu()
FileMenu.Add("&New", MenuFileNew)
FileMenu.Add("&Open", MenuFileOpen)
FileMenu.Add("&Save", MenuFileSave)
FileMenu.Add("Save &As", MenuFileSaveAs)
FileMenu.Add() ; 分隔线.
FileMenu.Add("E&xit", MenuFileExit)
HelpMenu := Menu()
HelpMenu.Add("&About", MenuHelpAbout)

; 通过附加子菜单来创建菜单栏:
MyMenuBar := MenuBar()
MyMenuBar.Add("&File", FileMenu)
MyMenuBar.Add("&Help", HelpMenu)

; 添加菜单栏到窗口:
MyGui.MenuBar := MyMenuBar

; 创建主编辑控件:
MainEdit := MyGui.Add("Edit", "WantTab W600 R20")

; 应用事件:
MyGui.OnEvent("DropFiles", Gui_DropFiles)
MyGui.OnEvent("Size", Gui_Size)

MenuFileNew()  ; 应用默认设置.
MyGui.Show()  ; 显示窗口.

MenuFileNew(*)
{
    MainEdit.Value := ""  ; 清空编辑控件.
    FileMenu.Disable("3&")  ; 使 &Save 灰色禁用.
    MyGui.Title := "Untitled"
}

MenuFileOpen(*)
{
    MyGui.Opt("+OwnDialogs")  ; 强制用户响应 FileSelectFile 对话框后才能返回到主窗口.
    SelectedFileName := FileSelect(3,, "Open File", "Text Documents (*.txt)")
    if SelectedFileName = "" ; 没有选择文件.
        return
    global CurrentFileName := readContent(SelectedFileName)
}

MenuFileSave(*)
{
    saveContent(CurrentFileName)
}

MenuFileSaveAs(*)
{
    MyGui.Opt("+OwnDialogs")  ; 强制用户响应 FileSelectFile 对话框后才能返回到主窗口.
    SelectedFileName := FileSelect("S16",, "Save File", "Text Documents (*.txt)")
    if SelectedFileName = "" ; 没有选择文件.
        return
    global CurrentFileName := saveContent(SelectedFileName)
}

MenuFileExit(*)  ; 用户从 File 菜单中选择 "Exit".
{
    WinClose()
}

MenuHelpAbout(*)
{
    About := Gui("+owner" MyGui.Hwnd)  ; 让主窗口成为 "about box" 的父窗口.
    MyGui.Opt("+Disabled")  ; 禁用主窗口.
    About.Add("Text",, "Text for about box.")
    About.Add("Button", "Default", "OK").OnEvent("Click", About_Close)
    About.OnEvent("Close", About_Close)
    About.OnEvent("Escape", About_Close)
    About.Show()

    About_Close(*)
    {
        MyGui.Opt("-Disabled")  ; 重新启用主窗口(必须在下一步之前进行).
        About.Destroy()  ; 销毁关于对话框.
    }
}

readContent(FileName)
{
    try
        FileContent := FileRead(FileName)  ; 读取文件的内容到变量中.
    catch
    {
        MsgBox("Could not open '" FileName "'.")
        return
    }
    MainEdit.Value := FileContent  ; 在控件中显示文本.
    FileMenu.Enable("3&")  ; Re-enable &Save.
    MyGui.Title := FileName  ; 在标题栏显示文件名.
    return FileName
}

saveContent(FileName)
{
    try
    {
        if FileExist(FileName)
            FileDelete(FileName)
        FileAppend(MainEdit.Value, FileName)  ; 保存内容到文件.
    }
    catch
    {
        MsgBox("The attempt to overwrite '" FileName "' failed.")
        return
    }
    ; 成功时在标题栏显示文件名(以防 MenuFileSaveAs 被调用的情况):
    MyGui.Title := FileName
    return FileName
}

Gui_DropFiles(thisGui, Ctrl, FileArray, *)  ; 支持拖拽.
{
    CurrentFileName := readContent(FileArray[1])  ; 仅获取首个文件(如果有多个文件的时候).
}

Gui_Size(thisGui, MinMax, Width, Height)
{
    if MinMax = -1  ; 窗口被最小化了. 无需进行操作.
        return
    ; 否则, 窗口的大小被调整过或被最大化了. 调整编辑控件的大小以匹配窗口.
    MainEdit.Move(,, Width-20, Height-20)
}

演示循环引用引起的问题.

; 单击打开或双击托盘图标, 显示另一个 GUI.
; 使用菜单项, Escape 或关闭按钮, 查看其响应情况.
A_TrayMenu.Add("&Open", ShowRefCycleGui)
Persistent

ShowRefCycleGui(*) {
    static n := 0
    g := Gui(, "GUI #" (++n)), g.n := n
    g.MenuBar := mb := MenuBar()   ; g -> mb
    mb.Add("Gui", m := Menu())     ; mb -> m
    m.Add("Hide", (*) => g.Hide()) ; (*) -> g
    m.Add("Destroy", (*) => g.Destroy())
    ; 对于 GUI(图形用户界面) 事件, 回调参数可用于避免
    ; 循环引用(使用相同的名称可防止意外捕获).
    ; 不过, Hide() 并不会破坏 *other* 循环引用.
    g.OnEvent("Escape", (g, *) => g.Hide())
    ; 捕捉变量对我们有利.
    g.OnEvent("Close", (*) => g := unset)
    g.Show("w300 h200")
    ; 由于循环引用 __Delete 不会被调用:
    ;   g -> mb -> m -> (*) -> g
    ; 除非通过触发关闭事件或者通过 Destroy 释放 MenuBar 和事件处理程序,
    ; 取消设置 g.
    g.__Delete := this => MsgBox("GUI #" this.n " deleted")
}


GuiControl 对象 - 方法 & 属性 | AutoHotkey v2

GuiControl 对象

class Gui.Control extends Object

提供用于修改 GUI 控件并检索有关控件的信息的接口. Gui.Add, Gui.__Item 和 GuiCtrlFromHwnd 返回这种类型的对象.

下面使用 "GuiCtrl" 作为任何 Gui.Control 类实例的占位符.

Gui.Control 作为所有 GUI 控件的基类, 但是每种类型的控件都有自己的类. 以下一些方法是由适当的类的原型, 或 Gui.List 基类定义的. 有关完整列表, 请参阅内置的类.

除了从 Object 继承的方法和属性外, GuiControl 对象还具有以下预定义的方法和属性.

目录

  • 方法:
    • Add: 添加项目到多项目控件中.
    • Choose: 选择多项目控件中的项目.
    • Delete: 删除的项目控件中的一个或所有项目.
    • Focus: 设置键盘焦点到控件上.
    • GetPos: 获取控件的位置和大小.
    • Move: 移动和/或调整控件的大小.
    • OnCommand: 注册一个在 WM_COMMAND 上调用的函数或方法.
    • OnEvent: 注册给定事件触发时要调用的函数或方法.
    • OnNotify: 注册一个在 WM_NOTIFY 上调用的函数或方法.
    • Opt: 为控件的外观和行为设置各种选项和样式.
    • Redraw: 重绘控件所占的 GUI 窗口区域.
    • SetFont: 设置控件的字体字体, 大小, 样式和/或颜色.
  • 属性:
    • ClassNN: 检索控件的类名和序列编号(ClassNN).
    • Enabled: 检索或设置控件的交互状态.
    • Focused: 检索控件的焦点状态.
    • Gui: 检索控件的父窗口的 Gui 对象.
    • Hwnd: 检索控件的窗口句柄(HWND).
    • Name: 检索或设置控件的显式名称.
    • Text: 检索或设置控件的文本/标题.
    • Type: 检索控件的类型.
    • Value: 检索或设置具有值属性的控件的内容.
    • Visible: 检索或设置控件的可见状态.
  • 备注:
    • Redraw: 关于控件重绘行为的性能相关注释.

方法

Add

添加项目到多项目控件(ListBox, DropDownList, ComboBox 或 Tab).

GuiCtrl.Add(Items)

参数

Items

类型:Array

将作为项目插入控件列表末尾的字符串数组, 例如 ["Red","Green","Blue"].

备注

要替换(覆盖) 列表, 请事先使用 Delete 方法. 要选择一个项目, 请使用 Choose 方法.

相关

ListView.Add, TreeView.Add

Choose

在多项目控件(ListBox, DropDownList, ComboBox 或 Tab) 中选择一个项目.

GuiCtrl.Choose(Value)

参数

Value

类型: 整数或字符串

指定 1 表示第一个项目, 2 表示第二个, 等等.

如果 Value 是字符串(即使是数字字符串), 将选择名称前部与 Value 相匹配的项目. 搜索不区分大小写. 例如, 如果控件中包含 "UNIX Text" 项目, 指定单词 unix(小写) 就可以选择它. 对于一个多选 ListBox, 所有匹配的项目都会被选中.

如果 Value 为零或为空, 则当前选择将被移除.

备注

要选择或取消选择一个多选 ListBox 中的 所有 项目, 请参照此例:

PostMessage 0x185, 1, -1, ListBox  ; 选择所有项目. 0x185 是 LB_SETSEL.
PostMessage 0x185, 0, -1, ListBox  ; 取消选择所有项目.
ListBox.Choose(0)  ; 取消选择所有项目.

与 ControlChooseIndex 不同, 该方法不会触发 Change 或 DoubleClick 事件.

Delete

删除多项目控件(ListBox, DropDownList, ComboBox 或 Tab) 中的一个或所有项目.

GuiCtrl.Delete(Value)

参数

Value

类型: 整数

如果省略, 则删除所有项目. 否则, 指定 1 表示第一个项目, 2 表示第二个, 等等.

备注

对于 Tab 控件, 一个标签的子控件会与其原始的标签编号相关联; 也就是说, 它们永远不会与其标签的实际显示名称相关联. 因此, 重命名或删除一个选项卡不会改变子控件所属的选项卡号. 例如, 如果有三个选项卡 ["Red","Green","Blue"] 并且通过 MyTab.Delete(2) 删除了第二个选项卡, 则原来与 Green 相关联的子控件现在将与 Blue 相关联. 由于这种行为, 一般只应删除最后的标签页. 以这种方式删除的标签页可以在以后再添加回来, 届时它们将重新获得原来的控件集.

相关

ListView.Delete, TreeView.Delete

Focus

设置键盘焦点到控件上.

GuiCtrl.Focus()

要让设置生效, 窗口一般不能处于最小化或隐藏状态.

要检索控件的焦点状态, 请使用 Focused 属性.

GetPos

获取控件的位置和大小.

GuiCtrl.GetPos(&X, &Y, &Width, &Height)

参数

&X, &Y

类型: VarRef

如果省略, 则不存储相应的值. 否则, 指定对输出变量的引用, 在输出变量中存储控件左上角的 X 和 Y 坐标(以像素为单位). 这些坐标相对于窗口客户端区域的左上角,该区域不包括标题栏, 菜单栏和边框.

&Width, &Height

类型: VarRef

如果省略, 则不存储相应的值. 否则, 指定对输出变量的引用, 以存储控件的宽度和高度(以像素为单位).

备注

与 ControlGetPos 不同的是, 本方法对返回的坐标应用了 DPI 缩放(除非使用了 -DPIScale 选项).

示例

MyEdit.GetPos(&x, &y, &w, &h)
MsgBox "The X coordinate is " x ". The Y coordinate is " y ". The width is " w ". The height is " h "."

Move

移动和/或调整控件的大小.

GuiCtrl.Move(X, Y, Width, Height)

参数

X, Y

类型: 整数

如果省略其中任何一个, 则不会更改控件在该维度中的位置. 否则, 指定控件新位置左上角的 X 和 Y 坐标(以像素为单位). 坐标相对于窗口的客户端区域的左上角, 该区域不包括标题栏, 菜单栏和边框.

Width, Height

类型: 整数

如果省略其中任何一个, 则不会更改该维度中的控件的大小. 否则, 指定控件的新宽度和高度(以像素为单位).

备注

与 ControlMove 不同的是, 本方法将 DPI 缩放应用于坐标(除非使用了 -DPIScale 选项).

示例

MyEdit.Move(10, 20, 200, 100)
MyEdit.Move(VarX+10, VarY+5, VarW*2, VarH*1.5)

OnCommand

注册一个函数或方法, 当通过 WM_COMMAND 消息接收到控件通知时调用.

GuiCtrl.OnCommand(NotifyCode, Callback , AddRemove)

有关详情, 请参阅 OnCommand.

OnEvent

注册给定事件触发时要调用的函数或方法.

GuiCtrl.OnEvent(EventName, Callback , AddRemove)

有关详情, 请参阅 OnEvent.

OnNotify

注册一个函数或方法, 当通过 WM_NOTIFY 消息接收到控件通知时调用.

GuiCtrl.OnNotify(NotifyCode, Callback , AddRemove)

有关详情, 请参阅 OnNotify.

Opt

为控件的外观和行为设置各种选项和样式.

GuiCtrl.Opt(Options)

参数

Options

类型: 字符串

指定一个或多个控件专用或通用选项和样式, 用一个或多个空格或制表符与下一个隔开.

备注

在下面的例子中, 该控件被禁用, 并且它的 background 恢复为系统默认值:

MyEdit.Opt("+Disabled -Background")

在下一个例子中, OK 按钮被变成了新的默认按钮:

OKButton.Opt("+Default")

虽然样式和扩展样式也被识别, 但其中一些样式在控件创建后无法应用或删除. 即使成功应用了某项更改, 控件也可能选择忽略它.

Redraw

重绘控件所占的 GUI 窗口区域.

GuiCtrl.Redraw()

虽然当重复和快速调用时, 可能会导致不必要的闪烁效果, 但它解决了某些控件类型(如 GroupBox) 的显示重影的问题.

SetFont

设置控件的字体字体, 大小, 样式和/或颜色.

GuiCtrl.SetFont(Options, FontName)

省略这两个参数, 以将字体设置为 GUI 的当前字体, 如 Gui.SetFont 所设置. 否则, 任何未指定的字体属性将从控件的先前字体中复制. 只有在 Options 中指定的情况下, 文本颜色才会改变.

关于这两个参数的详细说明, 请参阅 Gui.SetFont.

属性

ClassNN

检索控件的类名和序列编号(ClassNN).

ClassNN := GuiCtrl.ClassNN

控件的 ClassNN 是它的窗口类名后面跟着它在包含它的顶级窗口中的序列号. 例如, "Edit1" 是窗口上的第一个编辑控件, 而 "Button12" 是第十二个按钮.

相关: ControlGetClassNN

Enabled

检索或设置控件的交互状态.

CurrentSetting := GuiCtrl.Enabled
GuiCtrl.Enabled := NewSetting

如果已经赋值, CurrentSetting 为 NewSetting, 否则, 默认为 1(true), 除非被 Disabled 选项覆盖.

NewSetting 是一个布尔值, 用于启用或禁用此设置. 如果为 true, 则启用该控件. 如果为 false, 则禁用该控件.

对于 Tab 控件, 这也将启用或禁用该 Tab 的所有子控件. 然而, 任何通过 GuiCtrl.Enabled := false 显式禁用的子控件将记住该设置, 因此即使在其 Tab 控件被重新启用后也会保持禁用状态.

Focused

检索控件当前焦点状态.

IsFocused := GuiCtrl.Focused

如果控件有键盘焦点, IsFocused 为 1(true), 否则为 0(false).

要让设置生效, 窗口一般不能处于最小化或隐藏状态.

要对聚焦控件, 请使用 Focus 方法.

Gui

检索控件的父窗口的 Gui 对象.

GuiObj := GuiCtrl.Gui

Hwnd

检索控件的窗口句柄(HWND).

Hwnd := GuiCtrl.Hwnd

控件的 HWND, 通常与 PostMessage, SendMessage 和 DllCall 一起使用. 它也可以直接用于 Control 参数.

Name

检索或设置控件的显式名称.

CurrentName := GuiCtrl.Name
GuiCtrl.Name := NewName

如果已经赋值, CurrentName 为 NewName, 否则默认为空字符串, 除非被 V 选项覆盖.

NewName 为控件的新名称, 它可以与 Gui.__Item 一起使用, 来检索 GuiControl 对象. 对于大多数支持输入的控件, Gui.Submit 也会使用这个名称.

Text

检索或设置控件的文本/标题.

CurrentText := GuiCtrl.Text
GuiCtrl.Text := NewText

注意: 如果控件没有可见的标题文本和文本值, 则此属性对应于控件的隐藏标题文本(如 ControlGetText/ControlSetText).

CurrentText 和 NewText 的值取决于控件类型:

Button / CheckBox / Edit / GroupBox / Link / Radio / Text

CurrentText 和 NewText 是 Button, CheckBox, Edit, GroupBox, Link, Radio 或 Text 控件的标题/显示文本. 由于控件不会自动展开, 如果需要展开控件, 请使用 GuiCtrl.Move(,, 300) 或类似的方法.

DateTime

CurrentText 和 NewText 是 DateTime 控件显示的格式化文本. 不支持为控件指定格式化的日期/时间字符串. 要更改显示的日期/时间, 请为 Value 属性赋值为一个 YYYYMMDDHH24MISS 格式的日期-时间戳.

DropDownList / ComboBox / ListBox / Tab

CurrentText 和 NewText 是 DropDownList, ComboBox, ListBox 或 Tab 控件中当前选择的项/选项卡的文本.

NewText 应该是要选择的项目/标签的全部文本(不区分大小写).

对于 ComboBox, 如果没有选中的项目, 则会检索控件编辑栏中的文本. 对于其他控件, CurrentText 为空/空白. 同样, 如果 NewText 为空/空白, 则当前项/标签将被取消选择.

对于一个多选 ListBox, CurrentText 是一个数组. NewText 不能是一个数组, 但如果多个项目匹配, 它们都会被选择. 要用不同的文本选择多个项目, 请重复调用 Choose 方法.

要根据项目的位置编号而不是文本选择项目, 请使用 Value 属性.

Edit

CurrentText 和 NewText 是 Edit 控件的文本. 与其他控件一样, 文本按原样检索或设置; 不用预先进行尾转换. 要检索或设置多行 Edit 控件的文本, 同时在 `r`n 和 `n 之间进行转换, 请使用 Value 属性.

StatusBar

CurrentText 和 NewText 是 StatusBar 控件第一部分的文本(使用 SB.SetText 以获得更大的灵活性).

Type

检索控件的类型.

CurrentType := GuiCtrl.Type

取决于控件类型, CurrentType 是以下字符串之一: ActiveX, Button, CheckBox, ComboBox, Custom, DateTime, DDL, Edit, GroupBox, Hotkey, Link, ListBox, ListView, MonthCal, Pic, Progress, Radio, Slider, StatusBar, Tab, Tab2, Tab3, Text, TreeView, UpDown.

Value

检索或设置具有值的控件的内容.

CurrentValue := GuiCtrl.Value
GuiCtrl.Value := NewValue

注意: 如果控件不包含值, CurrentValue 将是空白, 并且赋值 NewValue 将引发错误. 无效的值会抛出异常.

CurrentValue 和 NewValue 的值取决于控件类型:

ActiveX

CurrentValue 是 ActiveX 控件的 ActiveX 对象. 例如, 如果控件是用文本 Shell.Explorer 创建的, 这是一个 WebBrowser 对象. 每次都返回相同的包装器对象.

NewValue 无效并抛出异常.

CheckBox / Radio

如果选中了 CheckBox 或 Radio 控件, 则 CurrentValue 为 1, 如果未选中, 则为 0, 如果有灰色复选标记, 则为 -1.

NewValue 可以是 0 来取消选中按钮, 1 来选中它, 或者 -1 来给它一个灰色的复选标记. 对于 Radio 按钮, 如果有一个按钮被选中(打开) 并且它是一个多个单选按钮组的成员, 那么该组中的其他单选按钮将被自动取消选中.

如果要获取或设置控件的文本/标题, 请使用 Text 属性.

ComboBox / DropDownList / ListBox / Tab

CurrentValue 是当前选中的项目/标签在 ComboBox, DropDownList, ListBox 或 Tab 控件中的位置编号. 如果没有选择, 则返回 0. 如果在 ComboBox 中输入了文本, 则使用第一个匹配文本的项目. 如果没有匹配的项目, 即使控件中有文本, 结果也是 0. 对于一个多选 ListBox, 结果是一个数字数组(如果没有选择任何项目, 则为空).

NewValue 是要选择的单个项目/标签的位置编号, 或者为零来清除当前的选择(即使对 Tab 控件也有效). 要选择多个项目, 请重复调用 Choose 方法.

要获取或设置选中项的文本而不是其位置, 请使用 Text 属性.

DateTime / MonthCal

CurrentValue 是当前在 DateTime 或 MonthCal 控件中选择的 YYYYMMDDHH24MISS 格式的日期-时间戳.

NewValue 是 YYYYMMDDHH24MISS 格式的日期-时间戳. 指定 A_Now 来使用当前日期和时间(今天). 对于 DateTime 控件, NewValue 可以是一个空字符串, 以使该控件没有选择日期/时间(如果它在创建时含有这个能力). 对于 MonthCal 控件, 如果控件是多选的, 则可以指定一个日期范围.

Edit

CurrentValue 是 Edit 件的当前内容. 对于多行控件, 文本中的任何换行符将以普通换行符(`n) 表示, 而不是 ControlGetText 和 ControlSetText 等非 GUI 函数所使用传统的 CR+LF(`r`n).

NewValue 是新的内容. 对于多行控件, NewValue 中任何缺少前回车(`r) 的换行(`n) 都会被自动转换为 CR+LF(`r`n) 以使其正确显示. 然而, 这通常不是一个问题, 因为当使用 MyGui.Submit 或检索这个值时, 这个转换会自动反过来, 用 LF(`n) 替换 CR+LF.

要检索或设置文本, 而不将 `n 转换为 `r`n, 请使用 Text 属性.

Hotkey

如果 Hotkey 控件中有热键, 则 CurrentValue 为修饰符和键名; 否则为空. 例如: ^!C, ^Home, +^NumpadHome.

NewValue 可以是一组修饰符和键名, 或空白以清空该控件. 例如: ^!c, ^Numpad1, +Home. 支持的修饰符仅包含 ^(Control), !(Alt), 和 +(Shift). 请参阅按键列表了解可用的按键名称.

Picture

CurrentValue 是创建 Picture 控件时指定的图片文件名. 即使指定了新的图片文件名, 这个名称也不会改变.

NewValue 是要加载的新图片的文件名(或句柄)(关于支持的文件类型, 请参阅 Picture). 可以在文件名前指定零个或多个下列选项: *wN(宽度 N), *hN(高度 N) 和 *IconN(DLL 或 EXE 文件中的图标组编号 N). 在下面的例子中, 将加载第二个图标组中的默认图标, 设置宽度为 100 以及通过 "保持高宽比" 自动设置高度: MyPic.Value := "*icon2 *w100 *h-1 C:\My Application.exe". 指定 *w0 *h0 使用图像的实际宽度和高度. 如果同时省略 *w 和 *h, 则调整图像以适应控件当前的大小. 从多图标的 .ICO 文件中加载时, 指定宽度和高度也决定了加载哪个图标. 注意: 在最后的选项和文件名之间只使用一个空格或制表符; 任何其他空格和制表符都会被视为文件名的一部分.

Progress / Slider / UpDown

CurrentValue 是 Progress, Slider 或 UpDown 控件的当前位置.

NewValue 是控件的新位置, 例如 MySlider.Value := 10. 要调整一个相对的数值, 请使用运算符 +=, -=, ++ 或 -- 代替 :=. 如果新的位置超出了控件的范围, 控件一般会被设置为最近的有效值.

Text

CurrentValue 是 Text 控件的的文本/标题.

NewValue 是控件的新文本. 由于控件不会自动展开, 所以如果需要扩大控件, 请使用 GuiCtrl.Move(,, 300).

Visible

检索或设置控件的当前可见状态.

CurrentSetting := GuiCtrl.Visible
GuiCtrl.Visible := NewSetting

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 1(true), 除非被 Hidden 选项覆盖.

NewSetting 是一个布尔值, 用于启用或禁用这个设置. 如果为 true, 控件可见. 如果为 false, 控件被隐藏.

对于 Tab 控件, 这也将显示或隐藏该 Tab 的所有子控件. 如果您还想阻止一个控件的快捷键(下划线字母) 工作, 通过 GuiCtrl.Enabled := false 禁用该控件.

备注

Redraw

当向控件(如 ListView, TreeView 或 ListBox) 添加大量项目时, 可以通过防止在进行更改时重绘控件来提高性能. 这是通过在添加项目之前使用 GuiCtrl.Opt("-Redraw") 和在添加项目之后使用 GuiCtrl.Opt("+Redraw") 来实现的. 对控件的更改, 如果在禁用重绘前还未显示, 一般在重绘重新启用后才会显示.

出于性能原因, 即使启用了重绘, 对控件内容的更改通常也不会立即重绘该控件. 相反, 当程序检查其内部消息队列时, 控件的部分区域被 "失效", 通常在短暂延迟后重新绘制. 脚本可以通过调用 Sleep -1 立即强制执行此操作.


GUI 控件类型 - 语法 & 使用 | AutoHotkey v2

GUI 控件类型

GUI 控制类型是可使用 Gui.Add 添加到 GUI 窗口中的交互元素.

目录

  • ActiveX(第三方控件)
  • Button(按钮)
  • CheckBox(多选按钮)
  • ComboBox(可输入下拉列表)
  • Custom(自定义控件)
  • DateTime(时间日期选择器)
  • DropDownList(或 DDL)(静态下拉列表)
  • Edit(文本编辑框)
  • GroupBox(分组框)
  • Hotkey(热键)
  • Link(链接)
  • ListBox(简单列表)
  • ListView(高级表格)
  • MonthCal(月历)
  • Picture(或 Pic)(图片)
  • Progress(进度条)
  • Radio(单选按钮)
  • Slider(滑动条)
  • StatusBar(状态栏)
  • Tab3 / Tab2 / Tab(选项卡)
  • Text(文本)
  • TreeView(树形列表)
  • UpDown(增减按钮组)

ActiveX

ActiveX 组件(例如 MSIE 浏览器控件) 可以按照以下方式嵌入到 GUI 窗口. 有关 ActiveX 组件及下面使用的方法的详细信息, 请参阅 WebBrowser object (Microsoft Docs) 和 Navigate method (Microsoft Docs).

MyGui := Gui()
WB := MyGui.Add("ActiveX", "w980 h640", "Shell.Explorer").Value  ; 最后一个参数是 ActiveX 组件的名称.
WB.Navigate("https://www.autohotkey.com/docs/")  ; 这是特定于网页浏览器控件的.
MyGui.Show()

当控件被创建时, ActiveX 对象可以通过 GuiControl.Value 来检索.

要处理对象公开的事件, 请使用 ComObjConnect, 如下所示. 有关下面使用的事件的详细信息, 请参阅 NavigateComplete2 event (Microsoft Docs).

MyGui := Gui()
URL := MyGui.Add("Edit", "w930 r1", "https://www.autohotkey.com/docs/")
MyGui.Add("Button", "x+6 yp w44 Default", "Go").OnEvent("Click", ButtonGo)
WB := MyGui.Add("ActiveX", "xm w980 h640", "Shell.Explorer").Value
ComObjConnect(WB, WB_events)  ; 连接 WB 事件到 WB_events 类对象.
MyGui.Show()
; 继续加载初始页面:
ButtonGo()

ButtonGo(*) {
    WB.Navigate(URL.Value)
}

class WB_events {
    NavigateComplete2(wb, &NewURL, *) {
        URL.Value := NewURL  ; 更新 URL 编辑控件.
    }
}

ComObjType 可以用来确定检索对象的类型.

Button

描述: 按下后可以触发动作的按钮. 此时最后一个参数为按钮的名称(显示在按钮上), 其中可以包含换行符(`n) 来开始新行.

例如:

MyBtn := MyGui.Add("Button", "Default w80", "OK")
MyBtn.OnEvent("Click", MyBtn_Click)  ; 当点击时, 调用 MyBtn_Click.

或者:

MyBtn := MyGui.AddButton("Default w80", "OK")
MyBtn.OnEvent("Click", MyBtn_Click)  ; 当点击时, 调用 MyBtn_Click.

外观:

每当用户点击按钮或在其具有焦点时按下 Space 或 Enter 键, Click 事件就会被触发.

同时也支持 DoubleClick, Focus 和 LoseFocus 事件. 由于这些事件只有在控件具有 BS_NOTIFY(0x4000) 样式时才会被触发, 所以它是由 OnEvent 自动添加的.

上面的例子在其 Options 中包含单词 Default 来让 "OK" 成为默认按钮. 每当用户按下 Enter 键时会自动触发默认按钮的 Click 事件, 除非此时键盘焦点在另一个按钮上或具有 WantReturn 样式的多行编辑控件中. 以后要改变默认按钮为另一个按钮, 请参照此例, 这里让 Cancel 按钮成为默认按钮: MyGui["Cancel"].Opt("+Default"). 以后要让窗口没有默认按钮, 请参照此例: MyGui["OK"].Opt("-Default").

在按钮名称中使用和符号(&) 可以让其中的某个字母带下划线显示. 例如:

MyGui.Add("Button",, "&Pause")

在上面的示例中, 字母 P 将被添加下划线, 这允许用户按下 Alt+P 作为其快捷键. 要显示一个原义的和符号, 请指定两个连续的和符号(&&).

已知限制: 某些桌面主题可能无法正确的显示按钮文本. 如果遇到此情况, 请尝试在控件的选项中包含 -Wrap(负 Wrap). 不过这样也使得按钮名称中无法包含多行文本.

Checkbox

描述: 一个小方框, 可以选中或取消选中来表示 On/Off, Yes/No, 等等.

例如:

MyGui.Add("CheckBox", "vShipToBillingAddress", "Ship to billing address?")

或者:

MyGui.AddCheckBox("vShipToBillingAddress", "Ship to billing address?")

外观:

对于最后一个参数, 指定要显示在框右侧的标签. 这个标签通常是关于复选框用途的提示或描述, 它可以包含换行符(`n) 来开始新行. 如果 Options 中指定了宽度(W) 而没有指定行数(R) 或高度(H), 那么在需要时控件的文本将自动换行, 同时自动设置控件的高度.

GuiControl.Value 返回数字 1 表示选中, 0 表示未选中, -1 表示灰色/不确定.

在 Options 中指定单词 Check3 来启用第三种状态即显示灰色的选择标记而不是黑色的(灰色状态表示复选框既不处于选中状态也不处于未选中状态). 在 Options 中指定单词 Checked 或 CheckedGray 可以让复选框初始状态分别为黑色选中状态或灰色状态. 单词 Checked 后面可以紧跟着 0, 1 或 -1 来表示初始状态. 换句话说, "Checked" 和 "Checked" VarContainingOne 是一样的.

每当复选框被点击时, 它就会自动在它的两个或三个可能的状态之间循环, 然后触发 Click 事件, 允许脚本立即响应用户的输入.

同时也支持 DoubleClick, Focus 和 LoseFocus 事件. 由于这些事件只有在控件具有 BS_NOTIFY(0x4000) 样式时才会被触发, 所以它是由 OnEvent 自动添加的. 默认情况下不应用该样式, 因为它可以阻止快速点击改变复选标记的状态(例如用户点击两次从未选中切换到选中, 然后再切换到不确定).

已知限制: 某些桌面主题可能无法正确的显示 checkbox 的文本. 如果遇到此情况, 请尝试在控件的选项中包含 -Wrap(负 Wrap). 不过这样也使得按钮名称中无法包含多行文本.

ComboBox

描述: 和 DropDownList 一样, 但也允许输入自由格式的文本, 作为从列表中选择项目的替代. 在本例中, Gui.Add 的最后一个参数是 Array, 如 ["Choice1", "Choice2", "Choice3"].

例如:

MyGui.Add("ComboBox", "vColorChoice", ["Red", "Green", "Blue", "Black", "White"])

或者:

MyGui.AddComboBox("vColorChoice", ["Red", "Green", "Blue", "Black", "White"])

外观:

除了可以使用所有 DropDownList 选项外, Options 中还可以包含单词 Limit 来限制用户的输入在 ComboBox 编辑区域的可见宽度内. 此外, 可以指定单词 Simple 来让 ComboBox 表现的像一个下方带有 ListBox 的 Edit 区域.

GuiControl.Value 返回当前选中项的位置编号(第一项为 1, 第二项为 2, 等等.), 如果控件包含的文本与列表项不匹配, 则返回 0, 而 GuiControl.Text 返回 ComboBox 的编辑栏的内容. Gui.Submit 会存储文本, 除非在控件的 Options 中含有单词 AltSubmit 并且文本与列表项相匹配, 在这种情况下, 它会存储该项目的位置编号.

每当用户选择一个新的项目或更改控件的文本时, 就会触发 Change 事件. 同时也支持 Focus 和 LoseFocus 事件.

Custom

AutoHotkey 不直接支持的控件也可以嵌入到 GUI 窗口. 要实现这样的操作, 在 Options 中包含单词 Class 后跟所需控件的 Win32 类名. 例如:

MyGui.Add("Custom", "ClassComboBoxEx32")  ; 添加 ComboBoxEx 控件.
MyGui.Add("Custom", "ClassScintilla")  ; 添加 Scintilla 控件. 注意必须加载 SciLexer.dll 库后才能添加此控件.

AutoHotkey 通过 Gui.Add 或 GuiControl.Value 使用标准的 Windows 操作方法来获取或替换控件中的文本.

Events: 由于每个通知代码的含义取决于发送它的控件, 因此 OnEvent不支持自定义控件. 然而, 如果控件以 WM_NOTIFY 或 WM_COMMAND 消息的形式发送通知, 脚本可以使用 OnNotify 或 OnCommand 来检测它们.

下面这个例子演示了如何添加和使用 IP 地址控件:

MyGui := Gui()
IP := MyGui.Add("Custom", "ClassSysIPAddress32 r1 w150")
IP.OnCommand(0x300, IP_EditChange)  ; 0x300 = EN_CHANGE
IP.OnNotify(-860, IP_FieldChange)  ; -860 = IPN_FIELDCHANGED
IPText := MyGui.Add("Text", "wp")
IPField := MyGui.Add("Text", "wp y+m")
MyGui.Add("Button", "Default", "OK").OnEvent("Click", OK_Click)
MyGui.Show()

IPCtrlSetAddress(IP, SysGetIPAddresses()[1])

OK_Click(*)
{
    MyGui.Hide()
    MsgBox("You chose " IPCtrlGetAddress(IP))
    ExitApp()
}

IP_EditChange(*)
{
    IPText.Text := "New text: " IP.Text
}

IP_FieldChange(thisCtrl, NMIPAddress)
{
    ; 从 NMIPADDRESS 结构体中提取信息.
    iField := NumGet(NMIPAddress, 3*A_PtrSize + 0, "int")
    iValue := NumGet(NMIPAddress, 3*A_PtrSize + 4, "int")
    if (iValue >= 0)
        IPField.Text := "Field #" iField " modified: " iValue
    else
        IPField.Text := "Field #" iField " left empty"
}

IPCtrlSetAddress(GuiCtrl, 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, GuiCtrl)
}

IPCtrlGetAddress(GuiCtrl)
{
    static WM_USER := 0x400
    static IPM_GETADDRESS := WM_USER + 102

    AddrWord := Buffer(4)
    SendMessage(IPM_GETADDRESS, 0, AddrWord, GuiCtrl)
    IPPart := []
    Loop 4
        IPPart.Push(NumGet(AddrWord, 4 - A_Index, "UChar"))
    return IPPart[1] "." IPPart[2] "." IPPart[3] "." IPPart[4]
}

DateTime

描述: 一个看起来像单行编辑控件的框, 不过它接受日期和/或时间. 同时提供下拉日历.

例如:

MyGui.Add("DateTime", "vMyDateTime", "LongDate")

或者:

MyGui.AddDateTime("vMyDateTime", "LongDate")

外观:

最后一个参数是一个格式字符串, 如下面的 SetFormat 方法所述. 此方法允许在创建 DateTime 控件之后更改显示格式.

DateTime 方法

SetFormat

设置 DateTime 控件的显示格式.

DateTime.SetFormat(Format)

参数

Format

类型: 字符串

如果为空或省略, 则默认为 ShortDate. 否则, 请指定以下格式之一:

ShortDate: 使用区域设置的短日期格式. 例如, 在某些区域设置中它看起来像这样: 6/1/2005

LongDate: 使用区域设置的长日期格式. 例如, 在某些区域设置中它看起来像这样: Wednesday, June 01, 2005

Time: 仅显示时间, 使用区域设置的时间格式. 尽管不显示日期, 但它仍然存在于控件中并且与 YYYYMMDDHH24MISS 格式的时间一起被获取. 例如, 在某些区域它看起来像这样: 9:37:45 PM

(自定义格式): 指定日期和时间格式的任意组合. 例如, "M/d/yy HH:mm" 显示的时间看起来像 6/1/05 21:37. 同样, "dddd MMMM d, yyyy hh:mm:ss tt" 显示的时间看起来像 June 1, 2005 09:37:45 PM. 想要原义显示的字母和数字应该括在一对单引号中, 如此例所示: "'Date:' MM/dd/yy 'Time:' hh:mm:ss tt". 与之相比, 非字母数字字符(例如空格, tab, 斜杠, 冒号, 逗号和其他标点) 不需要包围在单引号中. 例外情况是单引号字符本身: 要产生原义的单引号, 请使用四个连续的单引号(''''), 不过如果它们已经包含在一对外部引号中则仅使用连续的两个就行了.

DateTime 的用法

要预选今天外的其他日期, 请在 Options 中包含单词 Choose 紧跟着 YYYYMMDD 格式的日期. 例如, Choose20050531 将预选 May 31, 2005(和其他选项一样, 它还可以为变量, 例如 "Choose" Var). 要不预选日期/时间, 请指定 ChooseNone. ChooseNone 还在控件内部创建了一个复选框, 只要控件没有日期, 这个复选框就会被取消选中. 当控件中没有选择日期时, Gui.Submit 或 GuiControl.Value 将检索一个空白值(空字符串).

日期的时间部分是可选的. 但是, 当进入或离开控件时, 时间部分必须总是在日期之前. 时间部分的格式为 HH24MISS(小时数, 分钟数, 秒数), 其中 HH24 含义是用 24 小时格式表示; 例如, 09 为 9am, 而 21 为 9pm. 因此, 完整的日期时间字符串的格式应为 YYYYMMDDHH24MISS.

当指定了 YYYYMMDDHH24MISS 格式的日期时, 只有前导部分是不能缺少的. 其他任何省略的元素将使用下列默认值代替: MM: 月份 01, DD: 日期 01, HH24: 小时 00, MI: 分钟 00, SS: 秒 00.

在下拉日历中, 可以点击底部的今日字符串来选择今天的日期. 此外, 还可以点击年份和月份名称来方便地导航到新的月份或年份.

键盘导航: 使用 ↑/↓ 方向键, +/- 和 Home/End 来增加或减少控件的值. 使用 ← 和 → 方向键在控件中的区域间移动. 在下拉日历中, 使用方向键在日期间移动; 使用 PgUp/PgDn 在月份间往后/往前移动; 使用 Home/End 选择当月的第一天/最后一天.

当使用 Gui.Submit 或 GuiControl.Value 时, 返回值是所选的日期和时间, 格式为 YYYYMMDDHH24MISS. 无论日期和时间是否在控件中实际可见, 它们都是存在的.

每当用户更改日期或时间时, 就会触发 Change 事件. 同时也支持 Focus 和 LoseFocus 事件.

DateTime 选项

Choose: 请参阅上面.

Range: 限制可以选择的日期范围. 在单词 Range 后指定以 YYYYMMDD 格式表示的最小和最大的日期(它们之间使用破折号连接). 例如, Range20050101-20050615 将限制可选择的日期为 5.5 年的前 5 个半月. 最小或最大的日期可以省略, 此时控件中在这个方向上的日期不受限制. 例如, Range20010101 将禁止选择早于 2001 年的日期而 Range-20091231 有前导的破折号) 将禁止选择迟于 2009 年的日期. 如果不含 Range 选项, 则可以选择介于 1601 和 9999 年份之间的任何日期. 无法限制日期的时间部分.

Right: 让下拉日历在控件的右边而不是左边拉下.

1: 在 Options 中指定数字 1 会在此控件的右边提供一个增减控件来修改日期和时间的值, 这会取代其他地方可用的下拉月历的修改按钮. 这不能和上面所述的 LongDate 格式选项联用.

2: 在 Options 中指定数字 2 在控件中提供复选框, 用户可以取消此复选框选择来表示没有选择日期/时间. 控件创建后无法改变此选项.

下拉式日历内的颜色: 下拉式日历中天数的颜色由 Gui.SetFont 或 c(Color) 选项设置. 要改变日历其他部分的颜色, 如下例所示:

SendMessage 0x1006, 4, 0xFFAA99, "SysDateTimePick321" ; 0x1006 为 DTM_SETMCCOLOR. 4 为 MCSC_MONTHBK(背景颜色). 颜色必须以 BGR 格式指定, 而不是 RGB 格式(红蓝分量互换).

DropDownList(或 DDL)

描述: 当按下一个小按钮时显示的选择列表. 此时, Gui.Add 的最后一个参数是像 ["Choice1", "Choice2", "Choice3"] 这样的数组.

例如:

MyGui.Add("DropDownList", "vColorChoice", ["Black", "White", "Red", "Green", "Blue"])

或者:

MyGui.AddDropDownList("vColorChoice", ["Black", "White", "Red", "Green", "Blue"])

外观:

要在窗口第一次出现时预选其中一个项目, 请在 Options 中加入单词 Choose 后面紧跟着要预选的项目编号. 例如, Choose5 会预选第五项(和其他选项一样, 它也可以为变量, 例如 "Choose" Var). 在控件创建后, 请使用 GuiControl.Value, GuiControl.Text 或 GuiControl.Choose 来改变选择, 和使用 GuiControl.Add 或 GuiControl.Delete 来添加或移除列表中的条目.

在 Options 中指定单词 Uppercase 或 Lowercase 来把列表中的所有项目自动转换成大写字母或小写字母. 指定单词 Sort 来按字母顺序自动排列列表的内容(这也会影响后面通过 GuiControl.Add 添加的所有项目). Sort 选项还会启用在弹出下拉列表时的增量搜索; 这使得可以通过输入一个项目名称的前几个字符来选择此项.

GuiControl.Value 返回当前选中的项目的位置号(第一个项目是 1, 第二个项目是 2, 等等.), 如果没有选中项目, 则返回值为 0, 而 GuiControl.Text 返回当前选中项目的文本. Gui.Submit 存储文本>, 但如果控件的 Options 中含有单词 AltSubmit, 则存储项目的位置编号.

每当用户选择一个新的项目时, 就会触发 Change 事件. 同时也支持 Focus 和 LoseFocus 事件.

使用 R 或 H 选项来控制弹出列表的高度. 例如, 指定 R5 会设置列表为 5 行高, 而 H400 会设置选区字段和列表的总高度为 400 像素. 如果同时省略 R 和 H 选项, 则列表会自动扩展到用户桌面的可用高度.

要设置选区字段或列表项的高度, 请使用 CB_SETITEMHEIGHT 消息, 如下例所示:

MyGui := Gui()
DDL := MyGui.Add("DDL", "vcbx w200 Choose1", ["One", "Two"])
; CB_SETITEMHEIGHT = 0x153
PostMessage(0x153, -1, 50, DDL)  ; 设置选区字段的高度.
PostMessage(0x153, 0, 50, DDL)  ; 设置列表项的高度.
MyGui.Show("h70")

Edit

描述: 用户可以在其中键入自由格式文本的区域.

例如:

MyGui.Add("Edit", "r9 vMyEdit w135", "Text to appear inside the edit control (omit this parameter to start off empty).")

或者:

MyGui.AddEdit("r9 vMyEdit w135", "Text to appear inside the edit control (omit this parameter to start off empty).")

外观:

如果控件具有多行文本, 则它将是多行的. 例如, 在 Options 中指定 r3 将创建一个 3 行的编辑(Edit) 控件, 并拥有后面这些默认属性: 垂直滚动条, 启用自动换行, 并且 Enter 作为输入的一部分, 而不触发窗口的默认按钮.

要在多行编辑控件中开始新行, 请在最后一个参数中(内容) 包含单独的换行符(`n) 或回车换行符(`r`n). 这两种方法都会在编辑控件中产生原义的 `r`n 对. 然而, 当通过 Gui.Submit 或 GuiControl.Value 来检索控件的内容时, 文本中的每对 `r`n 总是被转换成单独的换行符(`n). 要绕过这个行尾转换, 请使用 GuiControl.Text. 要把文本写入到文件中, 请参照此例: FileAppend(MyEdit.Text, "C:\Saved File.txt").

如果控件启用了自动换行(对于多行编辑控件默认是启用的), 那么用户输入时任何自动换行的地方不会产生换行字符(仅 Enter 才会).

当用户或脚本改变控件的内容时, 触发 Change 事件.

提示: 要加载一个文本文件的内容到编辑控件中, 请使用 FileRead 和 GuiControl.Value. 例如:

MyEdit := MyGui.Add("Edit", "R20")
MyEdit.Value := FileRead("C:\My File.txt")

Edit 选项

要移除而非添加选项, 请在选项前加上负号:

Limit: 限制用户的输入在编辑区域的可见宽度内. 另外, 要限制输入指定数目的字符, 请在该选项后跟着数字. 例如, Limit10 将允许输入不超过 10 个字符.

Lowercase: 把用户输入的字符自动转换成小写形式.

Multi: 让控件可以含有多行文本. 然而, 通常没必要指定此选项, 因为它会根据高度(H), 行数(R) 或内容(Text) 自动判断.

Number: 阻止用户输入数字以外的其他字符到编辑区域(然而, 还是可能粘贴非数字字符到里面). 强制输入数字的另一种方法是添加 UpDown 控件到编辑控件中.

Password: 通过将用户输入替换为掩码字符来隐藏用户输入(例如密码输入). 如果想使用非默认的掩码字符, 请在单词 Password 后加上此符号. 例如, Password* 将使用星号而不是黑色圆(项目符号) 作为掩码符号. 注意: 此选项对于多行编辑控件没有效果.

ReadOnly: 阻止用户改变控件的内容. 不过, 仍然可以滚动, 选择文本或将文本复制到剪贴板.

T n: 字母 T 可以用来设置多行编辑控件的制表位(因为制表位决定了原义的 TAB 字符跳转的列位置, 所以它们可以把文本格式成列). 如果没有使用字母 T, 则每 32 个对话框单位设置一次制表位(每个 "对话框单位" 由操作系统决定). 如果仅使用一次字母 T, 则每 n 个单位设置一次横跨整个控件宽度的制表位. 例如, MyGui.Add("Edit", "vMyEdit r16 t64") 将设置制表位之间的距离为默认的两倍. 要自定义制表位, 请指定字母 T 多次, 如下例所示: MyGui.Add("Edit", "vMyEdit r16 t8 t16 t32 t64 t128"). 在列表中每个绝对的列位置设置一个制表位, 制表位数目最大可达 50 个. 注意: 制表位仅用于多行编辑控件.

Uppercase: 将用户输入的字符自动转换成大写形式.

WantCtrlA: 指定 -WantCtrlA(负 WantCtrlA) 来阻止用户按下 Ctrl+A 来选择编辑控件中所有文本.

WantReturn: 指定 -WantReturn(负 WantReturn) 来阻止多行编辑控件捕获 Enter. 按下 Enter 相当于点击了窗口的默认按钮(如果有). 在这种情况下, 用户可以使用 Ctrl+Enter 来开始新行.

WantTab: 使得 Tab 键击产生制表符而不是导航到下一个控件. 如果没有这个选项, 则在多行编辑控件中用户可以按下 Ctrl+Tab 来产生制表符. 注意: WantTab 也可以用于单行编辑控件.

Wrap: 指定 -Wrap(负 Wrap) 来关闭多行编辑控件中的自动换行属性. 由于在控件创建后不能改变此样式, 所以需要使用下列方法中的一个来改变它:: 1) Destroy 后重新创建窗口和其中的控件; 或 2) 创建两个重叠的编辑控件, 其中一个启用自动换行而另一个禁用. 当前没有使用的那个可以保持空的和/或隐藏.

请参阅常规选项来了解其他选项, 例如 Right, Center 和 Hidden. 另请参阅: 控件的位置和大小.

更强大的编辑控件: HiEdit 是免费, 多选项卡, 支持大文件且消耗很少内存的编辑控件. 它可以编辑文本和二进制文件. 有关详情和演示, 请参阅 HiEdit on GitHub.

GroupBox

描述: 一个矩形的框, 常用来封装一组相关的控件. 此时最后一个参数为分组框的标题, 其(如果存在) 显示在分组框的左上角.

例如:

MyGui.Add("GroupBox", "w200 h100", "Geographic Criteria")

或者:

MyGui.AddGroupBox("w200 h100", "Geographic Criteria")

外观:

默认情况下, 分组框的标题可以只有一行文本. 在 Options 中指定 Wrap 可以改变此特性.

要指定控件中的行数(或高度和宽度), 请参阅控件的位置和大小.

Hotkey

描述: 一个看起来像单行编辑控件的框, 但它接受用户按下的按键组合. 例如, 在英语键盘布局的系统中如果用户按下 Ctrl+Alt+C, 那么此框中将显示 "Ctrl + Alt + C".

例如:

MyGui.Add("Hotkey", "vChosenHotkey")

或者:

MyGui.AddHotkey("vChosenHotkey")

外观:

GuiControl.Value 返回控件的热键修饰符和名称, 与热键函数兼容. 例如: ^!C, +!Home, +^Down, ^Numpad1, !NumpadEnd. 如果控件中没有热键, 则该值为空白.

注意: 一些按键即使它们作为不同的名称获取也显示为相同的名称. 例如, ^Numpad7 和 ^NumpadHome 都可能显示为 Ctrl + Num 7.

默认情况下, 控件在初始时不含有热键. 要让控件含有默认的热键, 请在最后一个参数中指定热键修饰符和按键名称, 如此例所示: MyGui.Add("Hotkey", "vChosenHotkey", "^!p"). 支持的修饰符仅包含 ^(Control), !(Alt) 和 +(Shift). 请参阅按键列表了解可用的按键名称.

每当用户改变控件的内容时(通过按键), 则将触发 Change 事件.

注意: 即使存在不完整的热键, 该事件也会被触发. 例如, 如果用户按住 Ctrl, 该事件就会被触发一次, GuiControl.Value 只返回一个抑扬符(^). 当用户完成热键时, 事件再次被触发, GuiControl.Value 返回完整的热键.

要限制用户可以使用的热键类型, 请在选项中包含单词 Limit 接着一个或多个下列数字的和:

  • 1: 阻止不带有修饰符的按键
  • 2: 仅阻止 Shift
  • 4: 仅阻止 Ctrl
  • 8: 仅阻止 Alt
  • 16: 阻止 Shift+Ctrl
  • 32: 阻止 Shift+Alt
  • 64: 不支持这个值(它不会正确执行).
  • 128: 阻止 Shift+Ctrl+Alt.

例如, Limit1 将阻止输入不带修饰符的热键(例如单独的字母和数字), 而 Limit15 则要求至少有两个修饰键. 如果用户输入了被禁止的修饰键组合, 则自动使用 Ctrl+Alt 组合代替.

Hotkey 控件对热键的支持有限. 例如, 它不支持鼠标/控制器热键或 Win(LWin 和 RWin). 解决此问题的一种方法是提供一个或多个 checkbox 作为用户启用额外的修饰键的工具, 如 Win.

Link

描述: 一个可以包含类似于网络浏览器中的链接的文本控件. 在控件的文本中, 将链接文本包含在 <A> 和 </A> 中, 以创建一个可点击的链接. 虽然这看起来像 HTML, 但 Link 控件只支持左 <A> 标签(可选择使用 ID 和/或 HREF 属性) 和右</A> 标签.

例如:

MyGui.Add("Link",, 'This is a <a href="https://www.autohotkey.com">link</a>')
MyGui.Add("Link",, 'Links may be used anywhere in the text like <a id="A">this</a> or <a id="B">that</a>')

或者:

MyGui.AddLink(, 'This is a <a href="https://www.autohotkey.com">link</a>')
MyGui.AddLink(, 'Links may be used anywhere in the text like <a id="A">this</a> or <a id="B">that</a>')

外观:

每当用户点击一个链接, 就会触发 Click 事件. 如果控件没有 Click 回调(通过调用 OnEvent 注册), 链接的 HREF 会自动执行, 就像传递给 Run 函数一样.

Gui := Gui()
LinkText := 'Click to run <a href="notepad" id="notepad">Notepad</a> or open <a id="help" href="https://www.autohotkey.com/docs/">online help</a>.'
Link := MyGui.Add("Link", "w200", LinkText)
Link.OnEvent("Click", Link_Click)
Link_Click(Ctrl, ID, HREF)
{
    MsgText := Format("
    (
        ID: {1}
        HREF: {2}

        Execute this link?
    )", ID, HREF)
    if MsgBox(MsgText,, "y/n") = "yes"
        Run(HREF)
}
MyGui.Show()

ListBox

描述: 一个包含选择列表的较高的框. 此时, Gui.Add 的最后一个参数是像 ["Choice1", "Choice2", "Choice3"] 这样的数组.

例如:

MyGui.Add("ListBox", "r5 vColorChoice", ["Red", "Green", "Blue", "Black", "White"])

或者:

MyGui.AddListBox("r5 vColorChoice", ["Red", "Green", "Blue", "Black", "White"])

外观:

要在窗口第一次出现时预选其中一个项目, 请在 Options 中加入单词 Choose 后面紧跟着要预选的项目编号. 例如, Choose5 会预选第五项. 若要预选多个项目, 可多次使用 GuiControl.Choose(需要 Multi 选项). 在控件创建后, 请使用 GuiControl.Value, GuiControl.Text 或 GuiControl.Choose 来改变选择, 和使用 GuiControl.Add 或 GuiControl.Delete 来添加或移除列表中的条目.

如果没有 Multi 选项, GuiControl.Value 返回当前所选项目的位置编号(第一个项目为 1, 第二个项目为 2, 等等.), 如果没有选择项目, 则返回 0, 而 GuiControl.Text 返回当前所选项目的文本. 如果使用 Multi 选项, GuiControl.Value 和 GuiControl.Text 将返回一个项目数组, 而不是单个项目.

Gui.Submit 存储 GuiControl.Text, 除非控件的 Options 中有 AltSubmit, 在这种情况下, 存储 GuiControl.Value.

每当用户选择或取消选择一个或多个项目时, 就会触发 Change 事件. 同时也支持 DoubleClick, Focus 和 LoseFocus 事件.

当在 ListBox 中添加大量的项目时, 在操作之前使用 MyListBox.Opt("-Redraw"), 在操作之后使用 MyListBox.Opt("+Redraw"), 可以提高性能. 有关详情, 请参阅 Redraw.

ListBox 选项

Choose: 请参阅上面.

Multi: 允许使用 shift-click 和 control-click 同时选择多个项目(如果不希望使用 shift/control-click, 请指定数字 8 代替单词 Multi). 此时, Gui.Submit 或 GuiControl.Value 返回一个选定位置编号的数组. 例如, [1, 2, 3] 表示前三个项目被选中. 如果要得到一个选定的文本数组, 可以使用 GuiControl.Text. 要从数组中提取单个项目, 使用 MyListBox.Text[1](1 是第一个项目) 或 For-loop 如下例所示:

For Index, Field in MyListBox.Text
{
    MsgBox "Selection number " Index " is " Field
}

ReadOnly: 对选择的项目不进行高亮显示(但 Gui.Submit, GuiControl.Value 或 GuiControl.Text 仍会返回选择的项目).

Sort: 按字母顺序自动排列列表的内容(这也会影响后面通过 GuiControl.Add 添加的所有项目). Sort 选项还会启用增量搜索; 这使得可以通过输入一个项目名称的前几个字符来选择此项.

T n: 字母 T 可以用来设置制表位, 它可以把文本格式成列. 如果没有使用字母 T, 则每 32 个对话框单位设置一次制表位(每个 "对话框单位" 的宽度由操作系统决定). 如果仅使用一次字母 T, 则每 n 个单位设置一次横跨整个控件宽度的制表位. 例如, MyGui.Add("ListBox", "vMyListBox t64") 将设置制表位之间的距离为默认的两倍. 要自定义制表位, 请指定字母 T 多次, 如下例所示: MyGui.Add("ListBox", "vMyListBox t8 t16 t32 t64 t128"). 在列表中每个绝对的列位置设置一个制表位, 制表位数目最大可达 50 个.

0x100: 在 Options 中包含 0x100 来打开 LBS_NOINTEGRALHEIGHT 样式. 此选项强制 ListBox 准确符合指定的高度而不是适应于避免在底部的行只显示一部分的高度. 此选项也避免了其字体改变时 ListBox 缩小的情况.

要指定文本的行数(或高度和宽度), 请参阅控件的位置和大小.

ListView

ListView 是由操作系统提供的最精心设计的控件之一. 在其最容易识别的形式中, 它显示一个多行多列组成的表格视图, 最常见的例子是资源管理器的文件和文件夹列表(详细信息视图).

例如:

MyGui.Add("ListView", "r20 w700", ["Name", "In Folder", "Size (KB)", "Type"])

或:

MyGui.AddListView("r20 w700", ["Name", "In Folder", "Size (KB)", "Type"])

外观:

有关详情, 请参阅 ListView 的单独页面.

MonthCal

描述: 一个又高又宽的控件, 其中以日历的格式显示一个月中的所有日子. 用户可以选择单个日期或日期范围.

例如:

MyGui.Add("MonthCal", "vMyCalendar")

或者:

MyGui.AddMonthCal("vMyCalendar")

外观:

要预选今天外的其他日期, 请在最后一个参数中指定 YYYYMMDD 格式的日期(例如 20050531). 通过在两个日期间包含破折号可以预选一个日期范围(例如 "20050525-20050531").

通常最好忽略 MonthCal 的宽度(W) 和高度(H), 这样它会自动调整大小来准确适应一个月份. 要垂直地显示多个月份, 请在 Options 中指定 R2 或更高. 要水平地显示多个月份, 请指定 W-2(W 负 2) 或更高. 这两个选项可以同时出现, 此时会在两个方向上扩展.

可以点击控件底部的今日字符串来选择今天的日期. 此外, 还可以点击年份和月份名称来方便地选择新的月份或年份.

键盘导航: 在 MonthCal 中完全支持键盘导航, 但只有当它具有键盘焦点时才支持. 有关支持的键盘快捷方式, 请参阅 DateTime 的键盘导航(带有下拉日历).

当使用 Gui.Submit 或 GuiControl.Value 时, 返回值是所选的以 YYYYMMDD 格式表示的日期(没有任何时间部分). 但是, 存在多选选项时, 会得到以破折号连接的最小和最大日期(例如 20050101-20050108). 在可以多选的日历中如果仅选择单个日期, 则最小和最大日期都会存在但它们是相同的. 可以使用 StrSplit 来分隔日期. 例如, 下面将把最小值放在 Date[1] 中, 最大值放在 Date[2] 中: Date := StrSplit(MyMonthCal.Value, "-").

当用户更改选择时, 将触发更改事件.

指定 YYYYMMDD 格式的日期时, MM 和/或 DD 部分可以省略, 此时它们默认为 1. 例如, 200205 被视为 20020501, 而 2005 被视为 20050101.

MonthCal 选项

Multi: 多选. 允许用户使用 shift-click 或 click-drag 来选择一个连续的日期范围(此时用户仍然可以选择单个日期). 可以明确指定此选项或在创建控件时通过指定一个选择范围的方法来让此选项自动生效. 例如: MyGui.Add("MonthCal", "vMyCal", "20050101-20050108"). 控件创建后无法改变此选项.

Range: 限制日历中可以选择的时间范围. 在单词 Range 后指定以 YYYYMMDD 格式表示的最小和最大的日期(它们之间使用破折号连接). 例如, Range20050101-20050615 将限制选区为 2005 年的前 5 个半月. 最小或最大的日期可以省略, 此时日历中在这个方向上的日期不受限制. 例如, Range20050101-20050615 将禁止选择早于 2001 年的日期而 Range-20091231(有前导的破折号) 将禁止选择迟于 2009 年的日期. 如果不含 Range 选项, 则可以选择介于 1601 和 9999 年份之间的任何日期.

4: 在 Options 中指定数字 4 来在每行日期的左边显示周数(1-52). 星期编号由操作系统的用户本地设置决定. LOCALE_IFIRSTWEEKOFYEAR 的文档中描述了三种可能的模式.

8: 在 Options 中指定数字 8 来禁止控件中当前日期往复循环.

16: 在 Options 中指定数字 16 来禁止在控件的底部显示今天的日期.

Colors: 日历中天数的颜色由 Gui.SetFont 或 c(Color) 选项设置. 要改变日历其他部分的颜色, 如下例所示:

SendMessage 0x100A, 5, 0xFFAA99, "SysMonthCal321" ; 0x100A 为 MCM_SETCOLOR. 5 为 MCSC_TITLETEXT(标题文本颜色). 颜色必须以 BGR 格式指定, 而不是 RGB 格式(红蓝分量互换).

Picture(或 Pic)

描述: 包含图像的区域(请参阅最后两段来了解支持的文件类型). 最后一个参数是图像的文件名, 如果未指定绝对路径, 则假定在 A_WorkingDir 中.

例如:

MyGui.Add("Picture", "w300 h-1", "C:\My Pictures\Company Logo.gif")

或者:

MyGui.AddPicture("w300 h-1", "C:\My Pictures\Company Logo.gif")

要保持图像的实际宽度和/或高度, 请省略 W 和/或 H 选项. 否则, 缩放图像的尺寸到指定的宽度和/或高度(此宽度和高度也决定了从多图标的 .ICO 文件中加载哪个图标). 要保持高宽比来缩放图像, 请在其中一个尺寸中指定 -1 而在另一个中指定正数. 例如, 指定 "w200 h-1" 将缩放图像到 200 像素的宽度同时自动设置其高度. 如果图片无法加载或显示(例如找不到文件), 则抛出一个错误并且控件不会被添加.

Picture(图片) 控件支持 Click 和 DoubleClick 事件, 其注意事项与 Text 控件相同.

要使用图片作为其他控件的背景, 则应该在其他控件之前正常添加图片. 然而, 如果这些控件是可输入型且此图片控件含有 SS_NOTIFY 样式(可能由 OnEvent 自动添加), 则在其他控件之后创建图片, 并在图片的 Options 中包含 0x4000000(即 WS_CLIPSIBLINGS). 这个技巧还可以让图片成为 Tab 控件或 ListView 后面的背景.

图标, 光标和动画光标: 图标和光标可以从下列类型的文件中加载: ICO, CUR, ANI, EXE, DLL, CPL, SCR 以及包含图标资源的其他类型. 要使用文件中的图标组而不是首个图标, 请在 Options 包含单词 Icon 和图标组编号. 在下面的例子中, 将使用第二个图标组中的默认图标: MyGui.Add("Picture", "Icon2", "C:\My Application.exe").

在 Options 中指定单词 AltSubmit 会让程序使用微软的 GDIPlus.dll 来加载图像, 这可能让 GIF, BMP 和图标图像产生不同的外观. 例如, 它可以把含透明背景的 ICO/GIF 作为透明的位图进行加载, 这样允许 BackgroundTrans 选项生效(但图标支持透明而无需 AltSubmit).

在不使用 GDIPlus 的情况下, 支持的格式包括 GIF, JPG, BMP, ICO, CUR 和 ANI 图像. GDIPlus 默认用于其他图像格式, 如 PNG, TIF, Exif, WMF 和 EMF.

动态 GIFs: 虽然 GIF 动画文件可以显示在图片控件中, 但实际上它们并不会动起来. 要解决此问题, 请使用 AniGIF DLL(对非商业用途免费), 演示的例子请参阅 AutoHotkey 论坛. 此外, 可以使用 ActiveX 控件类型. 例如:

; 指定下面的路径到 GIF 文件以实现动态效果(也允许使用本地文件):
pic := "http://www.animatedgif.net/cartoons/A_5odie_e0.gif"
MyGui := Gui()
MyGui.Add("ActiveX", "w100 h150", "mshtml:<img src='" pic "' />")
MyGui.Show()

位图或图标的句柄可完全替代文件名使用. 例如, "HBITMAP:" handle.

Progress

描述: 一个双彩条, 通常用来指示一个操作接近完成的程度.

例如:

MyGui.Add("Progress", "w200 h20 cBlue vMyProgress", 75)

或者:

MyGui.AddProgress("w200 h20 cBlue vMyProgress", 75)

外观:

在最后一个参数中指定进度条的初始位置(如果省略, 则进度条的初始位置为 0 或允许的范围中最接近 0 的数字). 之后要改变进度条的位置, 请参照下面的例子, 所有这些都是在一个名称为 MyProgress 的进度条上操作:

MyGui["MyProgress"].Value += 20  ; 增加 20 到当前位置.
MyGui["MyProgress"].Value := 50  ; 设置当前位置为 50.

对于水平进度条, 进度条的厚度等于控件的高度. 对于垂直进度条它等于控件的宽度.

Progress 选项

C n: 改变进度条的颜色. 指定 n 为 16 种 HTML 基础颜色之一或 6 位的 RGB 颜色值. 例如: cRed, cFFFF33, cDefault. 如果从没有使用过 C 选项(或指定了 cDefault), 则使用系统默认的进度条颜色.

>Background N: 改变进度条的背景颜色. 指定 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: 显示一个简单的连续条. 如果不使用该选项, 并且进度条没有任何自定义颜色, 则进度条的外观由当前系统主题定义. 否则, 进度条将显示为一段段的长度.

Vertical: 让进度条垂直上升或下降而不是水平移动.

在控件创建后, 可以使用 GuiControl.Opt 来改变上面的选项.

Radio

描述: 单选按钮是一个小空圆, 可以被选中(打开) 或不选中(关闭).

例如:

MyGui.Add("Radio", "vMyRadioGroup", "Wait for all items to be in stock before shipping.")

或者:

MyGui.AddRadio("vMyRadioGroup", "Wait for all items to be in stock before shipping.")

外观:

这些控件经常出现在 单选按钮组 中, 每组包含两个或多个单选按钮. 当用户点击一个单选按钮来打开它时, 其所在的单选按钮组中其他所有的单选按钮会自动关闭(在单选按钮组中用户也可以使用方向键导航). 在所有连续添加的单选按钮周围会自动创建一个单选按钮组. 要开始一个新组, 请在新组的首个单选按钮的 Options 中指定单词 Group -- 或者在新组和之前的组之间简单地添加一个非单选按钮控件, 因为这样会自动开始一个新组.

在最后一个参数中指定的标注会显示在单选按钮的右侧. 此标注通常作为提示或描述, 它可以包含换行符(`n) 来开始新行. 如果在 Options 中指定了宽度(W) 而没有指定行数(R) 或高度(H), 那么在需要时控件的文本将自动换行, 同时自动设置控件的高度.

在 Options 中指定单词 Checked 来让按钮初始为选中状态. 可以在单词 Checked 后紧跟着 0 或 1 来表示初始状态: 0 表示未选中, 而 1 表示选中. 换句话说, "Checked" 和 "Checked" VarContainingOne 是一样的.

GuiControl.Value 返回数字 1 表示 "on", 0 表示 "off". 如果要在单选组中检索所选单选选项的位置号, 只需命名其中一个单选按钮, 然后使用 Gui.Submit.

每当用户打开按钮时, 就会触发 Click 事件. 与前一段的单变量模式不同, 事件回调必须为单选组中的每个按钮注册, 并为其调用. 这样就可以灵活地忽略某些按钮的点击.

同时也支持 DoubleClick, Focus 和 LoseFocus 事件. 由于这些事件只有在控件具有 BS_NOTIFY(0x4000) 样式时才会被触发, 所以它是由 OnEvent 自动添加的.

已知限制: 某些桌面主题可能无法正确的显示 checkbox 的文本. 如果遇到此情况, 请尝试在控件的选项中包含 -Wrap(负 Wrap). 不过这样也使得按钮名称中无法包含多行文本.

Slider

描述: 一个滑动栏, 用户可以让它沿着垂直或水平轨道移动. 滑动栏的一个常见的例子是在任务栏托盘中的标准音量控件.

例如:

MyGui.Add("Progress", "w200 h20 cBlue vMyProgress", 75)

或者:

MyGui.AddProgress("w200 h20 cBlue vMyProgress", 75)

外观:

请在最后一个参数中指定滑动栏的初始位置. 如果最后一个参数省略, 则滑动栏初始位置为 0 或允许的范围中最接近 0 的数字.

用户可以通过下列方法滑动控件: 1) 使用鼠标拖拉滑动栏; 2) 用鼠标在滑动栏的轨道区域点击; 3) 当焦点在控件上时转动鼠标滚轮; 或 4) 当焦点在控件上时使用下列键: ↑, →, ↓, ←, PgUp, PgDn, Home 和 End.

GuiControl.Value 和 Gui.Submit 返回或存储滑块的当前数值位置.

检测变化

默认情况下, 当用户停止移动滑块时, 例如在拖动滑块后释放鼠标按钮, 就会触发滑块的 Change 事件. 如果控件有 AltSubmit 选项, 那么当用户用鼠标拖动滑块时, 每次滑块的可见移动后, 也将触发 Change 事件(非常频繁).

Ctrl_Change(GuiCtrlObj, Info)
Info

类型: 整数

下面的表格中的数值, 表示滑块的移动方式. 这些值和相应的名称在 Windows SDK 中定义了.

值 | 名称 | 意义
0 | TB_LINEUP | 用户按下了 ← 或 ↑ 键.
1 | TB_LINEDOWN | 用户按下了 → 或 ↓ 键.
2 | TB_PAGEUP | 用户按下了 PgUp 键.
3 | TB_PAGEDOWN | 用户按下了 PgDn 键.
4 | TB_THUMBPOSITION | 用户用鼠标滚轮移动了滑块或已经把滑块拖放到新的位置.
6 | TB_TOP | 用户按下了 Home 键来移动滑块到左端或顶部.
7 | TB_BOTTOM | 用户按下了 End 键来移动滑块到右端或底部.

仅当使用 AltSubmit 选项时:

值 | 名称 | 意义
5 | TB_THUMBTRACK | 用户正用鼠标拖动滑块, 即鼠标按钮当前是按住的.
8 | TB_ENDTRACK | 用户已经使用鼠标或键盘移动了滑块. 注意: 除了鼠标滚轮移动(#4) 之外, Change 事件在 #8 中再次被触发, 尽管它已经被上面的一个数字触发了.

Slider 选项

Buddy1 和 Buddy2: 最多可以指定两个现有的控件来自动定位到滑动条的两侧. Buddy1 显示在左边或顶部(取决于是否存在 Vertical 选项). Buddy2 显示在右侧或底部. 在单词 Buddy1 或 Buddy2 后指定现有控件的名称或 HWND. 例如, Buddy1MyTopText 将分配变量名为 MyTopText 的控件. 控件的文本或 ClassNN 也能使用, 但只到第一个空格或制表符.

Center: 滑块(用户移动的滑动栏) 两端将是钝的而不指向其中一端.

Invert: 反转控件, 把较低值作为右边/底端而不是左边/顶端. 此选项常用来让垂直滑动栏在传统的音量控件方向上移动. 注: 下面描述的工具提示选项不会遵循反转, 因此此时不应该使用.

Left: 滑块(用户移动的滑动栏) 将指向上方而不是下方(原文中为顶端和底端, 这里用上/下放是为了避免和滑动栏的顶端/底端混淆). 但如果存在 Vertical 选项, 则滑块将指向左边而不是右边.

Line: 指定当用户按下其中一个方向键时要移动位置的数目. 在单词 Line 后指定移动位置的数目. 例如: Line2.

NoTicks: 不在轨道旁边显示刻度标记.

Page: 指定当用户按下 PgUp 或 PgDn 键时移动位置的数目. 在单词 Page 后指定移动位置的数目. 例如: Page10.

Range: 使用 0 到 100 外的其他范围. 在单词 Range 后指定最小值, 破折号和最大值. 例如, Range1-1000 将允许选择一个介于 1 和 1000 之间的数字; Range-50-50 将允许介于 -50 和 50 之间的数字; 而 Range-10--5 将允许介于 -10 和 -5 之间的数字.

Thick: 指定滑块的长度. 在单词 Thick 后指定以像素为单位的厚度(例如 Thick30). 如果要超过一定的厚度, 可能需要指定 Center 选项或者从控件中删除主题(可以通过在控件的选项中指定 -Theme 来实现).

TickInterval: 在轨道旁边指定间隔的位置显示刻度标记. 在单词 TickInterval 后指定间隔来显示附加的刻度标记(如果省略从未设置, 则默认为 1). 例如, TickInterval10 将每隔 10 位置显示一个刻度标记.

ToolTip: 创建工具提示, 当用户拖动滑动栏时显示它的数字位置. 要让工具提示不显示在默认位置, 请指定下列单词的其中一个代替: ToolTipLeft 或 ToolTipRight(对于水平滑动条); ToolTipTop 或 ToolTipBottom(对于水平滑动条).

Vertical: 让控件上下滑动而不是左右滑动.

在控件创建后, 可以使用 GuiControl.Opt 来改变上面的选项.

StatusBar

描述: 附加到窗口底部的一行文本和/或图标, 通常用来报告状态的变化.

例如:

SB := MyGui.Add("StatusBar",, "Bar's starting text (omit to start off empty).")
SB.SetText("There are " . RowCount . " rows selected.")

或者:

SB := MyGui.AddStatusBar(, "Bar's starting text (omit to start off empty).")
SB.SetText("There are " . RowCount . " rows selected.")

外观:

状态栏最简单的用法是每当应该报告给用户一些状态改变时调用 SetText 方法. 要报告多片的信息, 请使用 SetParts 方法把状态栏分成多段. 要在状态栏中显示图标, 请调用 SetIcon 方法.

StatusBar 方法

SetText

在状态栏指定部分显示 NewText.

SB.SetText(NewText , PartNumber, Style)

参数

NewText

类型: 字符串

在 NewText 中的任意地方可以使用最多两个两个制表符(`t): 第一个制表符右边的任何东西在该部分中居中, 而第二个制表符右边的任何东西是右对齐的.

PartNumber

类型: 整数

如果省略, 则默认为 1. 否则, 请指定介于 1 和 256 之间的整数.

Style

类型: 整数

如果省略, 则默认为 0, 此时使用让状态栏那部分看起来凹陷的传统边界. 否则, 指定 1 为无边框, 2 为带边框, 让状态栏看起来是凸起的.

SetParts

根据指定的宽度(单位为像素) 把状态栏分成多个部分.

SB.SetParts(Width1, Width2, ... Width255)

参数

Width1 ... Width255

类型: 整数

如果省略所有参数, 则状态栏恢复为只有一个很长的部分. 否则, 指定除了最后一部分外的其他每个部分的宽度(最后一部分将填充状态栏的剩余宽度). 例如, SB.SetParts(50, 50) 将创建三个部分: 前两个部分的宽度都为 50, 而最后一部分占据剩余的所有宽度.

返回值

类型: 整数

这个方法返回状态栏的窗口句柄(HWND). 控件的 HWND 通常与 PostMessage, SendMessage 和 DllCall 一起使用. 它也可以直接用于 Control 参数.

备注

通过该方法 "删除" 的任何部分下次显示时都不会显示文本(而且它们的图标会自动销毁).

SetIcon

在指定部分的文本左边显示一个小图标.

SB.SetIcon(FileName , IconNumber, PartNumber)

参数

FileName

类型: 字符串

图标或图像文件的路径, 或位图或图标句柄, 如 SB.SetIcon("HICON:" handle). 关于支持的格式列表, 请参阅图片控件.

IconNumber

类型: 整数

如果省略, 默认为 1(第一图标组). 否则, 请指定文件中使用的图标组编号. 例如, SB.SetIcon("Shell32.dll", 2) 将使用第二个图标组中的默认图标. 如果为负数, 则假定其绝对值表示可执行文件中图标的资源 ID.

PartNumber

类型: 整数

如果省略, 则默认为 1. 否则, 请指定介于 1 和 256 之间的整数.

返回值

Type: Integer

这个方法返回图标的句柄(HICON). HICON 是一种系统资源, 大多数脚本可以安全地忽略它, 因为当状态栏的窗口被销毁时它会被自动销毁. 类似地, 当此方法用新图标替换旧图标时, 旧图标将被销毁. 这可以通过以下方式避免:

SendMessage(0x040F, PartNumber - 1, HICON, SB)  ; 0x040F is SB_SETICON.

StatusBar 的使用

对鼠标点击做出反应: 每当用户点击状态栏时, Click, DoubleClick 或 ContextMenu 事件都会被触发, Info 或 Item 参数包含状态栏部分的编号. 但是, 如果用户点击状态栏右边靠近大小调整手柄的地方时, 目标部分的编号可能是很大的整数.

字体和颜色: 尽管字体大小, 外观和样式可以使用 MyGui.SetFont 来设置(像普通控件一样), 但是无法改变文本颜色. 状态栏的背景颜色可以通过在 Options 中指定单词 Background 后紧跟颜色名称(请参阅颜色表) 或 RGB 值(0x 前缀是可选的). 例如: BackgroundSilver, BackgroundFFDD99, BackgroundDefault. 注意, 控件必须具有经典主题外观. 因此, -Theme 选项必须与 Background 选项一起指定, 例如 -Theme BackgroundSilver.

隐藏状态栏: 创建时, 可以使用 SB := MyGui.Add("StatusBar", "Hidden") 隐藏状态栏. 要在创建后某个时候隐藏它, 请使用 SB.Visible := false. 要显示, 请使用 SB.Visible := true. 注意: 隐藏状态栏不会降低窗口的高度. 如果希望这样, 一个简便的方法是 Gui.Show("AutoSize").

样式(很少使用): 请参阅状态栏样式表.

已知限制: 1) 如果某个控件的位置和状态栏重叠, 那么它有可能会被绘制在状态栏的上方. 避免这种情况的一种方法是通过 Size 事件动态地缩小这样的控件. 2) 位置和尺寸选项被忽略. 3) 每个窗口只允许有一个状态栏控件.

示例: 示例 #1 在 TreeView 页面底部演示了一个多部分的状态栏.

Tab3 / Tab2 / Tab

描述: 一个包含多个页面的大型控件, 其中每个页面包含其他控件. 从这里开始, 这些页面被称为 "选项卡(标签页)".

选项卡控件有以下三种类型:

  • Tab3: 修复若干影响 Tab2 和 Tab 的问题. 各控件位于一个可见的 "标签页对话框", 其位置和大小随选项卡控件的移动和大小的改变而改变. 选项卡控件使用默认主题.
  • Tab2: 修正了原有 "Tab" 控件罕见的重绘问题, 但是引入了一些其他问题.
  • Tab: 保留向后兼容性, 因为在 Tab2/Tab3 和 Tab 之间有着行为差异.

例如:

MyGui.Add("Tab3",, ["General", "View", "Settings"])

或者:

MyGui.AddTab3(, ["General", "View", "Settings"])

外观:

上面的最后一个参数是一个标签页名称的数组. 创建 Tab 控件后, 随后添加的控件自动属于其第一个选项卡. 要更改这一点, 请使用下面的 UseTab 方法. 有关详细信息和示例, 请参阅 Tab 的用法.

Tab 方法

UseTab

指定随后创建的控件将被添加到的选项卡.

Tab.UseTab(Value, ExactMatch)

参数

Value

类型: 整数或字符串

如果为空或省略, 则默认为 0, 随后的创建的控件将被添加到 Tab 控件之外. 否则, 指定 1 表示第一个选项卡, 2 表示第二个, 等等.

如果 Value 字符串(即使是数字字符串), 前面部分与 Value 匹配的标签将被使用. 搜索不区分大小写. 例如, 如果一个控件包含 "UNIX Text" 标签, 指定单词 unix(小写) 就可以使用它. Use ExactMatch to change this matching behavior.

ExactMatch

类型: 布尔值

如果省略, 则默认为 false

如果为 false, 则使用其前导名称部分与 Value 匹配的选项卡.

如果为 true, Value 必须完全匹配(不区分大小写).

Tab 的用法

要在窗口初次出现时预选其中的某个选项卡, 请在 Options 中包含单词 Choose 紧跟着想预选的选项卡的编号. 例如, Choose5 会预选第五个选项卡(和其他选项一样, 它也可以为变量, 例如 "Choose" Var. 要在控件创建后改变选择的选项卡, 请使用 GuiControl.Value, GuiControl.Text 或 GuiControl.Choose, 而 GuiControl.Add 和 GuiControl.Delete 来添加或删除选项卡.

创建选项卡控件后, 随后添加的控件自动属于其首个选项卡. 这可以通过使用 href="#Tab_UseTab">UseTab 方法随时更改, 如下所示(在本例中, Tab 是第一个选项卡控件的 GuiControl 对象, 而 Tab2 是第二个标签控件的):

Tab.UseTab()  ; 随后的控件不属于任何选项卡控件的一部分.
Tab.UseTab(3)  ; 随后的控件属于当前选项卡控件的第三个选项卡.
Tab2.UseTab(3)  ; 随后的控件属于第二个选项卡控件的第三个选项卡.
Tab.UseTab("Name")  ; 随后的控件属于名称以 Name(不区分大小写) 开始的选项卡.
Tab.UseTab("Name", true)  ; 与上面相同, 不过这里需要准确匹配(并区分大小写).

还可以使用上面的每个例子分配控件到还不存在的选项卡或选项卡控件(不包括使用 Name 方法的情况). 但在此情况下, 不支持下面描述的相对位置选项.

位置: 当一个选项卡控件的每个选项卡接收到其首个子控件, 此子控件在下列情况下将具有特殊的默认位置: 1) 同时省略 X 和 Y 坐标, 此时首个子控件放在选项卡控件内部的左上角(带有标准的边距), 而首个子控件后的其他子控件放在之前控件的下面; 2) 指定了 X+n 和/或 Y+n 位置选项, 此时子控件放在相对于选项卡控件内部的左上角的位置. 例如, 指定 x+10 y+10 会把控件放置在左上角往右和往下各 10 个像素的位置.

当前标签页: GuiControl.Value 返回当前选中的标签页的位置编号(第一个标签页是 1, 第一个标签页是 2, 等等.), 而 GuiControl.Text 返回当前所选项目的文本. MyGui.Submit 存储 GuiControl.Text, 但如果控件的 Options 中含有单词 AltSubmit, 则存储标签页的编号.

检测标签页选择: 每当用户切换标签页时, Change 事件就会被触发.

键盘导航: 用户可以按下 Ctrl+PgDn/PgUp 来在选项卡控件的页面间导航; 如果键盘焦点在不属于选项卡的控件上, 则会导航到窗口的首个选项卡控件. 也可以使用 Ctrl+Tab 和 Ctrl+Shift+Tab, 除非当前焦点控件在多行编辑控件中(此时它们不起作用).

限制: 每个窗口的选项卡控件不能超过 255 个. 每个选项卡控件不能含有超过 256 个选项卡(页面). 此外, 选项卡控件不能包含其他选项卡控件.

Tab3 vs. Tab2 vs. Tab

父窗口: 控件的父窗口影响控件的位置和可见性以及 Tab 键的导航顺序. 如果控件添加到已存在的 Tab3 选项卡控件, 其父窗口是 "tab dialog", 该父窗口填充选项卡控件的显示区域. 大部分其他控件, 包括 Tab 或 Tab2 中的子控件, 没有父窗口除了 Gui 界面本身.

位置: 对于 Tab 和 Tab2, 子控件不需要在他们的选项卡控件的边界内: 当标签页是激活或未激活时他们总是会显示和隐藏. 这种行为特别适合下面描述的 "按钮" 样式.

对于 Tab3, 在标签页控件创建之 前, 添加子控件的行为与 Tab 或 Tab2 是一致的. 所有其他子控件只在选项卡控件的显示区域内可见.

如果 Tab3 控件移动, 他的子控件也随之移动. Tab 和 Tab2 控件没有这个行为.

在极少数情况下, WinMove(或等效的 DllCall) 用于移动控件, 坐标必须相对于控件的父窗口, 而不是 Gui(参阅上面的信息)). 相比之下, GuiControl.Move 采用 GUI 坐标, ControlMove 采用窗口坐标, 与控件的父窗口无关.

自动尺寸: 如果脚本没有指定, 在下列情况下 Tab3 控件的宽度 和/或 高度将会自动计算(在控件创建后以先到者为准):

  • 第一次 Tab3 控件不再是当前标签页控件. 这可能是调用了 UseTab 方法(有或没有参数) 或创建另一个标签页控件所导致的.
  • 对于特定的 Gui, 首次调用 Gui.Show.

存在的子控件计算尺寸时, 自动调整的尺寸再加上默认边距. 尺寸只计算一次, 即使添加控件也不会重新计算. 如果 Tab3 控件是空的, 与 Tab 或 Tab2 控件相同的默认大小.

Tab 和 Tab2 控件不会自动计算尺寸; 它们接受任意默认大小.

Tab 键导航顺序: Tab 导航顺序通常取决于控件创建的顺序. 当选项卡控件激活时, 顺序也取决于选项卡控件的类型:

  • Tab 和 Tab2 允许其子控件与其他控件混合.
  • Tab2 将标签页按钮置于其子控件之后.
  • Tab3 的子控件组合在一起并置于标签页按钮之后.

通知消息(Tab3): 命令和自定义控件通常向他们的父窗口发送通知消息. Tab3 控件的 tab dialog 接收到的任何 WM_COMMAND, WM_NOTIFY, WM_VSCROLL, WM_HSCROLL 或 WM_CTLCOLOR 消息转发到 GUI 窗口和能被 OnMessage 检测. 如果标签页控件使用主题并且其子控件没有 +BackgroundTrans 选项, tab dialog 处理 WM_CTLCOLORSTATIC 消息而不转发. 其他的通知消息(例如自定义消息) 不被支持.

Tab2 选项卡控件的已知问题:

  • BackgroundTrans 在 Tab2 控件中没有效果.
  • WebBrowser 控件重绘不正确.
  • 动态窗口和其他的某些 Win32 API 调用导致其中的控件不显示.

Tab 选项卡控件的已知问题:

  • 通过单击界面窗口中的某个控件来激活界面窗口, 例如滚动条, 将会出现重绘不正确的情况.
  • 如果 Tab 控件包含 ListView 控件, BackgroundTrans 没有效果.
  • WebBrowser 控件不可见.

Tab 选项

Choose: 请参阅上面描述的内容.

Background: 指定 -Background(负 Background) 覆盖窗口的自定义背景颜色, 而使用系统默认的选项卡控件的颜色. 指定 +Theme -Background 来让选项卡控件适应于当前桌面主题. 然而, 在这样选项卡控件内的大多数类型的控件看起来会很奇怪, 因为它们的背景颜色不匹配选项卡控件的背景颜色. 对于某些类型的控件(例如 Text), 这种情况可以在它们的选项中添加 BackgroundTrans 来修复.

Buttons: 在控件的顶部创建一系列按钮而不是选项卡(此时在默认情况下将没有边界, 因为显示的区域实际并不包含控件).

Left/Right/Bottom: 指定这些单词的其中一个让选项卡显示在左边, 右边或底部而不是顶部. 请参阅 TCS_VERTICAL 了解对于 Left 和 Right 的限制.

Wrap: 指定 -Wrap(负 Wrap) 阻止选项卡占用多行(此时为了适应过多的选项卡, 会显示箭头按钮以允许用户滑动来查看更多选项卡).

要指定控件中文本的行数(或高度和宽度), 请参阅控件的位置和大小.

在选项卡中添加图标: 通过 SendMessage 可以在每个选项卡的名称/文本旁边显示图标. 演示的例子请参阅论坛主题 Icons in tabs.

Text

描述: 包含用户不能编辑的无边界文本的区域. 常用来标识其他控件.

例如:

MyGui.Add("Text",, "Please enter your name:")

或者:

MyGui.AddText(, "Please enter your name:")

外观:

此时最后一个参数为要显示的字符串. 它可以包含换行符(`n) 来开始新行. 此外, 一个长行可以使用延续片段的方法分成较短的几行.

如果 Options 中指定了宽度(W) 而没有指定行数(R) 或高度(H), 那么在需要时控件的文本将自动换行, 同时自动设置控件的高度.

若要检测用户单击文本, 请使用 Click(单击) 事件. 例如:

MyGui := Gui()
FakeLink := MyGui.Add("Text", "", "Click here to launch Google.")
FakeLink.SetFont("underline cBlue")
FakeLink.OnEvent("Click", LaunchGoogle)

; 或者可以使用 Link 控件:
MyGui.Add("Link",, 'Click <a href="www.google.com">here</a> to launch Google.')
MyGui.Show()

LaunchGoogle(*) {
    Run("www.google.com")
}

Text(文本) 控件也支持 DoubleClick(双击) 事件.

只有带有 SS_NOTIFY(0x100) 样式的文本控件才能发送单击和双击通知, 因此 OnEvent 在注册单击或双击回调时自动添加这种样式. SS_NOTIFY 样式会导致操作系统在双击控件时自动将其文本复制到剪贴板.

在文本中使用和符号(&) 可以让其中的某个字母带下划线. 例如:

MyGui.Add("Text",, "&First Name:")
MyGui.Add("Edit")

在上述示例中, 字母 F 将添加下划线, 这允许用户按下快捷键 Alt+F 将键盘焦点设置到此文本控件之后添加的首个可输入型控件中. 要显示一个文字的和符号(&), 请指定两个连续的和符号(&&). 要取消控件中和符号的特殊含义, 请在控件的选项中包含 0x80.

有关其他选项, 如 Right, Center 和 Hidden, 请参阅常规选项. 另请参阅: 控件的位置和大小.

TreeView

TreeView 通过缩进父项目下的子项目来显示出层级关系. 最常见的例子是资源管理器的驱动器和文件夹树.

例如:

MyGui.Add("TreeView", "r10")

或:

MyGui.AddTreeView("r10")

外观:

有关详情, 请参阅 TreeView 的单独页面.

UpDown

描述: 一对箭头组成的按钮, 用户点击后会增加或减少值. 默认情况下, UpDown 控件自动依附于前一个添加的控件上. 这里的前一个控件被称为 UpDown 的 伙伴控件. 最常见的例子是 "微调器", 由 UpDown 附加到 Edit 控件.

例如:

MyGui.Add("Edit")
MyGui.Add("UpDown", "vMyUpDown Range1-10", 5)

或者:

MyGui.AddEdit()
MyGui.AddUpDown("vMyUpDown Range1-10", 5)

外观:

在上面的例子中, Edit 控件是 UpDown 的伙伴控件. 每当用户按下了增减按钮的其中一个, Edit 控件中的数字会自动增加或减少.

UpDown 的伙伴控件也可以是 Text 控件或 ListBox. 然而, 由于操作系统的限制, 除了这些以外的其他控件类型(例如 ComboBox 和 DropDownList) 可能无法和 Change 事件以及其他特性一起正常工作.

在最后一个参数中指定 UpDown 的初始位置(如果省略, 则初始为 0 或允许的范围中最接近 0 的数字).

当使用 Gui.Submit 或 GuiControl.Value 时, 返回值是 UpDown 的当前数字位置. 如果 UpDown 与 Edit 控件相连, 而您又不想验证用户的输入, 那么最好使用 UpDown 的值而不是 Edit 的值. 这是因为 UpDown 总是会产生一个范围内的数字, 即使用户在编辑控件中输入了一些非数字或超出范围的数字. 与此相关的是, 超过三位数的数字默认会有一个千位分隔符(如逗号). 这些分隔符是由 Edit 控件返回的, 但不是由 UpDown 控件返回的.

每当用户点击一个箭头按钮或按下键盘上的一个箭头键时, 就会触发 Change 事件.

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 或 GuiControl.Value 可以正常获取此位置.

0x80: 在 Options 中包含 0x80 来省略伙伴控件中正常出现在每三位十进制数间的千位分隔符. 然而, 通常不使用此样式, 因为当脚本从 UpDown 控件(而不是其伙伴控件) 获取的数字中不包含分隔符.

使用 1 以外的其他增量: 在此脚本中, 演示了如何改变 UpDown 增量为 1 以外的其他值(例如 5 或 0.1).

十六进制数字格式: 在伙伴控件中显示的数字格式可以通过以下示例从十进制改为十六进制:

SendMessage 0x046D, 16, 0, "msctls_updown321" ; 0x046D 为 UDM_SETBASE

但是, 这只影响伙伴控件, 而不影响 UpDown 报告的位置.

另请参阅: 控件的位置和大小.

相关

ListView, TreeView, Gui(), Gui 对象, GuiControl 对象, Menu 对象


GuiCtrlFromHwnd - 语法 & 使用 | AutoHotkey v2

GuiCtrlFromHwnd

检索与指定的窗口句柄关联的 GUI 控件的 GuiControl 对象.

GuiControlObj := GuiCtrlFromHwnd(Hwnd)

参数

Hwnd

类型: 整数

GUI 控件的窗口句柄(HWND), 或控件的子窗口(例如 ComboBox 的 Edit 控件) 的窗口句柄. 该控件必须是由当前脚本通过 Gui.Add 创建的.

返回值

类型: Object 或字符串(空)

函数返回与指定的 HWND 相关联的 GuiControl 对象, 如果没有该对象或 HWND 无效, 则返回一个空字符串.

备注

例如, 能通过 GuiControl.Hwnd, MouseGetPos 或 OnMessage 来检索 GUI 控件的 HWND.

相关

Gui(), Gui 对象, GuiControl 对象, GuiFromHwnd, 控件类型, ListView, TreeView, Menu 对象, 控件函数, MsgBox, FileSelect, DirSelect

示例

请参阅 Gui 对象页面上的 ToolTip 示例.


GuiFromHwnd - 语法 & 使用 | AutoHotkey v2

GuiFromHwnd

检索与指定的窗口句柄关联的 Gui 窗口的 Gui 对象.

GuiObj := GuiFromHwnd(Hwnd , RecurseParent)

参数

Hwnd

类型: 整数

脚本先前创建的 GUI 窗口的窗口句柄(HWND), 或者如果 RecurseParent 为 true, 则脚本创建的 GUI 窗口的任何子窗口的窗口句柄.

RecurseParent

类型: 布尔值

如果该参数为 true, 并且 Hwnd 标识了一个不是 GUI 的子窗口, 该函数将搜索并检索其最近的 GUI 的父窗口. 否则, 如果 Hwnd 没有直接识别 GUI 窗口, 该函数返回一个空字符串.

返回值

类型: Object 或字符串(空)

函数返回与指定的 HWND 相关联的 Gui 对象, 如果没有该对象或 HWND 无效, 则返回一个空字符串.

备注

例如, GUI 窗口的 HWND 可以传递给 OnMessage 函数, 也可以通过 Gui.Hwnd, WinExist 或其他一些方法来检索.

相关

Gui(), Gui 对象, GuiControl 对象, GuiCtrlFromHwnd, Control 类型, ListView, TreeView, Menu 对象, 控件函数, MsgBox, FileSelect, DirSelect

示例

通过使用刚刚创建的 GUI 窗口的 HWND 检索 Gui 对象, 并报告其标题.

MyGui := Gui(, "Title of Window")
MyGui.Add("Text",, "Some text to display.")
MyGui.Show()

MsgBox(GuiFromHwnd(Gui.Hwnd).Title)


OnCommand (GUI) - 语法 & 使用 | AutoHotkey v2

OnCommand

注册一个函数或方法, 当通过 WM_COMMAND 消息接收到控件通知时调用.

GuiCtrl.OnCommand(NotifyCode, Callback , AddRemove)

参数

NotifyCode

类型: 整数

要监控的控件定义的通知代码.

Callback

类型: 字符串或函数对象

事件发生时要调用的函数, 方法或对象.

如果 GUI 有事件接收器(即, 如果指定了 Gui() 的 EventObj 参数), 那么这个参数可能是属于事件接收器的方法的名称. 否则, 这个参数必须是一个函数对象.

回调函数接受一个参数, 定义如下:

MyCallback(GuiCtrl) { ...

虽然你给参数的名字并不重要, 但它被赋值为当前 GUI 控件的 GuiControl 对象.

如果不需要相应的信息, 可以省略回调参数, 但在这种情况下必须指定星号, 例如 MyCallback(*).

The OnEvent 注释中关于 this 和绑定函数的内容也适用于 OnCommand.

I如果一个事件注册了多个回调函数, 则回调函数可能返回一个非空值, 以防止调用任何剩余的回调函数.

回调的返回值被 GUI 控件忽略.

AddRemove

类型: 整数

如果省略, 则默认为 1. 否则, 指定下列数字之一:

  • 1 = 在任何先前注册的回调之后调用回调.
  • -1 = 在任何先前注册的回调之前调用回调.
  • 0 = 不调用该回调.

WM_COMMAND

某些类型的控件在发生要监控事件时, 会发送一条 WM_COMMAND 消息. 这些通常是标准的 Windows 控件, 它们已经存在很长时间了, 因为新的控件使用 WM_NOTIFY 消息(请参阅 OnNotify). 常用的通知代码被转换成事件, 脚本可以用 OnEvent 来监视.

消息的参数包含控件 ID, HWND 和通知代码, AutoHotkey 使用这些参数将通知发送到相应的回调. 没有额外的参数.

要确定哪些通知可用(如果有的话), 请参阅控件的文档. Control Library (Microsoft Docs) 包含了每个 Windows 常用控件的链接(然而, 只有少数控件使用 WM_COMMAND). 通知代码(编号) 可以在 Windows SDK 中找到, 或者在互联网上搜索.

相关

OnEvent 的说明也适用于 OnCommand: 线程, 销毁 GUI.

OnNotify 可以用于作为 WM_NOTIFY 消息发送的通知.


OnEvent (GUI) - 语法 & 使用 | AutoHotkey v2

OnEvent

注册一个函数或方法, 当 GUI 窗口或控件发生给定事件时, 该函数或方法将被调用.

Gui.OnEvent(EventName, Callback , AddRemove)
GuiCtrl.OnEvent(EventName, Callback , AddRemove)

参数

EventName

类型: 字符串

事件的名称. 请参阅下面的 Events.

Callback

类型: 字符串或函数对象

事件发生时要调用的函数, 方法或对象.

如果 GUI 有事件接收器(即, 如果指定了 Gui() 的 EventObj 参数), 那么这个参数可能是属于事件接收器的方法的名称. 否则, 这个参数必须是一个函数对象.

有关参数, 返回值, 命名等详细信息, 请参阅以下章节.

AddRemove

类型: 整数

如果省略, 则默认为 1. 否则, 指定下列数字之一:

  • 1 = 在任何先前注册的回调之后调用回调.
  • -1 = 在任何先前注册的回调之前调用回调.
  • 0 = 不调用该回调.

Callback 参数

如果回调是按名称注册的方法, 其隐藏的 this 参数无缝事件接收器对象(即该方法所属的对象). 这个参数在本文档的参数列表中没有显示.

由于 Callback 可以是一个对象, 它可以是一个 BoundFunc 对象, 在参数列表的开头插入额外的参数, 然后调用另一个函数. 这是一种通用的技术, 不是 OnEvent 所特有的, 所以一般被本文档的其他部分忽略.

回调的第一个显式参数是触发事件的 Gui 或 GuiControl 对象. 唯一的例外是, 当 Gui 处理自己的事件时, this 参数会被省略, 因为 this 已经包含了对 Gui 的引用.

许多事件都传递了关于事件的附加参数, 每个事件都有描述.

与所有动态调用的方法或函数一样, 回调不需要声明回调本身不需要的参数, 但在这种情况下, 必须指定一个星号作为最终参数, 例如 MyCallback(Param1, *). 如果一个事件的参数多于回调声明的参数, 那么这些参数将被忽略(除非回调是可变参数的).

回调可以声明比事件提供的参数更多的参数, 如果(而且只有当) 额外的参数被声明为可选参数. 然而, 不建议使用可选参数, 因为未来的程序版本可能会用额外的参数来扩展一个事件, 在这种情况下, 可选参数将停止接收它们的默认值.

Callback 返回值

如果一个事件已经注册了多个回调, 回调可以返回一个非空值, 以防止任何剩余的回调被调用.

对于特定的事件, 返回值可能有额外的意义. 例如, Close 回调可以返回一个非零的数字(例如 true) 来防止 GUI 窗口关闭.

Callback 名称

按照惯例, 为了清晰起见, 下面每个事件的语法都用 ObjectType_EventName 这种形式的函数名来显示. 脚本不需要遵循这个惯例, 可以使用任何有效的函数名.

线程

每个事件回调都是在一个新的线程中调用的, 因此会以诸如 SendMode 等设置的默认值重新开始. 这些默认值可以在脚本启动时更改.

每当一个 GUI 线程被启动时, 该线程的上次找到的窗口都会作为 GUI 窗口本身启动. 这使得窗口和控件的函数 -- 如 WinGetStyle, WinSetTransparent 和 ControlGetFocus -- 在对 GUI 窗口本身进行操作时可以省略 WinTitle 和 WinText(即使它是隐藏的).

除非另有说明, 每个事件被限制为每个对象一次只能有一个线程. 如果一个事件在由该事件启动的前一个线程结束之前被触发, 则该事件通常会被丢弃. 为了防止这种情况发生, 请使用 Critical 作为回调的第一行(然而, 这也将缓冲/延迟其他线程, 例如按下热键).

销毁 GUI

当 GUI 被销毁时, 所有的事件回调都被释放. 因此, 如果 GUI 在事件被派发时被销毁, 那么后续的事件回调就不会被调用. 为了清晰起见, 在销毁 GUI 后, 回调应该返回一个非空值.

事件

Gui 对象支持以下事件:

事件 | 当...时触发
Close | 关闭窗口.
ContextMenu | 用户在窗口内右键单击或按下 Menu 或 Shift+F10.
DropFiles | 文件/文件夹被拖放到窗口上.
Escape | 当 GUI 窗口处于活动状态时, 用户按下 Esc.
Size | 窗口被调整大小, 最小化, 最大化或还原.

根据控件类型, GuiControl 对象支持以下事件:

事件 | 当...时触发
Change | 控件的值发生变化.
Click | 控件被点击.
DoubleClick | 控件被双击.
ColClick | ListView 的一个列头被点击.
ContextMenu | 当控件具有键盘焦点时, 用户右键单击控件或按下 Menu 或 Shift+F10.
Focus | 控件获得键盘焦点.
LoseFocus | 控件失去键盘焦点.
ItemCheck | ListView 或 TreeView 的项目被选中或取消选中.
ItemEdit | 用户编辑 ListView 或 TreeView 项的标签.
ItemExpand | TreeView 项目被展开或折叠.
ItemFocus | ListView 中改变聚焦的项目.
ItemSelect | ListView 或 TreeView 项目被选中, 或者一个 ListView 项目被取消选择.

窗口事件

Close

当用户或其他程序试图关闭窗口时, 如按下标题栏中的 X 按钮, 从系统菜单中选择 "关闭", 或调用 WinClose, 则启动该函数.

Gui_Close(GuiObj)

默认情况下, 回调返回后或者没有注册回调, 窗口会自动隐藏. 回调可以通过返回 1(或 true) 来阻止这种情况, 这也将阻止任何剩余的回调被调用. 回调可以通过调用 GuiObj.Hide 立即隐藏窗口, 或者通过调用 Gui.Destroy 销毁窗口.

例如, 这个 GUI 在关闭前会显示一个确认提示:

MyGui := Gui()
MyGui.AddText("", "Press Alt+F4 or the X button in the title bar.")
MyGui.OnEvent("Close", MyGui_Close)
MyGui_Close(thisGui) {  ; 声明中 this 参数是可选的.
    if MsgBox("Are you sure you want to close the GUI?",, "y/n") = "No"
        return true  ; true = 1
}
MyGui.Show()

ContextMenu

每当用户在窗口中除标题栏和菜单栏外的任何地方单击右键时就会启动. 当按下 Menu 或 Shift+F10 时, 也会启动.

Gui_ContextMenu(GuiObj, GuiCtrlObj, Item, IsRightClick, X, Y)
GuiCtrlObj

类型: 对象或字符串(空)

接收事件的控件的 GuiControl 对象(如果没有则为空白).

Item

类型: 整数

当 ListBox, ListView 或 TreeView 是上下文菜单的目标时(由 GuiCtrlObj 决定), Item 指定控件的哪个项目是目标.

ListBox: 当前焦点项目的位置编号. 请注意, 标准的 ListBox 在右键单击时不会聚焦一个项目, 所以这可能不是被单击的项目.

ListView 和 TreeView: 对于右键点击, Item 包含被点击的项目的行号或 ID(如果用户点击的不是项目, 则为 0). 对于 Menu 和 Shift+F10, Item 包含所选项目的行号或 ID.

IsRightClick

类型: 整数(布尔值)

下列值之一:

  • 1(true) = 如果用户点击了鼠标右键.
  • 0(false) = 用户按下了 Menu 键或 Shift+F10.
X, Y

类型: 整数

脚本应该显示菜单的 X 和 Y 坐标(例如 MyContextMenu.Show(X, Y)). 坐标是相对于窗口客户端区域的左上角.

与大多数其他 GUI 事件不同, ContextMenu 事件可以有一个以上的并发线程.

每个控件都可以有自己的 ContextMenu 事件回调, 该回调在为 Gui 对象注册的任何回调之前被调用. 特定于控件的回调省略了 GuiObj 参数, 但所有其他参数都是一样的.

注意: 由于 Edit 和 MonthCal 控件有自己的上下文菜单, 所以在其中一个控件中右击不会启动 ContextMenu 事件.

DropFiles

每当文件/文件夹作为拖放操作的一部分被放置到窗口时, 就会启动该回调(但如果该回调已经运行, 则忽略拖拽事件).

Gui_DropFiles(GuiObj, GuiCtrlObj, FileArray, X, Y)
GuiCtrlObj

类型: 对象或字符串(空值)

文件被拖拽到的控件的 GuiControl 对象(如果没有则为空白).

FileArray

类型: Array

一个文件名的数组(对象), 其中 FileArray[1] 是第一个文件, FileArray.Length 返回文件的数量. 可以使用 for-loop 来迭代文件:

Gui_DropFiles(GuiObj, GuiCtrlObj, FileArray, X, Y) {
    for i, DroppedFile in FileArray
        MsgBox "File " i " is:`n" DroppedFile
}
X, Y

类型: 整数

文件拖拽位置的 X 和 Y 坐标, 相对于窗口客户端区域的左上角.

Escape

当用户在 GUI 窗口处于活动状态时按下 Esc 时启动.

Gui_Escape(GuiObj)

默认情况下, 按下 Esc 没有效果. 已知限制: 如果窗口中的第一个控件被禁用(可能取决于控件类型), Escape 事件将不会启动. 可能有其他情况会产生这种效果.

Size

当窗口被调整大小, 最小化, 最大化或还原时启动.

Gui_Size(GuiObj, MinMax, Width, Height)
MinMax

类型: 整数

以下数值之一:

  • 0: 窗口既没有最小化也没有最大化.
  • 1: 窗口已最大化.
  • -1: 窗口被最小化.

请注意, 已最大化的窗口可以在不恢复/取消最大化的情况下调整大小, 因此值为 1 并不一定意味着该事件是在用户最大化窗口的情况下发生的.

Width, Height

类型: 整数

窗口客户端区域的新宽度和高度, 即不包括标题栏, 菜单栏和边框的区域.

脚本可以使用 Size 事件来重新定位和调整控件的大小, 以响应用户对窗口的大小调整.

当窗口被调整大小时(即使是由脚本调整), Size 事件可能不会立即被触发. 与其他窗口事件一样, 如果当前线程是不可中断的, 那么在线程变得可中断之前, Size 事件不会被触发. 如果脚本刚刚调整了窗口的大小, 请按照这个例子来确保 Size 事件立即被触发:

Critical "Off"  ; 即使从未使用 Critical "On".
Sleep -1

Gui.Show 会自动 Sleep -1, 所以在这种情况下一般不需要调用 Sleep.

控件事件

Change

控件的值发生变化时触发该事件.

Ctrl_Change(GuiCtrlObj, Info)
Info

类型: 整数

Slider: 一个表示滑块如何移动的数值. 有关详情, 请参阅检测变化.

对于所有其他控件, Info 目前没有任何意义.

要获取控件的新值, 请使用 GuiCtrlObj.Value.

适用于: DDL, ComboBox, ListBox, Edit, DateTime, MonthCal, Hotkey, UpDown, Slider, Tab.

Click

控件被点击时触发该事件.

Ctrl_Click(GuiCtrlObj, Info)
Link_Click(GuiCtrlObj, Info, Href)
Info

类型: 整数

ListView: 点击的项目的行号, 如果鼠标没有在项目上, 则为 0.

TreeView: 点击的项目的 ID, 如果鼠标没有放在项目上, 则为 0.

Link: 如果有的话, 链接的 ID 属性(字符串), 否则为链接的索引(整数).

StatusBar: 点击的部分的编号(然而, 如果用户点击在栏右边的大小抓手附近, 编号可能是一个很大的整数).

对于所有其他控件, Info 目前没有任何意义.

Href

类型: 字符串

Link: 链接的 HREF 属性. 注意, 如果注册了 Click 事件回调, HREF 属性不会自动执行.

适用于: Text, Pic, Button, CheckBox, Radio, ListView, TreeView, Link, StatusBar.

DoubleClick

当控件被双击时触发该事件.

Ctrl_DoubleClick(GuiCtrlObj, Info)
Info

类型: 整数

ListView, TreeView 和 StatusBar: 与 Click 事件相同.

ListBox: 当前聚焦项的位置编号. 双击最后一个项目下面的空白处, 通常会聚焦最后一个项目, 并保持原样.

适用于: Text, Pic, Button, CheckBox, Radio, ComboBox, ListBox, ListView, TreeView, StatusBar.

ColClick

当 ListView 的一个列头被点击时触发该事件.

Ctrl_ColClick(GuiCtrlObj, Info)
Info

类型: 整数

被点击的以 1 开始的列号. 这是创建列时分配的原始编号; 也就是说, 它不反映用户对列的任何拖放.

适用于: ListView.

ContextMenu

当控件具有键盘焦点时, 用户右键单击控件或按下 Menu 或 Shift+F10 时触发该事件.

Ctrl_ContextMenu(GuiCtrlObj, Item, IsRightClick, X, Y)

有关详情, 请参阅 ContextMenu.

适用于: 除了 Edit 和 MonthCal(以及 ComboBox 内的 Edit 控件)(他们都有自己的标准上下文菜单) 外的所有控件.

Focus / LoseFocus

控件获得或失去键盘焦点时触发该事件.

Ctrl_Focus(GuiCtrlObj, Info)
Ctrl_LoseFocus(GuiCtrlObj, Info)
Info

保留.

适用于: Button, CheckBox, Radio, DDL, ComboBox, ListBox, ListView, TreeView, Edit, DateTime.

不支持: Hotkey, Slider, Tab 和 Link. 注意 Text, Pic, MonthCal, UpDown 和 StatusBar 控件不接受键盘焦点.

ItemCheck

当 ListView 或 TreeView 项目被选中或取消选中时触发该事件.

Ctrl_ItemCheck(GuiCtrlObj, Item, Checked)

适用于: ListView, TreeView.

ItemEdit

用户编辑 ListView 或 TreeView 项的标签时触发该事件.

Ctrl_ItemEdit(GuiCtrlObj, Item)

只有在控件的选项中使用了 -ReadOnly, 才能编辑项目的标签.

适用于: ListView, TreeView.

ItemExpand

TreeView 项目被展开或折叠时触发该事件.

Ctrl_ItemExpand(GuiCtrlObj, Item, Expanded)

适用于: TreeView.

ItemFocus

当 ListView 中的焦点项目发生变化时触发该事件.

Ctrl_ItemFocus(GuiCtrlObj, Item)

适用于: ListView.

ItemSelect

当 ListView 或 TreeView 项目被选中或 ListView 项目被取消选择时触发该事件.

ListView_ItemSelect(GuiCtrlObj, Item, Selected)
TreeView_ItemSelect(GuiCtrlObj, Item)

适用于: ListView, TreeView.

ListView: 该事件对每一个被取消选择或选择的项目都会被触发一次, 所以可以对用户的一个动作进行多次响应.

其他事件

其他类型的 GUI 事件可以通过 OnNotify, OnCommand 或 OnMessage 来检测和处理. 例如, 每当用户将鼠标移动到窗口中的特定控件上时, 脚本可以通过 ToolTip 显示上下文相关的帮助. 这在 GUI ToolTip 的例子中进行了演示.


OnNotify (GUI) - 语法 & 使用 | AutoHotkey v2

OnNotify

注册一个函数或方法, 当通过 WM_NOTIFY 消息接收到控制通知时调用.

GuiCtrl.OnNotify(NotifyCode, Callback , AddRemove)

参数

NotifyCode

类型: 整数

要监控的控件定义的通知代码.

Callback

类型: 字符串或函数对象

事件发生时要调用的函数, 方法或对象.

如果 GUI 有事件接收器(即, 如果指定了 Gui() 的 EventObj 参数), 那么这个参数可能是属于事件接收器的方法的名称. 否则, 这个参数必须是一个函数对象.

回调函数接受两个参数, 定义如下:

MyCallback(GuiCtrl, lParam) { ...

虽然你给参数的名字并不重要, 但是下面的值会依次赋给它们:

  1. 当前 GUI 控件的 GuiControl 对象.
  2. 从 NMHDR 派生的通知结构的地址. 其确切类型取决于控件和通知代码的类型. 如果结构包含关于通知的附加信息, 回调函数可以使用 NumGet 和/或 StrGet 检索它.

如果不需要相应的信息, 你可以从回调参数列表的末尾省略一个或多个参数, 但在这种情况下, 必须指定星号作为最后一个参数, 例如 MyCallback(Param1, *).

OnEvent 注释中关于 this 和绑定函数的内容也适用于 OnNotify.

如果一个事件注册了多个回调函数, 则回调函数可能返回一个非空值, 以防止调用任何剩余的回调函数.

根据通知的不同, 回调函数的返回值可能有其他含义. 例如, 如果回调返回 TRUE(1), ListView 通知 LVN_BEGINLABELEDIT(-175 或 -105) 会阻止用户编辑标签.

AddRemove

类型: 整数

如果省略, 则默认为 1. 否则, 指定下列数字之一:

  • 1 = 在任何先前注册的回调之后调用回调.
  • -1 = 在任何先前注册的回调之前调用回调.
  • 0 = 不调用该回调.

WM_NOTIFY

每当发生要监控事件或控件需要从程序中获取信息时, 某些类型的控件就会发送一条 WM_NOTIFY 消息. 该消息的 lParam 参数包含一个指向包含通知信息的结构的指针. 结构的类型取决于通知代码和触发通知的控件类型, 但总是基于 NMHDR.

要确定哪些通知是可用的(如果有的话), 它们提供的结构类型以及它们如何解释返回值, 请参考控件的文档. Control Library (Microsoft Docs) 包含了每个 Windows 常用控件的链接. 通知代码(编号) 可以在 Windows SDK 中找到, 或者在互联网上搜索.

AutoHotkey 使用 idFrom 和 hwndFrom 字段来识别是哪个控件发送的通知, 以便将其派遣到相应的对象. code 字段包含通知代码. 由于这些字段必须与用于注册回调的 GuiCtrl 和 NotifyCode 相匹配, 所以它们对脚本很少有用.

相关

OnEvent 的说明也适用于 OnNotify: 线程, 销毁 GUI.

OnCommand 可以用于作为 WM_COMMAND 消息发送的通知.


HasBase - 语法 & 使用 | AutoHotkey v2

HasBase

如果指定的值派生自指定的基对象, 则返回非零数字.

HasBase := HasBase(Value, BaseObj)

参数

Value

任何类型的任何值.

BaseObj

类型: 对象

要测试的潜在基对象.

返回值

类型: 整数(布尔值)

如果 BaseObj 在 Value 的基对象链中, 函数返回 1(true), 否则返回 0(false).

备注

下面的代码大致相当于这个函数:

MyHasBase(Value, BaseObj) {
    b := Value
    while b := ObjGetBase(b)
        if b = BaseObj
            return true
    return false
}

例如, 如果 Obj 是数组或任何派生类的实例, 则 HasBase(Obj, Array.Prototype) 为 true. 这与 Obj is Array 执行的检查相同; 但是, 实例可以基于其他实例, 而 is 需要一个类.

HasBase 同时接受对象和原始值. 例如, HasBase(1, 0.base) 返回 true.

相关

Objects, Obj.Base, ObjGetBase, HasMethod, HasProp

示例

说明函数的用法.

thebase := {key: "value"}
derived := {base: thebase}
MsgBox HasBase(thebase, derived) ; 0
MsgBox HasBase(derived, thebase) ; 1


HasMethod - 语法 & 使用 | AutoHotkey v2

HasMethod

如果指定的值具有指定名称的方法, 则返回非零数字.

HasMethod := HasMethod(Value , Name, ParamCount)

参数

Value

类型: Any

除了 ComObject 之外的任何类型的任何值.

Name

类型: 字符串

如果省略, 检查 Value 本身是否可调用. 否则, 请指定, 要检查的方法名.

ParamCount
类型: 整数

如果省略(或者参数数没有被验证), 则会对 Call 方法进行基本检查, 以验证该对象是可调用的.

否则, 请指定将被传递给方法或函数的参数数量. 如果指定, 可以查询该方法的 MinParams, MaxParams 和 IsVariadic 属性, 以验证它是否可以接受这个参数指定的数量. 如果这些属性不存在, 参数计数就不会被验证.

这个计数不应该包括隐含的 this 参数.

返回值

类型: 整数(布尔值)

如果找到方法并通过验证(如果执行), 则返回 1(true), 否则返回 0(false).

备注

HasMethod 与 GetMethod 具有同样的限制.

此函数可用于评估某个值是否支持特定操作. 例如, 没有调用方法的值不能被调用或传递给 SetTimer, 而没有 __Enum 方法或 Call 方法的值不能传递给 For. 但是, 方法的存在并不保证可以调用它, 因为必须满足一些要求, 比如参数计数.

当指定 ParamCount 时, 该函数执行的验证等同于 SetTimer 等内置函数所执行的验证.

返回 0(false) 并不一定表示不能调用该方法, 因为该值可能具有一个 __Call 元-函数. 但是, __Call 在特定的上下文中, 如 For 调用 __Enum 时, 不会触发调用. 如果 __Call 存在, 则无法检测它可能支持的方法.

函数支持原始值.

相关

Objects, HasBase, HasProp, GetMethod

示例

说明该函数的使用.

MsgBox HasMethod(0, "HasMethod") ; 1
MsgBox HasMethod(0, "Call") ; 0


HasProp - 语法 & 使用 | AutoHotkey v2

HasProp

如果指定值具有指定名称的属性, 则返回非零数字.

HasProp := HasProp(Value, Name)

参数

Value

类型: Any

除了 ComObject 之外的任何类型的任何值.

Name

类型: 字符串

要检查的属性名.

返回值

类型: 整数(布尔值)

如果值具有使用此名称的属性, 则返回 1(true), 否则返回 0(false).

备注

此函数不测试是否存在 __Get 或 __Set 元-函数. 如果存在, 则无法检测它可能实现的准确属性集.

函数支持原始值.

相关

Objects, HasBase, HasMethod

示例

说明此函数的使用.

MsgBox HasProp({}, "x") ; 0
MsgBox HasProp({x:1}, "x") ; 1
MsgBox HasProp(0, "Base") ; 1


HotIf / HotIfWin... - 语法 & 使用 | AutoHotkey v2

HotIf / HotIfWin...

指定后续创建或修改热键变体和热字串变体的条件.

目录:

HotIf

HotIf "Expression"
HotIf Callback

参数

"Expression"

类型: 字符串

如果省略, 将设置空白条件(关闭上下文相关性). 否则, 条件将被设置为现有的 #HotIf 表达式. 表达式通常写成一个加引号字符串, 但也可以是一个返回与 #HotIf 表达式匹配的文本的变量或表达式.

注意: HotIf 函数使用你传递给它的字符串, 而不是原始源代码. 当脚本加载时, 转义序列会被解析, 所以只考虑结果字符; 例如, HotIf 'x = "`t"' 和 HotIf 'x = "' A_Tab '"' 都对应于 #HotIf x = "`t".

有关示例, 请参阅 #HotIf 示例 #5.

Callback

类型: 函数对象

如果省略, 设置空白条件(关闭上下文相关性). 否则, 为给定的函数对象设置条件. 随后创建的热键和热字串只有在调用给定的函数对象产生一个非零的数字时才会执行. 这类似于 HotIf "Expression", 只不过每个热键和热字串可以有很多热键变体或热字串变体(每个对象一个).

回调函数接受一个参数, 定义如下:

MyCallback(HotkeyName) { ...

尽管您给参数的名称并不重要, 但它被赋值为热键名称或热字串名称.

如果不需要相应的信息, 可以省略回调参数, 但在这种情况下必须指定星号, 例如 MyCallback(*).

一旦传递给 HotIf 函数, 该对象将永远不会被删除(但进程退出时, 内存将被操作系统回收).

有关示例, 请参阅下面的示例 #2 或 Hotkey 的示例 #6.

HotIfWin...

HotIfWinActive WinTitle, WinText
HotIfWinExist WinTitle, WinText
HotIfWinNotActive WinTitle, WinText
HotIfWinNotExist WinTitle, WinText

参数

WinTitle, WinText

类型: 字符串

如果省略这两个选项, 将设置空白条件(关闭上下文相关性). 否则, 为 WinTitle 指定 窗口标题和其他条件, 以标识目标窗口和/或为 WinText 指定目标窗口的单个文本元素的子字符串(如同包含的 window Spy 实用程序显示的那样). 根据所调用的函数, 受影响的热键和热字串仅在目标窗口处于活动状态, 存在, 处于不活动状态, 或不存在时才有效.

由于参数在函数被调用之前就已经被计算了, 因此任何变量引用都会在那一刻成为永久性的. 换句话说, 变量内容的后续变化不会被现有的热键和热字串看到.

WinTitle 和 WinText 的含义与 WinActive 或 WinExist 中的相同, 但是只能使用字符串, 并且它们的计算与自动执行线程设置的 SetTitleMatchMode 和 DetectHiddenWindows 的默认设置一致.

有关示例, 请参阅下面的示例 #1.

错误处理

如果 HotIf 的参数无效, 例如它不匹配现有的表达式, 或不是一个有效的回调函数, 则抛出异常.

备注

HotIf 和 HotIfWin 函数允许在脚本运行时创建和修改上下文相关的热键和热字串(相比之下, #HotIf 指令是位置性的, 在脚本开始执行前生效). 例如:

HotIfWinActive "ahk_class Notepad"
Hotkey "^!e", MyFuncForNotepad  ; 创建一个只在记事本中工作的热键.

使用 HotIf 或其中一个 HotIfWin 函数会使当前线程中把所有随后创建或修改的热键都变成上下文相关的, 并影响 Hotkey 或 Hotstring 函数修改的热键或热字串变体. 只有最近一次对当前线程中任何 HotIf 或 HotIfWin 函数的调用才会生效.

要关闭上下文相关性(也就是说, 使后续创建的热键和 热字串在所有窗口中工作), 调用任意 HotIf 或其中一个 HotIfWin 函数, 但省略参数. 例如: HotIf 或 HotIfWinActive.

在热键或热字串线程中使用 HotIf 或其中一个 HotIfWin 之前, Hotkey 和 Hotstring 函数默认与启动该线程的热键或热串的上下文相同. 换句话说, Hotkey A_ThisHotkey, "Off" 关闭当前热键, 即使它是上下文相关的. 所有其他线程都默认创建或修改全局热键或热字串, 除非在脚本启动时使用 HotIf 或其中一个 HotIfWin 覆盖了该默认值.

使用 HotIf, 其中一个 HotIfWin, 或 #HotIf 指令禁用鼠标或键盘热键后, 它会执行其原来的功能; 也就是说, 它传递到活动窗口, 就好像不存在热键一样. 然而, 控制器热键总是有效, 无论禁用与否.

相关

热键, 热字串, Hotkey 函数, Hotstring 函数, #HotIf, 线程

示例

与 #HotIf 的示例 #1 类似, 这创建了两个热键和一个热字串, 一个热键仅在记事本处于活动状态时有效, 另一个热键适用于除记事本以外的任何窗口. 主要区别在于, 这个示例在运行时创建了与上下文相关的热键和热字串, 而 #HotIf 的示例在加载时创建它们.

HotIfWinActive "ahk_class Notepad"
Hotkey "^!a", ShowMsgBox
Hotkey "#c", ShowMsgBox
Hotstring "::btw", "This replacement text will occur only in Notepad."
HotIfWinActive
Hotkey "#c", (*) => MsgBox("You pressed Win-C in a window other than Notepad.")

ShowMsgBox(HotkeyName)
{
    MsgBox "You pressed " HotkeyName " while Notepad is active."
}

与上面的例子类似, 但是使用了回调.

HotIf MyCallback
Hotkey "^!a", ShowMsgBox
Hotkey "#c", ShowMsgBox
Hotstring "::btw", "This replacement text will occur only in Notepad."
HotIf
Hotkey "#c", (*) => MsgBox("You pressed Win-C in a window other than Notepad.")

MyCallback(*)
{
    if WinActive("ahk_class Notepad")
        return true
    else
        return false
}

ShowMsgBox(HotkeyName)
{
    MsgBox "You pressed " HotkeyName " while Notepad is active."
}


Hotkey - 语法 & 使用 | AutoHotkey v2

Hotkey

在脚本运行时创建, 修改, 启用或禁用热键.

Hotkey KeyName , Action, Options

参数

KeyName

类型: 字符串

热键的按键的名称, 包括所有修饰符. 例如, 指定 "#c" 来触发 Win+C 热键.

如果 KeyName 是已经存在的热键 -- 通过 Hotkey 函数或脚本中的双冒号语法 -- 那么将使用此函数的其他参数值更新原有的热键.

指定 现有的 热键, KeyName 是不区分大小写的. 但是, 按键名称必须和现有的热键拼写相同(例如在这种情况下 Esc 与 Escape 是不同的). 此外, 修饰符(如 ^!+#) 的顺序是无关紧要的. GetKeyName 可用于获取标准的按键名称.

热键首次创建时 -- 无论是通过 Hotkey 函数还是脚本中的双冒号语法 -- 其键名以及修饰符的顺序成为此热键的固定名称, 正如 ThisHotkey 所反映的那样. 这个名称由热键的所有变体共享, 并且即使之后 Hotkey 函数使用不同的修饰符顺序操作此热键, 此名称也不会改变.

如果热键变体已经存在, 则根据 KeyName 是否包含颚化符前缀(~) 更新它的行为.

使用钩子前缀($) 可添加到现有热键上. 这个前缀影响所有热键的变体且不能被删除.

Action

类型: 函数对象或字符串

如果省略, 并且 KeyName 已经作为热键存在, 则不会更改其操作. 这用于只更改热键的 Options. 否则, 指定回调, 不带冒号的热键名称, 或下面列出的特殊值之一.

指定在按下热键时要调用的函数(作为新线程).

回调函数接受一个参数, 定义如下:

MyCallback(HotkeyName) { ...

尽管您给参数的名称并不重要, 但它被赋值为热键名称.

如果不需要相应的信息, 可以省略回调参数, 但在这种情况下必须指定星号, 例如 MyCallback(*).

双冒号语法定义的热键自动使用参数名称 ThisHotkey. 也可以在没有 Hotkey 函数的情况下, 为热键指定一个函数名.

注意: 如果指定了回调, 但是由于之前使用 Hotkey 函数而禁用了热键, 那么热键仍将继续禁用. 为了避免这种情况, 请在 Options 中包含单词 ON.

指定热键名称以使用其原始函数; 具体来说, 热键变体的原始函数对应于当前的 HotIf 条件. 这通常用于在更改热键后恢复热键的原始函数, 但也可以用于分配不同热键的函数, 提是两个热键使用相同的 HotIf 条件.

指定以下特殊值之一:

On: 启用热键. 如果热键已经处于启用状态, 则不进行操作.

Off: 禁用热键. 如果热键已经处于禁用状态, 则不进行操作.

Toggle: 设置热键到相反的状态(启用或禁用).

AltTab(及其他): 这里描述的特殊的 Alt-Tab 热键动作.

Options

类型: 字符串

由零个或多个下列选项组成的字符串, 字母间可以用空格分隔. 例如: "On B0".

On: 如果热键当前是禁用的, 则启用它.

Off: 如果热键当前是启用的, 则禁用它. 此选项常用来创建初始状态为禁用的热键.

B 或 B0: 指定字母 B 将按照 #MaxThreadsBuffer 中描述的方法缓冲热键. 指定 B0(B 后跟着数字 0) 来禁用这种类型的缓冲.

P n: 指定字母 P 后面跟着热键的线程优先级. 如果创建热键时省略 P 选项, 则设置优先级为 0.

S 或 S0: 指定字母 S 热键免于 挂起, 这允许使用热键来关闭挂起. 指定 S0(S 和数字 0) 来移除该豁免, 允许热键被挂起.

T n: 指定字母 T 后面跟着一个表示此热键允许的线程数, 如同 #MaxThreadsPerHotkey 中描述的那样. 例如: T5.

I n(InputLevel): 指定字母 I(或 i) 后跟随热键的输入级别. 例如: I1.

如果任一选项字母被忽略并且热键已经存在, 这些选项将不会被更改. 但是, 如果热键还不存在 -- 也就是说, 它将由这个函数创建 -- 这些选项将默认为最近生效的那些. 例如, 如果 #MaxThreadsBuffer 出现在脚本的最底部, 也会被使用. 如果脚本中没有出现 #MaxThreadsBuffer, 那么将使用它的默认设置(在本例中为 OFF).

错误处理

如果参数无效或内存分配失败, 则抛出异常.

如果热键无效或无法创建, 则会抛出以下异常:

错误类 | .Message | 说明
ValueError | Invalid key name.(无效的按键名称.) | KeyName 参数指定一个或多个当前键盘布局/语言不识别或不支持的键. Exception.Extra 包含键名; 例如 !Entre 中的 "Entre".
 | Unsupported prefix key.(不支持的前缀键.) | 例如, 不支持将鼠标滚轮作为热键 WheelDown & Enter 的前缀. Exception.Extra 包含前缀键.
 | This AltTab hotkey must have exactly one modifier/prefix. | KeyName 参数不适合与 AltTab 或 ShiftAltTab 动作一起使用. 需要两个键(至多) 的组合. 例如: RControl & RShift::AltTab. Exception.Extra 包含 KeyName.
 | This AltTab hotkey must specify which key (L or R).
TargetError | Nonexistent hotkey.(不存在的热键.) | 该函数试图修改一个不存在的热键. Exception.Extra 包含 KeyName.
 | Nonexistent hotkey variant (IfWin). | 该函数试图修改一个不存在的现有热键变体. 要解决这个问题, 请使用 HotIf 设置条件使其与要修改的热键的条件相匹配. Exception.Extra 包含 KeyName.
Error | Max hotkeys. | 创建这个热键将超过每个脚本 32762 个热键的限制(不过, 每个热键可以有无限数量的变体, 而且也没有对热字串数量的限制).

提示: Try-Catch 可以用来测试是否存在热键变体. 例如:

try
    Hotkey "^!p"
catch TargetError
    MsgBox "The hotkey does not exist or it has no variant for the current HotIf criteria."

备注

当前的 HotIf 设置决定了 Hotkey 函数将操作热键的哪个变体.

如果需要根据活动窗口的类型来自动禁用选择的热键或热字串, 使用 Hotkey "^!c", "Off" 通常不如 #HotIf 带有 WinActive/WinExist(或它们的动态副本 HotIfWinActive/Exist) 来的方便.

通过双冒号语法创建的热键比使用 Hotkey 函数执行地更好, 因为在脚本启动时会批量启用它们(而非一个一个地启用). 因此, 最好使用此函数仅创建那些在脚本开始运行后才知道其键名的热键. 一种此类情况是, 当通过 INI 文件来配置脚本各种操作的热键时使用此函数.

如果脚本被挂起了, 那么新增加/启用的热键也将是挂起的, 直到挂起状态被关闭(除非它们像 Suspend 页面中描述的那样进行了豁免).

如果由这个函数所做的更改是合理的将会安装或移除键盘和/或鼠标钩子.

尽管 Hotkey 函数不能直接启用或禁用其他脚本中的热键, 但在大多数情况下它可以通过创建或启用相同的热键来覆盖它们. 这样是否有效取决于下列因素: 1) 在其他脚本中需要被覆盖的热键是否为钩子热键(非钩子热键总是可以成功覆盖); 2) 最近启动的热键通常优先于其他脚本中的相同热键(因此, 如果脚本是最近启动的, 那么它的覆盖应该总是会成功); 3) 此热键的启用或创建是否会重新激活键盘或鼠标钩子(如果是, 那么覆盖总是会成功).

脚本中至少有一个热键时, 它会变成持续运行的, 这意味着应该使用 ExitApp 而不是 Exit 来终止它.

变体(副本) 热键

一个特定的热键可以被创建多次, 如果每个定义有不同的 HotIf 条件. 这被称为 热键变体. 例如:

HotIfWinActive "ahk_class Notepad"
Hotkey "^!c", MyFuncForNotepad
HotIfWinActive  "ahk_class WordPadClass"
Hotkey "^!c", MyFuncForWordPad
HotIfWinActive
Hotkey "^!c", MyFuncForAllOtherWindows

如果有多个变体符合触发条件, 那么仅触发最早创建的那个. 这种情况的例外是全局变体(不带 HotIf 条件的那个): 它的优先级总是最低的, 仅当其他变体都不触发时它才会被触发.

创建重复热键时, 修饰符的顺序(如 ^!+#) 没有关系. 例如, "^!c" 等同于 "!^c". 但是, 按键必须拼写一致. 例如, 用于此目的时, Esc 不同于 Escape(尽管大小写无关). 最后, 任何带有通配符前缀(*) 的热键和不带通配符的热键是完全独立的; 例如, "*F1" 和 "F1" 都有他们各自的变体.

有关详情, 请参阅 HotIf 和 #HotIf 的备注.

相关

Hotkey, HotIf, A_ThisHotkey, #MaxThreadsBuffer, #MaxThreadsPerHotkey, Suspend, 线程, Thread, Critical, Return, Menu 对象, SetTimer, Hotstring function

示例

创建 Ctrl-Alt-Z 热键.

Hotkey "^!z", MyFunc

MyFunc(ThisHotkey)
{
    MsgBox "You pressed " ThisHotkey
}

让 RCtrl & RShift 执行 Alt-Tab 的功能.

Hotkey "RCtrl & RShift", "AltTab"

禁用 Shift-Win-C 热键.

Hotkey "$+#c", "Off"

改变热键为允许 5 个线程.

Hotkey "^!a",, "T5"

创建仅在记事本中有效的热键 Alt+W.

HotIfWinActive "ahk_class Notepad"
Hotkey "!w", ToggleWordWrap  ; !w = Alt+W

ToggleWordWrap(ThisHotkey)
{
    MenuSelect "A",, "Format", "Word Wrap"
}

创建一个界面允许你注册简单的三键组合热键.

HkGui := Gui()
HkGui.Add("Text", "xm", "Prefix key:")
HkGui.Add("Edit", "yp x100 w100 vPrefix", "Space")
HkGui.Add("Text", "xm", "Suffix hotkey:")
HkGui.Add("Edit", "yp x100 w100 vSuffix", "f & j")
HkGui.Add("Button", "Default", "Register").OnEvent("Click", RegisterHotkey)
HkGui.OnEvent("Close", (*) => ExitApp())
HkGui.OnEvent("Escape", (*) => ExitApp())
HkGui.Show()

RegisterHotkey(*)
{
    Saved := HkGui.Submit(false)
    HotIf (*) => GetKeyState(Saved.Prefix)
    Hotkey Saved.Suffix, (ThisHotkey) => MsgBox(ThisHotkey)
}


Hotstring - 语法 & 使用 | AutoHotkey v2

Hotstring

在脚本运行时创建, 修改, 启用或禁用热字串.

Hotstring String , Replacement, OnOffToggle
Hotstring NewOptions
Hotstring SubFunction , Value1

参数

String

类型: 字符串

热字串的触发字符串, 前面是常用的冒号对和选项字符. 例如, "::btw" 或 ":*:]d".

String 可以考虑通过区分大小写(C), 单词敏感性(?), 激活条件(如 #HotIf 或 HotIf 设置) 和触发字符串来匹配现有的热字符串. 例如, "::btw" 和 "::BTW" 只有在区分大小写模式作为默认值开启时才匹配, 而 ":C:btw" 和 ":C:BTW" 永远不匹配. C 和 ? 选项可能包含在 String 中, 也可以通过 #Hotstring 指令或之前使用的 NewOptions 设为默认值.

如果热字串已经存在, 那么在 String 中指定的所有选项都会生效, 而其他所有选项都保持原样. 但是, 由于带有 C 或 ? 的热字串被认为是与其他热字串不一样的, 所以不可能添加或删除这些选项. 作为代替, 关闭现有热字串并创建一个新的.

当热字串第一次被创建时 -- 无论是通过热字串函数还是脚本中的双冒号语法 -- 其触发字符串和选项字符序列都将成为热字串的固定名称, 正如 ThisHotkey 中显示的名称. 即使热字串函数稍后使用不同的选项字符访问热字串, 这个名称也不会改变.

Replacement

类型: 字符串或函数对象

如果省略, 并且 String 已经作为热字串存在, 则不会更改其替换. 这用于只更改热字串的选项, 或打开或关闭热字串. 否则, 请指定替换字符串或回调.

如果 Replacement 是一个函数, 则在热字串触发时调用它(作为一个新线程).

回调函数接受一个参数, 定义如下:

MyCallback(HotstringName) { ...

尽管您给参数的名称并不重要, 但它被赋值为热字串的名称.

如果不需要相应的信息, 可以省略回调参数, 但在这种情况下必须指定星号, 例如 MyCallback(*).

双冒号语法定义的热字串自动使用参数名称 ThisHotkey. 也可以在没有 Hotstring 函数的情况下, 为热字串指定一个函数名.

在重新指定热字符串的函数后, 只有在给定名称的情况下, 才能恢复其原始函数.

注意: 如果指定了这个参数, 但是由于之前使用此函数而禁用了热字串, 那么热字串将继续禁用. 为了避免这种情况, 请为 OnOffToggle 指定 "On".

OnOffToggle

类型: 字符串或整数

下列值之一:

On 或 1(true): 启用热字串.

Off 或 0(false): 禁用热字串.

Toggle 或 -1: 设置热字串到相反的状态(启用或禁用).

NewOptions

类型: 字符串

要为随后创建的热字串设置新的默认选项, 请将这些选项传递给 Hotstring 函数, 不带任何前导或尾随冒号. 例如: Hotstring "T".

打开大小写敏感(C) 或单词敏感(?) 也会影响对 Hotstring 函数的任何后续调用将找到哪些现有的热字符串. 例如, 默认情况下, Hotstring ":T:btw" 会找到 ::BTW, 但如果 Hotstring "C" 或 #Hotstring C 生效时, 则不会. 这可以通过传递互斥选项来撤消或重写; 例如, C0 和 C1 覆盖 C.

SubFunction, Value1

类型: 字符串

这些参数相互依赖, 它们的用法如下所述.

子函数

对于 SubFunction, 指定以下参数之一:

  • EndChars: 检索或修改结束字符集.
  • MouseReset: 控制鼠标点击是否重置热字串识别器.
  • Reset: 立即复位热字串识别器.

EndChars

检索或修改由热字串识别器用作终止符的字符集.

OldValue := Hotstring("EndChars" , NewValue)

例如:

prev_chars := Hotstring("EndChars", "-()[]{}':;`"/\,.?!`n`s`t")
MsgBox "The previous value was: " prev_chars

#Hotstring EndChars 也会影响这个设置.

目前不能为每一个热字串指定不同的终止符字符集.

MouseReset

检索或修改全局设置, 该设置控制鼠标单击是否重置热字串识别器, 如这里所描述的那样.

OldValue := Hotstring("MouseReset" , NewValue)

NewValue 为 1(true) 以启用鼠标点击检测和重置热字串识别器, 或者 0(false) 来禁用. 返回值是在调用函数之前生效的设置.

如果此函数所做的更改有需要, 将安装或删除鼠标钩子.

#Hotstring NoMouse 也会影响此设置, 等同于将 NewValue 指定为 false.

Reset

立即重置热字串识别器.

Hotstring "Reset"

换句话说, 脚本将开始等待一个全新热字串, 不再考虑之前键入的任何内容.

错误

如果参数无效或内存分配失败, 则函数抛出 TargetError.

如果省略了 Replacement 并且 String 有效但无法匹配到一个存在的热字串, 则也会抛出异常. 这可以用来测试热字串的存在. 例如:

try
    Hotstring "::btw"
catch TargetError
    MsgBox "The hotstring does not exist or it has no variant for the current HotIf criteria."

备注

当前 HotIf 设置决定了哪一个热字串函数的变体将会运行.

如果该脚本被挂起, 新添加/启用的热字串也将挂起, 直到挂起关闭(Suspend 页面中所描述的豁免除外).

如果此函数所做的更改有需要, 将安装或删除键盘和/或鼠标钩子.

此函数不能直接启用或禁用本身以外的脚本中的热字串.

一旦脚本具有至少一个热字符串, 它将成为持续运行的脚本, 这意味着应该使用 ExitApp 而不是 Exit 来退出(终止) 脚本.

变体(副本) 热字串

一个特定的热字符串可以创建多次, 如果每个定义具有不同的 HotIf 条件, 区分大小写(C vs. C0/C1), 或单词敏感性(?). 这些被称为 热字串变体. 例如:

HotIfWinActive "ahk_group CarForums"
Hotstring "::btw", "behind the wheel"
HotIfWinActive "Inter-Office Chat"
Hotstring "::btw", "back to work"
HotIfWinActive
Hotstring "::btw", "by the way"

如果一个热字串的多个变体能被触发, 那么只有最早创建的将会触发.

有关详情, 请参阅 HotIf.

相关

热字串, HotIf, A_ThisHotkey, #MaxThreadsPerHotkey, Suspend, 线程, Thread, Critical, Hotkey function

示例

热字串助手. 如果您是一个热字串重度用户, 下面的脚本可能会很有用. 它基于 Andreas Borutta 创建的 v1 脚本. 通过按下 Win+H(或您选择的其他热键), 可以将当前选定的文本转换为热字串. 例如, 如果您在文字处理软件中选择了 "by the way", 按下 Win+H 会提示您输入其缩写(例如 btw), 然后将新热字串添加到脚本中并启用它.

#h::  ; Win+H 热键
{
     获取当前选择的文本. 使用剪贴板代替
    ; EditGetSelectedText 是因为它可以工作于更大范围的编辑器
    ; (即文字处理软件).  保存剪贴板当前的内容
    ; 以便在后面恢复. 尽管只能处理纯文本,
    ; 但总比没有好:
    ClipboardOld := A_Clipboard
    A_Clipboard := "" ; 必须清空, 才能检测是否有效.
    Send "^c"
    if !ClipWait(1)  ; ClipWait 超时.
    {
        A_Clipboard := ClipboardOld ; 恢复剪贴板之前的内容.
        return
    }

    ; 替换 CRLF 和/或 LF 为 `n 以便用于 "send-raw" 热字串:
    ; 对其他任何在原始模式下可能出现问题
    ; 的字符进行相同的处理:
    ClipContent := StrReplace(A_Clipboard, "``", "````")  ; 首先进行此替换以避免和后面的操作冲突.
    ClipContent := StrReplace(ClipContent, "`r`n", "``n")
    ClipContent := StrReplace(ClipContent, "`n", "``n")
    ClipContent := StrReplace(ClipContent, "`t", "``t")
    ClipContent := StrReplace(ClipContent, "`;", "```;")
    A_Clipboard := ClipboardOld  ; 恢复剪贴板之前的内容.
    ShowInputBox(":T:::" ClipContent)
}

ShowInputBox(DefaultValue)
{
    ; 这里会移动输入框的光标到更人性化的位置:
    SetTimer MoveCaret, 10
    ; 显示输入框, 提供默认的热字串:
    IB := InputBox("
    (
    Type your abreviation at the indicated insertion point. You can also edit the replacement text if you wish.

    Example entry: :T:btw::by the way
    )", "New Hotstring",, DefaultValue)
    if IB.Result = "Cancel"  ; 用户选择了取消.
        return

    if RegExMatch(IB.Value, "(?P<Label>:.*?:(?P<Abbreviation>.*?))::(?P<Replacement>.*)", &Entered)
    {
        if !Entered.Abbreviation
            MsgText := "You didn't provide an abbreviation"
        else if !Entered.Replacement
            MsgText := "You didn't provide a replacement"
        else
        {
            Hotstring Entered.Label, Entered.Replacement  ; 现在激活热字串.
            FileAppend "`n" IB.Value, A_ScriptFullPath  ; 保存热字串以备以后使用.
        }
    }
    else
        MsgText := "The hotstring appears to be improperly formatted"

    if IsSet(MsgText)
    {
        Result := MsgBox(MsgText ". Would you like to try again?",, 4)
        if Result = "Yes"
            ShowInputBox(DefaultValue)
    }

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


If - 语法 & 使用 | AutoHotkey v2

If

指定在表达式计算结果为 True(真) 时要执行的语句.

If 表达式
{
    语句
}

备注

如果 If 语句的表达式的计算结果为 true(即除空字符串或数字 0 以外的任何结果), 则执行其下面的行或区块. 否则, 如果存在相应的 Else 语句, 则执行将跳转到其下面的行或区块.

如果 If 拥有多行, 那么这些行必须用大括号括起来(创建一个区块). 但是, 如果只有一行属于 If, 则大括号是可选的. 请参阅此页面底部的示例.

如果表达式以小括号开头, 则 if 后面的空格是可选的, 例如 if(expression).

可以选择使用 One True Brace(OTB) 样式. 例如:

if (x < y) {
    ; ...
}
if WinExist("Untitled - Notepad") {
    WinActivate
}
if IsDone {
    ; ...
} else {
    ; ...
}

与 If 语句不同, Else 语句支持任何类型的语句紧跟在其右边.

相关

表达式, 三元运算符(a?b:c), 区块, Else, While-loop

示例

如果 A_Index 大于 100, 则返回.

if (A_Index > 100)
    return

如果 A_TickCount - StartTime 的结果大于 2*MaxTime + 100, 显示 "Too much time has passed." 并终止脚本.

if (A_TickCount - StartTime > 2*MaxTime + 100)
{
    MsgBox "Too much time has passed."
    ExitApp
}

本例执行如下:

  1. 如果 Color 是单词 "Blue" 或 "White":
    1. 则显示 "The color is one of the allowed values.".
    2. 终止脚本.
  2. 否则如果 Color 是单词 "Silver":
    1. 显示 "Silver is not an allowed color.".
    2. 停止进一步的检查.
  3. 否则:
    1. 显示 "This color is not recognized.".
    2. 终止脚本.
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
}

单个多语句行不需要用大括号括起来.

MyVar := 3
if (MyVar > 2)
    MyVar++, MyVar := MyVar - 4, MyVar .= " test"
MsgBox % MyVar  ; 报告 "0 test".

类似于 AutoHotkey v1 的 If Var [not] between Lower and Upper, 下面的例子检查变量的内容是否在两个值(包括) 之间, 以数字或字母表示.

检查 var 是否在 1 到 5 的范围内:

if (var >= 1 and var <= 5)
    MsgBox var " is in the range 1 to 5, inclusive."

检查 var 是否在 0.0 到 1.0 的范围内:

if not (var >= 0.0 and var <= 1.0)
    MsgBox var " is not in the range 0.0 to 1.0, inclusive."

检查 var 是否在 VarLow 和 VarHigh(包括) 之间:

if (var >= VarLow and var <= VarHigh)
    MsgBox var " is between " VarLow " and " VarHigh "."

检查 var 是否按字母顺序排列在蓝色和红色(包括) 之间:

if (StrCompare(var, "blue") >= 0) and (StrCompare(var, "red") <= 0)
    MsgBox var " is alphabetically between the words blue and red."

允许用户输入一个数字, 并检查它是否在 1 到 10 的范围内:

LowerLimit := 1
UpperLimit := 10
IB := InputBox("Enter a number between " LowerLimit " and " UpperLimit)
if not (IB.Value >= LowerLimit and IB.Value <= UpperLimit)
    MsgBox "Your input is not within the valid range."

类似于 v1 的 If Var [not] in/contains MatchList, 下面的例子检查变量的内容是否匹配列表中的项目.

检查 var 是否是文件扩展名 exe, bat 或 com:

if (var ~= "i)\A(exe|bat|com)\z")
    MsgBox "The file extension is an executable type."

检查 var 是否是质数 1, 2, 3, 5, 7 或 11:

if (var ~= "\A(1|2|3|5|7|11)\z")
    MsgBox var " is a small prime number."

检查 var 是否包含数字 1 或 3:

if (var ~= "1|3")
    MsgBox "Var contains the digit 1 or 3 (Var could be 1, 3, 10, 21, 23, etc.)"

检查 var 是否是 MyItemList 中的一个项目:

; 如果 MyItemList 包含除 | 之外的 RegEx 字符, 则取消下一行的注释
; MyItemList := RegExReplace(MyItemList, "[\Q\.*?+[{()^$\E]", "\$0")
if (var ~= "i)\A(" MyItemList ")\z")
    MsgBox var " is in the list."

允许用户输入一个字符串并检查它是否是单词 yes 或 no:

IB := InputBox("Enter YES or NO")
if not (IB.Value ~= "i)\A(yes|no)\z")
    MsgBox "Your input is not valid."

检查 active_title 是否包含 "Address List.txt" 或 "Customer List.txt", 并检查它是否包含 "metapad" 或 "Notepad":

active_title := WinGetTitle("A")
if (active_title ~= "i)Address List\.txt|Customer List\.txt")
    MsgBox "One of the desired windows is active."
if not (active_title ~= "i)metapad|Notepad")
    MsgBox "But the file is not open in either Metapad or Notepad."


ImageSearch - 语法 & 使用 | AutoHotkey v2

ImageSearch

在屏幕的某个区域中搜索图像.

ImageSearch &OutputVarX, &OutputVarY, X1, Y1, X2, Y2, ImageFile

参数

&OutputVarX, &OutputVarY

类型: VarRef

用来保存在屏幕上找到的图像的左上角像素的 X 和 Y 坐标的变量的引用(如果没有找到匹配, 则这两个变量被置空). 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变了这个设置.

X1, Y1

类型: 整数

要搜索的矩形区域的左上角的 X 和 Y 坐标. 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变了这个设置.

X2,Y2

类型: 整数

要搜索的矩形区域的右下角的 X 和 Y 坐标. 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变了这个设置.

ImageFile

类型: 字符串

图像文件名, 如果未指定绝对路径, 则假定在 A_WorkingDir 中. 支持的图片格式包括 ANI, BMP, CUR, EMF, Exif, GIF, ICO, JPG, PNG, TIF 和 WMF(BMP 图像必须为 16 位或更高). 图标的其他来源包括以下类型的文件: EXE, DLL, CPL, SCR 和其他包含图标资源的类型.

选项: 在文件名前面可以直接添加零个或多个下列选项. 选项间使用单个空格或 tab 分隔. 例如: "*2 *w100 *h-1 C:\Main Logo.bmp".

*Icon N: 要使用文件中第一个图标以外的图标组, 请指定 *Icon 后紧跟着图标组编号. 例如, *Icon2 将加载第二个图标组中的默认图标.

*n(渐变值): 指定 n 为介于 0 和 255(包含) 之间的数字, 用于表示每个像素颜色红/绿/蓝通道强度在任一方向上允许的渐变值. 例如, 如果指定了 *2, 并且像素的颜色是 0x444444, 那么从 0x424242 到 0x464646 的任何颜色都将被视为匹配. 此参数可用于图像的颜色轻微变化或 ImageFile 使用的格式(例如 GIF 或 JPG) 不能准确地在屏幕上表示图像. 如果指定 255 为渐变值, 则匹配所有颜色. 默认渐变值为 0.

*Trans N: 此选项通过指定图像内的某种颜色能匹配屏幕上的任何颜色, 使得更容易找到匹配. 它常用于寻找含有透明区域的 PNG, GIF 和 TIF 文件(然而, 对于图标则不需要此选项, 因为它们的透明度是自动支持的). 对于 GIF 文件, *TransWhite 很可能会有用. 对于 PNG 和 TIF 文件, *TransBlack 可能是最佳的. 否则, 指定 N 为其他颜色名称或 RGB 值(有关详情, 请参阅颜色图表, 或使用 PixelGetColor 的 RGB 模式). 例如: *TransBlack, *TransFFFFAA, *Trans0xFFFFAA.

*w n 和 *h n: 用于缩放图像尺寸的宽度和高度(此宽度和高度也决定了从多图标的 .ICO 文件中加载哪个图标). 如果同时省略这两个选项, 则把从 ICO, DLL 或 EXE 文件中加载的图标调整到系统默认的小图标大小, 通常为 16X16(通过指定 *w0 *h0 您可以强制使用实际/内部的大小). 图标外的其他图像以它们的实际大小加载. 要保持高宽比来缩放图像, 请在其中一个尺寸中指定 -1, 而在另一个中指定正数. 例如, 指定 *w200 *h-1 将缩放图像到 200 像素的宽度同时自动设置其高度.

位图或图标句柄可用于替代文件名. 例如, "HBITMAP:*" handle.

返回值

类型: 整数(布尔值)

如果在指定的区域内找到了图像, 该函数返回 1(true), 如果没有找到, 则返回 0(false).

错误处理

如果检测到无效的参数或图像无法加载, 则抛出 ValueError.

如果内部函数调用失败, 则抛出 OSError.

备注

ImageSearch 可以用来检测屏幕上缺少文本或文本不容易被检索的图形对象. 例如, 它可以用来查找图片按钮, 图标, 网页链接, 或游戏对象的位置. 一旦找到了这些对象, 就可以通过Click 来点击.

在有些时候有用的一个策略是搜索图像中的一小块剪辑而不是整个图像. 此方法可以在图像整体发生变化而其内部某些部分保持不变时提高可靠性. 提取剪辑的一种方法是:

  1. 在活动窗口中图像可见时按下 Alt+PrtScr. 这样把屏幕截图放在了剪贴板中.
  2. 打开图像处理程序, 例如 Paint.
  3. 粘贴剪贴板的内容(即屏幕截图).
  4. 选择对图像而言唯一且不变的区域.
  5. 复制并粘贴那个区域到新的图像文档.
  6. 保存为小文件供 ImageSearch 使用.

要实现匹配, 屏幕上的图像必须与通过 ImageFile 参数及其选项加载的图像具有相同的尺寸.

要搜索的目标区域必须是可见的; 换句话说, 无法搜索隐藏在其他窗口背后的窗口区域. 与之相比, 部分在鼠标光标下方的图像通常可以检测出来. 例外情况是游戏的指针, 在大多数情况下它会遮住在它下方的任何图像.

由于搜索从目标区域的顶行开始往下, 所以如果有多个匹配, 则会找到最接近顶部的那个.

包含透明色的图标会自动允许那个颜色匹配屏幕上的任何颜色. 因此, 在图标后的颜色是不重要的.

ImageSearch 支持 8 位色(256 色) 或更高的屏幕.

搜索行为可能会因显示适配器的颜色深度而变化(尤其对于 GIF 和 JPG 文件). 因此, 如果脚本会在多种颜色深度下运行, 最好在每种深度设置下进行测试. 您可以使用渐变选项(*n) 来辅助协调在多种颜色深度下的搜索行为.

如果屏幕上的图像是半透明的, 则 ImageSearch 很可能无法找到它. 要避免此问题, 请尝试渐变选项(*n) 或使用 WinSetTransparent("Off") 临时地关闭窗口的透明.

相关

PixelSearch, PixelGetColor, CoordMode, MouseGetPos

示例

在活动窗口的某个区域搜索图像, 并在 FoundX 和 FoundY 中存储找到图像的左上角像素的 X 和 Y 坐标.

ImageSearch &FoundX, &FoundY, 40, 40, 300, 300, "C:\My Images\test.bmp"

在屏幕的某个区域搜索图像, 并在 FoundX 和 FoundY 中存储找到图像的左上角像素的 X 和 Y 坐标, 包括高级错误处理.

CoordMode "Pixel"  ; 将下面的坐标解释为相对于屏幕而不是活动窗口的客户端区域.
try
{
    if ImageSearch(&FoundX, &FoundY, 0, 0, A_ScreenWidth, A_ScreenHeight, "*Icon3 " A_ProgramFiles "\SomeApp\SomeApp.exe")
        MsgBox "The icon was found at " FoundX "x" FoundY
    else
        MsgBox "Icon could not be found on the screen."
}
catch as exc
    MsgBox "Could not conduct the search due to the following error:`n" exc.Message


函数列表 | AutoHotkey v2

按字母排序的函数索引

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

转到以以下字母开头的条目: E, I, M, S, W, #.

名称 | 描述
{ ... } (区块) | 区块是用大括号括起来的一个或多个语句. 通常与函数定义和控制流语句一起使用.
{ ... } / Object | 根据属性名称和值对列表创建对象.
[ ... ] / Array | 根据一系列参数值创建数组.
Abs | 返回指定数字的绝对值.
ASin | 返回以弧度表示的反正弦值(其正弦值为指定数字).
ACos | 返回以弧度表示的反余弦值(其余弦值为指定数字).
ATan | 返回以弧度表示的反正切值(其正切值为指定数字).
BlockInput | 禁用或启用用户通过键盘和鼠标与计算机交互的能力.
Break | 退出(终止) 任意类型的 loop 语句.
Buffer | 创建缓冲, 它封装了一个内存块, 以便与其他函数一起使用.
CallbackCreate | 创建一个机器码地址, 当调用该地址时, 将重定向调用到脚本中的函数.
CallbackFree | 删除回调函数并释放其对函数对象的引用.
CaretGetPos | 检索插入符号的当前位置(文本插入点).
Catch | 指定在执行 Try 语句抛出值或错误时执行的一或多条语句.
Ceil | 返回指定数字向上取整后的整数(不含任何 .00 后缀).
Chr | 返回与指定数字所表示的编码相对应的字符串(通常是单个字符).
Click | 在指定坐标处点击鼠标按钮. 它还可以按下鼠标按钮, 转动鼠标滚轮或移动鼠标.
ClipboardAll | 创建一个包含剪贴板上的所有内容的对象(如图片和格式).
ClipWait | 等待, 一直到剪贴板包含数据.
ComCall | 通过索引调用原生 COM 接口方法.
ComObjActive | 检索已注册的 COM 对象.
ComObjArray | 创建用于 COM 的 SafeArray.
ComObjConnect | 将 COM 对象的事件源连接到脚本, 使事件能够被处理.
ComObject | 创建 COM 对象.
ComObjFlags | 检索或更改控制 COM 包装器对象行为的标志.
ComObjFromPtr | 包装一个原始 IDispatch 指针(COM 对象), 以供脚本使用.
ComObjGet | 返回由 COM 组件提供的对象引用.
ComObjQuery | 查询 COM 对象的接口或服务.
ComObjType | 从 COM 对象检索类型信息.
ComObjValue | 检索存储在 COM 包装器对象中的值或指针.
ComValue | 包装一个值, 安全数组或 COM 对象, 以供脚本使用或传递给 COM 方法.
Continue | 跳过当前 loop 语句的剩余部分并继续下一次循环.
ControlAddItem | 将指定的字符串作为新条目添加到列表框或组合框的底部.
ControlChooseIndex | 将列表框, 组合框或标签页控件中的选择设置为指定的条目或选项卡编号.
ControlChooseString | 将列表框或组合框中的选择设置为前导部分与指定字符串匹配的第一个条目.
ControlClick | 向控件发送鼠标按钮或鼠标滚轮事件.
ControlDeleteItem | 从列表框或组合框中删除指定的条目编号.
ControlFindItem | 返回与指定字符串完全匹配的列表框或组合框的条目编号.
ControlFocus | 设置窗口上给定控件的输入焦点.
ControlGetChecked | 如果选中复选框或单选按钮, 返回非零值.
ControlGetChoice | 返回列表框或组合框中当前选定项的名称.
ControlGetClassNN | 返回指定控件的 ClassNN(类名和序号).
ControlGetEnabled | 如果指定的控件是启用的, 返回非零值.
ControlGetFocus | 检索目标窗口的哪个控件具有键盘焦点(如果有的话).
ControlGetHwnd | 返回指定控件的唯一 ID 号.
ControlGetIndex | 返回 ListBox, ComboBox 或 Tab 控件中当前选中的条目或标签的索引.
ControlGetItems | 从列表视图, 列表框, 组合框或下拉列表中返回项目/行的数组.
ControlGetPos | 获取控件的位置和大小.
ControlGetStyle ControlGetExStyle | 返回一个表示指定控件的样式或扩展样式的整数.
ControlGetText | 从控件检索文本.
ControlGetVisible | 如果指定的控件是可见的, 则返回非零值.
ControlHide | 隐藏指定的控件.
ControlHideDropDown | 隐藏组合框控件的下拉列表.
ControlMove | 移动或调整控件的大小.
ControlSend ControlSendText | 向窗口或控件发送模拟的击键或文本.
ControlSetChecked | 打开(选中) 或关闭(取消选中) 复选框或单选按钮.
ControlSetEnabled | 启用或禁用指定的控件.
ControlSetStyle ControlSetExStyle | 分别更改指定控件的样式或扩展样式.
ControlSetText | 更改控件的文本.
ControlShow | 显示先前隐藏的指定控件.
ControlShowDropDown | 显示组合框控件的下拉列表.
CoordMode | 为多个内置函数设置坐标模式, 相对于活动窗口还是屏幕.
Cos | 返回 Number 的余弦值.
Critical | 防止当前线程被其他线程中断, 或开启允许被中断.
DateAdd | 日期-时间值加上或减去时间.
DateDiff | 比较两个日期-时间值并返回差值.
DetectHiddenText | 设置在查找窗口时是否 "看见" 隐藏的文本. 这将影响 WinExist 和 WinActivate 等窗口命令.
DetectHiddenWindows | 设置脚本是否可以 "看见" 隐藏的窗口.
DirCopy | 复制文件夹及其所有子文件夹和文件(类似于 xcopy), 或者复制归档文件(如 ZIP) 的全部内容.
DirCreate | 创建目录.
DirDelete | 删除目录.
DirExist | 检查文件夹是否存在并返回其属性.
DirMove | 移动文件夹及其所有子文件夹和文件. 它也可以重命名一个文件夹.
DirSelect | 显示可以让用户选择文件夹的标准对话框.
DllCall | 调用 DLL 文件中的函数, 例如标准的 Windows API 函数.
Download | 从互联网下载文件.
DriveEject | 弹出或收回指定 CD/DVD 驱动器的托盘, 或弹出可移动驱动器.
DriveGetCapacity | 返回包含指定路径的驱动器的总容量, 单位为 mb(兆字节).
DriveGetFileSystem | 返回指定驱动器的文件系统的类型.
DriveGetLabel | 返回指定驱动器的卷标.
DriveGetList | 返回一串字母, 系统中的每个驱动器字母对应一个字符.
DriveGetSerial | 返回指定驱动器的卷序列号.
DriveGetSpaceFree | 包含指定路径的驱动器的空闲磁盘空间, 单位为 mb(兆字节).
DriveGetStatus | 返回包含指定路径的驱动器的状态.
DriveGetStatusCD | 返回指定 CD/DVD 驱动器的媒体状态.
DriveGetType | 返回包含指定路径的驱动器类型.
DriveLock | 阻止指定驱动器的弹出功能正常工作.
DriveRetract | 收回指定 CD/DVD 驱动器的托盘.
DriveSetLabel | 更改指定驱动器的卷标签.
DriveUnlock | 恢复指定驱动器的弹出功能.
Edit | 在默认编辑器中打开当前脚本进行编辑.
EditGetCurrentCol | 返回编辑控件中插入符号(文本插入点) 所在的列号.
EditGetCurrentLine | 返回编辑控件中插入符号(文本插入点) 所在的行号.
EditGetLine | 返回编辑控件中指定行的文本.
EditGetLineCount | 返回编辑控件中的行数.
EditGetSelectedText | 返回编辑控件中选定的文本.
EditPaste | 将指定的字符串粘贴到编辑控件中的插入符号(文本插入点) 处.
Else | 如果关联语句的主体没有执行, 指定要执行的一个或多个语句.
EnvGet | 检索环境变量的值.
EnvSet | 将值写入指定的环境变量中.
Exit | 退出当前线程.
ExitApp | 终止脚本.
Exp | 返回 e(近似值为 2.71828182845905) 的 N 次幂.
FileAppend | 在文件末尾写入文本或二进制数据(如果需要, 首先创建文件).
FileCopy | 复制一个或多个文件.
FileCreateShortcut | 创建快捷方式(.lnk) 文件.
FileDelete | 永久删除一个或多个文件.
FileEncoding | 为 FileRead, Loop Read, FileAppend 和 FileOpen 设置默认编码.
FileExist | 检查文件或目录是否存在并返回它的属性.
FileInstall | 在已编译的脚本中包含指定的文件.
FileGetAttrib | 报告文件或文件夹是否为只读, 隐藏等.
FileGetShortcut | 获取快捷方式(.lnk) 文件的信息, 例如其目标文件.
FileGetSize | 获取文件的大小.
FileGetTime | 获取文件或文件夹的时间戳.
FileGetVersion | 检索文件的版本.
FileMove | 移动或重命名一个或多个文件.
FileOpen | 打开文件, 从其中读取特定内容和/或将新内容写入其中.
FileRead | 检索文件的内容.
FileRecycle | 如果可能发送文件或目录到回收站, 或永久删除该文件.
FileRecycleEmpty | 清空回收站.
FileSelect | 显示可以让用户打开或保存文件的标准对话框.
FileSetAttrib | 改变一个或多个文件或文件夹的属性. 支持通配符.
FileSetTime | 改变一个或多个文件或文件夹的时间戳. 支持通配符.
Finally | 确保在 Try 语句完成之后始终执行一条或多条语句.
Float | 将数字字符串或整数值转换为浮点数.
Floor | 返回指定数字向下取整后的整数(不含任何 .00 后缀).
For | 对对象中的每对键值对重复执行一或多条语句.
Format | 根据格式字符串格式化一个可变数量的输入值.
FormatTime | 将 YYYYMMDDHH24MISS 时间戳转换为指定的日期/时间格式.
GetKeyName | 检索按键的名称/文本.
GetKeyVK | 检索按键的虚拟键码.
GetKeySC | 检索按键的扫描码.
GetKeyState | 根据指定的键盘按键或鼠标/控制器按钮是上还是下, 返回 1 (true) 或 0(false). 也检索控制器状态.
GetMethod | 检索方法的实现函数.
Goto | 跳转到指定的标签并继续执行.
GroupActivate | 激活由 GroupAdd 定义的窗口组中的下一个窗口.
GroupAdd | 增加窗口规格到窗口组, 必要时创建组.
GroupClose | 关闭刚刚被 GroupActivate 或 GroupDeactivate 激活的活动窗口. 接着激活系列中的下一个窗口. 它还可以关闭组中所有窗口.
GroupDeactivate | 类似于 GroupActivate, 不同的是它激活 不 在组中的下一个窗口.
Gui() | 创建并返回一个新的 Gui 对象. 这可以用来定义一个自定义窗口或图形用户界面(GUI), 以显示信息或接受用户输入.
GuiCtrlFromHwnd | 检索与指定的窗口句柄关联的 GUI 控件的 GuiControl 对象.
GuiFromHwnd | 检索与指定的窗口句柄关联的 Gui 窗口的 Gui 对象.
HasBase | 如果指定的值派生自指定的基对象, 则返回非零数字.
HasMethod | 如果指定的值具有指定名称的方法, 则返回非零数字.
HasProp | 如果指定值具有指定名称的属性, 则返回非零数字.
HotIf / HotIfWin... | 指定后续创建或修改热键变体和热字串变体的条件.
Hotkey | 在脚本运行时创建, 修改, 启用或禁用热键.
Hotstring | 在脚本运行时创建, 修改, 启用或禁用热字串.
If (expression) | 指定在表达式计算结果为 True(真) 时要执行的语句.
IL_Create IL_Add IL_Destroy | 将图标添加到 ListView 或 TreeView 控件的方法.
ImageSearch | 在屏幕的某个区域中搜索图像.
IniDelete | 删除标准格式的 .ini 文件中的值.
IniRead | 从标准 ini 格式文件中读取一个值, 一个段或段名列表.
IniWrite | 写入值或段到标准格式的 .ini 文件.
InputBox | 显示输入框让用户输入字符串.
InputHook | 创建一个可用于收集或拦截键盘输入的对象.
InstallKeybdHook | 安装或卸载键盘钩子.
InstallMouseHook | 安装或卸载鼠标钩子.
InStr | 从左边或右边搜索一个字符串的给定 occurrence(出现).
Integer | 将数字字符串或浮点值转换为整数.
IsLabel | 如果当前作用域中存在指定的标签, 则返回非零数字.
IsObject | 如果指定的值是对象, 则返回非零数字.
IsSet / IsSetRef | 如果指定变量已经被赋值, 则返回一个非零数字.
KeyHistory | 显示脚本信息和最近键击和鼠标点击的历史.
KeyWait | 等待按键或鼠标/控制器按钮被松开或按下.
ListHotkeys | 显示当前脚本使用的热键, 不论它们的子程序当前是否运行, 也不论它们是否使用键盘或鼠标钩子.
ListLines | 启用或禁用行日志记录或显示最近执行的脚本行.
ListVars | 显示脚本的变量: 它们的名称和当前的内容.
ListViewGetContent | 返回 ListView 中的一个项目/行的列表.
LoadPicture | 载入图像文件并返回位图或图标句柄.
Log | 返回指定数字的对数(10 为底).
Ln | 返回指定数字的自然对数(e 为底).
Loop (normal) | 重复执行一或多条语句: 可以指定重复次数或直到遇到 Break.
Loop Files | 检索指定的文件或文件夹, 每次一个.
Loop Parse | 每次从字符串中检索字符串(片段).
Loop Read | 检索文本文件中的行, 每次一行.
Loop Reg | 检索指定的注册表子键的内容, 每次一个项目.
Map | 根据键值对列表创建 Map(映射).
Max | 返回一组数字中的最大值.
MenuBar() | 创建一个 MenuBar 对象, 该对象可用于定义 GUI 菜单栏.
Menu() | 创建一个 Menu 对象, 可用于创建和显示菜单.
MenuFromHandle | 检索对应于 Win32 菜单句柄的 Menu 或 MenuBar 对象.
MenuSelect | 从指定窗口菜单栏中调用菜单项.
Min | 返回一组数字中的最小值.
Mod | 取模. 返回一个数字(被除数) 除以另一个数字(除数) 的余数.
MonitorGet | 检查指定的监视器是否存在, 并可选地检索其边界坐标.
MonitorGetCount | 返回监视器的数量.
MonitorGetName | 返回指定监视器的操作系统名称.
MonitorGetPrimary | 返回主监视器的编号.
MonitorGetWorkArea | 检查指定的监视器是否存在, 并可选地检索其工作区域的边界坐标.
MouseClick | 点击或按住鼠标按钮, 或滚动鼠标滚轮. 注意: Click 函数通常更灵活和易于使用.
MouseClickDrag | 点击并按住指定的鼠标按钮, 接着移动鼠标到目标坐标, 然后松开该按钮.
MouseGetPos | 获取鼠标光标的当前位置, 和可选的它悬停在哪个窗口和控件上.
MouseMove | 移动鼠标光标.
MsgBox | 在含有一个或多个按钮(例如 "是" 和 "否") 的小窗口中显示指定的文本.
Number | 将一个数字字符串转换为一个纯整数或浮点数.
NumGet | 返回存储在指定地址+偏移量处的二进制数.
NumPut | 将一个或多个数字以二进制格式存储在指定的地址+偏移量.
ObjAddRef / ObjRelease | 增加或减少对象的引用计数.
ObjBindMethod | 创建一个绑定函数对象, 它能调用指定对象的方法.
ObjHasOwnProp ObjOwnProps | 这些函数等同于 Object 类型的内置方法. 通常推荐使用相应的方法来代替.
ObjGetBase | 检索对象的基对象.
ObjGetCapacity | 返回对象内部属性数组的当前容量.
ObjOwnPropCount | 返回对象拥有的属性的数量.
ObjSetBase | 设置对象的基对象.
ObjSetCapacity | 设置对象内部自有属性数组的当前容量.
OnClipboardChange | 注册一个每当剪贴板内容发生改变时, 自动调用的函数.
OnError | 注册一个当未处理错误发生时, 自动调用的函数.
OnExit | 注册一个当脚本退出时, 自动调用的函数.
OnMessage | 注册一个当脚本接收到指定消息时, 自动调用的函数.
Ord | 返回指定字符串中首个字符的序号值(数字字符编码).
OutputDebug | 发送字符串到调试器(如果有) 显示出来.
Pause | 暂停脚本的当前线程或设置底层线程的暂停状态.
Persistent | 防止脚本在最后一个线程完成后自动退出, 允许它在空闲状态下运行.
PixelGetColor | 获取指定的 X 和 Y 坐标处像素的颜色.
PixelSearch | 在屏幕某个区域中搜索指定颜色所在的像素.
PostMessage | 将消息放入窗口或控件的消息队列中.
ProcessClose | 强制关闭第一个匹配的进程.
ProcessExist | 检查指定的进程是否存在.
ProcessGetName | 返回指定进程的名称.
ProcessGetParent | 返回创建指定进程的进程 ID(PID).
ProcessGetPath | 返回指定进程的路径.
ProcessSetPriority | 更改第一个匹配进程的优先级.
ProcessWait | 等待指定的进程存在.
ProcessWaitClose | 等待匹配进程关闭.
Random | 生成一个伪随机数字.
RegExMatch | 判断字符串是否包含某个匹配模式(正则表达式).
RegExReplace | 替换字符串中匹配模式(正则表达式) 出现的地方.
RegCreateKey | 创建注册表键而不写入值.
RegDelete | 从注册表中删除值.
RegDeleteKey | 从注册表中删除子键.
RegRead | 从注册表读取值.
RegWrite | 写入值到注册表.
Reload | 使用新的脚本实例替换当前正在运行的.
Return | 从函数返回到之前通过函数调用, Hotkey 激活, 或其他方式执行跳转的地方.
Round | 返回指定数字四舍五入到 N 位小数的数字.
Run | 运行外部程序.
RunAs | 指定一组用户凭据, 应用于后续所有的 Run 和 RunWait 函数.
RunWait | 运行一个外部程序并且等待它运行完毕.
Send / SendText / SendInput / SendPlay / SendEvent | 发送模拟键击和鼠标点击到活动窗口.
SendLevel | 控制热键和热字串是否忽略模拟的键盘和鼠标事件.
SendMessage | 发送消息到窗口或控件并等待回复.
SendMode | 使 Send 等同于 SendEvent 或 SendPlay, 而不是默认的(SendInput). 也使 Click 和 MouseMove/Click/Drag 使用指定的方法.
SetCapsLockState | 设置 CapsLock 的状态. 还可以强制此按键保持打开或关闭状态.
SetControlDelay | 设置每个控件改动函数后将发生的延迟.
SetDefaultMouseSpeed | 设置在 Click, MouseMove, MouseClick 和 MouseClickDrag 中没有指定鼠标速度时使用的速度.
SetKeyDelay | 设置每次 Send 或 ControlSend 发送键击后自动的延时.
SetMouseDelay | 设置每次鼠标移动或单击后发生的延迟.
SetNumLockState | 设置 NumLock 的状态. 还可以强制此按键保持打开或关闭状态.
SetScrollLockState | 设置 ScrollLock 键的状态. 还可以强制此按键保持打开或关闭状态.
SetRegView | 设置 RegRead, RegWrite, RegDelete, RegDeleteKey 和 Loop Reg 使用的注册表视图, 允许它们在 32 位脚本中访问 64 位注册表视图, 反之亦然.
SetStoreCapsLockMode | 在 Send 之后是否恢复 CapsLock 的状态.
SetTimer | 在指定的时间间隔自动重复的调用函数.
SetTitleMatchMode | 设置 WinTitle 参数在内置函数中的匹配行为, 如 WinWait.
SetWinDelay | 设置在每次执行窗口函数(例如 WinActivate) 后的延时.
SetWorkingDir | 更改脚本当前的工作目录.
Shutdown | 关机, 重启或注销系统.
Sin | 返回指定数字的三角正弦值.
Sleep | 在继续前等待指定的时间量.
Sort | 以字母, 数字或随机顺序排列变量的内容(可以选择是否移除重复项).
SoundBeep | 从 PC 扬声器发出声音.
SoundGetInterface | 检索声音设备或组件的原生 COM 接口.
SoundGetMute | 检索声音设备的静音设置.
SoundGetName | 检索声音设备或组件的名称.
SoundGetVolume | 检索声音设备的音量设置.
SoundPlay | 播放音频, 视频或其他支持的文件类型.
SoundSetMute | 更改声音设备的静音设置.
SoundSetVolume | 更改声音设备的音量设置.
SplitPath | 将文件名(路径) 或 URL 分解成它的名称, 目录, 扩展名和驱动器.
Sqrt | 返回指定数字的平方根.
StatusBarGetText | 获取标准状态栏控件的文本.
StatusBarWait | 等待直到窗口的状态栏包含指定的字符串.
StrCompare | 按字母顺序比较两个字符串.
StrGet | 从内存地址或缓冲中复制字符串, 可选地从给定的代码页进行转换.
String | 将值转换为字符串.
StrLen | 检索字符串中的字符数.
StrLower | 将字符串转换为小写.
StrPtr | 返回字符串的当前内存地址.
StrPut | 复制字符串到内存地址或缓冲, 可选地将字符串转换到给定的代码页.
StrReplace | 用新字符串替换指定的子字符串.
StrSplit | 使用指定的分隔符将字符串分成子字符串数组.
StrTitle | 将字符串转换为标题大写.
StrUpper | 将字符串转换为大写.
SubStr | 从字符串中的指定位置检索一个或多个字符.
Suspend | 禁用或启用所有的或选择的热键和热字串.
Switch | 将一个值与多个实例进行比较, 并执行第一个匹配的语句.
SysGet | 获取系统对象的尺寸和其他系统属性.
SysGetIPAddresses | 返回系统的 IPv4 地址数组.
Tan | 返回指定数字的三角正切值.
Thread | 设置线程的优先级或是否可以被中断. 它也可以临时禁用所有的计时器.
Throw | 发生错误时发出信号. 此信号可以被 Try-Catch 语句捕获.
ToolTip | 在屏幕的任意位置显示一个置顶的窗口.
TraySetIcon | 更改脚本的托盘图标(该图标也使用于 GUI 和对话框窗口).
TrayTip | 在托盘图标附近显示一个气球提示窗口. 在 Windows 10 及后续版本中, 会显示一个 toast 通知
Trim / LTrim / RTrim | 移除字符串开头和/或末尾的字符.
Try | 守护一个或多个语句以防备由 Throw 语句抛出的运行时错误和值.
Type | 返回值的类名.
Until | 根据条件判断是否继续执行 Loop 或 For 循环.
VarSetStrCapacity | 增加变量的容量或释放其内存. 一般情况下不需要, 但可以与 DllCall 或 SendMessage 一起使用, 或者优化重复连接.
VerCompare | 对比两个版本字符串.
While-loop | 重复执行一或多条语句, 直到指定的表达式计算结果为假时终止.
WinActivate | 激活指定的窗口.
WinActivateBottom | 与 WinActivate 相同, 只是此函数激活最下面的匹配窗口而不是最上面的.
WinActive | 检查指定的窗口是否被激活并返回其唯一 ID(HWND).
WinClose | 关闭指定的窗口.
WinExist | 检查指定的窗口是否存在并返回其唯一 ID(HWND).
WinGetClass | 获取指定窗口的类名.
WinGetClientPos | 检索指定窗口的工作区的位置和大小.
WinGetControls | 返回指定窗口中所有控件名称(ClassNN) 的数组.
WinGetControlsHwnd | 返回指定窗口中所有控件的唯一 ID 号(HWND) 的数组.
WinGetCount | 返回符合指定条件的现有窗口的数目.
WinGetID | 返回指定窗口的唯一 ID 号(HWND).
WinGetIDLast | 如果找到多个匹配窗口, 则返回最后的/最底部的窗口的唯一 ID 号(HWND).
WinGetList | 返回与指定条件匹配的所有现有窗口的唯一 ID 号(HWND) 的数组.
WinGetMinMax | 如果指定的窗口被最大化或最小化, 则返回一个非零数字.
WinGetPID | 返回指定窗口的进程 ID(PID).
WinGetPos | 获取指定窗口的位置和大小.
WinGetProcessName | 返回指定窗口的进程的名称.
WinGetProcessPath | 返回拥有指定窗口的进程的完整路径和名称.
WinGetStyle WinGetExStyle | 分别返回指定窗口的样式和扩展样式.
WinGetText | 从指定窗口检索文本.
WinGetTitle | 检索指定窗口的标题.
WinGetTransColor | 返回指定窗口中标记为透明的颜色.
WinGetTransparent | 返回指定窗口的透明度的等级.
WinHide | 隐藏指定的窗口.
WinKill | 强制关闭指定的窗口.
WinMaximize | 将指定的窗口放大到最大尺寸.
WinMinimize | 将指定的窗口最小化为任务栏上的按钮.
WinMinimizeAll / WinMinimizeAllUndo | 最小化或还原所有窗口.
WinMove | 改变指定窗口的位置和/或大小.
WinMoveBottom | 发送指定的窗口到堆栈的底部; 也就是说, 在所有其他窗口下方.
WinMoveTop | 将指定的窗口移到堆栈顶部, 而无需显式激活它.
WinRedraw | 重绘指定窗口.
WinRestore | 如果指定的窗口处于最小化或最大化状态, 则还原它.
WinSetAlwaysOnTop | 使指定的窗口停留在所有其他窗口的顶部(除了其他置顶窗口).
WinSetEnabled | 启用或禁用指定的窗口.
WinSetRegion | 将指定窗口的形状改为指定的矩形, 椭圆或多边形.
WinSetStyle WinSetExStyle | 分别改变指定窗口的样式和扩展样式.
WinSetTitle | 更改指定窗口的标题.
WinSetTransColor | 使所选颜色的所有像素在指定的窗口内不可见(透明).
WinSetTransparent | 使指定的窗口半透明.
WinShow | 显示指定的窗口.
WinWait | 等待直到指定的窗口存在.
WinWaitActive / WinWaitNotActive | 等待直到指定的窗口处于活动或不活动状态.
WinWaitClose | 等待直到找不到匹配的窗口.
#ClipboardTimeout | 更改首次尝试访问剪贴板失败时脚本继续尝试访问剪贴板的时间.
#DllLoad | 在脚本开始执行之前加载 DLL 或 EXE 文件.
#ErrorStdOut | 把任何阻止脚本运行的语法错误发送到标准错误(stderr), 而不是显示一个对话框.
#Hotstring | 改变热字串的选项或终止符.
#HotIf | 创建上下文相关的热键和热字串. 它们根据任何条件(表达式) 执行不同的操作(或什么都不做).
#HotIfTimeout | 设置计算单个 #HotIf 表达式可以使用的最大时间.
#Include / #IncludeAgain | 使脚本的行为与指定文件的内容位于此确切位置一样.
#InputLevel | 控制热键和热字串是否忽略模拟的键盘和鼠标事件.
#MaxThreads | 设置可同时存在的线程的最大数目.
#MaxThreadsBuffer | 当某些或所有的热键达到 #MaxThreadsPerHotkey 限制时, 这个指令让它们缓冲而不是忽略键击.
#MaxThreadsPerHotkey | 设置每个热键或热字串可同时存在的最大线程数.
#NoTrayIcon | 禁止托盘图标的显示.
#Requires | 如果不符合版本要求, 则显示错误并退出.
#SingleInstance | 决定当脚本已经运行时是否允许它再次运行.
#SuspendExempt | 从暂停状态中, 豁免后续的热键和热字串.
#UseHook | 强制使用钩子实现全部或部分键盘热键.
#Warn | 启用或禁用特定条件下的警告, 这些条件可能会产生错误, 例如书写错误或缺少 "global(全局)" 声明.
#WinActivateForce | 跳过温和的方法而直接使用强制的方法激活窗口.


IniDelete - 语法 & 使用 | AutoHotkey v2

IniDelete

删除标准格式的 .ini 文件中的值.

IniDelete Filename, Section , Key

参数

Filename

类型: 字符串

.ini 文件名, 如果未指定绝对路径则假定在 A_WorkingDir 中.

Section

类型: 字符串

.ini 文件中的段名, 它是包含在方括号中的标题短语(在此参数中不需要加方括号).

Key

类型: 字符串

如果省略, 将删除整个段. 否则, 请指定 .ini 文件中的键名.

错误处理

失败时抛出 OSError .

无论是否抛出异常, A_LastError 被设置为操作系统的 GetLastError() 函数的结果.

备注

标准的 ini 文件看起来类似下面这样:

[SectionName]
Key=Value

相关

IniRead, IniWrite, RegDelete, RegDeleteKey

示例

从标准格式的 .ini 文件中删除位于 section2 中的一个键及其值.

IniDelete "C:\Temp\myfile.ini", "section2", "key"


IniRead - 语法 & 使用 | AutoHotkey v2

IniRead

从标准 ini 格式文件中读取一个值, 一个段或段名列表.

Value := IniRead(Filename, Section, Key , Default)
Section := IniRead(Filename, Section ,, Default)
SectionNames := IniRead(Filename ,,, Default)

参数

Filename

类型: 字符串

.ini 文件名, 如果未指定绝对路径则假定在 A_WorkingDir 中.

Section

类型: 字符串

.ini 文件中的段名, 它是包含在方括号中的标题短语(在此参数中不需要加方括号).

Key

类型: 字符串

.ini 文件中的键名.

Default

类型: 字符串

如果省略, 失败时抛出 OSError. 否则, 指定失败时(例如未找到所请求的键, 段或文件) 返回的值.

返回值

类型: 字符串

该函数根据 Key 和 Section 参数返回以下值之一:

  • 如果指定了这两个参数, 则函数返回指定键的实际值.
  • 如果省略 Key 参数, 函数返回整个段. 省略注释和空行. 仅检索该段的前 65,533 个字符.
  • 如果同时省略 Key 和 Section, 函数将返回一个以换行符(`n) 分隔的段名列表.

如果这些都无法检索到, 则返回 Default 参数所指示的默认值.

错误处理

只有当 Default 被省略时, 才会在失败时抛出 OSError.

无论是否抛出异常, A_LastError 都会被设置为操作系统的 GetLastError() 函数的结果.

备注

操作系统会自动忽略获取字符串中的前导和尾随空格/制表符. 为避免此情况, 请将字符串括在单引号或双引号中. 最外层的单引号或双引号会被忽略, 但引号内的任何空格都会保留下来.

超过 65535 个字符的值可能会产生不一致的结果.

标准的 ini 文件看起来类似下面这样:

[SectionName]
Key=Value

Unicode: IniRead 和 IniWrite 依靠外部函数 GetPrivateProfileString 和 WritePrivateProfileString 来读取和写入值. 这些函数只支持 UTF-16 件中的 Unicode; 所有其他文件都假定使用系统的默认 ANSI 代码页.

相关

IniDelete, IniWrite, RegRead, file-reading loop, FileRead

示例

从标准格式的 .ini 文件中读取位于 section2 的键的值, 并将其存储在 Value.

Value := IniRead("C:\Temp\myfile.ini", "section2", "key")
MsgBox "The value is " Value


IniWrite - 语法 & 使用 | AutoHotkey v2

IniWrite

写入值或段到标准格式的 .ini 文件.

IniWrite Value, Filename, Section, Key
IniWrite Pairs, Filename, Section

参数

Value

类型: 字符串

将被写入到 Key 的等号(=) 右边的字符串或数字.

如果文本较长, 可以通过延续片段的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

Pairs

类型: 字符串

要写入 .ini 文件的 Section 的完整内容, 不包括 [SectionName] 题头. Key 必须省略. Pairs 不能包含空行. 如果 section 已经存在, 最后一个键=值对之前的所有内容都被覆盖. Pairs 可以包含没有等号(=) 的行, 但这可能会产生不一致的结果. 注释可以写入文件中, 但被 IniRead 读回时将被抛弃.

Filename

类型: 字符串

.ini 文件的名称, 如果未指定绝对路径, 则假定在 A_WorkingDir 中.

Section

类型: 字符串

.ini 文件的段名, 它是包含在方括号中的标题短语(在此参数中不需要加方括号).

Key

类型: 字符串

.ini 文件中的键名.

错误处理

失败时抛出 OSError.

无论是否抛出异常, A_LastError 被设置为操作系统的 GetLastError() 函数的结果.

备注

超过 65,535 个字符的值可以写入文件, 但可能会产生不一致的结果, 因为 IniRead 或其他应用程序通常无法正确读取它们.

标准的 ini 文件看起来类似下面这样:

[SectionName]
Key=Value

新文件使用带有 UTF-16 字节顺序标记的方式来创建, 以确保可以使用全部的 Unicode 字符. 如果不希望这样, 那么请确保在调用 IniWrite 前目标文件已经存在. 例如:

; 创建一个 ANSI 编码的文件.
FileAppend "", "NonUnicode.ini", "CP0"

; 创建一个没有字节顺序标记的 UTF-16 文件.
FileAppend "[SectionName]`n", "Unicode.ini", "UTF-16-RAW"

Unicode: IniRead 和 IniWrite 依靠外部函数 GetPrivateProfileString 和 WritePrivateProfileString 来读取和写入值. 这些函数只支持 UTF-16 件中的 Unicode; 所有其他文件都假定使用系统的默认 ANSI 代码页.

FileAppend "", "NonUnicode.ini", "CP0" ; 在大多数情况下最后一个参数是可选的.

相关

IniDelete, IniRead, RegWrite

示例

将一个值写入位于标准格式 .ini 文件中 section2 的一个键.

IniWrite "this is a new value", "C:\Temp\myfile.ini", "section2", "key"


InputBox - 语法 & 使用 | AutoHotkey v2

InputBox

显示输入框让用户输入字符串.

InputBoxObj := InputBox(Prompt, Title, Options, Default)

参数

Prompt

类型: 字符串

如果为空或省略, 则默认为空文本. 否则, 请指定文本, 通常是用于提示用户期望输入的数据类型的信息. 如果 Prompt 较长, 可以通过延续片段的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

Title

类型: 字符串

如果省略, 则默认为 A_ScriptName 当前的值. 否则, 请指定输入框的标题.

Options

类型: 字符串

如果为空或省略, 则输入框将在屏幕上水平和垂直居中, 默认大小约为 380x200 像素, 具体取决于操作系统版本和主题. 否则, 指定由以下一个或多个选项组成的字符串, 每个选项之间用空格或制表符分隔.

X n 和 Y n: 对话框的 X 和 Y 坐标. 例如, x0 y0 将窗口置于桌面的左上角. 如果省略任何一个坐标, 则对话框将在该维度上居中. 任何一个坐标都可以是负数, 以使对话框部分或完全偏离桌面(或在多显示器设置中的辅助显示器上).

W n 和 H n: 对话框客户端区域的宽度和高度, 不包括标题栏和边框. 例如, w200 h100.

T n: 指定超时时间, 单位为秒. 例如, T10.0 为 10 秒. 如果这个值超过 2147483(24.8 天), 那么它会被设置为 2147483. 达到超时时间后, 输入框窗口会自动关闭同时把 InputBoxObj.Result 设置为单词 "Timeout". InputBoxObj.Value 仍将包含用户输入的内容.

Password: 通过将用户键入的内容替换为屏蔽字符, 隐藏用户输入(例如密码输入). 如果需要一个非默认的屏蔽字符, 请将其紧接在单词 Password 之后. 例如, Password* 将使屏蔽字符变为星号而不是黑色圆圈(子弹).

Default

类型: 字符串

如果为空或省略, 则默认为无字符串. 否则, 指定一个字符串, 该字符串将在对话框首次出现时出现在输入框的编辑字段中. 用户可以通过回退键或其他方式来改变它.

返回值

类型: 对象

此函数返回一个具有以下属性的对象:

  • Value(字符串): 用户输入的文本.
  • Result(字符串): 以下单词之一表示输入框是如何关闭的: OK, Cancel 或 Timeout.

备注

输入框通常看起来像这样:

此对话框允许用户输入文本然后按下 OK 或 CANCEL. 用户可以通过拖动对话框的边界来调整它的大小.

GUI 窗口可以通过 OwnDialogs 选项显示模式输入框. 模式输入框阻止用户与 GUI 窗口交互, 直到输入框被关闭.

相关

Gui 对象, MsgBox, FileSelect, DirSelect, ToolTip, InputHook

示例

允许用户输入隐藏的密码.

password := InputBox("(your input will be hidden)", "Enter Password", "password").value

允许用户输入电话号码.

IB := InputBox("Please enter a phone number.", "Phone Number", "w640 h480")
if IB.Result = "Cancel"
    MsgBox "You entered '" IB.Value "' but then cancelled."
else
    MsgBox "You entered '" IB.Value "'."


InputHook - 语法 & 使用 | AutoHotkey v2

InputHook

创建一个对象, 该对象可用于收集或拦截键盘输入.

InputHookObj := InputHook(Options, EndKeys, MatchList)

参数

Options

类型: 字符串

由零个或多个下列选项组成的字符串(可任意顺序, 中间可选空格):

B: 设置 BackspaceIsUndo 为 0(false), 这会导致 Backspace 被忽略.

C: 设置 CaseSensitive 为 1(true), 使 MatchList 区分大小写.

I: 设置 MinSendLevel 为 1 或给定值, 使任何输入级别低于该值的输入被忽略. 例如, I2 将忽略级别为 0(默认值) 或 1 的任何输入, 但将捕获级别为 2 的输入.

L: 长度限制(例如 L5). 输入的最大允许长度. 当文本达到这个长度时, 输入被终止, EndReason 被设置为单词 Max(除非文本匹配 MatchList 中的一个短语, 在这种情况下 EndReason 被设置为单词 Match). 如果未指定, 则长度限制为 1023.

指定 L0 禁用文本的收集和长度限制, 但并不影响按键生成的文本的统计(请参阅 VisibleText). 这可以与 OnChar, OnKeyDown, KeyOpt 或 EndKeys 参数组合使用.

M: 允许在更大范围内使修饰键击生成文本. 通常情况下, 除了 Shift, Ctrl+Alt(即 AltGr) 或 Ctrl+Alt+Shift(即 AltGr+Shift), 按键和其他修饰键组合将被视为非文本. 该选项会尝试翻译其他修饰键组合. 参考这个例子, 它识别 Ctrl+C:

CtrlC := Chr(3) ; 将 Ctrl-C 对应的字符存储在 CtrlC 变量中.
ih := InputHook("L1 M")
ih.Start()
ih.Wait()
if (ih.Input = CtrlC)
    MsgBox "You pressed Control-C."

默认情况下, 系统将 Ctrl+A 到 Ctrl+Z 映射为 ASCII 控制字符 Chr(1) 到 Chr(26). 系统或活动窗口的键盘布局可定义其他转换. 对于键盘布局未定义修饰符位掩码的修饰符键, 转换可能会忽略. 例如, 如果使用 M 选项, Win+E 通常会转写为 "e".

M 选项可能会导致某些键盘快捷键, 如 Ctrl+← 在 Input 正在进行时出现异常.

T: 设置 Timeout (例如 T3 或 T2.5).

V: 设置 VisibleText 和 VisibleNonText 为 1(true). 通常, 用户的输入被阻止(对系统隐藏). 使用此选项可将用户的击键发送到活动窗口.

*: 通配符. 设置 FindAnywhere 为 1(true), 允许在用户键入的任何位置找到匹配项.

E: 按字符代码而不是键码处理单字符结束键. 如果活动窗口的键盘布局与脚本的键盘布局不同, 则可以提供更一致的结果. 它还可以防止实际上不会产生给定结束字符的键组合结束 Input(输入); 例如, 如果 @ 是结束键, 则在美式键盘中 Shift+2 将触发它, 但 Ctrl+Shift+2 不会触发(在使用 E 选项时). 如果还使用 C 选项, 则结束字符区分大小写.

EndKeys

类型: 字符串

一个由零个或多个按键组成的列表, 其中任何一个键在按下时终止输入(结束键本身不会写入输入缓冲). 当 Input 以这种方式终止时, EndReason 设置为单词 EndKey, EndKey 属性设置为键的名称.

EndKeys 使用类似于 Send 函数的格式. 例如, 指定 "{Enter}.{Esc}" 将使 Enter, . 或 Esc 任一一个都能终止 Input. 使用大括号本身作为结束键, 指定 {{} 和/或 {}}.

要使用 Ctrl, Alt 或 Shift 作为结束键, 请指定键的左和/或右的版本, 而不是中性版本. 例如, 指定 "{LControl}{RControl}" 而不是 "{Control}".

尽管不支持诸如 Alt+C(!c) 这样的修饰键, 而非-字母数字字符(如 ?!:@&{}) 默认情况下需要 Shift 或 AltGr 按键按下与否, 取决于字符的正常输入方式. 如果有 E 选项, 则将单个字符键名解释为字符, 在这种情况下, 修饰符键必须处于正确的状态才能生成该字符. 当同时使用 E 选项和 M 选项时, 通过在 EndKeys 中包括相应的 ASCII 控制字符来支持 Ctrl+A 到 Ctrl+Z.

还可以指定明确的虚拟按键代码, 例如 {vkFF} 或 {sc001}. 这在键没有名称且按下时不产生可见字符的罕见情况下非常有用. 它的键码可以通过按键列表页面底部的步骤来确定.

MatchList

类型: 字符串

以逗号分隔的关键词列表, 其中任何一个都将导致终止输入(在这种情况下, EndReason 将被设置为单词 Match). 用户输入的内容必须完全匹配匹配列表中的某个词组(除非有 * 选项). 此外, 分隔符逗号周围的任何空格或制表符都是有意义的, 这意味着它们是匹配字符串的一部分. 例如, 如果 MatchList 为 "ABC , XYZ", 则用户必须在 ABC 之后或 XYZ 之前键入空格以形成匹配.

两个连续的逗号产生单个原义逗号. 例如, 后面的匹配列表会在 string1 的末尾产生单个原义逗号: "string1,,,string2". 类似的, 后面的匹配列表仅包含其中有一个原义逗号的单个项目: "single,,item".

因为 MatchList 中的项目不被视为单独的参数, 所以列表可以完全包含在一个变量中. 事实上, 如果此列表的长度超过 16383, 那么列表的全部或部分必须包含在变量中, 因为这个长度是任何脚本行的最大长度. 例如, MatchList 可能由 List1 "," List2 "," List3 组成 -- 其中每个变量都包含匹配词组的子列表.

Input 堆栈

任何数量的 InputHook 对象都可以在任何时候创建和进行, 但是它们启动的顺序会影响 Input 的收集方式.

当每个 Input 开始时(通过 Start 方法), 它被推到堆栈的顶部, 只有当 Input 终止时才从堆栈中删除. 键盘事件按最近开始到最早的顺序传递给每个输入. 如果一个输入抑制了一个给定的键盘事件, 那么它就不会再向下传递.

如果击键的发送级别低于 InputHook 的 MinSendLevel, 则忽略 Sent 的击键. 在这种情况下, 击键仍然可以由堆栈中较低的输入来处理.

多个 InputHook 都可以与 MinSendLevel 一起使用, 以分别收集发送的击键和实际击键.

InputHook 对象

InputHook 函数返回一个 InputHook 对象, 该对象具有以下方法和属性.

"InputHookObj" 在下面用作任何 InputHook 对象的占位符, 因为 "InputHook" 是类本身.

  • 方法:
    • KeyOpt: 设置按键或按键列表的选项.
    • Start: 启动收集输入.
    • Stop: 终止 Input 并将 EndReason 设置为单词 Stopped.
    • Wait: 等待, 直到 Input 终止(InProgress 为 false).
  • 常规属性:
    • EndKey: 返回终止 Input 而按下的结束建的名称.
    • EndMods: 返回在 Input 终止时逻辑上是按下的修饰符键的字符串.
    • EndReason: 返回 EndReason 字符串, 该字符串表明了 Input 是如何终止的.
    • InProgress: 如果输入正在进行, 则返回 1(true), 否则返回 0(false).
    • Input: 返回自上次 Input 启动以来收集的任何文本.
    • Match: 返回导致 Input 终止的 MatchList 项目.
    • OnEnd: 检索或设置在 Input 终止时调用的函数对象.
    • OnChar: 检索或设置函数对象, 该函数对象将在字符添加到输入缓冲后调用.
    • OnKeyDown: 检索或设置函数对象, 该函数对象将在按下启用通知的按键时调用.
    • OnKeyUp: 检索或设置函数对象, 该函数对象将在释放启用通知按键时被调用.
  • 选项属性:
    • BackspaceIsUndo: 控制 Backspace 键是否从输入缓冲的末尾删除最近按下的字符.
    • CaseSensitive: 控制 MatchList 是否区分大小写.
    • FindAnywhere: 控制每个匹配项是否可以是输入文本的子字符串.
    • MinSendLevel: 检索或设置要收集的输入的最小发送级别.
    • NotifyNonText: 控制当按下非文本键时是否调用 OnKeyDown 和 OnKeyUp 回调.
    • Timeout: 检索或设置超时值(以秒为单位).
    • VisibleNonText: 控制不产生文本的键或键组合是否可见(不阻止).
    • VisibleText: 控制产生文本的键或键组合是否可见(不阻止).

方法

KeyOpt

设置按键或按键列表的选项.

InputHookObj.KeyOpt(Keys, KeyOptions)

参数

Keys

类型: 字符串

按键列表. 大括号用于括起按键名称, 虚拟键码或扫描码, 类似于 Send 函数. 例如, "{Enter}.{{}" 将应用于 Enter, . 和 {. 按名称, 按 {vkNN} 或按 {scNNN} 指定按键可能会产生三种不同的结果; 有关详情, 请参阅下文.

单独指定字符串 "{All}"(不区分大小写) 以便将 KeyOptions 应用于所有 VK 和所有 SC, 包括下面提到的 {vkE7} 和 {sc000}. 然后可以再次调用 KeyOpt 从特定按键中删除选项.

指定 {sc000} 将 KeyOptions 应用于所有缺乏扫描码的事件.

指定 {vkE7} 将 KeyOptions 应用于 Unicode 事件, 例如由 SendEvent "{U+221e}" 或 SendEvent "{Text}∞" 发送的事件.

KeyOptions

类型: 字符串

下列单字符选项中的一个或多个(空格和制表符).

-(减号): 移除 - 后面的任何选项, 直到下一个 +.

+(加号): 取消任何先前的 -, 否则无效.

E: 结束键. 如果启用, 则按下键终止 Input, 将 EndReason 设置为单词 EndKey, 将 EndKey 设置为键的标准名称. 与 EndKeys 参数不同, Shift 或 AltGr 键的状态将被忽略. 例如, @ 和 2 在美式键盘布局中都相当于 {vk32}.

I: 忽略文本. 通常由该键生成的任何文本都将被忽略, 并且该键被视为非文本键(请参阅 VisibleNonText). 如果键通常不产生文本, 则没有效果.

N: 通知. 在每次按下键时调用 OnKeyDown 和 OnKeyUp 回调.

S: 处理按键后抑制(阻止) 按键. 这将覆盖 VisibleText 或 VisibleNonText 直到使用 -S. +S 意味着 -V.

V: 可见. 防止按键被抑制(阻止). 这将覆盖 VisibleText 或 VisibleNonText 直到使用 -V. +V 意味着 -S.

备注

选项可以通过虚拟键码和扫描码来设置, 并且是累加的.

当按名称指定一个键时, 选项通过 VK 或 SC 来设置. 如果两个物理键共享相同的 VK, 但 SC 不同(如 Up 和 NumpadUp), 则由 SC 处理. 相反, 如果使用 VK 码, 则它将应用于产生该 VK 的任何物理键(这可能会随着时间的推移而变化, 这取决于活动键盘布局).

通过 VK 码删除选项不会影响 SC 设置的任何选项, 反之亦然. 但是, 当按键名删除一个选项并且该名称由 VK 处理时, 对应的 SC 也会删除该选项(根据脚本的键盘布局). 这允许在对所有按键应用一个选项后按名称排除按键.

为了防止一个选项影响按键, 必须从该按键的 VK 和 SC 中删除该选项, 或 sc000 如果按键没有 SC.

Unicode 事件, 例如由 SendEvent "{U+221e}" 或 SendEvent "{Text}∞" 发送的事件, 会受到 vkE7 或 sc000 设置的选项的影响. 应用于 {All} 的任何选项都将应用于 vkE7 和 sc000, 因此要排除 Unicode 事件, 请从两者中删除该选项. 例如:

InputHookObj.KeyOpt("{All}", "+I")  ; 忽略任何事件产生的文本
InputHookObj.KeyOpt("{vkE7}{sc000}", "-I")  ; Unicode 事件除外.

Start

启动收集输入.

InputHookObj.Start()

如果 Input 已经在进行中, 则没有效果.

新启动的 Input 放在 InputHook 堆栈的顶部, 这允许它覆盖任何先前启动的 Input.

此方法安装键盘钩子(如果还没有安装).

Stop

终止 Input 并将 EndReason 设置为单词 Stopped.

InputHookObj.Stop()

如果 Input 不在进行中, 则没有效果.

Wait

等待, 直到 Input 终止(InProgress 为 false).

EndReason := InputHookObj.Wait(MaxTime)

参数

MaxTime

类型: 浮点数

如果省略, 将无期限等待. 否则, 请指定等待的最大秒数. 如果 Input 在 MaxTime 秒后仍在进行中, 则该方法返回且不终止 Input.

返回值

类型: 字符串

此方法返回 EndReason.

常规属性

EndKey

返回结束键的名称, 按下结束键以终止 Input.

KeyName := InputHookObj.EndKey

注意, EndKey 返回按键的 "标准" 名称, 而不管它在 EndKeys 参数中是如何编写的. 例如, {Esc} 和 {vk1B} 都产生 Escape. GetKeyName 可用于检索标准名称.

如果使用 E 选项, EndKey 返回输入的实际字符(如果合适). 否则, 键名将根据脚本的活动键盘布局来确定.

如果 EndReason 不是 "EndKey", EndKey 返回一个空字符串.

EndMods

返回在 Input 终止时逻辑上按下的修饰符的字符串.

Mods := InputHookObj.EndMods

如果所有修饰符在逻辑上都是按下的, 则完整的字符串为:

<^>^<!>!<+>+<#>#

这些修饰符与热键的具有相同的含义. 每个修饰符总是用 <(左) 或 >(右) 限定. 对应的键名是: LCtrl, RCtrl, LAlt, RAlt, LShift, RShift, LWin, RWin.

InStr 可以用来检查给定的修饰符(如 >! 或 ^) 是否存在的. 下面的行可以用来将 Mods 转换成中性修饰符的字符串, 如 ^!+#:

Mods := RegExReplace(Mods, "[<>](.)(?:>\1)?", "$1")

由于这是瞬间发生的, 此属性可能比 GetKeyState 更可靠, 即使在 Input 终止后立即调用 GetKeyState, 或者在 OnEnd 回调中.

EndReason

返回 EndReason 字符串, 该字符串表明了 Input 是如何终止的.

Reason := InputHookObj.EndReason

如果 Input 正在进行, 则返回空字符串.

InProgress

如果输入正在进行, 返回 1(true), 否则返回 0(false).

Boolean := InputHookObj.InProgress

Input

返回自上次 Input 启动以来收集的任何文本.

String := InputHookObj.Input

此属性可在输入进行中或输入结束后使用.

Match

返回导致 Input 终止的 MatchList 项目.

String := InputHookObj.Match

此属性返回匹配项(原始的大小写), 如果省略了 C 选项, 则返回的大小写可能与用户键入的大小写不同. 如果 EndReason 不是 "Match", 则返回空字符串.

OnEnd

检索或设置在 Input 终止时调用的函数对象.

MyCallback := InputHookObj.OnEnd
InputHookObj.OnEnd := MyCallback

MyCallback 是要调用的函数对象. 空字符串意味着没有函数对象.

回调接受一个参数, 定义如下:

MyCallback(InputHookObj) { ...

尽管为参数指定的名称无关紧要, 但它被赋值了一个对 InputHook 对象的引用.

如果不需要相应的信息, 可以省略回调的参数, 但在这种情况下必须指定星号, 例如 MyCallback(*).

该函数作为一个新线程被调用, 因此使用 SendMode 和 DetectHiddenWindows 等设置的默认值重新开始.

OnChar

检索或设置将字符添加到输入缓冲后调用的函数对象.

MyCallback := InputHookObj.OnChar
InputHookObj.OnChar := MyCallback

MyCallback 是要调用的函数对象. 空字符串意味着没有函数对象.

回调接受两个参数, 定义如下:

MyCallback(InputHookObj, Char) { ...

尽管为参数指定的名称无关紧要, 以下值依次赋值给它们:

  1. 一个对 InputHook 对象的引用.
  2. 一个包含该字符(或多个字符, 有关详情, 请参阅下文) 的字符串.

如果不需要相应的信息, 你可以从回调函数参数列表的末尾省略一个或多个参数, 但在这种情况下, 必须指定星号作为最后一个参数, 例如 MyCallback(Param1, *).

多个字符的存在表明在先前最后的键击中使用了一个死键, 但是这两个键不能转换为单个字符. 例如, 在一些键盘布局中 `e 产生 è, 而 `z 产生 `z.

当按下结束键时, 该函数不会被调用.

OnKeyDown

检索或设置当按下启用通知的按键时调用的函数对象.

MyCallback := InputHookObj.OnKeyDown
InputHookObj.OnKeyDown := MyCallback

键-按下通知必须首先由 KeyOpt 或 NotifyNonText 启用.

MyCallback 是要调用的函数对象. 空字符串表示没有函数对象.

回调函数接受三个参数, 可以定义如下:

MyCallback(InputHookObj, VK, SC) { ...

虽然你给参数的名字并不重要, 但是下面的值会依次赋值给它们:

  1. 对 InputHook 对象的引用.
  2. 一个代表按键的虚拟键码的整数.
  3. 一个代表按键的扫描码的整数.

如果不需要相应的信息, 你可以从回调参数列表的末尾省略一个或多个参数, 但在这种情况下, 必须指定星号作为最后一个参数, 例如 MyCallback(Param1, *).

要检索按键名称(如果有), 请使用 GetKeyName(Format("vk{:x}sc{:x}", VK, SC)).

该函数作为一个新线程被调用, 因此使用设置(如 SendMode 和 DetectHiddenWindows) 的默认值重新开始.

当按下结束键时, 该函数不会被调用.

OnKeyUp

检索或设置释放启用通知的按键时调用的函数对象.

MyCallback := InputHookObj.OnKeyUp
InputHookObj.OnKeyUp := MyCallback

按键-释放通知必须首先由 KeyOpt 或 NotifyNonText 启用. 键被认为是文本还是非文本取决于什么时候键被按下. 如果 InputHook 在没有检测到 key-down 的情况下检测到 key-up, 则认为它是非文本.

MyCallback 是要调用的函数对象. 空字符串意味着没有函数对象.

回调函数接受三个参数, 可以定义如下:

MyCallback(InputHookObj, VK, SC) { ...

虽然你给参数的名字并不重要, 但是下面的值会依次赋值给它们:

  1. 一个对 InputHook 对象的引用.
  2. 一个代表按键的虚拟键码的整数.
  3. 一个代表按键的扫描码的整数.

如果不需要相应的信息, 你可以从回调参数列表的末尾省略一个或多个参数, 但是在这种情况下, 必须将星号指定为最后一个参数, 例如 MyCallback(Param1, *).

要检索按键名称(如果有), 请使用 GetKeyName(Format("vk{:x}sc{:x}", VK, SC)).

该函数作为一个新线程, 调用, 因此使用设置(如 SendMode 和 DetectHiddenWindows) 的默认值重新开始.

选项属性

BackspaceIsUndo

控制 Backspace 是否从 Input 缓冲的末尾删除最近按下的字符.

CurrentSetting := InputHookObj.BackspaceIsUndo
InputHookObj.BackspaceIsUndo := NewSetting

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 1(true), 除非被 B 选项覆盖.

NewSetting 是一个布尔值, 用于启用或禁用此设置.

当 Backspace 用作 undo 时, 它被视为文本输入键. 具体来说, 是否抑制该键取决于 VisibleText 而不是 VisibleNonText.

Backspace 与修饰符键(如 Ctrl) 结合使用, 则始终忽略 Backspace(检查的是修饰符的逻辑状态, 而不是物理状态).

注意: 如果输入文本是可见的(如在编辑器中) 并且使用箭头键或其他方法在其中导航, Backspace 仍然会删除最后一个字符, 而不是插入符号(插入点) 后面的字符.

CaseSensitive

控制 MatchList 是否区分大小写.

CurrentSetting := InputHookObj.CaseSensitive
InputHookObj.CaseSensitive := NewSetting

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 0(false), 除非被 C 选项覆盖.

NewSetting 是一个布尔值, 用于启用或禁用此设置.

FindAnywhere

控制每个匹配项是否可以是输入文本的子字符串.

CurrentSetting := InputHookObj.FindAnywhere
InputHookObj.FindAnywhere := NewSetting

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 0(false), 除非被 * 选项覆盖.

NewSetting 是一个布尔值, 用于启用或禁用此设置. 如果为真(true), 则可以在用户键入的任何位置找到匹配(匹配可以是输入文本的子字符串). 如果为假(false), 则用户键入的所有内容必须与 MatchList 中的一个短语匹配. 在这两种情况下, 都必须完整输入 MatchList 中的一个短语.

MinSendLevel

检索或设置要收集输入的最小发送级别.

CurrentLevel := InputHookObj.MinSendLevel
InputHookObj.MinSendLevel := NewLevel

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 0, 除非被 I 选项覆盖.

NewLevel 应该是 0 到 101 之间的整数. 发送级别 低于 此值的事件将被忽略. 例如, 值 101 会忽略 SendEvent 生成的所有输入, 而值 1 只会忽略默认发送级别(0) 的输入.

无论这个设置如何, SendInput 和 SendPlay 方法总是被忽略. 除了 AutoHotkey 以外的任何其他源生成的输入都不会因为这个设置而被忽略.

NotifyNonText

控制当按下非文本键时是否调用 OnKeyDown 和 OnKeyUp 回调.

CurrentSetting := InputHookObj.NotifyNonText
InputHookObj.NotifyNonText := NewSetting

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 0(false).

NewSetting 是一个布尔值, 用于启用或禁用此设置. 如果为 true, 可启用所有不产生文本的按键的通知, 如按下 ← 或 Alt+F. 设置此属性不会影响按键的 options, 因为文本的生成取决于按下按键时活动窗口的键盘布局.

NotifyNonText 通过考虑先前匹配的 VK 码的 key-down 是被归类为文本还是非文本来应用 key-up 事件. 例如, 如果 NotifyNonText 为 true, 那么按下 Ctrl+A 将同时产生对 Ctrl 和 A 的 OnKeyDown 和 OnKeyUp 调用, 而按下 A 本身不会调用 OnKeyDown 或 OnKeyUp, 除非使用 KeyOpt 来启用该键的通知.

有关计为生成文本的键详细信息, 请参阅 VisibleText.

Timeout

检索或设置超时值(以秒为单位).

CurrentSeconds := InputHookObj.Timeout
InputHookObj.Timeout := NewSeconds

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 0, 除非被 T 选项覆盖.

NewSeconds 是一个表示超时的浮点数. 0 意味着没有超时.

超时周期通常在调用 Start 时启动, 但如果在 Input 进行中为该属性赋值, 则会重新启动. 如果在超时时间过去后 Input 仍在进行中, 则终止输入并将 EndReason 设置为单词 Timeout.

VisibleNonText

控制不产生文本的键或键组合是否可见(不阻止).

CurrentSetting := InputHookObj.VisibleNonText
InputHookObj.VisibleNonText := NewSetting

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 1(true). V 选项设置改选项为 1(true).

NewSetting 是一个布尔值, 用于启用或禁用此设置. 如果为真, 不产生文本的键和键组合可能触发热键或被传递到活动窗口. 如果为假, 则会阻止它们.

有关计为生成文本的键详细信息, 请参阅 VisibleText.

VisibleText

控制产生文本的键或键组合是否可见(不阻止).

CurrentSetting := InputHookObj.VisibleText
InputHookObj.VisibleText := NewSetting

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 0(false), 除非被 V option.

NewSetting 是一个布尔值, 用于启用或禁用此设置. 如果为真(true), 产生文本的键和键组合可以触发热键或被传递到活动窗口. 如果为假(false), 则会阻止它们.

导致文本被附加到输入缓冲的任何击键都被视为生成文本, 即使在其他应用程序中通常不会这样做. 例如, 如果使用 M 选项, Ctrl+A 生成文本, 而 Esc 生成控制字符 Chr(27).

尽管死键通常不会立即产生效果, 但它们被视为产生文本. 按下死键也可能导致后面的键生成文本(如果只有死键的字符).

Backspace 仅在作为撤销时才被计为生成文本.

标准的修饰符键和 CapsLock, NumLock 和 ScrollLock 总是可见的(不被阻止).

EndReason

EndReason 属性返回以下字符串之一:

字符串 | 描述
Stopped | Stop 方法已被调用或 Start 方法尚未被调用.
Max | 输入达到允许的最大长度, 且它不匹配 MatchList 中的任何项.
Timeout | Input 超时.
Match | Input(输入) 匹配 MatchList 中的一项. Match 属性包含匹配的项.
EndKey | EndKeys 中的一个被按下终止了输入. EndKey 属性包含终止键的名称或字符, 不带大括号.
 | 如果 Input(输入) 正在进行中, EndReason 为空.

备注

必须先调用 Start 方法, 然后才能收集输入.

InputHook 设计为允许脚本的不同部分都能监视输入, 并且冲突最小. 它可以连续操作, 例如观察任意的单词或其他模式. 它还可以临时运行, 例如收集用户输入或临时覆盖特定(或非-特定) 按键而不干扰热键.

当 Input 正在进行时, 键盘热键仍然有效, 但是如果任何必需的修饰符键被抑制, 或者如果热键使用 reg 方法并且其后缀键被抑制, 则不能激活热键. 例如, 热键 ^+a:: 可能 会被 InputHook 覆盖, 而热键 $^+a:: 会优先, 除非 InputHook 抑制 Ctrl 或 Shift.

按键抑制(阻止) 与否取决于以下因素(按顺序):

  • 如果 V 选项对 VK 或 SC 有效, 则不会抑制.
  • 如果 S 选项对 VK 或 SC 有效, 则抑制.
  • 如果按键是标准修饰键或 CapsLock, NumLock 或 ScrollLock, 则不会抑制.
  • VisibleText 或 VisibleNonText 是否被考虑, 具体取决于按键是否生成文本. 如果该属性为 0(false), 则抑制按键. 有关将哪些按键计为生成文本的详细信息, 请参阅 VisibleText.

Input 正在进行时需要键盘钩子, 但当 Input 终止时, 如果不再需要键盘钩子, 则会自动卸载.

Input 正在进行时, 脚本为自动持续运行, 所以即使没有正在运行的线程, 它也会继续监视输入. 当输入结束时, 脚本可能会自动退出(如果没有正在运行的线程, 并且该脚本由于其他原因而不会持续运行).

AutoHotkey 不支持输入法编辑器(IME). 键盘钩子拦截键盘事件, 并通过使用 ToUnicodeEx 或 ToAsciiEx 将它们转换为文本(VK_PACKET 事件除外, 它封装了单个字符).

如果您使用多种语言或键盘布局, 则 InputHook 会使用活动窗口的键盘布局而不是脚本的(不论 Input 是否可见).

尽管不够灵活, 但热字串更容易使用.

InputHook vs. Input (v1)

在 AutoHotkey v1.1 中, InputHook 是 Input 命令的替代品, 提供了更大的灵活性. 在 2.0 版本中删除了 Input 命令, 但下面的代码基本相同:

; Input OutputVar, % Options, % EndKeys, % MatchList  ; v1
ih := InputHook(Options, EndKeys, MatchList)
ih.Start()
ErrorLevel := ih.Wait()
if (ErrorLevel = "EndKey")
    ErrorLevel .= ":" ih.EndKey
OutputVar := ih.Input

Input 命令终止任何先前由它启动的 Input, 而 InputHook 允许同时多个 Input.

Options 解释相同, 但默认设置不同:

  • Input 命令将输入的长度限制为 16383, 而 InputHook 将其限制为 1023. 这可以使用 L 选项来改写, 并且没有绝对最大值.
  • 默认情况下, Input 命令会阻止文本和非文本击键, 如果使用 V 选项, 则不会阻止. 相比之下, InputHook 默认只阻止文本击键(VisibleNonText 默认为 true), 因此大多数热键可以在输入正在进行时使用.

Input 命令在进行时会阻塞线程, 而 InputHook 允许线程继续, 甚至退出(这允许中断的任何线程继续运行). 脚本可以注册一个 OnEnd 函数, 当输入终止时调用该函数, 而不是等待.

Input 命令只在输入终止后返回用户的输入, 而 InputHook 的 Input 属性允许在任何时候检索它. 脚本可以注册一个 OnChar 函数, 以便在字符增加时调用, 而不是不断地检查 Input 属性.

InputHook 通过 KeyOpt 方法对单个按键提供了更多控制. 这包括添加或删除结束键, 抑制或不抑制特定键, 或忽略特定键生成的文本.

与 Input 命令不同, InputHook 可用于检测不产生文本的键, 而 不 终止输入. 这是通过注册 OnKeyDown 函数和使用 KeyOpt 或 NotifyNonText 来指定相关键来完成的.

如果 MatchList 中的项目导致 Input 终止, 可以参考 Match 属性来确定到底是哪个匹配(当 * 选项存在时这更有用).

尽管脚本可以在 Input 函数返回后查询 GetKeyState, 但有时它无法准确反映输入终止时按下了哪些键. InputHook 的 EndMods 属性反映了 Input 终止时修饰键的逻辑状态.

在向后兼容性方面有一些不同之处:

  • Input 命令以大写存储结束键 A-Z, 即使某些键盘布局中的一些字母是小写的. 将值传递给 Send 会产生 Shift 的击键, 而不是普通的击键. 相比之下, InputHook 的 EndKeys 属性始终返回规范化的名称; 即按下该键而不按住 Shift 或其他修饰键时产生的字符.

  • 如果 EndKeys 中使用的键的名称对应于两个物理键共享 VK(如 NumpadUp 和 Up), 则 Input 命令通过 VK 处理主键通过 SC 处理次要键, 而 InputHook 都通过 SC 来处理. {vkNN} 表示可以通过 VK 来处理按键.

    当结束键由 VK 处理时, 两个物理键都可以终止输入. 例如, {NumpadUp} 将导致通过按下主键盘上的 >↑ 方向键终止 Input 命令, 但是 ErrorLevel 将包含 EndKey:NumpadUp, 因为只考虑 VK.

    当结束键由 SC 处理时, Input 命令将始终为任何给定 VK 的已知辅助 SC 生成名称, 并始终为任何其他键生成 scNNN. 与之相比, InputHook 产生按键名(如果有).

相关

KeyWait, 热字串, InputBox, InstallKeybdHook, 线程

示例

等待用户按下任意一个键.

MsgBox KeyWaitAny()

; 再来一遍, 但不阻止按键.
MsgBox KeyWaitAny("V")

KeyWaitAny(Options:="")
{
    ih := InputHook(Options)
    if !InStr(Options, "V")
        ih.VisibleNonText := false
    ih.KeyOpt("{All}", "E")  ; 结束
    ih.Start()
    ih.Wait()
    return ih.EndKey  ; 返回按键名称
}

等待任何与 Ctrl/Alt/Shift/Win 组合的按键.

MsgBox KeyWaitCombo()

KeyWaitCombo(Options:="")
{
    ih := InputHook(Options)
    if !InStr(Options, "V")
        ih.VisibleNonText := false
    ih.KeyOpt("{All}", "E")  ; 结束
    ; Exclude the modifiers
    ih.KeyOpt("{LCtrl}{RCtrl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}", "-E")
    ih.Start()
    ih.Wait()
    return ih.EndMods . ih.EndKey  ; 返回字符串, 例如 <^<+Esc
}

简单的自动完成: 一周中的任何一天. 除了字母双关外, 这是一个功能齐全的例子. 只需运行脚本并开始输入, 按 Tab 完成或按 Esc 退出.

global WordList := "Monday`nTuesday`nWednesday`nThursday`nFriday`nSaturday`nSunday"

global Suffix := "", SacHook

SacHook := InputHook("V", "{Esc}")
SacHook.OnChar := SacChar
SacHook.OnKeyDown := SacKeyDown
SacHook.KeyOpt("{Backspace}", "N")
SacHook.Start()

SacChar(ih, char)  ; 当一个字符被添加到 SacHook.Input 时调用.
{
    Suffix := ""
    if RegExMatch(ih.Input, "`nm)\w+$", prefix)
        && RegExMatch(WordList, "`nmi)^" prefix[0] "\K.*", Suffix)
        Suffix := Suffix[0]

    if CaretGetPos(cx, cy)
        ToolTip Suffix, cx + 15, cy
    else
        ToolTip Suffix

    ; 只在显示工具提示时拦截 Tab 键.
    ih.KeyOpt("{Tab}", Suffix = "" ? "-NS" : "+NS")
}

SacKeyDown(ih, vk, sc)
{
    if (vk = 8) ; 退格键
        SacChar(ih, "")
    else if (vk = 9) ; Tab 键
        Send "{Text}" Suffix
}

等待用户按下任意键. 不产生可见字符的键 -- 比如修饰键, 功能键和箭头键 -- 被列为结束键, 这样它们也会被检测到.

ih := InputHook("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}")
ih.Start()
ih.Wait()

这是一个可工作的热键示例. 由于热键有波浪(~) 前缀, 它自己的击键将传递到活动窗口. 因此, 如果您在任何编辑器中键入 [btw(或其他匹配短语之一), 脚本将自动执行您选择的操作(例如替换键入的文本). 有关此示例的另一个版本, 请参阅 Switch.

~[::
{
    msg := ""
    ih := InputHook("V T5 L4 C", "{enter}.{esc}{tab}","btw,otoh,fl,ahk,ca")
    ih.Start()
    ih.Wait()
    if (ih.EndReason = "Max")
        msg := 'You entered "{1}", which is the maximum length of text.'
    else if (ih.EndReason = "Timeout")
        msg := 'You entered "{1}" at which time the input timed out.'
    else if (ih.EndReason = "EndKey")
        msg := 'You entered "{1}" and terminated the input with {2}.'

    if msg  ; 如果发现了EndReason, 跳过下面的部分.
    {
        MsgBox Format(msg, ih.Input, ih.EndKey)
        return
    }

    ; 否则, 找到了匹配.
    if (ih.Input = "btw")
        Send("{backspace 4}by the way")
    else if (ih.Input = "otoh")
        Send("{backspace 5}on the other hand")
    else if (ih.Input = "fl")
        Send("{backspace 3}Florida")
    else if (ih.Input = "ca")
        Send("{backspace 3}California")
    else if (ih.Input = "ahk")
        Run("https://www.autohotkey.com")
}


InstallKeybdHook - 语法 & 使用 | AutoHotkey v2

InstallKeybdHook

安装或卸载键盘钩子.

InstallKeybdHook Install, Force

参数

Install

类型: 布尔值

如果省略, 则默认为 true.

如果为 true, 则需要安装钩子.

如果为 false, 此函数之前设置的任何需求都将被删除, 可能会卸载钩子.

Force

类型: 布尔值

如果省略, 则默认为 false.

如果为 false, 内部变量会被更新, 以表明脚本是否需要钩子, 但是如果钩子是其他目的而需要的, 可能不会有直接的变化.

如果 true 和 Install 为 true, 钩子会被卸载和重新安装. 这具有使其优先于其他进程先前安装的钩子的效果. 如果系统由于一个无响应的程序而停止调用该钩子, 重新安装该钩子可能会使其再次工作.

如果 true 和 Install 为 false, 那么钩子就会被卸载, 即使是其他目的需要. 如果热键, 热字串或 InputHook 需要钩子, 它将停止工作, 直到该钩子被重新安装. 钩子可以通过调用这个函数显式地被重新安装, 也可以作为启用或禁用热键或调用其他需要钩子的函数的副作用而自动安装.

备注

键盘钩子监视击键, 以便激活热字串和任何 RegisterHotkey(操作系统内置的函数) 不支持的键盘热键. 它还支持其他一些特性, 如 InputHook 函数.

AutoHotkey 不会无条件安装键盘和鼠标钩子, 因为它们合起来至少占用 500 KB 的内存. 因此, 通常仅在脚本包含以下内容之一时才会安装键盘钩子: 1) 热字串; 2) 一个或多个需要键盘钩子(大多数不需要) 的热键; 3) SetCaps/Scroll/NumLock AlwaysOn/AlwaysOff; 4) 激活 Input 钩子.

与之相比, InstallKeybdHook 函数可以用来无条件安装键盘钩子, 它的好处包括:

  • KeyHistory 可以用来显示最近的 20 次击键(用于调试).
  • 可以可靠地跟踪修饰符键的物理状态, 这就消除了 A_HotkeyModifierTimeout 的需要, 并且可以提高 Send 将临时释放的修饰符键恢复到合适状态的可靠性.
  • GetKeyState 可以检索到一个键的物理状态.
  • A_TimeIdleKeyboard 和 A_TimeIdlePhysical 可以正确工作(分别忽略鼠标输入和人工输入).
  • 使用 Alt 修饰符的鼠标热键(如 !LButton::) 可以更有效地抑制窗口菜单, 当 Alt 键释放时只发送一个菜单掩饰键, 而不是每次单击按钮时发送一个.

不需要钩子的键盘热键将使用 reg 方法, 即使使用 InstallKeybdHook 函数. 相比之下, 将 #UseHook 指令或 $ 前缀应用于键盘热键, 强制需要钩子, 如果热键被启用, 就会导致钩子被安装.

你可以通过 KeyHistory 函数或菜单项来确定脚本是否在使用钩子. 你可以通过 ListHotkeys 函数或菜单项来确定哪些热键正在使用钩子.

相关

InstallMouseHook, #UseHook, Hotkey, InputHook, KeyHistory, Hotstrings, GetKeyState, KeyWait

示例

无条件安装键盘钩子.

InstallKeybdHook


InstallMouseHook - 语法 & 使用 | AutoHotkey v2

InstallMouseHook

安装或卸载鼠标钩子.

InstallMouseHook Install, Force

参数

Install

类型: 布尔值

如果省略, 则默认为 true.

如果为 true, 则需要安装钩子.

如果为 false, 此函数之前设置的任何需求都将被删除, 可能会卸载钩子.

Force

类型: 布尔值

如果省略, 则默认为 false.

如果为 false, 内部变量会被更新, 以表明脚本是否需要钩子, 但是如果钩子是其他目的而需要的, 可能不会有直接的变化.

如果 true 和 Install 为 true, 钩子会被卸载和重新安装. 这具有使其优先于其他进程先前安装的钩子的效果. 如果系统由于一个无响应的程序而停止调用该钩子, 重新安装该钩子可能会使其再次工作.

如果 true 和 Install 为 false, 那么钩子就会被卸载, 即使是其他目的需要. 如果热键, 热字串或 InputHook 需要钩子, 它将停止工作, 直到该钩子被重新安装. 钩子可以通过调用这个函数显式地被重新安装, 也可以作为启用或禁用热键或调用其他需要钩子的函数的副作用而自动安装.

备注

鼠标钩子监视鼠标的点击, 以便激活鼠标热键和辅助热字串.

AutoHotkey 不会无条件安装键盘和鼠标钩子, 因为它们合起来至少占用 500 KB 的内存(但如果安装了键盘钩子, 安装鼠标钩只需要大约 50 KB 的额外内存; 反之亦然). 因此, 通常只有当脚本包含一个或多个鼠标热键时才会安装鼠标钩子. 它也会为热字串安装, 但这可以通过 #Hotstring NoMouse 禁用.

与之相比, InstallMouseHook 函数可以用来无条件安装鼠标钩子, 它的好处包括:

  • KeyHistory 可以用来监控鼠标的点击.
  • GetKeyState 可以检索到一个按钮的物理状态.
  • A_TimeIdleMouse 和 A_TimeIdlePhysical 可以正确工作(分别忽略键盘输入和人工输入).

你可以通过 KeyHistory 函数或菜单项来确定脚本是否在使用钩子. 你可以通过 ListHotkeys 函数或菜单项来确定哪些热键正在使用钩子.

相关

InstallKeybdHook, #UseHook, Hotkey, KeyHistory, GetKeyState, KeyWait

示例

无条件安装鼠标钩子.

InstallMouseHook


InStr - 语法 & 使用 | AutoHotkey v2

InStr

在一个字符串中向右或向左搜索指定内容.

FoundPos := InStr(Haystack, Needle , CaseSense, StartingPos, Occurrence)

参数

Haystack

类型: 字符串

搜索其内容的字符串.

Needle

类型: 字符串

要搜索的字符串.

CaseSense

类型: 字符串或整数(布尔值)

如果省略, 默认为 Off. 否则, 指定下列值之一:

On 或 1(true): 搜索区分大小写.

Off 或 0(false): 搜索不区分大小写, 即字母 A-Z 被视为与其小写字母相同.

Locale:: 根据当前用户的区域设置规则, 搜索是不区分大小写的. 例如, 在大多数英语及西欧地区, 不仅将 A-Z 视为等同于它们的小写形式, 同时也将非-ASCII 字母(如 Ä 和 Ü) 视为等同的. 根据被比较字符串的性质, Locale 比 Off 慢 1 到 8 倍.

StartingPos

类型: 整数

如果省略, 搜索整个字符串. 否则, 指定开始搜索的位置, 其中 1 是第一个字符, 2 是第二个字符, 以此类推. 负值从 Haystack 的末尾开始计算, 所以 -1 是最后一个字符, -2 倒数第二个, 以此类推.

如果省略 Occurrence, 负的 StartingPos 会导致搜索从右到左进行. 然而, 如果指定了 Occurrence, StartingPos 对搜索的方向没有影响.

对于从右到左的搜索, StartingPos 指定了第一个可能出现的 Needle 的 最后 一个字符的位置. 例如, InStr("abc", "bc",, 2, +1) 会找到一个匹配, 但 InStr("abc", "bc",, 2, -1) 则不会.

如果 StartingPos 的绝对值大于 Haystack 的长度, 将返回 0.

Occurrence

类型: 整数

如果省略, 它默认为 Haystack 中的第一个匹配. 如果 StartingPos 为负数, 搜索将从右向左进行; 否则将从左向右进行.

如果 Occurrence 是正数, 搜索总是从左到右进行. 为 Occurrence 指定 2 来返回第二个匹配的位置, 3 来返回第三个匹配的位置, 等等.

如果 Occurrence 是负数, 搜索总是从右到左进行. 例如, -2 搜索从右边开始的第二次出现.

返回值

类型: 整数

该函数返回字符串 Needle 在字符串 Haystack 中的出现位置. 位置 1 表示第一个字符; 因为 0 等同于 "false", 使它能提供直觉上 "没找到" 的意义.

不管 StartingPos 或 Occurrence 的值是多少, 返回值总是相对于 Haystack 中的第一个字符. 例如, "abc" 在 "123abc789" 中的位置始终是 4.

传统上, 空字符串("") 的出现可以在任何位置找到. 然而, 由于空白的 Needle 通常只会被错误传递, 因此会被视为一个错误(抛出异常).

错误处理

在以下任何一种情况下都会抛出 ValueError:

  • Needle 是一个空(零长度) 字符串.
  • CaseSense 是无效的.
  • Occurrence 或 StartingPos 为 0 或非数字.

备注

RegExMatch 可用于搜索字符串中的模式(正则表达式), 这使得它比 InStr 更为灵活. 但是, 在搜索简单的子字符串时, InStr 通常比 RegExMatch 更快.

InStr 只搜索到第一个二进制零(空终止符), 而 RegExMatch 搜索整个字符串的长度, 即使它包含二进制零.

相关

RegExMatch, Is 函数

示例

报告子字符串 "abc" 在字符串 "123abc789" 中以 1 开始的位置.

MsgBox InStr("123abc789", "abc") ; 返回 4

在 Haystack 中搜索 Needle.

Haystack := "The Quick Brown Fox Jumps Over the Lazy Dog"
Needle := "Fox"
If InStr(Haystack, Needle)
    MsgBox "The string was found."
Else
    MsgBox "The string was not found."

演示不区分大小写和区分大小写搜索的区别.

Haystack := "The Quick Brown Fox Jumps Over the Lazy Dog"
Needle := "the"
MsgBox InStr(Haystack, Needle, false, 1, 2) ; 不区分大小写的搜索, 返回第二次匹配的位置
MsgBox InStr(Haystack, Needle, true) ; 区分大小写的搜索, 返回首次匹配的位置, 结果同上


Integer - 语法 & 使用 | AutoHotkey v2

Integer

将数字字符串或浮点值转换为整数.

IntValue := Integer(Value)

返回值

类型: 整数

函数返回将 Value 转换为纯整数(类型名称为 "Integer") 的结果, 或 Value 本身(如果它已经是正确的类型).

备注

任何 Value 的小数部分都会被删除, 等同于 Value < 0 ? Ceil(Value) : Floor(Value).

如果值无法转换, 则抛出 TypeError.

要确定一个值是否可以转换为整数, 使用 IsNumber 函数.

Integer 实际上是一个类, 但可以作为一个函数被调用. Value is Integer 可以用来检查一个值是否是一个纯整数.

相关

Type, Float, Number, String, 值, 表达式, Is 函数


Is 函数列表 - 语法 & 使用 | AutoHotkey v2

Is 函数

用于检查给定值的类型和其他条件的函数.

Result := IsSomething(Value , Mode)

这有三类函数:

  • Type: 检查一个值的类型, 或者一个字符串是否可以被解释为该类型的值.
  • Misc: 根据给定的值或变量引用, 检查杂项条件.
  • String: 检查字符串是否与特定模式匹配.

Mode 仅对 IsAlpha, IsAlnum, IsUpper 和 IsLower 有效. 默认情况下, 只考虑 ASCII 字母. 要根据当前用户的区域规则执行检查, 请为 Mode 参数指定字符串 "Locale". 也可以通过指定 0 或 1 来使用默认模式.

Type

检查一个值的类型, 或者一个字符串是否可以被解释为该类型的值.

函数 | 描述
IsInteger | 如果 Value 是整数或不带小数点的纯数字字符串(十进制或十六进制), 则为 True. 允许前导和尾随空格和制表符. 该字符串可以以加号或减号开头, 并且不能为空.
IsFloat | 如果 Value 是浮点数或包含小数点的纯数字字符串, 则为 True. 允许前导和尾随空格和制表符. 该字符串可以以加号, 减号或小数点开头, 并且不能为空.
IsNumber | 如果 IsInteger(Value) or IsFloat(Value) 为 true, 则为 True.
IsObject | 如果 Value 是一个对象. 这包括从 Object 派生的对象, 原型对象(如 0.base) 和 COM 对象, 但不包括数字或字符串.

Misc

根据给定的值或变量引用, 检查杂项条件.

函数 | 描述
IsLabel | 如果 Value 是当前作用域中定义的标签的名称, 则为 True.
IsSet | 如果变量 Value 已经被赋值, 则为 True.
IsSetRef | 如果 Value 所包含的 VarRef 已经被赋值, 则为 True.

String

检查字符串是否符合特定的模式. Value 必须是一个字符串, 否则抛出 TypeError.

函数 | 描述
IsDigit | 如果 Value 是一个正整数, 一个空字符串, 或仅包含字符 0 到 9 的字符串, 则为 True. 不允许使用其他字符, 例如以下字符: 空格, 制表符, 正号, 负号, 小数点, 十六进制数字, 以及 0x 前缀.
IsXDigit | 十六进制数字: 与 IsDigit 相同, 但也允许使用字符 A 到 F(大写或小写). 如果存在前缀 0x, 则可以接受.
IsAlpha | 如果 Value 是字符串, 可以为空字符串或仅包含字母字符. 如果字符串任意位置有任何 digit, 空格, 制表符, 标点或其他非字母的字符时, 则为 False. 例如, 如果 Value 包含一个空格后跟字母, 则 不被 视为 alpha. 默认情况下, 只考虑 ASCII 字母. 如果要根据当前用户的区域规则来执行检查, 请使用 IsAlpha(Value, "Locale").
IsUpper | 如果 Value 是字符串, 可以为空字符串或仅包含大写字母字符, 则为 True. 如果字符串任意位置有任何 digit, 空格, 制表符, 标点或其他非大写字母的字符时, 则为 False. 默认情况下, 只考虑 ASCII 字母. 如果要根据当前用户的区域规则来执行检查, 请使用 IsUpper(Value, "Locale").
IsLower | 如果 Value 是字符串, 可以为空字符串或仅包含小写字母字符, 则为 True. 如果字符串任意位置有任何 digit, 空格, 制表符, 标点或其他非小写字母的字符时, 则为 False. 默认情况下, 只考虑 ASCII 字母. 如果要根据当前用户的区域规则来执行检查, 请使用 IsLower(Value, "Locale").
IsAlnum | 除了还允许 0 到 9 的数字外, 其他与 IsAlpha 相同.
IsSpace | 如果 Value 是字符串, 可以为空字符串或仅包含下列空白字符: 空格(A_Space 或 `s), 制表符(A_Tab 或 `t), 换行符(`n), 回车符(`r), 垂直制表符(`v) 和进纸符(`f), 则为 True.
IsTime | 如果 Value 是有效的日期时间戳, 可以是 YYYYMMDDHH24MISS 格式的全部或开始部分, 则为 True. 例如, 类似 2004 这样的 4 位字符串被视为有效的. 使用 StrLen 确定是否存在其他时间分量. Value 必须为 4 到 14(包括) 之间的偶数位才被认为有效. 小于 1601 的年份会被视为无效的, 因为操作系统通常不支持它们. 被视为有效的最大年份为 9999.

备注

由于在脚本开始执行之前, 原义数字(如 128, 0x7F 和 1.0) 会转换为纯数字, 因此原义数字的格式会丢失. 为了避免混淆, 上面列出的字符串函数如果给定一个纯数字, 则抛出异常.

相关

A_YYYY, FileGetTime, If, StrLen, InStr, StrUpper, DateAdd

示例

检查 var 是浮点数还是整数, 并检查它是否是有效的时间戳.

if isFloat(var)
    MsgBox var " is a floating point number."
else if isInteger(var)
    MsgBox var " is an integer."
if isTime(var)
    MsgBox var  " is also a valid date-time."


IsLabel - 语法 & 使用 | AutoHotkey v2

IsLabel

如果当前作用域中存在指定的标签, 则返回非零数字.

Boolean := IsLabel(LabelName)

参数

LabelName

类型: 字符串

标签的名称. 不包含末尾的冒号.

返回值

类型: 整数(布尔值)

如果指定的标签在当前作用域内存在, 函数返回 1(true), 否则, 为 0(false).

备注

当为 Goto 指定动态标签时, 此函数可以避免运行时错误.

当从函数内部调用时, 只搜索该函数的标签. 全局标签不是局部 goto 的有效目标.

相关

标签

示例

报告 "Target label exists" , 因为子程序确实存在.

if IsLabel("Label")
    MsgBox "Target label exists"
else
    MsgBox "Target label doesn't exist"

Label:
return


IsObject - 语法 & 使用 | AutoHotkey v2

IsObject

如果指定的值是对象, 则返回非零数字.

Boolean := IsObject(Value)

参数

Value

类型: Any

要检查的值.

返回值

类型: 整数(布尔值)

如果 Value 是一个对象, 函数返回 1(true), 否则, 返回 0(false).

备注

任何不是原始值(数字或字符串) 的值都被认为是对象, 包括那些不是从 Object 派生的值, 例如 COM 封装对象. 之所以有这种区别, 是因为对象与原始值相比有几个共同的特征:

  • 每个对象都是动态分配和引用计数的. 任意数量的变量, 属性或数组元素都可以引用同一个对象. 对于不可变值, 这种区别并不重要, 但对象可以具有可变属性.
  • 每个对象都有一个唯一的地址, 这也是一个与 IDispatch 兼容的接口指针.
  • 只有在是同一对象时, 一个对象与另一个值比较才比较相等.
  • 对象不能隐式地转换为字符串或数字.

相关

Objects

示例

报告 "This is an object." 因为值是对象.

obj := {key: "value"}

if IsObject(obj)
    MsgBox "This is an object."
else
    MsgBox "This is not an object."


IsSet / IsSetRef - 语法 & 使用 | AutoHotkey v2

IsSet / IsSetRef

如果指定变量已经被赋值, 则返回一个非零数字.

Boolean := IsSet(Var)
Boolean := IsSetRef(&Ref)

参数

Var

类型: 变量

一个直接变量引用. 例如: IsSet(MyVar).

&Ref

类型: VarRef

对变量的间接引用. 通常不会像在 IsSetRef(&MyVar) 中那样直接传递, 而是间接传递, 比如在解引用一个 包含 VarRef 的参数之前检查它.

返回值

类型: 整数(布尔值)

如果 Var 或由 Ref 表示的变量已经被赋值, 则函数返回 1(true), 否则为 0(false).

备注

使用 IsSet 来直接检查一个变量, 如 IsSet(MyGlobalVar).

使用 IsSetRef 来检查一个 VarRef, 它通常被一个变量所包含, 如下面的示例所示.

未赋值的变量也称为未初始化变量. 默认情况下, 试图读取一个未初始化的变量会导致异常抛出. IsSet 可以用来避免这种情况, 例如在第一次使用全局变量或静态变量时是否需要初始化.

注意: 静态初始化 如 static my_static_array := [] 只被计算一次, 即在执行过程中第一次到达时, 因此通常不需要使用 IsSet.

尽管 IsSet 使用了与函数调用相同的语法, 但它可以被认为是一个操作符而不是一个函数. 关键字 IsSet 保留用于此处所示的用法, 不能被重新定义为一个变量或函数. IsSet 不能被间接调用, 因为任何试图传递一个未初始化的变量的行为都会导致错误的产生.

IsSetRef 也可以用来检查一个特定的变量, 通过与引用操作符一起使用. 当以这种方式使用它时, 要注意如果是全局变量需要先声明该变量. 例如, 如果在一个没有声明 global MyVar 的假设-局部函数中使用的话, IsSetRef(&MyVar) 中的 & 会导致 MyVar 默认解析为一个局部变量.

相关

ByRef 参数

示例

显示 IsSet 和 IsSetRef 的不同用法.

Loop 2
    if !IsSet(MyVar)  ; 是否是第一次 "使用" MyVar?
        MyVar := A_Index  ; 第一次 "使用" 时进行初始化.
MsgBox Function1(&MyVar)
MsgBox Function2(&MyVar)

Function1(&Param)  ; ByRef 参数.
{
    if IsSet(Param)  ; 传递 Param 本身, 它是 MyVar 的别名.
        return Param  ; ByRef 参数会自动解引用.
    else
        return "unset"
}
Function2(Param)
{
    if IsSetRef(Param)  ; 传递包含 VarRef 的 Param.
        return %Param%  ; 显式解引用 Param.
    else
        return "unset"
}


KeyHistory - 语法 & 使用 | AutoHotkey v2

KeyHistory

显示脚本信息和最近键击和鼠标点击的历史.

KeyHistory MaxEvents

参数

MaxEvents

类型: 整数

如果省略, 将会显示脚本的主窗口, 等同于选择 "View->Key history" 菜单项. 否则, 指定可以记录在窗口中显示的键盘和鼠标事件的最大数量(限制为 500). 按键历史也被重置, 但主窗口不显示或刷新. 指定 0 来完全禁用按键历史记录.

备注

如果不使用 KeyHistory, 则默认值为 40.

要禁用按键历史记录, 请使用以下方法:

KeyHistory 0

此特性旨在帮助调试脚本和热键. 通过使用按键列表页面底部描述的步骤, 它还可以用来检测非标准键盘按键的扫描码(知道按键的扫描码就可以把这个按键用在热键中).

滚轮事件(WheelDown, WheelUp, WheelLeft 和 WheelRight) 的虚拟键码(VK) 是一些在 AutoHotkey 外没有任何意义的占位符值. 此外, 滚轮事件的扫描码实际上是滚轮转动的格数(通常为 1).

如果脚本没有安装键盘钩子, 那么 KeyHistory 窗口将只显示由脚本自己(即不包含用户的) 生成的按键事件. 如果脚本没有安装鼠标钩子, 那么将不显示鼠标按钮事件. 可以通过脚本主窗口(通过托盘图标中的 "Open" 来访问) 中的 "View->Key History" 来确定您的脚本是否使用了任何一种钩子. 通过添加下面两行语句中的任何一行或同时添加两行到脚本中, 可以强制安装钩子:

InstallKeybdHook
InstallMouseHook

因为每个击键或鼠标点击都由一个向下的事件和一个向上的事件组成, 所以 KeyHistory 只显示 MaxEvents 所指定的一半的 "完整事件". 例如, 如果脚本调用 KeyHistory 50, 最多可显示 25 个击键和鼠标点击.

相关

InstallKeybdHook, InstallMouseHook, ListHotkeys, ListLines, ListVars, GetKeyState, KeyWait, A_PriorKey

示例

在主窗口中显示历史信息.

KeyHistory

导致 KeyHistory 显示最后 00 个而不是 40 个键盘和鼠标事件.

KeyHistory 100

完全停用按键历史.

KeyHistory 0


KeyWait - 语法 & 使用 | AutoHotkey v2

KeyWait

等待按键或鼠标/控制器按钮被松开或按下.

KeyWait KeyName , Options

参数

KeyName

类型: 字符串

此参数可以是键盘中任何的单个字符或按键列表中的一个键名, 例如鼠标/控制器按钮. 不支持除控制器按钮外的其他控制器属性.

还可以指定明确的虚拟按键代码, 例如 vkFF. 只有在一个按键没有指定名称且按下时不产生可见的字符这样少见的情况下, 这种方法才有用. 它的虚拟按键代码可以通过按键列表页面底部的步骤来确定.

Options

类型: 字符串

如果为空或省略, 则函数会无限期等待用户松开指定的按键或鼠标/控制器按钮. 不过, 如果没有安装键盘钩子并且 KeyName 是使用类似 Send 函数模拟释放的键盘按键, 则此按键会被视为物理松开了. 没有安装鼠标钩子时, 对鼠标按钮同样如此.

否则, 指定一个或多个下列选项组成的字符串(可任意顺序, 字母间可以用空格分隔):

D: 等待按键被按下.

L: 检测按键的逻辑状态, 这是操作系统和活动窗口所认为的按键所处的状态(可能和它的物理状态不一致). 对于控制器按钮会忽略此选项.

T: 超时(例如 T3). 超时前等待的秒数, 超时后返回 0. 如果按键或按钮达到指定的状态, 则函数不再等待超时时间到期. 相反地, 它会立即返回 1.

此超时时间值可以为浮点数(例如 2.5), 但不能为十六进制值(例如 0x03).

返回值

类型: 整数(布尔值)

如果该函数超时, 则此函数返回 0(false), 否则返回 1(true).

备注

如果没有安装键盘和/或鼠标钩子, 则按键或鼠标按钮的物理状态通常和逻辑状态一致(有时逻辑状态可能比物理状态滞后); 如果安装了钩子, 则它会准确反映出用户是否按下了按键. 您可以通过 KeyHistory 函数或菜单项确定脚本中是否使用了钩子. 通过添加 InstallKeybdHook 和 InstallMouseHook 函数到脚本中你可以强制安装其中一种或两种钩子.

当函数处于等待状态时, 可以通过热键, 自定义菜单项或计时器启动新的线程.

要等待两个或多个按键被释放, 请连续使用 KeyWait. 例如:

KeyWait "Control"  ; 等待 Control 和 Alt 被释放.
KeyWait "Alt"

要等待一组按键中的任意一个被按下, 请参阅 InputHook 示例 #4.

相关

GetKeyState, Key List, InputHook, KeyHistory, InstallKeybdHook, InstallMouseHook, ClipWait, WinWait

示例

等待 A 被释放.

KeyWait "a"

等待鼠标左键被按下.

KeyWait "LButton", "D"

等待第一个控制器按钮在 3 秒内被按下.

KeyWait "Joy1", "D T3"

等待左 Alt 键被逻辑释放.

KeyWait "LAlt", "L"

当按下这个热键时, KeyWait 会等待用户物理释放 CapsLock 键. 因此, 后续的语句是在释放而不是按下时执行的. 这个行为类似于 ~CapsLock up::.

~CapsLock::
{
    KeyWait "CapsLock"  ; 等待用户物理释放按键.
    MsgBox "按下和释放了 CapsLock 键."
}

重映射按键或鼠标按钮(该示例仅为了演示, 因为使用内置的重映射功能会更容易). 在下面的热键中, 当 NumpadAdd 按下时持续按住鼠标左键, 这样实际上把 NumpadAdd 映射成了鼠标按键.

*NumpadAdd::
{
    MouseClick "left",,, 1, 0, "D"  ; 按住鼠标左键.
    KeyWait "NumpadAdd"  ; 等待按键被释放.
    MouseClick "left",,, 1, 0, "U"  ; 释放鼠标按钮.
}

检测什么时候按下了某个按键两次(类似于双击). 当您按下 RControl 修饰另一个键时, 使用 KeyWait 来停止键盘自动重复功能以避免产生不想要的两次按下. 它通过保持热键线程的运行来实现这一点, 这依赖于 #MaxThreadsPerHotkey 默认设置值为 1, 从而阻止自动重复. 有关区分单次, 两次和三次按下的更详细的脚本, 请参阅 SetTimer 的示例 #3.

~RControl::
{
    if (A_PriorHotkey != ThisHotkey or A_TimeSincePriorHotkey > 400)
    {
        ; 两次按下时间间隔太长, 所以这不是按下两次.
        KeyWait "RControl"
        return
    }
    MsgBox "两次按下右 control 键."
}


ListHotkeys - 语法 & 使用 | AutoHotkey v2

ListHotkeys

显示当前脚本使用的热键, 不论它们的子程序当前是否运行, 也不论它们是否使用键盘或鼠标钩子.

ListHotkeys

此函数等同于在主窗口中选择 View->Hotkeys 菜单项.

如果某个热键已被 Hotkey 函数禁用, 则在列表中它会显示为 OFF 或 PART("PART" 意思是此热键有某些变体被禁用了).

如果热键的任何变体使用了非 0 级别的 #InputLevel, 将显示此级别(或最小及最大级别).

如果任何热键的子程序当前正在运行, 则显示该热键的线程总数.

最后, 还会显示热键的类型, 为下列的其中一个:

  • reg: 此热键是通过操作系统的 RegisterHotkey() 函数来实现的.
  • reg(no): 与上面相同, 不过热键当前不可用(由于不支持, 被禁用或挂起).
  • k-hook: 此热键是通过键盘钩子来实现的.
  • m-hook: 此热键是通过鼠标钩子来实现的.
  • 2-hooks: 此热键需要以上两种钩子.
  • joypoll: 此热键是通过定期轮询控制器来实现的.

相关

InstallKeybdHook, InstallMouseHook, #UseHook, KeyHistory, ListLines, ListVars, #MaxThreadsPerHotkey, A_MaxHotkeysPerInterval

示例

显示当前脚本使用的热键信息.

ListHotkeys


ListLines - 语法 & 使用 | AutoHotkey v2

ListLines

启用或禁用行日志记录或显示最近执行的脚本行.

ListLines Mode

参数

Mode

类型: 整数(布尔值)

如果省略, 则显示最近执行的脚本行的历史. 否则, 请指定以下数字之一, 这仅影响当前线程的行为, 如下所示:

1(true): 在历史中包括后续执行的行. 对于所有的脚本这是初始默认值.

0(false): 从历史中略去后续执行的行.

返回值

整数: 整数(布尔值)

函数返回以前的设置: 0(false) 或 1(true).

备注

如果不使用 ListLines 来影响行历史记录, 则默认设置为 1(true).

ListLines(不带参数) 等同于在 主窗口中选择了 "View->Lines most recently executed" 菜单项. 这可以帮助调试脚本.

ListLines False 和 ListLines True 可用来选择性的从历史中略去一些行, 这样有助于避免历史被过快填满(例如在含许多快速重复的循环中). 为了防止混乱, 调用 ListLines 的行也从行历史中删除了. 此外, 启用行日志记录后, 性能可能会降低几个百分点.

当改变 ListLines 模式时, 当前行(通常是调用 ListLines 或|赋值给 A_ListLines 的行) 将从行历史中删除.

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

如果启用了 ListLines, 则内置变量 A_ListLines 包含 1, 否则包含 0.

相关说明, 内置变量 A_LineNumber 和 A_LineFile 包含当前执行的行号及其所属的文件名.

相关

KeyHistory, ListHotkeys, ListVars

示例

启用和禁用特定行的行记录, 然后显示结果.

x := "This line is logged"
ListLines False
x := "This line is not logged"
ListLines True
ListLines
MsgBox


ListVars - 语法 & 使用 | AutoHotkey v2

ListVars

显示脚本的变量: 它们的名称和当前的内容.

ListVars

备注

这个命令等同于在主窗口中选择 "View->Variables" 菜单. 它可以帮助你调试脚本.

对于列表中的每个变量, 变量的名称和内容将被显示, 以及其他信息, 取决于变量包含的内容. 每个项目以回车符和换行符(`r`n) 结束, 但如果变量包含 `r`n, 则可能跨越多行.

列表中的项目采取以下形式(其中 斜体 字符为占位符):

VarName[Length of Capacity]: String
VarName: TypeName object {Info}
VarName: Number

Capacity 为变量当前的容量.

String 为变量字符串值的前 60 个字符.

Info 取决于对象的类型, 但目前是非常有限的.

如果在函数内使用 ListVars, 则会列出以下内容:

  • 局部变量, 包括被当前函数引用的外部函数的变量.
  • 当前函数的静态变量. 在函数内声明的全局变量也在这部分列出.
  • 如果当前函数嵌套在另一个函数中, 每个外部函数的静态变量也会被列出.
  • 所有全局变量.

相关

KeyHistory, ListHotkeys, ListLines

DebugVars 脚本可用于检查和更改变量和对象的内容.

示例

显示脚本变量的信息.

var1 := "foo"
var2 := "bar"
obj := []
ListVars
Pause


ListView (GUI) - 语法 & 使用 | AutoHotkey v2

ListView

目录

  • 入门和简单示例
  • 选项参数的选项和样式
  • 视图模式: 报告(默认), 图标, 平铺, 小图标和列表.
  • ListView 的内置方法
  • 事件
  • 图像列表(把图标添加到 ListView 的方法)
  • 备注
  • 示例

入门和简单示例

List-View 是由操作系统提供的最精心设计的控件之一. 在其最容易识别的形式中, 它显示一个多行多列组成的表格视图, 最常见的例子是资源管理器的文件和文件夹列表(详细信息视图).

ListView 通常是这样的:

尽管它可能是精细的, 但 ListView 的基本功能也易于使用. 创建 ListView 的语法为:

LV := GuiObj.Add("ListView", Options, ["ColumnTitle1", "ColumnTitle2", "..."])

或:

LV := GuiObj.AddListView(Options, ["ColumnTitle1", "ColumnTitle2", "..."])

这是一个可运行脚本, 它创建并显示一个 ListView 其中包含用户的 "我的文档" 目录中的文件列表:

; 创建窗口:
MyGui := Gui()

; 创建含名称和大小两列的 ListView:
LV := MyGui.Add("ListView", "r20 w700", ["Name", "Size (KB)"])

; 每当用户双击某行时, 通知脚本:
LV.OnEvent("DoubleClick", LV_DoubleClick)

; 从文件夹中获取文件名列表并把它们放入 ListView:
Loop Files, A_MyDocuments "\*.*"
    LV.Add(, A_LoopFileName, A_LoopFileSizeKB)

LV.ModifyCol()  ; 根据内容自动调整每列的大小.
LV.ModifyCol(2, "Integer")  ; 为了进行排序, 指出列 2 是整数.

; 显示窗口:
MyGui.Show()

LV_DoubleClick(LV, RowNumber)
{
    RowText := LV.GetText(RowNumber)  ; 从行的第一个字段中获取文本.
    ToolTip("You double-clicked row number " RowNumber ". Text: '" RowText "'")
}

Options 参数的选项和样式

Background: 指定单词 Background 后面紧跟着颜色名称(请参阅颜色列表) 或 RGB 值(0x 前缀可以省略). 例如: BackgroundSilver, BackgroundFFDD99. 如果此选项不存在, ListView 初始默认为系统默认的背景色. 指定 BackgroundDefault 或 -Background 来应用系统的默认背景颜色(通常为白色). 例如, 使用 LV.Opt("+BackgroundDefault") 可以把 ListView 恢复为默认的颜色.

C: 文本颜色. 指定字母 C 后面紧跟着颜色名称(请参阅颜色列表) 或 RGB 值(0x 前缀可以省略). 例如: cRed, cFF2211, c0xFF2211, cDefault.

Checked: 在每行的左侧提供一个复选框. 当添加行时, 在其选项中指定单词 Check 来让复选框初始为选中而不是未选中状态. 用户可以点击复选框或按下空格键来选中或取消选中一行.

Count: 指定单词 Count 后面跟着 ListView 最后会包含的总行数. 这不是限制: 超过此数目后仍然可以添加行. 相反, 此选项给控件一个暗示, 允许它一次性的而不是每次添加一行时分配内存, 这样极大地提高了添加行时的性能(这也可以提高排序性能). 要提升更多的性能, 请在添加大量行之前使用 LV.Opt("-Redraw") 和随后的 LV.Opt("+Redraw"). 有关详情, 请参阅 Redraw.

Grid: 提供水平的和垂直的线以形象地显示出行与行和列与列之间的边界.

Hdr: 指定 -Hdr(负 Hdr) 来隐藏标题(包含列标题的顶行). 后面要让它显示, 请使用 LV.Opt("+Hdr").

LV: 指定字符串 LV 后面紧跟着扩展 ListView 样式的数字. 这些样式完全独立于通用扩展样式. 例如, 指定 -E0x200 会移除通用扩展样式 WS_EX_CLIENTEDGE, 这样将会移除控件的默认边框. 与之相比, 指定 -LV0x20 会移除 LVS_EX_FULLROWSELECT 选择整行的效果.

LV0x10: 指定 -LV0x10 阻止用户通过拖动列标题到左边或右边来对它们重新排序. 然而, 通常没必要这么做, 因为列的实际重排不会影响脚本看到的列顺序. 例如, 从脚本的角度看第一列总是列 1, 即使用户实际已经把它移动到其他列的右边.

LV0x20: 指定 -LV0x20 来要求点击一行的第一个字段才可以进行选择(正常情况下, 点击 任意 字段都可以选择). 这样的好处是用户可以更方便地拖动矩形包围一组行来选择它们.

Multi: 指定 -Multi(负 Multi) 来禁止用户一次选择多行.

NoSortHdr: 禁止点击标题. 此时会显示平坦的外观而不是正常的类似按钮的外观. 与其他大多数 ListView 样式不同, 此样式在 ListView 创建后无法改变.

NoSort: 关闭当用户点击标题时发生的自动排序. 然而, 标题的外观看起来仍像按钮(除非指定了上面的 NoSortHdr 选项). 此外, ColClick 事件仍然会被触发, 所以脚本可以用自定义的排序或其他操作来响应.

ReadOnly: 指定 -ReadOnly(负 ReadOnly) 来允许编辑每行首列的文本. 要编辑某行, 请在选择后按下 F2 键(请参阅下面的 WantF2 选项). 或者, 您可以对一行点击一次来选择它, 至少等待半秒钟, 然后再次点击同一行进行编辑.

R: 行高(创建时). 指定字母 R 后面紧跟着要在控件中留出空间的行数. 例如, R10 会设置控件为 10 行的高度. 如果 ListView 是用报表视图以外的视图模式创建的, 那么控件的大小将适合于图标行而不是文本行. 注意: 在 ListView 的行中添加图标将增加每行的高度, 这将使该选项不准确.

Sort: 控件根据第一列的内容按字母顺序进行排序.

SortDesc: 和上面一样, 不过这里是降序排列.

WantF2: 指定 -WantF2(负 WantF2) 阻止 F2 键编辑当前聚焦的行. 这个设置会被忽略, 除非 -ReadOnly 也有效.

(未命名的数值样式): 由于上述以外的其他样式很少使用, 所以没有为它们命名. 请参阅 ListView 样式表了解这些样式.

视图模式

ListView 有五种视图模式, 其中最常见的是报告视图(这是默认的). 要使用其他某种视图, 请在选项列表中指定它的名称. 还可以在控件创建后改变视图模式; 例如: LV.Opt("+IconSmall").

Icon: 显示大图标视图. 在该视图和除 Report 之外的所有其他视图中, 除第一列之外的其他列中的文本是不可见的. 要在这种模式下显示图标, 必须有一个大图标 ImageList 分配给它.

Tile: 显示大图标视图, 但具有人体工学差异, 例如每项的文本显示在图标的右边而不是下面. Checkbox 在此视图中不起作用.

IconSmall: 显示小图标视图.

List: 以列表格式显示小图标视图, 其中图标显示在列中. 列数取决于控件的宽度和其中最宽的文本项的宽度.

Report: 切换回报告视图, 这是最初的默认模式. 例如: LV.Opt("+Report").

ListViews 的内置方法

除了 GUI 控件的默认方法/属性外, ListView 控件还有以下方法.

当在此页面使用短语 "行号" 时, 它指的是行在 ListView 中的当前位置. 最上面的行是 1, 第二行是 2, 以此类推. 当行被添加后, 它的行号往往会因为其他行的排序, 删除和插入而改变. 因此, 如果要根据行的内容找到特定的行, 通常最好在循环中使用 GetText 方法.

行的方法:

  • Add: 添加新行到列表底部.
  • Insert: 在指定行号插入一个新行.
  • Modify: 修改行的属性和/或文本.
  • Delete: 删除指定行或所有行.

列的方法:

  • ModifyCol: 修改指定列和标题的属性和/或文本.
  • InsertCol: 在指定列号插入一个新列.
  • DeleteCol: 删除指定的列及其中所有内容.

检索方法:

  • GetCount: 返回控件中行或列的总数.
  • GetNext: 返回下一个选择, 选中或具有焦点的行的行号.
  • GetText: 检索指定行号和列号的文本.

其他方法:

  • SetImageList: 设置或替换用于显示图标的 ImageList.

Add

添加新行到列表底部.

RowNumber := LV.Add(Options, Col1, Col2, ...)

参数

Options

类型: 字符串

如果为空或省略, 则默认为无选项. 否则, 请指定下表中的一或多个选项(不区分大小写). 选项间使用空格或 tab 分隔. 要移除某个选项, 请在该选项前加上负号. 要添加选项, 允许添加加号, 但不是必须的.

Check: 在行中显示选中标记(需要 ListView 含有 Checkbox). 以后要取消选中它, 请使用 LV.Modify(RowNumber, "-Check").

Col: 指定单词 Col 后紧跟着列号, 从此列开始往后应用参数 Col1 及以后. 此选项通常和 Modify 方法一起使用来修改行中的个别字段, 而不会影响其左侧的字段.

Focus: 设置键盘焦点到此行(通常和下面的 Select 选项一起使用). 以后要取消它的焦点, 请使用 LV.Modify(RowNumber, "-Focus").

Icon: 指定单词 Icon 后紧跟着这行图标的编号, 这行图标显示在首列的左侧. 如果此选项不存在, 则使用 ImageList 中的首个图标. 要显示空白图标, 请指定 -1 或一个大于图像列表中图标数目的数字. 如果控件没有小图标的图像列表, 则报告视图中既不显示图标也不为其保留空间.

该选项接受基于 1 开始的的图标编号, 但在内部转换为基于 0 开始的索引; 因此, Icon0 对应于常数 I_IMAGECALLBACK, 它通常被定义为 -1, 而 Icon-1 对应于 I_IMAGENONE. 其他超出范围的值也可能导致图标所在位置出现空白.

Select: 选择行. 以后要取消选择, 请使用 LV.Modify(RowNumber, "-Select"). 当选择行时, 通常最好确保至少有一行总含有聚焦属性, 为这样允许 Apps 键在焦点行附近显示其上下文菜单(如果有). 单词 Select 后可以紧跟着 0 或 1 来表示初始状态. 换句话说, both "Select" 和 "Select" . VarContainingOne 是一样的(此处的句点是连接运算符). 这种技术也适用于上面的 Focus 和 Check 选项.

Vis: 必要时通过滚动 ListView 来确保指定行完全可见. 此参数仅对 LV.Modify 有效; 例如: LV.Modify(RowNumber, "Vis").

Col1, Col2, ...

类型: 字符串

新行中的列, 可以是文本或数字(包括数字表达式的结果). 要使任何字段成为空, 请指定 "" 或等价物. 如果字段太少无法填满所有的列, 那么末尾的列将被留空. 如果字段太多, 末尾的字段将被完全忽略.

返回值

类型: 整数

该方法返回新的行号, 如果 ListView 具有 Sort 或 SortDesc 样式, 则不一定是最后一行.

Insert

在指定行号插入一个新行.

RowNumber := LV.Insert(RowNumber , Options, Col1, Col2, ...)

参数

RowNumber

类型: 整数

新插入行的行号. 任何位于 RowNumber 或其下方的行都会被向下移动, 以便为新行腾出空间. 如果 RowNumber 大于列表中的行数(甚至大于 2147483647), 新的行将被添加到列表的最后.

Options

类型: 字符串

如果为空或省略, 则默认为无选项. 否则, 请指定上表中一个或多个选项.

Col1, Col2, ...

类型: 字符串

新行中的列, 可以是文本或数字(包括数字表达式的结果). 要使任何字段成为空, 请指定 "" 或等价物. 如果字段太少无法填满所有的列, 那么末尾的列将被留空. 如果字段太多, 末尾的字段将被完全忽略.

返回值

类型: 整数

该方法返回指定的行号.

Modify

修改行的属性和/或文本.

LV.Modify(RowNumber , Options, NewCol1, NewCol2, ...)

参数

RowNumber

类型: 整数

要修改的行. 如果为 0, 那么控件中的 所有 的行都会被修改.

Options

类型: 字符串

如果为空或省略, 则默认为无选项. 否则, 请指定上表中的一个或多个选项. ColN 选项可用于更新特定的列而不影响其他列.

NewCol1, NewCol2, ...

类型: 字符串

指定行的新列, 可以是文本或数字(包括数字表达式的结果). 要使任何字段成为空, 请指定 "" 或等价物. 如果字段太少无法填满所有的列, 那么末尾的列将被留空. 如果字段太多, 末尾的字段将被完全忽略.

备注

如果只存在前两个参数, 则仅修改行的属性而不改变其文本.

Delete

删除指定行或所有行.

LV.Delete(RowNumber)

参数

RowNumber

类型: 整数

如果省略, 则删除 ListView 中的 所有 行. 否则, 请指定要删除的行号.

ModifyCol

修改指定列和标题的属性和/或文本.

LV.ModifyCol(ColumnNumber, Options, ColumnTitle)

参数

ColumnNumber

类型: 整数

如果省略所有参数, 则调整所有列的宽度以适应行的内容. 只有在报告(详细信息) 视图中才有效果.

否则, 请指定要修改的列的列号. 首列的列号为 1(不是 0).

Options

类型: 整数

如果省略, 则默认为 Auto(则调整列的宽度以适应其的内容). 否则, 请指定下表中的一个或多个选项(不区分大小写). 选项间使用空格或 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: 让列排序基于当前用户的区域设置且不区分大小写(仅影响文本列). 例如, 大多数英语和西欧地区把字母 A-Z 和 ANSI 字母例如 Ä 和 Ü 等同于它们的小写形式. 这种方法也使用 "单词排序", 它把单词中的连字符和撇号例如 "coop" 和 "co-op" 保持在一起.

Desc: 降序排列. 用户首次对此列排序时使用下降的顺序.

Logical: 与 CaseLocale 相同, 除了把文本中的任何数字位序列看成真正的数字而不仅仅字符. 例如, 字符串 "T33" 将被视为大于 "T4". Logical 和 Case 是互斥的: 只有最近指定的那个才有效.

NoSort: 避免用户点击此列对自动排序产生的影响. 然而, ColClick 事件仍然会被触发, 所以脚本可以用自定义的排序或其他操作来响应. 要禁用所有列的排序而不仅是其中的子集, 请在 ListView 的选项中包含 NoSort.

Sort: 立即对列按升序排列(即使它含有 Desc 选项).

SortDesc: 立即对列按降序排列.

Uni: 单向排序. 此选项防止在相同列进行第二次点击来反转排序方向.

ColumnTitle

类型: 字符串

如果省略, 当前标题保持不变. 否则, 请指定列的新标题.

InsertCol

在指定列号插入一个新列.

ColumnNumber := LV.InsertCol(ColumnNumber, Options, ColumnTitle)

参数

ColumnNumber

类型: 整数

如果省略或大于控件中的当前列数, 则新列将添加到右侧最后一列的旁边.

否则, 指定新插入的列的列号. 在 ColumnNumber 处和其右侧的任何列都会向右移动, 以便为新列腾出空间. 第一列的编号为 1(不是 0).

Options

类型: 字符串

如果省略, 列总是以默认值开始, 例如是否使用整数排序. 否则, 请指定上表中的一个或多个选项.

ColumnTitle

类型: 字符串

如果为空或省略, 则默认为空的标题. 否则, 请指定列的标题.

返回值

类型: 整数

函数返回新列的位置编号.

备注

新插入列的初始内容为空, 然而如果它是首列则会继承原来首列的内容, 同时原来首列的内容变为空白.

ListView 中的最大列数是 200.

DeleteCol

删除指定的列及其中所有内容.

LV.DeleteCol(ColumnNumber)

参数

ColumnNumber

类型: 整数

要删除的列. 当一列被删除后, 位于其右侧的列号将减少 1. 因此, 调用 LV.DeleteCol(2) 两次, 将删除第二列和第三列.

GetCount

返回控件中行数或列数.

Count := LV.GetCount(Mode)

参数

Mode

类型: 字符串

如果为空或省略, 该方法返回控件中的总行数. 否则, 请指定以下字符串之一:

S 或 Selected: 计数仅包括选择的/高亮的行.

Col 或 Column: 方法返回控件中的列数.

返回值

类型: 整数

此方法返回控件的行数或列数. 该值总是即时返回的, 因为控件会跟踪这些计数.

备注

这个方法通常用于 Loop 的顶行, 在这种情况下, 这个方法只会被调用一次(在首次循环前). 例如:

Loop LV.GetCount()
{
    RetrievedText := LV.GetText(A_Index)
    if InStr(RetrievedText, "some filter text")
        LV.Modify(A_Index, "Select")  ; 选择首个字段包含过滤文本的所有行.
}

要获取 ListView 的列宽 -- 用于例如保存它们到 INI 文件以便在会话期间保持一致 -- 请参照此例:

Loop LV.GetCount("Column")
{
    ColWidth := SendMessage(0x101D, A_Index - 1, 0, LV)  ; 0x101D 是 LVM_GETCOLUMNWIDTH.
    MsgBox("Column " A_Index "'s width is " ColWidth ".")
}

GetNext

返回下一个选择, 选中或具有焦点的行的行号.

RowNumber := LV.GetNext(StartingRowNumber, RowType)

参数

StartingRowNumber

类型: 整数

如果省略或小于 1, 则从列表的顶部开始搜索. 否则, 请指定开始搜索的行号.

RowType

类型: 字符串

如果省略, 则方法搜索下一个选择的/高亮的行(请参阅下面的例子). 否则, 请指定以下字符串之一:

C 或 Checked: 寻找下一个选中的行.

F 或 Focused: 寻找焦点行. 在整个列表中不可能有多个焦点行, 且有时甚至没有.

返回值

类型: 整数

此方法返回下一个选择, 选中或聚焦的行的行号. 如果没有找到, 返回 0.

备注

下面的示例, 报告 ListView 中所有选择的行:

RowNumber := 0  ; 这样使得首次循环从列表的顶部开始搜索.
Loop
{
    RowNumber := LV.GetNext(RowNumber)  ; 在前一次找到的位置后继续搜索.
    if not RowNumber  ; 上面返回零, 所以选择的行已经都找到了.
        break
    Text := LV.GetText(RowNumber)
    MsgBox('The next selected row is #' RowNumber ', whose first field is "' Text '".')
}

判断一个特定的行是否被选中的另一种方法如下:

ItemState := SendMessage(0x102C, RowNumber - 1, 0xF000, LV)  ; 0x102C 是 LVM_GETITEMSTATE. 0xF000 是 LVIS_STATEIMAGEMASK.
IsChecked := (ItemState >> 12) - 1  ; 如果 RowNumber 为选中的则设置 IsChecked 为真, 否则为假.

GetText

检索指定行号和列号的文本.

Text := LV.GetText(RowNumber , ColumnNumber)
RowNumber

类型: 整数

要检索文本的行的编号. 如果为 0, 则获取列标题的文本.

ColumnNumber

类型: 整数

如果省略, 默认为 1(首列的文本). 否则, 请指定 RowNumber 所在的行中的列号.

返回值

类型: 整数

此方法返回检索到的文本. 最多只能检索 8191 个字符.

备注

脚本中看到的列编号不会因为用户所做的拖放而改变. 例如, 最初首列的编号仍是 1, 即使用户把它拖到其他列的右边.

SetImageList

设置或替换用于显示图标的 ImageList(图像列表).

PrevImageListID := LV.SetImageList(ImageListID , IconType)

参数

ImageListID

类型: 整数

从之前调用 IL_Create 返回的 ID 数字.

IconType

类型: 整数

如果省略, 则自动检测 ImageList 中的图标类型为大图标或小图标. 否则, 指定 0 为大图标, 1 为小图标, 或者 2 为状态图标(这还不直接支持, 但可以通过 SendMessage 使用).

返回值

类型: 整数

成功时, 函数返回先前与 ListView 关联的 ImageList ID. 失败时, 返回 0. 任何这样分离的 ImageList 通常应该通过 IL_Destroy 来销毁.

备注

这个方法通常在向 ListView 添加任何行之前被调用. 它设置 ImageList, 其中的图标会显示在 ListView 的行中(可选的, 以及列).

一个 ListView 最多可以有两个图像列表: 小图标和/或大图标. 当脚本允许用户在大图标视图之间进行切换时, 这很有用. 要再关联一个图像列表到 ListView, 请再次调用 SetImageList 方法, 指定第二个列表的 ImageListID. 一个同时拥有大图标和小图标 ImageList 的 ListView 应该确保两个列表中的图标顺序相同. 这是因为相同的 ID 号被用来引用特定图标的大版本和小版本.

尽管除了图标模式和平铺模式外, 传统的所有的视图模式都显示小图标, 但可以通过传递一个大图标列表到 SetImageList 方法, 并且在第二个参数中指定 1(小图标) 覆盖此行为. 这也增加了 ListView 中每行的高度以适合大图标.

事件

以下事件可以通过调用 OnEvent 来注册一个回调函数或方法来检测:

事件 | 当...触发
Click | 控件被点击.
DoubleClick | 控件被双击.
ColClick | 列标题被点击.
ContextMenu | 当控件拥有键盘焦点时, 用户右键单击控件或按下 Menu 或 Shift+F10.
Focus | 控件获得键盘焦点.
LoseFocus | 控件失去键盘焦点.
ItemCheck | 一个项目被选中或取消选中.
ItemEdit | 一个项目的标签被用户编辑.
ItemFocus | 焦点项目改变.
ItemSelect | 一个项目被选中或取消选中.

额外的(很少使用的) 通知可以通过使用 OnNotify 来检测. 这些通知在 Microsoft Docs 上都有文档. Microsoft Docs 没有显示每个通知代码的数值; 这些可以在 Windows SDK 中找到, 或者在互联网上搜索.

ImageList(图像列表)

图像列表是存储在内存中的一组相同大小的图标. 在创建时, 每个图像列表是空的. 脚本重复调用 IL_Add 来添加图标到列表中, 且给每个图标分配一个序号, 序号从 1 开始. 脚本引用此编号在一行中或列标题中显示一个特定的图标. 这是个可运行示例, 其中演示了如何在 ListView 的行中显示图标:

MyGui := Gui()  ; 创建 Gui 窗口.
LV := MyGui.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")
MyGui.Show()

IL_Create

创建一个新的初始为空的图像列表.

ImageListID := IL_Create(InitialCount, GrowCount, LargeIcons)

参数

InitialCount

类型: 整数

如果省略, 默认为 2. 否则, 请指定希望立即放入列表的图标数量.

GrowCount

类型: 整数

如果省略, 默认为 5. 否则, 请指定每次超过当前列表容量时, 列表将增加的图标数量.

LargeIcons

类型: 布尔值

如果省略, 则默认为 false.

如果为 false, ImageList 将包含小图标.

如果为 true, ImageList 将包含大图标.

添加到列表中的图标自动进行缩放, 以符合系统中大小图标的尺寸.

返回值

类型: 整数

成功时, 函数返回新创建的图像列表的唯一 ID. 失败时, 返回 0.

IL_Add

添加图标或图片到指定的图像列表.

IconIndex := IL_Add(ImageListID, IconFileName , IconNumber)
IconIndex := IL_Add(ImageListID, PicFileName, MaskColor, Resize)

参数

ImageListID

类型: 整数

之前调用 IL_Create 返回的 ID 号.

IconFileName

类型: 字符串

图标(.ICO), 光标(.CUR) 或动画光标(.ANI) 文件的名称(动态光标在 ListView 中显示时实际将不会动), 或图标句柄 , 如 "HBITMAP:" handle. 图标的其他来源包含下列类型的文件: EXE, DLL, CPL, SCR, 以及包含图标资源的其他类型.

IconNumber

类型: 整数

如果省略, 默认为 1(第一个图标组). 否则, 请指定请指定文件中要使用的图标组的编号. 如果为负数, 则假定其绝对值表示可执行文件中图标的资源 ID. 在下面的例子中, 将使用第二个图标组中的默认图标: IL_Add(ImageListID, "C:\My Application.exe", 2).

PicFileName

类型: 字符串

非图标图像的名称, 例如 BMP, GIF, JPG, PNG, TIF, Exif, WMF 和 EMF, 或位图句柄, 如 "HBITMAP:" handle.

MaskColor

类型: 整数

屏蔽的/透明的颜色编码. 对于大多数图片, 0xFFFFFF(白色) 可能是最佳的.

Resize

类型: 布尔值

如果为 true, 则图片缩放为单个图标.

如果为 false, 则图片将被分割为多个可以匹配实际宽度的图标.

返回值

类型: 整数

成功时, 函数返回新图标的索引(首个图标索引为 1, 第二个为 2, 依此类推). 失败时, 返回 0.

IL_Destroy

删除指定的图像列表.

IsDestroyed := IL_Destroy(ImageListID)

参数

ImageListID

类型: 整数

之前调用 IL_Create 返回的 ID 号.

返回值

类型: 整数(布尔值)

成功时, 函数返回 1(true). 失败时, 返回 0(false).

备注

通常没必要销毁图像列表, 因为一旦关联到 ListView, 当 ListView 或其父窗口销毁时它们会被自动销毁. 但是, 如果一个 ListView 和其他 ListView 共享图像列表(通过在选项中包含 0x40), 在所有使用此图像列表的 ListView 销毁后脚本应该显式地销毁它. 同样地, 如果脚本使用一个新的图像列表代替 ListView 中原来的, 则应该显式销毁原来的图像列表.

备注

Gui.Submit 对 ListView 控件没有效果.

在对某个列进行排序后 -- 通过用户点击其标题或脚本调用 LV.ModifyCol(1, "Sort") -- 任何随后添加的行将出现在列表的底部而不会遵循排序顺序. 例外情况是 Sort 和 SortDesc 样式, 它们会把新添加的行移动正确的位置.

当 ListView 拥有焦点时如果要检测到用户是否按下 Enter 键, 请使用默认按钮(如果需要则可以隐藏它). 例如:

MyGui.Add("Button", "Hidden Default", "OK").OnEvent("Click", LV_Enter)
...
LV_Enter(*) {
    global
    if MyGui.FocusedCtrl != LV
        return
    MsgBox("Enter was pressed. The focused row number is " LV.GetNext(0, "Focused"))
}

使用键盘除了在行与行之间导航外, 用户还可以通过输入首列中一个项目名称的前几个字符来进行增量搜索. 这使得选择对象跳转到最近匹配的行.

尽管 ListView 中的每个字段可以存储任意长度的文本, 但仅显示开始的 260 个字符.

尽管 ListView 中可以使用的最大行数仅受系统可用内存的限制, 但参照 Count 选项中描述的方法可以极大地提高添加行的性能.

可以使用图片作为 ListView 周围的背景(即作为 ListView 的框架). 要实现这个效果, 请在 ListView 后创建图片控件并且在图片控件的 Options 中包含 0x4000000(这是 WS_CLIPSIBLINGS).

脚本可以在每个窗口中创建多个 ListView.

最好不要使用 SendMessage 直接插入或删除列. 这是因为程序为每个列维护一个排序参数集, 而这会让它们无法同步. 作为替代, 请使用内置的列的方法.

要对 ListView 执行一些操作(例如调整大小, 隐藏或改变字体), 请参阅 GuiControl 对象.

要从外部 ListView(那些不属于脚本自身的) 中提取文本, 请使用 ListViewGetContent.

相关

TreeView, 其他控件类型, Gui, ContextMenu 事件, Gui 对象, GuiControl 对象, ListView 样式列表

示例

指定行号为 0 来选择或取消选择所有行.

LV.Modify(0, "Select")   ; 选择所有行.
LV.Modify(0, "-Select")  ; 取消选择所有行.
LV.Modify(0, "-Check")  ;取消选中所有复选框.

自动根据内容调整所有列的宽度.

LV.ModifyCol()  ; 此模式不需要参数.

下面是一个比页面顶部的脚本更复杂的可工作的脚本. 它显示用户选择的文件夹中的文件, 且每个文件分配一个与其类型关联的图标. 用户在一个文件上双击或在一个或多个文件上右击后, 会显示上下文菜单.

; 创建 GUI 窗口:
MyGui := Gui("+Resize")  ; 允许用户最大化窗口或拖动来改变窗口的大小.

; 创建一些按钮:
B1 := MyGui.Add("Button", "Default", "Load a folder")
B2 := MyGui.Add("Button", "x+20", "Clear List")
B3 := MyGui.Add("Button", "x+20", "Switch View")

; 通过 Gui.Add 创建 ListView 及其列:
LV := MyGui.Add("ListView", "xm r20 w700", ["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)

; 应用控件事件:
LV.OnEvent("DoubleClick", RunFile)
LV.OnEvent("ContextMenu", ShowContextMenu)
B1.OnEvent("Click", LoadFolder)
B2.OnEvent("Click", (*) => LV.Delete())
B3.OnEvent("Click", SwitchView)

; 应用窗口事件:
MyGui.OnEvent("Size", Gui_Size)

; 创建弹出式菜单, 作为上下文菜单使用:
ContextMenu := Menu()
ContextMenu.Add("Open", ContextOpenOrProperties)
ContextMenu.Add("Properties", ContextOpenOrProperties)
ContextMenu.Add("Clear from ListView", ContextClearRows)
ContextMenu.Default := "Open"  ; 将 "Open(打开)" 改为粗体字, 以表明这是双击的默认动作.

; 显示窗口:
MyGui.Show()

LoadFolder(*)
{
    static IconMap := Map()
    MyGui.Opt("+OwnDialogs") ; 强制用户在使用主窗口之前关闭下面的对话框.
    Folder := DirSelect(, 3, "Select a folder to read:")
    if not Folder  ; 用户取消对话框.
        return

    ; 检查文件夹名称的最后一个字符是否为反斜杠, 对于根目录则会如此,
    ; 例如 C:\. 如果是, 则移除这个反斜杠以避免之后出现两个反斜杠.
    if SubStr(Folder, -1, 1) = "\"
        Folder := SubStr(Folder, 1, -1)  ; 移除尾部的反斜杠.

    ; 计算 SHFILEINFO 结构需要的缓冲大小.
    sfi_size := A_PtrSize + 688
    sfi := Buffer(sfi_size)

    ; 获取所选择文件夹中的文件名列表并添加到 ListView:
    LV.Opt("-Redraw")  ; 在加载时禁用重绘来提升性能.
    Loop Files, Folder "\*.*"
    {
        FileName := A_LoopFilePath  ; 必须保存到可写的变量中供后面使用.

        ; 建立唯一的扩展 ID 以避免变量名中的非法字符,
        ; 例如破折号. 这种使用唯一 ID 的方法也会执行地更好,
        ; 因为在数组中查找项目不需要进行搜索循环.
        SplitPath(FileName,,, &FileExt)  ; 获取文件扩展名.
        if FileExt ~= "i)\A(EXE|ICO|ANI|CUR)\z"
        {
            ExtID := FileExt  ; 特殊 ID 作为占位符.
            IconNumber := 0  ; 将其标记为未找到, 以便这些类型可以有一个唯一的图标.
        }
        else  ; 其他的扩展名/文件类型, 计算它们的唯一 ID.
        {
            ExtID := 0  ; 进行初始化来处理比其他更短的扩展名.
            Loop 7     ; 限制扩展名为 7 个字符, 这样之后计算的结果才能存放到 64 位值.
            {
                ExtChar := SubStr(FileExt, A_Index, 1)
                if not ExtChar  ; 没有更多字符了.
                    break
                ; 把每个字符与不同的位置进行运算来得到唯一 ID:
                ExtID := ExtID | (Ord(ExtChar) << (8 * (A_Index - 1)))
            }
            ; 检查此文件扩展名的图标是否已经在图像列表中. 如果是,
            ; 可以避免多次调用并极大提高性能,
            ; 尤其对于包含数以百计文件的文件夹而言:
            IconNumber := IconMap.Has(ExtID) ? IconMap[ExtID] : 0
        }
        if not IconNumber  ; 此扩展名还没有相应的图标, 所以进行加载.
        {
            ; 取与此文件扩展名关联的高质量小图标:
            if not DllCall("Shell32\SHGetFileInfoW", "Str", FileName
            , "Uint", 0, "Ptr", sfi, "UInt", sfi_size, "UInt", 0x101)  ; 0x101 是 SHGFI_ICON+SHGFI_SMALLICON
                IconNumber := 9999999  ; 把它设置到范围外来显示空图标.
            else ; 成功加载图标.
            {
                ; 从结构中提取 hIcon 成员:
                hIcon := NumGet(sfi, 0, "Ptr")
                ; 直接添加 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)
                ; 缓存图标来节省内存并提升加载性能:
                IconMap[ExtID] := IconNumber
            }
        }

        ; 在 ListView 中创建新行并把它和上面的图标编号进行关联:
        LV.Add("Icon" . IconNumber, A_LoopFileName, A_LoopFileDir, A_LoopFileSizeKB, FileExt)
    }
    LV.Opt("+Redraw")  ; 重新启用重绘(上面把它禁用了).
    LV.ModifyCol()  ; 根据内容自动调整每列的大小.
    LV.ModifyCol(3, 60)  ; 把 Size 列加宽一些以便显示出它的标题.
}

SwitchView(*)
{
    static IconView := false
    if not IconView
        LV.Opt("+Icon")        ; 切换到图标视图.
    else
        LV.Opt("+Report")      ; 切换回详细信息视图.
    IconView := not IconView   ; 进行反转以为下次做准备.
}

RunFile(LV, RowNumber)
{
    FileName := LV.GetText(RowNumber, 1) ; 获取首个字段的文本.
    FileDir := LV.GetText(RowNumber, 2)  ; 获取第二个字段的文本.
    try
        Run(FileDir "\" FileName)
    catch
        MsgBox("Could not open " FileDir "\" FileName ".")
}

ShowContextMenu(LV, Item, IsRightClick, X, Y)  ; 响应右键或 Apps 键.
{
    ; 在所提供的 X 和 Y 坐标处显示菜单.
    ; 这些应该被使用, 因为即使用户按了 Apps 键, 它们也能提供正确的坐标:
    ContextMenu.Show(X, Y)
}

OpenOrProperties(ItemName, *)  ; 用户在上下文菜单中选择了 "Open" 或 "Properties".
{
    ; 简单地说, 只对焦点行进行操作, 而不是对所有选中的行进行操作:
    FocusedRowNumber := LV.GetNext(0, "F")  ; Find the focused row.
    if not FocusedRowNumber  ; 没有聚焦行.
        return
    FileName := LV.GetText(FocusedRowNumber, 1) ; 获取首个字段的文本.
    FileDir := LV.GetText(FocusedRowNumber, 2)  ; 获取第二个字段的文本.
    try
    {
        if (ItemName = "Open")  ; 用户在上下文菜单中选择了 "Open".
            Run(FileDir "\" FileName)
        else
            Run("properties " FileDir "\" FileName)
    }
    catch
        MsgBox("Could not perform requested action on " FileDir "\" FileName ".")
}

ContextClearRows(*)  ; 用户在上下文菜单中选择了 "Clear".
{
    RowNumber := 0  ; 这会使得首次循环从顶部开始搜索.
    Loop
    {
        ; 由于删除了一行使得此行下面的所有行的行号都减小了,
        ; 所以把行号减 1, 这样搜索里包含的行号才会与之前找到的行号相一致
        ; (以防选择了相邻行):
        RowNumber := LV.GetNext(RowNumber - 1)
        if not RowNumber  ; 上面返回零, 所以没有更多选择的行了.
            break
        LV.Delete(RowNumber)  ; 从 ListView 中删除行.
    }
}

Gui_Size(thisGui, MinMax, Width, Height)  ; 扩大或缩小 ListView 来响应用户对窗口大小的改变.
{
    if MinMax = -1  ; 窗口被最小化了. 无需进行操作.
        return
    ; 否则, 窗口的大小被调整过或被最大化了. 调整 ListView 的大小来适应.
    LV.Move(,, Width - 20, Height - 40)
}


ListViewGetContent - 语法 & 使用 | AutoHotkey v2

ListViewGetContent

返回列表视图中的项目/行列表.

List := ListViewGetContent(Options, Control, WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Options

类型: 字符串

指定检索什么. 如果为空或省略, 则检索 ListView 中的所有文本. 否则, 指定零个或多个下列单词, 每个单词之间用空格或制表符分隔:

Selected: 只返回选中(突出显示) 的行, 而不是所有行. 如果没有, 则返回值为空.

Focused: 只返回聚焦行. 如果没有, 则返回值为空.

Col N 仅获取第 N 列(字段) 而不是所有列. 把 N 替换为您选择的数字. 例如, Col4 返回第四列.

Count: 返回 ListView 中的总行数.

Count Selected: 返回选中(高亮显示) 行的数量.

Count Focused: 返回聚焦行的行号(位置)(如果没有, 则返回 0).

Count Col: 返回控件中的列数(如果无法确定列数, 则返回 -1).

Control

类型: 字符串, 整数或对象

控件的 ClassNN, 文本或 HWND, 或具有 Hwnd 属性的对象. 有关详情, 请参阅 Control 参数. 该参数是必需的; 也就是说, 不能省略.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用最后找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示). 如果 DetectHiddenText 已经打开, 则检测隐藏文本元素. 标题或文本包含 ExcludeTitle 或 ExcludeText 的窗口将不被考虑.

返回值

类型: 字符串

此函数从 ListView 返回项目/行的列表. 在每一行中, 除最后一个字段外的每个字段(列) 都将以制表符(`t) 结尾. 若要分别访问项目/行, 请使用 parsing loop, 如示例 #1 所示.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果消息无法发送到控件, 或拥有 ListView 的进程无法打开, 这可能是由于缺少用户权限或因为它已被锁定, 则抛出 OSError.

如果 ColN 选项指定不存在的列, 则抛出 ValueError.

备注

一些应用程序将其 ListView 文本单独存储, 从而防止检索它们的文本. 在这些情况下, 通常不会抛出异常, 但是所有检索到的字段都是空的.

ListView 中的列可以通过 SendMessage 调整大小, 如下例所示:

SendMessage(0x101E, 0, 80, "SysListView321", WinTitle)  ; 0x101E 是 LVM_SETCOLUMNWIDTH 消息.

在上面, 0 表示第一列(第二列指定 1, 2 为第三列, 依此类推). 此外, 80 是新宽度. 用 -1 替换 80 以自动调整列大小. 将其替换为 -2 即可执行相同操作, 但还要考虑标题文本的宽度.

相关

ControlGetItems, WinGetList, 控件函数

示例

从 ListView 中提取各个行和字段.

List := ListViewGetContent("Selected", "SysListView321", WinTitle)
Loop Parse, List, "`n"  ; 行由换行符(`n) 分隔.
{
    RowNumber := A_Index
    Loop Parse, A_LoopField, A_Tab  ; 每行中的字段(列) 由制表符(A_Tab) 分隔.
        MsgBox "Row #" RowNumber " Col #" A_Index " is " A_LoopField
}


LoadPicture - 语法 & 使用 | AutoHotkey v2

LoadPicture

载入图像文件并返回位图或图标句柄.

Handle := LoadPicture(Filename , Options, &OutImageType)

参数

Filename

类型: 字符串

图片的文件名, 如果未指定绝对路径, 则通常假定在 A_WorkingDir 目录中. 如果指定了 DLL 或 EXE 文件的名称而没有路径, 则可以从当前可执行文件目录(AutoHotkey.exe 或已编译的脚本) 或系统目录加载.

Options

类型: 字符串

如果为空或省略, 则默认为无选项. 否则, 指定以下一个或多个选项组成的字符串, 选项之间以空格或制表符分隔::

W n 和 H n: 待载入图像的宽度和高度, n 为整数. 如果省略某个尺寸或指定为 -1, 该尺寸将在保持宽高比的情况下根据另一个尺寸进行计算. 如果两个尺寸都被省略, 将使用图像的原始尺寸. 如果任一尺寸被指定为 0, 则该尺寸仍会使用原始尺寸. 例如: "w80 h50", "w48 h-1" 或 "w48"(保持宽高比), "h0 w100"(使用原始高度但覆盖宽度).

Icon n: 指代多图标文件(一般是 EXE 或 DLL 文件) 中待载入图标的序号. 例如, "Icon2" 载入文件的第二个图标. 如果为负数, 则假定绝对值是可执行文件中图标的资源 ID. 任何支持的图像格式都可以通过指定 "Icon1" 来转换为图标. 但是, 如果省略 OutImageType 参数, 图标将转换回位图.

GDI+: 尝试使用 GDI+ 的方式载入图像. 例如, "GDI+ w100".

&OutImageType

类型: VarRef

如果省略, 将不存储相应的值, 并且返回值始终是位图句柄(图标/光标类型会按需转换). 这是因为可靠地使用或删除位图/图标/光标句柄需要知道它是哪种类型. 否则, 指定一个变量的引用, 在这个变量中存储了一个表示返回句柄类型的数字: 0(IMAGE_BITMAP), 1(IMAGE_ICON) 或 2(IMAGE_CURSOR).

返回值

类型: 整数

这个函数返回一个位图或图标句柄, 这取决于是否指定了图片或图标, 以及是否存在 &OutImageType 参数. 如果发生错误, 则函数返回 0.

备注

LoadPicture 也支持句柄语法, 如从一个已载入到内存中的图标或位图创建一个可调整大小的图像, 或将一个图标通过忽略 &OutImageType 转换成位图.

如果图像需要从内存中释放, 请调用任何适合于句柄类型的函数.

if (not OutImageType)  ; IMAGE_BITMAP(0) 或 OutImageType 参数省略.
    DllCall("DeleteObject", "ptr", Handle)
else if (OutImageType = 1)  ; IMAGE_ICON
    DllCall("DestroyIcon", "ptr", Handle)
else if (OutImageType = 2)  ; IMAGE_CURSOR
    DllCall("DestroyCursor", "ptr", Handle)

相关

Image Handles

示例

预加载并复用一些图像.

Pics := []
; 寻找几张图像用来展示.
Loop Files, A_WinDir "\Web\Wallpaper\*.jpg", "R"
{
    ; 载入找到的图像并添加到数组中.
    Pics.Push(LoadPicture(A_LoopFileFullPath))
}
if !Pics.Length
{
    ; 如果发生找不到文件的情形, 将正确的路径手动添加到上述的 Loop 循环中.
    MsgBox("No pictures found! Try a different directory.")
    ExitApp
}
; 创建图标控件, 保持第一张图的宽高比.
MyGui := Gui()
Pic := MyGui.Add("Pic", "w600 h-1 +Border", "HBITMAP:*" Pics[1])
MyGui.OnEvent("Escape", (*) => ExitApp())
MyGui.OnEvent("Close", (*) => ExitApp())
MyGui.Show()
Loop
{
    ; 切换图片!
    Pic.Value := "HBITMAP:*" Pics[Mod(A_Index, Pics.Length)+1]
    Sleep 3000
}


Loop - 语法 & 使用 | AutoHotkey v2

Loop (normal)

重复执行一或多条语句: 可以指定表示重复次数的数字或直到遇到 Break.

Loop Count

参数

Count

类型: 整数

如果省略, 则循环无限地继续, 直到遇到 Break 或 Return. 否则, 指定执行循环的次数(迭代). 但是, 显式的空值或小于 1 的数字将导致完全跳过循环.

Count 只在循环开始之前计算一次. 例如, 如果 Count 有附加作用的表达式(如, 函数调用或赋值), 附加作用仅发生一次.

如果 Count 用括号括起来, 则不需要空格或制表符. 例如: Loop(2)

备注

循环语句后通常跟着区块, 这是构成循环 主体 语句的集合. 但是, 在单语句的循环中可以不使用区块(用于此目的时 "if" 与其相匹配的 "else" 一起被视为单语句).

这个语句的一个常见用法是无限循环, 然后在循环 主体 中的某个地方使用 Break 语句来确定何时停止循环.

在循环中鼓励使用 Break 和 Continue 代替 Goto, 因为它们通常可以让脚本更容易理解和维护. 也可以通过将循环 主体 的第一个或最后一个语句作为有条件地发出 Break 语句的 IF 语句来创建 "While" 或 "Do...While/Until" 语句, 但使用 While 或 Loop...Until 通常是首选的.

内置变量 A_Index 包含当前循环迭代的次数. 首次执行循环 主体 时其值为 1. 第二次时其值为 2; 依此类推. 如果一个内层循环包含在一个外层循环中, 那么内层循环具有优先权. A_Index 在所有类型的循环中都有效, 包括 file-loops 和 registry-loops; 但是在循环外部时 A_Index 值为 0.

A_Index 可以由脚本赋值为任何整数值. 如果指定 Count, 则更改 A_Index 会影响将要执行的迭代次数. 例如, A_Index := 3 会使循环语句的行为好像是第三次迭代(A_Index 将在下一次迭代为 4), 而 A_Index-- 将防止当前迭代计入总数中.

循环后面可以有一个可选的 Else 语句, 如果 Count 为零, 则执行 Else 语句.

可以选择使用 One True Brace(OTB) 样式. 例如:

Loop {
    ...
}
Loop RepeatCount {
    ...
}

专用循环: 循环可以用来自动检索文件, 文件夹或注册表项(每次一个). 有关详情, 请参阅 file-loop 和 registry-loop. 此外, file-reading loops 可以对整个文件的内容进行操作, 每次一行. 最后, parsing loops 可以对可分隔的字符串中包含的各个字段进行操作.

相关

Until, While-loop, For-loop, Files-and-folders loop, Registry loop, File-reading loop, Parsing loop, Break, Continue, 区块, Else

示例

创建一个有 3 次迭代的循环.

Loop 3
{
    MsgBox "Iteration number is " A_Index  ; A_Index 将为 1, 2, 接着 3
    Sleep 100
}

创建一个无限循环, 但会在第 25 次迭代后终止.

Loop
{
    if (A_Index > 25)
        break  ; 终止循环
    if (A_Index < 20)
        continue ; 跳过后面并开始新的迭代
    MsgBox "A_Index = " A_Index ; 这里将仅显示数字 20 到 25
}


Loop Files - 语法 & 使用 | AutoHotkey v2

Loop Files

检索指定的文件或文件夹, 每次一个.

Loop Files FilePattern , Mode

参数

FilePattern

类型: 字符串

单个文件或文件夹的名称, 或者通配符模式, 如 "C:\Temp\*.tmp". 如果未指定绝对路径, 则假定 FilePattern 在 A_WorkingDir 中.

支持星号(*) 和问号(?) 作为通配符. * 匹配零个或多个字符, 而 ? 匹配任何单个字符. 使用示例:

  • *.* 或 * 匹配所有文件.
  • *.htm 匹配扩展名为 .htm, .html 等的文件.
  • *. 匹配没有扩展名的文件.
  • log?.txt 匹配如 log1.txt 但不匹配 log10.txt.
  • *report* 匹配任何包含单词 "report" 的文件名.

当模式出现在文件的长/普通名称或其 8.3 短名称时会产生匹配.

如果此参数为单个文件或文件夹(即不含通配符) 且 Mode 包含 R, 同时指定的文件名出现在多个被搜索的文件夹中, 那么将找到多个匹配.

由于系统限制(MAX_PATH), 超过 259 个字符的模式可能无法找到任何文件. 这个限制可以通过使用 \\?\ 长路径前缀绕过, 但有一些条件.

Mode

类型: 字符串

如果为空或省略, 则只包括文件且不递归子文件夹. 否则, 指定一个或多个下列字母:

  • D = 包含目录(文件夹).
  • F = 包含文件. 如果同时省略 F 和 D, 则仅包含文件而不包括目录.
  • R = 递归到子目录(子文件夹). 所有子文件夹都将被递归到其中, 而不仅仅是那些名称匹配 FilePattern 的子文件夹. 如果省略 R, 则不包含子目录中的文件和目录.

可在文件循环中使用的特殊变量

下列变量存在于任何文件循环中. 如果一个内层文件循环包含在一个外层文件循环中, 那么最内层循环的文件将具有优先权:

变量 | 描述
A_LoopFileName | 当前检索的文件或文件夹的名称(不包括路径).
A_LoopFileExt | 文件的扩展名(例如 TXT, DOC 或 EXE). 不包括点号(.).
A_LoopFilePath | 当前检索的文件/文件夹的路径和名称. 如果 FilePattern 包含相对路径而不是绝对路径, 这里的路径也将是相对路径. 此外, FilePattern 中的任何短(8.3) 文件夹名称仍将为短名称(参阅下一项目以获得长文件名).
A_LoopFileFullPath | 这与 A_LoopFilePath 有以下不同: 1) 它总是包含文件的绝对/完整路径, 即使 FilePattern 包含相对路径; 2) FilePattern 本身的任何短(8.3) 文件夹名都会被转换为长文件名; 3) FilePattern 中的字符会被转换为大写或小写以匹配文件系统中存储的大小写. 这对于将文件名 -- 例如作为命令行参数传入脚本的文件名 -- 转换为资源管理器显示的准确路径名很有用.
A_LoopFileShortPath

当前检索文件/文件夹的 8.3 短路径和名称. 例如: C:\MYDOCU~1\ADDRES~1.txt. 如果 FilePattern 包含相对路径而不是绝对路径, 这里的路径也将是相对路径.

要检索单个文件或文件夹的完整的 8.3 路径和名称, 如下例所示:

Loop Files, "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 命令, 默认情况下会省略隐藏文件. 为了避免处理隐藏的, 系统的, 和/或只读的文件, 在循环中使用类似下面的方法:

if A_LoopFileAttrib ~= "[HRS]"  ; 跳过任何具有 H(隐藏), R(只读) 或 S(系统). 请参阅 ~= 运算符.
    continue  ; 跳过这个文件并继续下一个文件.

在递归搜索过程中, 要检索文件的相对路径而不是绝对路径, 在循环之前使用 SetWorkingDir 改变基文件夹, 然后在循环中省略路径(例如 Loop Files, "*.*", "R"). 这将导致 A_LoopFilePath 包含相对于基文件夹的文件路径.

如果一个文件循环在它自己的权限范围内创建或重命名文件或文件夹, 它可能会自乱阵脚. 例如, 如果通过 FileMove 或其他方式重命名文件, 每个这样的文件可能会被发现两次: 一次是旧名, 另一次是新名. 为了解决这个问题, 只有在创建文件列表后才重命名这些文件. 例如:

FileList := ""
Loop Files, "*.jpg"
    FileList .= A_LoopFileName "`n"
Loop Parse, FileList, "`n"
    FileMove A_LoopField, "renamed_" A_LoopField

在 NTFS 文件系统中的文件可能总是按字母顺序来获取. 在其他文件系统中的文件则没有特殊的获取顺序. 要使用特殊的获取顺序, 使用 Sort 命令, 如同下文示例部分演示的那样.

支持超过 259 个字符的文件模式, 仅在满足至少一个以下情况时有效:

  • 系统启用了长路径支持(需要 Windows 10 版本 1607 或更高).
  • 使用了 \\?\ 长路径前缀(适用注意事项).

在所有其他情况下, 超过 259 个字符的文件模式将不会找到任何文件或文件夹. 这个限制既适用于 FilePattern, 也适用于递归到子文件夹时使用的任何临时模式.

可以选择使用 One True Brace(OTB) 样式, 它允许左大括号出现在同一行而不是下面. 例如: Loop Files "*.txt", "R" {.

请参阅 Loop 了解关于区块, Break, Continue 和 A_Index 变量(其存在于各种类型的循环中) 的相关信息.

循环后面可以有一个可选的 Else 语句, 如果没有找到匹配的文件或目录(即循环的迭代次数为零), 则执行 Else 语句.

函数 FileGetAttrib, FileGetSize, FileGetTime, FileGetVersion, FileSetAttrib 和 FileSetTime 可以在文件循环中使用, 而不需要它们的 Filename/FilePattern 参数.

相关

Loop, Break, Continue, 区块, SplitPath, FileSetAttrib, FileSetTime

示例

报告位于目录及其子目录中的每个文本文件的完整路径.

Loop Files, A_ProgramFiles "\*.txt", "R"  ; 递归子文件夹.
{
    Result := MsgBox("Filename = " A_LoopFilePath "`n`nContinue?",, "y/n")
    if Result = "No"
        break
}

计算文件夹的大小, 包括其所有子文件夹中的文件.

FolderSizeKB := 0
WhichFolder := DirSelect()  ; 让用户选取文件夹.
Loop Files, WhichFolder "\*.*", "R"
    FolderSizeKB += A_LoopFileSizeKB
MsgBox "Size of " WhichFolder " is " FolderSizeKB " KB."

获取根据名称排序的文件名(要以日期排序请参阅下一个例子).

FileList := ""  ; 初始化为空.
Loop Files, "C:\*.*"
    FileList .= A_LoopFileName "`n"
FileList := Sort(FileList, "R")  ; R 选项逆序排列. 有关其他选项, 请参阅 Sort.
Loop Parse, FileList, "`n"
{
    if A_LoopField = ""  ; 忽略列表末尾的空项.
        continue
    Result := MsgBox("File number " A_Index " is " A_LoopField ".  Continue?",, "y/n")
    if Result = "No"
        break
}

获取根据修改日期排序的文件名.

FileList := ""
Loop Files, A_MyDocuments "\Photos\*.*", "FD"  ; 包含文件和子目录
    FileList .= A_LoopFileTimeModified "`t" A_LoopFileName "`n"
FileList := Sort(FileList)  ; 根据日期排序.
Loop Parse, FileList, "`n"
{
    if A_LoopField = "" ; 忽略列表末尾的最后一个换行符(空项).
        continue
    FileItem := StrSplit(A_LoopField, A_Tab)  ; 用 tab 作为分隔符将其分为两部分.
    Result := MsgBox("The next file (modified at " FileItem[1] ") is:`n" FileItem[2] "`n`nContinue?",, "y/n")
    if Result = "No"
        break
}

仅复制比目标位置中的对应文件新的源文件. 使用源模式(如 "A:\Scripts\*.ahk") 和存在的目标目录(如 "B:\Script Backup") 来调用此函数.

CopyIfNewer(SourcePattern, Dest)
{
    Loop Files, SourcePattern
    {
        copy_it := false
        if !FileExist(CopyDest "\" A_LoopFileName)  ; 如果目标文件还不存在, 那么总是复制.
            copy_it := true
        else
        {
            time := FileGetTime(CopyDest "\" A_LoopFileName)
            time := DateDiff(time, A_LoopFileTimeModified, "Seconds")  ; 从目的时间中减去源文件的时间.
            if time < 0  ; 源文件比目的文件新.
                copy_it := true
        }
        if copy_it
        {
            try
                FileCopy A_LoopFilePath, CopyDest "\" A_LoopFileName, 1   ; 以覆盖形式复制 overwrite=yes
            catch
                MsgBox 'Could not copy "' A_LoopFilePath '" to "' CopyDest '\' A_LoopFileName '".'
        }
   }
}

把通过命令行参数传递的文件名转换为长名称, 完整路径和在文件系统中存储的正确的大写/小写字符形式.

for GivenPath in A_Args  ; 对于每一个参数(或拖放到脚本中的文件):
{
    Loop Files, GivenPath, "FD"  ; 包括文件和目录.
        LongPath := A_LoopFilePath
    MsgBox "The case-corrected long path name of file`n" GivenPath "`nis:`n" LongPath
}


Loop Parse - 语法 & 使用 | AutoHotkey v2

Loop Parse

每次从字符串中检索字符串(片段).

Loop Parse String , DelimiterChars, OmitChars

参数

String

类型: 字符串

要分析的字符串.

DelimiterChars

类型: 字符串

如果为空或省略, 那么将把输入字符串中的每个字符解析为单独的子字符串.

如果此参数为 "CSV", 字符串将以标准的逗号分隔值格式进行解析. 下面是一个由 MS Excel 生成的 CSV 行的示例:

"first field",SecondField,"the word ""special"" is quoted literally",,"last field, has literal comma"

否则, 请指定一个或多个字符(区分大小写), 每个字符用于确定子串之间的边界位置.

分割字符不被认为是子串本身的一部分. 此外, 如果输入字符串中的一对分隔字符之间没有任何内容, 那么相应的子串将是空的.

例如: ','(逗号) 会根据每一个逗号的出现来划分字符串. 类似地, A_Space A_Tab 会在每次输入字符串中出现空格或制表符时开始一个新的子串.

要使用字符串作为分隔字符而不是字符, 首先使用 StrReplace 将所有出现的字符串替换为从未在文本中使用过的单个字符, 例如, 这些特殊字符之一: ¢¤¥¦§©ª«®µ¶. 考虑这个示例, 它使用字符串 <br> 作为分隔符:

NewHTML := StrReplace(HTMLString, "<br>", "¢")
Loop Parse, NewHTML, "¢" ; 使用 ￠ 解析字符串.
{
    ; ...
}
OmitChars

类型: 字符串

如果为空或省略, 则不排除任何字符. 否则, 请指定一个字符列表(区分大小写), 用来从每个子字符串的开始和结尾部分移除这些字符. 例如, 如果 OmitChars 是 A_Space A_Tab, 那么每个解析出来的子字符串中开始和结尾部分(但中间的不会) 的空格和 tab 会被移除.

如果 DelimiterChars 为空, 那么 OmitChars 表示应该考虑移除哪些字符(它们将不会出现在循环中).

备注

当你想对一个字符串中包含的每一个片段进行操作时, 字符串解析循环很有用. 解析循环比 StrSplit 使用更少的内存且在大多数情况下更容易使用(尽管无论哪种方式使用的内存都是暂时的).

内置变量 A_LoopField 存在于任何解析循环中. 它包含了当前子字符串(片段) 的内容. 如果一个内层解析循环包含在一个外层解析循环中, 则最内层循环的片段将具有优先权.

尽管不存在内置变量 "A_LoopDelimiter", 不过在此页面最底部的例子演示了如何检测在分割每个片段时是由于遇到哪个分隔字符.

输入字符串或其片段没有大小限制.

要在解析前按不同的顺序排列字段, 请使用 Sort 函数.

请参阅 Loop 了解关于区块, Break, Continue 和 A_Index 变量(其存在于各种类型的循环中) 的相关信息.

循环的后面有一个可选的 Else 语句, 如果循环的迭代次数为零, 则执行 Else 语句. 注意, 除非 String 为空或者省略了 DelimiterChars 并且 String 中的所有字符都包含在 OmitChars 中, 否则循环总是至少有一次迭代.

相关

StrSplit, file-reading loop, Loop, Break, Continue, 区块, Sort, FileSetAttrib, FileSetTime

示例

解析一个逗号分隔的字符串.

Colors := "red,green,blue"
Loop parse, Colors, ","
{
    MsgBox "Color number " A_Index " is " A_LoopField
}

按行读取变量的内容, 一行接一行(类似于 file-reading 循环). 文件可以通过 FileRead 加载到变量中.

Loop parse, FileContents, "`n", "`r"  ; 在 `r 之前指定 `n, 这样可以同时支持对 Windows 和 Unix 文件的解析.
{
    Result := MsgBox("Line number " A_Index " is " A_LoopField ".`n`nContinue?",, "y/n")
}
until Result = "No"

除了用于剪贴板外, 这个例子和上一个一样. 每当剪贴板包含文件时这个例子很有用, 例如从打开的资源管理器窗口复制的文件(程序自动把这些文件转换为它们的文件名).

Loop parse, A_Clipboard, "`n", "`r"
{
    Result := MsgBox("File number " A_Index " is " A_LoopField ".`n`nContinue?",, "y/n")
}
until Result = "No"

解析逗号分隔值(CSV) 文件.

Loop read, "C:\Database Export.csv"
{
    LineNumber := A_Index
    Loop parse, A_LoopReadLine, "CSV"
    {
        Result := MsgBox("Field " LineNumber "-" A_Index " is:`n" A_LoopField "`n`nContinue?",, "y/n")
        if Result = "No"
            return
    }
}

判断遇到了哪个分隔字符.

; 初始化要搜索的字符串.
Colors := "red,green|blue;yellow|cyan,magenta"
; 初始化计数器来跟踪字符串中我们的位置.
Position := 0

Loop Parse, Colors, ",|;"
{
    ; 计算在这个字段末尾分隔字符的位置.
    Position += StrLen(A_LoopField) + 1
    ; 获取解析循环中找到的分隔字符.
    DelimiterChar := SubStr(Colors, Position, 1)

    MsgBox "Field: " A_LoopField "`nDelimiter character: " DelimiterChar
}


Loop Read - 语法 & 使用 | AutoHotkey v2

Loop Read

检索文本文件中的行, 每次一行.

Loop Read InputFile , OutputFile

参数

InputFile

类型: 字符串

需要在循环中读取其内容的文本文件的名称, 如果未指定绝对路径, 则假定在 A_WorkingDir 中. 文件的行结束符可以是回车和换行符(`r`n), 也可以只是换行符(`n), 或只是回车(`r).

OutputFile

类型: 字符串

(可选的) 在循环期间保持打开的文件的名称, 如果未指定绝对路径, 则假定在 A_WorkingDir 中.

在循环的主体内, 使用 FileAppend 函数, 不带 Filename 参数(即省略它) 来追加到这个特殊的文件. 以这种方式追加到一个文件比使用 2 个参数模式的 FileAppend 执行地更好, 因为每次操作时不需要关闭文件和再重新打开. 如果需要的话, 记得在文本后加入换行符(`n) 或回车符和换行符(`r`n).

如果没有向文件写入任何内容, 文件就不会被打开. 如果循环执行零迭代或从未调用 FileAppend, 就会发生这种情况.

选项: 行末(EOL) 转换模式和输出文件编码取决于在 FileAppend 的首次调用中传递的选项(即省略 Filename 的首次调用). 随后的调用会忽略 Options 参数. 默认情况下不执行 EOL 转换; 也就是说, 除非存在 "`n" 选项, 否则换行符(`n) 将按原样写入.

标准输出(stdout): 指定 OutputFile 为星号(*) 可以把 FileAppend 写入的任何文本发送到标准输出(stdout). 这些文本可以重定向到文件, 指向另一个 EXE 的管道或被高级文本编辑器捕获, 然而发送到标准输出的文本不会出现在运行它的命令提示符中. 这可以通过以下方法解决 1) 使用 Ahk2Exe ConsoleApp 指令编译脚本, 或 2) 通过管道或重定向捕获脚本的输出. 有关详情, 请参阅 FileAppend.

备注

当您想对包含在文本文件中的内容逐行进行操作时, 文件读取循环很有用. 在整个操作过程中, 文件是打开的, 以避免每次都要重新扫描以找到下一行.

内置变量 A_LoopReadLine 存在于任何文件读取循环中. 它包含当前行的内容, 不包括回车和标志行结束的换行符(`r`n). 如果一个内部的文件读取循环被一个外部的文件读取循环所包围, 那么最内部循环的文件行将优先.

读取长度为 65,534 个字符的行. 如果行的长度超过了这个长度, 其剩余的字符将在下一个循环迭代时被读取.

StrSplit 或解析循环通常用于文件读取循环中, 以解析从 InputFile 中获取的每一行的内容. 例如, 如果 InputFile 的每一行都是一系列以 tab 分隔的字段, 那么这些字段可以像这个例子一样单独检索:

Loop read, "C:\Database Export.txt"
{
    Loop parse, A_LoopReadLine, A_Tab
    {
        MsgBox "Field number " A_Index " is " A_LoopField "."
    }
}

要加载整个文件内容到变量中, 请使用 FileRead, 因为它比循环执行的更好(尤其对于大文件).

要同时打开多个文件, 请使用 FileOpen.

可以选择使用 One True Brace(OTB) 样式, 它允许左大括号出现在同一行而不是下面. 例如: Loop Read InputFile, OutputFile {.

请参阅 Loop 了解关于区块, Break, Continue 和 A_Index 变量(其存在于各种类型的循环中) 的相关信息.

在不存在字节顺序标记时要控制如何解码文件, 请使用 FileEncoding.

循环的后面可以有一个可选的 Else 语句, 如果输入文件是空的或者找不到的话, 就会执行这个语句. 如果指定了 OutputFile, 上面描述的 FileAppend 的特殊模式也可以在 Else 语句的主体中使用. 如果没有 Else 语句, 如果找不到文件, 则抛出 OSError.

相关

FileEncoding, FileOpen/File 对象, FileRead, FileAppend, Sort, Loop, Break, Continue, 区块, FileSetAttrib, FileSetTime

示例

只有首个文件中包含单词 FAMILY 的那些行才会写入第二个文件中. 取消注释首行可以覆盖而不是追加到任何现有的文件中.

;FileDelete "C:\Docs\Family Addresses.txt"

Loop read, "C:\Docs\Address List.txt", "C:\Docs\Family Addresses.txt"
{
    if InStr(A_LoopReadLine, "family")
        FileAppend(A_LoopReadLine "`n")
}
else
    MsgBox "Address List.txt was completely empty or not found."

获取文本文件的最后一行.

Loop read, "C:\Log File.txt"
    last_line := A_LoopReadLine  ; 当循环结束时, 这里会保持最后一行的内容.

尝试从文本或 HTML 文件中提取所有 FTP 和 HTTP URL.

SourceFile := FileSelect(3,, "Pick a text or HTML file to analyze.")
if SourceFile = ""
    return  ; 此时将退出.

SplitPath SourceFile,, &SourceFilePath,, &SourceFileNoExt
DestFile := SourceFilePath "\" SourceFileNoExt " Extracted Links.txt"

if FileExist(DestFile)
{
    Result := MsgBox("Overwrite the existing links file? Press No to append to it.`n`nFILE: " DestFile,, 4)
    if Result = "Yes"
        FileDelete DestFile
}

LinkCount := 0
Loop read, SourceFile, DestFile
{
    URLSearch(A_LoopReadLine)
}
MsgBox LinkCount ' links were found and written to "' DestFile '".'
return

URLSearch(URLSearchString)
{
    ; 由于在一些 URL(网址) 中内嵌有其他的 URL, 所以用这种特殊的方法进行处理:
    ; 找到最左边的起始位置:
    URLStart := 0  ; 设置起始默认值.
    for URLPrefix in ["https://", "http://", "ftp://", "www."]
    {
        ThisPos := InStr(URLSearchString, URLPrefix)
        if !ThisPos  ; 此前缀被取消资格.
            continue
        if !URLStart
            URLStart := ThisPos
        else ; URLStart 里面有一个有效的位置, 所以要和 ThisPos 比较一下.
        {
            if ThisPos && ThisPos < URLStart
                URLStart := ThisPos
        }
    }

    if !URLStart  ; 在 URLSearchString 中不存在 URL.
        return

    ; 否则, 提取该 URL:
    URL := SubStr(URLSearchString, URLStart)  ; 忽略开始/无效部分.
    Loop parse, URL, " `t<>"  ; 找到首个空格, tab 或尖括号(如果有).
    {
        URL := A_LoopField
        break  ; 即仅执行一次循环来获取首个 "片段".
    }
    ; 如果上面的循环因为没有找到结尾字符而导致迭代次数为零,
    ; 那么 URL 变量的内容保持不变.

    ; 如果 URL 以双引号结束, 那么移除它. 暂时使用 StringReplace, 不过注意
    ; 双引号似乎可以合法存在于 URL 中, 所以这样做
    ; 可能破坏它们:
    URLCleansed := StrReplace(URL, '"')
    FileAppend URLCleansed "`n"
    global LinkCount += 1

    ; 看看当前行中是否含有其他 URL:
    CharactersToOmit := StrLen(URL)
    CharactersToOmit += URLStart
    URLSearchString := SubStr(URLSearchString, CharactersToOmit)

    ; 到自身的递归调用:
    URLSearch(URLSearchString)
}


Loop Reg - 语法 & 使用 | AutoHotkey v2

Loop Reg

检索指定的注册表子键的内容, 每次一个项目.

Loop Reg KeyName , Mode

参数

KeyName

类型: 字符串

注册表键的全名, 例如 "HKLM\Software\SomeApplication".

必须以 HKEY_LOCAL_MACHINE(或 HKLM), HKEY_USERS(或 HKLM), HKEY_CURRENT_USER(或 HKLM), HKEY_CLASSES_ROOT(或 HKLM) 或 HKEY_CURRENT_CONFIG(或 HKLM) 开始.

要访问远程注册表, 请在前面加上计算机名和反斜杠, 例如 "\\workstation01\HKLM".

Mode

类型: 字符串

如果为空或省略, 则只包含值且不递归子键. 否则, 指定一个或多个下列字母:

  • K = 包含键名.
  • V = 包含键值. K 和 V 都被省略时, 默认也包含键值.
  • R = 递归子键. 若省略 R, KeyName 下的子键中的键名和键值都不会被包含.

备注

当您想对注册表值或子键集合中的项逐个进行操作时, 注册表循环很有用. 值和子键以逆序获取(自下而上), 这样在循环中使用 RegDelete 和 RegDeleteKey 不会扰乱循环自身.

下列变量存在于任何注册表循环中. 如果一个内层注册表循环包含在一个外层注册表循环中, 那么最内层循环的注册表项将具有优先权:

变量 | 描述
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 | 包含当前循环项目的键的全名. 对于远程注册表访问, 该值 不 包括计算机名称.
A_LoopRegTimeModified | 当前子键或其任何值最后被修改的时间. 格式为 YYYYMMDDHH24MISS. 如果当前检索到的项目不是子键(即 A_LoopRegType 不是单词 KEY), 则该变量为空.

在注册表循环中使用下列命令时, 可以以一种简化的方式来操作当前获取项:

语法 | 描述
Value := RegRead() | 读取当前项. 如果当前项为键, 则抛出异常.
RegWrite Value RegWrite | 写入到当前项. 如果省略 Value, 根据不同的类型当前项可能被置为 0 或空. 如果当前项为键, 则抛出异常, 并且注册表不会被修改.
RegDelete | 如果当前项目是值, 则删除当前项目. 如果当前项目是键, 则会删除其默认值.
RegDeleteKey | 如果当前项目是键, 则删除当前项目. 如果当前项目是一个值, 则 包含 该值的键将被删除, 包括所有子键和值.
RegCreateKey | 如上面 RegDeleteKey 所示的目标键. 如果该键在循环中被删除, 则可以使用 RegCreateKey 重新创建该键. 否则, 仅仅验证脚本是否具有对键的写访问权.

访问远程注册表时(通过上面描述的 KeyName 参数), 需要注意以下事项:

  • 目标机器上必须正在运行远程注册表服务.
  • 如果您和目标计算机不在相同的域或者本地或远程用户名缺乏足够的权限(然而, 请参阅下文了解可能的解决方法) 时, 访问远程注册表可能失败.
  • 在尝试访问远程注册表之前, 根据您的用户名所在的域, 工作组和/或权限, 您可能必须连接到共享设备, 例如通过映射驱动器. 建立这样的连接 -- 使用拥有访问或编辑注册表权限的远程用户名和密码 -- 也许可以顺带启用远程注册表访问
  • 如果您已经作为另一个用户连接到目标计算机(例如, 通过 Guest 用户映射驱动器), 您可能必须终止这个连接, 以允许远程注册表功能使用您当前登录的用户名重新连接和认证.

可以选择使用 One True Brace(OTB) 样式, 它允许左大括号出现在同一行而不是下面. 例如: Loop Reg "HKLM\Software\AutoHotkey", "V" {.

请参阅 Loop 了解关于区块, Break, Continue 和 A_Index 变量(其存在于各种类型的循环中) 的相关信息.

循环后面可以有一个可选的 Else 语句, 如果没有找到指定类型的注册表项(即循环的迭代次数为零), 则执行 Else 语句.

相关

Loop, Break, Continue, 区块, RegRead, RegWrite, RegDelete, RegDeleteKey, SetRegView

示例

检索指定注册表子键的内容, 每次检索一项.

Loop Reg, "HKEY_LOCAL_MACHINE\Software\SomeApplication"
    MsgBox A_LoopRegName

删除用户输入的 Internet Explorer 的 URL 历史.

Loop Reg, "HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\TypedURLs"
    RegDelete

有效的测试脚本.

Loop Reg, "HKCU\Software\Microsoft\Windows", "R KV"  ; 递归检索键和值.
{
    if A_LoopRegType = "key"
        value := ""
    else
    {
        try
            value := RegRead()
        catch
            value := "*error*"
    }
    Result := MsgBox(A_LoopRegName " = " value " (" A_LoopRegType ")`n`nContinue?",, "y/n")
}
Until Result = "No"

用于在整个注册表中递归搜索特定值.

RegSearch("Notepad")

RegSearch(Target)
{
    Loop Reg, "HKEY_LOCAL_MACHINE", "KVR"
    {
        if !CheckThisRegItem()  ; 这里告知我们要停止搜索.
            return
    }
    Loop Reg, "HKEY_USERS", "KVR"
    {
        if !CheckThisRegItem()  ; 这里告知我们要停止搜索.
            return
    }
    Loop Reg, "HKEY_CURRENT_CONFIG", "KVR"
    {
        if !CheckThisRegItem()  ; 这里告知我们要停止搜索.
            return
    }
    ; 请注意: 我认为如果已经搜索了 HKEY_USERS, 那么可以不必搜索 HKEY_CURRENT_USER.
    ; 同样地, HKEY_CLASSES_ROOT 提供了
    ; HKEY_LOCAL_MACHINE 和 HKEY_CURRENT_USER 键的集合视图, 所以完全搜索这三个键是没有必要的.

    CheckThisRegItem()
    {
        if A_LoopRegType = "KEY"  ; 如果您也想检查键名, 那么移除这两行.
            return true
        try
            RegValue := RegRead()
        catch
            return true
        if InStr(RegValue, Target)
        {
            Result := MsgBox(
            (
            "The following match was found:
            " A_LoopRegKey "\" A_LoopRegName "
            Value = " RegValue "

            Continue?"
            ),, "y/n")
            if Result = "No"
                return false  ; 告知我们的调用者停止搜索.
        }
        return true
    }
}


Map 对象 - 方法 & 属性 | AutoHotkey v2

Map 对象

class Map extends Object

Map(映射) 对象将一组称为 键 的值关联或 映射 到另一组值. 键及其映射到的值称为键-值对. 映射可以包含任意数量的键值对, 但是每个键必须是唯一的.

键可以是任何整数, 对象引用或以 null 结尾的字符串. 字符串键的比较是区分大小写的, 而对象是通过引用/地址进行比较的. 浮点数键被自动转换成字符串.

映射的最简单用法是通过隐式的 __Item 属性检索或设置键-值对, 只需在映射对象后面的方括号中写入键. 例如:

clrs := Map()
clrs["Red"] := "ff0000"
clrs["Green"] := "00ff00"
clrs["Blue"] := "0000ff"
for clr in Array("Blue", "Green")
    MsgBox clrs[clr]

下面使用 "MapObj" 作为任何 Map 对象的占位符, 因为 "Map" 就是类本身.

除了从 Object 继承的方法和属性外, Map 对象还具有以下预定义的方法和属性.

目录

  • 静态方法:
    • Call: 创建一个 Map 并设置项目.
  • 方法:
    • Clear: 从映射中删除所有键-值对.
    • Clone: 返回对象的一个浅拷贝.
    • Delete: 从映射中删除键-值对.
    • Get: 返回键关联的值, 或者一个默认值.
    • Has: 如果 Key 在映射中有关联的值, 则返回 true.
    • Set: 设置零个或多个项目.
    • __Enum: 枚举键-值对.
    • __New: 设置项目. 等同于 Set.
  • 属性:
    • Count: 检索映射中存在的键-值对的数量.
    • Capacity: 检索或设置映射的当前容量.
    • CaseSense: 检索或设置映射的大小写敏感性设置.
    • Default: 定义当没有找到键时返回的默认值.
    • __Item: 检索或设置键-值对的值.

静态方法

Call

创建一个 Map 并设置项目.

MapObj := Map(Key1, Value1, Key2, Value2, ...)
MapObj := Map.Call(Key1, Value1, Key2, Value2, ...)

这等同于使用用 MapObj[Key] := Value 来设置每个项目, 除了 __Item 没有被调用, 而且 Capacity 会被自动调整以避免在一次调用中多次扩展.

参数由 __New 定义.

方法

Clear

从映射中删除所有键-值对.

MapObj.Clear()

Clone

返回对象的一个浅拷贝.

Clone := MapObj.Clone()

所有键-值对都被复制到新映射. 对象 引用 被复制(就像普通的赋值一样), 而不是对象本身.

根据 Obj.Clone 来复制自有的属性, 方法和基.

Delete

从映射中删除键-值对.

RemovedValue := MapObj.Delete(Key)

参数

Key

类型: 整数, 对象或字符串

任意一个键. 如果映射不包含此键, 则抛出 UnsetItemError.

返回值

类型: Any

此方法返回删除的值.

Get

返回键关联的值, 或者一个默认值.

Value := MapObj.Get(Key , Default)

此方法执行以下操作:

  • 返回与 Key 关联的值, 如果找到.
  • 如果 Default 参数的值, 如果指定.
  • 返回 MapObj.Default 的值, 如果定义.
  • 抛出 UnsetItemError.

当 Default 被省略时, 这等同于 MapObj[Key], 除了没有调用 __Item.

Has

如果 Key 在映射中有关联的值, 则返回 true, 否则返回 false.

MapObj.Has(Key)

Set

设置零个或多个项目.

MapObj.Set(Key, Value, Key2, Value2, ...)

这相当于用 MapObj[Key] := Value 来设置每个项目, 除了 __Item 没有被调用和 Capacity 会被自动调整, 以避免在一次调用中扩展多次.

返回值

类型: Object

此方法返回 map 对象.

__Enum

枚举键-值对.

For Key , Value in MapObj

返回一个新的枚举器. 该方法通常不直接调用. 而是将映射对象被直接传递给 for-loop, 其调用一次 __Enum 然后循环的每次迭代都调用一次枚举器. 每次对枚举器的调用都会返回下一个键和/或值. for-loop 的变量对应于枚举器的参数, 它们是:

Key

类型: 整数, 对象或字符串

键.

Value

类型: Any

值.

__New

设置项目. 等同于 Set.

MapObj.__New(Key, Value, Key2, Value2, ...)

这个方法是为了支持 Call 而存在的, 并不打算直接调用. 请参阅构造和销毁.

属性

Count

检索映射中存在的键-值对的数量.

Count := MapObj.Count

Capacity

检索或设置映射的当前容量.

MaxItems := MapObj.Capacity
MapObj.Capacity := MaxItems

MaxItems 是一个整数, 表示在必须自动扩展前, 映射可以包含的最大键-值对数量. 如果设置的值小于当前键-值对数量, 则使用设置的值并释放未使用的空间.

CaseSense

检索或设置映射的大小写敏感性设置.

CurrentSetting := MapObj.CaseSense
MapObj.CaseSense := NewSetting

如果已经赋值, CurrentSetting 为 NewSetting, 否则默认为 On(但请注意, 该属性只能检索当前设置的字符串变量).

NewSetting 是以下字符串或整数(布尔值) 之一:

On 或 1(true): 键查找区分大小写. 这是默认设置.

Off 或 0(false): 键查找不区分大小写, 即字母 A-Z 被认为与对应小写字母相同.

Locale: 根据当前用户的区域设置规则, 键查找不区分大小写. 例如, 大多数英语和西欧地区不仅将字母 A-Z视为与其对应的小写字母相同, 而且将非 ASCII 字母(如 Ä 和 Ü) 视为与其对应的字母相同. Locale 比 Off 慢 1 到 8 倍, 具体取决于所比较字符串的性质.

如果 Map 不是空的, 尝试为该属性赋值将导致抛出异常.

Default

定义当没有找到键时返回的默认值.

MapObj.Default := Value

默认情况下, 这个属性实际上并不存在, 但可以由脚本定义. 如果定义了, 如果无法找到请求的项, 则由 __Item 或 Get 返回其值, 而不是抛出 UnsetItemError. 它可以通过任何正常的方式来实现, 包括动态属性或元函数, 但确定哪个键被查询到, 需要覆盖 __Item 或 Get 来代替.

__Item

检索或设置键-值对的值.

Value := MapObj[Key]
Value := MapObj.__Item[Key]
MapObj[Key] := Value
MapObj.__Item[Key] := Value

检索值时, Key 必须是先前与另一个值关联的唯一值. 如果 Key 在映射中没有关联的值, 则抛出 UnsetItemError, 除非定义了 Default 属性, 在这种情况下返回其值.

赋值时, 与 Value 关联的 Key 可以是任何值; 换句话说, key 用于以后访问 Value. 浮点键会自动转换为字符串.

如上所示, 属性名 __Item 通常被省略, 但在覆盖属性时使用.


数学函数 - 语法 & 使用 | AutoHotkey v2

数学函数

用于执行各种数学运算的函数, 如四舍五入, 取幂, 平方等.

目录

  • 常规数学:
    • Abs: 返回数字的绝对值.
    • Ceil: 返回数字向上到的最近的整数.
    • Exp: 返回 e 的 N 次方.
    • Floor: 返回数字向下到的最近的整数.
    • Log: 返回数字的对数(10 为底).
    • Ln: 返回数字的自然对数(e 为底).
    • Max: 返回一组数字中的最大值.
    • Min: 返回一组数字中的最小值.
    • Mod: 取模. 返回除法的余数.
    • Round: 返回四舍五入到 N 位小数的数字.
    • Sqrt: 返回数字的平方根.
  • 三角函数:
    • Sin: 返回一个数字的三角正弦值.
    • Cos: 返回数字的三角余弦值.
    • Tan: 返回数字的三角正切值.
    • ASin: 返回以弧度表示的反正弦值.
    • ACos: 返回以弧度表示的反余弦值.
    • ATan: 返回以弧度表示的反正切值.
  • 错误处理

常规数学

Abs

返回指定数字的绝对值.

Value := Abs(Number)

返回值的类型和 Number 的一样(整数或浮点数).

MsgBox Abs(-1.2) ; 返回 1.2

Ceil

返回指定数字向上取整后的整数(不含任何 .00 后缀).

Value := Ceil(Number)
MsgBox Ceil(1.2)  ; 返回 2
MsgBox Ceil(-1.2) ; 返回 -1

Exp

返回 e(近似值为 2.71828182845905) 的 N 次幂.

Value := Exp(N)

N 可以为负数或十进制小数. 要计算 e 之外的数字的幂, 请使用 ** 运算符.

MsgBox Exp(1.2) ; 返回 3.320117

Floor

返回指定数字向下取整后的整数(不含任何 .00 后缀).

Value := Floor(Number)
MsgBox Floor(1.2)  ; 返回 1
MsgBox Floor(-1.2) ; 返回 -2

Log

返回指定数字的对数(10 为底).

Value := Log(Number)

结果为浮点数. 如果 Number 为负数, 则抛出 ValueError.

MsgBox Log(1.2) ; 返回 0.079181

Ln

返回指定数字的自然对数(e 为底).

Value := Ln(Number)

结果为浮点数. 如果 Number 为负数, 则抛出 ValueError.

MsgBox Ln(1.2) ; 返回 0.182322

Max

返回一组数字中的最大值.

Number := Max(Number1 , Number2, ...)
MsgBox Max(2.11, -2, 0) ; 返回 2.11

你还可以指定一个可变参数来传递数字的数组. 例如:

Numbers := [1, 2, 3, 4]
MsgBox Max(Numbers*) ; 返回 4

Min

返回一组数字中的最小值.

Number := Min(Number1 , Number2, ...)
MsgBox Min(2.11, -2, 0) ; 返回 -2

你还可以指定一个可变参数来传递数字的数组. 例如:

Numbers := [1, 2, 3, 4]
MsgBox Min(Numbers*) ; 返回 1

Mod

取模运算. 返回一个数字(被除数) 除以另一个数字(除数) 的余数.

Value := Mod(Dividend, Divisor)

结果的正负号总是与第一个参数相同. 如果任意一个输入是浮点数, 则结果也是浮点数. 如果第二个参数为 0, 则抛出 ValueError .

MsgBox Mod(7.5, 2) ; 返回 1.5 (2 x 3 + 1.5)

Round

返回指定数字四舍五入到 N 位小数的数字.

Value := Round(Number , N)

如果 N 省略或为 0, Number 四舍五入到整数:

MsgBox Round(3.14)    ; 返回 3

如果 N 为正数, Number 四舍五入到 N 位小数:

MsgBox Round(3.14, 1) ; 返回 3.1

如果 N 为负数, Number 四舍五入到小数点左边 N 位:

MsgBox Round(345, -1) ; 返回 350
MsgBox Round(345, -2) ; 返回 300

如果 N 省略或小于 1, 结果为整数. 否则, 结果为精确到 N 位小数的数字字符串. 如果需要纯数字, 只需对 Round 的返回值执行另一个数学运算; 例如: Round(3.333, 1)+0.

Sqrt

返回指定数字的平方根.

Value := Sqrt(Number)

结果为浮点数. 如果 Number 为负数, 则抛出 ValueError.

MsgBox Sqrt(16) ; 返回 4

三角函数

注意: 要将弧度值转换为度数值, 可用弧度值乘以 180/pi(约为 57.29578). 要将度数值转为弧度值, 可用度数值乘以 pi/180(约为 0.01745329252). pi(约为 3.141592653589793) 的值为 4 乘以 1 的反正切.

Sin

返回指定数字的正弦.

Value := Sin(Number)

Number 必须为弧度值.

MsgBox Sin(1.2) ; 返回 0.932039

Cos

返回指定数字的余弦值.

Value := Cos(Number)

Number 必须为弧度值.

MsgBox Cos(1.2) ; 返回 0.362358

Tan

返回指定数字的正切值.

Value := Tan(Number)

Number 必须为弧度值.

MsgBox Tan(1.2) ; 返回 2.572152

ASin

返回以弧度表示的反正弦值(其正弦值为指定数字).

Value := ASin(Number)

如果 Number 小于 -1 或大于 1, 则抛出 ValueError.

MsgBox ASin(0.2) ; 返回 0.201358

ACos

返回以弧度表示的反余弦值(其余弦值为指定数字).

Value := ACos(Number)

如果 Number 小于 -1 或大于 1, 则抛出 ValueError.

MsgBox ACos(0.2) ; 返回 1.369438

ATan

返回以弧度表示的反正切值(其正切值为指定数字).

Value := ATan(Number)
MsgBox ATan(1.2) ; 返回 0.876058

错误处理

如果传入的参数是非数字的, 或者尝试执行无效操作(如除以0), 则这些函数抛出异常.


Menu/MenuBar 对象 - 方法 & 属性 | AutoHotkey v2

Menu/MenuBar 对象

提供创建和修改菜单或菜单栏, 添加和修改菜单项目, 检索菜单或菜单栏信息的接口.

class Menu extends Object

菜单对象用于定义, 修改和显示弹出菜单. Menu(), MenuFromHandle 和 A_TrayMenu 返回此类对象.

class MenuBar extends Menu

MenuBar 对象用于定义和修改与 Gui.MenuBar 一起使用的菜单栏. 它们是使用 MenuBar() 创建的. 如果给定菜单栏句柄, 则 MenuFromHandle 返回此类型的对象.

下面使用 "MyMenu" 作为任何 Menu 对象的占位符, 因为 "Menu" 就是类本身.

除了从 Object 继承的方法和属性外, Menu 对象还具有以下预定义的方法和属性.

目录

  • 静态方法:
    • Call: 创建一个新的 Menu 或 MenuBar 对象.
  • 方法:
    • Add: 添加或修改菜单项.
    • AddStandard: 添加标准托盘菜单项.
    • Check: 在菜单项旁边添加一个可见的选中标记.
    • Delete: 删除一个或所有菜单项.
    • Disable: 将菜单项更改为灰色, 表示用户无法选择它.
    • Enable: 允许用户再次选择以前禁用的菜单项(灰色).
    • Insert: 在指定的项之前插入一个新项.
    • Rename: 重命名菜单项.
    • SetColor: 改变菜单的背景颜色.
    • SetIcon: 设置显示在菜单项旁边的图标.
    • Show: 显示菜单.
    • ToggleCheck: 切换菜单项旁边的复选标记.
    • ToggleEnable: 启用或禁用菜单项.
    • Uncheck: 移除菜单项上的复选标记(如果有的话).
  • 属性:
    • ClickCount: 检索或设置必须点击多少次托盘图标才能选择其默认菜单项.
    • Default: 检索或设置默认菜单项.
    • Handle: 检索菜单的 Win32 句柄.
  • 常规:
    • MenuItemName
    • Win32 菜单
    • 备注
    • 相关
    • 示例

静态方法

Call

创建新的 Menu 或 MenuBar 对象.

MyMenu := Menu()
MyMenuBar := MenuBar()
MyMenu := Menu.Call()
MyMenuBar := MenuBar.Call()

Add

添加或修改菜单项.

MyMenu.Add(MenuItemName, CallbackOrSubmenu, Options)

参数

MenuItemName

类型: 字符串

要显示在菜单项上的文字, 或者要修改的现有项的位置&. 请参阅 MenuItemName.

CallbackOrSubmenu

类型: 函数对象或 Menu

选择菜单项或作为子菜单使用的 Menu 对象引用时, 函数作为新线程被调用.

在创建新项目时需要此参数, 但在更新现有项目选项时可选.

回调接受三个参数, 可以定义如下:

MyCallback(ItemName, ItemPos, MyMenu) { ...

虽然你给参数的名字并不重要, 但是下面的值会依次赋值给它们:

  1. 菜单项的名称.
  2. 菜单项的位置编号.
  3. 添加菜单项的 Menu 对象.

如果不需要相应的信息, 你可以从回调参数列表的末尾省略一个或多个参数, 但在这种情况下, 必须指定星号作为最后一个参数, 例如 MyCallback(Param1, *).

Options

类型: 字符串

如果为空或省略, 则默认为无选项. 否则, 从下面的列表中指定一个或多个选项(不区分大小写). 用空格或制表符将每个选项与下一个选项分开. 若要删除某个选项, 请在其前面加一个减号. 要添加一个选项, 可以使用加号, 但不是必需的.

P n: 指定 n 为菜单项的线程优先级, 例如 P1. 如果在添加菜单项时省略该选项, 优先级将为 0, 这是标准的默认值. 如果在更新菜单项时省略该选项, 则该项目的优先级将不会改变. 请使用十进制(不是十六进制) 数字作为优先级.

Radio: 如果该项目被选中, 则使用个空心圆代替复选标记.

Right: 该项目在菜单栏内右对齐. 这只适用于菜单栏, 不适用于弹出式菜单或子菜单.

Break: 该项在弹出式菜单中开始一个新的列.

BarBreak: 同上, 但在列之间有一条分界线.

要改变一个现有项目的选项而不影响它的回调或子菜单, 只需省略 CallbackOrSubmenu 参数.

要添加菜单分隔线, 请省略所有三个参数.

备注

这是一个多用途的方法, 它可以添加一个菜单项, 用新的子菜单或回调更新一个菜单项, 或者将一个菜单项从普通项转换为子菜单(反之亦然). 如果 MenuItemName 还不存在, 它将被添加到菜单中. 否则, 将用新指定的 CallbackOrSubmenu 和/或 Options 更新 MenuItemName.

Add 总是在菜单底部添加新的菜单项, 但 Insert 可以用来在现有的自定义菜单项之前插入一个项目.

此方法总是在菜单底部添加新的菜单项, 而 Insert 方法可用于在现有自定义菜单项之前插入一个项目.

AddStandard

添加标准的托盘菜单项.

MyMenu.AddStandard()

此方法可以与托盘菜单或任何其他菜单一起使用.

标准项目被插入到任何现有项目之后. 任何已经在菜单中的标准项不会被重复, 但任何缺失的项目会被添加. 下表显示了在空菜单上调用 AddStandard 后标准项的名称和位置:

&Open | 1 | 0
&Help | 2 |
 | 3 |
&Window Spy | 4 |
&Reload Script | 5 |
&Edit Script | 6 |
 | 7 |
&Suspend Hotkeys | 8 | 1
&Pause Script | 9 | 2
E&xit | 10 | 3

编译后的脚本默认只包含最后三个. 只有在 A_AllowMainWindow 为 1 时, 调用 AddStandard 才会包含 &Open(在这种情况下, 在第三列显示的位置上加 1). 如果托盘菜单中包含标准项目, 每当改变 A_AllowMainWindow 时, 就会插入或移除 &Open. 对于其他菜单, 如果 A_AllowMainWindow 为 0, 则 &Open 没有效果.

每个标准项都有一个内部的菜单项 ID, 与它所执行的功能相对应, 但也可以像其他菜单项一样被修改或删除. AddStandard 通过 ID 而不是名称来检测现有的项目. 如果使用 Add 方法来改变与标准菜单项相关联的回调函数, 那么它将被分配一个新的唯一 ID, 并且不再被认为是一个标准项.

将 &Open 项添加到托盘菜单中会导致它成为默认项, 如果还没有的话.

Check

在菜单项旁边添加一个可见的复选标记(如果还没有).

MyMenu.Check(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

Delete

删除一个或所有菜单项.

MyMenu.Delete(MenuItemName)

参数

MenuItemName

类型: 字符串

如果省略, 则所有项目都会从菜单中删除, 使菜单为空. 否则, 请指定菜单项的名称或位置. 请参阅 MenuItemName.

备注

空菜单仍然存在, 因此, 任何使用它作为子菜单的其他菜单将保留这些子菜单.

要删除一个分隔线, 请通过它在菜单中的位置来识别它. 例如, 如果分隔符前面有两个项目, 则使用 MyMenu.Delete("3&").

如果删除了 default 菜单项, 其效果将类似于设置了 Menu.Default := "".

Disable

将菜单项改为灰色, 以指示用户无法选择它.

MyMenu.Disable(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

Enable

允许用户再次选择菜单项, 如果它之前被禁用(灰色).

MyMenu.Enable(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

Insert

在指定的项之前插入一个新项.

MyMenu.Insert(MenuItemName, ItemToInsert, CallbackOrSubmenu, Options)

参数

MenuItemName

类型: 字符串

如果为空或省略, ItemToInsert 将被添加到菜单的底部. 否则, 指定现有自定义菜单项的名称或位置, ItemToInsert 应插入到该菜单项之前. 请参阅 MenuItemName.

ItemToInsert

类型: 字符串

要在 MenuItemName 之前插入的新菜单项的名称. 与 Add 方法不同的是, 即使 ItemToInsert 与现有项目的名称一致, 也始终会创建一个新项目.

CallbackOrSubmenu

请参阅 Add 方法的 CallbackOrSubmenu 参数.

Options

请参阅 Add 方法的 Options 参数.

备注

要在现有自定义菜单项之前插入菜单分隔线, 请省略除 MenuItemName 以外的所有参数. 要在菜单底部添加菜单分隔线, 请省略所有参数.

Rename

重命名菜单项.

MyMenu.Rename(MenuItemName , NewName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

NewName

类型: 字符串

如果为空或省略, MenuItemName 将被转换为分隔线. 否则, 请指定新的名称.

备注

菜单项的当前回调或子菜单不变.

通过指定分隔线的位置, 如为 MenuItemName 指定 "1&" 和给 NewName 指定一个非空白名称, 然后使用 Add 方法给项目一个回调或子菜单, 可以将分隔线转换为一个普通项目.

SetColor

改变菜单的背景颜色.

MyMenu.SetColor(ColorValue, ApplyToSubmenus)

参数

ColorValue

类型: 字符串或整数

16 种主要的 HTML 颜色名称之一, 十六进制的 RGB 颜色字符串(0x 前缀是可选的), 或一个纯数字 RGB 颜色值. 省略 ColorValue(或指定一个空字符串或单词 "Default") 来恢复菜单的默认颜色. 示例值: "Silver", "FFFFAA", 0xFFFFAA, "Default".

ApplyToSubmenus

类型: 布尔值

如果省略, 则默认为 true.

如果为 true, 颜色将应用于这个菜单的所有子菜单.

如果为 false, 颜色将只应用于菜单.

SetIcon

设置显示在菜单项旁边的图标.

MyMenu.SetIcon(MenuItemName, FileName , IconNumber, IconWidth)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

FileName

类型: 字符串

图标或图像文件的路径, 或位图或图标句柄, 如, "HICON:" handle. 关于支持的格式列表, 请参阅 Picture 控件.

指定一个空字符串或 "*" 来删除该项的当前图标.

IconNumber

类型: 整数

如果省略, 则默认为 1(第一个图标组). 否则, 请在文件中指定要使用的图标组的编号. 例如, MyMenu.SetIcon(MenuItemName, "Shell32.dll", 2) 将使用第二个图标组中的默认图标. 如果为负数, 则假定其绝对值为可执行文件中图标的资源 ID.

IconWidth

类型: 整数

如果省略, 则默认为操作系统推荐的小图标宽度(通常为 16 像素). 如果为 0, 则使用原始宽度. 否则, 指定图标所需的宽度(以像素为单位). 如果 IconNumber 表示的图标组包含多个图标大小, 则使用最接近的匹配, 并将图标缩放到指定的大小.

备注

目前, 在设置图标时需要指定 "实际大小" 以保持透明度, 例如 MyMenu.SetIcon(MenuItemName, "Filename.png",, 0).

Show

显示菜单.

MyMenu.Show(X, Y)

参数

X, Y

类型: 整数

如果省略, 菜单将显示在鼠标光标附近. 否则, 指定显示菜单左上角的 X 和 Y 坐标. 坐标相对于活动窗口的客户端区域, 除非使用 CoordMode 或 A_CoordModeMenu 覆盖.

备注

显示菜单允许用户使用方向键, 菜单快捷方式(带下划线的字母)或鼠标选择项目.

任何弹出式菜单都可以被显示, 包括子菜单和托盘菜单. 但是, 如果 MyMenu 是 MenuBar 对象, 则抛出异常.

ToggleCheck

如果没有复选标记, 则添加; 否则, 就移除.

MyMenu.ToggleCheck(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

ToggleEnable

如果之前已经启用, 则禁用菜单项; 否则启用.

MyMenu.ToggleEnable(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

Uncheck

移除菜单项上的复选标记(如果有的话).

Menu.Uncheck(MenuItemName)

参数

MenuItemName

类型: 字符串

菜单项的名称或位置. 请参阅 MenuItemName.

属性

ClickCount

检索或设置必须点击多少次托盘图标才能选择其默认菜单项.

CurrentCount := MyMenu.ClickCount
MyMenu.ClickCount := NewCount

如果已经赋值, CurrentCount 为 NewCount, 否则默认为 2.

NewCount 为 1, 允许单次点击选择托盘菜单的默认菜单项. 指定 2 可返回默认行为(双击). 任何其他值都是无效的, 并抛出异常.

Default

检索或设置默认菜单项.

CurrentDefault := MyMenu.Default
MyMenu.Default := MenuItemName

CurrentDefault 是默认菜单项的名称, 如果没有默认项, 则为空字符串.

MenuItemName 是菜单项的名称或位置. 请参阅 MenuItemName. 如果 MenuItemName 是一个空字符串, 则没有默认项.

设置默认项会使该项的字体变粗(在托盘菜单以外的其他菜单中设置默认项目前没有效果). 当用户双击托盘图标时, 其默认的菜单项就会被启动(即使该项目被禁用). 如果没有默认项, 双击没有效果.

托盘菜单的默认项目最初是 &Open, 如果存在的话. 通过调用 AddStandard 将 &Open 添加到托盘菜单中或改变 A_AllowMainWindow 如果没有默认项, 也会使其成为默认项.

如果删除了默认项, 则菜单中没有默认项.

Handle

返回一个 Win32 menu 的句柄(HMENU 类型的句柄), 必要时构造它.

Handle := MyMenu.Handle

返回的句柄只在 Win32 菜单被销毁之前有效, 这通常发生在菜单对象被释放时. 一旦菜单被销毁, 操作系统可以将句柄值重新分配给脚本或任何其他程序随后创建的任何菜单.

MenuItemName

菜单项的名称或位置. 一些通用规则适用于所有使用该参数的方法:

要为菜单项名称的某个字母加下划线, 在这个字母前加一个 & 符号. 当菜单显示出来时, 此项可以通过按键盘上对应的按键来选中. 要显示原义的 & 符号, 指定连续的两个 & 号, 如此例所示: "Save && Exit"

当引用到一个已存在的菜单或菜单项时, 其名称不区分大小写但 & 号不能少. 例如: "&Open"

菜单项的名称最多可以有 260 个字符.

要通过菜单中的位置来识别一个现有的项目, 请在项目的位置后写上一个 &. 例如, "1&" 表示第一个项目.

Win32 Menus

Windows 提供了一组函数和通知, 用于创建, 修改和显示具有标准外观和行为的菜单. 我们把由这些函数之一创建的菜单称为 Win32 menu.

当项目被添加到菜单中或修改时, 每个项目的名称和其他属性都存储在 Menu 对象. 当菜单或它的父菜单第一次连接到 GUI 或显示时, 就会构造一个 Win32 menu. 当菜单对象被删除时, 它就会被自动销毁(当它的引用计数达到零时就会发生).

Menu.Handle 返回一个 Win32 menu 的句柄(HMENU 类型的句柄), 必要时构造它.

任何由 Win32 函数直接对菜单进行的修改都不会反映在脚本的 Menu 对象中, 所以如果一个项目被内置方法修改, 可能会丢失.

当每个菜单项第一次被添加到菜单中时, 它被分配了一个 ID. 脚本不能依赖一个项目收到一个特定的 ID, 但是可以通过使用 GetMenuItemID 来检索一个项目的 ID, 如示例 #5 所示. 这个 ID 不能用于 Menu 对象, 但可以用于各种 Win32 函数.

备注

菜单通常看起来像这样:

如果一个菜单完全变空 -- 比如使用 MyMenu.Delete() -- 它就不能被显示. 如果托盘菜单变成空的, 右击和双击托盘图标将没有任何效果(在这种情况下, 通常最好使用 #NoTrayIcon).

如果一个菜单项的回调已经在运行, 而用户再次选择同一个菜单项, 则会创建一个新的线程来运行同样的回调, 从而中断之前的线程. 如果要把这些事件缓冲到以后, 可以使用 Critical 作为回调的第一行(然而, 这也会缓冲/延迟其他线程, 比如按下热键).

每当通过菜单项调用一个函数时, 它都会以默认值(如 SendMode) 重新开始. 这些默认值可以在脚本启动时更改.

当建立一个内容不总是相同的菜单时, 一种方法是将所有这样的菜单项指向同一个函数, 并让该函数参考它的参数来决定采取什么行动. 另外, 可以使用函数对象, 闭包或胖箭头函数将一个或多个值或变量绑定到菜单项的回调函数上.

相关

GUI, 线程, Thread, Critical, #NoTrayIcon, 函数, Return, SetTimer

示例

添加一个新菜单项到托盘图标菜单的底部.

A_TrayMenu.Add()  ; 创建分隔线.
A_TrayMenu.Add("Item1", MenuHandler)  ; 创建新菜单项.
Persistent

MenuHandler(ItemName, ItemPos, MyMenu) {
    MsgBox "You selected " ItemName " (position " ItemPos ")"
}

创建一个弹出菜单, 当用户按下热键时显示.

; 添加一些菜单项来创建弹出菜单.
MyMenu := Menu()
MyMenu.Add("Item 1", MenuHandler)
MyMenu.Add("Item 2", MenuHandler)
MyMenu.Add()  ; 添加分隔线.

; 添加子菜单到上面的菜单中.
Submenu1 := Menu()
Submenu1.Add("Item A", MenuHandler)
Submenu1.Add("Item B", MenuHandler)

; 创建第一个菜单的子菜单(右箭头指示符). 当用户选择它时会显示第二个菜单.
MyMenu.Add("My Submenu", Submenu1)

MyMenu.Add()  ; 在子菜单下添加分隔线.
MyMenu.Add("Item 3", MenuHandler)  ; 在子菜单下添加另一个菜单项.

MenuHandler(Item, *) {
    MsgBox("You selected " Item)
}

#z::MyMenu.Show()  ; 即按下 Win-Z 热键来显示菜单.

演示各种菜单对象成员.

#SingleInstance
Persistent
Tray := A_TrayMenu ; 为了方便.
Tray.Delete() ; 删除标准项目.
Tray.Add() ; 分隔线
Tray.Add("TestToggleCheck", TestToggleCheck)
Tray.Add("TestToggleEnable", TestToggleEnable)
Tray.Add("TestDefault", TestDefault)
Tray.Add("TestAddStandard", TestAddStandard)
Tray.Add("TestDelete", TestDelete)
Tray.Add("TestDeleteAll", TestDeleteAll)
Tray.Add("TestRename", TestRename)
Tray.Add("Test", Test)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TestToggleCheck(*)
{
    Tray.ToggleCheck("TestToggleCheck")
    Tray.Enable("TestToggleEnable") ; 由于自己无法撤销禁用, 所以还能进行下一次测试.
    Tray.add("TestDelete", TestDelete) ; 类似于上面.
}

TestToggleEnable(*)
{
    Tray.ToggleEnable("TestToggleEnable")
}

TestDefault(*)
{
    if Tray.Default = "TestDefault"
        Tray.Default := ""
    else
        Tray.Default := "TestDefault"
}

TestAddStandard(*)
{
    Tray.AddStandard()
}

TestDelete(*)
{
    Tray.Delete("TestDelete")
}

TestDeleteAll(*)
{
    Tray.Delete()
}

TestRename(*)
{
    static OldName := "", NewName := ""
    if NewName != "renamed"
    {
        OldName := "TestRename"
        NewName := "renamed"
    }
    else
    {
        OldName := "renamed"
        NewName := "TestRename"
    }
    Tray.Rename(OldName, NewName)
}

Test(Item, *)
{
    MsgBox("You selected " Item)
}

添加图标到其菜单项.

FileMenu := Menu()
FileMenu.Add("Script Icon", MenuHandler)
FileMenu.Add("Suspend Icon", MenuHandler)
FileMenu.Add("Pause Icon", MenuHandler)
FileMenu.SetIcon("Script Icon", A_AhkPath, 2) ; 使用文件中的第二个图标组
FileMenu.SetIcon("Suspend Icon", A_AhkPath, -206) ; 使用资源标识符 206 表示的图标
FileMenu.SetIcon("Pause Icon", A_AhkPath, -207) ; 使用资源标识符 207 表示的图标
MyMenuBar := MenuBar()
MyMenuBar.Add("&File", FileMenu)
MyGui := Gui()
MyGui.MenuBar := MyMenuBar
MyGui.Add("Button",, "Exit This Example").OnEvent("Click", (*) => WinClose())
MyGui.Show()

MenuHandler(*) {
    ; 在这个例子中, 菜单项没有任何作用.
}

报告菜单中的项目数量和最后一项的 ID.

MyMenu := Menu()
MyMenu.Add("Item 1", NoAction)
MyMenu.Add("Item 2", NoAction)
MyMenu.Add("Item B", NoAction)

; 检索菜单中的项目数.
item_count := DllCall("GetMenuItemCount", "ptr", MyMenu.Handle)

; 检索最后一个项目的 ID.
last_id := DllCall("GetMenuItemID", "ptr", MyMenu.Handle, "int", item_count-1)

MsgBox("MyMenu has " item_count " items, and its last item has ID " last_id)

NoAction(*) {
    ; 什么都不做.
}


MenuFromHandle - 语法 & 使用 | AutoHotkey v2

MenuFromHandle

检索对应于 Win32 菜单句柄的菜单或菜单栏对象.

Menu := MenuFromHandle(Handle)

参数

Handle

类型: 整数

返回 Win32 菜单的句柄(类型为 HMENU).

备注

如果句柄无效或与此脚本创建的菜单不对应, 则该函数返回一个空字符串.

相关

Win32 菜单, Menu/MenuBar 对象, Menu.Handle, Menu()


MenuSelect - 语法 & 使用 | AutoHotkey v2

MenuSelect

从指定窗口菜单栏中调用菜单项.

MenuSelect WinTitle, WinText, Menu , SubMenu1, SubMenu2, SubMenu3, SubMenu4, SubMenu5, SubMenu6, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

Menu

类型: 字符串

顶级菜单项的名称(或名称前缀), 例如"File", "Edit", "View". 此参数也可以使用期望的菜单项的位置, 通过使用 "1&" 表示首个菜单, "2&" 表示第二个, 以此类推.

根据当前用户区域设置的规则, 搜索是不区分大小写的, 并在第一个匹配项处停止. 使用和符号(&) 来表示菜单项中带下划线的字母, 通常 是不必要的(例如 "&File" 等同于 "File").

已知限制: 如果参数包含一个和符号(&), 那么它必须与项目名称完全匹配, 包括所有非原义的和符号(隐藏或显示为下划线). 如果参数不包含和符号, 则忽略所有和符号, 包括原义的. 例如, 显示为 "a & b" 的项可能匹配的参数值为 a && b 或 a b.

指定 "0&" 使用窗口的系统菜单.

SubMenu1

类型: 字符串

要选择的菜单项的名称或位置(请参阅上面). 如果顶级项目不包含菜单(罕见的), 则可以省略此项.

SubMenu2, SubMenu3, SubMenu4, SubMenu5, SubMenu6

类型: 字符串

如果前一个子菜单包含菜单, 那么这是里面的菜单项的名称或位置.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果找不到菜单, 子菜单或菜单项, 或最后的菜单参数对应于一个打开子菜单的菜单项, 则抛出 ValueError.

备注

为了使该函数工作, 目标窗口可以处于不活动状态. 然而, 某些窗口可能需要处于非最小化状态.

函数对于使用非标准菜单栏的应用程序 无效. 例如 Microsoft Outlook 和 Outlook Express, 它们使用伪装的工具栏作为菜单栏. 在这种情况下, 考虑使用 ControlSend 或 PostMessage, 它们应该能和一些这样的非标准菜单栏交互.

参数中的菜单名称还可以使用位置代替. 提供这种方法是为了支持不包含文本的菜单(可能是由于它们包含文本的图片而不是真实的文本). 位置 1& 表示首个菜单项(例如 File 菜单), 位置 2& 表示第二个菜单项(例如 Edit 菜单), 以此类推. 为了确定菜单项的位置, 菜单分隔线也作为菜单项计算.

系统菜单

Menu 可以是 "0&", 以选择窗口系统菜单的项目, 该菜单通常在用户按下 Alt+Space 或点击窗口标题栏中的图标时出现. 例如:

; 粘贴命令到 cmd.exe 而不用激活窗口.
A_Clipboard := "echo Hello, world!`r"
MenuSelect "ahk_exe cmd.exe",, "0&", "Edit", "Paste"

警告: 仅在窗口的系统菜单中具有自定义项目时使用此项.

如果窗口还没有自定义系统菜单, 则将产生创建一个标准系统菜单的副本并关联到目标窗口的副作用. 该副本在脚本退出时被系统销毁, 导致其他脚本无法访问该副本. 因此, 避免在所有显示标准项目的窗口上使用 0& 作为代替, 直接 post WM_SYSCOMMAND 消息. 例如:

; 类似 [WinMinimize "A"], 但最小化时播放系统声音.
WM_SYSCOMMAND := 0x112
SC_MINIMIZE := 0xF020
PostMessage WM_SYSCOMMAND, SC_MINIMIZE, 0,, "A"

相关

ControlSend, PostMessage

示例

选择记事本的 File -> Open 菜单. 这个例子在 Windows 11 或更高版本系统可能会失败, 因为它需要经典版本的记事本.

MenuSelect "Untitled - Notepad",, "File", "Open"

与上述相同, 只是按位置而不是按名称进行. 在 Windows 10 中, 2& 必须被替换为 3&, 因为新的 "New Window" 菜单项. 这个例子在 Windows 11 或更高版本系统可能会失败, 因为它需要经典版本的记事本.

MenuSelect "Untitled - Notepad",, "1&", "2&"

选择主窗口中的 View -> Lines most recently executed.

WinShow "ahk_class AutoHotkey"
MenuSelect "ahk_class AutoHotkey",, "View", "Lines most recently executed"


监视器函数列表 | AutoHotkey v2

监视器函数

用于检索屏幕分辨率和多显示器信息的函数. 点击函数名获取详细信息.

函数 | 描述
MonitorGet | 检查指定的监视器是否存在, 并可选地检索其边界坐标.
MonitorGetCount | 返回监视器的数量.
MonitorGetName | 返回指定监视器的操作系统名称. .
MonitorGetPrimary | 返回主监视器的编号.
MonitorGetWorkArea | 检查指定的监视器是否存在, 并可选地检索其工作区域的边界坐标.

备注

内置变量 A_ScreenWidth 和 A_ScreenHeight 包含主监视器的尺寸(以像素为单位).

可以使用 SysGet 检索所有显示监视器的边框. 例如, 它检索虚拟屏幕的宽度和高度:

MsgBox SysGet(78) " x " SysGet(79)

相关

DllCall, 窗口函数, SysGet

示例

显示每个监视器的信息.

MonitorCount := MonitorGetCount()
MonitorPrimary := MonitorGetPrimary()
MsgBox "Monitor Count:`t" MonitorCount "`nPrimary Monitor:`t" MonitorPrimary
Loop MonitorCount
{
    MonitorGet A_Index, &L, &T, &R, &B
    MonitorGetWorkArea A_Index, &WL, &WT, &WR, &WB
    MsgBox
    (
        "Monitor:`t#" A_Index "
        Name:`t" MonitorGetName(A_Index) "
        Left:`t" L " (" WL " work)
        Top:`t" T " (" WT " work)
        Right:`t" R " (" WR " work)
        Bottom:`t" B " (" WB " work)"
    )
}


MonitorGet - 语法 & 使用 | AutoHotkey v2

MonitorGet

检查指定的监视器是否存在, 并可选地检索其边界坐标.

ActualN := MonitorGet(N, &Left, &Top, &Right, &Bottom)

参数

N

类型: 整数

如果省略, 则使用主监视器. 否则, 请指定监视器编号, 介于 1 和 MonitorGetCount 返回的数字之间.

&Left, &Top, &Right, &Bottom

类型: VarRef

如果省略, 将不会存储相应的值. 否则, 请指定储存边界坐标(以像素为单位) 的变量的引用.

返回值

类型: 整数

该函数返回显示器编号(与 N 相同, 除非省略 N).

错误处理

失败时抛出异常, 输出变量不会被修改.

备注

内置变量 A_ScreenWidth 和 A_ScreenHeight 包含主监视器的尺寸(以像素为单位).

可以使用 SysGet 检索所有显示监视器的边框. 例如, 它检索虚拟屏幕的宽度和高度:

MsgBox SysGet(78) " x " SysGet(79)

相关

MonitorGetWorkArea, SysGet, 监视器函数

示例

在消息框中显示监视器 #2 的边界坐标.

try
{
    MonitorGet 2, &Left, &Top, &Right, &Bottom
    MsgBox "Left: " Left " -- Top: " Top " -- Right: " Right " -- Bottom: " Bottom
}
catch
    MsgBox "Monitor 2 doesn't exist or an error occurred."

有关此函数的演示, 请参阅监视器函数页面的示例 #1.


MonitorGetCount - 语法 & 使用 | AutoHotkey v2

MonitorGetCount

返回监视器的数量.

Count := MonitorGetCount()

参数

此函数没有参数.

返回值

类型: 整数

此函数返回监视器的数量.

备注

与通过 SysGet(80) 检索到的 SM_CMONITORS 系统属性不同, 返回值包括所有监视器, 甚至包括那些不作为桌面的一部分使用的监视器.

相关

SysGet, 监视器函数

示例

有关此函数的演示, 请参阅监视器函数页面的示例 #1.


MonitorGetName - 语法 & 使用 | AutoHotkey v2

MonitorGetName

返回指定监视器的操作系统名称.

Name := MonitorGetName(N)

参数

N

类型: 整数

如果省略, 则使用主监视器. 否则, 请指定监视器编号, 介于 1 和 MonitorGetCount 返回的数字之间.

返回值

类型: 字符串

此函数返回指定监视器的操作系统名称.

错误处理

失败时抛出异常.

相关

SysGet, Monitor 函数

示例

有关此函数的演示, 请参阅监视器函数页面的示例 #1.


MonitorGetPrimary - 语法 & 使用 | AutoHotkey v2

MonitorGetPrimary

返回主监视器的编号.

Primary := MonitorGetPrimary()

参数

此函数没有参数.

返回值

类型: 整数

此函数返回主显示器的编号. 在一个单一监视器系统中, 这将总是 1.

相关

SysGet, 监视器函数

示例

有关此函数的演示, 请参阅监视器函数页面的示例 #1.


MonitorGetWorkArea - 语法 & 使用 | AutoHotkey v2

MonitorGetWorkArea

检查指定的监视器是否存在, 并可选地检索其工作区域的边界坐标.

ActualN := MonitorGetWorkArea(N, &Left, &Top, &Right, &Bottom)

参数

N

类型: 整数

如果省略, 则使用主监视器. 否则, 请指定监视器编号, 介于 1 和 MonitorGetCount 返回的数字之间.

&Left
&Top
&Right
&Bottom

类型: VarRef

用于存储工作区边界坐标(以像素为单位) 的变量的引用.

返回值

类型: 整数

该函数返回显示器编号(与 N 相同, 除非省略了 N).

错误处理

一旦失败, 将抛出异常, 并且不会修改输出变量.

备注

监视器的工作区域不包括任务栏和其他注册桌面工具栏占用的区域.

相关

MonitorGet, SysGet, 监视器函数

示例

有关此函数的演示, 请参阅监视器函数页面的示例 #1.


MouseClick - 语法 & 使用 | AutoHotkey v2

MouseClick

点击或按住鼠标按钮, 或滚动鼠标滚轮. 注意: Click 函数通常更灵活和易于使用.

MouseClick WhichButton, X, Y, ClickCount, Speed, DownOrUp, Relative

参数

WhichButton

类型: 字符串

如果为空或省略, 默认为 Left(鼠标左键). 否则, 指定要单击的按钮或鼠标滚轮的旋转/推入方向.

鼠标按钮: Left, Right, Middle(或这些单词的首字母); X1(第四个按钮) 或 X2(第五个按钮). 例如: MouseClick "X1".

Left 和 Right 分别对应主按钮和次按钮. 如果用户通过系统设置交换按钮, 则按钮的物理位置被交换, 但效果保持不变.

鼠标滚轮: 指定 WheelUp 或 WU 使滚轮向上转动(远离你); 指定 WheelDown(或 WD) 使滚轮向下转动(朝向你). 指定 WheelLeft(或 WL) 或 WheelRight(或 WR) 分别向左或向右滚动滚轮. ClickCount 是转动滚轮的格数.

X, Y

类型: 整数

如果省略, 则使用光标的当前坐标. 否则, 请指定在点击前, 鼠标光标要移动到的 X 和 Y 坐标. 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变了这个设置.

ClickCount

类型: 整数

如果省略, 默认为 1. 否则, 请指定单击鼠标按钮或转动鼠标滚轮的次数.

Speed

类型: 整数

如果省略, 则使用默认速度(由 SetDefaultMouseSpeed 设置, 否则为 2). 否则, 请指定移动鼠标的速度, 介于 0(最快) 和 100(最慢) 之间. 速度为 0 表示鼠标瞬时移动.

对于 SendInput 和 SendPlay 模式会忽略 Speed; 它们会瞬时移动鼠标到目标位置(不过 SetMouseDelay 有适用于 SendPlay 的模式). 要显示鼠标移动轨迹(例如使用脚本向观众进行演示时) -- 请使用 SendEvent "{Click 100 200}" 或 SendMode "Event"(可以和 BlockInput 联合使用).

DownOrUp

类型: 字符串

如果为空或省略, 则每次点击由 "按下" 事件后接着 "弹起" 事件组成. 否则, 请指定以下字母之一:

D: 按下鼠标按钮, 但不释放(即生成按下事件).

U: 释放鼠标按钮(即生成弹起事件).

Relative

类型: 字符串

如果为空或省略, 则将 X 和 Y 坐标作为绝对位置使用. 否则, 请指定下面的字母:

R: 将 X 和 Y 坐标视为距离当前鼠标位置的偏移. 换句话说, 会把光标从当前位置往右移动 X 像素(负值则往左) 且往下移动 Y 像素(负值则往上).

备注

这个函数使用 SendMode 设置的发送方法.

比起 MouseClick, 更推荐使用 Click 函数, 因为它一般更容易使用. 但是, MouseClick 支持 Speed 参数, 而通过 Click 调整移动速度需要使用 SetDefaultMouseSpeed.

要进行 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 模式生成的鼠标事件可以比其他模式适应更大范围的游戏. 此外, 某些应用程序和游戏在鼠标移动过快时可能会跟踪困难. 可以使用 Speed 参数或 SetDefaultMouseSpeed 来降低鼠标的速度(仅对默认的 SendEvent 模式有效).

有些程序不接受鼠标滚轮转动的格数 ClickCount 大于 1 的情况. 对于这些程序, 请参考下面的例子使用 Loop:

Loop 5
    MouseClick "WheelUp"

可以使用 BlockInput 函数防止用户对鼠标的任何物理操作干扰由鼠标函数产生的模拟鼠标事件. 不过, 在 SendInput 和 SendPlay 模式中通常不需要这样做, 因为它们会自动将用户对鼠标的物理操作延迟到发送之后.

在每次鼠标按下事件和鼠标弹起事件后都会有一个自动的延时(不包括在 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  ; 把它转两个位置.
#down::MouseClick "WheelDown",,, 2


MouseClickDrag - 语法 & 使用 | AutoHotkey v2

MouseClickDrag

点击并按住指定的鼠标按钮, 接着移动鼠标到目标坐标, 然后松开该按钮.

MouseClickDrag WhichButton, X1, Y1, X2, Y2 , Speed, Relative

参数

WhichButton

类型: 字符串

如果为空或省略, 则默认为 Left(鼠标左键). 否则, 请指定 Left, Right, Middle(或这些单词的首个字母); X1(第四个按钮) 或 X2(第五个按钮). 例如: MouseClickDrag "X1", 0, 0, 10, 10.

Left 和 Right 分别对应主按钮和次按钮. 如果用户通过系统设置调换了按钮, 按钮的物理位置会被调换, 但效果不变.

X1, Y1

类型: 整数

指定拖动的起始位置的 X 和 Y 坐标(在开始拖动前会移动鼠标到这个坐标). 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变了这个设置.

[v2.0.7+]: 如果同时省略 X1 和 Y1, 则使用鼠标光标的当前位置. 由于一个 bug, X1 和 Y1 在以前的版本中是必需的.

X2, Y2

类型: 整数

拖动的目标位置的 X 和 Y 坐标. 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变了这个设置.

Speed

类型: 整数

如果省略, 则使用默认速度(由 SetDefaultMouseSpeed 设置, 否则为 2). 否则, 请指定移动鼠标的速度, 介于 0(最快) 和 100(最慢) 之间. 速度为 0 表示鼠标瞬时移动.

对于 SendInput 和 SendPlay 模式会忽略 Speed; 它们会瞬时移动鼠标到目标位置(不过 SetMouseDelay 有适用于 SendPlay 的模式). 要显示鼠标移动轨迹(例如使用脚本向观众进行演示时) -- 请使用 SendEvent "{Click 100 200}" 或 SendMode "Event"(可以和 BlockInput 联合使用).

Relative

类型: 字符串

如果为空或省略, 则将 X 和 Y 坐标作为绝对位置使用. 否则, 请指定下面的字母:

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) , 可能无法工作.

某些应用程序和游戏在鼠标移动过快时可能会跟踪困难. 可以使用 Speed 参数或 SetDefaultMouseSpeed 来降低鼠标的速度(仅对默认的 SendEvent 模式有效).

可以使用 BlockInput 函数防止用户对鼠标的任何物理操作干扰由鼠标函数产生的模拟鼠标事件. 不过, 在 SendInput 和 SendPlay 模式中通常不需要这样做, 因为它们会自动将用户对鼠标的物理操作延迟到发送之后.

在每次鼠标按下事件和鼠标弹起事件后都会有一个自动的延时(不包括 SendInput 模式). 此延时同样发生在拖动期间鼠标的移动之后. 使用 SetMouseDelay 可以改变延时的长度.

相关

CoordMode, SendMode, SetDefaultMouseSpeed, SetMouseDelay, Click, MouseClick, MouseGetPos, MouseMove, BlockInput

示例

点击并按住鼠标左键, 将鼠标光标移动到目标坐标, 然后松开按钮.

MouseClickDrag "left", 0, 200, 600, 400

打开微软的画图并画一个小房子.

Run "mspaint.exe"
if !WinWaitActive("ahk_class MSPaintApp",, 2)
    return
MouseClickDrag "L", 150, 450, 150, 350
MouseClickDrag "L", 150, 350, 200, 300
MouseClickDrag "L", 200, 300, 250, 350
MouseClickDrag "L", 250, 350, 150, 350
MouseClickDrag "L", 150, 350, 250, 450
MouseClickDrag "L", 250, 450, 250, 350
MouseClickDrag "L", 250, 350, 150, 450
MouseClickDrag "L", 150, 450, 250, 450


MouseGetPos - 语法 & 使用 | AutoHotkey v2

MouseGetPos

获取鼠标光标的当前位置, 以及它悬停在哪个窗口和控件上.

MouseGetPos &OutputVarX, &OutputVarY, &OutputVarWin, &OutputVarControl, Flag

参数

&OutputVarX, &OutputVarY

类型: VarRef

如果省略, 将不存储对应的值. 否则, 请指定用于存储 X 和 Y 坐标的变量的引用. 获取的坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变为屏幕坐标.

&OutputVarWin

类型: VarRef

如果省略, 将不存储对应的值. 否则, 请指定用来保存鼠标光标下窗口的唯一 ID 号的变量的引用. 如果无法检测到窗口, 则此变量被置空.

即使窗口不处于活动状态, 也能检测到它的信息. 无法检测到隐藏窗口.

&OutputVarControl

类型: VarRef

如果省略, 将不存储对应的值. 否则, 请指定用来保存鼠标光标下控件的类名(ClassNN) 的变量的引用. 如果无法检测到控件, 则此变量被置空.

控件的名称应该总是和 Window Spy 中显示的相同. 即使鼠标光标下的窗口不处于活动状态, 也能检测到其中控件的信息.

Flag

类型: 整数

如果省略, 这意味着函数使用默认方法来确定 OutputVarControl 并存储控件的 ClassNN. 否则, 请指定以下数字的组合(和):

1: 使用更简单的方法来获取 OutputVarControl. 这种方法可以正确获取多文档界面(MDI) 应用程序(例如 SysEdit 或 TextPad) 的活动/顶级子窗口的信息. 不过, 对于其他的情况(例如获取 GroupBox 控件中的控件) 就没有那么准确了.

2: 把控件的 HWND 保存到 OutputVarControl 而不是控件的 ClassNN.

例如, 要使上面两个选项都生效, Flag 参数必须设置为 3(1+2).

备注

如果不需要相应的信息, 则可以省略相应的输出变量.

在具有不同 DPI 设置的多个屏幕的系统上, 由于操作系统 DPI 缩放, 返回的位置和大小可能与预期不同.

相关

CoordMode, 窗口函数, SetDefaultMouseSpeed, Click

示例

报告鼠标光标的位置.

MouseGetPos &xpos, &ypos
MsgBox "The cursor is at X" xpos " Y" ypos

显示当前在鼠标光标下窗口的 HWND, 类名, 标题和控件.

SetTimer WatchCursor, 100

WatchCursor()
{
    MouseGetPos , , &id, &control
    ToolTip
    (
        "ahk_id " id "
        ahk_class " WinGetClass(id) "
        " WinGetTitle(id) "
        Control: " control
    )
}


MouseMove - 语法 & 使用 | AutoHotkey v2

MouseMove

移动鼠标光标.

MouseMove X, Y , Speed, Relative

参数

X, Y

类型: 整数

鼠标要移动到的 X 和 Y 坐标. 除非使用 CoordMode 来改变坐标, 否则坐标是相对于活动窗口的的客户端区域.

Speed

类型: 整数

如果省略, 则使用默认速度(由 SetDefaultMouseSpeed 设置, 否则为 2). 否则, 请指定移动鼠标的速度, 介于 0(最快) 和 100(最慢) 之间. 速度为 0 表示鼠标瞬时移动.

对于 SendInput 和 SendPlay 模式会忽略 Speed; 它们会瞬时移动鼠标(不过 SetMouseDelay 有适用于 SendPlay 的模式). 若要在视觉上更缓慢地移动鼠标 -- 如为观众进行演示的脚本 -- 请使用 SendEvent "{Click 100 200}" 或 SendMode Event(可以和 BlockInput 联合使用).

Relative

类型: 字符串

如果为空或省略, 则将 X 和 Y 坐标作为绝对位置使用. 否则, 请指定下面的字母:

R: X 和 Y 坐标将被视为当前鼠标位置的偏移量. 换句话说, 光标将从其当前位置向右移动 X 像素(如果是负数, 则向左), 向下移动 Y 像素(如果是负数, 则向上).

备注

这个函数使用 SendMode 设置的发送方法.

与其他模式相比, SendPlay 模式能够在更多的游戏中成功地生成鼠标事件. 此外, 如果鼠标移动速度过快, 一些应用程序和游戏可能会在跟踪鼠标时出现问题. 可以使用 Speed 参数或 SetDefaultMouseSpeed 来降低速度(仅在默认的 SendEvent 模式下).

可以使用 BlockInput 函数防止用户对鼠标的任何物理操作干扰由鼠标函数产生的模拟鼠标事件. 不过, 在 SendInput 和 SendPlay 模式中通常不需要这样做, 因为它们会自动将用户对鼠标的物理操作延迟到发送之后.

鼠标每次移动后都会有一个自动延迟(除了 SendInput 模式). 使用 SetMouseDelay 来改变延迟的长度.

下面是另一种移动鼠标光标的方法, 在某些多显示器配置中可能效果更好:

DllCall("SetCursorPos", "int", 100, "int", 400)  ; 第一个数字是 X 坐标而第二个是 Y(相对于屏幕).

相关提示, 鼠标光标可以通过隐藏光标示例临时隐藏起来.

相关

CoordMode, SendMode, SetDefaultMouseSpeed, SetMouseDelay, Click, MouseClick, MouseClickDrag, MouseGetPos, BlockInput

示例

移动鼠标光标到新位置.

MouseMove 200, 100

缓慢移动鼠标光标(速度 50 vs. 2) 到距离当前位置右边 20 个像素且在下面 30 个像素的位置.

MouseMove 20, 30, 50, "R"


MsgBox - 语法 & 使用 | AutoHotkey v2

MsgBox

在含有一个或多个按钮(例如 "是" 和 "否") 的小窗口中显示指定的文本.

MsgBox Text, Title, Options
Result := MsgBox(Text, Title, Options)

参数

Text

类型: 字符串

如果省略并且 "OK" 是唯一存在的按钮, 则默认为字符串 "Press OK to continue.". 如果在任何其他情况下省略, 则默认为空字符串. 否则, 指定要在消息框内显示的文本.

可以使用转义序列来表示特殊字符. 例如, `n 表示换行符, 它结束当前行并开始一个新行. 因此, 使用 text1`n`ntext2 会在 text1 和 text2 之间添加一个空行.

如果 Text 较长, 可以通过延续片段的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

Title

类型: 字符串

如果省略, 则默认为 A_ScriptName 的当前值. 否则, 请指定消息框的标题.

Options

类型: 字符串

如果为空或省略, 则默认为 0(只显示 OK 按钮)). 否则, 从下表中指定值的组合(总和) 或一个或多个选项的字符串, 以指示消息框的类型和可能的按钮组合.

此外, 还可以指定以下零个或多个选项:

Owner: 要为消息框指定所有者窗口, 请使用单词 Owner 后接 HWND(窗口 ID).

T: 超时. 如果用户在指定的时间内没有关闭消息框, 要让消息框自动关闭, 请使用字母 T 后接超时秒数, 可以包含小数点. 如果这个值超过 2147483(24.8 天), 将被设置为 2147483. 如果消息框超时, 返回值为单词 Timeout.

Options 参数的值

Options 参数可以是以下组的数字值的组合(和), 这些值直接传递给操作系统的 MessageBox 函数, 也可以是由至少一个空格或制表符分隔的不区分大小写的选项组成的字符串. 字符串中还可以包含一个或多个数字选项.

组 #1: 按钮

若要指定在消息框中显示的按钮, 请添加以下值 之一:

功能 | 十进制 | 十六进制 | 字符串
OK(确认) | 0 | 0x0 | OK 或 O
确认和 Cancel(取消) | 1 | 0x1 | OKCancel, O/C 或 OC
Abort(中止(A)), Retry(重试(R)) 和 Ignore(忽略(I)) | 2 | 0x2 | AbortRetryIgnore, A/R/I 或 ARI
Yes(是(Y)), No(否(N)) 和取消 | 3 | 0x3 | YesNoCancel, Y/N/C 或 YNC
是(Y) 和否(N) | 4 | 0x4 | YesNo, Y/N 或 YN
重试(R) 和取消 | 5 | 0x5 | RetryCancel, R/C 或 RC
取消, Try Again(重试(T)) 和 Continue(继续(N)) | 6 | 0x6 | CancelTryAgainContinue, C/T/C 或 CTC

组 #2: 图标

要在消息框中显示一个图标, 请添加以下值 之一:

功能 | 十进制 | 十六进制 | 字符串
停止/错误图标. | 16 | 0x10 | Iconx
问号图标. | 32 | 0x20 | Icon?
惊叹号图标. | 48 | 0x30 | Icon!
星号图标(信息). | 64 | 0x40 | Iconi

组 #3: 默认按钮

若要指定默认按钮, 请添加以下值 之一:

功能 | 十进制 | 十六进制 | 字符串
使第二个按钮成为默认按钮. | 256 | 0x100 | Default2
使第三个按钮成为默认按钮. | 512 | 0x200 | Default3
使第四个按钮为默认的. 需要存在 Help(帮助) 按钮 | 768 | 0x300 | Default4

组 #4: 模式

若要指定对话框的模式, 请添加以下值 之一:

功能 | 十进制 | 十六进制 | 字符串
系统模式(始终置顶) | 4096 | 0x1000 | N/A
任务模式 | 8192 | 0x2000 | N/A
置顶(WS_EX_TOPMOST 样式) (和系统模式类似, 但省略了标题栏图标) | 262144 | 0x40000 | N/A

组 #5: 其他选项

若要指定其他选项, 请添加以下值中的 一个或多个:

功能 | 十进制 | 十六进制 | 字符串
添加帮助按钮(请参阅下面的备注) | 16384 | 0x4000 | N/A
让文本右对齐显示. | 524288 | 0x80000 | N/A
用于希伯来语/阿拉伯语的从右向左的阅读顺序. | 1048576 | 0x100000 | N/A

返回值

类型: 字符串

该函数返回以下字符串中之一来表示用户按下了哪个按钮:

  • OK
  • Cancel
  • Yes
  • No
  • Abort
  • Retry
  • Ignore
  • TryAgain
  • Continue
  • Timeout(即, 如果消息框超时, 则返回单词 "timeout")

如果对话框无法显示, 返回空字符串. 这通常只发生在 MsgBox 达到限制的情况下, 但也可能是特殊情况.

错误处理

失败时抛出 Error, 如选项无效, 达到 MsgBox 限制, 或由于其他原因无法显示消息框.

备注

消息框通常看起来像这样:

要确定用户按下了哪个按钮, 请使用函数的返回值. 例如:

Result := MsgBox("Would you like to continue? (press Yes or No)",, "YesNo")
if Result = "Yes"
    MsgBox "You pressed Yes."
else
    MsgBox "You pressed No."

if MsgBox("Retry or cancel?",, "R/C") = "Retry"
    MsgBox("You pressed Retry.")

若要自定义按钮的名称, 请参阅Changing MsgBox's Button Names.

注意: 当消息框窗口处于活动状态时, 按下 Ctrl+C 将复制其中的文本到剪贴板. 这适用于所有的消息框, 而不仅是 AutoHotkey 生成的那些.

GUI 窗口当作 MsgBox: 通过使用 OwnDialogs 选项的方法 GUI 窗口可以显示为 modal(模式) 消息框. 模式 消息框在其消失之前会阻止用户与原来的 GUI 窗口进行交互. 此时, 不需要指定上表中的系统模式或任务模式选项.

当 OwnDialogs 选项 无效 时, 任务模式选项(8192) 可用于禁用所有脚本的窗口, 直到用户取消消息框.

如果指定了 OwnerHWND 选项, 它将优先于任何其他设置. HWND 可以是任何窗口的 HWND, 即使不是脚本所拥有的窗口.

帮助按钮: 在 Options 中使用了帮助按钮选项(16384) 时, 只有符合下面两个条件, 那么按下帮助按钮才会有效果:

  1. 消息框是使用 OwnDialogs 选项的方法为 Gui 窗口所有.
  2. 脚本正在监控 WM_HELP 消息(0x0053). 例如: OnMessage(0x0053, "WM_HELP"). 当 WM_HELP 函数被调用时, 可能会通过诸如显示另一个窗口或消息框等方式引导用户.

关闭按钮(在消息框的标题栏): 由于消息框窗口是操作系统内置的特性, 所以它的 X 按钮只有在某些按钮存在时才会被启用. 如果只有一个 OK(确认) 按钮, 点击 X 按钮等同于点击 OK 按钮. 否则, X 按钮将被禁用, 除非有一个取消按钮, 在这种情况下, 点击 X 按钮就等同于按下取消.

最大持续调用数 7: 显示消息框的线程通常可以被中断, 从而允许新线程在前一个调用返回之前显示自己的消息框. 最多允许对 MsgBox 进行 7 次进行中的调用, 任何第 7 次以后的调用都会抛出 Error. 注意, 在中断的线程中, 对 MsgBox 的调用只有在线程恢复后才能返回.

相关

InputBox, FileSelect, DirSelect, ToolTip, Gui 对象

示例

显示一个带有特定文字的信息框. 一种快速简单的信息显示方式. 用户可以按确定按钮关闭信息框并继续执行.

MsgBox "This is a string."

显示一个带有特定文本和标题的消息框.

MsgBox "This MsgBox has a custom title.", "A Custom Title"

显示一个带有默认文本的消息框. 主要用于调试目的, 例如快速设置脚本中的断点.

MsgBox ; "Press OK to continue."

显示一个带有特定文本, 标题和信息图标的消息框. 此外, 延续片段用于更清晰地显示多行文本.

MsgBox "
  (
    第一个参数显示为信息.
    第二个参数成为窗口标题.
    第三个参数决定了消息框的类型.
  )", "Window Title", "iconi"

使用返回值来确定用户在消息框中按了哪个按钮. 注意, 在这种情况下, MsgBox 函数调用必须用括号来指定.

result := MsgBox("Do you want to continue? (Press YES or NO)",, "YesNo")
if (result = "No")
    return

使用 T(超时) 选项, 在一定秒数后自动关闭消息框.

result := MsgBox("This MsgBox will time out in 5 seconds.  Continue?",, "Y/N T5")
if (result = "Timeout")
    MsgBox "You didn't press YES or NO within the 5-second period."
else if (result = "No")
    return

在消息中包含一个变量或子表达式. 另请参阅: 连接

var := 10
MsgBox "The initial value is: " var
MsgBox "The result is: " var * 2
MsgBox Format("The result is: {1}", var * 2)


Number - 语法 & 使用 | AutoHotkey v2

Number

将一个数字字符串转换为一个纯整数或浮点数.

NumValue := Number(Value)

返回值

类型: 整数或浮点数

该函数返回将 Value 转换为纯整数或浮点数的结果, 如果 Value 已经是一个整数或浮点数值, 则返回其本身.

备注

如果该值不能被转换, 则抛出 TypeError.

要确定一个值是否可以转换为一个数字, 请使用 IsNumber 函数.

Number 实际上是一个类, 但可以作为一个函数被调用. Value is Number 可以用来检查一个值是否是一个纯整数.

相关

Type, Float, Integer, String, 值, 表达式, Is 函数


NumGet - 语法 & 使用 | AutoHotkey v2

NumGet

返回存储在指定地址+偏移量处的二进制数.

Number := NumGet(Source, Offset, Type)
Number := NumGet(Source, Type)

参数

Source

类型: 对象或整数

类缓冲对象或内存地址.

可以使用任何实现 Ptr 和 Size 属性的对象, 但此函数针对原生的缓冲对象进行了优化. 传递具有这些属性的对象可以确保函数不会从无效的内存位置读取内存; 否则可能会导致崩溃或其他不可预测的行为.

Offset

类型: 整数

如果为空或省略(或当使用双参数模式时), 默认为 0. 否则, 请指定一个单位为字节的偏移, 将其与 Source 相加, 以确定源地址.

Type

类型: 字符串

下列字符串的其中一个: UInt, Int, Int64, Short, UShort, Char, UChar, Double, Float, Ptr 或 UPtr

不支持 无符号 的 64 位整数, 因为 AutoHotkey 的内置整数类型是 Int64. 因此, 为了处理大于或等于 0x8000000000000000 的数字, 会省略 U 前缀并将任何负数解释为大整数. 例如, -1 在 Int64 中实际上是 0xFFFFFFFFFFFFFFFF(如果期望它为 UInt64). 在 64 位构建中, UPtr 等同于 Int64.

有关详情, 请参阅 DllCall 类型.

返回值

类型: 整数或浮点数

函数返回指定地址+偏移处的二进制数字.

一般说明

如果只使用了两个参数, 第二个参数必须是 Type. 例如, NumGet(var, "int") 是有效的.

如果源地址无效, 则可能抛出异常. 然而, 一些无效的地址无法检测到, 并可能导致不可预知的行为. 传递缓冲对象而不是地址可以确保源地址始终能得到验证.

相关

NumPut, DllCall, Buffer 对象, VarSetStrCapacity


NumPut - 语法 & 使用 | AutoHotkey v2

NumPut

将一个或多个数字以二进制格式存储到指定地址+偏移的位置.

NumPut Type, Number, Type2, Number2, ... Target , Offset

参数

Type

类型: 字符串

下列字符串的其中一个: UInt, UInt64, Int, Int64, Short, UShort, Char, UChar, Double, Float, Ptr 或 UPtr

对于所有整数类型, 或者在传递纯整数时, 有符号与无符号并不影响结果, 因为使用了二进制补码来表示有符号整数.

有关详情, 请参阅 DllCall 类型.

Number

类型: 整数

要保存的数字.

Target

类型: 对象或整数

类缓冲对象, 内存地址.

可以使用任何实现 Ptr 和 Size 属性的对象, 但此函数针对原生的缓冲对象进行了优化. 传递具有这些属性的对象可确保函数不会将内存写入无效位置; 否则可能会导致崩溃或其他不可预测的行为.

Offset

类型: 整数

如果省略, 默认为 0. 否则, 请指定一个单位为字节的偏移, 将其加到 Target 以确定目标地址.

返回值

类型: 整数

函数返回最后写入项目右边的地址. 这在写入一个不连续的数字序列时, 例如在 DllCall 中使用的结构, 某些字段未被设置时, 就可以使用这个函数. 但是, 在许多情况下, 指定多个 Type, Number 对更简单有效. 将地址传回 NumPut 比传给一个更新了 Offset 的类 Buffer 对象更不安全.

一般说明

可以在第一个 Number 之后, 通过重复任意次数的 Type 和 Number 来写入数字序列. 每个数字都写入前一个数字之后的下一个字节, 不带填充. 创建用于 DllCall 的结构时, 请注意, 由于数据对齐要求, 某些字段可能需要添加显式填充.

如果整数太大而无法放入指定的 Type, 那么它的高位会被忽略; 例如 NumPut("Char", 257, buf) 将存储数字 1.

如果目标地址无效, 则可能抛出异常. 但是, 一些无效地址不能被检测到, 并可能导致不可预知的行为. 传递缓冲对象而不是地址可以确保目标地址总是可以得到验证.

相关

NumGet, DllCall, Buffer 对象, VarSetStrCapacity


ObjAddRef / ObjRelease - 语法 & 使用 | AutoHotkey v2

ObjAddRef / ObjRelease

增加或减少对象的引用计数.

NewRefCount := ObjAddRef(Ptr)
NewRefCount := ObjRelease(Ptr)

参数

Ptr

类型: 整数

非托管对象指针或 COM 接口指针.

返回值

类型: 整数

这两个函数返回新的引用计数. 该值应该 仅 用于调试.

相关

引用计数

尽管后面列出的文章讨论了适用于 COM 的引用计数, 但其中也包含了通常也适用于 AutoHotkey 对象的重要概念和规则: IUnknown::AddRef, IUnknown::Release, 引用计数规则.


ObjBindMethod - 语法 & 使用 | AutoHotkey v2

ObjBindMethod

创建一个绑定函数对象, 它能调用指定对象的方法.

BoundFunc := ObjBindMethod(Obj , Method, Params)

参数

Obj

类型: 对象

任意对象.

Method

类型: 字符串

方法名. 如果省略, 绑定函数将调用 Obj 本身.

Params

任意数量的参数.

备注

有关详情和示例, 请参阅绑定函数对象.


Object - 方法 & 属性 | AutoHotkey v2

Object

class Object extends Any

Object(对象) 是派生其他 AutoHotkey 对象类的基本类. Object 的每个实例都由一组 "自有属性" 和一个基对象组成, 可以从基对象中继承更多的属性. Object 也有方法, 但这些只是可以调用的属性.

有值属性和动态属性. 值属性只是包含一个值. 动态属性不包含一个值, 而是根据访问方式(get, set 或 call) 调用一个 访问函数.

下面使用 "Obj" 作为 Object 类的任何实例的占位符.

所有 Object 的实例都基于 Object.Prototype, 而其又基于 Any.Prototype. 除了从 Any 继承的方法和属性外, Object 还具有以下预定义的方法和属性.

目录

  • 静态方法:
    • Call: 创建一个新对象.
  • 方法:
    • Clone: 返回对象的一个浅拷贝.
    • DefineProp: 定义一个新的自有属性.
    • DeleteProp: 删除对象拥有的属性.
    • GetOwnPropDesc: 返回给定自有属性的描述符, 兼容于 DefineProp.
    • HasOwnProp: 如果对象拥有该名称的属性, 则返回 1(true).
    • OwnProps: 枚举一个对象自有的属性.
  • 属性:
    • Base: 检索或设置一个对象的基对象.
  • 函数:
    • ObjSetBase: 设置对象的基对象.
    • ObjGetCapacity, ObjSetCapacity: 检索或设置对象所包含属性的容量.
    • ObjOwnPropCount: 检索对象包含的自有属性的数量.
    • ObjHasOwnProp, ObjOwnProps: 等同于相应的预定义方法, 但不能被覆盖.

静态函数

Call

创建一个新对象.

Obj := Object()
Obj := Object.Call()

方法

Clone

返回对象的一个浅拷贝.

Clone := Obj.Clone()

对象拥有的每个属性或方法都被复制到副本中. 对象 引用 被复制(就像普通的赋值一样), 而不是对象本身; 换句话说, 如果属性包含对对象的引用, 则副本将包含对同一对象的引用.

动态属性被复制, 而不是调用.

副本具有与原始对象相同的基对象.

如果 Obj 派生自不支持的内置类型, 则抛出 TypeError. Clone 的实现支持 Object, Class 和 Error 对象. 另请参阅: Clone (Array), Clone (Map).

DefineProp

定义一个新的自有属性.

Obj := Obj.DefineProp(Name, Descriptor)

参数

Name

类型: 字符串

属性的名称.

Descriptor

类型: Object

具有以下自有属性之一的对象, 或同时具有 Get 和 Set:

Get:: 获取属性值时调用的函数对象.

Set:: 属性被赋值时调用的函数对象. 第二个参数是要分配的值.

Call:: 调用该属性时要调用的函数对象.

Value:: 要赋值该属性的任何值.

返回值

类型: Object

此方法返回目标对象(Obj).

备注

该方法可用于将值属性转换为动态属性, 反之亦然, 但不可能同时指定一个值和访问函数.

如果省略任何一个访问函数, 行为就会从基对象中继承.

  • 一个继承的值属性相当于一组访问函数, 它们返回或调用该值, 或在 this 中存储一个新的值. 注意, 一个新的值将覆盖其在 this 本身中的任何动态属性, 并覆盖任何继承的访问函数.
  • 如果没有定义或继承 Set 或值, 那么试图设置该属性将抛出异常.
  • 如果没有定义或继承 Call, 可以调用 Get 来检索一个函数对象, 然后再调用它.
  • 如果没有定义或继承 Get, 但有一个 Call 访问函数, 那么函数本身就会成为属性的值(只读).

与方法一样, Get, Set 或 Call 的第一个参数是 this(目标对象). 对于 Set, 第二个参数是 value(被分配的值). 这些参数由类中的方法和属性定义自动定义, 但如果使用普通函数, 则必须显式定义. 调用者传递的任何其他参数都会附加到参数列表中.

计算函数对象的 MaxParams 和 IsVariadic 属性, 以确定该属性是否可以接受参数. 如果 Get 的 MaxParams 为 1, 或 Set 的 MaxParams 为 2, 并且 IsVariadic 为 false 或未定义, 则属性不能接受参数; 它们被转发到由 get 返回的对象的 __Item 属性.

DeleteProp

删除对象拥有的属性.

RemovedValue := Obj.DeleteProp(Name)

参数

Name

类型: 字符串

属性名.

返回值

类型: Any

此方法返回删除属性的值(如果没有则为空).

GetOwnPropDesc

返回给定自有属性的描述符, 兼容于 DefineProp.

Descriptor := Obj.GetOwnPropDesc(Name)

参数

Name

类型: 字符串

属性名.

返回值

类型: Object

对于动态属性, 返回值是一个新对象, 其中每个访问函数都有自己的属性: Get, Set, Call. 只有在 Obj 本身定义了相应的访问函数, 每个属性才会存在. 对于值属性, 返回值是一个新对象, 其属性名为 Value. 在这种情况下, Obj.GetOwnPropDesc(Name).Value == Obj.%Name%.

除非调用 DefineProp, 否则修改返回的对象对 Obj 没有影响.

错误处理

如果 Obj 不拥有该名称的属性, 则抛出 PropertyError. 脚本可以通过检查 not desc.HasProp("Value") 来确定一个属性是否是动态的, 其中 desc 是 GetOwnPropDesc 的返回值.

HasOwnProp

如果对象拥有该名称的属性, 则返回 1(true), 否则返回 0(false).

HasOwnProp := Obj.HasOwnProp(Name)

该方法的默认实现也被定义为一个函数: ObjHasOwnProp(Obj, Name).

OwnProps

枚举一个对象自有的属性.

For Name , Value in Obj.OwnProps()

此方法返回一个新的枚举器. 该枚举器通常直接传递给 for-loop, 循环的每次迭代都调用一次枚举器. 每次对枚举器的调用都会返回下一个属性名和/或其值. for-loop 的变量对应于枚举器的参数, 它们是:

Name

类型: 字符串

属性名.

Value

类型: Any

属性的值.

如果该属性具有 getter 方法, 则将调用该方法以获得该值(除非省略 Value).

动态属性包含在枚举中. 但是:

  • 因为只有对象自有的属性才会被枚举, 所以属性必须在 Obj 中直接定义.
  • 如果只指定了第一个变量, 则返回属性的名称, 不调用它的 getter.
  • 如果指定了两个变量, 枚举器会尝试调用属性的 getter 来检索值.
    • 如果 getter 需要参数, 则跳过该属性.
    • 如果 Obj 本身没有为该属性定义 getter, 则跳过.

      注意: 由方法定义定义的属性通常没有 getter, 因此会被跳过.

    • 如果 Obj 是一个类原型对象, 则不应该(在某些情况下不能) 调用 getter; 所以跳过该属性.
    • 如果 getter 抛出异常, 它将被传播(而不是被抑制). 调用者只有在保留了对枚举器的引用的情况下, 才能继续对下一个属性进行枚举(例如, 如果直接将枚举器传递给 for-loop, 则不能继续枚举, 因为在这种情况下, 当 for-loop 中止时, 枚举器会被释放).

要在不调用属性获取器(getters) 的情况下枚举自有的属性, 或者要枚举所有的属性而不考虑类型, 只需向 for-loop 或枚举器传递一个变量. GetOwnPropDesc 可以用来区分值属性和动态属性, 同时还可以检索值或获取器/设置器(setter)/方法.

方法通常被排除在双参数模式的枚举之外, 因为属性的计算通常取决于对象是否有相应的 getter 或值(在同一对象或基对象中). 为了避免在指定两个变量时出现不一致, OwnProps 跳过了只有一个 Call 访问函数的自有属性. 例如:

  • 如果 OwnProps 在没有定义 getter 的情况下返回方法本身, 那么定义 getter 就会阻止该方法被返回. 依靠双变量模式来检索方法的脚本就会缺失一些方法.
  • 如果 OwnProps 在基对象定义了 getter 时返回方法本身, 这将与属性的正常计算结果不一致.

该方法的默认实现也被定义为一个函数: ObjOwnProps(Obj).

属性

Base

检索或设置一个对象的基对象.

CurrentBaseObj := Obj.Base
Obj.Base := NewBaseObj

NewBaseObj 必须是一个对象.

如果给新基赋值会改变对象的原生类型, 则抛出异常. 对象的原生类型由属于内置类的最近原型对象决定, 例如 Object.Prototype 或 Array.Prototype. 例如, Array 的实例必须始终直接或间接地从 Array.Prototype 派生.

属性和方法是从基对象动态继承的, 因此更改对象的基也会更改哪些可用继承的属性和方法.

属性继承于 Any; 但是, 只能为 Object 的实例设置它.

另请参阅: ObjGetBase, ObjSetBase

函数

ObjSetBase

设置一个对象的基对象.

ObjSetBase(Obj, BaseObj)

不调用元-函数或属性函数. 覆盖 Base 属性不会影响此函数的行为.

如果 Obj 或 BaseObj 的类型不正确, 则抛出异常.

另请参阅: ObjGetBase, Base 属性

ObjOwnPropCount

返回对象拥有的属性的数量.

Count := ObjOwnPropCount(Obj)

ObjSetCapacity

设置对象内部自有属性的当前容量.

MaxProps := ObjSetCapacity(Obj, MaxProps)

参数

MaxProps

类型: 整数

新的容量. 如果小于自有属性的当前数量, 则使用该数量, 并释放所有未使用的空间.

返回值

类型: 整数

此函数返回新容量.

错误处理

如果 Obj 的类型不正确, 则抛出异常.

ObjGetCapacity

返回对象内部属性数组的当前容量.

MaxItems := ObjGetCapacity(Obj)

如果 Obj 的类型不正确, 则抛出异常.


OnClipboardChange - 语法 & 使用 | AutoHotkey v2

OnClipboardChange

注册一个每当剪贴板内容发生改变时, 回自动调用的函数.

OnClipboardChange Callback , AddRemove

参数

Callback

类型: 函数对象

要调用的函数.

回调函数接受一个参数, 可以定义如下:

MyCallback(DataType) { ...

虽然你给参数的名称并不重要, 但是它会被赋值为下面的数字之一:

  • 0 = 剪贴板当前为空.
  • 1 = 剪贴板包含可以用文本形式表示的内容(包括从资源管理器窗口复制的文件).
  • 2 = 剪贴板包含完全是非文本的内容, 例如图片.

如果不需要相应的信息, 可以省略回调的参数, 但在这种情况下必须指定星号, 例如 MyCallback(*).

如果这是最近的或仅有的回调, 其返回值会被忽略. 否则, 此回调会返回一个非零整数来阻止随后的回调被调用.

AddRemove

类型: 整数

如果省略, 则默认为 1. 否则, 指定下列数字之一:

  • 1 = 在任何先前的注册回调之后调用该回调.
  • -1 = 在任何先前的注册回调之前调用该回调.
  • 0 = 不调用该回调.

备注

如果剪贴板在回调已经运行时发生更改, 则剪贴板通知事件会丢失. 如果不希望这样, 请使用 Critical. 不过, 这样做也会缓冲/延迟 OnClipboardChange 线程运行时发生的其他线程(例如按下热键).

如果是脚本本身改变了剪贴板内容, 脚本中的回调或标签通常不会立即执行; 也就是说紧接在改变剪贴板语句后面的语句就像提前运行了一样. 要强制立即执行这个回调, 请在改变剪贴板内容后使用短暂的延迟, 例如 Sleep 20.

相关

A_Clipboard, OnExit, OnMessage, CallbackCreate

示例

在每次剪贴板更改时简要显示工具提示.

OnClipboardChange ClipChanged

ClipChanged(DataType) {
    ToolTip "剪贴板数据类型: " DataType
    Sleep 1000
    ToolTip  ; 关闭工具提示.
}


OnError - 语法 & 使用 | AutoHotkey v2

OnError

注册一个当发生未处理错误时, 会自动调用的函数.

OnError Callback , AddRemove

参数

Callback

类型: 函数对象

要调用的函数.

回调接受两个参数, 可以定义如下:

MyCallback(Thrown, Mode) { ...

虽然你给参数的名称并不重要, 但是下面的值会依次赋值给它们:

  1. 抛出的值, 通常为 Error 对象.
  2. 错误的模式: Return, Exit 或 ExitApp. 有关详情, 请参阅下面的表格.

如果不需要相应的信息, 可以从回调参数列表的末尾省略一个或多个参数, 但在这种情况下, 必须指定星号作为最后一个参数, 例如 MyCallback(Param1, *).

回调可以返回以下值之一(其他值是为将来使用而保留的, 应该避免):

  • 0, "" 或没有 Return: 允许错误处理正常进行.
  • 1: 抑制默认错误对话框和任何剩余的错误回调.
  • -1: 同上, 但如果 Mode(第二个参数) 包含单词 Return, 则允许继续执行当前线程.
AddRemove

类型: 整数

如果省略, 则默认为 1. 否则, 指定下列数字之一:

  • 1 = 在所有之前注册的回调之后调用该回调.
  • -1 = 在所有之前注册的回调之前调用该回调.
  • 0 = 不调用该回调.

Error 模式

模式 | 描述
Return | 抛出的值是一个可继续的运行时错误. 如果回调返回 -1, 线程继续; 否则线程退出.
Exit | 抛出的值是一个不可继续的运行时错误或由脚本 thrown 的值. 线程将退出.
ExitApp | 抛出的值是一个严重的运行时错误, 例如由 DllCall 检测到的损坏. 程序将退出.

备注

Callback 只会被调用来处理通常会导致显示错误消息的错误或异常. 加载时的错误无法调用, 因为在加载脚本完毕之前无法调用 OnError.

Callback 在当前线程中被调用, 在线程退出之前(即在调用堆栈展开之前).

相关

Try, Catch, Throw, OnExit

示例

将脚本产生的错误记录到文本文件, 而不是显示给用户.

OnError LogError
i := Integer("cause_error")

LogError(exception, mode) {
    FileAppend "Error on line " exception.Line ": " exception.Message "`n"
        , "errorlog.txt"
    return true
}

使用 OnError 来实现其他错误处理方法. 注意: 当 Try 处于活动状态时, OnError 是无效的.

AccumulateErrors()
{
    local ea := ErrorAccumulator()
    ea.Start()
    return ea
}

class ErrorAccumulator
{
    Errors := []                        ; 累计错误数组.
    _cb := AccumulateError.Bind(this.Errors)
    Start() => OnError(this._cb, -1)    ; 先注册 cb.
    Stop() => OnError(this._cb, 0)      ; 取消注册 cb.
    Last => this.Errors[-1]             ; 最近的错误.
    Count => this.Errors.Length         ; 累计错误的数目.
    __item[i] => this.Errors[i]         ; 索引.
    __delete() => this.Stop()           ; 用于与函数范围绑定.
}

; 这是 OnError 回调. 'errors' 是通过 Bind() 给定的值.
AccumulateError(errors, e, mode)
{
    if mode != "Return" ; 不可继续.
        return
    if e.What = "" ; 表达式缺陷或类似的, 不是内置函数.
        return
    try {
        ; 尝试将错误打印到 stdout.
        FileAppend Format("{1} ({2}) : ({3}) {4}`n", e.File, e.Line, e.What, e.Message), "*"
        if HasProp(e, "extra")
            FileAppend "     Specifically: " e.Extra "`n", "*"
    }
    errors.Push(e)
    return -1 ; 继续.
}

RearrangeWindows()
{
    ; 开始在 'err' 中累积错误.
    local err := AccumulateErrors()

    ; 做一些可能失败的事情...
    MonitorGetWorkArea, &left, &top, &right, &bottom
    width := (right-left)//2, height := bottom-top
    WinMove left, top, width, height, A_ScriptFullPath
    WinMove left+width, top, width, height, "AutoHotkey v2 Help"

    ; 检查是否发生任何错误.
    if err.Count
        MsgBox err.Count " error(s); last error at line #" err.Last.Line
    else
        MsgBox "No errors"

    ; 当变量超出作用域时, Stop 会被自动调用,
    ; 因为只有我们有一个对象的引用. 这将导致 OnError
    ; 被调用来解除回调.
    ; err.Stop()
}

; 调用抑制和累积错误的测试函数.
RearrangeWindows()
; 调用另一个函数来显示恢复正常的错误行为.
WinMove 0, 0, 0, 0, "non-existent window"


OnExit - 语法 & 使用 | AutoHotkey v2

OnExit

注册一个当脚本退出时, 会自动调用的函数.

OnExit Callback , AddRemove

参数

Callback

类型: 函数对象

要调用的函数.

回调函数接受两个参数, 可以定义如下:

MyCallback(ExitReason, ExitCode) { ...

虽然你给参数的名称并不重要, 但是下面的值会依次赋值给它们:

  1. 退出原因(下表中的一个单词).
  2. 传递给 Exit 或 ExitApp 的退出代码.

如果不需要相应的信息, 可以从回调函数的参数列表末尾省略一个或多个参数, 但在这种情况下必须指定星号作为最终的参数, 例如 MyCallback(Param1, *).

回调可以返回一个非零的整数来阻止脚本退出(除了一些罕见的例外), 也不会再调用其他回调. 否则, 脚本将在调用所有注册回调之后退出.

AddRemove

类型: 整数

如果省略, 则默认为 1. 否则, 请指定以下数字之一:

  • 1 = 在所有之前注册的回调之后调用该回调.
  • -1 = 在所有之前注册的回调之前调用该回调.
  • 0 = 不调用该回调.

备注

可以注册任意数量的回调. 回调通常不应该调用 ExitApp, 如果调用了, 脚本将会立即退出.

当脚本以任何方式退出时, 将调用回调(除非被类似 "结束任务" 的方式强行终止). 每当 #SingleInstance 和 Reload 请求前一个实例终止时, 也会调用它.

脚本可以通过 OnMessage(0x0011, On_WM_QUERYENDSESSION) 来检测和是否选择中止系统关闭或注销(有关工作脚本, 请参阅 OnMessage 的示例 #2).

OnExit 线程不遵守 #MaxThreads(它总是在需要的时候启动). 此外, 当它运行时, 它不会被任何线程中断, 包括热键, 自定义菜单项和计时器子程序. 不过, 它会在这些情况下被中断(终止)(且脚本也同时被终止了), 用户从托盘菜单或主菜单栏中选择 Exit, 或由于 Reload 或 #SingleInstance. 而要求脚本终止. 由于这些原因, 回调应该被设计为尽快结束, 除非用户知道正在做什么.

如果 OnExit 线程遇到失败条件, 比如运行错误时, 脚本将会终止.

如果 OnExit 线程是由 Exit 或 ExitApp 启动并指定了退出码, 则将使用该退出码, 除非回调返回 1(true) 阻止退出或调用 ExitApp.

每当进行一个退出尝试时, 每个回调都使用 SendMode 等设置的默认值重新启动. 这些默认值可以在脚本启动段中更改.

退出原因

原因 | 描述
Logoff | 用户正在注销.
Shutdown | 正在关闭或重启系统, 例如使用 Shutdown 函数.
Close | 脚本发送 WM_CLOSE 或 WM_QUIT 消息, 出现致命错误, 或者正在被其他方式关闭. 尽管这些情况都是很少见的, 然而 WM_CLOSE 可能是由于在脚本主窗口使用 WinClose 而引起的. 要关闭(隐藏) 窗口而不终止脚本, 请使用 WinHide. 如果脚本因严重错误或其主窗口被被销毁而退出, 它将在 OnExit 线程完成后无条件终止. 如果主窗口正在被销毁, 它可能仍然存在, 但不能显示. 这个条件可以通过使用 OnMessage 监听 WM_DESTROY 消息来检测.
Error | 在不是持续运行的脚本中发生了运行时错误. 运行时错误的一个例子是 Run/RunWait 无法启动指定的程序或打开指定的文档.
Menu | 用户在主窗口的菜单或标准托盘菜单中选择了 Exit.
Exit | 使用 Exit 或 ExitApp(包括自定义菜单项).
Reload | 正通过 Reload 函数或菜单项重载脚本.
Single | 由于 #SingleInstance 的原因, 脚本正被它自身的新实例代替.

相关

OnError, OnMessage, CallbackCreate, OnClipboardChange, ExitApp, Shutdown, Persistent, 线程, Return

示例

在退出脚本之前询问用户. 要测试它们, 右击托盘图标 然后单击 Exit(退出).

Persistent  ; 阻止脚本自动退出.
OnExit ExitFunc

ExitFunc(ExitReason, ExitCode)
{
    if ExitReason != "Logoff" and ExitReason != "Shutdown"
    {
        Result := MsgBox("Are you sure you want to exit?",, 4)
        if Result = "No"
            return 1  ; 回调必须返回非零值来避免退出.
    }
    ; 不要调用 ExitApp -- 这会阻止其他回调的调用.
}

注册一个在退出时调用的方法.

Persistent  ; 阻止脚本自动退出.
OnExit MyObject.Exiting

class MyObject
{
    static Exiting(*)
    {
        MsgBox "MyObject is cleaning up prior to exiting..."
        /*
        this.SayGoodbye()
        this.CloseNetworkConnections()
        */
    }
}


OnMessage - 语法 & 使用 | AutoHotkey v2

OnMessage

注册一个当脚本接收到指定消息时, 会自动调用的函数.

OnMessage MsgNumber, Callback , MaxThreads

参数

MsgNumber

类型: 整数

需要监听或查询的消息编号, 应该介于 0 和 4294967295(0xFFFFFFFF) 之间. 如果你不想监听系统消息(即编号小于 0x0400 的那些), 那么最好选择一个大于 4096(0x1000) 的数字. 这降低了可能对当前及将来版本的 AutoHotkey 内部所使用的消息的干扰.

Callback

类型: 函数对象

要调用的函数.

回调函数接受四个参数, 可以定义如下:

MyCallback(wParam, lParam, msg, hwnd) { ...

虽然给参数的名称并不重要, 但是下面的值会依次赋值给它们:

  1. 消息的 WPARAM 值.
  2. 消息的 LPARAM 值.
  3. 消息号, 可用在用一个回调监听多个消息时.
  4. 发送消息到的窗口或控件的 HWND(唯一 ID). HWND 可以直接在 WinTitle 参数中使用.

如果不需要相应的信息, 可以从回调参数列表的末尾省略一个或多个参数, 但在这种情况下, 必须指定星号作为最后一个参数, 例如 MyCallback(Param1, *).

WPARAM 和 LPARAM 是无符号的 32 位整数(从 0 到 232-1) 或有符号的 64 位整数(从 -263 到 263-1), 这取决于运行脚本的 exe 程序是 32 位还是 64 位. 对于 32 位的脚本, 如果传入参数预期为有符号整数, 则可以参照下面的这个例子得到负数:

if (A_PtrSize = 4 && wParam > 0x7FFFFFFF)  ; 检查 A_PtrSize 以确保脚本为 32 位.
    wParam := -(~wParam) - 1
MaxThreads

类型: 整数

如果省略, 则默认为 1, 这表示回调一次只能处理一个线程. 这通常是最好的, 因为否则每当监控函数中断时, 脚本就会按时间顺序处理消息. 因此, 作为 MaxThreads 的替代方案, 可以考虑使用 Critical, 如下所示.

如果回调直接或间接导致消息再次被发送, 而该回调仍在运行, 则有必要指定一个大于 1 或小于 -1 的 MaxThreads 值, 以允许回调为了新消息而被调用(如果需要). 脚本自己的进程向自己发送(不是发布) 的消息不能被延迟或缓冲.

指定 0 来取消注册之前由 Callback 标识的回调.

默认情况下, 当为一个 MsgNumber 注册了多个回调时, 会按照注册的顺序调用它们. 要在之前注册的回调之前注册一个回调, 请为 MaxThreads 指定一个负值. 例如, OnMessage Msg, Fn, -2 将 Fn 注册为在之前为 Msg 注册的任何其他回调之前被调用, 并且允许 Fn 最多有 2 个线程. 但是, 如果回调已经被注册了, 除非取消注册然后重新注册, 否则顺序不会改变.

使用

任意数量的回调都可以监视同一个给定的 MsgNumber.

这两行中的任何一行都注册了一个回调, 在先前注册的回调 之后 被调用:

OnMessage MsgNumber, Callback     ; 选项 1 - 省略 MaxThreads
OnMessage MsgNumber, Callback, 1  ; 选项 2 - 指定 MaxThreads 为 1

注册一个回调, 以便在任何先前注册的回调 之前 被调用:

OnMessage MsgNumber, Callback, -1

要取消注册一个回调, 将 MaxThreads 指定为 0:

OnMessage MsgNumber, Callback, 0

Callback 中可获取的额外信息

除了上面接收到的参数外, 回调还可以查询内置变量 A_EventInfo, 如果消息是通过 SendMessage 发送的, 则其为 0. 如果是通过 PostMessage 发送的, 则其为消息发出时的 tick-count 时间.

回调的上次找到的窗口初始与消息发送到的父窗口相同(即使消息是发送到控件的). 如果窗口是隐藏的, 但不是 GUI 窗口(例如脚本的主窗口), 在使用它之前打开 DetectHiddenWindows. 例如:

DetectHiddenWindows True
MsgParentWindow := WinExist()  ; 这里保存了消息发送的目标窗口的唯一 ID.

Callback 应该返回什么

如果回调使用不带任何参数的 Return, 或指定空值如 ""(甚至没有使用 Return), 则当此回调结束时, 传入的消息将继续被正常处理. 同样的情况也会出现在使用 Exit 回调或者出现了运行时错误的时候(例如, 运行不存在的文件). 与此相反, 返回一个整数时会被作为回复立即发送; 即程序不会再进一步处理此消息. 例如, 监听 WM_LBUTTONDOWN(0x0201) 的回调可以返回一个整数来阻止目标窗口接收到鼠标点击的通知. 在许多情况下(例如使用 PostMessage 发送的消息), 返回哪个整数并不重要; 不过如果不确定, 0 通常是最安全的.

有效返回值的范围取决于运行脚本的 exe 文件是 32 位还是 64 位. 对于 32 位(A_PtrSize = 4) 脚本, 非空的返回值必须在 -231 和 232-1 之间, 对于 64 位(A_PtrSize = 8) 脚本, 必须在 -263 和 263-1 之间.

如果有多个回调一个给定的消息号, 它们会被逐一调用, 直到其中一个回调返回一个非空值.

备注

与普通的函数调用不同, 当一个被监听的消息到达时, 回调会作为一个新的线程被调用. 因此, 回调会以设置的默认值启动, 例如 SendMode 和 DetectHiddenWindows. 这个默认设置可以通过在脚本启动中使用此函数来改变.

Send(发送)(而不是 Post) 到控件的消息不会被监听, 因为系统直接把它们发送给后台的控件了. 对于系统生成的消息来说, 这很少是一个问题, 因为大多数信息都是 Post 的.

如果脚本要在空闲状态下保持运行, 以监测传入的消息, 可能需要调用 Persistent 函数来防止脚本退出. OnMessage 不会自动使脚本持续运行, 因为这有时是不必要的或不需要的. 例如, 当 OnMessage 被用来监视 GUI 窗口的输入时(如在 WM_LBUTTONDOWN 的例子), 通常让脚本在最后一个 GUI 窗口关闭时自动退出更为合适.

当一个消息达到时, 如果其回调由于之前到达的相同消息而仍在运行, 默认情况下, 该回调将不会被再次调用; 相反, 该消息将被视为不受监控. 如果不希望这样, 有多种方法可以避免它:

  • 如果消息是 post 的, 而不是 sent 的, 并且其编号大于 0x0311, 那么可以通过指定 Critical 作为回调的第一行来缓冲, 直到其回调完成. 另外, Thread Interrupt 也可以达到同样的效果, 只要它持续的时间足够长能让回调完成.
  • 使用 Critical 来增加消息检查间隔, 可以让回调在任何消息被派发之前有更多的时间来完成. 为了保证可靠性, 可能需要一个大于 16 的间隔时间. 由于系统定时器的粒度(通常为 15.6 毫秒), 非-Critical 线程默认的间隔(5 毫秒) 可能会在回调启动后的瞬间出现.
  • 确保回调快速返回, 可以减少因 MaxThreads. 而错过消息的风险. 一种方法是让它通过向自己的脚本 post 大于 0x0311 的监控消息, 让它在未来的线程中排队. 该消息的回调应该使用 Critical 作为其第一行, 以确保其消息被缓冲. 另外, 也可以用一个计时器来在未来的线程中排队.
  • 为 MaxThreads 参数指定一个较高的值, 可以使回调被中断以处理新收到的消息.

如果在脚本不可中断的情况下, Post 一条数值大于 0x0311 的监控信息, 那么这条信息就会被缓冲; 也就是说, 在脚本变得可中断之前, 它的回调不会被调用. 然而, sent 而不是 posted 的消息不能被缓冲, 因为它们必须提供一个返回值. Post 的消息也可能不被缓冲, 当一个模式消息循环在运行时, 如系统对话框, ListView 拖放操作或菜单.

如果一个被监控的消息到达并且没有被缓冲, 那么它的回调会被立即调用, 即使在收到消息的时候线程是不可中断的.

OnMessage 的优先级总是为 0. 因此, 如果当前线程的优先级大于 0 时将不会监听或缓冲任何消息.

监听系统消息(小于 0x0400 的那些) 时应多加小心. 例如, 如果回调不会快速结束, 那么对消息的响应时间可能比系统预期的要长, 这可能会导致一些副作用. 如果回调返回一个整数来抑制对消息的进一步处理, 但系统期望不同的处理或响应方式时, 可能会发生不想要的行为.

当脚本显示系统对话框时(例如 MsgBox), 则不会监听到任何投递(Post) 到控件的消息. 例如, 如果脚本正显示消息框而用户点击一个 GUI 窗口上的按钮, 则 WM_LBUTTONDOWN 消息会被直接发送到按钮而不会调用监听函数.

尽管外部程序可以使用 PostThreadMessage() 或其他 API 调用直接投递(Post) 消息给脚本的线程, 但不建议这么做, 因为如果此时脚本正显示系统窗口(例如 消息框) . 则消息会丢失. 相反, 通常最好投递或发送(Send) 消息到脚本的主窗口或其中的某个 GUI 窗口.

相关

CallbackCreate, OnExit, OnClipboardChange, PostMessage, SendMessage, 函数, Windows 消息, 线程, Critical, DllCall

示例

监听在 GUI 窗口中的鼠标点击. 相关主题: ContextMenu 事件

MyGui := Gui(, "Example Window")
MyGui.Add("Text",, "Click anywhere in this window.")
MyGui.Add("Edit", "w200")
MyGui.Show()
OnMessage 0x0201, WM_LBUTTONDOWN

WM_LBUTTONDOWN(wParam, lParam, msg, hwnd)
{
    X := lParam & 0xFFFF
    Y := lParam >> 16
    Control := ""
    thisGui := GuiFromHwnd(hwnd)
    thisGuiControl := GuiCtrlFromHwnd(hwnd)
    if thisGuiControl
    {
        thisGui := thisGuiControl.Gui
        Control := "`n(in control " . thisGuiControl.ClassNN . ")"
    }
    ToolTip "You left-clicked in Gui window '" thisGui.Title "' at client coordinates " X "x" Y "." Control
}

检测系统的关机/注销动作并允许您中止它. 在 Windows Vista 及更高的版本中, 系统会显示一个用户界面, 显示哪个程序正在阻止关机/注销, 并允许用户强制关机/注销. 在较旧的操作系统上, 脚本显示一个确认提示. 相关主题: OnExit

; 下面的 DllCall 是可选的: 它告诉操作系统首先要关闭此脚本(在其他所有程序之前).
DllCall("kernel32.dll\SetProcessShutdownParameters", "UInt", 0x4FF, "UInt", 0)
OnMessage(0x0011, On_WM_QUERYENDSESSION)
Persistent

On_WM_QUERYENDSESSION(wParam, lParam, *)
{
    ENDSESSION_LOGOFF := 0x80000000
    if (lParam & ENDSESSION_LOGOFF)  ; 用户正在注销.
        EventType := "Logoff"
    else  ; 系统正在关机或重启.
        EventType := "Shutdown"
    try
    {
        ; 设置显示操作系统关闭 UI 的提示. 我们不会显示自己的确认提示
        ; 因为我们只有 5 秒钟的时间, 操作系统会显示关机 UI
        ; 同样, 没有可见窗口的程序在没有提供原因的情况下无法阻止关机.
        BlockShutdown("Example script attempting to prevent " EventType ".")
        return false
    }
    catch
    {
        ; ShutdownBlockReasonCreate 不可用,
        ; 所以这可能是 Windows XP, 2003 或 2000, 我们实际上可以防止关机.
        Result := MsgBox(EventType " in progress. Allow it?",, "YN")
        if (Result = "Yes")
            return true  ; 通知操作系统允许关机/注销操作继续.
        else
            return false  ; 通知操作系统中止关机/注销操作.
    }
}

BlockShutdown(Reason)
{
    ; 如果您的脚本具有可见的 GUI, 请使用它代替 A_ScriptHwnd.
    DllCall("ShutdownBlockReasonCreate", "ptr", A_ScriptHwnd, "wstr", Reason)
    OnExit StopBlockingShutdown
}

StopBlockingShutdown(*)
{
    OnExit StopBlockingShutdown, 0
    DllCall("ShutdownBlockReasonDestroy", "ptr", A_ScriptHwnd)
}

接收其他脚本或程序的自定义消息和最多两个数字(要发送字符串而不是数字, 请参阅下一个示例).

OnMessage 0x5555, MsgMonitor
Persistent

MsgMonitor(wParam, lParam, msg, *)
{
    ; 由于尽快返回常常很重要, 所以最好使用 ToolTip 而不是
    ; 类似 MsgBox 的进行显示, 以避免阻止回调结束:
    ToolTip "Message " msg " arrived:`nWPARAM: " wParam "`nLPARAM: " lParam
}

; 下面的代码可用于其他脚本内来激发运行上面脚本中的回调:
SetTitleMatchMode 2
DetectHiddenWindows True
if WinExist("Name of Receiving Script.ahk ahk_class AutoHotkey")
    PostMessage 0x5555, 11, 22  ; 因为上面的 WinExist, 所以消息被发送到 "上次找到的窗口".
DetectHiddenWindows False  ; 必须在 PostMessage 之后才能关闭.

从一个脚本发送任意长度的字符串到另一个脚本. 要使用它, 请保存并运行下面的两个脚本, 然后按下 Win+Space 来显示输入框来让您输入字符串. 两个脚本必须使用相同的原生编码.

保存下面的脚本为 Receiver.ahk, 然后运行它:

#SingleInstance
OnMessage 0x004A, Receive_WM_COPYDATA  ; 0x004A is WM_COPYDATA
Persistent

Receive_WM_COPYDATA(wParam, lParam, msg, hwnd)
{
    StringAddress := NumGet(lParam, 2*A_PtrSize, "Ptr")  ; 检索 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 热键. 按下此热键会显示输入框用于输入消息字符串.
{
    ib := InputBox("Enter some text to Send:", "Send text via WM_COPYDATA")
    if ib.Result = "Cancel"  ; 用户按下了取消按钮.
        return
    result := Send_WM_COPYDATA(ib.Value, TargetScriptTitle)
    if result = ""
        MsgBox "SendMessage failed or timed out. 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."
}

Send_WM_COPYDATA(StringToSend, TargetScriptTitle)
; 此函数发送指定的字符串到指定的窗口然后返回收到的回复.
; 如果目标窗口处理了消息则回复为 1, 而消息被忽略了则为 0.
{
    CopyDataStruct := Buffer(3*A_PtrSize)  ; 分配结构的内存区域.
    ; 首先设置结构的 cbData 成员为字符串的大小, 包括它的零终止符:
    SizeInBytes := (StrLen(StringToSend) + 1) * 2
    NumPut( "Ptr", SizeInBytes  ; 操作系统要求这个需要完成.
          , "Ptr", StrPtr(StringToSend)  ; 设置 lpData 为到字符串自身的指针.
          , CopyDataStruct, A_PtrSize)
    Prev_DetectHiddenWindows := A_DetectHiddenWindows
    Prev_TitleMatchMode := A_TitleMatchMode
    DetectHiddenWindows True
    SetTitleMatchMode 2
    TimeOutTime := 4000  ; 可选的. 等待 receiver.ahk 响应的毫秒数. 默认是 5000
    ; 必须使用发送 SendMessage 而不是投递 PostMessage.
    RetValue := SendMessage(0x4a, 0, CopyDataStruct,, TargetScriptTitle,,,, TimeOutTime) ; 0x4a 是 WM_COPYDATA.
    DetectHiddenWindows Prev_DetectHiddenWindows  ; 恢复调用者原来的设置.
    SetTitleMatchMode Prev_TitleMatchMode         ; 同样.
    return RetValue  ; 返回 SendMessage 的回复给我们的调用者.
}

有关如何使用 OnMessage 来接收网络连接上数据到达时的通知的演示, 请参阅 WinLIRC 客户端脚本.


Ord - 语法 & 使用 | AutoHotkey v2

Ord

返回指定字符串中首个字符的序号值(数字字符编码).

Number := Ord(String)

参数

String

类型: 字符串

检索序号值的字符串.

返回值

类型: 整数

此函数返回 String 的序列编号, 或者如果 String 为空, 则返回 0. 如果 String 以 Unicode 补充字符开头, 本函数将返回对应的 Unicode 字符编码(一个介于 0x10000 到 0x10FFFF 之间的数字). 其他情况下返回的值介于 0 到 255(ANSI), 或 0 到 0xFFFF(Unicode). 有关详情, 请参阅 Unicode vs ANSI.

相关

Chr

示例

下面两个弹窗都显示 116, 因为只检测第一个字符.

MsgBox Ord("t")
MsgBox Ord("test")


OutputDebug - 语法 & 使用 | AutoHotkey v2

OutputDebug

发送字符串到调试器(如果有) 显示出来.

OutputDebug Text

参数

Text

类型: 字符串

要发送到调试器中显示的文本. 文本可以包含换行符(`n) 来开始新行. 此外, 一个长行可以使用延续片段的方法分成较短的几行.

备注

如果脚本的进程没有附加调试器, 那么系统调试器会显示此字符串. 如果系统调试器未激活, 则此命令没有效果.

调试器的一个例子是 DebugView, 它是免费的并可从 microsoft.com 获取.

另请参阅: 其他调试方法

相关

FileAppend, 延续片段

示例

发送一个字符串到调试器(如果有的话) 进行显示.

OutputDebug A_Now ': Because the window "' TargetWindowTitle '" did not exist, the process was aborted.'


Pause - 语法 & 使用 | AutoHotkey v2

Pause

暂停脚本的当前线程或设置底层线程的暂停状态.

Pause UnderlyingThreadState

参数

UnderlyingThreadState

类型: 整数

如果省略, 暂停当前线程. 否则, 请指定以下值之一:

1 或 True: 将底层线程标记为暂停. 当前线程不会暂停并继续运行. 当前线程结束后, 底层线程会恢复在底层线程运行时任何中断的函数. 一旦底层线程完成函数(如果有), 就会进入暂停状态. 如果当前线程下面没有线程, 脚本本身就会被暂停, 这将阻止计时器运行(这个效果与脚本没有线程时使用菜单项 "Pause Script" 的效果一样).

0 或 False: 取消底层线程的暂停.

-1: 切换底层线程的暂停状态.

备注

默认情况下, 脚本也可以通过它的托盘图标或主窗口来暂停.

与 Suspend 禁用热键和热字串不同, 开启暂停状态会冻结线程(如果省略了 UnderlyingThreadState, 则冻结当前线程, 否则冻结底层线程). 副作用是, 在它下面的任何被中断线程都将处于休眠状态, 直到当前线程取消暂停并结束.

暂停任意线程或脚本本身后, 计时器不会运行. 与之相比, 显式启动的线程(如 热键和菜单项) 仍然可以运行; 但当它们的线程结束时, 底层线程仍会被暂停. 换句话说, 每个线程都能独立于其他线程被暂停.

每当脚本的当前线程处于暂停状态时, 托盘图标变为 a green icon with a Pause symbol (或为 a green icon with a transparent Pause symbol, 如果脚本同时也被挂起). 可以通过冻结图标来避免图标更改, 这通过使用 TraySetIcon(,, true) 来实现.

要禁用计时器而不暂停脚本, 请使用 Thread NoTimers.

当脚本显示任意类型的菜单(托盘菜单, 菜单栏, GUI 上下文菜单, 等) 时, 脚本总是处于停顿状态(虽然不是正式地暂停).

如果紧挨着当前线程的线程被暂停, 则内置变量 A_IsPaused 包含 1, 否则为 0.

相关

Suspend, Menu 对象, ExitApp, 线程, SetTimer

示例

使用 Pause 来停止脚本, 比如检查变量.

ListVars
Pause
ExitApp ; 这一行将不会被执行, 直到用户取消暂停脚本为止.

按一次热键可暂停脚本. 再按一次即可取消暂停.

Pause::Pause -1  ; Pause/Break 键.
#p::Pause -1  ; Win+P

发送 Pause 函数到另一个脚本.

DetectHiddenWindows True
WM_COMMAND := 0x111
ID_FILE_PAUSE := 65403
PostMessage WM_COMMAND, ID_FILE_PAUSE,,, "C:\YourScript.ahk ahk_class AutoHotkey"


Persistent - 语法 & 使用 | AutoHotkey v2

Persistent

防止脚本在最后一个线程完成后自动退出, 允许它在空闲状态下运行.

Persistent Persist

参数

Persist

类型: 布尔值

如果省略, 则默认为 true.

如果为 true, 在所有线程退出后, 脚本将继续保持运行, 即使没有满足保持脚本运行的其他条件.

如果为 false, 则恢复默认行为.

返回值

类型: 整数(布尔值)

此函数返回先前的设置; 0(false) 或 1(true).

备注

如果 Persistent 没有使用, 则默认设置为 0(false).

如果脚本是 持续运行的, 它将在启动完成和所有其他线程退出后继续运行. 通常没有必要调用这个函数, 因为在用户希望脚本持续运行的大多数常见情况下脚本都是自动持续运行的, 比如响应热键, 执行计时器或者显示 GUI.

在某些情况下可能需要此函数(如果它打算在没有运行的线程或热键, 计时器, 等时保持运行) 包括:

  • 使用 OnMessage 或 CallbackCreate 和 DllCall 来响应事件的脚本, 因为这些函数不会使脚本持续运行.
  • 通过选择一个自定义托盘菜单项来执行的脚本.
  • 创建或检索 COM 对象并使用 ComObjConnect 来响应对象的事件的脚本.

如果将此函数添加到现有脚本中, 则可能需要将部分或全部出现的 Exit 更改为 ExitApp. 这是因为 Exit 不会终止持续运行的脚本; 它仅终止当前线程.

相关

Exit, ExitApp

示例

防止脚本自动退出.

; 这个脚本不会自动退出, 即使它没有任何事情要做.
; 但是, 你可以使用它的托盘图标在编辑器中打开脚本,
; 或启动 Window Spy 或帮助文件.
Persistent


PixelGetColor - 语法 & 使用 | AutoHotkey v2

PixelGetColor

获取指定的 X 和 Y 坐标处像素的颜色.

Color := PixelGetColor(X, Y , Mode)

参数

X, Y

类型: 整数

目标像素的 X 和 Y 坐标. 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变了这个设置.

Mode

类型: 字符串

如果为空或省略, the pixel is retrieved using the normal method. 否则, 请指定 one个或多个下列单词. 如果含有多个单词, 则它们之间使用空格分隔(例如 "Alt Slow").

Alt: 使用另一种方法获取颜色, 当在特殊类型的窗口中正常的方法获取到无效或错误的颜色时, 应考虑使用这种方法. 此方法比正常方法大约慢 10%.

Slow: 使用一种更精细复杂的方法获取颜色, 在某些全屏应用程序中其他方法失败时, 此方法可能有效. 此方法比正常方法大约慢三倍. 注: Slow 方法优先于 Alt, 所以此时不需要指定 Alt.

返回值

类型: 字符串

该函数返回一个十六进制数字字符串, 代表像素的 RGB(红-绿-蓝) 颜色. 例如, 紫色被定义为 0x800080, 因为它的红色和蓝色分量的强度为 0x80(128) 而绿色分量的强度为 0x00(0).

错误处理

在失败时抛出 OSError.

备注

像素必须是可见的; 换句话说, 无法获取隐藏在其他窗口背后的窗口的像素颜色. 与之相比, 鼠标光标下方的像素颜色通常可以检测出来. 例外情况是游戏的指针, 在大多数情况下它会遮挡其下方的任何像素.

使用 Window Spy(从托盘图标菜单打开) 或参阅本页底部的示例可以确定当前屏幕上的颜色.

已知限制:

  • 在部分透明或其中某种颜色透明(WinSetTransColor) 的窗口中实际获取的是它后面窗口的颜色而不是它自己的颜色(即我们在屏幕上看到的颜色.
  • 在某些应用程序中 PixelGetColor 可能得不到准确的结果. 如果发生这种情况, 请尝试在最后一个参数中指定单词 Alt 或 Slow.

相关

PixelSearch, ImageSearch, CoordMode, MouseGetPos

示例

按下热键显示位于鼠标光标当前位置的像素的颜色.

^!z::  ; Control+Alt+Z 热键.
{
    MouseGetPos &MouseX, &MouseY
    MsgBox "The color at the current cursor position is " PixelGetColor(MouseX, MouseY)
}


PixelSearch - 语法 & 使用 | AutoHotkey v2

PixelSearch

在屏幕某个区域中搜索指定颜色所在的像素.

PixelSearch &OutputVarX, &OutputVarY, X1, Y1, X2, Y2, ColorID , Variation

参数

&OutputVarX, &OutputVarY

类型: VarRef

存储与 ColorID 匹配的第一个像素的 X 和 Y 坐标的变量的引用(如果没有找到匹配的像素, 则变量为空). 除非使用 CoordMode 来改变坐标, 否则坐标是相对于活动窗口的客户端区域.

X1, Y1

类型: 整数

要搜索的矩形区域的起始角的 X 和 Y 坐标. 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变了这个设置.

X2, Y2

类型: 整数

搜索的矩形区域的结束角的 X 和 Y 坐标. 坐标相对于活动窗口的客户端区域, 除非曾使用 CoordMode 改变了这个设置.

ColorID

类型: 整数

要搜索的颜色 ID. 通常用红绿蓝(RGB) 格式的十六进制数表示. 例如: 0x9d6346. 颜色 ID 可以通过 Window Spy(可从托盘菜单访问) 或 PixelGetColor 来确定.

Variation

类型: 整数

如果省略, 默认为 0. 否则, 请指定一个介于 0 和 255(包含) 之间的数字, 用于表示每个像素颜色红/绿/蓝通道强度在任一方向上允许的渐变值. 例如, 如果指定值为 2 并且 ColorID 为 0x444444, 那么从 0x424242 到 0x464646 的任何颜色都将被视为匹配. 此参数用于需要寻找的颜色渐变值可能变化时. 如果指定 255 为浮动的渐变值, 则匹配所有颜色.

返回值

类型: 整数(布尔值)

如果在指定的区域内找到了指定颜色, 该函数返回 1(true), 如果没有找到, 则返回 0(false).

错误处理

如果有问题导致函数无法进行搜索, 则抛出 OSError.

备注

要搜索的区域必须是可见的; 换句话说, 不可能搜索隐藏在另一个窗口后面的窗口区域. 相比之下, 鼠标光标下方的像素通常可以被检测到. 游戏光标是个例外, 在大多数情况下, 游戏中的光标会遮挡其下方的任何像素.

虽然支持低至 8 位(256-色) 的颜色深度, 但 PixelSearch 在 24 位或 32 位颜色中的表现要好得多.

搜索从 X1 和 Y1 指定的坐标开始, 并检查 X1 到 X2 这一行的所有像素是否匹配. 如果在那里没有找到匹配的像素, 则继续向 Y2 逐行搜索, 直到找到匹配的像素.

搜索顺序取决于参数的顺序. 换句话说, 如果 X1 大于 X2, 搜索将从右到左, 从 X1 列开始. 同样, 如果 Y1 大于 Y2, 则将从下往上搜索.

如果要搜索的区域比较大而且搜索频率比较高, 可能会消耗大量的 CPU 时间. 为了缓解这种情况, 要尽量减少区域的大小.

相关

PixelGetColor, ImageSearch, CoordMode, MouseGetPos

示例

在活动窗口的区域中搜索一个像素, 并在 Px 和 Py 中存储与指定颜色相匹配(渐变值为 3) 第 1 个像素的 X 和 Y 坐标.

if PixelSearch(&Px, &Py, 200, 200, 300, 300, 0x9d6346, 3)
    MsgBox "A color within 3 shades of variation was found at X" Px " Y" Py
else
    MsgBox "That color was not found in the specified region."


PostMessage - 语法 & 使用 | AutoHotkey v2

PostMessage

将消息放入窗口或控件的消息队列中.

PostMessage MsgNumber , wParam, lParam, Control, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

MsgNumber

类型: 整数

要发送的消息的编号. 请参阅消息列表来确定编号.

wParam, lParam

类型: 整数

如果省略其中一个, 则发送 0. 否则, 请指定消息的第一个和第二个组件.

每个参数必须是整数.

如果 AutoHotkey 或目标窗口是 32 位的, 则只使用参数的低 32 位; 也就是说, 如果超出了有符号值的范围 -2147483648 到 2147483647(-0x80000000 to 0x7FFFFFFF), 或者超出了无符号值的范围 0 到 4294967295(0xFFFFFFFF), 则值会被截断. 如果 AutoHotkey 和目标窗口都是 64 位的, 可以使用 AutoHotkey 所支持的任何整数值.

Control

类型: 字符串, 整数或对象

如果省略, 则消息会被直接发送到目标窗口而不是它的某个控件. 否则, 指定为控件的 ClassNN, 文本或 HWND, 或者是一个具有 Hwnd 属性的对象. 有关详情, 请参阅控件参数.

如果这个参数指定了一个 HWND(作为一个整数或对象), 那么它不需要是一个控件(子窗口) 的 HWND. 也就是说, 它也可以是一个顶层窗口的 HWND.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果消息不能被投递, 则抛出 OSError. 如果目标窗口运行在比脚本更高的完整性级别上(例如, 它以管理员身份运行, 而脚本不是), 消息可能被阻止.

备注

应该小心使用该函数, 因为发送消息到错误的窗口(或发送错误的消息) 可能导致意外的行为或者甚至让目标应用程序崩溃. 这是因为大多数应用程序并不是设计用于从外部来源中接受某些类型的消息.

PostMessage 将消息放入与目标窗口相关联的消息队列中, 它不会等待确认或回复. 相比之下, SendMessage 会等待目标窗口处理消息, 直到超时期结束.

与 SendMessage 不同, PostMessage 通常只发送数值, 而不是结构或字符串的指针.

要发送消息到系统中的所有窗口, 包括隐藏或禁用的那些, 请在 WinTitle 中指定 0xFFFF(0xFFFF 是 HWND_BROADCAST). 这种技术应该只用于目标为广播的消息.

要让脚本接收消息, 请使用 OnMessage.

请参阅消息指南来查看使用这些命令的介绍.

相关

SendMessage, 消息列表, 消息指导, OnMessage, Automating Winamp, DllCall, ControlSend, MenuSelect

示例

切换活动窗口的键盘布局/语言为英语(US).

PostMessage 0x0050, 0, 0x4090409,, "A"  ; 0x0050 is WM_INPUTLANGCHANGEREQUEST.


进程函数列表 | AutoHotkey v2

进程函数

用于检索信息, 或对进程执行各种操作的函数. 单击函数名查看详细信息.

函数 | 描述
ProcessClose | 强制关闭第一个匹配的进程.
ProcessExist | 检查指定的进程是否存在.
ProcessGetName | 返回指定进程的名称.
ProcessGetParent | 返回创建指定进程的进程 ID(PID).
ProcessGetPath | 返回指定进程的路径.
ProcessSetPriority | 更改第一个匹配进程的优先级.
ProcessWait | 等待指定的进程存在.
ProcessWaitClose | 等待匹配进程关闭.

备注

进程列表: 虽然没有 ProcessList 函数, 但示例 #1 和示例 #2 演示了如何通过 DllCall 或 COM 检索进程.

相关

Run, WinClose, WinKill, WinWait, WinWaitClose, WinExist, 窗口函数

示例

显示一个通过 DllCall 获取的正在运行的进程列表.

d := "  |  "  ; 字符串分隔符
s := 4096  ; 缓冲和数组的大小(4 KB)

ScriptPID := ProcessExist()  ; 正在运行脚本的 PID.
; 使用 PROCESS_QUERY_INFORMATION(0x0400) 获取此脚本的句柄:
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ScriptPID, "Ptr")
; 打开此进程的可调整的访问令牌(TOKEN_ADJUST_PRIVILEGES = 32):
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", &t := 0)
; 获取调试特权的本地唯一标识符:
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", &luid := 0)
ti := Buffer(16, 0)  ; 特权结构
NumPut( "UInt", 1  ; 特权数组中的一个条目...
      , "Int64", luid
      , "UInt", 2  ; 启用这个特权: SE_PRIVILEGE_ENABLED = 2
      , ti)
; 使用新的访问令牌更新此进程的特权:
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")  ; 通过预加载来提升性能.
a := Buffer(s)  ; 接收进程列表标识符的数组:
c := 0  ; 用于进程标识符的计数器
l := ""
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
    n := Buffer(s, 0)  ; 接收模块基础名称的缓冲:
    e := DllCall("Psapi.dll\GetModuleBaseName", "Ptr", h, "Ptr", 0, "Ptr", n, "UInt", s//2)
    if !e    ; 用于 64 位进程在 32 位模式时的回退方法:
        e := DllCall("Psapi.dll\GetProcessImageFileName", "Ptr", h, "Ptr", n, "UInt", s//2)
    SplitPath StrGet(n), &n
    DllCall("CloseHandle", "Ptr", h)  ; 关闭进程句柄以节约内存
    if (n && e)  ; 如果映像不是空的, 则添加到列表:
        l .= n "`n", c++
}
DllCall("FreeLibrary", "Ptr", hModule)  ; 卸载库来释放内存.
;l := Sort(l)  ; 取消注释这行来按字母顺序对列表进行排序.
MsgBox StrReplace(l, "`n", d), c " Processes", 0

显示使用 COM 和 Win32_Process 获取的正在运行的进程列表.

MyGui := Gui(, "Process List")
LV := MyGui.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)
MyGui.Show()


ProcessClose - 语法 & 使用 | AutoHotkey v2

ProcessClose

强制关闭第一个匹配的进程.

PID := ProcessClose(PIDOrName)

参数

PIDOrName

类型: 整数或字符串

指定数字(PID) 或进程名:

PID: 进程 ID, 唯一标识一个特定进程的数字(只有在此进程的生存期这个数字才有意义). 新运行的进程的 PID 可以通过 Run 函数获取. 同样的, 窗口的 PID 可以通过 WinGetPID 获取. ProcessExist 也可以用来获取 PID.

Name: 进程的名称, 通常和它的可执行文件名相同(不带路径), 例如 notepad.exe 或 winword.exe. 由于一个名称可能与多个正在运行的进程匹配, 因此将仅对第一个进程进行操作. 名称不区分大小写.

返回值

类型: 整数

此函数返回指定进程的进程 ID(PID). 如果没有找到匹配的进程或无法对其操作, 则返回 0.

备注

因为进程被突然终止 -- 可能在一个关键点中断它的工作或导致窗口中未保存数据丢失(如果有) -- 因此仅当无法使用 WinClose 关闭进程窗口时, 才使用这个函数.

相关

Run, WinClose, WinKill, 进程函数, 窗口函数

示例

强制关闭第一个匹配的进程(警告: 任何未保存的数据将丢失).

ProcessClose "notepad.exe"

强制关闭 所有 匹配的进程.

ProcessCloseAll(PIDOrName)
{
    While ProcessExist(PIDOrName)
        ProcessClose PIDOrName
}

; 示例:
Loop 3
    Run "notepad.exe"
Sleep 3000
ProcessCloseAll "notepad.exe"


ProcessExist - 语法 & 使用 | AutoHotkey v2

ProcessExist

检查指定的进程是否存在.

PID := ProcessExist(PIDOrName)

参数

PIDOrName

类型: 整数或字符串

如果省略, 使用脚本自身的进程. 否则, 指定一个数字(PID) 或进程名:

PID: 进程的 ID, 它是唯一标识一个特定进程的数字(此数字仅在该进程的存在周期内有效). 新启动进程的 PID 可以通过 Run 函数来确定. 同样, 窗口的 PID 也可以用 WinGetPID 来确定.

Name: 进程的名称通常与其可执行文件相同(没有路径), 例如 notepad.exe 或 winword.exe. 由于名称可能匹配多个正在运行的进程, 因此只对第一个匹配的进程进行操作. 该名称不区分大小写.

返回值

类型: 整数

此函数返回指定进程的进程 ID(PID). 如果没有匹配的进程, 则返回 0.

相关

Run, WinExist, 进程函数, 窗口函数

示例

检查记事本进程是否存在.

if (PID := ProcessExist("notepad.exe"))
    MsgBox "Notepad exists and has the Process ID " PID "."
else
    MsgBox "Notepad does not exist."


ProcessGetName / ProcessGetPath - Syntax & Usage | AutoHotkey v2

ProcessGetName / ProcessGetPath

返回指定进程的名称或路径.

Name := ProcessGetName(PIDOrName)
Path := ProcessGetPath(PIDOrName)

参数

PIDOrName

类型: 整数或字符串

如果省略, 则使用脚本本身的进程. 否则, 指定一个数字(PID) 或进程名:

PID: 进程 ID, 这是一个唯一标识一个特定进程的数字(这个数字仅在该进程的生命周期内有效). 新启动进程的 PID 可以通过 Run 函数确定. 同样, 窗口的 PID 也可以通过 WinGetPID 来确定. ProcessExist 也可以用来获取 PID.

Name: 进程名通常与它的可执行文件(没有路径) 相同, 例如 notepad.exe 或 winword.exe. 因为一个名称可能与多个正在运行的进程匹配, 所以只对第一个进程进行操作. 名称不区分大小写.

返回值

类型: 字符串

ProcessGetName 返回指定进程的名称. 例如: notepad.exe.

ProcessGetPath 返回指定进程的路径. 例如: C:\Windows\notepad.exe.

错误处理

如果找不到进程, 则抛出 TargetError.

如果无法检索名称/路径, 则抛出 OSError.

相关

进程函数, Run, WinGetProcessName, WinGetProcessPath

示例

获取用于打开文档的进程的名称和路径.

Run "license.rtf",,, &pid  ; 这可能存在于 C:\Windows\System32.
try {
    name := ProcessGetName(pid)
    path := ProcessGetPath(pid)
}
MsgBox "Name: " (name ?? "could not be retrieved") "`n"
    .  "Path: " (path ?? "could not be retrieved")


ProcessGetParent - 语法 & 使用 | AutoHotkey v2

ProcessGetParent

返回创建指定进程的进程 ID(PID).

PID := ProcessGetParent(PIDOrName)

参数

PIDOrName

类型: 整数或字符串

如果省略, 则使用脚本自己的进程. 否则, 指定一个数字(PID) 或进程名:

PID: 进程 ID, 是唯一标识一个特定进程的数字(这个数字只在该进程的生命周期内有效). 新启动进程的PID可以通过 Run 函数确定. 类似地, 窗口的 PID 可以用 WinGetPID 确定. ProcessExist can also be used to discover a PID.

Name: 进程的名称通常与它的可执行文件相同(没有路径), 例如 notepad.exe 或 winword.exe. 因为一个名称可能匹配多个正在运行的进程, 所以只操作第一个进程. 名称不区分大小写.

返回值

类型: 整数

函数返回创建指定进程的进程 ID(PID).

错误处理

如果找不到指定的进程, 则抛出 TargetError.

备注

如果父进程不再运行, 则有可能返回的 PID 已被系统重用, 现在标识了一个不同的进程.

相关

进程函数

示例

显示启动脚本的进程的名称.

try
    MsgBox ProcessGetName(ProcessGetParent())
catch
    MsgBox "Unable to retrieve parent process name; the process has likely exited."


ProcessSetPriority - 语法 & 使用 | AutoHotkey v2

ProcessSetPriority

更改第一个匹配进程的优先级.

PID := ProcessSetPriority(Level , PIDOrName)

参数

Level

类型: 字符串

指定下列单词或字母的其中一个:

  • Low(或 L) (低)
  • BelowNormal(或 B) (低于标准)
  • Normal(或 N) (普通)
  • AboveNormal(或 A) (高于标准)
  • High(或 H) (高)
  • Realtime(或 R) (实时)

请注意, 如果将任何没有设计为实时优先级运行的进程设置为该级别, 则可能会降低系统稳定性.

PIDOrName

类型: 整数或字符串

如果省略, 则使用脚本自己的进程. 否则, 请指定一个数字(PID) 或进程名:

PID: 进程 ID, 唯一标识一个特定进程的数字(只有在此进程的生存期这个数字才有意义). 新运行的进程的 PID 可以通过 Run 函数获取. 同样的, 窗口的 PID 可以通过 WinGetPID 获取. ProcessExist 也可以用来获取 PID.

Name: 进程的名称, 通常和它的可执行文件名相同(不带路径), 例如 notepad.exe 或 winword.exe. 由于一个名称可能与多个正在运行的进程匹配, 因此将仅对第一个进程进行操作. 名称不区分大小写.

返回值

类型: 整数

此函数返回指定进程的进程 ID(PID). 如果没有找到匹配的进程或无法对其操作, 则返回 0.

备注

进程的当前优先级可以在 Windows 任务管理器中看到.

相关

Run, 进程函数, 窗口函数

示例

启动记事本, 将其优先级设置为高, 并显示其当前的 PID.

Run "notepad.exe", , , &NewPID
ProcessSetPriority "High", NewPID
MsgBox "The newly launched Notepad's PID is " NewPID

按下热键改变活动窗口进程优先级.

#z:: ; Win+Z 热键
{
    active_pid := WinGetPID("A")
    active_title := WinGetTitle("A")
    MyGui := Gui(, "Set Priority")
    MyGui.Add("Text",, "
    (
        Press Escape to cancel, or double-click a new
        priority level for the following window:
    )")
    MyGui.Add("Text", "wp", active_title)
    LB := MyGui.Add("ListBox", "r5 Choose1", ["Normal", "High", "Low", "BelowNormal", "AboveNormal"])
    LB.OnEvent("DoubleClick", SetPriority)
    MyGui.Add("Button", "default", "OK").OnEvent("Click", SetPriority)
    MyGui.OnEvent("Escape", (*) => MyGui.Destroy())
    MyGui.OnEvent("Close", (*) => MyGui.Destroy())
    MyGui.Show()

    SetPriority(*)
    {
        MyGui.Destroy()
        if ProcessSetPriority(new_prio, active_pid)
            MsgBox "Success: Its priority was changed to '" new_prio "'."
        else
            MsgBox "Error: Its priority could not be changed to '" new_prio "'."
    }
}


ProcessWait - 语法 & 使用 | AutoHotkey v2

ProcessWait

等待指定的进程存在.

PID := ProcessWait(PIDOrName , Timeout)

参数

PIDOrName

类型: 整数或字符串

指定数字(PID) 或进程名:

PID: 进程 ID, 唯一标识一个特定进程的数字(只有在此进程的生存期这个数字才有意义). 新运行的进程的 PID 可以通过 Run 函数获取. 同样的, 窗口的 PID 可以通过 WinGetPID 获取. ProcessExist 也可以用来获取 PID.

Name: 进程的名称, 通常和它的可执行文件名相同(不带路径), 例如 notepad.exe 或 winword.exe. 由于一个名称可能与多个正在运行的进程匹配, 因此将仅对第一个进程进行操作. 名称不区分大小写.

Timeout

类型: 整数或浮点数

如果省略, 该函数将无限期地等待. 否则, 指定在超时之前等待的秒数(可以包含小数).

返回值

类型: 整数

如果发现了指定的进程, 该函数返回该进程的进程 ID (PID). 如果函数超时, 则返回 0.

备注

进程每 100 毫秒检查一次; 当条件满足时, 函数停止等待. 换句话说, 它不会等待超时过期, 而是立即返回并继续执行脚本. 此外, 当函数处于等待状态时, 可以通过热键, 自定义菜单项或计时器启动新的线程.

相关

ProcessWaitClose, Run, WinWait, 进程函数, 窗口函数

示例

等待记事本进程出现, 如果在 5.5 秒内出现, 则其优先级设置为 Low, 而脚本自己的优先级设置为 High. 之后, 会尝试在 5 秒内关闭进程.

NewPID := ProcessWait("notepad.exe", 5.5)
if not NewPID
{
    MsgBox "The specified process did not appear within 5.5 seconds."
    return
}
; 否则:
MsgBox "A matching process has appeared (Process ID is " NewPID ")."
ProcessSetPriority "Low", NewPID
ProcessSetPriority "High"  ; 把脚本自己设置为高优先级.
WinClose "Untitled - Notepad"
WaitPID := ProcessWaitClose(NewPID, 5)
if WaitPID ; PID 仍然存在.
    MsgBox "The process did not close within 5 seconds."


ProcessWaitClose - 语法 & 使用 | AutoHotkey v2

ProcessWaitClose

等待匹配进程关闭.

PID := ProcessWaitClose(PIDOrName , Timeout)

参数

PIDOrName

类型: 整数或字符串

指定数字(PID) 或进程名:

PID: 进程 ID, 唯一标识一个特定进程的数字(只有在此进程的生存期这个数字才有意义). 新运行的进程的 PID 可以通过 Run 函数获取. 同样的, 窗口的 PID 可以通过 WinGetPID 获取. ProcessExist 也可以用来获取 PID.

Name: 进程的名称, 通常和它的可执行文件名相同(不带路径), 例如 notepad.exe 或 winword.exe. 由于一个名称可能与多个正在运行的进程匹配, 因此将仅对第一个进程进行操作. 名称不区分大小写.

Timeout

类型: 整数或浮点数

如果省略, 该函数将无限期地等待. 否则, 指定在超时之前等待的秒数(可以包含小数).

返回值

类型: 整数

如果关闭了匹配进程, 则返回 0. 如果该函数超时, 它将返回仍然存在的第一个匹配进程的进程 ID(PID).

备注

进程每 100 毫秒检查一次; 当条件满足时, 函数停止等待. 换句话说, 它不会等待超时过期, 而是立即返回并继续执行脚本. 此外, 当函数处于等待状态时, 可以通过热键, 自定义菜单项或计时器启动新的线程.

相关

ProcessWait, Run, WinWaitClose, 进程函数, 窗口函数

示例

请参阅 ProcessWait 页面的示例 #1.


Random - 语法 & 使用 | AutoHotkey v2

Random

生成一个伪随机数字.

N := Random(A, B)

参数

A, B

类型: 整数或浮点数

如果两个都省略, 默认为 0.0 到 1.0. 如果只指定一个参数, 另一个参数默认为 0. 否则, 请指定要生成的最小和最大数字(任意顺序).

对于整数, 最小值和最大值都包含在可能返回的数字集合中. 支持全范围的 64 位整数.

对于浮点数, 一般不包括最大值.

返回值

类型: 整数或浮点数

这个函数返回一个伪随机生成的数字, 这是一个模拟真实随机数的数字, 但实际上是一个基于复杂公式的数字, 使确定/猜测下一个数字变得非常困难.

如果 A 或 B 中有一个是浮点数, 或者两者都被省略, 结果将是一个浮点数. 否则, 结果将是一个整数.

备注

指定范围内的所有数字产生的概率大致相同.

虽然在返回浮点数时设计中排除了指定的最大值, 但理论上可能由于浮点数舍入错误而返回该最大值. 这一点还没有被证实, 可能只有当选择的边界大于 2**53 时才可能. 还要注意, 因为可能有多达 2**53 个可能的值(例如在 0.0 到 1.0 的范围内), 所以正好是下限的概率通常非常低.

示例

生成一个范围为 1 到 10 的随机整数, 并将其存储在 N.

N := Random(1, 10)

在 0 到 9 的范围内生成一个随机整数, 并将其存储在 N.

N := Random(9)

生成一个范围为 0.0 到 1.0 的随机浮点数, 并将其存储在 fraction.

fraction := Random(0.0, 1.0)
fraction := Random() ; 等同于上一行.


RegCreateKey - Syntax & Usage | AutoHotkey v2

RegCreateKey

创建注册表键而不写入值.

RegCreateKey KeyName

参数

KeyName

类型: 字符串

注册表键的全名, 例如 "HKLM\Software\SomeApplication".

必须以 HKEY_LOCAL_MACHINE(或 HKLM), HKEY_USERS(或 HKU), HKEY_CURRENT_USER(或 HKCU), HKEY_CLASSES_ROOT(或 HKCR) 或 HKEY_CURRENT_CONFIG(或 HKCC) 开始.

要访问远程注册表, 请在前面加上计算机名和反斜杠, 例如 "\\workstation01\HKLM".

KeyName 只有在注册表循环运行时才可以省略, 在这种情况下, 它默认为当前循环项的键(即使键在循环期间被删除). 如果项目是一个子键, 则默认使用该子键的全名.

错误处理

失败时抛出 OSError.

A_LastError 被设置为操作系统的 GetLastError() 函数的结果.

备注

如果 KeyName 指定了一个现有的注册表键, RegCreateKey 将验证脚本是否对该键具有写访问权, 但不会进行更改. 否则, RegCreateKey 将尝试创建该键(以及它的上级, 如果需要).

有关如何访问远程计算机的注册表, 请参阅注册表循环中的备注.

要在 32 位脚本中在 64 位注册表中创建子键, 或反之, 请使用 SetRegView.

相关

RegDelete, RegDeleteKey, RegRead, RegWrite, Registry-loop, SetRegView

示例

创建一个空的注册表键. 如果安装了 Notepad2, 它的效果是将它添加到 .ahk 文件的 "打开方式" 菜单中.

RegCreateKey "HKCU\Software\Classes\.ahk\OpenWithList\notepad2.exe"


RegDelete - 语法 & 使用 | AutoHotkey v2

RegDelete

从注册表中删除值.

RegDelete KeyName, ValueName

参数

KeyName

类型: 字符串

注册表键的全名, 例如 "HKLM\Software\SomeApplication".

必须以 HKEY_LOCAL_MACHINE(或 HKLM), HKEY_USERS(或 HKU), HKEY_CURRENT_USER(或 HKCC), HKEY_CLASSES_ROOT(或 HKCR) 或 HKEY_CURRENT_CONFIG(或 HKCC) 开始.

要访问远程注册表, 请在前面加上计算机名和反斜杠, 例如 "\\workstation01\HKLM".

只有在注册表循环时, 才能省略 KeyName, 在这种情况下, 默认为当前循环项目的键. 如果项目是子键, 则默认使用该子键的全名. 如果项目是值, 则 ValueName 默认为该值的名称, 但是可以被重写.

ValueName

类型: 字符串

如果为空或省略, 将删除键的默认值(除了上面提到的), 这是在注册表中显示为 "(默认)" 的值. 否则, 请指定要删除值的名称.

错误处理

失败时抛出 OSError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

警告: 对注册表进行删除操作有潜在的风险 - 操作前请三思!

要检索和操作多个注册表键或值, 请考虑使用注册表循环.

在注册表循环中, RegDeleteKey 没必要删除当前循环的项目. 如果项目是子键, 则 RegDelete() 只删除它的默认值.

有关如何访问远程计算机注册表的详情, 请参阅注册表循环中的备注.

从 32 位脚本中删除注册表的 64 位部分中的条目, 反之亦然, 请使用 SetRegView.

相关

RegCreateKey, RegDeleteKey, RegRead, RegWrite, 注册表循环, SetRegView, IniDelete

示例

从注册表中删除一个值.

RegDelete "HKEY_LOCAL_MACHINE\Software\SomeApplication", "TestValue"


RegDeleteKey - 语法 & 使用 | AutoHotkey v2

RegDeleteKey

从注册表中删除子键.

RegDeleteKey KeyName

参数

KeyName

类型: 字符串

注册表键的全名, 例如 "HKLM\Software\SomeApplication".

必须以 HKEY_LOCAL_MACHINE(或 HKLM), HKEY_USERS(或 HKLM), HKEY_CURRENT_USER(或 HKLM), HKEY_CLASSES_ROOT(或 HKLM) 或 HKEY_CURRENT_CONFIG(或 HKLM) 开始.

要访问远程注册表, 请在前面加上计算机名和反斜杠, 例如 "\\workstation01\HKLM".

只有在注册表循环时, 才能省略 KeyName, 在这种情况下, 默认为当前循环项目的键. 如果项目是子键, 则默认使用该子键的全名.

错误处理

失败时抛出 OSError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

警告: 对注册表进行删除操作有潜在的风险 - 操作前请三思!

要检索和操作多个注册表键或值, 请考虑使用注册表循环.

在注册表循环中, RegDeleteKey 没必要删除当前循环的项目. 如果项目是子键, 则 RegDeleteKey() 将删除键本身. 如果项目是值, 则 RegDeleteKey() 删除 包含 该值的键, 包括所有子键和值.

有关如何访问远程计算机注册表的详情, 请参阅注册表循环中的备注.

从 32 位脚本中删除注册表的 64 位部分中的条目, 反之亦然, 请使用 SetRegView.

相关

RegCreateKey, RegCreateKey, RegDelete, RegRead, RegWrite, Registry-loop, SetRegView, IniDelete

示例

从注册表中删除一个值.

RegDeleteKey "HKEY_LOCAL_MACHINE\Software\SomeApplication"


RegExMatch - 语法 & 使用 | AutoHotkey v2

RegExMatch

判断字符串是否包含某个匹配模式(正则表达式).

FoundPos := RegExMatch(Haystack, NeedleRegEx , &OutputVar, StartingPos := 1)

参数

Haystack

类型: 字符串

要搜索其内容的字符串. 可能包含二进制零.

NeedleRegEx

类型: 字符串

要搜索的模式, 它是兼容 Perl 的正则表达式(PCRE). 模式的选项(如果有) 必须放在模式字符串的开始且后面跟着闭括号. 例如, 模式 i)abc.*123 将匹配不区分大小写的 "abc", 接着零个或多个任意字符, 然后是 "123". 如果没有选项, ")" 是可选的; 例如, )abc 等同于 abc.

虽然 NeedleRegEx 不能包含二进制零, 但模式 \x00 可用来匹配 Haystack 中的二进制零.

&OutputVar

类型: VarRef

如果省略, 没有使用输出变量. 否则, 请指定指定一个变量引用, 在其中存储匹配对象, 可以用来获取整体匹配和每个捕获子模式(如果存在) 的位置, 长度和值.

如果没有找到模式(也就是说, 如果函数返回 0), 这个变量将被置空.

StartingPos

类型: 整数

如果省略, 则它默认为 1(Haystack 的开始位置). 否则, 指定 2 从第二个字符开始, 3 从第三个字符开始, 以此类推. 如果 StartingPos 的长度超过 Haystack 的长度, 那么搜索将从 Haystack 末尾的空字符串开始(常结果是不匹配).

指定负值的 StartingPos, 从右边的位置开始搜索. 例如, -1 从最后一个字符开始, -2 从倒数第二个字符开始. 如果 StartingPos 试图超出 Haystack 的左端, 则会搜索整个 Haystack.

指定 0, 从 Haystack 的末尾开始; 即最后一个字符的右边的位置. 这可以用于零宽度的断言, 如 (?<=a).

不论 StartingPos 的值是多少, 返回的值总是相对于 Haystack 的第一个字符. 例如, "abc" 在 "123abc789" 中的位置总是 4.

返回值

类型: 整数

函数返回在字符串 Haystack 中最左边出现 NeedleRegEx 的位置. 位置 1 表示第一个字符. 如果没有找到模式, 则返回 0.

错误

语法错误: 如果模式中包含语法错误, 则抛出 Error, 并带有以下形式的消息: Compile error N at offset M: description. 在该字符串中, N 是 PCRE 中错误的编号, M 是正则表达式中违规字符的位置, 而 description 是描述该错误的文本.

执行错误: 如果在 执行 正则表达式的过程中发生错误, 则抛出 Error. 错误对象的 Extra 属性包含了 PCRE 的错误编号. 虽然这种错误很少发生, 但最有可能发生的是 ""太多空字符串匹配"(-22), "递归太深"(-21), 和 "达到匹配限制"(-8). 如果出现这些情况, 请尝试重新设计更严格的匹配模式, 例如无论是否可行都把每个 * 替换为 ?, + 或像 {0,3} 这样的限制.

选项

请参阅 RegEx 快速参考中的选项, 例如 i)abc, 它关闭了区分大小写.

匹配对象(RegExMatchInfo)

如果找到了匹配, 一个包含匹配信息的对象将被存储在 OutputVar. 这个对象有以下方法和属性:

Match.Pos, Match.Pos[N] 或 Match.Pos(N): 返回整个匹配或捕获子模式的位置.

Match.Len, Match.Len[N] 或 Match.Len(N): 返回整个匹配或捕获子模式的长度.

Match.Name[N] 或 Match.Name(N): 返回指定的子模式的名称(如果它含有).

Match.Count: 返回所有子模式的数目(捕获组), 这也是 N 的最大值.

Match.Mark: 适用时返回上次遇到 (*MARK:NAME) 的 NAME.

Match[] 或 Match[N]: 返回整个匹配或捕获子模式.

对于上面的所有, N 可以为下列值:

  • 0 表示整个匹配.
  • 子模式的编号, 包括含有名称的子模式.
  • 子模式的名称.

Match.N: Match["N"] 的简写, 其中 N 是任何未加引号的名称或数字, 其不能与定义的属性(上面列出) 冲突. 例如, match.1 或 match.Year.

该对象还支持枚举; 也就是说, 支持 for-loop. 或者, 可以使用 Loop Match.Count.

性能

要在一个较大的字符串中搜索简单的子字符串, 请使用 InStr, 因为它比 RegExMatch 更快.

为了提升性能, 最近使用的 100 个正则表达式会被缓存在内存中(以已编译的形式).

多次使用一个正则表达式时(例如在循环中), 使用研究选项(S) 可以提高性能.

备注

可以为子模式指定名称, 例如模式 (?P<Year>\d{4}) 中的单词 Year. 这种名称最多可以由 32 个字母数字和下划线组成. 请注意, 命名的子模式也是有编号的, 如果在 "Year" 后出现了一个未命名的子模式, 它将被存储在 OutputVar[2] 中, 而不是 OutputVar[1] 中.

大多数字符, 如 abc123 可以原义使用在正则表达式中. 然而, 集合 \.*?+[{|()^$ 中的任何字符则必须在其前面加上反斜杠才能被视为原义. 例如, \. 表示一个原义的句点, 而 \\ 表示一个原义的反斜杠. 使用 \Q...\E 能避免转义. 例如: \QLiteral Text\E.

在正则表达式中, 特殊字符(如制表符和换行符) 可以使用一个重音符(`) 或反斜杠(\) 进行转义. 例如, 在不使用 x 选项时, `t 等同于 \t.

要了解正则表达式的基础(或复习正则表达式的语法), 请参阅正则表达式快速参考.

AutoHotkey 的正则表达式是使用 www.pcre.org 的兼容 Perl Regular Expressions(PCRE) 实现的.

在表达式中, a ~= b 能被当作 RegExMatch(a, b) 的缩写.

相关

RegExReplace, RegEx 快速参考, Regular Expression Callouts, InStr, SubStr, SetTitleMatchMode RegEx, Global matching and Grep (forum link)

文本数据的常见来源: FileRead, Download, A_Clipboard, GUI Edit 控件

示例

有关普通 RegEx 的示例, 请参阅 RegEx 快速参考.

报告 4, 这是找到匹配的位置.

MsgBox RegExMatch("xxxabc123xyz", "abc.*xyz")

报告 7, 因为 $ 要求在末端进行匹配.

MsgBox RegExMatch("abc123123", "123$")

报告 1, 因为通过不区分大小写选项实现了匹配.

MsgBox RegExMatch("abc123", "i)^ABC")

报告 1, 并把 "XYZ" 保存到 SubPat[1].

MsgBox RegExMatch("abcXYZ123", "abc(.*)123", &SubPat)

报告 7 而不是 1, 这是由于开始位置为 2 而不是 1.

MsgBox RegExMatch("abc123abc456", "abc\d+",, 2)

演示匹配对象的用法.

FoundPos := RegExMatch("Michiganroad 72", "(.*) (?<nr>\d+)", &SubPat)
MsgBox SubPat.Count ": " SubPat[1] " " SubPat.Name[2] "=" SubPat.nr  ; 显示 "2: Michiganroad nr=72"

检索文件的扩展名. 注意 SplitPath 也可以用于此目的, 而且更可靠.

Path := "C:\Foo\Bar\Baz.txt"
RegExMatch(Path, "\w+$", &Extension)
MsgBox Extension[]  ; 报告 "txt".

类似于 AutoHotkey v1 的 Transform Deref, 下面的函数可以扩展包含在其他变量中的变量引用和转义序列. 此外, 这个例子还展示了如何在一个字符串中找到所有匹配项, 而不是停留在第一个匹配项(类似于 JavaScript 的 RegEx 中的 g 标志).

var1 := "abc"
var2 := 123
MsgBox Deref("%var1%def%var2%")  ; 报告 abcdef123.

Deref(Str)
{
    spo := 1
    out := ""
    while (fpo:=RegexMatch(Str, "(%(.*?)%)|``(.)", &m, spo))
    {
        out .= SubStr(Str, spo, fpo-spo)
        spo := fpo + StrLen(m[0])
        if (m[1])
            out .= %m[2]%
        else switch (m[3])
        {
            case "a": out .= "`a"
            case "b": out .= "`b"
            case "f": out .= "`f"
            case "n": out .= "`n"
            case "r": out .= "`r"
            case "t": out .= "`t"
            case "v": out .= "`v"
            default: out .= m[3]
        }
    }
    return out SubStr(Str, spo)
}


RegExReplace - 语法 & 使用 | AutoHotkey v2

RegExReplace

替换字符串中匹配模式(正则表达式) 出现的地方.

NewStr := RegExReplace(Haystack, NeedleRegEx , Replacement, &OutputVarCount, Limit, StartingPos)

参数

Haystack

类型: 字符串

要搜索和替换其内容的字符串. 可以包含二进制零.

NeedleRegEx

类型: 字符串

要搜索的模式, 它是兼容 Perl 的正则表达式(PCRE). 模式的选项(如果有) 必须放在模式字符串的开始且后面跟着闭括号. 例如, 模式 i)abc.*123 将打开不区分大小写的选项并搜索 "abc", 接着零个或多个任意字符, 然后是 "123". 如果没有选项, ")" 是可选的; 例如, )abc 等同于 abc.

虽然 NeedleRegEx 不能包含二进制零, 但模式 \x00 可用来匹配 Haystack 中的二进制零.

Replacement

类型: 字符串

如果为空或省略, NeedleRegEx 将被替换为空, 这意味着将它从返回值中删除. 否则, 请指定要替换每个匹配项的字符串, 它是纯文本(不是正则表达式).

该参数可能包括反向引用, 比如 $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

类型: VarRef

如果省略, 将不存储对应的值. 否则, 请指定指定一个变量引用, 用于存储发生的替换次数(如果没有, 则为 0).

Limit

类型: 整数

如果省略, 则默认为 -1, 即替换 Haystack 中出现的 所有 模式. 否则, 指定允许的最大替换次数. Haystack 中最后一次替换右边的部分将保持不变.

StartingPos

类型: 整数

如果省略, 则它默认为 1(Haystack 的开始位置). 否则, 指定 2 从第二个字符开始, 3 从第三个字符开始, 以此类推. 如果 StartingPos 的长度超过 Haystack 的长度, 那么搜索将从 Haystack 末尾的空字符串开始(常结果是不替换).

指定负值的 StartingPos 将从右边的位置开始. 例如, -1 从最后一个字符开始, -2 从倒数第二个字符开始. 如果 StartingPos 试图超出 Haystack 的左端, 则会搜索整个 Haystack.

指定 0 从 Haystack 的末尾开始; 也就是最后一个字符的右边的位置. 这可以用于零宽度的断言, 如 (?<=a).

不论 StartingPos 的值是多少, 返回值始终是 Haystack 的完整副本 -- 唯一的区别是, 与 StartingPos 为 1 时相比, 它的左侧更多部分可能没有改变.

返回值

类型: 字符串

函数将返回 Haystack 的一个版本, 其内容已经被操作所替换. 如果没有发生替换, 将返回 Haystack 原始值.

错误

在以下情况下会抛出 Error:

  • 该模式包含一个语法错误; 或
  • 在 execution 正则表达式的过程中发生了错误.

有关详情, 请参阅 RegExMatch.

选项

有关选项, 请参阅RegEx 快速参考中选项, 例如 i)abc, 它关闭了区分大小写.

性能

要进行简单的子字符串替换, 请使用 StrReplace, 因为它比 RegExReplace 执行地更快.

如果您知道替换的最大次数是多少, 请在 Limit 参数中指定来提高性能, 因为这样可以早一些停止搜索(这样也可能会降低在替换操作过程中占用的系统内存). 例如, 如果您知道在一个大字符串的开始处仅有一个匹配, 请指定最大次数为 1.

为了提升性能, 最近使用的 100 个正则表达式会被缓存在内存中(以已编译的形式).

多次使用一个正则表达式时(例如在循环中), 使用研究选项(S) 可以提高性能.

备注

大多数字符(例如 abc123) 可以原义使用在正则表达式中. 然而集合 \.*?+[{|()^$ 中的任何字符则必须在其前面加上反斜杠才能被视为原义. 例如, \. 表示一个原义的句点, 而 \\ 表示一个原义的反斜杠. 使用 \Q...\E 能避免转义. 例如: \QLiteral Text\E.

在正则表达式中, 特殊字符(如制表符和换行符) 可以使用一个重音符(`) 或反斜杠(\) 进行转义. 例如, 当不使用 x 选项时, `t 等同于 \t.

要了解正则表达式的基础(或复习正则表达式的语法), 请参阅正则表达式快速参考.

相关

RegExMatch, RegEx 快速参考, 正则表达式调出, StrReplace, InStr

文本数据的常见来源: FileRead, Download, A_Clipboard, GUI Edit 控件

示例

有关普通 RegEx 的示例, 请参阅 RegEx 快速参考.

报告 "abc123xyz", 因为 $ 只能在末尾形成匹配.

MsgBox RegExReplace("abc123123", "123$", "xyz")

报告 "123", 因为通过不区分大小写选项实现了匹配.

MsgBox RegExReplace("abc123", "i)^ABC")

报告 "aaaXYZzzz", 使用了 $1 后向引用.

MsgBox RegExReplace("abcXYZ123", "abc(.*)123", "aaa$1zzz")

报告空字符串, 并保存 2 到 ReplacementCount.

MsgBox RegExReplace("abc123abc456", "abc\d+", "", &ReplacementCount)


RegRead - 语法 & 使用 | AutoHotkey v2

RegRead

从注册表读取值.

Value := RegRead(KeyName, ValueName, Default)

参数

KeyName

类型: 字符串

注册表键的全名, 例如 "HKLM\Software\SomeApplication".

必须以 HKEY_LOCAL_MACHINE(或 HKLM), HKEY_USERS(或 HKU), HKEY_CURRENT_USER(或 HKCU), HKEY_CLASSES_ROOT(或 HKCR) 或 HKEY_CURRENT_CONFIG(或 HKCC) 开始.

要访问远程注册表, 请在前面加上计算机名和反斜杠, 例如 "\\workstation01\HKLM".

只有在注册表循环时, 才能省略 KeyName, 在这种情况下, 默认为当前循环项目的键. 如果项目是子键, 则默认使用该子键的全名. 如果项目是值, 则 ValueName 默认为该值的名称, 但是可以被重写.

ValueName

类型: 字符串

如果为空或省略, 将删除键的默认值(除了上面提到的), 这是 RegEdit 中显示为 "(默认)". 否则, 请指定将检索值的名称. 如果没有默认值(即注册表中显示 "数值未设置"), 则抛出一个 OSError.

Default

类型: Any

如果省略, 则抛出 OSError, 而不是返回默认值. 否则, 如果指定的键或值不存在, 请指定要返回的值.

返回值

类型: 字符串或整数

函数返回指定注册表键的值.

错误处理

如果遇到问题(如不存在的键或值且省略 Default, 或权限错误), 则抛出 OSError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

目前只支持以下值类型: REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ, REG_DWORD 和 REG_BINARY.

在注册表中, REG_DWORD 值总是被转换为正十进制数. 如果数字是负数, 则使用 OutputVar := OutputVar << 32 >> 32 或类似的方法将其转换为有符号的 32 位整数.

读取 REG_BINARY 键时, 结果是一串十六进制字符. 例如, REG_BINARY 值 01,a9,ff,77 的读取结果为字符串 01A9FF77.

读取 REG_MULTI_SZ 值的每个部分会以换行符结束(`n). 如果值为空, 则返回空字符串. 从返回值中逐个提取单独的部分, use a parsing loop.

要检索和操作多个注册表键或值, 请考虑使用注册表循环.

有关如何访问远程计算机注册表的详情, 请参阅注册表循环中的备注.

从 32 位脚本中读取或写入注册表的 64 位部分中的条目, 反之亦然, 请使用 SetRegView.

相关

RegCreateKey, RegDelete, RegDeleteKey, RegWrite, 注册表循环, SetRegView, IniRead

示例

从注册表中读取一个值并将其存储在 TestValue.

TestValue := RegRead("HKEY_LOCAL_MACHINE\Software\SomeApplication", "TestValue")

检索并报告 "Program Files"(程序文件) 目录的路径. 有关另一种方法, 请参阅 EnvGet 示例 #2.

; 此行确保在 64 位系统上运行非 64 位脚本时
; 也能正常返回 64 位的 Program Files 目录路径.
SetRegView 64

ProgramFilesDir := RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion", "ProgramFilesDir")
MsgBox "Program files are in: " ProgramFilesDir

检索注册表值的类型(例如 REG_SZ 或 REG_DWORD).

MsgBox RegKeyType("HKCU", "Environment", "TEMP")
return

RegKeyType(RootKey, SubKey, ValueName)  ; 此函数返回指定值的类型.
{
    Loop Reg, RootKey "\" SubKey
        if (A_LoopRegName = ValueName)
            return A_LoopRegType
    return "Error"
}


RegWrite - 语法 & 使用 | AutoHotkey v2

RegWrite

写入值到注册表.

RegWrite Value, ValueType, KeyName , ValueName
RegWrite Value , ValueType, , ValueName

参数

Value

类型: 字符串或整数

要写入的值. 如果文本较长, 可以通过延续片段的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

ValueType

类型: 字符串

必须为 REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ, REG_DWORD 或 REG_BINARY 的其中一个.

只有在 KeyName 省略和注册表循环中项目是值时, 才能省略 ValueType, 如下所示.

KeyName

类型: 字符串

注册表键的全名, 例如 "HKLM\Software\SomeApplication".

必须以 HKEY_LOCAL_MACHINE(或 HKLM), HKEY_USERS(或 HKU), HKEY_CURRENT_USER(或 HKCU), HKEY_CLASSES_ROOT(或 HKCR) 或 HKEY_CURRENT_CONFIG(或 HKCC) 开始.

要访问远程注册表, 请在前面加上计算机名和反斜杠, 例如 "\\workstation01\HKLM".

只有在注册表循环时, 才能省略 KeyName, 在这种情况下, 默认为当前循环项目的键. 如果项目是子键, 则默认使用该子键的全名. 如果项目是值, ValueType 和 ValueName 默认为值的类型和名称, 但是可以被重写.

ValueName

类型: 字符串

如果为空或省略, 将删除键的默认值(除了上面提到的), 这是在 RegEdit 中显示为 "(默认)" 的值. 否则, 请指定要写入的值的名称.

错误处理

失败时抛出 OSError.

A_LastError 被设置为操作系统 GetLastError() 函数返回的结果.

备注

如果 KeyName 指定的子键不存在, RegWrite 将尝试创建它(如果需要, 还将创建它的父键). 虽然 RegWrite 可以直接写入根键, 但是一些操作系统可能会拒绝写入到 HKEY_CURRENT_USER 的顶层.

要创建一个键而不写入任何值, 请使用 RegCreateKey.

如果 ValueType 为 REG_DWORD, 则 Value 应该介于 -2147483648 和 4294967295(0xFFFFFFFF) 之间. 在注册表中, REG_DWORD 值总是表示为正的十进制数. 若要使用 RegRead 等方法将其作为负数读取, 请使用 OutputVar := OutputVar << 32 >> 32 类似方法将其转换为带符号的 32 位整数.

写入 REG_BINARY 键时, 请使用十六进制的字符串, 例如 REG_BINARY 值 01,a9,ff,77 可以使用字符串 01A9FF77 写入.

写入 REG_MULTI_SZ 键时, 你必须使用换行符(`n) 分隔各个部分. 最后一个部分后面的换行符是可选的. 不允许存在空的部分. 换句话说, 在一行中不能连续指定两个换行符(`n`n), 因为这样会导致写入到注册表的值比期望的短.

要检索和操作多个注册表键或值, 请考虑使用注册表循环.

有关如何访问远程计算机注册表的详情, 请参阅注册表循环中的备注.

从 32 位脚本中读取或写入注册表的 64 位部分中的条目, 反之亦然, 请使用 SetRegView.

相关

RegCreateKey, RegDelete, RegDeleteKey, RegRead, 注册表循环, SetRegView, IniWrite

示例

向注册表写入一个字符串.

RegWrite "Test Value", "REG_SZ", "HKEY_LOCAL_MACHINE\SOFTWARE\TestKey", "MyValueName"

将二进制数据写入注册表.

RegWrite "01A9FF77", "REG_BINARY", "HKEY_CURRENT_USER\Software\TEST_APP", "TEST_NAME"

向注册表写入一个多行字符串.

RegWrite "Line1`nLine2", "REG_MULTI_SZ", "HKEY_CURRENT_USER\Software\TEST_APP", "TEST_NAME"


Reload - 语法 & 使用 | AutoHotkey v2

Reload

使用新的脚本实例替换当前正在运行的.

Reload

此函数可用于需要频繁改变的脚本. 通过给此函数设置热键, 您可以在编辑器中保存修改后轻松地重启脚本.

默认情况下, 脚本也可以通过它的托盘图标或主窗口来重新加载.

传递给原始脚本的命令行参数不会被传递给新的实例. 要传递这些参数, 请不要使用 Reload. 相反地, 把 Run 配合 A_AhkPath 和 A_ScriptFullPath 使用(如果会以编译后的形式运行脚本, 还包括 A_IsCompiled). 此外, 使用 /restart 作为首个参数(即在可执行文件名后), 这样告诉程序要使用和 Reload 相同的动作. 另请参阅: 命令行开关和语法.

当脚本重启时, 会从它原来的工作目录启动(当它首次启动时生效的那个). 换句话说, SetWorkingDir 不会改变新实例的初始工作目录.

如果脚本无法重载(可能由于语法错误), 那么原来的实例会继续运行. 因此, reload 函数后应跟着在重载失败时您想执行的动作(例如使用 return 来退出当前子程序). 要在原来的实例中检测到失败, 请参照此例:

Reload
Sleep 1000 ; 如果成功, 则 reload 会在 Sleep 期间关闭这个实例, 所以下面这行语句永远不会执行.
Result := MsgBox("The script could not be reloaded. Would you like to open it for editing?",, 4)
if Result = "Yes"
    Edit
return

脚本以前的实例是通过与 #SingleInstance 相同的机制来识别的, 有着同样的限制.

如果脚本允许多个实例, Reload 可能无法识别正确的实例. 最简单的方法是 Run 一个新的实例, 然后退出. 例如:

if A_IsCompiled
    Run Format('"{1}" /force', A_ScriptFullPath)
else
    Run Format('"{1}" /force "{2}"', A_AhkPath, A_ScriptFullPath)
ExitApp

相关

Edit

示例

按下热键重启脚本.

^!r::Reload  ; Ctrl+Alt+R


Return - 语法 & 使用 | AutoHotkey v2

Return

从函数返回到之前通过函数调用, Hotkey 激活, 或其他方式执行跳转的地方.

Return Expression

参数

Expression

此参数进能在函数中使用.

如果省略, 默认为空字符串.

当 return 不在函数内使用时, 应该省略此参数.

由于此参数为表达式, 下面所有的例子都是有效的:

return 3
return "literal string"
return MyVar
return i + 1
return true  ; 返回数字 1 表示 "true".
return ItemCount < MaxItems  ; 返回 true 或 false 值.
return FindColor(TargetColor)

备注

如果表达式用圆括号括起来, 则 Return 后面的空格或制表符是可选的, 如 return(expression).

如果没有调用者可返回, 则 Return 将执行 Exit 作为代替.

在返回值给调用者中描述了多种从函数中返回多个值给调用者的方法.

相关

函数, Exit, ExitApp

示例

报告函数返回的值.

MsgBox returnTest() ; 显示 123

returnTest() {
    return 123
}

第一个 Return 确保如果前面的条件为真, 则跳过后续的函数调用. 第二个 Return 是多余的, 当在这样的函数结尾使用时.

#z::  ; Win-Z
^#z::  ; Ctrl-Win-Z
{
    MsgBox "A Win-Z hotkey was pressed."
    if GetKeyState("Ctrl")
        return  ; 尽早完成, 跳过下面的函数调用.
    MyFunction()
}

MyFunction()
{
    Sleep 1000
    return  ; 像这样在函数末尾使用时, 是多余的.
}


Run / RunWait - 语法 & 使用 | AutoHotkey v2

Run / RunWait

运行外部程序. 与 Run 不同, RunWait 将等到程序完成后才继续.

Run Target , WorkingDir, Options, &OutputVarPID
ExitCode := RunWait(Target , WorkingDir, Options, &OutputVarPID)

参数

Target

类型: 字符串

要运行的文档, URL, 可执行文件(.exe, .com, .bat, 等等), 快捷方式(.lnk), CLSID, 或系统动词(请参阅备注). 如果 Target 是一个本地文件, 并且没有指定路径, 如何定位文件通常取决于文件的类型和其他条件. 有关详情, 请参阅 Target 的解释.

要传递参数, 请让它们紧跟在程序或文档名的后面, 如下所示:

Run 'MyProgram.exe Param1 Param2'

如果程序/文档名称或参数包含空格, 则把它们括在双引号中是最可靠的(虽然它在某些情况下没有括在双引号中也能工作), 如下所示:

Run '"My Program.exe" "param with spaces"'
WorkingDir

类型: 字符串

如果为空或省略, 则使用脚本自己的工作目录(A_WorkingDir). 否则, 请指定新进程要使用的初始工作目录. 这通常也会影响 Target 中的相对路径, 但是命令行参数的解释取决于目标程序.

Options

类型: 字符串

如果为空或省略, 将正常启动 Target. 否则, 请指定以下一个或多个选项:

Max: 最大化运行

Min: 最小化运行

Hide: 隐藏运行(不能和上面任意一个选项组合使用)

注意: 一些程序(例如 Calc.exe) 不会遵循请求的启动状态, 因此对于它们 Max/Min/Hide 没有效果.

&OutputVarPID

类型: VarRef

如果省略, 将不存储对应的值. 否则, 请指定用于存储新启动的程序的唯一进程 ID(PID) 的变量引用. 如果无法确定 PID, 该变量将被置为空, 这经常发生在运行系统动词, 文档或快捷方式而不是直接的可执行文件时. RunWait 也支持此参数, 不过它的 OutputVarPID 必须在另一个线程中检查(否则, PID 将是无效的, 因为在 RunWait 后面的线程执行时, 进程已经终止了).

在 Run 函数检索到 PID 之后, 由进程创建的窗口可能还不存在. 要等待至少一个窗口被创建, 请使用 WinWait "ahk_pid " OutputVarPID.

返回值

类型: 整数

与 Run 不同, RunWait 会等待 Target 关闭或退出, 此时返回值被设置为程序的退出代码(32 位的有符号整数). 一些程序即使仍在运行, 但会出现立即返回; 这是因为这些程序启动了另一个进程.

错误处理

如果无法启动 Target, 则会抛出异常(即, 显示一个错误窗口) 并退出当前线程, 除非错误被 Try/Catch 语句捕获. 例如:

try
    Run "NonExistingFile"
catch
    MsgBox "File does not exist."

内置变量 A_LastError 被设置为操作系统的 GetLastError() 函数的结果.

Target 的解释

Run/RunWait 本身不解释命令行参数或搜索目标文件. 相反, 它尝试执行目标, 如下所示:

  • 如果没有指定动词, Target 将按原样传递给 CreateProcess 的参数 lpCommandLine.
  • 如果指定了动词或 CreateProcess 失败, 并且 RunAs 没有生效, 则尝试 ShellExecuteEx.

如果 Target 指定了名称, 但没有指定目录, 如果它是集成的("已知的"), 例如包含在 PATH 的文件夹之一中, 系统将搜索并启动该文件. 确切的搜索顺序取决于是否调用 CreateProcess 和/或 ShellExecuteEx. 如果调用 CreateProcess, 应用程序目录(其中包含 AutoHotkey 解释器或编译的脚本) 优先于 WorkingDir 指定的工作目录. 要避免这种情况, 请指定目录; 例如 .\program.exe.

当尝试 ShellExecuteEx 时, Target 被解释如下:

  • 以第一个空格或制表符结尾的 Target 子字符串可以是预定义的动词名称, 也可以是星号后面跟着动词词名称. 如果存在, 则排除可选的星号, 动词名称和单个分隔空格或制表符. 动词名称不支持包含空格或制表符, 但允许使用连字符等符号.
  • 如果存在前置双引号, 则将其与下一个双引号之间的子字符串视为目标文件或动作.
  • 否则, 第一个子字符串以空格结尾, 并且是一个现有文件(由绝对路径或相对于 WorkingDir 指定), 或以 .exe, .bat, .com, .cmd 或 .hta 结尾被认为是动作. 这允许文件类型 .ahk, .vbs 或 .lnk 接受参数, 同时仍然允许 "已知的" 的可执行文件(如 wordpad.exe) 在没有绝对路径的情况下启动.
  • 如果存在单个分隔空格, 则忽略, Target 其余部分将按原样传递给 CreateProcess 或 ShellExecuteEx 作为命令行参数.

备注

当通过 ComSpec(cmd.exe) 运行程序时 -- 也许是因为你需要重定向程序的输入或输出 -- 如果可执行文件的路径或名称中包含空格, 那么整个字符串应该用一对外置引号来括起. 在下面的例子中, 外部的引号用黄色高亮显示:

Run A_ComSpec ' /c ""C:\My Utility.exe" "param 1" "second param" >"C:\My File.txt""'

如果 Target 为准确路径时可轻微提升性能, 例如使用 Run 'C:\Windows\Notepad.exe "C:\My Documents\Test.txt"' 代替 Run "C:\My Documents\Test.txt".

Run 还可以打开指定的 CLSID 文件夹. 它们中的大多数可以通过使用 shell: 前缀打开. 有些不用前缀也能打开. 例如:

Run "shell:::{D20EA4E1-3957-11D2-A40B-0C5020524153}" ; Windows Tools.
Run "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"  ; 打开此电脑(以前是我的电脑或计算机).
Run "::{645FF040-5081-101B-9F08-00AA002F954E}"  ; 打开回收站.

系统动词对应于资源管理器中文件的右键菜单中可用的操作. 如果启动文件时没有指定动词, 则使用该文件类型的默认动词(通常为 "打开"). 如果指定了, 则动词后应该跟着目标文件的名称. 目前支持下列动词:

Verb(动词) | 描述
*verb | 任何系统定义或自定义的动词. 例如: Run "*Compile " A_ScriptFullPath. *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 动词相当于文件右键菜单的 以管理员身份运行. 例如, 以下代码尝试以管理员权限重启当前脚本:

full_command_line := DllCall("GetCommandLine", "str")

if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
    try
    {
        if A_IsCompiled
            Run '*RunAs "' A_ScriptFullPath '" /restart'
        else
            Run '*RunAs "' A_AhkPath '" /restart "' A_ScriptFullPath '"'
    }
    ExitApp
}

MsgBox "A_IsAdmin: " A_IsAdmin "`nCommand line: " full_command_line

如果用户取消了 User Account Control (UAC) 对话框, 或者由于其他原因启动失败, 脚本就会直接退出.

如果在调用 ExitApp 之前启动新的脚本实例, 使用 /restart 可以确保不显示单一实例的提示弹窗.

如果禁用了 UAC, *RunAs 将不会提权启动进程. 在命令行中检查 /restart 可以确保在这种情况下脚本不会进入失控循环. 注意 /restart 是一个内置的开关, 所以其不包括在命令行参数数组中.

可以根据脚本的需要修改上面的例子:

  • 如果脚本的确需要管理员权限, 在 *RunAs 未能提升脚本权限的情况下(例如, 因为 UAC 被禁用), 第二次检查 A_IsAdmin.
  • 在用户取消了 UAC 提示的情况下, 为了保持脚本的运行, 可以将 ExitApp 移到 try 块中.
  • 在重新启动失败的情况下, 为了保持脚本的运行(比如脚本文件已被重命名或删除), 移除 ExitApp 并且使用 RunWait 代替 Run. 若是成功, /restart 使新实例终止旧实例. 若是失败, 新实例的退出及 RunWait 返回.

AutoHotkey 的安装程序为 .ahk 文件注册 RunAs 动词, 这允许 Run "*RunAs script.ahk" 以管理员权限启动脚本.

相关

RunAs, 进程函数, Exit, CLSID 列表, DllCall

示例

Run 能够从任何目录下启动 Windows 系统程序. 注意, 可执行文件的扩展名如 .exe 可以省略.

Run "notepad"

Run 能够启动 URLs:

以下是在用户的默认网页浏览器中打开一个互联网地址.

Run "https://www.google.com"

以下打开默认的电子邮件应用程序并填写收件人.

Run "mailto:someone@somedomain.com"

下面的操作和上面一样, 加上主题和正文.

Run "mailto:someone@somedomain.com?subject=This is the subject line&body=This is the message body's text."

在最大化应用程序中打开文档, 并在失败时显示一个自定义的错误信息.

try Run("ReadMe.doc", , "Max")
if A_LastError
    MsgBox "The document could not be launched."

在最小化状态下运行 dir 命令, 并将输出结果存储在文本文件中. 之后, 文本文件及其属性对话框将被打开.

RunWait A_ComSpec " /c dir C:\ >>C:\DirTest.txt", , "Min"
Run "C:\DirTest.txt"
Run "properties C:\DirTest.txt"
Persistent ; 保持脚本不退出, 否则属性对话框将关闭.

Run 能够启动 CLSID:

下面打开回收站.

Run "::{645FF040-5081-101B-9F08-00AA002F954E}"

下面打开此电脑(以前是我的电脑或计算机).

Run "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"

要连续运行多个命令, 请每个命令之间使用 "&&".

Run A_ComSpec "/c dir /b > C:\list.txt && type C:\list.txt && pause"

以下自定义函数可以用来运行一个命令并检索其输出, 或者一次性运行多个命令并检索其输出. 有关 WshShell 对象, 请参阅 Microsoft Docs.

MsgBox RunWaitOne("dir " A_ScriptDir)

MsgBox RunWaitMany("
(
echo Put your commands here,
echo each one will be run,
echo and you'll get the output.
)")

RunWaitOne(command) {
    shell := ComObject("WScript.Shell")
    ; 通过 cmd.exe 执行单条命令
    exec := shell.Exec(A_ComSpec " /C " command)
    ; 读取并返回命令的输出
    return exec.StdOut.ReadAll()
}

RunWaitMany(commands) {
    shell := ComObject("WScript.Shell")
    ; 打开 cmd.exe 禁用命令回显
    exec := shell.Exec(A_ComSpec " /Q /K echo off")
    ; 发送并执行命令, 使用新行分隔
    exec.StdIn.WriteLine(commands "`nexit")  ; 总是在最后退出!
    ; 读取并返回所有命令的输出
    return exec.StdOut.ReadAll()
}

在新的 AutoHotkey 进程中执行给定的代码.

ExecScript(Script, Wait:=true)
{
    shell := ComObject("WScript.Shell")
    exec := shell.Exec("AutoHotkey.exe /ErrorStdOut *")
    exec.StdIn.Write(Script)
    exec.StdIn.Close()
    if Wait
        return exec.StdOut.ReadAll()
}

; 示例:
ib := InputBox("Enter an expression to evaluate as a new script.",,, 'Ord("*")')
if ib.result = "Cancel"
    return
result := ExecScript('FileAppend ' ib.value ', "*"')
MsgBox "Result: " result


RunAs - 语法 & 使用 | AutoHotkey v2

RunAs

指定一组用户凭据, 用于后续所有的 Run 和 RunWait 函数.

RunAs User, Password, Domain

参数

User

类型: 字符串

如果省略此参数和其他所有参数, 则关闭 RunAs 的功能, 这样会恢复 Run 和 RunWait 到它们默认的行为. 否则, 指定新进程创建所用的账户名.

Password

类型: 字符串

如果为空或省略, 默认为空密码. 否则, 请指定 User 的密码. 请注意, 默认情况下不允许传递空白密码, 根据操作系统策略 "帐户: 使用空密码的本地帐户只允许进行控制台登录".

Domain

类型: 字符串

如果为空或省略, 将使用本地账户. 否则, 请指定 User 的域名. 如果这样不起作用, 请尝试使用 @YourComputerName.

备注

如果脚本由于用户帐户控制(UAC) 而以受限特权运行, 则即使使用 RunAs, 其启动的任何程序通常也将受到限制. 要提升权限, 请改用 Run *RunAs.

此命令只通知 AutoHotkey 为后续所有的 Run 和 RunWait 函数使用(或不使用) 替换的用户凭据. 该函数不验证证书.

如果指定了无效的 User, Password 或 Domain, 则 Run 和/或 RunWait 将显示一条错误消息来说明问题(除非 Try/Catch 语句捕获了此错误).

当 RunAs 功能生效时, Run 和 RunWait 将无法启动文档, URL 或系统动词. 换句话说, 要启动的文件必须是可执行文件.

为了使此函数起作用, "Secondary Logon" 服务必须设置为手动或自动(如果设置为手动, 则操作系统会根据需要自动启动).

相关

Run, RunWait

示例

以管理员身份打开注册表编辑器.

RunAs "Administrator", "MyPassword"
Run "RegEdit.exe"
RunAs  ; 恢复为普通行为.


Send - 语法 & 使用 | AutoHotkey v2

Send / SendText / SendInput / SendPlay / SendEvent

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

Send Keys
SendText Keys
SendInput Keys
SendPlay Keys
SendEvent Keys

参数

Keys

类型: 字符串

要发送的按键序列.

默认情况下(也就是说, 如果既不使用 SendText, 也不使用原始模式或文本模式), 字符 ^+!#{} 具有特殊含义. 字符 ^+!# 分别代表修饰符键 Ctrl, Shift, Alt 和 Win. 他们仅影响紧跟着的下一个键. 若要发送修饰符本身对应的键, 将按键名称括在大括号中. 若要按下(按住) 或松开按键, 下面所示的单词 "down" 或 "up" 跟在按键名称的后面.

符号 按键 按下 松开 示例
^ {Ctrl} {Ctrl down} {Ctrl up} Send "^{Home}" 按下 Ctrl+Home
+ {Shift} {Shift down} {Shift up} Send "+abC" 发送文本 "AbC"
Send "!+a" 按下 Alt+Shift+A
! {Alt} {Alt down} {Alt up} Send "!a" 按下 Alt+A
# {LWin}
{RWin} 		{LWin down}
{RWin down} 		{LWin up}
{RWin up} 		Send "#e" 按住 Win 键时, 按下字母 E

注意: 由于大写字母是通过发送 Shift 产生的, 因此在某些程序中 A 和 a 会产生不同的效果. 例如, !A 按下 Alt+Shift+A, 而 !a 按下 Alt+A. 如果不确定, 请使用小写字母.

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

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

Send 的变体

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

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

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

SendPlay: 不推荐. 类似于 SendInput, 除了它在 Windows 11 和更高版本的系统中, 或者即使脚本以管理员身份运行, 但如果启用了用户帐户控制(UAC) 时可能根本没有作用. 有关详情, 请参阅 SendPlay.

SendEvent: SendEvent 使用 Windows keybd_event 函数发送键击(有关详情, 请在 Microsoft Docs 搜索). 发送击键的速率由 SetKeyDelay 决定. 通过 SendMode 可以使 Send 等同于 SendEvent.

特殊模式

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

原始模式

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

原始模式不影响转义序列和表达式的解释. 例如, Send "{Raw}``100`%" 发送字符 `100%.

文本模式

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

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

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

盲从模式

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

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

单词 "Blind" 后面可以用一个或多个修饰符号(!#^+) 以便在需要时自动释放这些修饰符. 例如, *^a::Send "{Blind^}b" 在按下 Ctrl+Shift+A 时, 将发送 Shift+B 而不是 Ctrl+Shift+B. {Blind!#^+} 可以在需要的时候释放所有的修饰符, 但是会启用盲从模式的其他效果.

在重映射按键时, 盲从模式可以在其内部使用. 例如, 重映射 a::b 会发生这样的情况: 1) 输入 "a" 时会映射为 "b"; 2) 输入大写字母 "A" 时映射为大写字母 "B"; 并且 3) 按下 Ctrl+A 时映射为按下 Ctrl+B. 如果任何修饰符指定为源按键(包括 Shift 如果源按键是大写字母), 则如上所述, 这些修饰符被排除在外. 例如 ^a::b 产生的是正常的 B, 而不是 Ctrl+B.

SendText 或 ControlSendText 不支持 {Blind}; 请使用 {Blind}{Text} 代替.

SendPlay 不完全支持盲从模式, 尤其是在处理修饰键时(Ctrl, Alt, Shift 和 Win).

Key 名称

下表中列出了可以发送的特殊按键(每个按键名称必须用大括号括起来):

按键名称 | 描述
{F1} - {F24} | 功能键. 例如: {F12} 表示 F12.
{!} !
{#} #
{+} +
{^} ^
{{} {
{}} }
{Enter} | 主键盘上的 Enter
{Escape} 或 {Esc} | Esc
{Space} | Space(这只适用于出现在要发送的字符串的开头或结尾的空格 -- 而在中间的空格是原义的)
{Tab} | Tab
{Backspace} 或 {BS} | Backspace
{Delete} 或 {Del} | Del
{Insert} 或 {Ins} | Ins
{Up} ↑(主键盘上的向上键)
{Down} ↓(主键盘上的向下键)
{Left} ←(主键盘上的向左键)
{Right} →(主键盘上的向右键)
{Home} | Home(主键盘)
{End} | End(主键盘)
{PgUp} | PgUp(主键盘)
{PgDn} | PgDn(主键盘)
{CapsLock} | CapsLock(使用 SetCapsLockState 更可靠). 发送 {CapsLock} 之前可能要求 SetStoreCapsLockMode False.
{ScrollLock} | ScrollLock(另请参阅: SetScrollLockState)
{NumLock} | NumLock(另请参阅: SetNumLockState)
{Control} 或 {Ctrl} | Ctrl(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)
{LControl} 或 {LCtrl} | 左 Ctrl(技术信息: 发送左边键的虚拟键码而不是中性键)
{RControl} 或 {RCtrl} | 右 Ctrl
{Control down} 或 {Ctrl down} | 按住 Ctrl 键直到发送 {Ctrl up}. 要按住左边或右边的键, 请使用 LCtrl 或 RCtrl 替换 Ctrl.
{Alt} | Alt(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)
{LAlt} | 左 Alt(技术信息: 发送左边键的虚拟键码而不是中性键)
{RAlt} | 右 Alt(或 AltGr, 取决于键盘布局)
{Alt down} | 按住 Alt 直到发送 {Alt up}. 要按住左边或右边的键, 请使用 LAlt 或 RAlt 替换 Alt.
{Shift} | Shift(技术信息: 发送中性键的虚拟键码而不是左边键的扫描码)
{LShift} | 左 Shift(技术信息: 发送左边键的虚拟键码而不是中性键)
{RShift} | 右 Shift
{Shift down} | 按住 Shift 直到发送 {Shift up}. 要按住左边或右边的键, 请使用 LShift 或 RShift 替换 Shift.
{LWin} | 左 Win
{RWin} | 右 Win
{LWin down} | 按住左 Win 直到发送 {LWin up}
{RWin down} | 按住右 Win 直到发送 {RWin up}
{AppsKey} | Menu (调用右键点击或上下文菜单)
{Sleep} | Sleep
{ASC nnnnn}

发送 Alt+nnnnn 小键盘按键组合, ，可用于生成键盘上不存在的特殊字符.

要生成可打印 ASCII 字符或系统的 OEM(DOS) 代码页中的其他字符, 请指定一个介于 1 和 255 之间的数字. DllCall("GetOEMCP", "UInt") 返回当前 OEM 代码页编号, 如 437(美国) 货 850(西欧).

要生成 ANSI 字符(大多数语言中的标准), 请指定一个介于 128 和 255 之间的数字, 但需要在数字前加上一个前导零, 例如 {Asc 0133}. DllCall("GetACP", "UInt") 返回当前 ANSI 代码页编号, 如 1252(美国, 西欧等.).

要生成 Unicode 字符, 请指定一个介于 256 和 65535 之间的数字(不带前导零). 但是, 有些应用程序不支持这种方法. 对于替代方法, 请参阅下面的部分.
{U+nnnn}

发送 Unicode 字符, 其中 nnnn 为字符的不包括 0x 前缀的十六进制值. 通常不需要这么做, 因为 Send 和 ControlSend 自动支持 Unicode 文本.

会使用 SendInput() 或 WM_CHAR 来发送字符, 并且当前的发送模式没有效果. 以这种方式发送的字符通常不会触发快捷键或热键.

{vkXX}
{scYYY}
{vkXXscYYY}

发送虚拟键为 XX 和扫描码为 YYY 的按键. 例如: Send "{vkFFsc159}". 如果省略 sc 或 vk 部分, 则发送最合适的值.

XX 和 YYY 的值是十六进制的, 通常可以从主窗口的 View->Key history 菜单项中确定. 另请参阅: 特殊按键

警告: 以这种方式组合 vk 和 sc 仅在 Send 有效.
{Numpad0} - {Numpad9} | 小键盘上的数字键(与 NumLock 打开时输入的一样). 例如: {Numpad5} 为数字 5.
{NumpadDot} | .(小键盘上的点)(与 NumLock 打开时输入的一样).
{NumpadEnter} | 小键盘上的 Enter
{NumpadMult} | *(小键盘上的乘号)
{NumpadDiv} | /(小键盘上的除号)
{NumpadAdd} | +(小键盘上的加号)
{NumpadSub} | -(小键盘上的减号)
{NumpadDel} | 小键盘上的 Del(当 NumLock 为 OFF 时, 此键和以下的小键盘按键将被使用)
{NumpadIns} | 小键盘上的 Ins
{NumpadClear} | 小键盘上的 Clear 键(在 NumLock 关闭时, 通常为 5).
{NumpadUp} | 小键盘上的 ↑(向上)
{NumpadDown} | 小键盘上的 ↓(向下)
{NumpadLeft} | 小键盘上的 ←(向左)
{NumpadRight} | 小键盘上的 →(向右)
{NumpadHome} | 小键盘上的 Home
{NumpadEnd} | 小键盘上的 End
{NumpadPgUp} | 小键盘上的 PgUp
{NumpadPgDn} | 小键盘上的 PgDn
{Browser_Back} | 浏览器 "后退" 按钮
{Browser_Forward} | 浏览器 "前进" 按钮
{Browser_Refresh} | 浏览器 "刷新" 按钮
{Browser_Stop} | 浏览器 "停止" 按钮
{Browser_Search} | 浏览器 "搜索" 按钮
{Browser_Favorites} | 浏览器 "收藏" 按钮
{Browser_Home} | 启动浏览器并打开主页
{Volume_Mute} | 主音量静音/取消静音. 通常相当于 SoundSetMute -1.
{Volume_Down} | 减小主音量. 通常相当于 SoundSetVolume -5.
{Volume_Up} | 增加主音量. 通常相当于 SoundSetVolume "+5".
{Media_Next} | 在媒体播放器中播放下一曲目
{Media_Prev} | 在媒体播放器中播放前一曲目
{Media_Stop} | 停止媒体播放器
{Media_Play_Pause} | 播放/暂停媒体播放器
{Launch_Mail} | 启动电子邮件程序
{Launch_Media} | 启动媒体播放器
{Launch_App1} | 启动用户程序 1
{Launch_App2} | 启动用户程序 2
{PrintScreen} | PrtScr
{CtrlBreak} | Ctrl+Pause
{Pause} | Pause
{Click [Options]} | Send 鼠标点击使用的选项与 Click 函数中的一样. 例如, Send "{Click}" 会在鼠标光标当前位置点击一次鼠标左键, 而 Send "{Click 100 200}" 则在坐标 100, 200 处点击(这里的坐标模式取决于 CoordMode). 要移动鼠标而不点击, 请在坐标后指定 0; 例如: Send "{Click 100 200 0}". 鼠标点击之间的延迟由 SetMouseDelay 决定(而不是 SetKeyDelay).
{WheelDown}, {WheelUp}, {WheelLeft}, {WheelRight}, {LButton}, {RButton}, {MButton}, {XButton1}, {XButton2}

在光标的当前位置发送一个鼠标按钮事件(要控制位置和其他选项, 请使用上面的 {Click}). 鼠标点击之间的延迟由 SetMouseDelay 决定.

LButton 和 RButton 分别对应鼠标的主按钮和次按钮. 通常鼠标的主按钮(LButton) 在左边, 但是用户可以通过系统设置来交换按钮.
{Blind} | 启用盲从模式, 通过禁用一些通常会自动完成的事情, 让脚本有了更多的控制权, 从而使事情一般都能正常工作. {Blind} 必须出现在字符串的开头.
{Raw} | 启用原始模式, 这将导致以下字符按原义解释: ^+!#{}. 虽然 {Raw} 不需要出现在字符串的开头, 但一旦指定, 它将在字符串的其余部分保持有效.
{Text} | 启用文本模式, 它发送的是字符流而不是按键. 与原始模式一样, 文本模式会使以下字符按原义解释: ^+!#{}. 虽然 {Text} 不需要出现在字符串的开头, 但一旦指定, 它将在字符串的其余部分保持有效.

重复或按住按键

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

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

按住或释放按键: 用大括号括起按键名称和单词 Down 或 Up. 例如:

Send "{b down}{b up}"
Send "{TAB down}{TAB up}"
Send "{Up down}"  ; 按下向上键.
Sleep 1000  ; 按住 1 秒.
Send "{Up up}"  ; 释放向上键.

使用上面的方法按住一个按键后, 这个期间它不会像您实际按住这个按键一样自动重复(这是由于自动重复是一个驱动/硬件的特性). 不过, 可以使用 Loop 来模拟自动重复. 下面的例子中发送 20 次 tab 键击:

Loop 20
{
    Send "{Tab down}"  ; 自动重复由连续的按下事件组成(没有弹起事件).
    Sleep 30  ; 在两次键击之间的毫秒数(或使用 SetKeyDelay 设置).
}
Send "{Tab up}"  ; 松开按键.

默认情况下, 如果一个修饰键在发送时被 "按下", 则 Send 不会自动释放该修饰键(Control, Shift, Alt 和 Win) . 例如, 如果用户物理按下 Ctrl 时, Send "a" 的行为类似于 Send "{Blind}{Ctrl up}a{Ctrl down}", 但 Send "{Ctrl Down}" 后面接着 Send "a" 将产生 Ctrl+A. DownTemp 和 DownR 可以用来覆盖这种行为. DownTemp 和 DownR 与 Down 具有同样的效果, 除了修饰键(Control, Shift, Alt 和 Win).

DownTemp 告诉后续的发送, 该键不是永久按下的, 只要有按键需要就可以释放. 例如, 在发送 Send "{Control DownTemp}" 之后, 再 Send "a" 将产生一个正常的 A, 而不是 Ctrl+A. 任何使用 Send 的方法都有可能永久地释放修饰键, 所以 DownTemp 并不是重映射修饰键的理想选择.

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

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

备注

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

  • SendEvent 和 SendInput 使用带有 a href="https://learn.microsoft.com/windows/win32/api/winuser/ns-winuser-keybdinput#keyeventf_unicode">KEYEVENTF_UNICODE 标志的 SendInput().
  • SendPlay 使用 Alt+nnnnn 方法, 只有在目标应用程序支持的情况下才会产生 Unicode 字符.
  • ControlSend 发布 WM_CHAR 消息.

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

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

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

如果字母存在于当前的键盘布局中, 那么它总是以布局与该字母相关联的键码发送(除非使用了文本模式, 在这种情况下, 该字符将通过其他方式发送). 换句话说, 上面的部分只适用于非拉丁语系的布局, 如俄语.

修饰键状态: 当 Send 需要改变 Win 或 Alt 修饰键的状态时(比如用户按住其中一个键), 它可能会注入额外的按键(默认为 Ctrl) 来阻止开始菜单或窗口菜单的出现. 有关详情, 请参阅 A_MenuMaskKey.

BlockInput 对比 SendInput/SendPlay: 尽管 BlockInput 函数可以用来防止用户物理输入的任何按键破坏模拟按键的流, 但通常最好使用 SendInput 或 SendPlay 这样按键和鼠标点击就不会中断. 这是因为与 BlockInput 不同的是, SendInput/Play 不会在发送过程中丢弃用户输入的内容; 相反, 这样的按键会被缓冲并在之后发送.

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

由于操作系统不允许模拟 Ctrl+Alt+Del 组合, 所以类似 Send "^!{Delete}" 这样的操作是没有效果的.

当活动窗口以管理身份运行而当前脚本不是时, Send 可能没有效果. 这是由于一种叫做用户界面特权隔离的安全机制造成的.

SendInput

一般情况下, SendInput 是发送按键和鼠标点击的首选方法, 因为它的速度和可靠性都很高. 在大多数情况下, SendInput 几乎是瞬间完成的, 即使是发送长字符串时也是如此. 由于 SendInput 的速度如此之快, 它的可靠性也更高, 因为这样其他一些窗口更没有机会出乎意料地弹出并打断按键. 用户在 SendInput 过程中输入的任何东西都会被推迟到之后再进行, 从而进一步提高了可靠性.

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

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

如果脚本安装了底层键盘钩子, SendInput 会在执行之前自动卸载它, 并在执行后重新安装. 因此, SendInput 通常不能触发脚本自己的钩子热键或 InputHooks. 之所以暂时卸载钩子, 是因为它的存在会使 SendInput 的所有优势失效, 使其不如 SendPlay 和 SendEvent. 然而, 这只能对脚本自己的钩子执行, 如果检测到外部钩子, 则不会执行, 如下所述.

如果执行 SendInput 的脚本 以外的 脚本安装了低级键盘钩子, 则 SendInput 会自动恢复为 SendEvent(或当 SendMode "InputThenPlay" 生效时为 SendPlay). 这是由于外部钩子的存在让 SendInput 失去了所有的优势, 使它不如 SendPlay 和 SendEvent 两者. 然而, 由于 SendInput 无法检测到除 AutoHotkey v1.0.43+ 以外的程序中的低级钩子, 所以在这些情况下它不会还原, 使得它的可靠性不如 SendPlay/Event.

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

SendPlay

不推荐的: 在 Windows 11 或较新的系统中, 或者如果启用了用户账户控制(UAC), 即使脚本以管理员身份运行, SendPlay 可能没有效果(有关详情, 请参阅 FAQ).

SendPlay 最大的优势在于它能在更多的游戏中 "回放" 按键和鼠标点击. 例如, 某款游戏只有在有 SendPlay 选项的情况下才能接受热字串.

在这三种发送模式中, SendPlay 是最特别的, 因为它本身并不模拟按键和鼠标点击. 相反, 它创建了一系列的事件(消息), 直接流向活动窗口(类似于 ControlSend, 但级别较低). 因此, 不会触发热键或热字串.

和 SendInput 一样, SendPlay 的按键与用户键入的按键互不干扰. 因此, 如果用户在 SendPlay 期间碰巧输入了一些东西, 这些键程会被推迟到之后.

虽然 SendPlay 比 SendInput 要慢很多, 但它通常比传统的 SendEvent 模式要快(即使 KeyDelay 为 -1 时, 也是如此).

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

SendPlay 不使用 SetKeyDelay 和 SetMouseDelay 的标准设置. 相反, 它默认为无延迟, 可以按照下面的例子来改变:

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

SendPlay 无法打开或关闭 CapsLock, NumLock 或 ScrollLock. 同样, 它也无法改变 GetKeyState 所看到的键的状态, 除非按键被发送到脚本自己的一个窗口. 即使如此, 任何对左/右修饰键(例如 RControl) 的改变也只能通过它们的中性对应键(例如 Control) 来检测. 此外, SendPlay 还有其他限制, 在 SendMode 页面上有描述.

与 SendInput 和 SendEvent 不同, 用户可以通过按下 Ctrl+Alt+Del 或 Ctrl+Esc 来中断 SendPlay. 当这种情况发生时, 剩余的按键不会被发送, 但是脚本会继续执行, 就像 SendPlay 已经正常完成一样.

虽然 SendPlay 可以发送 LWin 和 RWin 事件, 但是它们会直接发送到活动窗口, 而不是执行它们的在操作系统中的原生功能. 要解决这个问题, 请使用 SendEvent. 例如, SendEvent "#r" 将显示开始菜单的运行对话框.

相关

SendMode, SetKeyDelay, SetStoreCapsLockMode, 转义序列(例 `n), ControlSend, BlockInput, 热字串, WinActivate

示例

输入两行签名.

Send "Sincerely,{enter}John Smith"

选择 File->Save 菜单(Alt+F 后面跟着 S).

Send "!fs"

到文本的末尾然后发送四次 shift 和左方向键组合的键击.

Send "{End}+{Left 4}"

通过最快的方法发送一长串原始字符.

SendInput "{Raw}A long series of raw characters sent via the fastest method."


SendLevel - 语法 & 使用 | AutoHotkey v2

SendLevel

控制热键和热字串是否忽略模拟的键盘和鼠标事件.

SendLevel Level

参数

Level

类型: 整数

介于 0 和 100 之间的整数.

返回值

整数: 整数

函数返回以前的设置; 一个介于 0 到 100 之间的整数.

备注

如果 SendLevel 没有使用, 则默认级别为 0.

默认情况下, 钩子 热键和热字串会忽略由任何 AutoHotkey 脚本生成的键盘和鼠标事件. 在某些情况下, 你可能希望覆盖这种行为; 例如, 可使用重映射键来触发其他热键. SendLevel 和 #InputLevel 提供了实现此目的的方法.

SendLevel 设置由当前脚本线程生成的事件级别, 而 #InputLevel 设置在它下面的所有热键或热字串的级别. 要让脚本生成的事件触发钩子热键或热字串, 则此事件的发送级别必须高于热键或热字串的输入级别.

兼容性:

  • SendPlay 不受 SendLevel 影响.
  • SendInput 会受 SendLevel 影响, 但在 SendInput 执行时其所在脚本中的钩子热键无法激活, 因为它会让钩子暂时失效. 但是, 当 Send 或 SendInput 恢复为 SendEvent, 它可以激活脚本自己的热键.
  • 使用 "reg" 方法实现的热键不能区分物理和模拟输入, 所以不会受 SendLevel 的影响. 然而, 级别高于 0 的热键总是使用了键盘或鼠标钩子.
  • 热字串仅使用 #InputLevel 来确定最后一个键入的字符是否应该触发热字串. 例如, 无论 #InputLevel 设置如何, 热字串 ::btw:: 都可以通过级别为 1 或更高级别的发送 btw 和物理输入结束字符来触发. 这是因为热字串识别的工作原理是将除 0 级以外的所有级别的输入收集到单个全局缓冲区中.
  • 自动替换型热字串生成事件的级别始终为 0, 因为通常在替换文本时不希望触发其他热字串或热键. 要解决此问题, 请使用非自动替换型热字串和 SendEvent 函数.
  • 即使使用了 SendLevel, 通过 ASC (Alt+nnnnn) 方法发送字符也不能触发热字串.
  • 通过 SendEvent 的 {Text} 模式, {U+nnnn} 或 Unicode fallback method 发送字符可以触发热字串.

内置变量 A_SendLevel 包含了当前设置.

每个新启动的热键或热字串线程都以一个等于热键或热字串输入级别的发送级别开始. 每个新启动的其他线程(例如, 自定义菜单项或计时子程序) 会以其默认设置开始, 一般为 0, 不过可以在脚本启动中使用此函数进行改变.

如果在脚本启动中使用 SendLevel, 它还会影响键盘和鼠标的重映射.

相关

#InputLevel, Send, Click, MouseClick, MouseClickDrag

示例

SendLevel 允许触发另一个脚本的热键和热字符串, 而通常情况下是不会的.

SendLevel 1
SendEvent "btw{Space}" ; 生成 "by the way ".

; 这可以在单独的脚本中定义:
::btw::by the way


SendMessage - 语法 & 使用 | AutoHotkey v2

SendMessage

发送消息到窗口或控件并等待回复.

Result := SendMessage(MsgNumber , wParam, lParam, Control, WinTitle, WinText, ExcludeTitle, ExcludeText, Timeout)

参数

MsgNumber

类型: 整数

要发送的消息的编号. 请参阅消息列表来确定编号.

wParam, lParam

类型: 整数或对象

如果省略其中一个, 则发送 0. 否则, 请指定消息的第一个和第二个组件.

每个参数必须是一个整数或一个具有 Ptr 属性的对象, 比如 Buffer. 对于需要指向字符串指针的消息, 使用 Buffer 或 StrPtr 函数. 如果通过将变量的地址传递给 SendMessage 来改变变量所包含的字符串, 那么之后必须通过调用 VarSetStrCapacity(&MyVar, -1) 来更新变量的长度.

如果 AutoHotkey 或目标窗口是 32 位的, 则只使用参数的低 32 位; 也就是说, 如果超出了有符号值的范围 -2147483648 到 2147483647(-0x80000000 to 0x7FFFFFFF), 或者超出了无符号值的范围 0 到 4294967295(0xFFFFFFFF), 则值会被截断. 如果 AutoHotkey 和目标窗口都是 64 位的, 可以使用 AutoHotkey 所支持的任何整数值.

Control

类型: 字符串, 整数或对象

如果省略, 则消息会被直接发送到目标窗口而不是它的某个控件. 否则, 指定控件的 ClassNN, 文本或 HWND, 或者是一个具有 Hwnd 属性的对象. 有关详情, 请参阅控件参数.

如果这个参数指定了一个 HWND(作为一个整数或对象), 那么它不需要是一个控件(子窗口) 的 HWND. 也就是说, 它也可以是一个顶层窗口的 HWND.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改. 指定 0 无限等待. 负数导致 SendMessage 立即超时.

Timeout

类型: 整数

如果省略, 默认为 5000. 否则, 请指定 the等待目标窗口处理消息的最大毫秒数. 如果消息在这段时间内没有被处理, 则会抛出 TimeoutError.

返回值

类型: 整数

该函数返回消息的结果, 有时可能是一个 "回复", 这取决于消息的性质及其目标窗口.

可能的值范围取决于目标窗口和正在运行的 AutoHotkey 版本. 当使用 32 位版本的 AutoHotkey, 或者如果目标窗口是 32 位的, 结果是一个 32 位的无符号整数, 介于 0 和 4294967295 之间. 当使用 64 位版本的 AutoHotkey 和 64 位窗口时, 结果是介于 -9223372036854775808 和 9223372036854775807 之间的 64 位有符号整数.

如果期望结果是一个 32 位有符号的整数(从 -2147483648 到 2147483648 的值), 它可以被截断为 32 位, 并转换成一个有符号的值, 如下所示:

MsgReply := MsgReply << 32 >> 32

即使在 64 位的 AutoHotkey 上, 这种转换也是必要的, 因为来自 32 位窗口的结果是零扩展的. 例如, 来自 32 位窗口的 -1 结果在任何版本的 AutoHotkey 上都被视为 0xFFFFFFFF, 而来自 64 位窗口的 -1 在 32 位 AutoHotkey 被视为 0xFFFFFFFF, 在 64 位 AutoHotkey 被视为 -1.

错误处理

如果找不到窗口或控件, 则抛出 TargetError.

如果消息超时, 则抛出 TimeoutError.

如果消息不能被发送, 则抛出 OSError. 例如, 如果目标窗口运行在比脚本更高的完整性级别上(例如, 它以管理员身份运行, 而脚本不是), 消息可能被阻止.

备注

应该小心使用该函数, 因为发送消息到错误的窗口(或发送错误的消息) 可能导致意外的行为或者甚至让目标应用程序崩溃. 这是因为大多数应用程序并不是设计用于从外部来源中接受某些类型的消息.

SendMessage 等待目标窗口处理消息, 直到超时期结束. 与此相反, PostMessage 将消息放入与目标窗口相关联的消息队列中, 而无需等待确认或回复.

字符串参数必须按地址传递. 例如:

ListVars
WinWaitActive "ahk_class AutoHotkey"
SendMessage 0x000C, 0, StrPtr("New Title")  ; 0X000C is WM_SETTEXT

要发送消息到系统中的所有窗口, 包括隐藏或禁用的那些, 请在 WinTitle 中指定 0xFFFF(0xFFFF 是 HWND_BROADCAST). 这种技术应该只用于目标为广播的消息, 例如:

SendMessage 0x001A,,,, 0xFFFF  ; 0x001A is WM_SETTINGCHANGE

要让脚本接收消息, 请使用 OnMessage.

请参阅消息指南来查看使用这些命令的介绍.

相关

PostMessage, 消息列表, 消息指导, OnMessage, Automating Winamp, DllCall, ControlSend, MenuSelect

示例

通过热键关闭显示器. 在 SendMessage 行中, 将数字 2 替换为 -1 以打开显示器, 或将其替换为 1 以激活显示器的低功耗模式.

#o::  ; Win+O 热键
{
    Sleep 1000  ; 让用户有机会释放按键(以防释放它们时再次唤醒显视器).
    ; 关闭显示器:
    SendMessage 0x0112, 0xF170, 2,, "Program Manager"  ; 0x0112 is WM_SYSCOMMAND, 0xF170 is SC_MONITORPOWER.
}

启动用户选择的屏幕保护程序.

SendMessage 0x0112, 0xF140, 0,, "Program Manager"  ; 0x0112 为 WM_SYSCOMMAND, 而 0xF140 为 SC_SCREENSAVE.

向上滚动一行(用于含垂直滚动条的控件).

SendMessage 0x0115, 0, 0, ControlGetFocus("A")

向下滚动一行(具有竖直滚动栏的控件).

SendMessage 0x0115, 1, 0, ControlGetFocus("A")

这个例子请求 Winamp 的当前活动的轨道编号(有关详情, 请参阅 Automating Winamp.

SetTitleMatchMode 2
TrackNumber := SendMessage(0x0400, 0, 120,, "- Winamp")
TrackNumber++  ; Winamp 的计数从 "0" 开始, 所以加 1 进行调整.
MsgBox "Track #" TrackNumber " is active or playing."

找出 AHK 脚本的进程 ID(另一种方法是 WinGetPID).

SetTitleMatchMode 2
DetectHiddenWindows true
PID := SendMessage(0x0044, 0x405, 0, , "SomeOtherScript.ahk - AutoHotkey v")
MsgBox PID " is the process id."


SendMode - 语法 & 使用 | AutoHotkey v2

SendMode

使 Send 等同于 SendEvent 或 SendPlay, 而不是默认的(SendInput). 也使 Click 和 MouseMove/Click/Drag 使用指定的方法.

SendMode Mode

参数

Mode

类型: 字符串

指定以下单词之一:

Event: 将 Send 切换到 SendEvent 方法, 适用于 SendText, Click, MouseMove, MouseClick 和 MouseClickDrag.

Input: 使 Send, SendText, Click, MouseMove, MouseClick 和 MouseClickDrag 使用 SendInput 方法. 已知限制:

  • Windows 资源管理器忽略 SendInput 的特定导航热键的模拟, 例如 Alt+←. 要解决这个问题, 可以使用 SendEvent "!{Left}" 或 SendInput "{Backspace}".

InputThenPlay: 与上面相同, 不同之处在于当 SendInput 不可用时, 它并没有退回到 Event 模式, 而是恢复为 Play 模式(如下). 当 SendInput 不可用时, 这也会导致 SendInput 函数本身返回到 Play 模式.

Play: 切换到 SendPlay 方法, 适用于 Send, SendText, Click, MouseMove, MouseClick 和 MouseClickDrag. 已知限制:

  • 不能发送在当前键盘布局上不存在的字符(例如英语中的 Ô). 为了解决这个问题, 请使用 SendEvent.
  • 在 RichEdit 控件(可能还有其他的, 例如 WordPad 和 Metapad), 模拟鼠标拖动可能没有效果. 要为特殊的拖动使用替换模式, 请参照此例: SendEvent "{Click 6 52 Down}{Click 45 52 Up}".
  • 模拟鼠标滚轮的滚动只进行一个方向上的移动(通常是向下, 但在一些程序中可能是向上). 此外, 滚轮的滚动在类似 MS Word 和 Notepad 的程序中可能没有效果. 要为特殊的滚动使用替换模式, 请参照此例: SendEvent "{WheelDown 5}".
  • 当在脚本启动中使用 SendMode "Play" 时, 会影响所有的重映射按键并可能失去它们的某些功能. 有关详情, 请参阅 SendPlay 重映射限制.
  • SendPlay 不会触发 AutoHotkey 的热键或热字符串, 也不会触发其他程序或操作系统注册的全局热键.

返回值

类型: 字符串

函数返回以前的设置; Event, Input, InputThenPlay 或 Play.

备注

如果 SendMode 没有使用, 则默认的模式为 Input.

由于 SendMode 也改变了 Click, MouseMove, MouseClick 和 MouseClickDrag 的模式, 所以您有机会为特殊的鼠标事件使用不同的模式. 实现这种操作最便捷的方法是使用 {Click}. 例如:

SendEvent "{Click 100 200}"  ; SendEvent 使用更老更传统的点击方法.

如果在脚本启动中使用了 SendMode, 那么它还会影响键盘和鼠标重映射. 特别是, 如果你将 SendMode "Play" 与重新映射一起使用, 请参阅 SendPlay 的重映射限制.

内置变量 A_SendMode 包含当前的设置.

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

Send, SetKeyDelay, SetMouseDelay, Click, MouseClick, MouseClickDrag, MouseMove

示例

让 Send 成为 SendInput 的代名词, 但如果 SendInput 不可用, 则回到 SendPlay.

SendMode "InputThenPlay"


SetControlDelay - 语法 & 使用 | AutoHotkey v2

SetControlDelay

设置每个控件改动函数后将发生的延迟.

SetControlDelay Delay

参数

Delay

类型: 整数

时间(单位为毫秒). 指定 -1 表示无延时, 或 0 表示最小延时.

返回值

整数: 整数

函数返回以前的设置.

备注

如果没有使用 SetControlDelay, 默认的延迟为 20.

在每个变更控件的函数之后, 都会自动进行短暂的延时(休眠). 这样做提高了脚本的可靠性, 因为控件在被这些函数之一更改后有时需要一段 "休息" 时间, 这允许它更新自身并响应脚本可能尝试发送给它的下一个函数.

具体来说, SetControlDelay 影响以下函数: ControlAddItem, ControlChooseIndex, ControlChooseString, ControlClick, ControlDeleteItem, EditPaste, ControlFindItem, ControlFocus, ControlHide, ControlHideDropDown, ControlMove, ControlSetChecked, ControlSetEnabled, ControlSetText, ControlShow, ControlShowDropDown.

ControlSend 不受影响; 它使用 SetKeyDelay.

虽然允许使用 -1(完全无延时), 但建议至少使用 0, 以增强即使在 CPU 处于负载状态下脚本也能正确运行的几率.

延时为 0 时实际内部会执行 Sleep(0), 这会将脚本时间片段的剩余部分提供给可能需要它的任何其他进程. 如果没有其他进程需要, 则 Sleep(0) 相当于完全没有延时.

如果 CPU 比较慢或在负载下, 或启用了窗口动画, 那么可能需要较高的延迟值.

内置变量 A_ControlDelay 包含了当前设置, 也可以为其赋予新的值, 而不用调用 SetControlDelay.

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

控件函数, SetWinDelay, SetKeyDelay, SetMouseDelay

示例

在每次控件修改命令后产生尽可能小的延迟.

SetControlDelay 0


SetDefaultMouseSpeed - 语法 & 使用 | AutoHotkey v2

SetDefaultMouseSpeed

设置在 Click, MouseMove, MouseClick 和 MouseClickDrag 中没有指定鼠标速度时使用的速度.

SetDefaultMouseSpeed Speed

参数

Speed

类型: 整数

移动鼠标的速度, 介于 0(最快) 和 100(最慢) 之间. 速度为 0 表示瞬时移动鼠标.

返回值

整数: 整数

函数返回以前的设置.

备注

如果没有使用 SetDefaultMouseSpeed, 则默认鼠标速度为 2.

对于 SendInput 和 SendPlay 模式会忽略 SetDefaultMouseSpeed; 它们会瞬时移动鼠标到目标位置(除非 SendInput 恢复为 SendEvent; 此外, SetMouseDelay 有适用于 SendPlay 的模式). 为了在视觉上更慢地移动鼠标 -- 如使用脚本向观众进行演示时 -- 请使用 SendEvent "{Click 100 200}" 或 SendMode "Event"(可以和 BlockInput 联合使用).

内置变量 A_DefaultMouseSpeed 包含了当前的设置.

函数 MouseClick, MouseMove 和 MouseClickDrag 都有一个参数来设置默认鼠标速度.

当 Speed 大于零时, SetMouseDelay 还会影响在鼠标朝目标位置移动时的速度, 这是通过在鼠标每次移动后产生的延迟实现的.

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

SetMouseDelay, SendMode, Click, MouseClick, MouseMove, MouseClickDrag, SetWinDelay, SetControlDelay, SetKeyDelay, SetKeyDelay

示例

使鼠标光标瞬间移动.

SetDefaultMouseSpeed 0


SetKeyDelay - 语法 & 使用 | AutoHotkey v2

SetKeyDelay

设置每次 Send 或 ControlSend 发送键击后自动的延时.

SetKeyDelay Delay, PressDuration, "Play"

参数

Delay

类型: 整数

如果省略, 则保留当前的延时. 否则, 请指定毫秒表示的时间. 指定 -1 表示无延时, 或 0 表示最小延时(然而如果使用了 Play 参数, 则 0 和 -1 都表示无延时).

PressDuration

类型: 整数

某些游戏和特殊的应用程序可能要求每次键击具有一定的按下时间; 即按下按键后, 持续一段时间, 然后才松开.

如果省略, 则保留当前的按下持续时间. 否则, 请指定毫秒表示的时间. 指定 -1 表示无延时(默认), 或 0 表示最小延时(然而, 如果使用了 Play 参数, 则 0 和 -1 都表示无延时).

注意: PressDuration 也会在修饰键(Ctrl, Alt, Shift 和 Win)) 状态发生任何变化后产生一个延迟, 以支持正在发送的键.

Play

类型: 字符串

如果为空或省略, 则将延时和按下持续时间应用于传统的 SendEvent 模式. 否则, 请指定单词 Play 会把上面的设置应用于 SendPlay 模式. 如果脚本没有使用过此参数, 则 SendPlay 总是 -1.

备注

如果没有使用 SetKeyDelay, 则对于传统的 SendEvent 模式默认延时为 10 而对于 SendPlay 模式为 -1. 对于这两种模式默认的 按住时长 为 -1

SendInput 不会影响 SetKeyDelay; 在这种模式下, 键击之间没有延时. 当 SendMode Input 生效时, 对于 Send 同样如此.

在每次 Send 或 ControlSend 发送键击后会自动进行短暂的延时. 这样做提高了脚本的可靠性, 因为窗口有时无法响应快速的键击流.

在延迟(睡眠) 期间, 使当前线程不可中断.

由于操作系统计时系统的精确度, 延时可能会被向上取整到最近的 10 或 15 的倍数.

对于 Send/SendEvent 模式, 延时为 0 时实际内部会执行 Sleep(0), 这样会将脚本时间片的剩余部分分配给其他需要的进程. 如果没有进程需要, 那么 Sleep(0) 相当于完全没有延时. 与之相比, 延时为 -1 则从不休眠. 为了提高可靠性, 推荐使用 0 而不是 -1.

当延时设为 -1 时, 脚本的进程优先级会成为传统的 SendEvent 模式中键击发送速度的重要因素. 要提升脚本的优先级, 请使用 ProcessSetPriority "High". 尽管这通常会使得键击发送的速度超过活动窗口的处理速度, 不过系统会自动对它们进行缓冲. 在 Send 函数完成后, 被缓冲的键击会继续到达目标窗口(即使此窗口现在已经不是活动窗口). 这种情况一般是不要紧的, 因为任何后续发送给相同窗口的键击会排列在缓冲中的那些键击之后.

内置变量 A_KeyDelay 包含了 Send/SendEvent 模式的当前 Delay 设置. A_KeyDuration 包含了 PressDuration 的设置, 同时 A_KeyDelayPlay 和 A_KeyDurationPlay 包含了 SendPlay 的设置.

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

Send, ControlSend, SendMode, SetMouseDelay, SetControlDelay, SetWinDelay, Click

示例

在通过 Send 或 ControlSend 每次发送按键后, 产生尽可能小的延迟.

SetKeyDelay 0


SetMouseDelay - 语法 & 使用 | AutoHotkey v2

SetMouseDelay

设置每次鼠标移动或单击后发生的延迟.

SetMouseDelay Delay , "Play"

参数

Delay

类型: 整数

时间(单位为毫秒). 指定 -1 表示无延时, 或 0 表示最小延时(然而, 如果使用了 Play 参数, 则 0 和 -1 都表示无延时).

Play

类型: 字符串

如果为空或省略, 将延时应用于传统的 SendEvent 模式. 否则, 请指定单词 Play 会把上面的延时应用于 SendPlay 模式. 如果脚本没有使用此参数, 则 SendPlay 的延时始终为 -1.

返回值

整数: 整数

函数返回以前的设置.

备注

如果没有使用 SetMouseDelay, 则对于传统的 SendEvent 模式默认延时为 10 而对于 SendPlay 模式为 -1.

在每次由 Click, MouseMove, MouseClick 和 MouseClickDrag 生成的鼠标移动或点击后会自动进行短暂的延时(除非处于 SendInput 模式). 这样做提高了脚本的可靠性, 因为窗口有时无法响应快速的鼠标事件流.

由于操作系统计时系统的精确度, 延时可能会被向上取整到最近的 10 或 15 的倍数.

延时为 0 时实际内部会执行 Sleep(0), 这会将脚本时间片段的剩余部分提供给可能需要它的任何其他进程. 如果没有其他进程需要, 则 Sleep(0) 相当于完全没有延时. 与之相比, 延时为 -1 将完全没有延时.

内置变量 A_MouseDelay 包含了 Send/SendEvent 模式的当前设置. A_MouseDelayPlay 包含了 SendPlay 模式的当前设置.

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

SetDefaultMouseSpeed, Click, MouseMove, MouseClick, MouseClickDrag, SendMode, SetKeyDelay, SetControlDelay, SetWinDelay

示例

使每次鼠标移动或点击后发生的延迟尽可能的小.

SetMouseDelay 0


SetCapsLockState / SetNumLockState / SetScrollLockState - 语法 & 使用 | AutoHotkey v2

SetCapsLockState / SetNumLockState / SetScrollLockState

设置 CapsLock/NumLock/ScrollLock 键的状态. 还可以强制这些键保持打开或关闭状态.

SetCapsLockState State
SetNumLockState State
SetScrollLockState State

参数

State

类型: 字符串或整数

如果为空或省略, 则清除按键的 AlwaysOn/Off(如果存在) 状态. 否则, 请指定下列值之一:

On 或 1(true): 打开按键并清除按键的 AlwaysOn/Off(如果存在) 状态.

Off 或 0(false): 关闭按键并清除按键的 AlwaysOn/Off(如果存在) 状态.

AlwaysOn: 强制按键保持打开状态.

AlwaysOff: 强制按键保持关闭状态.

备注

与下面的示例 #2 相比, 还可以通过 Send 函数将按键切换到相反的状态, 例如: Send "{CapsLock}". 但是, 发送 {CapsLock} 可能需要事先 SetStoreCapsLockMode False.

保持一个按键 AlwaysOn 或 AlwaysOff 需要键盘钩子, 在这样的情况中会自动进行安装..

相关

SetStoreCapsLockMode, GetKeyState

示例

开启 NumLock 并移除键的 AlwaysOn/Off 属性(如果存在).

SetNumLockState True

强制 ScrollLock 永久关闭.

SetScrollLockState "AlwaysOff"

切换 CapsLock 到相反的状态.

SetCapsLockState !GetKeyState("CapsLock", "T")


SetRegView - 语法 & 使用 | AutoHotkey v2

SetRegView

设置 RegRead, RegWrite, RegDelete, RegDeleteKey 和 Loop Reg 使用的注册表视图, 允许它们在 32 位脚本中访问 64 位注册表视图, 反之亦然.

SetRegView RegView

参数

RegView

类型: 整数或字符串

指定 32 以 32 位程序的方式来查看注册表, 而 64 以 64 位程序的方式浏览注册表.

指定单词 Default 来恢复到默认的行为.

返回值

类型: 字符串

函数返回以前的设置; 32, 64 或 Default.

备注

如果 SetRegView 没有使用, 则默认设置为 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, RegCreateKey, RegDeleteKey, Loop Reg

示例

演示了如何设置特定的注册表视图以及注册表重定向对脚本的影响.

; 以 32 位程序的方式访问注册表.
SetRegView 32
RegWrite "REG_SZ", "HKLM\SOFTWARE\Test.ahk", "Value", 123

; 以 64 位程序的方式访问注册表.
SetRegView 64
value := RegRead("HKLM\SOFTWARE\Wow6432Node\Test.ahk", "Value")
RegDelete "HKLM\SOFTWARE\Wow6432Node\Test.ahk"

MsgBox "Read value '" value "' via Wow6432Node."

; 恢复默认的注册表视图, 这
; 取决于脚本是 32 位还是 64 位的.
SetRegView "Default"
;...

演示了如何判断正在运行脚本的 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 "."


SetStoreCapsLockMode - 语法 & 使用 | AutoHotkey v2

SetStoreCapsLockMode

在 Send 之后是否恢复 CapsLock 的状态.

SetStoreCapsLockMode Mode

参数

Mode

类型: 布尔值

如果为 true, 如果 Send 在发送时需要临时更改 CapsLock 的状态, 则在发送后会恢复 CapsLock 为之前的状态.

如果为 false, 不会更改 CapsLock 的状态. 所以, 如果在 Send 发送时 CapsLock 恰巧是打开的, 则它所发送的字符是大小写颠倒的.

返回值

类型: 整数(布尔值)

函数返回以前的设置; 0(false) 或 1(true).

备注

这意味着在 Send 和 ControlSend 执行时, CapsLock 的状态不总是关闭的. 即使 CapsLock 键被成功关闭了, 在发送按键后也可能不会恢复它原来的状态.

此函数极少使用, 因为在大多数情况中默认行为是最佳的.

该设置被盲从模式和文本模式忽略; 也就是说, 在这些情况下 CapsLock 的状态不会改变.

内置变量 A_StoreCapsLockMode 包含当前设置(1 或 0).

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

SetCaps/Num/ScrollLockState, Send, ControlSend

示例

使 CapsLock 的状态完全不改变.

SetStoreCapsLockMode False


SetTimer - 语法 & 使用 | AutoHotkey v2

SetTimer

在指定的时间间隔内自动重复调用函数.

SetTimer Function, Period, Priority

参数

Function

类型: 函数对象

要调用的函数对象.

函数对象的引用保存在脚本的计时器列表中, 除非删除计时器, 否则不会释放该引用. 对于只运行一次的计时器, 此操作会自动发生, 但是也可以通过调用 Period(周期) 为 0 的 SetTimer 来完成.

如果 Function 省略, 如果有的话, SetTimer 将在启动当前线程的定时器上运行. 例如, SetTimer , 0 可以在一个定时器函数中用于标记要删除的定时器, 而 SetTimer , 1000 将更新当前定时器的 Period.

注意: 传递空变量或返回空值的表达式被看做一个错误. 这个参数必须为非空的值或完全忽略.

Period

类型: 整数

如果省略, 并且计时器不存在, 将创建一个周期为 250 的计时器. 如果省略, 并且计时器已经存在, 将重置之前的周期, 除非指定了 Priority. 否则, 参数的绝对值被用作在执行计时器之前必须经过的大约毫秒数. 定时器将被自动重置. 可以设置为自动重复或只运行一次:

  • 如果 Period 大于 0, 定时器将自动重复, 直到脚本明确禁用.
  • 如果 Period 小于 0, 定时器将只运行一次. 例如, 指定 -100 将在 100 ms 后调用 Function, 然后删除定时器, 就像使用 SetTimer Function, 0 一样.
  • 如果 Period 为 0, 定时器被标记为删除. 如果由这个定时器启动的线程还在运行, 那么在线程结束后, 定时器就会被删除(除非它被重新启用); 否则, 它会被立即删除. 在任何情况下, 定时器之前的 Period 和 Priority 都不会被保留.

Period 的绝对值不能大于 4294967295 ms (49.7 天).

Priority

类型: 整数

如果省略, 默认为 0. 否则, 请指定一个介于 -2147483648 和 2147483647 之间的整数(或为表达式) 来表示计时器的优先级. 有关详情, 请参阅线程.

要改变现有计时器的优先级而不以任何其他方式影响它, 请省略 Period.

备注

计时器很有用, 因为它们是异步运行的, 这意味着它们会以指定的频率(间隔) 运行, 即使脚本正等待窗口, 显示对话框或忙于其他任务的时候. 它们的许多应用实例包括了当用户空闲时(如 A_TimeIdle 反映的那样) 执行一些动作或在不需要的窗口出现时关闭它们.

尽管计时器给人一种脚本同时执行多个任务的错觉, 实际并非如此. 相反地, 定时子程序只是被当作其他线程来处理: 它们可以中断另一个线程或被另一个线程中断, 例如 热键子程序. 有关详情, 请参阅线程.

每当创建或重新启用计时器或用新的 period 更新计时器时, 它的函数不会立即被调用; 必须先经过它的 period 时间. 如果您希望立即开始计时器的首次执行, 请直接调用计时器的函数(但是, 这不会像定时器本身那样启动一个新的线程; 所以像 SendMode 这样的设置不会以其默认值启动).

重置: 如果 SetTimer 被用在一个已经存在的计时器上, 那么这个计时器会被重置(除非指定了 Priority 并且省略了 Period); 换句话说, 在经过它的整个周期后函数才会再次被调用.

计时器精度: 由于操作系统中计时系统的精确度, Period 通常会被向上取整到最近的 10 或 15.6 毫秒的倍数(取决于安装的硬件和驱动程序的类型). 可以通过 Loop+Sleep 实现更短的延迟, 如 DllCall+timeBeginPeriod+Sleep 所示.

可靠性: 在以下情况下, 计时器可能无法按预期时间运行:

  1. 其他应用程序对 CPU 造成了很大的负荷.
  2. 计时器函数在计时器周期到期时仍在运行.
  3. 有太多其他竞争的计时器.
  4. 计时器被另一个线程中断, 即另一个定时函数, 热键子程序或自定义菜单项(这可以通过 Critical 来避免). 如果发生这种情况, 而中断的线程需要很长时间才能完成, 那么被中断的计时器将在这段时间内有效地被禁用. 但是, 任何其他的计时器都会通过中断中断第一个计时器的线程继续运行.
  5. 使用 Critical 或 Thread Interrupt/Priority 后脚本会变成不可中断的. 在这样的时期, 计时器不会运行. 之后, 当脚本恢复可中断时, 任何过时的计时器会尽快运行一次然后恢复到正常的调度.

虽然当脚本被挂起时, 计时器会运行, 但如果当前线程的 Thread NoTimers 正在生效或任何线程暂停时, 计时器都不会运行. 此外, 当用户正在浏览脚本的某个菜单(如托盘图标菜单或菜单栏) 时, 它们也不会运行.

因为定时器是通过临时中断脚本的当前线程来运行的, 所以当长时间的中断是不可取的, 它们的函数应该保持短暂的(以便快速完成).

其他备注: 临时的计时器经常可以在它自己的函数中禁用(请参阅此页面底部的示例).

每当函数被定时器调用时, 它都会以默认的设置值(如 SendMode) 重新开始. 这些默认值可以在脚本启动中更改.

如果热键的响应时间非常重要(如在游戏中) 并且脚本中包含的任何计时器, 其函数的执行时间超过 5 毫秒, 请使用下面的函数来避免 15 毫秒的延迟. 否则, 如果在计时器线程处于不中断期的时候按下热键, 就会出现这样的延迟:

Thread "Interrupt", 0  ; 使所有线程始终处于可中断状态.

如果一个计时器的函数正在运行时被禁用, 那么该函数将继续运行, 直到完成.

KeyHistory 功能显示存在的计时器数目, 以及当前启用的数目.

相关

线程, Thread (函数), Critical, 函数对象

示例

当不想要的窗口出现时关闭它们.

SetTimer CloseMailWarnings, 250

CloseMailWarnings()
{
    WinClose "Microsoft Outlook", "A timeout occured while communicating"
    WinClose "Microsoft Outlook", "A connection to the server could not be established"
}

等待特定的窗口出现, 然后通知用户.

SetTimer Alert1, 500

Alert1()
{
    if !WinExist("Video Conversion", "Process Complete")
        return
    ; 否则:
    SetTimer , 0  ; 即此处计时器关闭自己.
    MsgBox "The video conversion is finished."
}

检测热键的单次, 两次和三次按下. 这样允许热键根据您按下次数的多少执行不同的操作.

#c::
KeyWinC(ThisHotkey)  ; 这是一个命名的函数热键.
{
    static winc_presses := 0
    if winc_presses > 0 ; SetTimer 已经启动, 所以我们记录键击.
    {
        winc_presses += 1
        return
    }
    ; 否则, 这是新开始系列中的首次按下. 把次数设为 1 并启动计时器
    winc_presses := 1
    SetTimer After400, -400 ; 在 400 毫秒内等待更多的键击.

    After400()  ; 这是一个嵌套函数.
    {
        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
    }
}

使用方法作为计时器函数.

counter := SecondCounter()
counter.Start()
Sleep 5000
counter.Stop()
Sleep 2000

; 一个记录秒数的示例类...
class SecondCounter {
    __New() {
        this.interval := 1000
        this.count := 0
        ; Tick() 有一个隐式参数 "this", 其引用一个对象
        ; 所以, 我们需要创建一个封装了 "this " 和调用方法的函数:
        this.timer := ObjBindMethod(this, "Tick")
    }
    Start() {
        SetTimer this.timer, this.interval
        ToolTip "Counter started"
    }
    Stop() {
        ; 要关闭计时器, 我们必须传递和之前一样的对象:
        SetTimer this.timer, 0
        ToolTip "Counter stopped at " this.count
    }
    ; 本例中, 计时器调用了以下方法:
    Tick() {
        ToolTip ++this.count
    }
}

示例 #4 的备注:

  • 我们也可使用 this.timer := this.Tick.Bind(this). 当 this.timer 被调用时, 它实际上是调用 tick_function.Call(this), 而 tick_function 是实现该方法的函数对象. 相比之下, ObjBindMethod 会产生一个调用 this.Tick() 的对象.
  • 如果我们将 Tick 重命名为 Call, 我们可以直接使用 this 来代替 this.timer. 然而, 当对象有多个方法需要被不同的事件源调用时, ObjBindMethod 是非常有用的, 如热键, 菜单项, GUI 控件, 等等.
  • 如果计时器是在计时器调用的函数/方法中修改或删除时, 可能更容易省略 Function 参数. 在某些情况下, 这样可以避免保留传递给 SetTimer 的原始对象.


SetTitleMatchMode - 语法 & 使用 | AutoHotkey v2

SetTitleMatchMode

设置 WinTitle 参数在内置函数中的匹配行为, 如 WinWait.

SetTitleMatchMode MatchMode
SetTitleMatchMode Speed

参数

MatchMode

类型: 整数或字符串

指定下列值之一:

1: 窗口标题必须以指定的 WinTitle 开头才能匹配.

2: 默认行为. 窗口标题的任意位置包含有 WinTitle 才能匹配.

3: 窗口标题必须和 WinTitle 完全一致才能匹配.

RegEx: 使 WinTitle, WinText, ExcludeTitle 和 ExcludeText 接受正则表达式, 例如, WinActivate "Untitled.*Notepad". RegEx 也适用于 ahk_class 和 ahk_exe, 例如, "ahk_class IEFrame" 会搜索类名包含有 IEFrame 的所有窗口(这是由于在默认情况下, 正则表达式在目标字符串 任意位置 查找匹配). 对于 WinTitle, 每个部分是独立分开的. 例如, 在 "i)^untitled ahk_class i)^notepad$ ahk_pid " mypid 中, i)^untitled 和 i)^notepad$ 都是独立的正则模式, 且 mypid 总是比较数值(它并不是一个正则模式). 对于 WinText, 每个文本元素(比如, 每个控件的文本) 都是独立匹配正则表达式的. 因此, 它不可能有跨越多个文本元素的匹配.

上述模式还会对 ExcludeTitle 产生与 WinTitle 相同的影响. 例如, 模式 3 要求被排除的窗口的标题必须准确匹配 ExcludeTitle.

在所有模式中, 只有 RegEx 模式会影响非标题窗口匹配条件 ahk_class 和 ahk_exe. 这些匹配条件在任何编号模式下的操作都是相同的.

Speed

类型: 字符串

指定以下单词之一, 来指示 WinText 和 ExcludeText 参数应如何匹配:

Fast: 默认行为. 性能可能大大优于慢速模式, 但某些类型的控件不会被检测到. 例如, 文本通常会在静态和按钮控件中被检测到, 但不会在编辑控件中被检测到, 除非它们为脚本所拥有.

Slow: 速度慢得多, 但适用于所有能响应 WM_GETTEXT 消息的控件.

返回值

类型: 整数或字符串

函数返回被改变的设置(A_TitleMatchMode 或 A_TitleMatchModeSpeed) 的先前值.

备注

如果没有使用 SetTitleMatchMode, 默认的匹配模式为 2, 且默认的速度为 Fast.

此函数影响所有窗口函数的行为, 例如 WinExist 和 WinActivate. WinGetText 和 ControlGetText 受影响的方式与其他函数相同, 但它们总是使用慢速模式来检索文本.

如果使用窗口组, 则当前标题匹配模式适用于组中的每个单独的规则.

通常, 只有在无法通过其标题和快速-模式文本唯一标识目标窗口时, 才应该使用慢速模式. 这是因为当任意一个应用程序窗口正忙或 "无响应" 时, 慢速模式会非常慢.

Window Spy 有 Slow TitleMatchMode 的选项, 所以它很容易确定是否需要慢速模式.

如果您想同时改变两个属性, 请执行函数两次, 例如:

SetTitleMatchMode 2
SetTitleMatchMode "Slow"

内置变量 A_TitleMatchMode 和 A_TitleMatchModeSpeed 包含了当前的设置.

不管当前的匹配模式如何, WinTitle, WinText, ExcludeTitle 和 ExcludeText 都是区分大小写的. 唯一的例外是带不区分大小写选项的 RegEx 模式; 例如, "i)untitled - notepad".

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

WinTitle 参数, SetWinDelay, WinExist, WinActivate, RegExMatch

示例

强制窗口函数操作在开头处包含 WinTitle 而不是任意地方的窗口.

SetTitleMatchMode 1

允许窗口函数尽可能地检测更多的控件类型, 但性能较低. 注意, Slow/Fast 可以独立于其他所有模式进行设置.

SetTitleMatchMode "Slow"

使用 RegEx 模式可轻松排除多个窗口. 将以下 ExcludeTitle 替换为您希望从计数中排除的实际窗口的标题.

SetTitleMatchMode "RegEx"
CountAll := WinGetCount()
CountExcluded := WinGetCount(,, "ExcludeTitle1|ExcludeTitle2")
MsgBox CountExcluded " out of " CountAll " windows were counted"


SetWinDelay - 语法 & 使用 | AutoHotkey v2

SetWinDelay

设置在每次执行窗口函数(例如 WinActivate) 后的延时.

SetWinDelay Delay

参数

Delay

类型: 整数

时间, 以毫秒为单位. 指定 -1 表示无延时, 或 0 表示最小延时.

返回值

整数: 整数

函数返回以前的设置.

备注

如果没有使用 SetWinDelay, 默认延时为 100.

除了 WinActive 和 WinExist 之外, 在每个窗口函数之后都会自动执行短暂的延迟(睡眠). 这样做是为了提高脚本的可靠性, 因为窗口在创建, 激活或最小化等操作之后有时需要一段 "休息" 时间, 以便它有机会更新自身, 并响应下一个脚本可能尝试发送给它的函数.

虽然允许使用 -1(完全无延时), 但建议至少使用 0, 以增强即使在 CPU 处于负载状态下脚本也能正确运行的几率.

延时为 0 时实际内部会执行 Sleep(0), 这会将脚本时间片段的剩余部分提供给可能需要它的任何其他进程. 如果没有其他进程需要, 则 Sleep(0) 相当于完全没有延时.

如果 CPU 比较慢或在负载下, 或启用了窗口动画, 那么可能需要较高的延迟值.

内置变量 A_WinDelay 包含当前设置.

每个新运行的线程(如 热键, 自定义菜单项或定时子程序) 都会以此函数的默认设置开始. 这个默认设置可以通过在脚本启动中使用此函数来改变.

相关

SetControlDelay, SetKeyDelay, SetMouseDelay, SendMode

示例

在每次窗口函数后, 有 10 毫秒的延迟.

SetWinDelay 10


SetWorkingDir - 语法 & 使用 | AutoHotkey v2

SetWorkingDir

更改脚本当前的工作目录.

SetWorkingDir DirName

参数

DirName

类型: 字符串

新工作目录的名称, 如果未指定绝对路径, 则假定在当前 A_WorkingDir 的子目录中.

错误处理

失败时抛出 OSError.

备注

脚本的工作目录是用来访问未指定绝对路径的文件和文件夹的默认目录. 在下面的例子中, 将假定文件 My Filename.txt 在 A_WorkingDir 中: FileAppend "A Line of Text", "My Filename.txt".

不管脚本如何启动, 脚本的工作目录默认为 A_ScriptDir. 相反, A_InitialWorkingDir 的值由脚本的启动方式确定. 例如, 如果它是通过快捷方式运行的 -- 例如在 "开始" 菜单中 -- 则其初始工作目录由快捷方式属性内的 "起始位置" 字段决定.

一旦更改, 新的工作目录会立即对整个脚本生效. 所有被中断的, 暂停的和新启动的线程都会受影响, 包括计时器.

相关

A_WorkingDir, A_InitialWorkingDir, A_ScriptDir, DirSelect

示例

改变脚本的当前工作目录.

SetWorkingDir "D:\My Folder\Temp"

强制脚本使用它最初启动的文件夹作为其工作目录.

SetWorkingDir A_InitialWorkingDir


Shutdown - 语法 & 使用 | AutoHotkey v2

Shutdown

关机, 重启或注销系统.

Shutdown Flag

参数

Flag

类型: 整数

以下数字的组合(和):

  • 0 = 注销
  • 1 = 关机
  • 2 = 重启
  • 4 = 强制
  • 8 = 关闭电源

把需要的值加在一起. 例如, 要关机并关闭电源, 标志为 9(关机 + 关闭电源 = 1 + 8 = 9).

使用 "强制" 值(4) 来强制关闭所有打开的应用程序. 它应该仅用于紧急的情况中, 因为这样可能导致打开的应用程序数据丢失.

"关闭电源" 值(8) 表示关闭系统并关闭电源.

备注

要让系统暂停或休眠, 请参阅页面底部的示例 #2.

要关闭显示器, 请参阅 PostMessage 示例 #1.

相关说明, 脚本通过 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)


Sleep - 语法 & 使用 | AutoHotkey v2

Sleep

在继续前等待指定的时间量.

Sleep Delay

参数

Delay

类型: 整数

要暂停的时间量(单位为毫秒), 介于 0 和 2147483647(24 天) 之间.

备注

由于操作系统中计时系统的精确度, Delay 通常会被向上取整到最近的 10 或 15.6 毫秒的倍数(取决于所安装的硬件和驱动的类型). 要实现更短的延时, 请参阅示例.

如果 CPU 在负载时, 那么实际的延时可能超过请求的时间. 这是因为在给脚本另一个时间片之前, 会给每个有需要的进程一个 CPU 时间片(一般为 20 毫秒).

延时为 0 会将脚本当前时间片的剩余部分分配给其他需要的进程(只要它们的优先级不是显著比脚本低). 因此, 延时为 0 实际会产生在 0 和 20 ms(或更多) 之间的延时, 取决于有需要的进程的数目(如果没有这样的进程, 则完全没有延时). 然而, 0 的 Delay 应该比任何更长的 Delay 会更早结束.

当脚本休眠时, 可以通过热键, 自定义菜单项或计时器启动新的线程.

Sleep -1: -1 的 Delay 不会休眠, 相反地它让脚本立即检查消息队列. 这可用来强制任何迫近的中断在指定的位置发生, 而不是在更随机的位置. 有关详情, 请参阅 Critical.

相关

SetKeyDelay, SetMouseDelay, SetControlDelay, SetWinDelay

示例

在继续执行前等待 1 秒.

Sleep 1000

等待 30 分钟后再继续执行.

MyVar := 30 * 60000 ; 30 表示分钟, 乘以 60000 表示时间(毫秒).
Sleep MyVar ; 休眠 30 分钟.

演示如何休眠比普通的 10 或 15.6 毫秒更短的时间. 注意: 像这样的脚本运行时, 整个操作系统和所有的应用程序都会受到下面的 timeBeginPeriod 的影响.

SleepDuration := 1  ; 这里有时可以根据下面的值进行细微调整(例如 2 与 3 的区别).
TimePeriod := 3 ; 尝试 7 或 3. 请参阅下面的注释.
; 在 PC 中休眠持续时间一般向上取整到 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


Sort - 语法 & 使用 | AutoHotkey v2

Sort

以字母, 数字或随机顺序排列变量的内容(可以选择是否移除重复项).

SortedString := Sort(String , Options, Callback)

参数

String

类型: 字符串

需要排序的字符串.

Options

类型: 字符串

如果为空或省略, String 按字母升序排序(不区分大小写), 使用换行符('n) 作为分隔符. 否则, 请指定从下面选项章节指定一个或多个选项的字符串(以任意顺序, 中间有可选的空格).

Callback

类型: 函数对象

如果省略, 将不执行自定义排序. 否则, 请指定要调用的比较列表中任意两个项的函数.

回调接受三个参数, 并能定义如下:

MyCallback(First, Second, Offset) { ...

尽管为参数指定的名称并不重要, 但将依次为它们分配以下值:

  1. 第一个项目.
  2. 第二个项目.
  3. 在原始/未排序列表中看到的第二项与第一项的偏移量(以字符为单位)(参见示例)).

如果不需要相应的信息, 你可以从回调参数列表的末尾省略一个或多个参数, 但在这种情况下, 必须指定星号作为最后一个参数, 例如, MyCallback(Param1, *).

当回调函数认为第一个参数大于第二个参数时, 它应该返回一个正整数; 当它认为这两个参数相等时, 它应该返回 0, "", 或什么都不返回; 否则, 它应该返回一个负整数. 如果返回值中存在小数点, 则忽略该部分(即 0.8 与 0 相同).

回调函数使用与调用它的 Sort 函数相同的全局(或线程特定的) 设置.

注意: 当指定 Callback 时, 除了 D, Z 和 U 之外的所有选项都会被忽略(尽管 N, C 和 CL 仍然会影响重复项的检测方式).

返回值

类型: 字符串

该函数返回指定字符串的排序版本.

选项

C, C1 或 COn: 区分大小写的排序(如果也存在 N 选项, 则此选项被忽略).

C0 或 COff: 不区分大小写的排序. 排序时大写字母 A-Z 被认为与其小写字母相同. 如果没有使用其他区分大小写的选项, 这是默认模式.

CL 或 CLocale: 基于当前用户区域设置的不区分大小写的排序. 例如, 大多数英语和西欧地区把字母 A-Z 和 ANSI 字母(如 Ä 和 Ü) 等同于它们的小写形式. 这种方法还使用了 "单词排序", 它以这样的方式(像 "coop" 和 "co-op" 这样的单词保持在一起) 处理连字符和撇号. 根据被排序项目的内容, 它的执行性能比默认的不区分方法差了 1 到 8 倍.

CLogical: 类似 CLocale, 但是字符串中的数字被认为是数字内容而不是文本. 例如, "A2" 被视为小于 "A10". 然而, 如果两个数字只因前导零的存在而不同, 有前导零的字符串可能被认为 小于 另一个字符串. 实际的行为在不同的操作系统版本中可能有所不同.

D x: 指定 x 作为分隔符, 它决定了每个项目的开始和结束位置. 分隔符总是区分大小写的. 如果此选项不存在, 则 x 默认为换行符(`n). 在大多数情况下, 即使是以 CR+LF(`r`n) 结尾的行也能工作, 但回车键(`r) 包含在比较中, 因此会影响排序顺序. 例如, "B`r`nA" 将按预期排序, 但 "A`r`nA`t`r`nB" 将把 A`t`r 放在 A`r 之前.

N: 数字排序. 每个项目都被假定为数字而不是字符串进行排序(例如, 如果此选项不存在, 则根据字母顺序字符串 233 被认为小于字符串 40). 十进制和十六进制字符串(例如 0xF1) 都被认为是数字. 不是以数字开头的字符串在排序中被看成是零. 把数字作为 64 位浮点值进行处理, 这样可以考虑到小数部分的每位数字(如果有).

P n: 根据字符位置 n(不使用十六进制的 n) 对项目进行排序(每个项目从第 n 个字符开始进行比较). 如果不使用该选项, n 默认为 1, 即第一个字符的位置. 排序会从第 n 个字符开始将每个字符串与其他字符串进行比较. 如果 n 大于任何字符串的长度, 则在排序时, 该字符串将被视为空白. 当与选项 n(数字排序) 一起使用时, 将使用字符串的字符位置, 这不一定与数字的数字位置相同.

R: 逆向排序(根据其他选项进行字母或数字排序).

Random: 随机排序. 此选项会使得除 D, Z 和 U 外的其他选项被忽略(尽管如此, 但 N, C 和 CL 仍会影响对于重复项的检测). 示例:

MyVar := Sort(MyVar, "Random")
MyVar := Sort(MyVar, "Random Z D|")

U: 移除列表中的重复项目使得每个项目都是唯一的. 如果 C 选项有效, 则项目的大小写必须匹配才会被认为是等同的. 如果 N 选项有效, 那么像 2 这样的项目将被认为是 2.0 的重复. 如果 P 或 \(反斜杠) 选项有效, 则整个项目必须相同才看成是重复项, 而不仅是用于排序的子字符串. 如果 Random 选项或自定义排序生效, 只有当排序结果中出现相邻的重复项时, 重复项才会被删除. 例如, 当 "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 加载整个文件.

如果一个大的变量被排序后, 以后不再需要它的内容, 可以通过使其为空来释放它的内存, 例如 MyVar := "".

相关

FileRead, File-reading loop, Parsing loop, StrSplit, CallbackCreate, A_Clipboard

示例

对以逗号分隔的数字列表进行排序.

MyVar := "5,3,7,9,1,13,999,-4"
MyVar := Sort(MyVar, "N D,")  ; 数值排序, 使用逗号作为分隔符.
MsgBox MyVar   ; 结果为 -4,1,3,5,7,9,13,999

对文件的内容进行排序.

Contents := FileRead("C:\Address List.txt")
FileDelete "C:\Address List (alphabetical).txt"
FileAppend Sort(Contents), "C:\Address List (alphabetical).txt"
Contents := ""  ; 释放内存.

设置 Win+C 热键来从打开的资源管理器窗口中复制文件, 对其中的文件名进行排序后放回剪贴板.

#c:: ; Win+C
{
    A_Clipboard := "" ; 必须为空以检测是否有效.
    Send "^c"
    if !ClipWait(2)
        return
    MsgBox "Ready to be pasted:`n" Sort(A_Clipboard)
}

演示通过回调函数进行自定义排序.

MyVar := "This`nis`nan`nexample`nstring`nto`nbe`nsorted"
MsgBox Sort(MyVar,, LengthSort)
LengthSort(a1, a2, *)
{
    a1 := StrLen(a1), a2 := StrLen(a2)
    return a1 > a2 ? 1 : a1 < a2 ? -1 : 0  ; 根据上面确定的长度进行排序.
}

MyVar := "5,3,7,9,1,13,999,-4"
MsgBox Sort(MyVar, "D,", IntegerSort)
IntegerSort(a1, a2, *)
{
    return a1 - a2  ; 按升序数字排序. 只有当差值不会大到溢出有符号的 64 位整数时, 此方法才有效.
}

MyVar := "1,2,3,4"
MsgBox Sort(MyVar, "D,", ReverseDirection)  ; 将列表反转, 使其包含 4,3,2,1
ReverseDirection(a1, a2, offset)
{
    return offset  ; 如果 a2 在原列表中 a1 之后, 则偏移量为正; 否则为负.
}

MyVar := "a bbb cc"
; 按升序排列; 使用胖箭头函数:
MsgBox Sort(MyVar, "D ", (a,b,*) => StrLen(a) - StrLen(b))


Sound 函数 | AutoHotkey v2

Sound 函数

适用于:

  • SoundGetVolume / SoundSetVolume
  • SoundGetMute / SoundSetMute
  • SoundGetName
  • SoundGetInterface

其他声音相关的函数:

  • SoundBeep
  • SoundPlay

终端设备

SoundGet 和 SoundSet 函数引用的 "devices" 是 音频终端设备. 单个设备驱动程序或物理设备通常具有多个终端, 例如用于不同类型的输出或输入. 例如:

名称 | 描述
扬声器(例如 HD Audio) | 此设备的主模拟输出(在环绕声的情况下使用多个插孔).
数字输出(例如 HD Audio) | 光纤或同轴数字输出.
麦克风(例如 HD Audio) | 通过麦克风插孔捕获音频.
立体声混音(例如 HD Audio) | 捕获任何输出到扬声器终端的音频.

设备名称通常由终端名称(如 "Speakers") 和括号中的音频驱动程序名称组成. 脚本可以使用全名, 也可以仅使用名称的开头, 如 "Mic" 或 "Microphone". 音频驱动程序具有固定名称, 但是管理员可以随时通过声音控制面板更改终端名称.

声音控制面板列出了设备, 从命令行运行 mmsys.cpl, 或通过运行对话框(Win+R) 或 Run 函数可以打开该面板. 默认情况下, 控制面板只列出启用和插入的设备(如果合适), 但这可以通过右键菜单进行更改. AutoHotkey 检测没有插入的设备, 但不检测禁用的设备.

组件

组件显示在声音设备属性对话框的级别选项卡上.

在本例中, 主控制位于顶部, 其次是前四个组件: Microphone, FrontMic, Line In 和 Side. 所有的控制都有音量和静音控制, 除了第四个组件, 它只有音量.

声音设备的属性对话框可以通过声音控制面板打开.

音频驱动程序能够显示其他控制, 如低音和高音. 但是, 常见的音频驱动程序往往只具有音量和静音控制, 或者根本没有组件. 音量和静音控制是通过 SoundGetVolume, SoundSetVolume, SoundGetMute 和 SoundSetMute 直接支持的. 所有其他控制仅通过 SoundGetInterface 和 ComCall 间接支持.

详细信息

组件可以通过 DeviceTopology API 发现, 该 API 公开 Connectors 和 Subunits 的图表. 上面显示的每个组件都有一个连接器, 而连接器定义了组件的名称. 每个控制(例如音量或静音) 由位于连接器和终端之间的子单元表示. 数据从连接器 "流出" 或流入, 并随着流过每个子单元而改变, 例如调节音量或抑制(静音) 所有声音.

SoundGet 和 SoundSet 函数通过遍历 device topology 图并计算具有给定名称的连接器(或所有未指定名称的连接器) 来标识组件. 一旦找到匹配的连接器, 就可以从最近的连接器开始通过查询图形的该特定分支上的每个子单元来检索控制接口(例如 IAudioVolumeLevel 或 IAudioMute).

应用于多个连接器的子单元被排除在外 - 例如与主音量和静音控制对应的子单元. 如果连接器至少有一个自己的子单元, 即使该子单元不是所请求的类型, 该连接器也会被计数.

实际上, 最终结果的可用的组件和级别选项卡中列出的是一样的, 并且它们的顺序是相同的. 但是, 这个过程是基于观察, 反复尝试的, 所以可能不是 100 % 的准确.

通用参数

Component

类型: 字符串或整数

以下之一:

  • component 的索引, 其中 1 是第一个组件.
  • 组件的完整显示名称(不区分大小写).
  • 如上, 但后跟冒号和整数, 其中 1 是第一个使用该名称的组件. 例如, "Line In:2" 是名称为 "Line In" 的第二个组件. 仅当 Component 可能导致歧义时, 例如多个组件具有相同的名称, 或显示名称为空, 为整数或包含冒号时, 才需要这样做.
  • 如果为空或省略, 则该函数以主音量/静音控制或由 IMMDevice::Activate 返回的接口为目标.

如果只指定索引, 则忽略显示名称. 例如, 1, "1" 和 ":1" 使用第一个组件, 而不管名称如何, 而 "" 使用主控制.

如果声音设备缺少指定的 Component, 则抛出 TargetError.

Device

类型: 字符串或整数

以下之一:

  • 介于 1 和支持的设备总数之间的数字(整数).
  • 设备的显示名称; 全名或开头部分(不区分大小写). 例如, "Speakers" 或 "Speakers (Example HD Audio)".
  • 如上, 但后跟冒号和整数, 其中 1 是具有匹配名称的第一个设备. 例如, "Speakers:2" 表示名称为 "Speakers" 的第二个设备. 仅当 Device 可能导致歧义时, 例如多个组件具有相同的名称, 或包含冒号时, 才需要这样做.
  • 如果为空或省略, 则默认为系统的默认播放设备(不一定是设备 1).

声卡分析脚本可以帮助确定要使用的名称和/或编号.

示例

声卡分析. 使用以下脚本发现可用的音频设备和组件名称, 以及每个设备或组件是否支持音量和/或静音控件. 它在一个简单的 ListView 中显示结果. 如果可以检索当前音量和静音设置, 则会显示它们, 但不会实时更新.

scGui := Gui(, "Sound Components")
scLV := scGui.Add('ListView', "w600 h400"
    , ["Component", "#", "Device", "Volume", "Mute"])

devMap := Map()

loop
{
    ; 对于每一次循环迭代, 尝试获取相应的设备.
    try
        devName := SoundGetName(, dev := A_Index)
    catch  ; 没有更多的设备.
        break

    ; 如果需要, 使用 ":index" 来限定名称.
    devName := Qualify(devName, devMap, dev)

    ; 如有可能, 获取主音量和静音设置.
    vol := mute := ""
    try vol := Round(SoundGetVolume( , dev), 2)
    try mute := SoundGetMute( , dev)

    ; 仅在至少检索到一项时显示主设置.
    if vol != "" || mute != ""
        scLV.Add("", "", dev, devName, vol, mute)

    ; 对于每个组件, 首先查询其名称.
    cmpMap := Map()

    loop
    {
        try
            cmpName := SoundGetName(cmp := A_Index, dev)
        catch
            break
        ; 如有可能, 检索该组件的音量和静音设置.
        vol := mute := ""
        try vol := Round(SoundGetVolume(cmp, dev), 2)
        try mute := SoundGetMute(cmp, dev)
        ; 显示此组件, 即使它不支持音量或静音,
        ; 因为它可能通过 SoundGetInterface() 支持其他控制.
        scLV.Add("", Qualify(cmpName, cmpMap, A_Index), dev, devName, vol, mute)
    }
}

loop 5
    scLV.ModifyCol(A_Index, 'AutoHdr Logical')
scGui.Show()

; 如果需要, 使用 ":index" 来限定名称.
Qualify(name, names, overallIndex)
{
    if name = ''
        return overallIndex
    key := StrLower(name)
    index := names.Has(key) ? ++names[key] : (names[key] := 1)
    return (index > 1 || InStr(name, ':') || IsInteger(name)) ? name ':' index : name
}


SoundBeep - 语法 & 使用 | AutoHotkey v2

SoundBeep

从 PC 扬声器发出声音.

SoundBeep Frequency, Duration

参数

Frequency

类型: 整数

如果省略, 默认为 523. 否则, 请指定声音的频率, 一个介于 37 和 32767 之间的数字.

Duration

类型: 整数

如果省略, 默认为 150. 否则, 请指定声音的持续时间, 单位为毫秒.

备注

脚本会等待声音结束后才继续执行. 此外, 在发出声音时系统的响应可能会减慢.

如果计算机没有声卡, 则 PC 扬声器将播放标准的哗音.

要生成标准的系统声音而不是 PC 扬声器的哗音, 请参阅 SoundPlay 中的星号模式.

相关

SoundPlay

示例

以默认的音高和间隔进行发音.

SoundBeep

以较高的音高进行发音并持续半秒.

SoundBeep 750, 500


SoundGetInterface - 语法 & 使用 | AutoHotkey v2

SoundGetInterface

检索声音设备或组件的原生 COM 接口.

InterfacePtr := SoundGetInterface(IID, Component, Device)

参数

IID

类型: 字符串

格式为 "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" 的接口标识符(GUID).

Component

类型: 字符串或整数

如果为空或省略, 则检索由设备本身实现的接口. 否则, 指定组件的显示名称和/或索引. 例如, 1, "Line in" 或 "Line in:2".

有关详情, 请参阅 Component (Sound 函数).

Device

类型: 字符串或整数

如果为空或省略, 则它默认为系统的默认回放设备(不一定是设备 1). 否则, 指定设备的显示名称和/或索引. 例如, 1, "Speakers", "Speakers:2" 或 "Speakers (Example HD Audio)".

有关详情, 请参阅 Device (Sound 函数).

返回值

类型: 整数

如果成功, 返回值是接口指针.

如果接口不支持, 返回值是零.

错误处理

如果无法找到设备或组件, 则抛出 TargetError. 否则失败时, 抛出 OSError.

备注

接口是从以下来源之一检索的:

  • 如果省略 Component, 则调用 IMMDevice::Activate 检索接口.
  • 为 Component 连接器标识调用 QueryInterface, 如果成功, 则返回接口指针. 这可以用于检索连接器的 IPart 或 IConnector 接口.
  • 对于给定 Component 唯一的每个子单元, 都会调用 IPart::Activate. 例如, IID 可以是 "{7FB7B48F-531D-44A2-BCB3-5AD5A134B3DC}" 检索 IAudioVolumeLevel 接口, 该接口提供对每个通道音量级别控件的访问.

一旦检索到接口指针, 可用 ComCall 来调用它的方法. 参考 Windows SDK 头文件来识别正确的方法索引.

接口指针必须在不再需要时通过传递给 ObjRelease 来释放. 这可以通过使用 ComValue "包装" 它来实现. 包装的值(对象) 可以直接传递给 ComCall.

Interface := ComValue(13, InterfacePtr)

相关

Sound 函数, DeviceTopology API

示例

峰值表. 将显示带有当前峰值的工具提示, 但峰值为零时除外(无声音播放).

; IAudioMeterInformation
audioMeter := SoundGetInterface("{C02216F6-8C67-4B5B-9D00-D008E73E0064}")
if audioMeter
{
    try loop  ; 直到脚本退出或发生错误.
    {
        ; audioMeter->GetPeakValue(&peak)
        ComCall 3, audioMeter, "float*", &peak:=0
        ToolTip peak > 0 ? peak : ""
        Sleep 15
    }
    ObjRelease audioMeter
}
else
    MsgBox "Unable to get audio meter"


SoundGetMute - 语法 & 使用 | AutoHotkey v2

SoundGetMute

检索声音设备的静音设置.

Setting := SoundGetMute(Component, Device)

参数

Component

类型: 字符串或整数

如果为空或省略, 则检索主静音设置. 否则, 指定组件的显示名称和/或索引. 例如, 1, "Line in" 或 "Line in:2".

有关详情, 请参阅 Component (Sound 函数).

Device

类型: 字符串或整数

如果为空或省略, 则它默认为系统的默认回放设备(不一定是设备 1). 否则, 指定设备的显示名称和/或索引. 例如, 1, "Speakers", "Speakers:2" 或 "Speakers (Example HD Audio)".

有关详情, 请参阅 Device (Sound 函数).

返回值

类型: 整数(布尔值)

函数返回 0(false) 表示未静音, 或 1(true) 代表静音.

错误处理

如果无法找到设备或组件, 或组件不支持此控制类型, 则抛出 TargetError. 否则失败时, 抛出 OSError.

备注

要发现系统上安装的声音设备的功能 -- 比如名称和可用的组件 -- 请运行这个声卡分析脚本.

相关

Sound 函数

示例

确认默认的播放设备是否处于静音状态.

master_mute := SoundGetMute()
if master_mute
    MsgBox "The default playback device is muted."
else
    MsgBox "The default playback device is not muted."

确认 "Line In pass-through" 是否处于静音状态.

if SoundGetMute("Line In") = 0
    MsgBox "Line In pass-through is not muted."

确认麦克风(录音) 是否静音.

if SoundGetMute( , "Microphone") = 0
    MsgBox "The microphone (recording) is not muted."


SoundGetName - 语法 & 使用 | AutoHotkey v2

SoundGetName

检索声音设备或组件的名称.

Name := SoundGetName(Component, Device)

参数

Component

类型: 字符串或整数

如果为空或省略, 将检索设备本身的名称. 否则, 指定组件的显示名称和/或索引. 例如, 1, "Line in" 或 "Line in:2".

有关详情, 请参阅 Component (Sound 函数).

Device

类型: 字符串或整数

如果为空或省略, 则它默认为系统的默认回放设备(不一定是设备 1). 否则, 指定设备的显示名称和/或索引. 例如, 1, "Speakers", "Speakers:2" 或 "Speakers (Example HD Audio)".

有关详情, 请参阅 Device (Sound 函数).

返回值

类型: 字符串

行数返回设备或组件的名称, 可以为空.

错误处理

如果无法找到设备或组件, 则抛出 TargetError. 否则失败时, 抛出 OSError.

相关

Sound 函数

示例

检索并报告默认播放设备的名称.

default_device := SoundGetName()
MsgBox "The default playback device is " default_device

检索并报告第一个设备的名称.

device1 := SoundGetName( , 1)
MsgBox "Device 1 is " device1

索并报告第一个组件的名称.

component1 := SoundGetName(1)
MsgBox "Component 1 is " component1

有关更复杂的示例, 请参阅声卡分析脚本.


SoundGetVolume - 语法 & 使用 | AutoHotkey v2

SoundGetVolume

检索声音设备的音量设置.

Setting := SoundGetVolume(Component, Device)

参数

Component

类型: 字符串或整数

如果为空或省略, 则检索主音量设置. 否则, 指定组件的显示名称和/或索引. 例如, 1, "Line in" 或 "Line in:2".

有关详情, 请参阅 Component (Sound 函数).

Device

类型: 字符串或整数

如果为空或省略, 则它默认为系统的默认回放设备(不一定是设备 1). 否则, 指定设备的显示名称和/或索引. 例如, 1, "Speakers", "Speakers:2" 或 "Speakers (Example HD Audio)".

有关详情, 请参阅 Device (Sound 函数).

返回值

类型: 浮点数

函数返回 0.0 到 100.0 之间的浮点数.

错误处理

如果无法找到设备或组件, 或组件不支持此控制类型, 则抛出 TargetError. 否则失败时, 抛出 OSError.

备注

要发现系统上安装的声音设备的功能 -- 比如名称和可用的组件 -- 请运行这个声卡分析脚本.

相关

Sound 函数

示例

检索并报告主音量.

master_volume := SoundGetVolume()
MsgBox "Master volume is " master_volume " percent."

检索和报告麦克风播放音量.

mic_volume := SoundGetVolume("Microphone")
MsgBox "Microphone listening volume is " mic_volume " percent."

检索并报告麦克风的录音音量.

mic_volume := SoundGetVolume( , "Microphone")
MsgBox "Microphone recording volume is " mic_volume " percent."


SoundPlay - 语法 & 使用 | AutoHotkey v2

SoundPlay

播放音频, 视频或其他支持的文件类型.

SoundPlay Filename , Wait

参数

Filename

类型: 字符串

要播放的文件的名称, 如果未指定绝对路径, 则假定在 A_WorkingDir 中.

要发出标准的系统声音, 请指定星号后跟着数字, 如下所示. 注意: 在此模式中 Wait 参数没有效果.

  • *-1 = 简单的哔音. 如果声卡不可用, 则使用扬声器生成这个声音.
  • *16 = 手型(停止/错误声)
  • *32 = 问号声
  • *48 = 感叹声
  • *64 = 星号(消息声)
Wait

类型: 整数(布尔值) or 字符串

如果为空或省略, 则默认为 0(false). 否则, 指定下列值之一:

0(false): 在播放文件时, 当前线程会移动到下一个语句.

1(true) 或 Wait: 当前线程会等到文件播放结束后才继续执行. 但在等待时, 新线程可以通过热键, 自定义菜单或计时器来启动.

已知限制: 如果没有使用 Wait 参数, 则操作系统可能认为播放的文件 "正在使用中", 直到脚本关闭或播放另一个文件(甚至是不存在的文件).

错误处理

失败时抛出异常.

备注

所有 Windows 操作系统应该都能播放 .wav 文件. 不过, 如果操作系统中没有安装正确的解码器或功能, 那么其他文件(.mp3, .avi, 等等) 可能无法播放.

已知限制: 由于 Windows 系统的限制, 路径超过 127 个字符的 WAV 文件将不会被播放. 要解决这个问题, 可以使用其他文件类型如 MP3(路径长度最多可以有 255 个字符) 或使用 8.3 短路径(如何检索这些路径, 请参阅 A_LoopFileShortPath).

如果在播放一个文件时当前脚本播放了第二个文件, 那么第一个文件会被停止后才可以播放第二个. 在一些系统中, 即使在另一个完全独立的脚本中播放新文件时, 某些文件类型也可能停止播放.

要停止当前正在播放的文件, 请对不存在的文件使用 SoundPlay, 例如: try SoundPlay "Nonexistent.avi".

如果脚本退出了, 那么任何由它启动的当前正在播放的文件将会停止.

相关

SoundBeep, Sound 函数, MsgBox, 线程

示例

播放位于 Windows 目录下的 .wav 文件.

SoundPlay A_WinDir "\Media\ding.wav"

产生一个简单的哔哔声.

SoundPlay "*-1"


SoundSetMute - 语法 & 使用 | AutoHotkey v2

SoundSetMute

更改声音设备的静音设置.

SoundSetMute NewSetting , Component, Device

参数

NewSetting

类型: 整数

下列值之一:

  • 1 或 True 打开设置
  • 0 或 False 关闭设置
  • -1 切换设置(将其设置为与当前状态相反的状态)
Component

类型: 字符串或整数

如果为空或省略, 则更改主静音设置. 否则, 请指定组件的显示名称和/或索引. 例如, 1, "Line in" 或 "Line in:2".

有关详情, 请参阅 Component (Sound 函数).

Device

类型: 字符串或整数

如果为空或省略, 则它默认为系统的默认回放设备(不一定是设备 1). 否则, 请指定设备的显示名称和/或索引. 例如, 1, "Speakers", "Speakers:2" 或 "Speakers (Example HD Audio)".

有关详情, 请参阅 Device (Sound 函数).

错误处理

如果无法找到设备或组件, 或组件不支持此控制类型, 则抛出 TargetError. 否则失败时, 抛出 OSError.

备注

切换默认回放设备的主静音设置的另一种方法是让脚本发送一个击键, 如下例所示:

Send "{Volume_Mute}"  ; 静音/不静音主音量.

要发现系统上安装的声音设备的功能 -- 比如名称和可用的组件 -- 请运行这个声卡分析脚本.

使用 SoundGetMute 来获取当前静音设置.

相关

Sound 函数

示例

开启主音量静音.

SoundSetMute true

关闭主静音.

SoundSetMute false

切换主静音(设置到相反的状态).

SoundSetMute -1

静音 Line In.

SoundSetMute true, "Line In"

静音麦克风录音.

SoundSetMute true,, "Microphone"


SoundSetVolume - 语法 & 使用 | AutoHotkey v2

SoundSetVolume

更改声音设备的音量设置.

SoundSetVolume NewSetting , Component, Device

参数

NewSetting

类型: 字符串, 整数或浮点数

一个包含 -100 和 100(包含的) 之间的百分数的字符串. 如果这个数字以加号或减号开头, 则将 当前设置 往上或往下调指示的数量. 否则, 此设置将被明确地设置为 NewSetting 表示的级别.

如果百分数以减号开头或无符号开头, 则不需要用引号括起来.

Component

类型: 字符串或整数

如果为空或省略, 则更改主音量设置. 否则, 指定组件的显示名称和/或索引. 例如, 1, "Line in" 或 "Line in:2".

有关详情, 请参阅 Component (Sound 函数).

Device

类型: 字符串或整数

如果为空或省略, 则它默认为系统的默认回放设备(不一定是设备 1). 否则, 指定设备的显示名称和/或索引. 例如, 1, "Speakers", "Speakers:2" 或 "Speakers (Example HD Audio)".

有关详情, 请参阅 Device (Sound 函数).

错误处理

如果无法找到设备或组件, 或组件不支持此控制类型, 则抛出 TargetError. 否则失败时, 抛出 OSError.

备注

调整音量的另一种方法是让脚本发送音量控制按键来改变整个系统的主音量, 如下例所示:

Send "{Volume_Up}"  ; 增加 1 个音程的主音量(通常为 5%).
Send "{Volume_Down 3}"  ; 降低 3 个音程的主音量.

要发现系统上安装的声音设备的功能 -- 比如名称和可用的组件 -- 请运行这个声卡分析脚本.

SoundSetVolume 在更改音量级别时会尝试保持现有的平衡.

使用 SoundGetVolume 来获取当前音量设置.

相关

Sound 函数

示例

将主音量设置为百分之 50. 引号可以省略.

SoundSetVolume "50"
SoundSetVolume 50

将主音量增加百分之 10. 引号 不能 省略.

SoundSetVolume "+10"

将主音量减小百分之 10. 引号可以省略.

SoundSetVolume "-10"
SoundSetVolume -10

将麦克风录音音量增加百分之 20.

SoundSetVolume "+20", , "Microphone"


SplitPath - 语法 & 使用 | AutoHotkey v2

SplitPath

将文件名(路径) 或 URL 分解成它的名称, 目录, 扩展名和驱动器.

SplitPath Path , &OutFileName, &OutDir, &OutExtension, &OutNameNoExt, &OutDrive

参数

Path

类型: 字符串

要分析的文件名或 URL.

注意, 此函数文件名路径仅支持反斜杠(\), URL 仅支持正斜杠(/).

&OutFileName

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定 要在其中存储文件名而不包含其路径的输出变量的引用. 包含文件的扩展名.

&OutDir

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定用于存储文件目录的输出变量的引用, 包括驱动器名或共享名(如果存在). 即使文件位于驱动器的根目录中, 也不包括最后的反斜杠.

&OutExtension

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定存储文件扩展名的输出变量的引用(例如 TXT, DOC 或 EXE). 不包含句点.

&OutNameNoExt

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定用来保存不带路径, 句点和扩展名的文件名的输出变量的引用.

&OutDrive

类型: VarRef

如果省略, 则不存储相应的值. 否则, 请指定用来保存文件的驱动器字母或共享名的输出变量的引用. 如果文件在本地或映射的驱动器中, 则此变量会被设为驱动器字母后跟着冒号(没有反斜杠). 如果文件在网络路径中(UNC), 则变量会被设为共享名, 例如 \\Workstation01

备注

如果不需要相应的信息, 则可以省略相应的输出变量.

如果 Path 包含不带驱动器字母的文件名(即没有路径或只是相对路径), 则 OutDrive 会被置空, 但其他输出变量会被设置正确. 同样地, 如果没有路径, 则 OutDir 会被置空; 而如果有路径但没有文件名, 则 OutFileName 和 OutNameNoExt 都会被置空.

该函数不检查文件系统中的实际文件和目录. 它只是分析所提供的字符串.

文件名中的通配符(* 和 ?) 及其他非法字符被视为等同于合法字符, 除了冒号, 反斜杠和句点, 对它们处理时会根据它们在文件的驱动器字母, 目录和扩展名中的性质进行.

支持 URL: 如果 Path 包含一个冒号后跟两个斜杠, 例如 "https://domain.com" 或 "ftp://domain.com", 则 OutDir 会被设置为协议前缀 + 域名 + 目录(例如 https://domain.com/images), 而 OutDrive 被设置为协议前缀 + 域名(例如 https://domain.com). 其他所有变量会根据上面的定义对它们进行设置.

相关

A_LoopFileExt, StrSplit, InStr, SubStr, FileSelect, DirSelect

示例

演示不同的用法.

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:


StatusbarGetText - 语法 & 使用 | AutoHotkey v2

StatusBarGetText

获取标准状态栏控件的文本.

Text := StatusBarGetText(Part#, WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

Part#

类型: 整数

如果省略, 默认为 1, 这部分通常包含了我们感兴趣的文本. 否则, 请指定要获取的状态栏那一部分的编号.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

此函数返回状态栏控件的文本.

错误处理

如果找不到目标窗口或不包含标准状态栏, 则抛出 TargetError.

如果在发送 SB_GETPARTS 消息时出现问题, 或者在 2000 ms 内没有收到回复, 或在拥有状态栏的进程中无法分配内存, 则抛出 OSError.

备注

该函数尝试读取窗口中首个 标准 状态栏(微软通用控件: msctls_statusbar32). 某些程序使用它们自己的状态栏或微软通用控件的特殊版本, 此时无法获取它的文本.

使用 StatusBarWait 通常比在循环中使用 StatusBarGetText 更有效, 因为其包含了避免重复调用 StatusBarGetText 形成的高开销的优化.

相关

StatusBarWait, WinGetTitle, WinGetText, ControlGetText

示例

从状态栏的第一部分检索和分析文本.

RetrievedText := StatusBarGetText(1, "Search Results")
if InStr(RetrievedText, "found")
    MsgBox "Search results have been found."


StatusBarWait - 语法 & 使用 | AutoHotkey v2

StatusBarWait

等待, 直到窗口的状态栏包含指定的字符串.

StatusBarWait BarText, Timeout, Part#, WinTitle, WinText, Interval, ExcludeTitle, ExcludeText

参数

BarText

类型: 字符串

如果为空或省略, 函数等待状态栏变成空白. 否则, 请指定函数所等待的文本或部分文本. 此文本是区分大小写的, 且匹配行为由 SetTitleMatchMode 决定, 类似于下面的 WinTitle.

若要等待状态栏是否发生了 改变, 可以在循环中使用 StatusBarGetText, 或像本页底部的例子那样使用 RegEx.

Timeout

类型: 整数或浮点数

如果省略, 函数将会无限期等待. 否则, 等待的时间不会超过这个秒数. 若要等待零点几秒, 请指定一个浮点数, 例如, 0.25 表示最多等待 250 毫秒.

Part#

类型: 整数

如果省略, 默认为 1, 这部分通常包含了我们感兴趣的文本. 否则, 请指定要获取的状态栏那一部分的编号.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

Interval

类型: 整数

如果省略, 默认为 50. 否则, 请指定此函数在等待时对状态栏进行检查的时间间隔(单位为毫秒).

返回值

类型: 整数(布尔值)

如果找到匹配, 该函数返回 1(true), 如果函数超时, 则返回 0(false).

错误处理

如果找不到目标窗口或不包含标准状态栏, 则抛出 TargetError.

如果在发送 SB_GETPARTS 消息时出现问题, 或者在 2000 ms 内没有收到回复, 或在拥有状态栏的进程中无法分配内存, 则抛出 OSError.

备注

该函数尝试读取窗口中首个 标准 状态栏(Microsoft 通用控件: msctls_statusbar32). 某些程序使用它们自己的状态栏或微软通用控件的特殊版本. 不支持这样的状态栏.

在大多数时候, 与其在循环中使用 StatusBarGetText, 不如使用 StatusBarWait 来得有效率, 因为它避免重复调用 StatusBarGetText 所带来的开销.

StatusBarWait 在开始等待匹配前会确定它的目标窗口. 如果那个目标窗口关闭了, 那么此命令会停止等待, 即使存在另一个匹配指定 WinTitle 和 WinText 的窗口.

当函数处于等待状态时, 可以通过热键, 自定义菜单项或计时器启动新的线程.

相关

StatusBarGetText, WinGetTitle, WinGetText, ControlGetText

示例

在现有的资源管理器/搜索窗口中输入新的搜索模式.

if WinExist("Search Results") ; 设置上次找到的窗口以简化后面的代码.
{
    WinActivate
    Send "{tab 2}!o*.txt{enter}"  ; 在搜索窗口中, 输入要搜索的模式.
    Sleep 400  ; 给状态栏时间, 等它改变为 "Searching".
    if StatusBarWait("found", 30)
        MsgBox "The search successfully completed."
    else
        MsgBox "The function timed out."
}

等待活动窗口的状态栏发生变化.

SetTitleMatchMode "RegEx"  ; 接受正则表达式, 以便在下面使用.
if WinExist("A")  ; 设置上次找到的窗口为活动窗口(供下面使用).
{
    OrigText := StatusBarGetText()
    StatusBarWait "^(?!^\Q" OrigText "\E$)"  ; 该正则表达式等待文本发生任何变化.
}


StrCompare - 语法 & 使用 | AutoHotkey v2

StrCompare

按字母顺序比较两个字符串.

Result := StrCompare(String1, String2 , CaseSense)

参数

String1, String2

类型: 字符串

要比较的字符串.

CaseSense

类型: 字符串或整数(布尔值)

如果省略, 则默认为 Off. 否则, 指定下列值之一:

On 或 1(true): 比较区分大小写.

Off 或 0(false): 比较不区分大小写, 即字母 A-Z 被视为与其小写字母相同.

Locale: 根据当前用户的区域设置规则, 比较是不区分大小写的. 例如, 在大多数英语及西欧地区, 不仅将 A-Z 视为等同于它们的小写形式, 同时也将非-ASCII 字母(如 Ä 和 Ü) 视为等同的. 根据被比较字符串的性质, Locale 比 Off 慢 1 到 8 倍.

Logical: 类似 Locale, 但字符串中的数字被视为数字内容, 而不是文本. 例如, "A2" 被认为小于 "A10". 然而, 如果两个数字仅因前导零的存在而不同, 则前导零的字符串可能被视为 小于 另一个字符串. 确切的行为可能会在不同的操作系统版本中有所不同.

返回值

类型: 整数

指示 String1 和 String2 之间的关系, 该函数返回以下内容之一:

  • 0, 如果 String1 等于 String2
  • 正整数, 如果 String1 大于 String2
  • 负整数, 如果 String1 小于 String2

要检查两个字符串之间的特定关系, 请将结果与 0 进行比较. 例如:

a_less_than_b := StrCompare(a, b) < 0
a_greater_than_or_equal_to_b := StrCompare(a, b) >= 0

备注

此函数通常用于 sort 回调.

相关

Sort, VerCompare

示例

展示不区分大小写和区分大小写比较的区别.

MsgBox StrCompare("Abc", "abc") ; 返回 0
MsgBox StrCompare("Abc", "abc", true) ; 返回 -1


StrGet - 语法 & 使用 | AutoHotkey v2

StrGet

从内存地址或缓冲中复制字符串, 可选地从给定的代码页进行转换.

String := StrGet(Source , Length, Encoding)
String := StrGet(Source , Encoding)

参数

Source

类型: 对象或整数

包含字符串的类缓冲对象, 或字符串的内存地址.

可以使用任何实现 Ptr 和 Size 属性的对象, 但此函数针对原生的缓冲对象进行了优化. 传递具有这些属性的对象可确保函数不会从无效位置读取内存; 这样做可能会导致崩溃或其他不可预测的行为.

如果提供了类缓冲对象, 或者如果指定了 Length, 则字符串不需要以空终止符结尾.

Length

类型: 整数

如果省略(或使用 2 参数模式时), 则默认为字符串的当前长度, 前提是字符串以空终止符结尾. 否则, 请指定需读取的最大字符数.

默认情况下, 只复制到第一个二进制零. 如果 Length 为负数, 则它的绝对值指示要转换的确切字符数, 包括字符串可能包含的任何二进制零 - 换句话说, 结果始终是具有该长度的字符串.

注意: 如果字符串不是以空终止符结尾的, 则省略 Length 可能会造成访问冲突, 从而导致程序终止或其他一些不希望的结果. 指定不正确的长度可能会产生意外的行为.

Encoding

类型: 字符串

如果省略, 那么将简单地复制字符串, 而不进行任何转换. 否则, 请指定源编码; 例如, "UTF-8", "UTF-16" 或 "CP936". 对于数字标识符, 只有在 3 参数模式中, 才可以省略前缀 "CP". 指定空字符串或 "CP0" 则使用系统默认 ANSI 代码页.

返回值

类型: 字符串

函数返回复制或转换后的字符串. 如果正确地指定了源编码, 则返回值总是使用原生编码. 返回值总是以空终止符终止, 但是空终止符不包括在返回值的 length 中, 除非 Length 为负数, 如前所述.

错误处理

如果检测到无效参数, 则抛出 ValueError.

如果转换无法执行, 则抛出 OSError.

备注

注意, 返回值总是使用当前可执行文件的原生编码, 而 Encoding 指定如何解释从给定 Source 读取的字符串. 如果没有指定 Encoding, 只复制字符串而不进行任何转换.

换句话说, StrGet 用于从内存地址或缓冲检索文本, 或者将其转换为脚本可以接受的格式.

如果需要在代码页之间进行转换, 返回值的长度可能与源字符串的长度不同.

相关

字符编码, StrPut, 二进制兼容性, FileEncoding, DllCall, 缓冲对象, VarSetCapacity

示例

Length 或 Encoding 都可以直接在 Source 后面指定, 但在这种情况下 Encoding 必须是非数字的.

str := StrGet(address, "cp0")  ; 代码页 0, 未指定长度
str := StrGet(address, n, 0)   ; 最大 n 字符, 代码页 0
str := StrGet(address, 0)      ; 最大 0 字符(始终为空)


String - 语法 & 使用 | AutoHotkey v2

String

将值转换为字符串.

StrValue := String(Value)

返回值

类型: 字符串

函数返回将值 Value 转换为字符串的结果, 如果是字符串, 则返回 Value 本身.

如果 Value 是数字, 则使用默认的十进制格式.

如果 Value 是对象, 则返回值是调用 Value.ToString() 的结果. 如果对象没有这样的方法, 则抛出 MethodError. 默认情况下该方法没有实现, 因此必须由脚本定义.

相关

Type, Integer, Float, 值, 表达式, Is 函数


StrLen - 语法 & 使用 | AutoHotkey v2

StrLen

检索字符串中的字符数.

Length := StrLen(String)

参数

String

类型: 字符串

要统计其内容的字符串.

返回值

类型: 整数

函数返回指定字符串的长度.

相关

InStr, SubStr, Trim, StrLower, StrUpper, StrPut, StrGet, StrReplace, StrSplit

示例

获取和报告字符串中包含的字符数量.

StrValue := "The quick brown fox jumps over the lazy dog"
MsgBox "The length of the string is " StrLen(StrValue) ; 结果: 43


StrLower / StrUpper / StrTitle - 语法 & 使用 | AutoHotkey v2

StrLower / StrUpper / StrTitle

将字符串转换为小写, 大写, 或标题大小写.

NewString := StrLower(String)
NewString := StrUpper(String)
NewString := StrTitle(String)

参数

String

类型: 字符串

要转换的字符串.

返回值

类型: 字符串

这些函数返回指定字符串转换后的新版本.

备注

要判断一个字符或字符串是完全大写还是小写, 请使用 IsUpper, IsLower 或 RegExMatch 函数. 例如:

var := "abc"
if isUpper(var)
    MsgBox "var is empty or contains only uppercase characters."
if isLower(var)
    MsgBox "var is empty or contains only lowercase characters."
if RegExMatch(var, "^[a-z]+$")
    MsgBox "var is not empty and contains only lowercase ASCII characters."
if !RegExMatch(var, "[A-Z]")
    MsgBox "var does not contain any uppercase ASCII characters."

Format 也能实现大小写变换, 如下所示:

MsgBox Format("{:U}, {:L} and {:T}", "upper", "LOWER", "title")

相关

InStr, SubStr, StrLen, StrReplace

示例

转换字符串为小写, 并将 "this is a test." 存储在 String1.

String1 := "This is a test."
String1 := StrLower(String1)  ; 即输出可以和输入相同.

转换字符串为大写, 并将 "THIS IS A TEST." 存储在 String2.

String2 := "This is a test."
String2 := StrUpper(String2)

转换字符串为标题大写并将 "This Is A Test." 存储在 String3.

String3 := "This is a test."
String3 := StrTitle(String3, "T")


StrPtr - 语法 & 使用 | AutoHotkey v2

StrPtr

返回字符串的当前内存地址.

Address := StrPtr(Value)

参数

Value

类型: 字符串

返回值

类型: 整数

该函数返回 Value 的当前内存地址.

备注

一个地址的寿命以及对它进行哪些操作是有效的, 取决于 Value 是如何传递给这个函数的. 有三种不同的情况, 如下面的示例代码所示. 在所有情况下, 如果字符串 不会 被修改, 返回值可以 直接 传递给 DllCall 函数或 SendMessage.

Ptr := StrPtr(MyVar)

如果 Value 是一个变量引用(如 MyVar)(而不是内置变量), 那么返回值就是变量内部字符串缓冲的内存地址. VarSetStrCapacity(&MyVar) 以字符为单位 返回缓冲的大小, 不包括终止的空字符.

这个地址应该被认为是有效的, 直到变量被释放或被重新赋值(通过赋值运算符或将其传递给内置函数). 在函数返回后, 函数的局部变量的内容地址是无效的, 因为局部变量是自动释放的.

该地址可以存储在 structure(结构体) 或其他变量中, 并间接传递给 DllCall 或 SendMessage 或以其他方式使用, 只要它仍然有效, 如上所述.

脚本可以通过将地址间接传递给 NumPut, DllCall 或 SendMessage 来改变字符串的值. 如果以这种方式改变了字符串的长度, 必须通过调用 VarSetStrCapacity(&MyVar, -1) 来更新变量的内部长度属性.

Ptr := StrPtr("literal string")

原义字符串的地址是有效的, 直到程序退出. 脚本不应试图修改该字符串. 该地址可以存储在结构体或其他变量中, 并间接传递给 DllCall 或 SendMessage 或以其他方式使用.

SendMessage 0x000C, 0, StrPtr(A_ScriptName " changed this title"),, "A"

临时字符串的地址只在整体表达式的计算或函数调用语句完成之前有效, 之后不得使用. 对于上面的例子, 地址在 SendMessage 返回之前都是有效的. 以下所有内容都会产生临时字符串:

  • 连接.
  • 内置变量, 如 A_ScriptName.
  • 返回字符串的函数.
  • 访问对象的属性, 数组元素或映射元素.

如果上面没有明确说明, 可以安全的假定字符串是临时的.

相关

VarSetStrCapacity, DllCall, SendMessage, Buffer 对象, NumPut, NumGet


StrPut - 语法 & 使用 | AutoHotkey v2

StrPut

复制字符串到内存地址或缓冲, 可选地将字符串转换到给定的代码页.

BytesWritten := StrPut(String, Target , Length, Encoding)
BytesWritten := StrPut(String, Target , Encoding)
ReqBufSize   := StrPut(String , Encoding)

参数

String

类型: 字符串

任何字符串. 如果给定一个数字, 它将自动转换为字符串.

String 被假定为使用原生编码.

Target

类型: 对象或整数

类缓冲对象或内存地址, 字符串将写入其中.

可以使用任何实现 Ptr 和 Size 属性的对象, 但此函数针对原生的缓冲对象进行了优化. 传递具有这些属性的对象可确保函数不会将内存写入无效位置; 这样做可能会导致崩溃或其他不可预测的行为.

注意: 如果需要在代码页之间进行转换, 则所需的缓冲大小可能与源字符串的大小不同. 对于这种情况, 调用带有两个参数的 StrPut 来计算所需的大小.

Length

类型: 整数

要写入的最大字符数, 如果需要, 请包含空终止符.

如果 Length 为 0 或小于转换后的计划长度(或不需要转换时, 源字符串的长度), 则抛出异常.

Length 不能被省略, 除非已知缓冲大小足够, 例如, 如果缓冲是基于先前使用相同的 String 和 Encoding 调用 StrPut 分配的.

如果 Target 是一个对象, 指定一个超过 Target.Size 计算出的缓冲大小的 Length 被认为是一个错误, 即使转换后的字符串大小在缓冲内.

注意: 当指定 Encoding 时, Length 应该是缓冲的大小(以字符为单位), 而不是 String 或子字符串的长度, 因为转换可能会增加其长度.

注意: Length 是以字符数来计算的, 而缓冲大小通常以字节度量, StrPut 的返回值也是如此. 若要以字节为单位来指定缓冲大小, 请在 Target 参数中使用类缓冲对象.

Encoding

类型: 字符串或整数

如果省略, 那么将简单地复制或测量字符串, 而不进行任何转换. 否则, 请指定目标编码; 例如, "UTF-8", "UTF-16" 或 "CP936". 对于数字标识符, 只有在 4 参数模式中, 才可以省略前缀 "CP". 指定空字符串或 "CP0" 则使用系统默认 ANSI 代码.

返回值

类型: 整数

在 4 或 3 参数模式下, 函数返回写入的的字节数. 只有当有足够的空间时, 才会写入空终止符并包含在返回值中; 也就是说, 当 Length 或 Target.Size(乘以一个字符的大小) 正好等于转换后的字符串的长度时, 则会省略空终止符.

在 2 参数模式下, 函数返回以字节数表示的所需的缓冲大小, 其中包含了空终止符.

错误处理

如果检测到无效参数, 则抛出 ValueError, 例如转换后的字符串会超过 Length 或 Target.Size 所允许的长度.

如果转换无法执行, 则抛出 OSError.

备注

注意, String 参数总是假定使用当前可执行文件的原生编码, 而 Encoding 指定写入给定 Target 的字符串的编码. 如果没有指定 Encoding, 则只复制或测量字符串, 而不进行任何转换.

相关

字符编码, StrGet, 二进制兼容性, FileEncoding, DllCall, 缓冲对象, VarSetStrCapacity

示例

Length 或 Encoding 都可以直接在 Target 后面指定, 但在这种情况下 Encoding 必须是非数字的.

StrPut(str, address, "cp0")  ; 代码页 0, 未指定缓冲大小
StrPut(str, address, n, 0)   ; 最大 n 字符, 代码页 0
StrPut(str, address, 0)      ; 不支持(最大长度为 0 的字符)

可以调用一次 StrPut, 来计算特定编码中的字符串所需的缓冲大小, 然后再次对字符串进行编码并将其写入缓冲. 这个过程可以通过利用这个函数来简化.

; 返回包含字符串的缓冲对象.
StrBuf(str, encoding)
{
    ; 计算所需的大小并分配缓冲.
    buf := Buffer(StrPut(str, encoding))
    ; 复制或转换字符串.
    StrPut(str, buf, encoding)
    return buf
}


StrReplace - 语法 & 使用 | AutoHotkey v2

StrReplace

用新字符串替换指定的子字符串.

ReplacedStr := StrReplace(Haystack, Needle , ReplaceText, CaseSense, &OutputVarCount, Limit)

参数

Haystack

类型: 字符串

内容被搜索和替换的字符串.

Needle

类型: 字符串

要搜索的字符串.

ReplaceText

类型: 字符串

如果为空或省略, 那么 Needle 会被替换为空. 这意味着它将在返回值中被省略. 否则, 请指定替换 Needle 的文本.

CaseSense

类型: 字符串或整数(布尔值)

如果省略, 则默认为 Off. 否则, 指定下列值之一:

On 或 1(true): 搜索区分大小写.

Off 或 0(false): 搜索不区分大小写, 即字母 A-Z 被视为与其小写字母相同.

Locale: 根据当前用户的区域设置规则, 搜索是不区分大小写的. 例如, 在大多数英语及西欧地区, 不仅将 A-Z 视为等同于它们的小写形式, 同时也将非-ASCII 字母(如 Ä 和 Ü) 视为等同的. 根据被比较字符串的性质, Locale 比 Off 慢 1 到 8 倍.

&OutputVarCount

类型: VarRef

如果省略, 将不存储相对的值. 否则, 请指定输出变量的引用, 其中储存了要进行替换的数量(没有则为 0).

Limit

类型: 整数

如果省略, 则默认为 -1, 它将替换 Haystack 中找到的 所有 模式. 否则, 请指定允许的最大替换数量. Haystack 最后一个替换对象右边的内容将保持不变.

返回值

类型: 字符串

此函数返回指定字符串的替换版本.

备注

内置变量 A_Space 和 A_Tab 分别包含了单个空格和单个制表符. 当在 Needle 的开头或结尾或单独搜索空格和制表符时, 这很有用.

相关

RegExReplace, InStr, SubStr, StrLen, StrLower, StrUpper

示例

移除剪贴板中所有的 CR-LF 对.

A_Clipboard := StrReplace(A_Clipboard, "`r`n")

用加号替换所有空格.

NewStr := StrReplace(OldStr, A_Space, "+")

移除变量文本中所有空行.

Loop
{
    MyString := StrReplace(MyString, "`r`n`r`n", "`r`n",, &Count)
    if (Count = 0)  ; 不再需要更多的替换.
        break
}


StrSplit - 语法 & 使用 | AutoHotkey v2

StrSplit

使用指定的分隔符将字符串分成子字符串数组.

Array := StrSplit(String , Delimiters, OmitChars, MaxParts)

参数

String

类型: 字符串

要分割的字符串.

Delimiters

类型: 字符串或数组

如果为空或省略, 那么将把输入字符串中的每个字符解析为单独的子字符串.

否则, 请指定单个字符串或字符串数组(区分大小写), 每个分隔符用于确定子字符串之间的边界出现的位置. 由于分隔符不被视为子字符串本身的一部分, 因此它们决不会包含在返回的数组中. 同样, 如果输入字符串中的一对定界符之间没有任何内容, 则对应的数组元素将为空.

例如: "," 将根据逗号每次出现的位置分割字符串. 同样地, 使用 [A_Space, A_Tab] 作为分隔符将在输入字符串中每次遇到空格或制表符时创建一个新的数组元素.

OmitChars

类型: 字符串

如果为空或省略, 则不会排除任何字符. 否则, 请指定要从每个数组元素的开始和结尾部分移除的字符列表(区分大小写). 例如, 如果 OmitChars 是 " `t", 那么每个元素中开始和结尾部分(但中间的不会) 的空格和制表符会被移除.

如果 Delimiters 为空, 那么 OmitChars 表示需要从数组中排除的那些字符.

MaxParts

类型: 整数

如果省略, 则默认为 -1, 表示 "没有限制". 否则, 请指定返回的子字符串的最大数目. 如果非零, 则字符串最多被分割 MaxParts-1 次, 并且在最后一个子字符串中返回字符串的其余部分(不包括任何前导或尾随的 OmitChars).

返回值

类型: a href="Array.htm">Array

函数返回一个包含指定字符串的子字符串的数组.

备注

除非空格和制表符之类的空白字符包含在 Delimiters 或 OmitChars 参数中, 否则它们将被保留. 可以使用 Trim 从任何变量的两端移除空格和制表符. 例如: Var := Trim(Var)

要拆分标准 CSV(逗号分隔值) 格式的字符串, 请使用解析循环, 因为它具有内置 CSV 处理功能.

要在分割前按不同的顺序排列字段, 请使用 Sort 函数.

如果您不需要把子字符串长时间的存储到内存中, 建议使用解析循环 -- 尤其在 String 非常大时可以节约大量内存. 例如:

Colors := "red,green,blue"
Loop Parse, Colors, ","
    MsgBox "Color number " A_Index " is " A_LoopField

相关

Parsing loop, Sort, SplitPath, InStr, SubStr, StrLen, StrLower, StrUpper, StrReplace

示例

将一个句子拆分成单词数组, 并报告第四个单词.

TestString := "This is a test."
word_array := StrSplit(TestString, A_Space, ".")  ; 忽略句点.
MsgBox "The 4th word is " word_array[4]

将一个以逗号分隔的颜色列表拆分成一个子字符串数组, 并逐个遍历它们.

colors := "red,green,blue"
For index, color in StrSplit(colors, ",")
    MsgBox "Color number " index " is " color


SubStr - 语法 & 使用 | AutoHotkey v2

SubStr

从字符串中的指定位置检索一个或多个字符.

NewStr := SubStr(String, StartingPos , Length)

参数

String

类型: 字符串

要复制其内容的字符串. 这可能包含二进制零.

StartingPos

类型: 整数

指定 1 从首个字符开始, 2 从第二个开始, 依此类推. 如果 StartingPos 为 0 或超过了 String 的长度, 则返回空字符串.

指定一个负的 StartingPos 以从右边的那个位置开始. 例如, -1 提取最后一个字符, 而 -2 提取最后两个字符. 如果 StartingPos 试图超出字符串的左端, 提取将从第一个字符开始).

Length

类型: 整数

如果省略, 则默认为 "全部字符". 否则, 请指定为需提取字符的最大数目(当字符串剩余部分太短时提取的数目会比最大值少).

您还可以指定负的 Length 从而在返回字符串的末尾省略这个数目的字符(如果省略了全部或过多字符, 则返回空字符串).

返回值

类型: 字符串

此函数返回所请求的指定字符串的子字符串.

相关

RegExMatch

示例

在第 4 的位置检索一个长度为 3 个字符的子串.

MsgBox SubStr("123abc789", 4, 3) ; 返回 abc

分别从一个字符串的开头和结尾处开始检索一个子串.

Str := "The Quick Brown Fox Jumps Over the Lazy Dog"
MsgBox SubStr(Str, 1, 19)  ; 返回 "The Quick Brown Fox"
MsgBox SubStr(Str, -8)  ; 返回 "Lazy Dog"


Suspend - 语法 & 使用 | AutoHotkey v2

Suspend

禁用或启用所有的或选择的热键和热字串.

Suspend NewState

参数

NewState

类型: 整数

如果省略, 默认为 -1. 否则, 请指定以下值之一:

1 或 True: 挂起所有的热键和热字串, 备注部分说明的豁免除外.

0 或 False: 重新启用上面禁用的热键和热字串.

-1: 更改为与以前状态相反的状态(On 或 Off).

备注

默认情况下, 脚本也可以通过它的托盘图标或主窗口来挂起.

热键/热字串可以通过在它前面加上 #SuspendExempt 指令来避免挂起. 即使挂起为 ON, 豁免热键/热字符串将保持启用. 这允许通过热键来关闭挂起, 否则这是不可能的, 因为热键将被挂起.

如果此函数所做的更改有充分理由, 那么键盘和/或鼠标钩子将安装或删除.

要根据任何条件(如活动窗口的类型) 自动禁用选定的热键或热字串, 请使用 #HotIf.

挂起脚本的热键不会停止脚本中已经运行的线程(如果有); 请使用 Pause 来让它停止.

当脚本的热键挂起时, 它的托盘图标会变为 a green icon with a transparent H (或为 a green icon with a transparent Pause symbol, 如果脚本同时也被暂停). 可以通过冻结图标来避免图标更改, 这通过使用 TraySetIcon(,, true) 来实现.

当脚本挂起时, 内置变量 A_IsSuspended 为 1, 否则为 0.

相关

#SuspendExempt, 热键, 热字串, #HotIf, Pause, ExitApp

示例

按下一次热键可暂停所有热键和热字串. 再按一次可取消暂停.

#SuspendExempt
^!s::Suspend  ; Ctrl+Alt+S
#SuspendExempt False

发送 Suspend 函数到另一个脚本.

DetectHiddenWindows True
WM_COMMAND := 0x0111
ID_FILE_SUSPEND := 65404
PostMessage WM_COMMAND, ID_FILE_SUSPEND,,, "C:\YourScript.ahk ahk_class AutoHotkey"


Switch - 语法 & 使用 | AutoHotkey v2

Switch

将一个值与多个实例进行比较, 并执行第一个匹配的语句.

Switch SwitchValue, CaseSense
{
Case CaseValue1:
    Statements1
Case CaseValue2a, CaseValue2b:
    Statements2
Default:
    Statements3
}

参数

SwitchValue

如果 CaseSense 省略, 将执行第一个计算为 true(非零和非空) 的实例. 否则, 对 SwitchValue 进行一次计算并与每个实例值进行比较, 直到找到匹配为止, 然后执行该实例.

如果没有匹配的实例并且存在 Default, 则执行它.

CaseSense

类型: 字符串或整数(布尔值)

如果省略, 则默认为 On. 否则, 指定以下值之一, 以强制所有值作为字符串进行比较:

On 或 1(true): 每次比较区分大小写.

Off 或 0(false): 每次比较不区分大小写, 即字母 A-Z 被视为等同于其小写字母.

Locale: 根据当前用户地区的规则, 每次比较都是不区分大小写的. 例如, 在大多数英语及西欧地区, 不仅将 A-Z 视为等同于它们的小写形式, 同时也将非-ASCII 字母(如 Ä 和 Ü) 视为等同的. 根据被比较字符串的性质, Locale 比 Off 慢 1 到 8 倍.

CaseValueN

要检查或比较的值, 取决于 SwitchValue 是否存在.

备注

与 = 和 == 运算符一样, 当省略 CaseSense 时, 如果 SwitchValue 和实例值都是纯数字, 或者其中一个是纯数字而另一个是数字字符串, 则会执行数字比较. 每个实例值都是单独考虑的, 并不影响用于其他实例值的比较类型.

如果 CaseSense 参数存在, 所有的值都作为字符串而不是数字进行比较, 如果 SwitchValue 或 CaseValue 被计算为一个对象, 则会抛出一个 TypeError.

如果忽略 CaseSense 参数, 默认情况下字符串比较是区分大小写的.

每个实例最多可以列出 20 个值. 每个值必须是一个表达式, 但可以是一个原义数字, 加引号的字符串或变量. Case 和 Default 必须以冒号(:) 终止.

每个实例的第一个语句可以在 Case 下面, 也可以在同一行, 挨着冒号. 每个实例都隐式地以下一个 Case/Default 或右大括号结束. 与在其他一些语言中找到的 switch 语句不同, 没有隐式的落下直通和不使用 Break(除非用于跳出封闭循环).

由于所有实例都包含在同一个块中, 因此在一个实例中定义的标签可以是另一个案例的 Goto 的目标. 但是, 如果标签位于 Case 或 Default 的正上方, 则它将指向前一个实例的结尾, 而不是下一个实例的开头.

Default 不需要列在最后.

相关

If, Else, 区块

示例

将一个数字与多个实例进行比较, 并显示第一个匹配的消息框.

switch 2
{
case 1: MsgBox "no match"
case 2: MsgBox "match"
case 3: MsgBox "no match"
}

SwitchValue 参数可以省略, 以执行第一个计算结果为 true 的情况.

str := "the red fox jumps over the lazy brown dog"
switch
{
case InStr(str, "blue"):  MsgBox "false"
case InStr(str, "red"):   MsgBox "true"
case InStr(str, "green"): MsgBox "false"
}

要测试这个例子, 输入 [ 后面跟着下面列出的一个缩写, 任何其他 5 个字符, 或 Enter/Esc/Tab/.; 或等待 4 秒.

~[::
{
    ih := InputHook("V T5 L4 C", "{enter}.{esc}{tab}", "btw,otoh,fl,ahk,ca")
    ih.Start()
    ih.Wait()
    switch ih.EndReason
    {
    case "Max":
        MsgBox 'You entered "' ih.Input '", which is the maximum length of text'
    case "Timeout":
        MsgBox 'You entered "' ih.Input '" at which time the input timed out'
    case "EndKey":
        MsgBox 'You entered "' ih.Input '" and terminated it with ' ih.EndKey
    default:  ; 匹配
        switch ih.Input
        {
        case "btw":   Send "{backspace 4}by the way"
        case "otoh":  Send "{backspace 5}on the other hand"
        case "fl":    Send "{backspace 3}Florida"
        case "ca":    Send "{backspace 3}California"
        case "ahk":
            Send "{backspace 3}"
            Run "https://www.autohotkey.com"
        }
    }
}


SysGet - 语法 & 使用 | AutoHotkey v2

SysGet

获取系统对象的尺寸和其他系统属性.

Value := SysGet(Property)

参数

Property

类型: 整数

从下面的表格中指定一个数字来检索对应的值.

返回值

类型: 整数

此函数返回指定的系统属性的值.

常用的

数字 | 描述
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: 虚拟屏幕左边和上面的坐标. 虚拟屏幕是所有监视器的边框. 与之相比, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN 度量(较远的上面) 为虚拟屏幕的宽度和高度.

不常用的

数字 | 描述
56 | SM_ARRANGE: 指定系统排列最小化窗口方式的标志. 请参阅 Microsoft Docs 了解更多信息.
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 的转换可能无法正确执行, 或者不存在某些组件, 例如字体或注册表设置.
40 | SM_MENUDROPALIGNMENT: 如果下拉菜单与相应的菜单项右对齐时为非零值; 而左对齐时为零.
74 | SM_MIDEASTENABLED: 如果系统启用了希伯来和阿拉伯语言则为非零值, 如果没有则为零.
41 | SM_PENWINDOWS: 如果安装了 Microsoft Windows for Pen computing 扩展则为非零值; 否则为零.
44 | SM_SECURE: 如果存在安全支持则为非零值; 否则为零.
81 | SM_SAMEDISPLAYFORMAT: 如果所有的监视器使用相同的颜色格式则为非零值, 否则为零. 请注意两个显示器中可以含有相同的位深度, 但是不同的颜色格式. 例如, 红, 绿和蓝像素可以使用不同的位数进行编码, 或者这些位可能位于像素颜色值的不同地方.

备注

SysGet 只是调用了 GetSystemMetrics 函数, 该函数可能支持比本文中描述的更多的系统属性.

相关

DllCall, 窗口函数, 监视器函数

示例

检索鼠标按钮的数量, 并将其存储在 MouseButtonCount.

MouseButtonCount := SysGet(43)

读取虚拟屏幕的宽度和高度, 并将其存储在 VirtualScreenWidth 和 VirtualScreenHeight 中.

VirtualScreenWidth := SysGet(78)
VirtualScreenHeight := SysGet(79)


SysGetIPAddresses - 语法 & 使用 | AutoHotkey v2

SysGetIPAddresses

返回系统的 IPv4 地址数组.

Addresses := SysGetIPAddresses()

参数

此函数没有参数.

返回值

类型: Array

函数返回一个数组, 其每个元素是 IPv4 地址字符串, 如 "192.168.0.1".

备注

目前仅支持 IPv4.

此函数仅返回计算机网络适配器的 IP 地址. 如果计算机通过路由器连接到 Internet, 这将不包括计算机的公共(Internet) IP 地址. 要确定计算机的公共 IP 地址, 请使用外部 web API. 例如:

whr := ComObject("WinHttp.WinHttpRequest.5.1")
whr.Open("GET", "https://api.ipify.org")
whr.Send()
MsgBox "Public IP address: " whr.ResponseText

相关

A_ComputerName

示例

检索并报告系统的 IPv4 地址.

addresses := SysGetIPAddresses()
msg := "IP addresses:`n"
for n, address in addresses
    msg .= address "`n"
MsgBox msg


Thread - 语法 & 使用 | AutoHotkey v2

Thread

设置线程的优先级或是否可以被中断. 它也可以临时禁用所有的计时器.

Thread SubFunction , Value1, Value2

SubFunction, Value1 和 Value2 参数互相依赖, 其用法描述如下.

子函数

对于 SubFunction, 指定以下之一:

  • NoTimers: 防止被任何的计时器中断.
  • Priority: 更改当前线程的优先级级别.
  • Interrupt: 更改新启动的线程的可中断时间.

NoTimers

防止被任何计时器中断.

Thread "NoTimers" , False

此子函数防止线程被任何计时器中断, 直至当前线程结束, 或执行 Thread "NoTimers", false, 或被另一个允许计时器的线程中断(这样的情况下, 计时器可以中断正在中断的线程直到计时器完成).

如果自动执行线程没有改变这个设置, 则所有线程均以可被计时器中断的方式启动(然而下面的 Interrupt 子函数设置仍会生效). 相比之下, 如果在自动执行线程中打开了这一设置, 但却从没有关闭它, 则每个新启动的线程(如 热键, 自定义菜单项或计时器) 均以不会被计时器中断的方式启动.

不论默认的设置如何, 当脚本没有其他线程时计时器总能执行(除非使用了 Pause).

Thread "NoTimers" 等同于 Thread "NoTimers", true. 此外, 由于 False 参数是一个表达式, 因此 true 解析为 1, 而 false 解析为 0. 有关详情, 请参阅布尔值.

Priority

更改当前线程的优先级级别.

Thread "Priority", Level

指定 Level 为介于 -2147483648 和 2147483647 之间的整数(或表达式) 来表示当前线程的新优先级. 这不会影响其他线程. 有关详情, 请参阅线程.

由于具有缓冲事件的能力, 函数 Critical 通常优于这个子函数.

相关提示, 整个脚本的操作系统优先级可以通过 ProcessSetPriority 来改变. 例如:

ProcessSetPriority "High"

Interrupt

更改新启动的线程的可中断时间.

Thread "Interrupt" , Duration, LineCount

注意: 应该谨慎使用此子函数, 因为大多数脚本在接近默认设置的情况下执行更一致.

默认情况下, 每个新启动的线程在开始的 Duration(15 毫秒) 或 LineCount(1000 行) 中都是不中断的, 以先到者为准. 这使线程有机会完成操作, 而不是被正在等待启动的另一个线程立即中断(如, 缓冲的热键或计划运行的计时器子程序).

注意: 任何 Duration 小于 17 可能导致实际持续时间缩短或直接中断, 因为系统刻度计数的最小分辨率为 10 到 16 毫秒. 但是, 在线程中断之前, 将至少执行一行, 从而允许脚本在需要时启用 Critical.

如果任一参数为 0, 每个新启动的线程都可以被立即中断. 如果任一参数为 -1, 那么此参数会使得线程不会被中断. 这两个参数的最大值为 2147483647.

这个设置是全局的, 这意味着着它影响所有后续的线程, 即使此函数没有被自动执行线程调用. 然而, 已经被中断过的线程则不受影响, 因为它们不可中断的时间已经期满. 同样地, 当前线程不受影响, 除非在更改 LineCount 参数时当前线程是不中断的, 在这种情况下, 新的 LineCount 将对其生效.

如果在当前线程处于不可中断状态时, 按下了热键或选择了自定义菜单项, 那么这些事件会被缓冲起来. 换句话说, 到当前线程结束或变得可中断时(无论先遇到哪个) 它们才会运行. 例外情况是当当前线程在结束前变得可中断并且它的优先级高于被缓冲的事件, 此时被缓冲的事件将被取消缓冲并被丢弃.

不论此子函数如何, 当一个线程在显示 MsgBox, InputBox, FileSelect 或 DirSelect 对话框时都将变成可中断的.

任一参数都可以留空来保持此设置不变.

备注

由于更大的灵活性和缓冲事件的能力, 函数 Critical 通常比 Thread "Interrupt" 和 Thread "Priority" 更有效.

相关

Critical, 线程, Hotkey, Menu 对象, SetTimer, Process 函数

示例

使当前线程的优先级稍高于平均值.

Thread "Priority", 1

让每个新启动的线程变成可立即中断的.

Thread "Interrupt", 0

让每个线程在 50 ms 或 2000 行(无论先遇到哪个) 之后变成可中断.

Thread "Interrupt", 50, 2000


Throw - 语法 & 使用 | AutoHotkey v2

Throw

发生错误时发出信号. 此信号可以被 Try-Catch 语句捕获.

Throw Value

参数

Value

要抛出的值; 通常是一个 Error 对象. 例如:

throw ValueError("Parameter #1 invalid", -1, theBadParam)

所有类型的值都可以被抛出, 但是如果使用 Catch 而不指定一个类(或者使用 Try 而不使用 Catch 或 Finally), 它将只捕获 Error 类的实例.

当在 Catch 中执行时, 可以省略 Value 来重新抛出捕获的值(避免仅为此目的指定一个输出变量). 这甚至在嵌套的 Try-Finally 中也支持, 但在嵌套的 Try-Catch 中不支持. 带有 Throw 的行不需要被 Catch 语句的主体所包含; 它可以被调用的函数所使用.

备注

如果表达式被括在括号中, 则 throw 后的空格或制表符是可选的 , 如 throw(Error()) 所示.

一个抛出的值或运行时错误可以被 Try-Catch 捕获. 在这种情况下, 执行被转移到 catch 语句或 try 之后的下一个语句. 如果一个抛出的值没有被捕获, 会发生以下情况:

  • 任何激活的 OnError 回调都会被调用. 每个回调可以检查 Value 并抑制或允许进一步的回调和默认处理.
  • 默认情况下, 会根据抛出的内容显示错误信息. 如果 Value 是一个对象, 并且拥有一个名为 Message 的值属性, 那么它的值将被用作消息. 如果 Value 是一个非数字字符串, 则使用它作为消息. 在任何其他情况下, 都会使用一个默认的消息. 如果 Value 是数字, 则显示在默认消息的下方.
  • 线程退出. 请注意, 这不一定发生在可持续的错误上, 但 throw 永远是不可持续的.

相关

Error 对象, Try, Catch, Finally, OnError

示例

请参阅 Try.


ToolTip - 语法 & 使用 | AutoHotkey v2

ToolTip

在屏幕的任意位置显示一个置顶的窗口.

ToolTip Text, X, Y, WhichToolTip

参数

Text

类型: 字符串

如果为空或省略, 则隐藏现有的工具提示(如果有). 否则, 指定为要在工具提示中显示的文本. 要创建多行的工具提示, 请在每行之间使用换行符(`n), 例如 Line1`nLine2.

如果 Text 较长, 可以通过延续片段的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

X, Y

类型: 整数

如果省略, 则工具提示显示在鼠标光标附近. 否则, 请指定 the相对于活动窗口客户端区域的 X 和 Y 坐标(请使用 CoordMode "ToolTip" 来让坐标相对于屏幕).

WhichToolTip

类型: 整数

如果省略, 默认为 1(第一个工具提示). 否则, 请指定一个介于 1 和 20 之间的数字, 在同时使用了多个工具提示时, 用来表示要操作的工具提示窗口.

返回值

类型: 整数

如果一个工具提示正在显示或更新, 这个函数返回工具提示窗口的唯一 ID(HWND), 它可以用来移动工具提示或发送工具提示控制消息.

如果 Text 为空或省略, 返回值为零.

备注

工具提示通常看起来像这样: ToolTip

如果 X 和 Y 坐标让工具提示离开屏幕, 或在 Windows 8 或更高版本的显示器工作区域之外, 则会对其进行重新定位以使其完全可见.

工具提示会一直显示, 直到出现以下情况之一:

  • 脚本终止.
  • 再次执行 ToolTip 函数, 并且 Text 参数为空.
  • 用户点击了工具提示(此行为可能因操作系统版本而有所不同).

GUI 窗口可以通过 OwnDialogs 选项成为工具提示的所有者. 这样的工具提示在其拥有者被销毁时也会自动被销毁.

相关

CoordMode, TrayTip, GUI, MsgBox, InputBox, FileSelect, DirSelect

示例

在活动窗口的特定位置显示一个多行工具提示.

ToolTip "Multiline`nTooltip", 100, 150

在一段时间后隐藏工具提示, 而不使用 Sleep(它会停止当前线程).

ToolTip "Timed ToolTip`nThis will be displayed for 5 seconds."
SetTimer () => ToolTip(), -5000


TraySetIcon - 语法 & 使用 | AutoHotkey v2

TraySetIcon

更改脚本的托盘图标(它也被 GUI 和对话框窗口使用).

TraySetIcon(FileName, IconNumber, Freeze)

参数

FileName

类型: 字符串

如果省略, 则使用 当前 托盘图标, 这只对 Freeze 有意义. 否则, 请指定图标或图片的路径, 位图或图标句柄(如 "HICON:" handle), 或星号(*) 将脚本恢复到其默认图标.

IconNumber

类型: 整数

如果省略, 则它默认为 1(文件中除第一组图标). 否则, 请指定要使用的图标组的编号. 例如, 2 将加载第二组图标中的默认图标. 如果 IconNumber 为负数, 则假定其绝对值表示可执行文件中图标的资源 ID. 如果省略 FileName, IconNumber 将被忽略.

Freeze

类型: 布尔值

如果省略, 则图标的冻结/解冻状态保持不变.

如果为 true, 冻结图标, 例如 Pause 和 Suspend 将不会改变图标.

如果为 false, 将解冻图标.

备注

若要冻结(或解冻) 当前 图标, 使用函数如下所示: TraySetIcon(,, true).

改变托盘图标同时也改变由 InputBox 和后续创建的 GUI 窗口显示的图标. 也会影响已编译脚本, 即使它在编译时指定了自定义的图标. 注意: 如果之前使用如 #NoTrayIcon 的方法隐藏了托盘图标, 则改变图标不会让它显示出来; 要让它显示, 请使用 A_IconHidden := false.

从 .ICO 外的其他类型文件中加载托盘图标时可能产生轻微的变形. 尤其是对于 16x16 的图标. 要避免此问题, 请把要使用的托盘图标保存为 .ICO 文件.

操作系统的 DLL 和 CPL 文件包含的一些内置图标可能会有用. 例如: TraySetIcon "Shell32.dll", 174.

内置变量 A_IconNumber 和 A_IconFile 分别包含了当前图标的编号和名称(带完整路径)(如果为默认图标则两者都为空).

托盘图标的工具提示可以通过给 A_IconTip 赋值来更改.

相关

#NoTrayIcon, TrayTip, Menu 对象


TrayTip - 语法 & 使用 | AutoHotkey v2

TrayTip

在托盘图标附近显示一个气球提示窗口. 在 Windows 10 及后续版本中, 显示一个 toast 通知.

TrayTip Text, Title, Options

参数

Text

类型: 字符串

如果为空或省略, 则会移除托盘提示中的文本, 这会让它垂直高度变短. 否则, 请指定请托盘提示要显示的消息. 仅显示前 255 个字符.

可以使用回车(`r) 或换行(`n) 来创建多行文本. 例如: Line1`nLine2.

如果 Text 较长, 可以通过延续片段的方法将其分解成较短的几行, 这样可以增加可读性和可维护性.

Title

类型: 字符串

如果为空或省略, 则会移除托盘提示的标题行, 这会让它垂直高度变短. 否则, 请指定托盘提示的标题. 仅显示前 63 个字符.

Options

类型: 字符串或整数

如果为空或省略, 则默认为 0. 否则, 请指定一个整数值(由加法或按位或的组合), 也可以是一个由至少一个空格或制表符分隔的不区分大小写的零或多个选项字符串. 字符串中还可以包含一个或多个数字选项.

功能 | 十进制值 | 十六进制值 | 字符串
无图标 | 0 | 0x0 | N/A
信息图标 | 1 | 0x1 | Iconi
警告图标 | 2 | 0x2 | Icon!
错误图标 | 3 | 0x3 | Iconx
托盘图标 | 4 | 0x4 | N/A
不播放通知音. | 16 | 0x10 | Mute
使用大图标. | 32 | 0x20 | N/A

如果省略 Title, 也不会显示图标(这不适用于 Windows 10 及后续版本的 toast 通知).

在 Windows 10 及后续版本中, 即使省略了 "tray icon" 选项 (4), 小托盘图标通常也会显示, 并且指定该选项可能会导致程序的名称显示在通知中.

隐藏托盘提示

若要隐藏托盘提示, 请省略所有参数(或至少省略 Text 和 Title 参数). 例如:

TrayTip

要在 Windows 10 上隐藏托盘提示, 临时移除托盘图标(根据至少一个报告, 这并不总是工作). 例如:

TrayTip "#1", "This is TrayTip #1"
Sleep 3000   ; 让它显示 3 秒钟.
HideTrayTip
TrayTip "#2", "This is the second notification."
Sleep 3000

; 将此函数复制到脚本中使用.
HideTrayTip() {
    TrayTip  ; 尝试以普通的方式隐藏它.
    if SubStr(A_OSVersion,1,3) = "10." {
        A_IconHidden := true
        Sleep 200  ; 可能有必要调整 sleep 的时间.
        A_IconHidden := false
    }
}

备注

在 Windows 10 中, 托盘提示窗口通常是这样的:

Windows 10 及后续版本 默认以 toast 通知替换气球提示窗口(这能被重置通过主策略). TrayTip 多次调用通常会导致多个通知被放置在一个 "队列" 而不是每个通知取代最近的那个.

如果脚本没有托盘图标(使用 #NoTrayIcon 或 A_IconHidden := true), 则 TrayTip 没有效果. 同样地, 如果下列的 REG_DWORD 值存在且被设置为 0, 则 TrayTip 没有效果:

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced >> EnableBalloonTips

相关提示, 每当用户把鼠标悬停在脚本托盘图标上时会显示工具提示. 此工具提示的内容可以使用这样的方法改变: A_IconTip := "My New Text".

相关

ToolTip, SetTimer, Menu 对象, MsgBox, InputBox, FileSelect, DirSelect

示例

在托盘图标附近显示多行气球消息或 toast 通知 20 秒, 而不播放通知声音. 它也有一个标题并包含一个信息图标.

TrayTip "Multiline`nText", "My Title", "Iconi Mute"

提供更精确的控制显示的时间, 没有使用 Sleep(它会停止当前线程).

TrayTip "This will be displayed for 5 seconds.", "Timed traytip"
SetTimer () => TrayTip(), -5000

下面的代码也有同样的功能, 但可以用上面为 Windows 10 定义的 HideTrayTip 函数来替换.

TrayTip "This will be displayed for 5 seconds.", "Timed traytip"
SetTimer HideTrayTip, -5000

HideTrayTip() {
    TrayTip
}

通过定时器定期刷新, 永久显示托盘提示. 注意: 由于上述原因, 这在 Windows 10 及后续版本中可能无法正常工作.

#Persistent
SetTimer RefreshTrayTip, 1000
RefreshTrayTip  ; 调用一次来让它立即开始.

RefreshTrayTip()
{
    TrayTip "This is a more permanent traytip.", "Refreshed traytip", "Mute"
}

每当托盘提示被左键单击, 超时, 关闭, 显示, 排队或消失时, 显示一个消息框. 按 F1 测试这个示例. 有关详情, 请参阅 Shell_NotifyIcon (Microsoft Docs).

OnMessage 0x404, AHK_NOTIFYICON

F1::TrayTip("foo", "bar")

AHK_NOTIFYICON(wParam, lParam, msg, hwnd)
{
    if (hwnd != A_ScriptHwnd)
        return
    if (lParam = 1029) ; NIN_BALLOONUSERCLICK
        MsgBox "Traytip was left-clicked."
    if (lParam = 1028) ; NIN_BALLOONTIMEOUT
        MsgBox "Traytip timed out or was closed or right-clicked."
    if (lParam = 1026) ; NIN_BALLOONSHOW
        MsgBox "Traytip was shown or queued."
    if (lParam = 1027) ; NIN_BALLOONHIDE
        MsgBox "Traytip disappeared, but not due to timeout or user interaction."
}


TreeView (GUI) - 语法 & 使用 | AutoHotkey v2

TreeView

目录

  • 入门和简单示例
  • 选项参数的选项和样式
  • TreeView 的内置方法
  • 事件
  • 备注
  • 示例

入门和简单示例

TreeView 通过缩进父项目下的子项目来显示出层级关系. 最常见的例子是资源管理器的驱动器和文件夹树.

TreeView 通常看起来像这样:

创建 TreeView 的语法为:

TV := GuiObj.Add("TreeView", Options)

或:

TV := GuiObj.AddTreeView(Options)

这是一个创建和显示简单项目层次结构的可运行脚本:

MyGui := Gui()
TV := MyGui.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)

MyGui.Show()  ; 显示窗口和 TreeView.

Options 参数的选项和样式

Background: 指定单词 Background 后面紧跟着颜色名称(请参阅颜色图表) 或 RGB 值(0x 前缀可以省略). 例如: BackgroundSilver, BackgroundFFDD99. 如果此选项不存在, 则 TreeView 初始的背景颜色默认为系统默认的背景颜色. 指定 BackgroundDefault 或 -Background 来应用系统的默认背景颜色(通常为白色). 例如, 使用 TV.Opt("+BackgroundDefault") 可以把 TreeView 恢复为默认的颜色.

Buttons: 指定 -Buttons(负 Buttons) 来避免在每个含有子项目的项目左边显示加号或减号按钮.

C: 文本颜色. 指定字母 C 后面紧跟着颜色名称(请参阅颜色图表) 或 RGB 值(0x 前缀可以省略). 例如: cRed, cFF2211, c0xFF2211, cDefault.

Checked: 在每项的左边提供一个复选框. 当添加项目时, 在其选项中指定单词 Check 来让复选框初始为选中而不是未选中状态. 用户可以点击复选框或按下空格键来选中或取消选中项目. 要找出 TreeView 中当前选中了哪些项目, 请调用 GetNext 方法或 Get 方法.

HScroll: 指定 -HScroll(负 HScroll) 来禁用控件中的水平滚动(而且控件将不显示任何水平滚动条).

ImageList: 这是把图标添加到 TreeView 的方法. 指定单词 ImageList 后紧跟着由之前调用 IL_Create. 返回的 ImageListID. 此选项仅在创建 TreeView 时才有效果(但是, SetImageList 方法没有此限制). 这里是一个可运行示例:

MyGui := Gui()
ImageListID := IL_Create(10)  ; 创建初始容量为 10 个图标的图像列表.
Loop 10  ; 加载一些标准系统图标到图像列表中.
    IL_Add(ImageListID, "shell32.dll", A_Index)
TV := MyGui.Add("TreeView", "ImageList" . ImageListID)
TV.Add("Name of Item", 0, "Icon4")  ; 添加项目到 TreeView 并给它分配文件夹图标.
MyGui.Show()

Lines: 指定 -Lines(负 Lines) 来避免显示连接父项目和它们的子项目之间的网状线. 但是, 移除这些线也阻止了顶级项目坐标加号/减号按钮的显示.

ReadOnly: 指定 -ReadOnly(负 ReadOnly) 来允许编辑每项的文本/名称. 要编辑某项, 请选择它接着按下 F2(请参阅下面的 WantF2 选项). 或者, 您可以对某个项目点击一次来选择它, 至少等半秒, 然后再次点击同一项目进行编辑. 编辑后, 可以对一个项目在其同级项目之间按字母顺序进行重新定位, 请参考下面的例子:

TV := MyGui.Add("TreeView", "-ReadOnly")
TV.OnEvent("ItemEdit", TV_Edit)  ; 每当用户完成一个项目的编辑后, 调用 TV_Edit.
; ...
TV_Edit(TV, Item)
{
    TV.Modify(TV.GetParent(Item), "Sort")  ; 即使该项目没有父项目, 该功能也可以使用.
}

R: 行高(创建时). 指定字母 R 后面紧跟着要在控件中留出空间的行数. 例如, R10 会设置控件为 10 个项目的高度.

WantF2: 指定 -WantF2(负 WantF2) 来禁止使用 F2 来编辑当前选择的项目. 仅当 -ReadOnly 也有效时, 此设置才不会被忽略.

(未命名的数值样式): 由于上述以外的其他样式很少使用, 所以没有为它们命名. 请参阅 TreeView 样式表了解这些样式.

TreeViews 的内置方法

除了GUI 控件的默认方法/属性外, TreeView 还拥有以下方法(在 Gui.TreeView 类中定义).

项目方法:

  • Add: 添加新的项目到 TreeView.
  • Modify: 修改项目的属性和/或名称.
  • Delete: 删除指定项目或所有项目.

检索方法:

  • GetSelection: 返回选择项目的 ID 号.
  • GetCount: 返回控件中项目的总数.
  • GetParent: 返回指定项目的父项目的 ID.
  • GetChild: 返回指定项目的第一个/最上面的子项目的 ID.
  • GetPrev: 返回指定项目上面一个的同级项目的 ID 号.
  • GetNext: 返回指定项目下面一个项目的 ID 号.
  • GetText: 检索指定项目的文本/名称.
  • Get: 如果指定项目含有指定的属性, 则返回项目的 ID.

其他方法:

  • SetImageList: 设置或替换用于显示图标的 ImageList.

Add

添加新的项目到 TreeView.

ItemID := TV.Add(Name, ParentItemID, Options)

参数

Name

类型: 字符串

项目显示的文本, 它可以为文本或数值(包括数值表达式的结果).

ParentItemID

类型: 整数

如果省略, 默认为 0, 这意味着项目将被添加到顶级. 否则, 请指定新项目的父项的 ID.

Options

类型: 字符串

如果为空或省略, 默认为无选项. 否则, 请指定下面的列表中的一个或多个选项(不区分大小写). 选项间使用空格或 tab 分隔. 要移除某个选项, 请在该选项前加上负号. 要添加选项, 选项前允许使用正号, 但不是必须的(可以省略).

Bold: 用粗体显示项目的名称. 以后要取消项目名称的粗体显示, 请使用 TV.Modify(ItemID, "-Bold"). 单词 Bold 后可以可选地紧跟着 0 或 1 以指示起始状态.

Check: 在项目的坐标显示一个复选标记(需要 TreeView 含有复选框). 以后要取消选中, 请使用 TV.Modify(ItemID, "-Check"). 在单词 Check 后可以紧跟着 0 或 1 来表示初始状态. 换句话说, "Check" 和 "Check" . VarContainingOne 是等同的(这里中间使用的是连接运算符).

Expand: 展开此项以让其子项目显示出来(如果有). 以后要折叠项目, 请使用 TV.Modify(ItemID, "-Expand"). 如果没有子项目, 那么 Modify 方法返回 0 而不是它的项目 ID. 与之相比, Add 方法标记项目为展开, 以备以后添加子项目时使用. 与下面的 Select 选项不同, 展开一个项目不会自动展开其父项目. 最后, 在单词 Expand 后可以紧跟着 0 或 1 来表示初始状态. 换句话说, "Expand" 和 "Expand" . VarContainingOne 是等同的.

First | Sort | N: 这些选项仅适用于 Add 方法. 它们指定新项目相对于 其同级项目的位置(同级项目 是同一级别的其他任何项目). 如果这些选项都不存在, 则新项目被添加到同级项目的最后/底部. 否则, 请指定单词 First 来添加项目到同级项目的第一个/顶部, 或指定单词 Sort 来按字母顺序插入新项目到同级项目中间. 如果指定一个纯整数 N, 则假定它为同级项目的 ID 号, 新项目会被插入到它的后面(如果 N 是唯一使用的选项, 则它不需要括在引号中).

Icon: 指定单词 Icon 后紧跟着此项目图标的编号, 项目图标显示在项目名称的左边. 如果此选项不存在, 则使用图像列表中的首个图标. 要显示空白图标, 请指定一个大于图像列表中图标数目的数字. 如果控件没有图像列表, 则既不显示图标也不为图标保留空间.

Select: 选择项目. 因为一次只能选择一个项目, 此时任何原来选择的项目会自动取消选择. 此外, 如果有必要此选项会展开其父项目以显示新选择的项目. 要找出当前选择的项目, 请调用 GetSelection 方法.

Sort: 对于 Modify 方法, 此选项按字母顺序排列指定项目的子项目. 要对所有顶级项目进行排序, 请使用 TV.Modify(0, "Sort"). 如果不含子项目, 则返回 0 而不是所修改项目的 ID.

Vis: 在需要时, 通过滚动 TreeView 和/或展开其父项目来确保此项目完全可见.

VisFirst: 和上面一样, 不过在可行时它还会滚动 TreeView 使得此项显示在顶部. 此选项与 Modify 方法比与 Add 方法一起使用通常更有效.

返回值

类型: 整数

成功时, 方法返回新添加项目的唯一 ID 号. 失败时, 返回 0.

备注

当添加大量项目时, 可以在添加项目之前使用 TV.Opt("-Redraw"), 之后使用 TV.Opt("+Redraw") 来提高性能. 有关详情, 请参阅 Redraw.

Modify

修改项目的属性和/或名称.

ItemID := TV.Modify(ItemID , Options, NewName)

参数

ItemID

类型: 整数

要修改的项目.

Options

类型: 字符串

如果该参数和 NewName 参数都省略, 则选择项目. 否则, 请指定上表中的一个或多个选项.

NewName

类型: 字符串

如果省略, 则保持当前名称不变. 否则, 请指定项目的新名称.

返回值

类型: 整数

方法返回项目自己的 ID.

Delete

删除指定项目或所有项目.

TV.Delete(ItemID)

参数

ItemID

类型: 整数

如果省略, 则删除 TreeView 中的 所有 项目. 否则, 请指定要删除项目的 ID 号.

GetSelection

返回选择项目的 ID 号.

ItemID := TV.GetSelection()

返回值

类型: 整数

此方法返回选择项目的 ID 号.

GetCount

返回控件中项目的总数.

Count := TV.GetCount()

返回值

类型: 整数

此方法返回控件中项目的总数. 此返回值总是即时检索的, 因为控件会一直跟踪此计数.

GetParent

返回指定项目的父项目的 ID.

ParentItemID := TV.GetParent(ItemID)

参数

ItemID

类型: 整数

要检查的项目.

返回值

类型: 整数

此方法返回指定项目的父项目的 ID 号. 如果项目没有父项目, 返回 0, 这适用于所有顶级项目.

GetChild

返回指定项目的第一个/最上面的子项目的 ID.

ChildItemID := TV.GetChild(ItemID)

参数

ItemID

类型: 整数

要检查项目的 ID. 如果为 0, 返回 TreeView 中首个/顶部项目的 ID 号.

返回值

类型: 整数

此方法返回指定项目的第一个/最上面的子项目的 ID 号. 如果没有子项目, 返回 0.

GetPrev

返回指定项目上面一个的同级项目的 ID 号.

PrevItemID := TV.GetPrev(ItemID)
ItemID

类型: 整数

要检查的项目.

返回值

类型: 整数

此方法返回指定项目上一个同级项目的 ID 号. 如果没有同级项目, 返回 0.

GetNext

返回指定项目下面一个项目的 ID 号.

NextItemID := TV.GetNext(ItemID, ItemType)

参数

ItemID

类型: 整数

要检查的项目. 如果该参数为 0 或省略, 则返回 TreeView 中第一个/顶部项目的 ID 号.

ItemType

类型: 字符串

如果省略, 将检索指定项目下面一个同级项目的 ID 号. 否则, 请指定以下字符串之一:

Full 或 F: 检索下一个项目, 不论它是否为指定项目的同级项目. 这使得脚本可以容易地逐项遍历整个树. 请参阅下面的示例.

Check, Checked 或 C: 仅获取下一个带复选标记的项目.

返回值

类型: 整数

此方法返回指定项目下一个项目的 ID 号. 如果没有下一个项目, 返回 0.

备注

下面的例子逐项遍历整个树:

ItemID := 0  ; 这样使得首次循环从树的顶部开始搜索.
Loop
{
    ItemID := TV.GetNext(ItemID, "Full")  ; 把 "Full" 替换为 "Checked" 来找出所有含复选标记的项目.
    if not ItemID  ; 没有更多项目了.
        break
    ItemText := TV.GetText(ItemID)
    MsgBox('The next Item is ' ItemID ', whose text is "' ItemText '".')
}

GetText

检索指定项目的文本/名称.

Text := TV.GetText(ItemID)

参数

ItemID

类型: 整数

要检索文本的项目的 ID 号.

返回值

类型: 字符串

此方法返回检索到的文本. 最多只能检索 8191 个字符.

Get

如果指定项目含有指定的属性, 则返回一个项目的 ID.

ItemID := TV.Get(ItemID, Attribute)

参数

ItemID

类型: 整数

要检查的项目的 ID 号.

Attribute

类型: 字符串

指定以下字符串之一:

E, Expand 或 Expanded: 当前展开的项目(即它的子项目是显示的).

C, Check 或 Checked: 具有复选标记的项目.

B 或 Bold: 当前字体为粗体的项目.

返回值

类型: 整数

如果指定的项目具有指定的属性, 则返回它自己的 ID. 否则, 返回 0.

备注

因为在 IF 语句中把任何非零值视为 "true", if TV.Get(ItemID, "Checked") = ItemID 和 if TV.Get(ItemID, "Checked") 在功能上是相同的.

SetImageList

设置或替换用于显示图标的 ImageList.

PrevImageListID := TV.SetImageList(ImageListID , IconType)

参数

ImageListID

类型: 整数

上次调用 IL_Create 后返回的 ID 数字.

IconType

类型: 整数

如果省略, 则默认为 0. 否则, 为状态图标指定 2(状态图标还没有被直接支持, 但可以通过 SendMessage 使用).

返回值

类型: 整数

成功时, 此方法返回先前与 TreeView 关联的 ImageList ID. 失败时, 返回 0. 任何这样的分离的 ImageList 通常应该通过 IL_Destroy 来销毁.

事件

通过调用 OnEvent 来注册一个回调函数或方法, 可以检测到以下事件:

事件 | 当...触发
Click | 控件被点击.
DoubleClick | 控件被双击.
ContextMenu | 当控件拥有键盘焦点时, 用户右键单击控件或按下 Menu 或 Shift+F10.
Focus | 控件获得键盘焦点.
LoseFocus | 控件失去键盘焦点.
ItemCheck | 一个项目被选中或取消选中.
ItemEdit | 一个项目的标签被用户编辑.
ItemExpand | 一个项目被展开或折叠.
ItemSelect | 一个项目被选中或取消选中.

额外的(很少使用的) 通知可以通过使用 OnNotify 来检测. 这些通知在 Microsoft Docs 上都有文档. Microsoft Docs 没有显示每个通知代码的数值; 这些可以在 Windows SDK 中找到, 或者在互联网上搜索.

备注

当 TreeView 拥有焦点时如果要检测到用户按下的 Enter 键, 请使用默认按钮(如果需要可以隐藏它). 例如:

MyGui.Add("Button", "Hidden Default", "OK").OnEvent("Click", ButtonOK)
...
ButtonOK(*) {
    global
    if MyGui.FocusedCtrl != TV
        return
    MsgBox("Enter was pressed. The selected item ID is " TV.GetSelection())
}

使用键盘除了在项与项之间导航外, 用户还可以通过输入一个项目名称的前几个字符来进行增量搜索. 这使得选择对象跳转到最近匹配的项目.

尽管 TreeView 中的每个项目可以存储任意长度的文本, 但仅显示开始的 260 个字符.

尽管理论上 TreeView 中的项目数可以多达 65536, 然而接近此数目时添加项的性能将显著降低. 通过使用 Add 方法中描述的重绘提示可以稍微减轻这种情况.

与 ListViews, 不同, 当 TreeView 销毁时它的图像列表不会自动被销毁. 因此, 如果 TreeView 中使用的图像列表以后不再用于其他地方, 则在销毁 TreeView 所在的窗口后脚本应调用 IL_Destroy 来销毁此图像列表. 然而, 如果脚本很快将退出, 这样做是没必要的, 因为那时所有的图像列表会自动被销毁.

脚本可以在每个窗口中创建多个 TreeView.

要执行一些操作, 例如调整大小, 隐藏或改变 TreeView 的字体, 请参阅 GuiControl 对象.

Tree View eXtension(TVX) 扩展了 TreeView 的功能, 增加对移动, 插入和删除的支持. 演示的例子请参阅 www.autohotkey.com/board/topic/17497-

相关

ListView, 其他控件类型, Gui(), ContextMenu 事件, Gui 对象, GuiControl 对象, TreeView 样式表

示例

下面是一个比页面顶部的脚本更复杂的可工作的脚本. 它创建并显示一个 TreeView, 其中包含所有用户开始菜单中的所有文件夹. 当用户选择一个文件夹时, 它的内容会显示在右边的 ListView 中(类似于 Windows 资源管理器). 此外, StatusBar 控件会显示当前选择文件夹的信息.

; 下面的文件夹为 TreeView 的根文件夹. 请注意, 如果指定整个驱动器例如 C:\
; 那么可能需要很长加载时间:
TreeRoot := A_MyDocuments
TreeViewWidth := 280
ListViewWidth := A_ScreenWidth/2 - TreeViewWidth - 30

;  创建 Gui 窗口并在标题栏中显示源目录(TreeRoot):
MyGui := Gui("+Resize", TreeRoot)  ; 让用户可以最大化或拖动调整窗口大小.

; 创建图像列表并在其中放入一些标准的系统图标:
ImageListID := IL_Create(5)
Loop 5
    IL_Add(ImageListID, "shell32.dll", A_Index)
; 创建 TreeView 和 ListView, 让它们像在 Windows 资源管理器中那样靠在一起:
TV := MyGui.Add("TreeView", "r20 w" TreeViewWidth " ImageList" ImageListID)
LV := MyGui.Add("ListView", "r20 w" ListViewWidth " x+10", ["Name", "Modified"])

; 创建状态栏/, 显示文件夹数及其总大小的信息:
SB := MyGui.Add("StatusBar")
SB.SetParts(60, 85)  ; 在状态栏中创建三个部分(第三部分占用所有剩余宽度).

; 添加文件夹及其子文件夹到树中. 如果加载需要很长时间, 则显示提示信息:
M := Gui("ToolWindow -SysMenu Disabled AlwaysOnTop", "Loading the tree..."), M.Show("w200 h0")
DirList := AddSubFoldersToTree(TreeRoot, Map())
M.Hide()

; 每当有新的项目被选中时, 调用 TV_ItemSelect:
TV.OnEvent("ItemSelect", TV_ItemSelect)

; 每当窗口被调整大小时, 调用 Gui_Size:
MyGui.OnEvent("Size", Gui_Size)

; 设置 ListView 的列宽(这是可选的):
Col2Width := 70  ; 缩小到只显示 YYYYMMDD 部分.
LV.ModifyCol(1, ListViewWidth - Col2Width - 30)  ; 允许垂直滚动条.
LV.ModifyCol(2, Col2Width)

; 显示窗口并返回. 每当用户执行符合条件的动作时, 操作系统会通知脚本:
MyGui.Show()

AddSubFoldersToTree(Folder, DirList, ParentItemID := 0)
{
    ; 该函数将指定文件夹中的所有子文件夹添加到 TreeView 中,
    ; 并将它们与 ID 相关联的路径保存到一个对象中, 供以后使用.
    ; 它还可以递归地调用自己来收集任意深度的嵌套文件夹.
    Loop Files, Folder "\*.*", "D"  ; 获取所有文件夹的子文件夹.
    {
        ItemID := TV.Add(A_LoopFileName, ParentItemID, "Icon4")
        DirList[ItemID] := A_LoopFilePath
        DirList := AddSubFoldersToTree(A_LoopFilePath, DirList, ItemID)
    }
    return DirList
}

TV_ItemSelect(thisCtrl, Item)  ; 当选择一个新的项目时, 该函数被调用.
{
    ; 将文件放入 ListView 中:
    LV.Delete()  ; 清除所有行.
    LV.Opt("-Redraw")  ; 通过在加载过程中禁止重绘来提高性能.
    TotalSize := 0  ; 在下面循环之前初始化.
    Loop Files, DirList[Item] "\*.*"  ; 为了简化, 这里省略了文件夹, 所以只在 ListView 中显示文件.
    {
        LV.Add(, A_LoopFileName, A_LoopFileTimeModified)
        TotalSize += A_LoopFileSize
    }
    LV.Opt("+Redraw")

    ; 更新状态栏的三个部分, 让它们显示当前选择的文件夹的信息:
    SB.SetText(LV.GetCount() " files", 1)
    SB.SetText(Round(TotalSize / 1024, 1) " KB", 2)
    SB.SetText(DirList[Item], 3)
}

Gui_Size(thisGui, MinMax, Width, Height)  ; 当用户改变窗口大小时扩展/收缩 ListView 和 TreeView.
{
    if MinMax = -1  ; 窗口被最小化了. 无需进行操作.
        return
    ; 否则, 窗口的大小被调整过或被最大化了. 调整控件大小以适应.
    TV.GetPos(,, &TV_W)
    TV.Move(,,, Height - 30)  ; -30 用于状态栏和边距.
    TV.Move(,, Width - TV_W - 30, Height - 30)
}


Trim / LTrim / RTrim - 语法 & 使用 | AutoHotkey v2

Trim / LTrim / RTrim

移除字符串开头和/或末尾的某些字符.

NewString :=  Trim(String , OmitChars)
NewString := LTrim(String , OmitChars)
NewString := RTrim(String , OmitChars)

参数

String

类型: 字符串

任何字符串值或变量. 不支持数字.

OmitChars

类型: 字符串

如果省略, 将移除空格和 tab. 否则, 请指定一个字符列表(区分大小写), 在 String 的开头和/或末尾处移除这些字符.

返回值

类型: 字符串

这些函数返回指定字符串修剪后的版本.

示例

移除字符串左右两边的所有空格.

text := "  text  "
MsgBox
(
    "No trim:`t'" text "'
    Trim:`t'" Trim(text) "'
    LTrim:`t'" LTrim(text) "'
    RTrim:`t'" RTrim(text) "'"
)

移除字符串左边的所有的零.

MsgBox LTrim("00000123", "0")


Try - 语法 & 使用 | AutoHotkey v2

Try

守护一个或多个语句不受由 Throw 语句抛出的运行时错误和值的影响.

Try Statement
Try
{
    Statements
}

备注

Try 语句后常跟着区块, 括在大括号中的一个或多个语句. 如果仅需执行单个语句, 那么此语句可以和 Try 放在同一行, 也可以在下一行, 并且可以省略大括号. 要指定仅在 Try 捕获错误时执行的代码, 请使用一个或多个 Catch 语句.

如果使用 Try 而没有 Catch 或 Finally, 那就相当于一个空的 catch Error.

Throw 语句或程序在运行遇到错误时会抛出值. 当 Try 区块或由其调用的函数抛出值时, 将进行下列操作:

  • 如果该区块有相应的 Catch 语句, 则继续执行该语句.
  • 如果没有匹配的 Catch 语句但有 Finally 语句, 则执行该语句并在结束后自动再次抛出值.
  • 如果没有匹配的 Catch 语句或 Finally 语句, 值会被自动再次抛出(除非根本没有 Catch 或 Finally, 如上所述).

最后一个 Catch 后面可以选择加上 Else. 如果 Try 语句完成后没有抛出异常(并且没有通过 Return, Break 或类似的方式将控制权转移到其他地方), 则会执行 Else 语句. 由 Else 语句抛出的异常不会被其相关的 Try 语句处理, 但可以被一个包围的 Try 语句处理. Finally 也可以出现, 但是必须放在 Else 之后, 而且总是最后执行.

如果在没有 try 区块执行的情况下引发异常, 则会显示错误消息, 并且当前线程退出.

可以选择将 One True Brace(OTB) 样式与 try 语句一起使用. 例如:

try {
    ...
} catch Error as err {
    ...
} else {
    ...
} finally {
    ...
}

相关

Throw, Catch, Else, Finally, 区块, OnError

示例

演示 Try/Catch/Throw 的基本概念.

try  ; 尝试执行的代码.
{
    HelloWorld
    MakeToast
}
catch as e  ; 处理由上面区块抛出的首个错误.
{
    MsgBox "An error was thrown!`nSpecifically: " e.Message
    Exit
}

HelloWorld()  ; 总是成功.
{
    MsgBox "Hello, world!"
}

MakeToast()  ; 总是失败.
{
    ; 立即跳到 try 区块的错误处理程序:
    throw Error(A_ThisFunc " is not implemented, sorry")
}

演示内置函数的基本错误处理.

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 "There was a problem while backing the files up!",, "IconX"
    ExitApp 1
}
else
{
    MsgBox "Backup successful."
    ExitApp 0
}

演示使用 Try-Catch 处理 COM 错误. 有关下面使用的 COM 对象的详情, 请参阅 Using the ScriptControl (Microsoft Docs).

try
{
    obj := ComObject("ScriptControl")
    obj.ExecuteStatement('MsgBox "This is embedded VBScript"')  ; 这一行会产生一个 Error.
    obj.InvalidMethod() ; 这一行会产生一个 MethodError.
}
catch MemberError  ; 包括 MethodError 和 PropertyError.
{
    MsgBox "We tried to invoke a member that doesn't exist."
}
catch as e
{
    ; 关于 e 对象的更多细节, 请参阅 Error 对象.
    MsgBox("Exception thrown!`n`nwhat: " e.what "`nfile: " e.file
        . "`nline: " e.line "`nmessage: " e.message "`nextra: " e.extra,, 16)
}

演示嵌套的 Try-Catch 语句.

try Example1 ; 单个语句可以和 Try 放在同一行.
catch Number as e
    MsgBox "Example1() threw " e

Example1()
{
    try Example2
    catch Number as e
    {
        if (e = 1)
            throw ; 将捕获的值重新抛给调用者.
        else
            MsgBox "Example2() threw " e
    }
}

Example2()
{
    throw Random(1, 2)
}


Type - 语法 & 使用 | AutoHotkey v2

Type

返回值的类名.

ClassName := Type(Value)

返回值

类型: 字符串

函数返回 Value 的类名.

确定一个值的类名的算法可以近似地显示如下:

TypeOf(Value)
{
    if (comClass := ComObjType(Value, "Class")) != ""
        return comClass
    try ; `Value is Object` 没有被检查, 因为对于原型可能为假.
        if ObjHasOwnProp(Value, "__Class")
            return "Prototype"
    while Value := ObjGetBase(Value)
        if ObjHasOwnProp(Value, "__Class")
            return Value.__Class
    return "Object"
}

对于 COM 包装器对象, 类名也可以根据变体类型来确定, 如下所示:

ComObject_Type(obj)
{
    if ComObjType(obj) & 0x2000 ; VT_ARRAY
        return "ComObjArray" ; ComObjArray.Prototype.__Class
    if ComObjType(obj) & 0x4000 ; VT_BYREF
        return "ComValueRef" ; ComValueRef.Prototype.__Class
    if (ComObjType(obj) = 9 || ComObjType(obj) = 13) ; VT_DISPATCH || VT_UNKNOWN
        && ComObjValue(obj) != 0
    {
        if (comClass := ComObjType(obj, "Class")) != ""
            return comClass
        if ComObjType(obj) = 9 ; VT_DISPATCH
            return "ComObject" ; ComObject.Prototype.__Class
    }
    return "ComValue" ; ComValue.Prototype.__Class
}

备注

通常不应该使用此函数来确定一个值是否是数值, 因为数值 字符串 在数学表达式和大多数内置函数中都是有效的. 但是, 在某些情况下, 值的确切类型更为重要. 在这种情况下, 可以考虑用 Value is Number 或类似的方式代替 Type.

要检查一个值是否可以用作数字, 请使用 IsNumber, IsInteger 或 IsFloat 函数.

要检查任何类型的对象(即, 任何不是原始值的东西), 请使用 IsObject 函数.

为了检查一个值是否是一个特定类的实例, 请使用 is 运算符. 这甚至可以用于原始值或识别 COM 封装对象.

相关

值, 表达式, Is 函数, Integer, Float, String

示例

检索并报告存储在 a, b 和 c 中的值的确切类型.

a := 1, b := 2.0, c := "3"
MsgBox Type(a)  ; 整数
MsgBox Type(b)  ; 浮点数
MsgBox Type(c)  ; 字符串


Until - 语法 & 使用 | AutoHotkey v2

Until

根据条件判断是否继续执行 Loop 或 For 循环.

Loop {
    ...
} Until Expression

参数

Expression

任何有效的表达式.

备注

如果表达式被括在括号中, Until 后的空格和制表是可选的, 如 until(expression) 所示.

表达式在每次迭代后求值一次, 即使使用了 Continue 也会进行计算. 如果表达式计算结果为 false(即为空字符串或数值 0), 循环继续; 否则循环被打破且跳到 Until 后面一行继续执行.

Loop Until 是下列结构的简写形式:

Loop {
    ...
    if (Expression)
        break
}

不过, Loop Until 通常更容易理解, 且与上面不同的是, 可以与单行动作一起使用. 例如:

Loop
    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-loop, For-loop, Break, Continue, 区块, Files-and-folders loop, Registry loop, File-reading loop, Parsing loop, If (表达式)


VarSetStrCapacity - 语法 & 使用 | AutoHotkey v2

VarSetStrCapacity

增加变量的容量或释放其内存. 一般情况下不需要, 但可以与 DllCall 或 SendMessage 一起使用, 或者优化重复连接.

GrantedCapacity := VarSetStrCapacity(&TargetVar , RequestedCapacity)

参数

&TargetVar

类型: VarRef

变量的引用. 例如: VarSetStrCapacity(&MyVar, 1000). 这也可以是动态变量, 例如 Array%i% 或是函数的 ByRef 参数.

RequestedCapacity

类型: 整数

如果省略, 则函数将返回变量当前的容量且不会改变其的内容. 否则, 变量中的所有内容将会丢弃(变量被置空).

指定 RequestedCapacity 为调整后变量所能容纳的字节数. RequestedCapacity 不包括内部零终止符. 例如, 指定 1 将允许变量在其内部结束符之外最多容纳一个字符. 注意: 如果脚本稍后给它分配一个更大的值, 变量将自动展开.

因此可以经常简单地调用此函数来确保变量占用最小的空间, 出于性能的考虑, 它只在 RequestedCapacity 为 0 的时候才会缩小变量. 换句话说, 如果变量的容量已经大于 RequestedCapacity, 它就不会被缩小(但为了保持一致性, 变量会被置空).

因此, 要显式地缩小变量, 首先请使用 VarSetStrCapacity(&Var, 0) 释放它占用的内存, 然后使用 VarSetStrCapacity(&Var, NewCapacity) -- 或者简单地让它自动按需从零扩展.

出于性能考虑, 要释放一个原来容量小于 64 字符的变量可能会没有效果, 因为它的内存是永久类型的. 在这种情况下, 会返回当前容量, 而不是 0.

出于性能考虑, 容量小于 4096 字节的变量的内存不能通过赋值空字符串的方法来释放(例如 Var := ""). 然而, VarSetStrCapacity(&Var, 0) 可释放它.

为 RequestedCapacity 指定 -1, 将变量内部存储的字符串长度更新为其当前内容的长度. 这在字符串被间接改变的情况下很有用, 比如通过 DllCall 或 SendMessage 传递其地址. 在这种模式下, VarSetStrCapacity 返回的是长度而不是容量.

返回值

类型: 整数

该函数返回 TargetVar 现在可以容纳的字符数, 该字符数将大于或等于 RequestedCapacity.

失败

在以下任何一种情况下都会抛出异常:

  • VarName 不是一个有效的变量引用. 不可能通过引用传递一个对象属性或内置变量, 因此不能将其传递给该函数.
  • 请求的容量太大, 无法容纳在脚本可用的任何一个连续的内存块中. 在极少数情况下, 这可能是由于系统内存耗尽所致.
  • RequestedCapacity 小于 -1 或大于当前平台的理论支持的容量.

备注

Buffer 对象在处理二进制数据, 结构体, DllCall 和类似的东西时, 提供了卓越的清晰度和灵活性. 例如, Buffer 对象可以分配给一个属性或数组元素, 或者传递给一个函数或从一个函数返回, 而不需要复制其内容.

在通过渐进式连接的方式构建一个字符串时, 可以使用这个函数来提高性能. 这是因为当你对字符串的最终长度有一定了解时, 可以避免多次自动调整大小. 在这种情况下, RequestedCapacity 不需要太准确: 如果容量太小, 性能仍然会得到提高, 当容量用完后, 变量将开始自动扩展. 如果容量过大, 则会浪费部分内存, 但只是暂时的, 因为所有的内存都可以在操作后通过 VarSetStrCapacity(&Var, 0) 或 Var := "" 来释放.

相关

Buffer 对象, DllCall, NumPut, NumGet

示例

通过确保 MyVar 有足够的工作空间来优化.

VarSetStrCapacity(&MyVar, 5120000)  ; ~10 MB
Loop
{
    ; ...
    MyVar .= StringToConcatenate
    ; ...
}

使用一个变量通过 DllCall 从外部函数接收一个字符串. (注意, 使用 Buffer 对象可能是首选; 尤其是在处理非 Unicode 字符串时.)

max_chars := 10

Loop 2
{
    ; 分配用于 DllCall 的空间.
    VarSetStrCapacity(&buf, max_chars)

    if (A_Index = 1)
        ; 通过 DllCall 间接修改变量.
        DllCall("wsprintf", "Ptr", StrPtr(buf), "Str", "0x%08x", "UInt", 4919, "CDecl")
    else
        ; 使用 "str" 来自动更新长度:
        DllCall("wsprintf", "Str", buf, "Str", "0x%08x", "UInt", 4919, "CDecl")

    ; 连接字符串以演示为什么需要更新长度:
    wrong_str := buf . "<end>"
    wrong_len := StrLen(buf)

    ; 更新变量的长度.
    VarSetStrCapacity(&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
    )
}


VerCompare - 语法 & 使用 | AutoHotkey v2

VerCompare

对比两个版本字符串.

Result := VerCompare(VersionA, VersionB)

参数

VersionA

类型: 字符串

要比较的第一个版本字符串.

VersionB

类型: 字符串

要比较的第二个版本字符串, 可选地使用以下操作符之一作为前缀: <, <=, >, >= 或 =.

返回值

类型: 整数(布尔值)或整数

如果 VersionB 以操作符符号开头, 则此函数返回 1(true) 或 0(false).

否则, 该函数返回以下值之一, 以指示 VersionA 和 VersionB 之间的关系:

  • 如果 VersionA 等于 VersionB, 则返回 0
  • 如果 VersionA 大于 VersionB, 则返回正整数
  • 如果 VersionA 小于 VersionB, 则返回负整数

要检查两个字符串之间的特定关系, 请将结果与 0 比较. 例如:

a_less_than_b := VerCompare(a, b) < 0
a_greater_than_or_equal_to_b := VerCompare(a, b) >= 0

备注

版本字符串是按照与 #Requires 相同的规则进行比较的.

这个函数应该能够正确地比较 Semantic Versioning 2.0.0 版本字符串, 但是不要求参数是有效的 SemVer 字符串.

该函数可用于排序回调.

已知限制: 任何大于 2147483647(231-1) 的数字分量都被认为等于 2147483647.

相关

Sort, StrCompare

示例

检查正在使用的 AutoHotkey 的版本.

if VerCompare(A_AhkVersion, "2.0") < 0
    MsgBox "This version < 2.0; possibly a pre-release version."
else
    MsgBox "This version is 2.0 or later."

显示 VerCompare 和 StrCompare 之间的区别.

MsgBox VerCompare("1.20.0", "1.3")  ; 返回 1
MsgBox StrCompare("1.20.0", "1.3")  ; 返回 -1

示范预发布版本的比较.

MsgBox VerCompare("2.0-a137", "2.0-a136")  ; 返回 1
MsgBox VerCompare("2.0-a137", "2.0")  ; 返回 -1
MsgBox VerCompare("10.2-beta.3", "10.2.0")  ; 返回 -1

演示范围检查.

MsgBox VerCompare("2.0.1", ">=2.0") && VerCompare("2.0.1", "<2.1")  ; 返回 1


While Loop - 语法 & 使用 | AutoHotkey v2

While-loop

重复执行一条或多条语句, 直到指定的表达式计算结果为假时终止.

While Expression

参数

Expression

任何有效的表达式. 例如: while x < y.

备注

如果表达式括在括号中, While 后的空格或制表符是可选的, 例如 While(expression).

在每次重复执行前都会计算一次表达式. 如果表达式计算结果为 true(即除空字符串和数值 0 以外的任何结果), 那么执行循环体; 否则跳到循环体之后一行执行.

while 循环后通常跟着区块, 这是形成循环 主体 的语句的集合. 但是, 只有一个语句的循环不需要区块(为此, "if" 及其 "else" 计为单个语句).

One True Brace(OTB) 样式可选使用, 这使得开括号可以出现在同一行, 而不是下面一行. 例如: while x < y {.

内置变量 A_Index 包含当前循环迭代的次数. 第一次执行循环的表达式和循环体时, 它包含 1. 第二次, 它包含 2; 等等. 如果内部循环被外部循环包围, 则内部循环优先. A_Index 在所有类型的循环内工作, 但在循环外为 0.

与所有循环一样, Break 可用于提前退出循环. 此外, Continue 可用于跳过当前迭代的其余部分, 在此期间 A_Index 增加 1, 而 while 循环的表达式将被重新计算. 如果仍然为 true, 则开始新的迭代; 否则, 循环结束.

循环后面可以有一个可选的 Else 语句, 如果循环的迭代次数为零, 则执行 Else 语句.

专用循环: 循环可以用来自动检索文件, 文件夹或注册表项(每次一个). 有关详情, 请参阅 file-loop 和 registry-loop. 此外, file-reading loops 可以对整个文件的内容进行操作, 每次一行. 最后, parsing loops 可以对可分隔的字符串中包含的各个字段进行操作.

相关

Until, Break, Continue, 区块, Loop, For-loop, Files-and-folders loop, Registry loop, File-reading loop, Parsing loop, 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
}


窗口函数列表 | AutoHotkey v2

窗口函数

用于检索关于一个或多个窗口的信息, 或对窗口执行各种操作的函数. 有关详情, 请点击函数名称.

函数 | 描述
WinActivate | 激活指定的窗口.
WinActivateBottom | 和 WinActivate 一样, 只是它激活了最下面的匹配窗口而不是最上面的.
WinActive | 检查指定的窗口是否存在并且当前处于活动状态(最前的).
WinClose | 关闭指定的窗口.
WinExist | 检查指定的窗口是否存在.
WinGetClass | 检索指定窗口的类名.
WinGetClientPos | 检索指定窗口的客户端区域的位置和大小.
WinGetControls | 返回指定窗口中所有控件名称(ClassNN) 的数组.
WinGetControlsHwnd | 返回指定窗口中所有控件的唯一 ID 号(HWND) 的数组.
WinGetCount | 返回符合指定条件的现有窗口的数目.
WinGetID | 返回指定窗口的唯一 ID 号(HWND).
WinGetIDLast | 如果找到多个匹配窗口, 则返回最后的/最底部的窗口的唯一 ID 号(HWND).
WinGetList | 返回与指定条件匹配的所有现有窗口的唯一 ID 号(HWND) 的数组.
WinGetMinMax | 如果指定的窗口被最大化或最小化, 则返回一个非零数字.
WinGetPID | 返回指定窗口的进程 ID(PID).
WinGetPos | 获取指定窗口的位置和大小.
WinGetProcessName | 返回指定窗口的进程的名称.
WinGetProcessPath | 返回拥有指定窗口的进程的完整路径和名称.
WinGetStyle WinGetExStyle | 分别返回指定窗口的样式或扩展样式.
WinGetText | 检索指定窗口的文本.
WinGetTitle | 检索指定窗口的标题.
WinGetTransColor | 返回指定窗口中标记为透明的颜色.
WinGetTransparent | 返回指定窗口的透明度的等级.
WinHide | 隐藏指定的窗口.
WinKill | 强制关闭指定的窗口.
WinMaximize | 将指定的窗口放大到最大尺寸.
WinMinimize | 将指定的窗口最小化为任务栏上的按钮.
WinMinimizeAll WinMinimizeAllUndo | 最小化或还原所有窗口.
WinMove | 改变指定窗口的位置和/或大小.
WinMoveBottom | 发送指定的窗口到堆栈的底部; 也就是说, 在所有其他窗口下方.
WinMoveTop | 将指定的窗口移到堆栈顶部, 而无需显式激活它.
WinRedraw | 重绘指定窗口.
WinRestore | 如果指定的窗口处于最小化或最大化状态, 则还原它.
WinSetAlwaysOnTop | 使指定的窗口停留在所有其他窗口的顶部(除了其他置顶的窗口).
WinSetEnabled | 启用或禁用指定的窗口.
WinSetRegion | 将指定窗口的形状改为指定的矩形, 椭圆或多边形.
WinSetStyle WinSetExStyle | 分别改变指定窗口的样式和扩展样式.
WinSetTitle | 更改指定窗口的标题.
WinSetTransColor | 使所选颜色的所有像素在指定的窗口内不可见(透明).
WinSetTransparent | 使指定的窗口半透明.
WinShow | 显示指定的窗口.
WinWait | 等待直到指定的窗口存在.
WinWaitActive WinWaitNotActive | 等待直到指定的窗口处于活动或不活动状态.
WinWaitClose | 等待直到找不到匹配的窗口.

备注

要发现鼠标当前悬停的窗口的唯一 ID 号, 请使用 MouseGetPos.

相关

SetWinDelay, 控件函数, Gui 对象(脚本创建的窗口)


WinActivate - 语法 & 使用 | AutoHotkey v2

WinActivate

激活指定的窗口.

WinActivate WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

当非活动窗口变为活动状态时, 操作系统也会使其处于最前面(将其带到堆栈的顶部). 如果窗口已经处于活动状态, 则不会发生这种情况.

如果窗口处于最小化和非活动状态, 那么会对其还原后再进行激活. 如果 WinTitle 是字母 "A", 并且省略了其他参数, 则活动窗口将会还原. 窗口即使已经是活动窗口, 也会被还原.

在 60 ms 的时间中, 会对目标窗口进行六次激活的尝试. 如果六次尝试都失败了, WinActivate 会自动发送 {Alt 2} 作为操作系统可能实施的限制的变通方法, 然后进行第七次尝试. 因此, 通常不需要在此函数后使用 WinWaitActive 或 if not WinActive(...).

WinActivate 第一次尝试失败后, 会自动发送 {Alt up}. 测试表明, 这可能会提高所有后续尝试的可靠性, 减少第一次尝试失败并导致任务栏按钮闪烁的情况. 在每个脚本的生命周期中, 为此目的发送的 {Alt up} 不超过一个. 如果这个或任何其他(AutoHotkey v1.1.27+) 脚本安装了键盘钩子, {Alt up} 就会被阻挡在活动窗口之外, 从而将已经很小的副作用风险降到最低.

通常, 如果有多个窗口匹配, 则会激活最上面的匹配窗口(通常是最近使用的窗口). 如果窗口已经激活, 则它将保持激活状态, 而不是激活它下面的任何其他匹配窗口. 但是, 如果使用 WinMoveBottom, 将活动窗口移动到堆栈底部, 则可能会激活其他窗口, 即使活动窗口是匹配的.

WinActivateBottom 激活最底层的匹配窗口(通常是最近最早使用的那个).

GroupActivate 激活与窗口组指定的条件匹配的下一个窗口.

如果要激活的窗口处于隐藏状态并且 DetectHiddenWindows 被设置为 OFF 时, 该窗口将永远不会视为一个匹配项. 相反, 只要有一个匹配窗口是可见的, 它就会被激活.

在激活另一个窗口后立即激活一个窗口时, 任务栏按钮可能在某些系统上可能会闪烁(取决于操作系统和设置). 为防止这种情况, 请使用 #WinActivateForce.

已知问题: 如果脚本运行在正在被远程桌面访问的计算机或服务器上, 当远程桌面客户端最小化时, WinActivate 可能会挂起. 一种解决办法是使用不需要激活窗口的内置函数, 如 ControlSend 和 ControlClick. 另一个可能的解决方法是在本地/客户端计算机的注册表上做如下设置:

; 将 HKCU 改成 HKLM, 以对该系统上的所有用户生效.
RegWrite "REG_DWORD", "HKCU\Software\Microsoft\Terminal Server Client"
    , "RemoteDesktop_SuppressWhenMinimized", 2

相关

WinActivateBottom, #WinActivateForce, SetTitleMatchMode, DetectHiddenWindows, 上次找到的窗口, WinExist, WinActive, WinWaitActive, WinWait, WinWaitClose, WinClose, GroupActivate, 窗口函数

示例

如果记事本确实存在, 激活它, 否则激活计算器.

if WinExist("Untitled - Notepad")
    WinActivate ; 使用由 WinExist 找到的窗口
else
    WinActivate "Calculator"


WinActivateBottom - 语法 & 使用 | AutoHotkey v2

WinActivateBottom

与 WinActivate 相同, 只是此函数激活最下面的匹配窗口而不是最上面的.

WinActivateBottom WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

至少需要其中的一个. 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

最底层窗口通常是最近使用的最早的窗口, 除非窗口已经被重新排序, 例如使用了 WinMoveBottom.

如果只有一个匹配窗口, 那么 WinActivateBottom 的行为与 WinActivate 相同.

窗口组比此函数更高级, 所以请考虑使用它们以获得更多的功能和灵活性.

如果窗口处于最小化和非活动状态, 那么会对其还原后再进行激活. 如果 WinTitle 是字母 "A", 并且省略了其他参数, 则活动窗口将会还原. 窗口即使已经是活动窗口, 也会被还原.

在 60 ms 的时间中, 会对目标窗口进行六次激活的尝试. 因此, 通常不需要在此函数后使用 WinWaitActive 函数.

与 WinActivate不同, 此函数中不能使用上次找到的窗口, 因为它可能不是底层窗口. 因此, 至少需要有一个参数不为空.

在激活另一个窗口后立即激活一个窗口时, 任务栏按钮可能在某些系统上可能会闪烁(取决于操作系统和设置). 为防止这种情况, 请使用 #WinActivateForce.

相关

WinActivate, #WinActivateForce, SetTitleMatchMode, DetectHiddenWindows, WinExist, WinActive, WinWaitActive, WinWait, WinWaitClose, GroupActivate

示例

按下热键可以按从最早到最新的顺序访问所有打开的浏览器窗口.

#i:: ; Win+I
{
    SetTitleMatchMode 2
    WinActivateBottom "- Microsoft Internet Explorer"
}


WinActive - 语法 & 使用 | AutoHotkey v2

WinActive

检查指定的窗口是否激活且返回其唯一 ID(HWND).

UniqueID := WinActive(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

函数返回匹配指定的条件的活动窗口的唯一 ID(HWND), 如果不匹配, 则函数返回 0.

因为所有非零数字被视为 "true", 当 WinTitle 为活动窗口时, 语句 if WinActive(WinTitle) 为 true .

备注

如果省略所有参数, 那么将使用上次找到的窗口.

如果符合条件的窗口存在, 那么上次找到的窗口将更新为此窗口.

获取活动窗口的唯一 ID 的简便方法是使用 ActiveHwnd := WinExist("A").

SetWinDelay 不适用于此函数.

相关

WinExist, SetTitleMatchMode, DetectHiddenWindows, Last Found Window, WinActivate, WinWaitActive, WinWait, WinWaitClose, #HotIf

示例

关闭记事本或另一个窗口, 这取决于 WinActive 函数找到的是哪个窗口. 注意, "ahk_" 关键字和它的标准值之间的空格可以省略; 这在使用变量时特别有用, 如第二个 WinActive 所示.

if WinActive("ahk_class Notepad") or WinActive("ahk_class" ClassName)
    WinClose ; 使用由 WinActive 找到的窗口.


WinClose - 语法 & 使用 | AutoHotkey v2

WinClose

关闭指定的窗口.

WinClose WinTitle, WinText, SecondsToWait, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

SecondsToWait

类型: 整数或浮点数

如果省略, 此函数不会等待. 否则, 请指定秒数(可以为小数) 来等待窗口关闭. 如果窗口在此期间没有关闭, 那么脚本会继续执行.

错误处理

如果找不到窗口, 则抛出 TargetError, 除非使用了 group 模式.

如果找到了一个窗口但无法关闭, 则不会抛出异常, 因此, 如果你需要确定窗口已经关闭, 请使用 WinExist 或 WinWaitClose.

备注

此函数发送关闭消息到窗口. 结果取决于窗口(它可能会询问是否保存数据等).

如果匹配窗口是活动的, 那么会优先关闭此窗口而不是其他匹配窗口. 一般而言, 如果有多个匹配窗口, 那么会关闭最上面的(最近使用的) 窗口.

此函数仅对单独一个窗口起作用, 除非 WinTitle 是 ahk_group GroupName(没有其他指定条件), 在这种情况下, 组中的所有窗口均会受到影响.

当函数处于等待状态时, 可以通过热键, 自定义菜单项或计时器来启动新的线程.

WinClose 发送 WM_CLOSE 消息到目标窗口, 这种关闭方法有些强制性. 关闭窗口的另一种方法是发送下面的消息. 它可能会产生与此命令不同的行为, 因为它类似于按下 Alt+F4 或点击窗口标题栏的关闭按钮的效果:

PostMessage 0x112, 0xF060,,, WinTitle, WinText  ; 0x112 = WM_SYSCOMMAND, 0xF060 = SC_CLOSE

如果使用 WinClose 无法关闭窗口, 那么您可以使用 WinKill 来强制关闭.

相关

WinKill, WinWaitClose, ProcessClose, WinActivate, SetTitleMatchMode, DetectHiddenWindows, Last Found Window, WinExist, WinActive, WinWaitActive, WinWait, GroupActivate

示例

如果记事本确实存在, 关闭它, 否则关闭计算器.

if WinExist("Untitled - Notepad")
    WinClose ; 使用由 WinExist 找到的窗口
else
    WinClose "Calculator"


WinExist - 语法 & 使用 | AutoHotkey v2

WinExist

检查指定的窗口是否存在并返回第一个匹配的窗口的唯一 ID(HWND).

UniqueID := WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改. 当使用纯 HWND 时, 始终检测 隐藏窗口而不管 DetectHiddenWindows 的设置如何. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

函数返回首个匹配窗口的唯一 ID(HWND)(没有找到匹配时则为 0).

因为所有非零数字被视为 "true", 当 WinTitle 存在时, 语句 if WinExist(WinTitle) 为 true.

备注

如果符合条件的窗口存在, 那么上次找到的窗口将更新为此窗口.

要发现控件的 HWND(用于 PostMessage, SendMessage 或 DllCall), 请使用 ControlGetHwnd 或 MouseGetPos.

SetWinDelay 不适用于此函数.

相关

WinActive, SetTitleMatchMode, DetectHiddenWindows, Last Found Window, ProcessExist, WinActivate, WinWaitActive, WinWait, WinWaitClose, #HotIf

示例

激活记事本或另一个窗口, 这取决于 WinExist 函数找到的是哪个窗口. 注意, "ahk_" 关键字和它的标准值之间的空格可以省略; 这在使用变量时特别有用, 如第二个 WinExist 所示.

if WinExist("ahk_class Notepad") or WinExist("ahk_class" ClassName)
    WinActivate ; 使用由 WinExist 找到的窗口.

获取和报告活动窗口的唯一 ID(HWND).

MsgBox "The active window's ID is " WinExist("A")

如果计算器不存在则返回.

if not WinExist("Calculator")
    return


WinGetClass - 语法 & 使用 | AutoHotkey v2

WinGetClass

获取指定窗口的类名.

ClassName := WinGetClass(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

函数返回指定窗口的类名.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果类名不能被检索, 则抛出 OSError.

备注

仅获取类名(返回值中不包含前缀 "ahk_class").

有关窗口类的一般解释和使用它们的一种方法, 请参阅 ahk_class.

窗口标题和文本是区分大小写的. 只有在打开 DetectHiddenWindows 设置时, 才会检测隐藏窗口.

相关

WinGetTitle, 窗口函数

示例

检索并报告活动窗口的类名.

MsgBox "The active window's class is " WinGetClass("A")


WinGetClientPos - 语法 & 使用 | AutoHotkey v2

WinGetClientPos

检索指定窗口的工作区的位置和大小.

WinGetClientPos &OutX, &OutY, &OutWidth, &OutHeight, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

&OutX, &OutY

类型: VarRef

如果省略, 将不会存储相应的值. 否则, 请指定用于存储工作区左上角的 X 和 Y 坐标的输出变量的引用.

&OutWidth, &OutHeight

类型: VarRef

如果省略, 将不会存储相应的值. 否则, 请指定用于存储工作区宽度和高度的输出变量的引用.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

工作区是窗口的一部分, 可以包含控件. 它不包括窗口的标题栏, 菜单栏(如果有标准菜单) 和边框. 与 WinGetPos 返回的值相比, 工作区的位置和大小较少地依赖于操作系统版本和主题.

如果 WinTitle 为 "Program Manager", 该函数将检索桌面的大小, 通常与当前屏幕分辨率相同.

最小化的窗口仍然有位置和大小. 在这种情况下, 返回的值可能因操作系统和配置而异, 但是 X 和 Y 坐标通常为 -32000, 而宽度和高度为 0.

要发现鼠标当前悬停在其上的窗口和控件的名称, 请使用 MouseGetPos.

在具有不同 DPI 设置的多个屏幕的系统上, 由于操作系统 DPI 缩放, 返回的位置和大小可能与预期不同.

相关

WinGetPos, WinMove, ControlGetPos, WinGetTitle, WinGetText, ControlGetText

示例

获取和报告计算器工作区域的位置和大小.

WinGetClientPos &X, &Y, &W, &H, "Calculator"
MsgBox "Calculator's client area is at " X "," Y " and its size is " W "x" H

获取并报告活动窗口工作区域的位置.

WinGetClientPos &X, &Y,,, "A"
MsgBox "The active window's client area is at " X "," Y

如果记事本存在, 检索并报告其工作区域的位置.

if WinExist("Untitled - Notepad")
{
    WinGetClientPos &Xpos, &Ypos ; 使用由 WinExist 找到的窗口.
    MsgBox "Notepad's client area is at " Xpos "," Ypos
}


WinGetControls - 语法 & 使用 | AutoHotkey v2

WinGetControls

返回指定窗口中所有控件的an array of names (ClassNNs).

ClassNNs := WinGetControls(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: Array

此函数返回指定窗口中所有控件的名称的数组. 每个名称由控件的类名紧接着其序号(ClassNN) 组成, 如 Window Spy 所示.

例如, 如果将返回值赋值给名为 ClassNNs 的变量, 并且存在两个控件, 则 ClassNNs[1] 包含第一个控件的名称, ClassNNs[2] 包含第二个控件的名称, 而 ClassNNs.Length 返回该数字 2.

控件是按照 Z 轴顺序排序的, 如果窗口支持 Tab 键, Z 轴顺序通常与通过 Tab 导航的顺序相同.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

鼠标光标下的窗口或控件的 ID 可以使用 MouseGetPos 来获取.

相关

WinGetControlsHwnd, 窗口函数, 控件函数

示例

从活动窗口的控件列表中提取每个控件的名称.

for n, ctrl in WinGetControls("A")
{
    Result := MsgBox("Control #" n " is '" ctrl "'. Continue?",, 4)
    if (Result = "No")
        break
}

实时显示活动窗口的控件列表.

SetTimer WatchActiveWindow, 200

WatchActiveWindow()
{
    try
    {
        Controls := WinGetControls("A")
        ControlList := ""
        for ClassNN in Controls
            ControlList .= ClassNN . "`n"
        if (ControlList = "")
            ToolTip "The active window has no controls."
        else
            ToolTip ControlList
    }
    catch TargetError
        ToolTip "No visible window is active."
}


WinGetControlsHwnd - 语法 & 使用 | AutoHotkey v2

WinGetControlsHwnd

返回指定窗口中所有控件的唯一 ID 号(HWND) 的数组.

HWNDs := WinGetControlsHwnd(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: Array

函数返回一个指定窗口中所有控件的唯一 ID 号的数组. 其中每个编号是窗口句柄(HWND).

例如, 如果将返回值赋值给名为 HWNDs 的变量, 并且存在两个控件, 则 HWNDs[1] 包含第一个控件的 ID, HWNDs[2] 包含第二个控件的 ID, 而 HWNDs.Length 返回数字 2.

控件是按照 Z 轴顺序排序的, 如果窗口支持 Tab 键, Z 轴顺序通常与通过 Tab 键导航的顺序相同.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

鼠标光标下的窗口或控件的 ID 可以使用 MouseGetPos 来获取.

相关

WinGetControls, 窗口函数, 控件函数


WinGetCount - 语法 & 使用 | AutoHotkey v2

WinGetCount

返回符合指定条件的现有窗口的数目.

Count := WinGetCount(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 则将检索整个系统上的所有窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

此函数返回与指定条件相匹配的现有窗口的数量. 如果没有匹配的窗口, 则返回 0.

备注

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinGetList, 窗口函数, 控件函数


WinGetID - 语法 & 使用 | AutoHotkey v2

WinGetID

返回指定窗口的唯一 ID 号(HWND).

HWND := WinGetID(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

此函数返回指定窗口的窗口句柄(HWND).

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

此函数等同于 WinExist.

窗口的 ID 号仅在其生存期内有效. 换句话说, 如果应用程序重新启动, 它的所有窗口都将获得新的 ID 号.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取. 要发现控件的 HWND(用于与 PostMessage, SendMessage 或 DllCall 一起使用), 请使用 ControlGetHwnd 或 MouseGetPos.

相关

WinGetIDLast, ControlGetHwnd, Hwnd 属性(Gui 对象), 窗口函数, 控件函数

示例

最大化活动窗口并报告其唯一 ID.

active_id := WinGetID("A")
WinMaximize active_id
MsgBox "The active window's ID is " active_id


WinGetIDLast - 语法 & 使用 | AutoHotkey v2

WinGetIDLast

如果找到多个匹配窗口, 则返回最后的/最底部的窗口的唯一 ID 号(HWND).

HWND := WinGetIDLast(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

如果有多个匹配项, 则返回最后的/最底部的窗口的窗口句柄(HWND).

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

如果只有一个匹配, 那么它的效果与 WinGetID 相同.

窗口的 ID 号仅在其生存期内有效. 换句话说, 如果应用程序重新启动, 它的所有窗口都将获得新的 ID 号.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取. 要发现控件的 HWND(用于与 PostMessage, SendMessage 或 DllCall 一起使用), 请使用 ControlGetHwnd 或 MouseGetPos.

相关

WinGetID, ControlGetHwnd, Hwnd 属性(Gui 对象), 窗口函数, 控件函数


WinGetList - 语法 & 使用 | AutoHotkey v2

WinGetList

返回符合指定条件的所有现有窗口的唯一 ID 号(HWND) 数组.

HWNDs := WinGetList(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 则将检索整个系统上的所有窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: Array

此函数返回所有符合指定条件的现有窗口的唯一 ID 号的数组. 每个数字是一个窗口句柄(HWND). 如果没有匹配窗口, 则返回空数组.

例如, 如果将返回值赋值给变量 HWNDs, 并且发现了两个匹配的窗口, 则 HWNDs[1] 包含第一个窗口的 ID, HWNDs[2] 包含第二个窗口的 ID, 而 HWNDs.Length 返回数字 2.

Windows 将按从顶部到底部的顺序检索(根据它们在桌面上的堆叠方式).

备注

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinGetCount, 窗口函数, 控件函数

示例

访问整个系统中的所有窗口并显示它们的信息.

ids := WinGetList(,, "Program Manager")
for this_id in ids
{
    WinActivate this_id
    this_class := WinGetClass(this_id)
    this_title := WinGetTitle(this_id)
    Result := MsgBox(
    (
        "Visiting All Windows
        " A_Index " of " ids.Length "
        ahk_id " this_id "
        ahk_class " this_class "
        " this_title "

        Continue?"
    ),, 4)
    if (Result = "No")
        break
}


WinGetMinMax - 语法 & 使用 | AutoHotkey v2

WinGetMinMax

如果指定的窗口被最大化或最小化, 则返回一个非零数字.

MinMax := WinGetMinMax(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

这个函数返回一个数字, 指示指定窗口的当前状态:

  • -1: 窗口处于最小化状态(使用 WinRestore 可以使其还原).
  • 1: 窗口处于最大化状态(使用 WinRestore 可以使其还原).
  • 0: 窗口既不处于最小化状态也不处于最大化状态.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinMaximize, WinMinimize, 窗口函数, 控件函数


WinGetPID - 语法 & 使用 | AutoHotkey v2

WinGetPID

返回指定窗口的进程 ID(PID).

PID := WinGetPID(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

此函数返回指定窗口的进程 ID(PID).

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinGetProcessName, WinGetProcessPath, Process 函数, 窗口函数, 控件函数


WinGetPos - 语法 & 使用 | AutoHotkey v2

WinGetPos

获取指定窗口的位置和大小.

WinGetPos &OutX, &OutY, &OutWidth, &OutHeight, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

&OutX, &OutY

类型: VarRef

如果省略, 将不会存储相应的值. 否则, 请指定用于存储目标窗口左上角的 X 和 Y 坐标的变量的引用.

&OutWidth, &OutHeight

类型: VarRef

如果省略, 将不会存储相应的值. 否则, 请指定用于目标窗口的宽度和高度的变量的引用.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

如果 WinTitle 是 "Program Manager", 那么此函数会获取桌面的大小, 这通常与当前的屏幕分辨率相同.

最小化的窗口同样含有位置和大小. 此时返回的值可能因操作系统和配置而变化, but are usually -32000 for the X and Y coordinates and zero for the width and height..

要获取鼠标当前悬停的窗口和控件的名称, 请使用 MouseGetPos.

由于此函数返回的坐标包括窗口的标题栏, 菜单和边框, 它们可能取决于操作系统版本和主题. 要在不同的系统之间获得更一致的值, 可以考虑使用 WinGetClientPos.

在具有不同 DPI 设置的多个屏幕的系统上, 由于操作系统 DPI 缩放, 返回的位置和大小可能与预期不同.

相关

WinMove, WinGetClientPos, ControlGetPos, WinGetTitle, WinGetText, ControlGetText

示例

获取和报告计算器的位置和大小.

WinGetPos &X, &Y, &W, &H, "Calculator"
MsgBox "Calculator is at " X "," Y " and its size is " W "x" H

获取并报告活动窗口的位置.

WinGetPos &X, &Y,,, "A"
MsgBox "The active window is at " X "," Y

如果记事本存在, 检索并报告其位置.

if WinExist("Untitled - Notepad")
{
    WinGetPos &Xpos, &Ypos ; 使用由 WinExist 找到的窗口.
    MsgBox "Notepad is at " Xpos "," Ypos
}


WinGetProcessName - 语法 & 使用 | AutoHotkey v2

WinGetProcessName

返回指定窗口的进程的名称.

ProcessName := WinGetProcessName(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

此函数返回拥有指定窗口的进程名. 例如: notepad.exe.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinGetPID, WinGetProcessPath, Process 函数, 窗口函数, 控件函数


WinGetProcessPath - 语法 & 使用 | AutoHotkey v2

WinGetProcessPath

返回拥有指定窗口的进程的完整路径和名称.

ProcessPath := WinGetProcessPath(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

此函数返回拥有指定窗口的进程的完整路径和名称. 例如: C:\Windows\System32\notepad.exe. 如果没有匹配窗口, 则返回空字符串.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinGetPID, WinGetProcessName, Process 函数, 窗口函数, 控件函数


WinGetStyle / WinGetExStyle - 语法 & 使用 | AutoHotkey v2

WinGetStyle / WinGetExStyle

分别返回指定窗口的样式或扩展样式.

Style := WinGetStyle(WinTitle, WinText, ExcludeTitle, ExcludeText)
ExStyle := WinGetExStyle(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数

这些函数分别返回指定窗口的样式或扩展样式.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

有关样式的部分列表, 请参阅样式列表.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinSetStyle / WinSetExStyle, ControlGetStyle / ControlGetExStyle, 样式列表, 窗口函数, 控件函数

示例

确定窗口是否具有 WS_DISABLED 样式.

Style := WinGetStyle("My Window Title")
if (Style & 0x8000000)  ; 0x8000000 为 WS_DISABLED.
    MsgBox "The window is disabled."

确定窗口是否具有 WS_EX_TOPMOST 样式(置顶).

ExStyle := WinGetExStyle("My Window Title")
if (ExStyle & 0x8)  ; 0x8 为 WS_EX_TOPMOST.
    MsgBox "The window is always-on-top."


WinGetText - 语法 & 使用 | AutoHotkey v2

WinGetText

从指定窗口检索文本.

Text := WinGetText(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

函数返回指定窗口的文本.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果在检索窗口文本时出现问题, 则抛出 Error.

备注

通常情况下获取的文本和 Window Spy 中显示的相同. 但是, 如果 DetectHiddenText 为关闭状态, 则返回值中省略了隐藏的文本.

每个文本元素都以回车换行符(CR+LF) 结束, 它们在脚本中表示为 `r`n. 要提取个别行或子字符串, 请使用类似 InStr 和 SubStr 的函数. 解析循环还可用于逐个检查每行或每个单词.

如果获取的文本看起来像被截短了(不完整), 可能需要通过 SendMessage 发送 WM_GETTEXT 消息来获取文本. 这是很有必要的, 因为有些应用程序不能正确响应 WM_GETTEXTLENGTH 消息, 这会导致 AutoHotkey 将返回值设置得太小, 无法容纳所有的文本. 因为某些应用程序不能正确响应 WM_GETTEXTLENGTH 消息, 所以这是必要的, 否则会导致 AutoHotkey 把输出变量设的过小以致无法保存所有的文本.

如果目标窗口(例如打开大文档的编辑器) 包含大量文本, 则此函数可能会使用大量 RAM. 为了避免这种情况, 可以通过使用 ControlGetText 来仅检索窗口文本的一部分. 无论如何, 以后可以通过将变量赋值为空来释放变量的内存, 例如 Text := "".

没有必要执行 SetTitleMatchMode "Slow", 因为 WinGetText 总是使用慢速模式检索文本(因为它适用于更广泛的控件类型).

要获取窗口中所有控件的数组, 请使用 WinGetControls 或 WinGetControlsHwnd.

相关

ControlGetText, WinGetTitle, WinGetPos

示例

打开计算器, 等待其存在, 并检索和报告其文本.

Run "calc.exe"
WinWait "Calculator"
MsgBox "The text is:`n" WinGetText()  ; 使用由 WinWait 找到的窗口.


WinGetTitle - 语法 & 使用 | AutoHotkey v2

WinGetTitle

检索指定窗口的标题.

Title := WinGetTitle(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

此函数返回指定窗口的标题.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

要发现鼠标当前悬停的窗口的名称, 请使用 MouseGetPos.

相关

WinSetTitle, WinGetClass, WinGetText, ControlGetText, WinGetPos, 窗口函数

示例

检索并报告活动窗口的标题.

MsgBox "The active window is '" WinGetTitle("A") "'."


WinGetTransColor - 语法 & 使用 | AutoHotkey v2

WinGetTransColor

返回指定窗口中标记为透明的颜色.

TransColor := WinGetTransColor(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 字符串

函数返回六位的 RGB 颜色, 例如 0x00CC99 在指定的窗口中被标记为透明.

在下列情况下, 返回值是一个空字符串:

  • 窗口没有透明色.
  • 其他情况(由操作系统行为引起) 例如设置透明后窗口被最小化, 还原和/或重设大小.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

若要将颜色标记为透明, 请使用 WinSetTransColor.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinSetTransColor, WinGetTransparent, 窗口函数, 控件函数

示例

检索鼠标光标下的窗口的透明颜色.

MouseGetPos ,, &MouseWin
TransColor := WinGetTransColor(MouseWin)


WinGetTransparent - 语法 & 使用 | AutoHotkey v2

WinGetTransparent

返回指定窗口的透明度的等级.

TransDegree := WinGetTransparent(WinTitle, WinText, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

返回值

类型: 整数或字符串(空)

函数返回一个 0 到 255 之间的整数, 其代表了指定窗口的透明度等级, 其中 0 表示不可见窗口, 而 255 表示不透明窗口.

在下列情况下, 返回值为空字符串:

  • 窗口没有设置透明度等级.
  • 其他情况(由操作系统行为引起) 例如设置透明后窗口被最小化, 还原和/或重设大小.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

若要设置透明度, 请使用 WinSetTransparent.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinSetTransparent, WinGetTransColor, 窗口函数, 控件函数

示例

检索鼠标指针下窗口的透明度.

MouseGetPos ,, &MouseWin
TransDegree := WinGetTransparent(MouseWin)


WinHide - 语法 & 使用 | AutoHotkey v2

WinHide

隐藏指定的窗口.

WinHide WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError, 除非使用 group(组) 模式.

备注

使用 WinShow 来恢复隐藏的窗口的显示(DetectHiddenWindows 设置为 On 或 Off 都没关系).

此函数仅对最上面的匹配窗口起作用, 除非 WinTitle 是 ahk_group GroupName, 在这种情况下, 组中的所有窗口均会受到影响.

相关

WinShow, SetTitleMatchMode, DetectHiddenWindows, Last Found Window, 窗口函数

示例

打开记事本, 等到记事本窗口存在后, 短时间内将其隐藏起来, 然后取消隐藏.

Run "notepad.exe"
WinWait "Untitled - Notepad"
Sleep 500
WinHide ; 使用由 WinWait 找到的窗口.
Sleep 1000
WinShow ; 使用由 WinWait 找到的窗口.

Temporarily hides the taskbar.

WinHide "ahk_class Shell_TrayWnd"
Sleep 1000
WinShow "ahk_class Shell_TrayWnd"


WinKill - 语法 & 使用 | AutoHotkey v2

WinKill

强制关闭指定的窗口.

WinKill WinTitle, WinText, SecondsToWait, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

SecondsToWait

类型: 整数或浮点数

如果省略, 此函数不会等待. 否则, 请指定等待窗口关闭的秒数(可以为小数). 如果窗口在此期间没有关闭, 那么脚本会继续执行.

错误处理

如果找不到窗口, 则抛出 TargetError, 除非使用了 group 模式.

如果找到了一个窗口但无法关闭, 则不会抛出异常, 因此, 如果你需要确定窗口已经关闭, 请使用 WinExist 或 WinWaitClose.

备注

此函数首先会用短暂的时间尝试正常地关闭窗口. 如果失败, 那么函数会尝试终止窗口进程来强制关闭窗口.

如果匹配窗口是活动的, 那么会优先关闭此窗口而不是其他匹配窗口. 一般而言, 如果有多个匹配窗口, 那么会关闭最上面的(最近使用的) 窗口.

此函数仅对单一窗口起作用, 除非 WinTitle 是 ahk_group GroupName, 在这种情况下, 组中的所有窗口均会受到影响.

当函数处于等待状态时, 可以通过热键, 自定义菜单项, 或计时器来启动新线程.

相关

WinClose, WinWaitClose, ProcessClose, WinActivate, SetTitleMatchMode, DetectHiddenWindows, Last Found Window, WinExist, WinActive, WinWaitActive, WinWait, GroupActivate

示例

如果记事本确实存在, 强制关闭它, 否则强制关闭计算器.

if WinExist("Untitled - Notepad")
    WinKill ; 使用由 WinExist 找到的窗口
else
    WinKill "Calculator"


WinMaximize - 语法 & 使用 | AutoHotkey v2

WinMaximize

将指定的窗口放大到最大尺寸(最大化指定的窗口).

WinMaximize WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError, 除非使用 group(组) 模式.

备注

使用 WinRestore 还原最大化窗口, 或使用 WinMinimize 来最小化窗口.

如果有特殊类型的窗口无法正确响应, 请尝试使用下面的方法:

PostMessage 0x0112, 0xF030,,, WinTitle, WinText  ; 0x0112 = WM_SYSCOMMAND, 0xF030 = SC_MAXIMIZE

此函数仅对最上面的匹配窗口起作用, 除非 WinTitle 是 ahk_group GroupName, 在这种情况下, 组中的所有窗口均会受到影响.

相关

WinRestore, WinMinimize

示例

打开记事本, 等到记事本存在后将其最大化.

Run "notepad.exe"
WinWait "Untitled - Notepad"
WinMaximize ; 使用 WinWait 找到的窗口

按下热键来最大化活动窗口.

^Up::WinMaximize "A"  ; Ctrl+Up


WinMinimize - 语法 & 使用 | AutoHotkey v2

WinMinimize

将指定的窗口最小化为任务栏上的按钮(最小化指定的窗口).

WinMinimize WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError, 除非使用 group(组) 模式.

备注

使用 WinRestore 取消窗口最小化, 或 WinMaximize 最大化窗口.

WinMinimize 最小化窗口使用了直接的方法, 绕过了通常在最小化按钮, 窗口菜单或任务栏用于最小化窗口时发送的窗口信息. 这可以防止窗口覆盖动作(比如通过隐藏窗口来 "最小化" 到任务栏), 但也可能阻止窗口正确响应, 比如在恢复窗口时保存当前焦点. 它还会阻止 "最小化" 系统声音的播放.

如果有特殊类型的窗口无法正确响应 WinMinimize, 请尝试使用下面的方法:

PostMessage 0x0112, 0xF020,,, WinTitle, WinText ; 0x0112 = WM_SYSCOMMAND, 0xF020 = SC_MINIMIZE

此函数仅对最上面的匹配窗口起作用, 除非 WinTitle 是 ahk_group GroupName, 在这种情况下, 组中的所有窗口均会受到影响.

相关

WinRestore, WinMaximize, WinMinimizeAll

示例

打开记事本, 等到记事本存在后将其最小化.

Run "notepad.exe"
WinWait "Untitled - Notepad"
WinMinimize ; 使用由 WinWait 找到的窗口

按下热键来最小化活动窗口.

^Down::WinMinimize "A"  ; Ctrl+Down


WinMinimizeAll / WinMinimizeAllUndo - 语法 & 使用 | AutoHotkey v2

WinMinimizeAll / WinMinimizeAllUndo

最小化或还原所有窗口.

WinMinimizeAll
WinMinimizeAllUndo

在大多数系统中, 此命令等同于资源管理器的 Win+M 和 Win+D 热键.

相关

WinMinimize, GroupAdd

示例

将所有窗口最小化 1 秒, 然后还原.

WinMinimizeAll
Sleep 1000
WinMinimizeAllUndo


WinMove - 语法 & 使用 | AutoHotkey v2

WinMove

改变指定窗口的位置和/或大小.

WinMove X, Y, Width, Height, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

X, Y

类型: 整数

如果其中一个为空或省略, 则不会更改该维度中的位置. 否则, 请指定目标窗口新位置的左上角的 X 和 Y 坐标(单位为像素). 屏幕左上角坐标为 0, 0.

Width, Height

类型: 整数

如果其中一个省略, 则不会更改该维度中的尺寸. 否则, 请指定目标窗口的新宽度和高度(单位为像素).

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果内部函数调用报告失败, 则抛出 OSError. 但是, 即使窗口没有移动, 也可能报告成功, 例如, 如果窗口限制了自己的移动.

备注

如果 Width 或 Height 太小(或为负数), 那么大多数带标题栏的窗口最小尺寸不会小于 112 x 27 像素(不过, 有些类型的窗口的最小的尺寸可能有差异). 如果 Width 或 Height 太大, 那么大多数窗口最大尺寸不会大于超过桌面尺寸大约 12 像素.

X 和 Y 坐标允许使用负数, 这样可以支持多显示器系统, 并将窗口完全移出屏幕.

尽管 WinMove 不能移动最小化状态的窗口, 不过当 DetectHiddenWindows 设置开启时它可以移动隐藏窗口.

WinMove 移动窗口的速度受 SetWinDelay 影响.

在具有不同 DPI 设置的多个屏幕的系统上, 由于操作系统 DPI 缩放, 返回的位置和大小可能与预期不同.

相关

ControlMove, WinGetPos, WinHide, WinMinimize, WinMaximize, 窗口函数

示例

打开计算器, 等待它的存在并将其移动到屏幕的左上角.

Run "calc.exe"
WinWait "Calculator"
WinMove 0, 0 ; 使用由 WinWait 找到的窗口.

创建一个固定大小的弹出窗口, 显示剪贴板的内容, 并将其移动到屏幕的左上角.

MyGui := Gui("ToolWindow -Sysmenu Disabled", "The clipboard contains:")
MyGui.Add("Text",, A_Clipboard)
MyGui.Show("w400 h300")
WinMove 0, 0,,, MyGui
MsgBox "Press OK to dismiss the popup window"
MyGui.Destroy()

让指定窗口显示在屏幕中间.

CenterWindow("ahk_class Notepad")

CenterWindow(WinTitle)
{
    WinGetPos ,, &Width, &Height, WinTitle
    WinMove (A_ScreenWidth/2)-(Width/2), (A_ScreenHeight/2)-(Height/2),,, WinTitle
}


WinMoveBottom - 语法 & 使用 | AutoHotkey v2

WinMoveBottom

发送指定的窗口到堆栈的底部; 也就是说, 在所有其他窗口下方.

WinMoveBottom WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果无法应用更改, 则抛出 OSError.

备注

此效果类似于按下 Alt+Esc.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinMoveTop, WinSetAlwaysOnTop, 窗口函数, 控件函数


WinMoveTop - 语法 & 使用 | AutoHotkey v2

WinMoveTop

将指定的窗口移到堆栈顶部, 而无需显式激活它.

WinMoveTop WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果无法应用更改, 则抛出 OSError.

备注

但是, 在大多数情况下, 系统默认设置可能会导致其激活. 此外, 由于操作系统针对试图窃取用户焦点的应用程序提供保护, 因此该函数可能无效(这可能取决于诸如当前活动窗口的类型和用户正在执行的操作之类的因素). 一种可能的解决方法是使窗口暂时置顶, 然后关闭置顶.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinMoveBottom, WinSetAlwaysOnTop, 窗口函数, 控件函数


WinRedraw - 语法 & 使用 | AutoHotkey v2

WinRedraw

重绘指定窗口.

WinRedraw WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

备注

函数试图通过通知操作系统窗口的矩形需要重新绘制来更新窗口的外观/内容. 如果此方法对特定窗口无效, 请尝试 WinMove. 如果这不起作用, 请尝试 WinHide 与 WinShow 结合使用.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinMoveBottom, WinSetAlwaysOnTop, 窗口函数, 控件函数


WinRestore - 语法 & 使用 | AutoHotkey v2

WinRestore

如果指定的窗口处于最小化或最大化状态, 则还原它.

WinRestore WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError, 除非使用 group(组) 模式.

备注

如果有特殊类型的窗口无法正确响应 WinRestore, 请尝试使用下面的方法:

PostMessage 0x112, 0xF120,,, WinTitle, WinText  ; 0x112 = WM_SYSCOMMAND, 0xF120 = SC_RESTORE

此函数仅对最上面的匹配窗口起作用, 除非 WinTitle 是 ahk_group GroupName, 在这种情况下, 组中的所有窗口均会受到影响.

相关

WinMinimize, WinMaximize

示例

如果记事本处于最小化或最大化状态, 则还原它.

WinRestore "无标题 - 记事本"


WinSetAlwaysOnTop - 语法 & 使用 | AutoHotkey v2

WinSetAlwaysOnTop

使指定的窗口停留在所有其他窗口的顶部(除了其他始终在顶部(置顶) 的窗口).

WinSetAlwaysOnTop NewSetting, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

NewSetting

类型: 整数

如果省略, 默认为 1. 否则, 请指定以下值之一:

  • 1 或 True 打开该设置
  • 0 或 False 关闭该设置
  • -1 切换设置(将其设置为与当前状态相反的状态)

如果为空或省略, 则默认为 "Toggle".

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果无法应用更改, 则抛出 OSError.

备注

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinMoveTop, WinMoveBottom, 窗口函数, 控件函数

示例

切换计算器的置顶状态.

WinSetAlwaysOnTop -1, "Calculator"


WinSetEnabled - 语法 & 使用 | AutoHotkey v2

WinSetEnabled

启用或禁用指定的窗口.

WinSetEnabled NewSetting , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

NewSetting

类型: 整数

以下值之一:

  • 1 或 True 打开该设置
  • 0 或 False 关闭该设置
  • -1 切换设置(将其设置为与当前状态相反)
WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果无法应用更改, 则抛出 OSError.

备注

禁用窗口后, 用户将无法移动它或与其控件进行交互. 另外, 将从 alt-tab 列表中忽略禁用的窗口.

WinGetStyle 示例 #1 可用于确定是否禁用了窗口.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

ControlSetEnabled, 窗口函数, 控件函数


WinSetRegion - 语法 & 使用 | AutoHotkey v2

WinSetRegion

将指定窗口的形状改为指定的矩形, 椭圆或多边形.

WinSetRegion Options, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Options

类型: 字符串

如果为空或省略, 则窗口恢复到其原始/默认显示形状. 否则, 请指定以下一个或多个选项, 每个选项之间用空格分隔:

W n: 矩形或椭圆的宽度. 例如: w200.

H n: 矩形或椭圆的高度. 例如: h200.

X-Y: 每一个都是一对 X/Y 坐标. 例如, 200-0 将使用 200 作为 X 坐标, 0 作为 Y 坐标.

E: 设置窗口形状为椭圆形而不是矩形. 此选项仅在同时指定了 W 和 H 时才有效.

R w-h: 设置窗口形状为圆角矩形. 例如, r30-30 表示每个角为 30x30 的椭圆. 如果 w-h 省略, 则使用 30-30. R 仅在同时指定了 W 和 H 时才有效.

矩形或椭圆形: 如果指定了 W 和 H 选项, 那么会设置新显示的局域为矩形, 且其左上角的坐标为首个(且唯一) X-Y 坐标对. 但是, 如果同时指定了 E 选项, 那么会设置窗口形状为椭圆形而不是矩形. 例如: WinSetRegion "50-0 w200 h250 E".

多边形: 如果 W 和 H 选项都不存在时, 新的显示区域将是由多个 X-Y 坐标对决定的多边形(每对坐标是窗口内相对于其左上角的一个点). 例如, 如果指定了三对坐标, 那么在多数时候窗口形状会被设置为三角形. 坐标对彼此间的相对顺序有时很重要. 此外, 可以在 Options 中指定单词 Wind 从而使用缠绕法代替变换方法来确定多边形的形状.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果一个或多个 Options 无效, 或指定的坐标超过 2000 对, 则抛出 ValueError.

如果指定的区域无效或无法应用于目标窗口, 则抛出 OSError.

备注

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

当为脚本所拥有的窗口设置了一个区域时, 系统可能会自动改变渲染窗口框架的方法, 从而改变其外观. 其效果类似于下面所示的解决方法 #2, 但只影响窗口, 直到其区域被重置.

已知限制: 为不属于脚本的窗口设置一个区域可能会产生意想不到的结果, 如果该窗口有标题(标题栏), 并且系统启用了桌面合成. 这是因为可见的框架实际上并不是窗口的一部分, 而是由一个名为 "桌面窗口管理器(DWM)" 的单独系统进程渲染的. 注意, 在 Windows 8 及以后的版本中, 桌面合成始终处于启用状态. 可以使用以下两种解决方法之一:

; #1: 移除窗口标题.
WinSetStyle "-0xC00000", "Window Title"

; 恢复:
WinSetStyle "+0xC00000", "Window Title"
; #2: 禁用 DWM 渲染窗口的框架.
DllCall("dwmapi\DwmSetWindowAttribute", "ptr", WinExist("Window Title")
  , "uint", DWMWA_NCRENDERING_POLICY := 2, "int*", DWMNCRP_DISABLED := 1, "uint", 4)

; 恢复(这也可能导致任何设置的区域被忽略):
DllCall("dwmapi\DwmSetWindowAttribute", "ptr", WinExist("Window Title")
  , "uint", DWMWA_NCRENDERING_POLICY := 2, "int*", DWMNCRP_ENABLED := 2, "uint", 4)

相关

窗口函数, 控件函数

示例

使记事本在此矩形之外的所有部分都不可见. 这个例子可能不适用于 Windows 11 或更高版本的新记事本.

WinSetRegion "50-0 w200 h250", "ahk_class Notepad"

与上面相同, 不过带有 40x40 的圆角. 这个例子可能不适用于 Windows 11 或更高版本的新记事本.

WinSetRegion "50-0 w200 h250 r40-40", "ahk_class Notepad"

创建椭圆形窗口.

WinSetRegion "50-0 w200 h250 E", "ahk_class Notepad"

创建倒三角形窗口. 这个例子可能不适用于 Windows 11 或更高版本的新记事本.

WinSetRegion "50-0 250-0 150-250", "ahk_class Notepad"

将窗口恢复原来/默认的形状. 这个例子可能不适用于 Windows 11 或更高版本的新记事本.

WinSetRegion , "ahk_class Notepad"

它在记事本(或任何其他窗口) 内创建一个透明的矩形孔. 下面指定了两个矩形: 一个外部的, 一个内部的. 每个矩形由 5 对 X/Y 坐标组成, 因为第一对是用来 "闭合" 每个矩形的重复坐标. 这个例子可能不适用于 Windows 11 或更高版本的新记事本.

WinSetRegion "0-0 300-0 300-300 0-300 0-0   100-100 200-100 200-200 100-200 100-100", "ahk_class Notepad"


WinSetStyle / WinSetExStyle - 语法 & 使用 | AutoHotkey v2

WinSetStyle / WinSetExStyle

分别改变指定窗口的样式和扩展样式.

WinSetStyle Value , WinTitle, WinText, ExcludeTitle, ExcludeText
WinSetExStyle Value , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Value

类型: 整数或字符串

传递一个正整数来完全覆盖窗口的样式; 也就是说, 设置它的值为 Value.

要添加, 删除或切换样式, 请分别传递一个以加号(+), 减号(-) 或插入符号(^) 前缀的数字字符串. 新样式值的计算如下所示(其中 CurrentStyle 可以通过 WinGetStyle 或 WinGetExStyle 检索):

操作 前缀 示例 公式
添加 + "+0x80" NewStyle := CurrentStyle | Value
删除 - "-0x80" NewStyle := CurrentStyle & ~Value
切换 ^ "^0x80" NewStyle := CurrentStyle ^ Value

如果 Value 是一个负整数, 它将被视为与对应的数字字符串相同.

要在表达式中原义使用 + 或 ^ 前缀, 前缀或值必须用引号括起来. 例如: WinSetStyle("+0x80") 或 WinSetStyle("^" StylesToToggle). 这是因为表达式 +123 产生 123(没有前缀), 而 ^123 是一个语法错误.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果无法应用更改, 则抛出 OSError.

备注

有关样式的部分列表, 请参阅样式列表.

将某些样式更改应用于可见窗口后, 可能需要使用 WinRedraw 重新绘制窗口.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinGetStyle / WinGetExStyle, ControlSetStyle / ControlSetExStyle, 样式列表, 窗口函数, 控件函数

示例

移除活动窗口的标题栏(WS_CAPTION).

WinSetStyle "-0xC00000", "A"

切换 WS_EX_TOOLWINDOW 属性, 它会从 alt-tab 列表中移除/添加 Notepad 窗口.

WinSetExStyle "^0x80", "ahk_class Notepad"


WinSetTitle - 语法 & 使用 | AutoHotkey v2

WinSetTitle

更改指定窗口的标题.

WinSetTitle NewTitle , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

NewTitle

类型: 字符串

窗口的新标题. 如果只给出此参数, 那么使用上次找到的窗口.

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果无法应用更改, 则抛出 OSError.

备注

如果拥有窗口的应用程序频繁地更改标题, 那么对窗口标题的更改可能只是暂时的.

相关

WinMove, WinGetTitle, WinGetText, ControlGetText, WinGetPos, 窗口函数

示例

更改记事本的标题. 这个例子在 Windows 11 或更高版本系统可能会失败, 因为它需要经典版本的记事本.

WinSetTitle("This is a new title", "Untitled - Notepad")

打开记事本, 等到记事本处于活动状态时, 更改标题. 这个例子在 Windows 11 或更高版本系统可能会失败, 因为它需要经典版本的记事本.

Run "notepad.exe"
WinWaitActive "Untitled - Notepad"
WinSetTitle "This is a new title" ; 使用 WinWaitActive 找到的窗口.

打开主窗口, 等待它激活并改变它的标题.

ListVars
WinWaitActive "ahk_class AutoHotkey"
WinSetTitle "This is a new title" ; 使用 WinWaitActive 找到的窗口.


WinSetTransColor - 语法 & 使用 | AutoHotkey v2

WinSetTransColor

使所选颜色的所有像素在指定的窗口内不可见(透明).

WinSetTransColor Color , WinTitle, WinText, ExcludeTitle, ExcludeText

参数

Color

类型: 字符串或整数

指定一个颜色名称或 RGB 值(请参阅颜色列表以获得指导, 或在 RGB 模式下使用 PixelGetColor). 如果要使窗口的可见部分部分透明(半透明), 请在透明度级别(0-255) 后面添加一个空格(不是逗号). 例如: WinSetTransColor "EEAA99 150".

如果值是一个字符串, 任何数字颜色值必须是十六进制的格式. 颜色值可以省略; 例如, WinSetTransColor " 150"(带前导空格) 等同于 WinSetTransparent 150.

"Off"(不区分大小写) 或空字符串可以完全关闭窗口的透明度. 这与 WinSetTransparent "Off" 功能相同. 指定 Off 与指定 255 不同, 因为它可能会提高性能并减少系统资源的使用(但可能只在禁用桌面合成时).

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果无法应用更改, 则抛出 OSError.

备注

这使得后面的窗口内容可以显示出来. 如果用户点击一个不可见的像素, 点击会 "穿透" 到后面的窗口.

要改变一个窗口现有的 TransColor, 可能需要在改变之前关闭透明度.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

此函数常用来创建屏幕显示(OSD) 和其他视觉效果. 在 Gui 对象页面的底部有一个屏幕显示的例子. 有关通过热键的简单演示, 请参阅 WinSetTransparent 示例 #4.

这个函数经常被用来创建屏幕上的显示和其他视觉效果. 在 Gui 对象页面的底部有一个屏幕显示的例子. 通过热键进行简单的演示, 请参阅 WinSetTransparent 页面的示例 #3.

相关

WinSetTransparent, 窗口函数, 控件函数

示例

使记事本中的所有白色像素都不可见. 这个例子在 Windows 11 或更高版本的新记事本上可能不能很好地工作.

WinSetTransColor "White", "Untitled - Notepad"


WinSetTransparent - 语法 & 使用 | AutoHotkey v2

WinSetTransparent

使指定的窗口半透明.

WinSetTransparent N, WinTitle, WinText, ExcludeTitle, ExcludeText

参数

N

类型: 整数或字符串

要启用透明度, 请指定一个 0 到 255 之间的数字, 以表示透明度: 0 表示完全透明, 而 255 表示完全不透明.

"Off"(不区分大小写) 或空字符串可以完全关闭窗口的透明度. 这在功能上与 WinSetTransColor "Off" 相同. 指定 Off 与指定 255 的区别是, 这样可以提升性能并降低系统资源的占用(但可能仅在禁用 DWM 时).

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError.

如果无法应用更改, 则抛出 OSError.

备注

例如, 要使任务栏透明, 请使用 WinSetTransparent 150, "ahk_class Shell_TrayWnd". 类似地, 要使经典的开始菜单透明, 请参阅示例 #2. 要使开始菜单的子菜单透明, 还需要包含示例 #2 中的脚本.

在使用 Off 之前, 将透明级别设置为 255, 可以避免窗口重绘问题, 比如黑色背景. 如果窗口仍无法正确重绘, 那么请参阅 WinRedraw 了解可能的解决方法.

鼠标光标下的窗口的 ID 可以使用 MouseGetPos 来获取.

相关

WinSetTransColor, 窗口函数, 控件函数

示例

让记事本变得有点透明.

WinSetTransparent 200, "Untitled - Notepad"

使经典开始菜单透明(若要使开始菜单的子菜单透明, 请参阅示例 #3).

DetectHiddenWindows True
WinSetTransparent 150, "ahk_class BaseBar"

使所有或选定的菜单一出现就在整个系统中变得透明. 请注意, 尽管这样的脚本不能使自己的菜单透明, 但它可以使其他脚本的菜单透明.

SetTimer WatchForMenu, 5

WatchForMenu()
{
    DetectHiddenWindows True  ; 可以更早的检测菜单.
    if WinExist("ahk_class #32768")
        WinSetTransparent 150  ; 使用上面一行找到的窗口.
}

演示 WinSetTransparent 和 WinSetTransColor 效果的一些热键. 注意: 如果在鼠标光标悬停在 TransColor 造成的不可见的像素上时按下其中一个热键, 则这个像素下面可见的窗口将会被替代!

#t::  ; 按下 Win+T 来让鼠标光标下的颜色透明.
{
    MouseGetPos &MouseX, &MouseY, &MouseWin
    MouseRGB := PixelGetColor(MouseX, MouseY)
    ;  似乎有必要首先关闭任何现有的透明度:
    WinSetTransColor "Off", MouseWin
    WinSetTransColor MouseRGB " 220", MouseWin
}

#o::  ; 按下 Win+O 来关闭鼠标下窗口的透明度.
{
    MouseGetPos ,, &MouseWin
    WinSetTransColor "Off", MouseWin
}

#g::  ; 按下 Win+G 来显示鼠标下窗口的当前透明设置.
{
    MouseGetPos ,, &MouseWin
    TransDegree := WinGetTransparent(MouseWin)
    TransColor := WinGetTransColor(MouseWin)
    ToolTip "Translucency:`t" TransDegree "`nTransColor:`t" TransColor
}


WinShow - 语法 & 使用 | AutoHotkey v2

WinShow

显示指定的窗口.

WinShow WinTitle, WinText, ExcludeTitle, ExcludeText

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

错误处理

如果找不到窗口, 则抛出 TargetError, 除非使用 group(组) 模式.

备注

默认情况下, WinShow 是唯一一个在任何时候都能检测隐藏窗口的函数. 只有在 DetectHiddenWindows 设置打开时, 其他内置函数才能检测到隐藏窗口.

此函数仅对最上面的匹配窗口起作用, 除非 WinTitle 是 ahk_group GroupName, 在这种情况下, 组中的所有窗口均会受到影响.

相关

WinHide, SetTitleMatchMode, DetectHiddenWindows, Last Found Window

示例

打开记事本, 等到记事本窗口存在后, 短时间内将其隐藏起来, 然后取消隐藏.

Run "notepad.exe"
WinWait "无标题 - 记事本"
Sleep 500
WinHide  ; 使用由 WinWait 找到的窗口.
Sleep 1000
WinShow  ; 使用由 WinWait 找到的窗口.


WinWait - 语法 & 使用 | AutoHotkey v2

WinWait

等待直到指定的窗口存在.

HWND := WinWait(WinTitle, WinText, Timeout, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

至少需要其中的一个. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

Timeout

类型: 整数或浮点数

如果省略, 函数将会无限期等待. 否则, 指定在超时之前等待的秒数. 若要等待零点几秒, 请指定一个浮点数, 例如, 0.25 表示最多等待 250 毫秒.

返回值

类型: 整数

如果发现了匹配的窗口, 则该函数返回该窗口的 HWND(唯一 ID), 否则函数超时, 返回 0.

备注

如果匹配窗口存在, 函数不会等待到 Timeout 过期. 相反, 它会更新上次找到的窗口和返回, 并让脚本继续执行.

如果 WinTitle 指定了一个纯 HWND(作为一个整数或带有 HWND 属性的对象), 隐藏窗口只有在使用 DetectHiddenWindows 时才会被检测到. 这只适用于 WinWait 和 WinWaitClose; 对于其他窗口函数, 指定一个纯 HWND 将导致检测隐藏窗口, 而不考虑 DetectHiddenWindows.

如果 WinTitle 指定了一个无效的纯 HWND, 该函数立即返回, 而不等待 Timeout 超时. 等待另一个具有相同 HWND 值的窗口创建是没有意义的, 因为两个窗口之间可能没有关系.

当函数处于等待状态时, 可以通过热键, 自定义菜单项或计时器启动新的线程.

如果另一个线程更改了用于该函数参数的任何变量的内容, 该函数将不会看到更改 -- 它将继续使用在函数首次开始等待时最初出现在变量中的标题和文本.

与 WinWaitActive 不同, 不能使用上次找到的窗口. 所以, 至少有一个窗口参数(WinTitle, WinText, ExcludeTitle, ExcludeText) 必须是非空的.

相关

WinWaitActive, WinWaitClose, WinExist, WinActive, ProcessWait, SetTitleMatchMode, DetectHiddenWindows

示例

打开记事本, 最多等待 3 秒, 直到它存在. 如果 WinWait 超时, 会显示一条错误信息, 否则记事本将被最小化.

Run "notepad.exe"
if WinWait("Untitled - Notepad", , 3)
    WinMinimize  ; 使用由 WinWait 找到的窗口.
else
    MsgBox "WinWait timed out."


WinWaitActive / WinWaitNotActive - 语法 & 使用 | AutoHotkey v2

WinWaitActive / WinWaitNotActive

等待直到指定的窗口处于活动或不活动状态.

HWND := WinWaitActive(WinTitle, WinText, Timeout, ExcludeTitle, ExcludeText)
Boolean := WinWaitNotActive(WinTitle, WinText, Timeout, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或对象

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

Timeout

类型: 整数或浮点数

如果省略, 函数将会无限期等待. 否则, 指定在超时之前等待的秒数. 若要等待零点几秒, 请指定一个浮点数, 例如, 0.25 表示最多等待 250 毫秒.

返回值

类型: 整数或整数(布尔值)

如果匹配条件, WinWaitActive 返回活动窗口的 HWND(唯一 ID), 否则函数超时, 返回 0.

如果活动窗口不匹配条件, 则 WinWaitNotActive 返回 1(true), 否则函数超时, 返回 0(false).

备注

如果活动窗口满足函数的期望, 函数不会等待到 Timeout 过期. 相反, 它将立即返回, 并让脚本继续执行.

由于 "A" 匹配任何给定时刻处于活动状态的窗口, 因此 WinWaitNotActive "A" 通常无限期地等待. 要替代等待一个不同的窗口激活, 指定其唯一的 ID, 如下例所示:

WinWaitNotActive WinExist("A")

如果匹配窗口在函数开始时或在函数等待时处于活动状态, 则 WinWaitActive 和 WinWaitNotActive 都将更新上次找到的窗口.

当函数处于等待状态时, 可以通过热键, 自定义菜单项或计时器启动新的线程.

如果另一个线程更改了用于该函数参数的任何变量的内容, 该函数将不会看到更改 -- 它将继续使用在函数首次开始等待时最初出现在变量中的标题和文本.

相关

WinWait, WinWaitClose, WinExist, WinActive, SetTitleMatchMode, DetectHiddenWindows

示例

打开记事本, 最多等待 2 秒, 直到它被激活. 如果 WinWait 超时, 会显示一条错误信息, 否则记事本将被最小化.

Run "notepad.exe"
if WinWaitActive("Untitled - Notepad", , 2)
    WinMinimize  ; 使用由 WinWaitActive 找到的窗口.
else
    MsgBox "WinWaitActive timed out."


WinWaitClose - 语法 & 使用 | AutoHotkey v2

WinWaitClose

等待直到找不到匹配的窗口.

Boolean := WinWaitClose(WinTitle, WinText, Timeout, ExcludeTitle, ExcludeText)

参数

WinTitle, WinText, ExcludeTitle, ExcludeText

类型: 字符串, 整数或

如果这些都是空白或省略, 将使用上次找到的窗口. 否则, 为 WinTitle 指定窗口标题或其他条件, 来标识目标窗口, 和/或为 WinText 指定目标窗口的单个文本元素的子字符串(由包含的 Window Spy 实用程序显示).

ExcludeTitle 和 ExcludeText 可用于根据标题或文本排除一个或多个窗口. 它们的规范类似于 WinTitle 和 WinText, 除了 ExcludeTitle 不识别除窗口标题之外的任何条件.

窗口标题和文本是区分大小写的. 默认情况下, 不检测隐藏窗口, 而检测隐藏文本元素, 除非使用 DetectHiddenWindows 和 DetectHiddenText 进行更改; 但是, 当使用纯 HWND 时, 无论 DetectHiddenWindows 怎样设置, 都会检测隐藏窗口. 默认情况下, 窗口标题的任意位置包含 WinTitle 或 ExcludeTitle 就能形成匹配, 除非使用 SetTitleMatchMode 进行了更改.

Timeout

类型: 整数或浮点数

如果省略, 函数将会无限期等待. 否则, 等待的时间不会超过这个秒数. 若要等待零点几秒, 请指定一个浮点数, 例如, 0.25 表示最多等待 250 毫秒.

返回值

类型: 整数(布尔值)

如果该函数超时, 则此函数返回 0(false), 否则返回 1(true).

备注

如果没有匹配的窗口存在, 函数将不会等待 Timeout 过期. 相反, 它将立即返回 1 并让脚本继续执行. 相反, 即使关闭了匹配窗口, 函数也可以继续等待, 直到找不到更多的匹配窗口.

如果 WinTitle 指定了一个纯 HWND(作为一个整数或带有 HWND 属性的对象), 隐藏窗口只有在使用 DetectHiddenWindows 时才会被检测到. 这只适用于 WinWait 和 WinWaitClose; 对于其他窗口函数, 指定一个纯 HWND 将导致检测隐藏窗口, 而不考虑 DetectHiddenWindows.

由于 "A" 匹配任何给定时刻处于活动状态的窗口, 因此 WinWaitClose "A" 通常无限期地等待. 要替代等待当前活动窗口关闭, 请指定其标题或唯一 ID, 如下例所示:

WinWaitClose WinExist("A")

只要找到匹配的窗口, WinWaitClose 就会更新最后找到的窗口. 这样做的一个用途是在函数超时后识别或操作窗口. 例如:

Gui("", "Test window " Random()).Show("w300 h50")  ; 显示测试窗口.
if !WinWaitClose("Test",, 5)  ; 等待 5 秒钟以让人关闭窗口.
{
    MsgBox "Window not yet closed: " WinGetTitle()
    WinClose  ; 关闭 WinWaitClose 找到的窗口.
}

当函数处于等待状态时, 可以通过热键, 自定义菜单项或计时器启动新的线程.

如果另一个线程更改了用于该函数参数的任何变量的内容, 该函数将不会看到更改 -- 它将继续使用在函数首次开始等待时最初出现在变量中的标题和文本.

相关

WinClose, WinWait, WinWaitActive, WinExist, WinActive, ProcessWaitClose, SetTitleMatchMode, DetectHiddenWindows

示例

打开记事本, 等待它的存在, 然后等待它被关闭.

Run "notepad.exe"
WinWait "Untitled - Notepad"
WinWaitClose  ; 使用由 WinWait 找到的窗口.
MsgBox "Notepad is now closed."


致谢 | AutoHotkey v2

致谢

除了已经提到的 AutoIt 作者, 还有:

Robert Yaklin: 不知疲倦地测试大量孤立的缺陷, 伟大的第一版安装者, 且对命令 应该 如何工作提出过极好的建议 :)

Jason Payam Ahdoot: 提供浮点数支持的建议和描述.

Jay D. Novak: 发现了 Send 命令, CapsLock 以及热键修饰符在 Win9x 中存在的问题; 并慷慨地分享了大量的代码以及在热键, 热字串, 钩子用法和输入加速方面的知识.

Rajat: 制作了时尚的图标替换了最初的 AHK 图标; 伟大的产品标志; 制作了 TextPad 的自定义语法; 发现了注册表命令和 AutoIt v2 在兼容上的一些问题; 编写了 SmartGUI Creator; 以及其他很多事情.

Thaddeus Beck(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:

jackieku: 开发了 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 控件的支持.

同时对其他所有提交故障报告或建议的人说声: 谢谢!


脚本编译器指令 | AutoHotkey v2

脚本编译器指令

目录

  • 介绍
  • 控制脚本行为的指令:
    • IgnoreBegin
    • IgnoreEnd
    • IgnoreKeep
  • 控制可执行文件元数据的指令:
    • 介绍
    • AddResource: 为 .exe 添加一个资源.
    • Bin / Base: 指定使用的 AutoHotkey 的基版本.
    • ConsoleApp: 设置 Console 模式.
    • Cont: 指定指令的延续行.
    • Debug: 显示指令的调试文本.
    • ExeName: 指定 .exe 的位置和名称.
    • Let: 设置一个用户变量.
    • Nop: 什么也不做.
    • Obey: 执行一个命令或表达式.
    • PostExec: 编译后运行程序.
    • ResourceID: 为主脚本指定一个非标准的资源 ID.
    • SetMainIcon: 设置主图标.
    • SetProp: 设置 .exe 的一个属性.
    • Set: 设置各种属性.
    • UpdateManifest: 更改 .exe 的 manifest.
    • UseResourceLang: 更改资源语言.

介绍

脚本编译器指令允许用户指定如何通过 Ahk2Exe 编译脚本的细节. 一些功能是:

  • 能够改变版本信息(如名称, 描述, 版本...).
  • 能够向编译的脚本添加资源.
  • 能够调整编译的一些选项.
  • 能够从编译的脚本中删除部分代码, 反之亦然.

脚本编译器在源代码中寻找特殊的注释, 并将其识别为编译器指令. 所有的编译器指令都是由字符串 @Ahk2Exe- 引入的, 前面有注释标志(通常为 ;).

控制脚本行为的指令

可以通过将已编译脚本中的代码片段包装在指令中来删除它们:

MsgBox "这条信息同时出现在已编译和未编译的脚本中"
;@Ahk2Exe-IgnoreBegin
MsgBox "这条信息不会出现在编译的脚本中"
;@Ahk2Exe-IgnoreEnd
MsgBox "这条信息同时出现在已编译和未编译的脚本中"

反过来说也是可以的, 即标记代码片段只在编译后的脚本中执行:

/*@Ahk2Exe-Keep
MsgBox "这条信息只出现在编译的脚本中"
*/
MsgBox "这条信息同时出现在已编译和未编译的脚本中"

这比 A_IsCompiled 的优势在于, 在预处理过程中, 代码被完全从编译脚本中移除, 从而使编译脚本更小. 反之亦然: 不需要检查 A_IsCompiled 因为代码在未编译的脚本中的注释块中.

控制可执行程序元数据的指令

介绍

在这些指令的参数中, 支持以下转义序列: ``, `,, `n, `r 和 `t. 无论参数位置如何, 逗号 始终 需要转义. "Integer" 是指无符号的 16 位整数(0..0xFFFF).

如果需要, 指令参数可以通过使用 %(百分号) 括住变量名来引用以下标准内置变量列表:

组 1: A_AhkPath, A_AppData, A_AppDataCommon, A_ComputerName, A_ComSpec, A_Desktop, A_DesktopCommon, A_MyDocuments, A_ProgramFiles, A_Programs, A_ProgramsCommon, A_ScriptDir, A_ScriptFullPath, A_ScriptName, A_Space, A_StartMenu, A_StartMenuCommon, A_Startup, A_StartupCommon, A_Tab, A_Temp, A_UserName, A_WinDir.

组 2: A_AhkVersion, A_IsCompiled, A_PtrSize.

除了这些变量名之外, 特殊变量 A_WorkFileName 还保存着处理后的 .exe 文件的临时名称. 这可以用来将文件名作为参数传递给任何需要访问生成的 .exe 文件的 PostExec 指令.

此外, 特殊变量 A_BasePath 包含所选基文件的完整路径和名称.

另外, 特殊变量 A_PriorLine 包含了紧接当前编译器指令之前的源代码行. 只忽略中间的空白行和注释, 以及任何中间的编译器指令行. 这个变量可以用来从脚本源代码中 "提取" 常量信息, 并在以后的编译器指令中使用它. 一个例子是访问脚本的版本号, 因为它可能会经常改变. 以这种方式访问版本号, 意味着在源代码中只需要更改一次, 更改的内容会被复制到必要的指令中. (有关详情, 请参阅下面的 RegEx 示例.)

同样, 也可以使用 Let 和 Obey 指令来创建形如 U_Name 的特殊用户变量, 如下所示.

除了可用于指令参数外, 所有变量都可以从任何 RT_MENU, RT_DIALOG, RT_STRING, RT_ACCELERATORS, RT_HTML 和 RT_MANIFEST 文件中访问, 提供给下面的 AddResource 指令.

如果需要, 从上述变量返回的值可以通过在内置变量名称结尾, 结束 % 的前面, 包括最多 2 个参数(称为 p2 和 p3) 来进行操作, 所有参数都用波浪号 ~ 分隔. 在 RegExReplace 函数的第 2 个和第 3 个参数中, p2 和 p3 参数将作为原义使用, 以操作返回的值. (请参阅正则快速参考.) 请注意, p3 是可选的.

要在 p2 或 p3 中包含波浪号作为数据, 在其前面加上重音符, 即 `~. 要在 p2 或 p3 中包含重音符作为数据, 请将其加倍, 即 ``.

RegEx 示例:
  • %A_ScriptName~\.[^\.]+$~.exe%

    这将在实际的脚本名称中用 .exe 替换扩展名加上前面的句号.
    (\.[^\.]+$~.exe 表示扫描 . 后面跟着的 1 个或多个非-. 字符, 并后面跟着结束字符, 并将其替换为 .exe)

  • 假设有一个源码行后面有两个编译器指令, 如下所示:

    CodeVersion := "1.2.3.4", company := "My Company"
    ;@Ahk2Exe-Let U_version = %A_PriorLine~U)^(.+"){1}(.+)".*$~$2%
    ;@Ahk2Exe-Let U_company = %A_PriorLine~U)^(.+"){3}(.+)".*$~$2%

    这些指令将版本号 1.2.3.4 复制到特殊变量 U_version, 将公司名称 My Company 复制到特殊变量 U_company 中, 供后面其他指令使用.
    (第一个正则表达式中的 {1} 在第二个正则表达式中改为 {3} 以便在第三个 " 之后选择提取公司名称.)

其他示例: 其他的工作示例可以从这里下载和检查.

AddResource

将资源添加到已编译的可执行文件中. (另请参阅下面的 UseResourceLang)

;@Ahk2Exe-AddResource FileName , ResourceName
FileName
要添加的资源的文件名. 如果没有指定绝对路径, 则假定该文件位于(或相对于) 脚本自己的目录中. 资源的类型(作为整数或字符串) 可以通过附加一个星号显式指定: *type Filename. 如果省略, Ahk2Exe 会根据文件扩展名自动检测类型.
ResourceName
(可选) 资源将具有的名称(可以为整数或字符串). 如果省略, 则默认为文件的名称(没有路径), 大写.

以下是常见的标准资源类型和默认触发这些资源类型的扩展名的清单.

  • 2 (RT_BITMAP): .bmp, .dib
  • 4 (RT_MENU)
  • 5 (RT_DIALOG)
  • 6 (RT_STRING)
  • 9 (RT_ACCELERATORS)
  • 10 (RT_RCDATA): 每一个其他的扩展名.
  • 11 (RT_MESSAGETABLE)
  • 12 (RT_GROUP_CURSOR): .cur(尚未支持)
  • 14 (RT_GROUP_ICON): .ico
  • 23 (RT_HTML): .htm, .html, .mht
  • 24 (RT_MANIFEST): .manifest. 如果没有指定资源的名称, 则默认为 1.

示例 1: 替换标准图标(除主图标外):

;@Ahk2Exe-AddResource Icon1.ico, 160  ; 替换 '蓝色 H'
;@Ahk2Exe-AddResource Icon2.ico, 206  ; 替换 '绿色 S'
;@Ahk2Exe-AddResource Icon3.ico, 207  ; 替换 '红色 H'
;@Ahk2Exe-AddResource Icon4.ico, 208  ; 替换 '红色 S'

示例 2: 要把另一个脚本作为单独的 RCDATA 资源包括在内(请参阅嵌入式脚本):

;@Ahk2Exe-AddResource MyScript1.ahk, #2
;@Ahk2Exe-AddResource MyScript2.ahk, MYRESOURCE

注意, 使用此指令添加的每个脚本将由编译器完全单独处理, 并且可以包含更多的指令. 如果有任何相冲突的指令, 编译器将使用最后遇到的那个指令.

Bin / Base

指定用于生成 .exe 文件的 AutoHotkey 的基础版本. 这个指令可以被 GUI 或 CLI 中指定的基文件参数所覆盖. 如果有必要, 这个指令可以被多次指定, 但只能在最顶层的脚本文件中指定(也就是说, 不能在 #Include 文件中). 编译器将为每个发现的 Bin/Base 指令至少运行一次. (如果要在这个指令上附加一个实际的注释, 必须使用 ; 标志. 要想真正注释这个指令, 请在第一个注释标志后插入一个空格.)

;@Ahk2Exe-Bin  [Path\]Name , [Exe_path\][Name], Codepage ; 不推荐
;@Ahk2Exe-Base [Path\]Name , [Exe_path\][Name], Codepage
[Path\]Name
要使用的 *.bin 或 *.exe 文件. 如果没有提供扩展名, 则假定为 .bin. 如果没有指定绝对路径, 则假定该文件位于(或相对于) 编译器自己的目录中. 可以为 Name 指定一个 DOS 掩码, 例如 ANSI*, Unicode 32*, Unicode 64* 或为这三种掩码指定 *bit. 编译器将为每个匹配的 *.bin 或 *.exe 文件运行. 任何使用内置变量替换的情况都必须是来自上述的组 1.
[Exe_path\][Name]
(可选) 要给 .exe 的文件名. 任何提供的扩展名都将被替换为 .exe. 如果没有指定路径, 则会在脚本文件夹中创建 .exe 文件. 如果没有指定名称, .exe 将使用默认名称. 任何内置变量替换的使用只能来自上面的组 1. (这个参数可以被 ExeName 指令覆盖.)
Codepage
(可选) 覆盖用于处理脚本文件的默认代码页. (脚本应该以 Unicode 字节顺序标记(BOM) 开始, 因此不需要使用这个参数.)

ConsoleApp

将可执行子系统更改为控制台模式.

;@Ahk2Exe-ConsoleApp

Cont

为前指令指定一个延续行. 这允许格式化一个长行指令, 以便在源代码中容易阅读.

;@Ahk2Exe-Cont Text
Text
在处理前一行指令之前, 要附加到该行的文字. 文本开始于 Cont 关键字后面的单个空格之后.

Debug

显示带有支持文本的消息框, 用于调试.

;@Ahk2Exe-Debug Text
Text
要显示的文本. 在 % 符号之间包含的任何特殊变量, 请参阅 (manipulated) 部分的内容.

ExeName

指定生成的 .exe 文件的位置和名称. (另请参阅 Base 指令.) 这个指令可以被 GUI 或 CLI 中指定的输出文件覆盖.

;@Ahk2Exe-ExeName [Path\][Name]
[Path\][Name]
.exe 文件的名称. 任何提供的扩展名都将被替换为 .exe. 如果没有指定路径, .exe 将在脚本文件夹中创建. 如果没有指定名称, .exe 将使用默认名称.
示例:
;@Ahk2Exe-Obey U_bits, = %A_PtrSize% * 8
;@Ahk2Exe-Obey U_type, = "%A_IsUnicode%" ? "Unicode" : "ANSI"
;@Ahk2Exe-ExeName %A_ScriptName~\.[^\.]+$%_%U_type%_%U_bits%

Let

创建(或修改) 一个或多个用户变量, 这些变量可以通过 %U_Name% 来访问, 类似于内置变量(见上文).

;@Ahk2Exe-Let Name = Value , Name = Value, ...
Name
变量的名称(带或不带前缀 U_).
Value
要使用的值.

Nop

什么也不做.

;@Ahk2Exe-Nop Text
Text
(可选) 任何文本, 会被忽略.
示例:
Ver := A_AhkVersion "" ; 如果加引号的原义文字不为空, 执行 'SetVersion'
;@Ahk2Exe-Obey U_V, = "%A_PriorLine~U)^(.+")(.*)".*$~$2%" ? "SetVersion" : "Nop"
;@Ahk2Exe-%U_V%        %A_AhkVersion%%A_PriorLine~U)^(.+")(.*)".*$~$2%

Obey

执行独立于 AutoHotkey 的命令或表达式, 结果为 U_Name.

;@Ahk2Exe-Obey Name, CmdOrExp , Extra
Name
要接收结果的变量名称(带或不带前缀 U_).
CmdOrExp

要执行的命令或表达式.

Command 格式必须使用 Name 作为输出变量(通常是第一个参数), 例如

;@Ahk2Exe-Obey U_date, FormatTime U_date`, R D2 T2

Expression 格式必须以 = 开头, 例如

;@Ahk2Exe-Obey U_type, = "%A_IsUnicode%" ? "Unicode" : "ANSI"

表达式可以用命令格式来写, 例如

;@Ahk2Exe-Obey U_bits, U_bits := %A_PtrSize% * 8

如果需要, 用 `n 分隔多个命令和表达式.

Extra
(可选) 数字(1-9) 指定要返回的额外结果的数量. 例如, 如果 extra = 2, 结果将以 U_name, U_name1 和 U_name2 的形式返回. names 中的值必须先由表达式或命令设置.

PostExec

指定在编译成功后, 在任何压缩程序应用于 .exe 文件之前(或之后) 要执行的程序. 该指令可以多次出现, 并将按照编译器遇到的顺序, 在由 When 参数指定的适当队列中执行.

;@Ahk2Exe-PostExec Program [parameters] , When, WorkingDir, Hidden, IgnoreErrors
Program [parameters]
要执行的程序, 加上参数. 要允许访问已处理的 .exe 文件, 请指定特殊变量 A_WorkFileName 作为加引号的参数, 如 "%A_WorkFileName%". 如果程序更改了 .exe, 则必须将更改的 .exe 移回程序指定的输入文件 %A_WorkFileName%. (注意, .exe 将包含二进制数据.)
When

(可选) 在执行任何压缩之前运行, 则置空. 否则设置为压缩后运行的数字如下:

  • 0 - 仅在没有指定压缩时运行.
  • 1 - 仅在指定 MPRESS 压缩时运行.
  • 2 - 仅在指定 UPX 压缩时运行.
WorkingDir
(可选) 程序的工作目录. 即使包含空格, 也不要用双引号括起来. 如果省略, 将使用编译器的目录(Ahk2Exe).
Hidden
(可选) 如果设置为 1, 程序将被隐藏启动.
IgnoreErrors
(可选) 如果设置为 1, 则不会向用户报告程序启动或运行过程中发生的任何错误.

示例 1: (要使用前两个例子, 首先要下载 BinMod.ahk 并根据下载的脚本中的说明进行编译.)

这个例子可以用来删除生成的 .exe 文件中对 "AutoHotkey" 的引用, 以掩盖它是一个编译过的 AutoHotkey 脚本:

;@Ahk2Exe-Obey U_au, = "%A_IsUnicode%" ? 2 : 1    ; Script ANSI or Unicode?
;@Ahk2Exe-PostExec "BinMod.exe" "%A_WorkFileName%"
;@Ahk2Exe-Cont  "%U_au%2.>AUTOHOTKEY SCRIPT<. DATA              "

示例 2: 这个例子将改变一个 UPX 压缩的 .exe 文件, 使它不能用 UPX -d 来解压:

;@Ahk2Exe-PostExec "BinMod.exe" "%A_WorkFileName%"
;@Ahk2Exe-Cont  "11.UPX." "1.UPX!.", 2

(BinMod.ahk 脚本中还有一些其他的例子.)

示例 3: 如果在 CLI 或 GUI 中没有指定压缩, 则此示例指定要在在编译脚本上使用的压缩程序. 编译器通常使用的默认参数如下所示.

对于 MPRESS:

;@Ahk2Exe-PostExec "MPRESS.exe" "%A_WorkFileName%" -q -x, 0,, 1

对于 UPX:

;@Ahk2Exe-PostExec "UPX.exe" "%A_WorkFileName%"
;@Ahk2Exe-Cont  -q --all-methods --compress-icons=0, 0,, 1

ResourceID

指定一个非标准的资源 ID, 用于使用 .exe 基文件编译的主脚本(请参阅嵌入脚本). 这个指令可以被 GUI 或 CLI 中指定的资源 ID 所覆盖. 如果该指令出现在由 AddResource 指令插入的脚本中, 则会被忽略.

;@Ahk2Exe-ResourceID Name
Name
要使用的资源 ID. 数字资源 ID 应该由一个哈希符号(#) 和一个十进制数字组成.

SetMainIcon

覆盖用于编译的自定义 EXE 图标. (要改变其他图标, 请参阅 AddResource 的示例.) 这个指令可以被 GUI 或 CLI 中指定的图标文件覆盖. 如果编译文件之前存在一个不同的图标, 新图标可能不会立即在 Windows 资源管理器中可见, 但是可以通过从 Ahk2Exe 的 File 菜单中选择 Refresh Windows Icons 来显示新图标.

;@Ahk2Exe-SetMainIcon IcoFile
IcoFile
(可选) 要使用的图标文件. 如果省略, 则使用默认的 AutoHotkey 图标.

SetProp

更改已编译可执行文件的版本信息中的属性. 注意, 无论指定属性的顺序如何, 所有属性都按字母顺序处理.

;@Ahk2Exe-SetProp Value
Prop

要更改的属性的名称. 必须是下列名单之一.

属性 | 描述
CompanyName | 更改公司名称.
Copyright | 更改法定版权信息.
Description | 更改文件说明. 在 Windows 8 及以上版本中, 这也会改变任务管理器中 "Processes" 下的脚本名称.
FileVersion | 更改文件版本, 包括文本和原始二进制格式. (有关详情, 请参阅下面的 Version.)
InternalName | 更改内部名称.
Language | 更改语言代码. 请注意, 十六进制数字必须有 0x 前缀.
LegalTrademarks | 更改合法商标信息.
Name | 更改产品名称和内部名称.
OrigFilename | 更改原始文件名信息.
ProductName | 更改产品名称.
ProductVersion | 更改产品版本, 包括文本和原始二进制格式. (有关详情, 请参阅下面的 Version.)
Version

更改文件版本和产品版本, 包括文本和原始二进制格式.

Ahk2Exe 用可能出现在版本文本开头的以周期限定的数字(最多 4 个) 填充二进制版本字段. 未填写的字段被设置为零. 例如, 1.3-alpha 会产生 1.3.0.0 的二进制版本号. 如果这个属性没有被修改, 它默认为用于编译脚本的 AutoHotkey 版本.
Value
要设置属性的值.

Set

改变 SetProp 指令未覆盖的编译后的可执行文件版本信息中的其他杂项属性. 请注意, 所有的属性都是按字母顺序处理的, 而不考虑它们被指定的顺序. 此指令仅用于特殊用途.

;@Ahk2Exe-Set Prop, Value
Prop
要更改的属性名称.
Value
属性将设置的值.

UpdateManifest

更改 .exe 清单中的详细信息. 此指令仅供特殊用途.

;@Ahk2Exe-UpdateManifest RequireAdmin , Name, Version, UIAccess
RequireAdmin
设置为 1, 可执行文件运行时需要管理员权限. 设置为 2, 可执行文件运行时请求最高可用权限. 设置为 0, 则保持不变.
Name
(可选) 要在清单中设置的名称.
Version
(可选) 要在清单中设置的版本.
UIAccess
(可选) 设置为 1, 使清单中的 UIAccess 为 true.

UseResourceLang

更改 AddResource 使用的资源语言. 这条指令是位置性的, 会影响它后面所有的 AddResource 指令.

;@Ahk2Exe-UseResourceLang LangCode
LangCode
语言代码. 请注意, 十六进制数字必须带有 0x 前缀. 默认的资源语言是美国英语(0x0409).


CLSID List (Windows Class Identifiers) | AutoHotkey v2

CLSID List (Windows Class Identifiers)

操作系统中某些特殊的文件夹使用唯一的字符串进行标识. 这些字符串的其中一些可以用在 DirSelect. 例如:

DirSelect("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}")  ; 在此电脑(以前是我的电脑或计算机) 中选择文件夹.

要通过 Run, 打开 CLSID, 只需将 CLSID 指定为第一个参数即可. 下表中的大多数 CLSID 都可以通过 Run "shell:CLSID" 来打开. 有些可以不使用 shell: 前缀来打开. 例如:

Run "shell:::{D20EA4E1-3957-11D2-A40B-0C5020524153}"  ; Windows Tools.
Run "::{21EC2020-3AEA-1069-A2DD-08002B30309D}"  ; All Control Panel Items.
Run "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"  ; 此电脑(以前是我的电脑或计算机).
Run "::{645FF040-5081-101B-9F08-00AA002F954E}"  ; 回收站.
Run "::{450D8FBA-AD25-11D0-98A8-0800361B1103}\My Folder"  ; Opens a folder that exists inside My Documents.
Run A_MyDocuments "\My Folder"  ; Same as the above on most systems.

CLSID 的可用性和功能因当前操作系统, 安装的应用程序和使用的命令而异. 可用性一栏表示 CLSID 可用于的操作系统版本范围(XP, Vista, 7, 8, 10, 11). 其他 CLSID 可在 HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID 注册表中找到.

默认情况下, 该表按 CLSID 升序排序. 要按其他列或其他顺序排序, 请单击列标题.

CLSID | Location | Availability
::{00020D75-0000-0000-C000-000000000046} | Inbox (Outlook) | XP-11
::{00028B00-0000-0000-C000-000000000046} | Microsoft Network | XP
::{00C6D95F-329C-409A-81D7-C46C66EA7F33} | Default Location | 7
::{0142E4D0-FB7A-11DC-BA4A-000FFE7AB428} | Biometric Devices | 7
::{018D5C66-4533-4307-9B53-224DE2ED1FE6} | OneDrive | 10-11
::{025A5937-A6BE-4686-A844-36FE4BEC8B6D} | Power Options | Vista-11
::{031E4825-7B94-4DC3-B131-E946B44C8DD5} | Libraries | 7-11
::{04731B67-D933-450A-90E6-4ACD2E9408FE} | Desktop in Favorites | Vista-11
::{05D7B0F4-2121-4EFF-BF6B-ED3F69B894D9} | Notification Area Icons (append \SystemIcons for System Icons) | 7-10
::{088E3905-0323-4B02-9826-5D99428E115F} | Downloads | 10-11
::{0907616E-F5E6-48D8-9D61-A91C3D28106D} | Hyper-V Remote File Browsing | 10-11
::{0DB7E03F-FC29-4DC6-9020-FF41B59E513A} | 3D Objects | 10
::{0DF44EAA-FF21-4412-828E-260A8728E7F1} | Taskbar Settings | XP-11
::{1206F5F1-0569-412C-8FEC-3204630DFB70} | Credential Manager | 7-11
::{15EAE92E-F17A-4431-9F28-805E482DAFD4} | Get Programs | Vista-11
::{17CD9488-1228-4B2F-88CE-4298E93E0966} | Default Programs Default Apps | Vista-11
::{1CF1260C-4DD0-4EBB-811F-33C572699FDE} | Music | 7-11
::{1F3427C8-5C10-4210-AA03-2EE45287D668} | User Pinned | 7-11
::{1F4DE370-D627-11D1-BA4F-00A0C91EEDBA} | Network Computers | XP
::{1FA9085F-25A2-489B-85D4-86326EEDCD87} | Manage Wireless Networks | Vista-7
::{208D2C60-3AEA-1069-A2D7-08002B30309D} | My Network Places | XP-11
::{20D04FE0-3AEA-1069-A2D8-08002B30309D} | 我的电脑 计算机 此电脑 | XP-11
::{21EC2020-3AEA-1069-A2DD-08002B30309D} | 控制面板 All Control Panel Items | XP-11
::{2227A280-3AEA-1069-A2DE-08002B30309D} | Printers and Faxes | XP-11
::{22877A6D-37A1-461A-91B0-DBDA5AAEBC99} | Recent Places Recent Folders | Vista-11
::{241D7C96-F8BF-4F85-B01F-E2B043341A4B} | RemoteApp and Desktop Connections | 7-11
::{24AD3AD4-A569-4530-98E1-AB02F9417AA8} | Pictures | 10-11
::{2559A1F0-21D7-11D4-BDAF-00C04F60B9F0} | Search | XP-10
::{2559A1F3-21D7-11D4-BDAF-00C04F60B9F0} | Run | XP-11
::{2559A1F5-21D7-11D4-BDAF-00C04F60B9F0} | E-mail | XP-11
::{2559A1F7-21D7-11D4-BDAF-00C04F60B9F0} | Set Program Access and Defaults | XP-11
::{2559A1F8-21D7-11D4-BDAF-00C04F60B9F0} | Search (Modern) | 8-11
::{26EE0668-A00A-44D7-9371-BEB064C98683} | Control Panel (Category view) | Vista-11
::{28803F59-3A75-4058-995F-4EE5503B023C} | Bluetooth Devices | Vista-11
::{289AF617-1CC3-42A6-926C-E6A863F0E3BA} | Media Servers | 8-11
::{2965E715-EB66-4719-B53F-1672673BBEFA} | Results Folder | Vista-11
::{2E9E59C0-B437-4981-A647-9C34B9B90891} | Sync Setup Folder | Vista-11
::{3080F90D-D7AD-11D9-BD98-0000947B0257} | Show Desktop | Vista-11
::{3080F90E-D7AD-11D9-BD98-0000947B0257} | Window Switcher | Vista-11
::{323CA680-C24D-4099-B94D-446DD2D7249E} | Favorites | 7-11
::{35786D3C-B075-49B9-88DD-029876E11C01} | Portable Devices | 7-11
::{36EEF7DB-88AD-4E81-AD49-0E313F0C35F8} | Windows Update | Vista-8
::{374DE290-123F-4565-9164-39C4925E467B} | Downloads | 8-11
::{37EFD44D-EF8D-41B1-940D-96973A50E9E0} | Windows Sidebar Properties Desktop Gadgets | Vista-8
::{38A98528-6CBF-4CA9-8DC0-B1E1D10F7B1B} | Connected To | Vista-8
::{3936E9E4-D92C-4EEE-A85A-BC16D5EA0819} | Frequent Folders | 10-11
::{3ADD1653-EB32-4CB0-BBD7-DFA0ABB5ACCA} | Pictures | 8-11
::{3DFDF296-DBEC-4FB4-81D1-6A3438BCF4DE} | Music | 10-11
::{3F6BC534-DFA1-4AB4-AE54-EF25A74E0107} | System Restore | Vista-10
::{4026492F-2F69-46B8-B9BF-5654FC07E423} | Windows Firewall | Vista-10
::{40419485-C444-4567-851A-2DD7BFA1684D} | Phone and Modem | 7-11
::{4234D49B-0245-4DF3-B780-3893943456E1} | Applications | 8-11
::{4336A54D-038B-4685-AB02-99BB52D3FB8B} | Public Folder | Vista-11
::{437FF9C0-A07F-4FA0-AF80-84B6C6440A16} | Command Folder | Vista-11
::{450D8FBA-AD25-11D0-98A8-0800361B1103} | My Documents | XP-11
::{48E7CAAB-B918-4E58-A94D-505519C795DC} | Start Menu Folder | XP-Vista
::{5224F545-A443-4859-BA23-7B5A95BDC8EF} | People Near Me | Vista-7
::{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0} | Control Panel | Vista-11
::{58E3C745-D971-4081-9034-86E34B30836A} | Speech Recognition | Vista-11
::{59031A47-3F72-44A7-89C5-5595FE6B30EE} | User Folder | Vista-11
::{5EA4F148-308C-46D7-98A9-49041B1DD468} | Mobility Center | Vista-11
::{60632754-C523-4B62-B45C-4172DA012619} | User Accounts | Vista-11
::{62D8ED13-C9D0-4CE8-A914-47DD628FB1B0} | Region and Language | 7-11
::{645FF040-5081-101B-9F08-00AA002F954E} | Recycle Bin | XP-11
::{67718415-C450-4F3C-BF8A-B487642DC39B} | Windows Features | Vista-10
::{679F85CB-0220-4080-B29B-5540CC05AAB6} | Quick access | 10-11
::{67CA7650-96E6-4FDD-BB43-A8E774F73A57} | HomeGroup | 7-11
::{6C8EEC18-8D75-41B2-A177-8831D59D2D50} | Mouse Properties | 7-11
::{6DFD7C5C-2451-11D3-A299-00C04F8EF6AF} | Folder Options | XP-11
::{7007ACC7-3202-11D1-AAD2-00805FC1270E} | Network Connections | XP-11
::{725BE8F7-668E-4C7B-8F90-46BDB0936430} | Keyboard Properties | 7-11
::{74246BFC-4C96-11D0-ABEF-0020AF6B0B7A} | Device Manager | Vista-11
::{78CB147A-98EA-4AA6-B0DF-C8681F69341C} | Windows Cardspace | Vista-7
::{78F3955E-3B90-4184-BD14-5397C15F1EFC} | Performance Information and Tools | Vista-7
::{7A9D77BD-5403-11D2-8785-2E0420524153} | User Accounts (netplwiz) | XP-11
::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5} | Programs and Features | Vista-11
::{7BD29E00-76C1-11CF-9DD0-00A0C9034933} | Temporary Internet Files | XP
::{7BE9D83C-A729-4D97-B5A7-1B7313C39E0A} | Programs Folder | XP-8
::{80F3F1D5-FECA-45F3-BC32-752C152E456E} | Tablet PC Settings | 7-10
::{85BBD920-42A0-1069-A2E4-08002B30309D} | Briefcase | XP
::{863AA9FD-42DF-457B-8E4D-0DE1B8015C60} | Printers | 7-11
::{871C5380-42A0-1069-A2EA-08002B30309D} | Internet Explorer | XP-10
::{87D66A43-7B11-4A28-9811-C86EE395ACF7} | Indexing Options | 7-11
::{8E908FC9-BECC-40F6-915B-F4CA0E70D03D} | Network and Sharing Center | Vista-11
::{93412589-74D4-4E4E-AD0E-E0CB621440FD} | Font Settings | 7-11
::{9343812E-1C37-4A49-A12E-4B2D810D956B} | Search Results | Vista-10
::{96AE8D84-A250-4520-95A5-A47A7E3C548B} | Parental Controls | 7-8
::{992CFFA0-F557-101A-88EC-00DD010CCC48} | Network Connections | XP-11
::{9C60DE1E-E5FC-40F4-A487-460851A8D915} | AutoPlay | Vista-11
::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF} | Sync Center | Vista-11
::{9FE63AFD-59CF-4419-9775-ABCC3849F861} | Recovery | 7-10
::{A0275511-0E86-4ECA-97C2-ECD8F1221D08} | Infrared | 7-10
::{A0953C92-50DC-43BF-BE83-3742FED03C9C} | Videos | 8-11
::{A304259D-52B8-4526-8B1A-A1D6CECC8243} | iSCCI Initiator | Vista-11
::{A3DD4F92-658A-410F-84FD-6FBBBEF2FFFE} | Internet Options | 7-11
::{A6482830-08EB-41E2-84C1-73920C2BADB9} | Removable Storage Devices | 8-11
::{A8A91A66-3A7D-4424-8D24-04E180695C7A} | Devices and Printers | 7-11
::{A8CDFF1C-4878-43BE-B5FD-F8091C1C60D0} | Documents | 8-11
::{AFDB1F70-2A4C-11D2-9039-00C04F8EEB3E} | Offline Files Folder | XP-10
::{B155BDF8-02F0-451E-9A26-AE317CFD7779} | delegate folder that appears in Computer | Vista-10
::{B2C761C6-29BC-4F19-9251-E6195265BAF1} | Color Management | Vista-11
::{B4BFCC3A-DB2C-424C-B029-7FE99A87C641} | Desktop | 8-11
::{B4FB3F98-C1EA-428D-A78A-D1F5659CBA93} | Other Users Folder Media Streaming Options | 7-11
::{B98A2BEA-7D42-4558-8BD1-832F41BAC6FD} | Backup and Restore | Vista-7
::{BB06C0E4-D293-4F75-8A90-CB05B6477EEE} | System | Vista-11
::{BB64F8A7-BEE7-4E1A-AB8D-7D8273F7FDB6} | Action Center Security and Maintenance (append \pageSettings for Problem Reporting Settings) | 7-11
::{BD84B380-8CA2-1069-AB1D-08000948F534} | Fonts | XP-11
::{BDEADF00-C265-11D0-BCED-00A0C90AB50F} | Web Folders | XP
::{BE122A0E-4503-11DA-8BDE-F66BAD1E3F3A} | Windows Anytime Upgrade | Vista-8
::{C555438B-3C23-4769-A71F-B6D3D9B6053A} | Display (DPI) | 7-8
::{C58C4893-3BE0-4B45-ABB5-A63E4B8C8651} | Troubleshooting | 7-10
::{CB1B7F8C-C50A-4176-B604-9E24DEE8D4D1} | Welcome Center Getting Started | Vista-7
::{D17D1D6D-CC3F-4815-8FE3-607E7D5D10B3} | Text to Speech | 7-11
::{D20EA4E1-3957-11D2-A40B-0C5020524152} | Fonts | XP-Vista
::{D20EA4E1-3957-11D2-A40B-0C5020524153} | Administrative Tools Windows Tools | XP-11
::{D3162B92-9365-467A-956B-92703ACA08AF} | Documents | 10-11
::{D34A6CA6-62C2-4C34-8A7C-14709C1AD938} | Common Places FS Folder | Vista-11
::{D4480A50-BA28-11D1-8E75-00C04FA31A86} | Add Network Place | XP-11
::{D450A8A1-9568-45C7-9C0E-B4F9FB4537BD} | Installed Updates | Vista-11
::{D555645E-D4F8-4C29-A827-D93C859C4F2A} | Ease of Access Center | Vista-11
::{D6277990-4C6A-11CF-8D87-00AA0060F5BF} | Scheduled Tasks | XP
::{D8559EB9-20C0-410E-BEDA-7ED416AECC2A} | Windows Defender | Vista-8
::{D9EF8727-CAC2-4E60-809E-86F80A666C91} | BitLocker Drive Encryption | Vista-10
::{E211B736-43FD-11D1-9EFB-0000F8757FCD} | Scanners and Cameras | XP
::{E2E7934B-DCE5-43C4-9576-7FE4F75E7480} | Date and Time | 7-11
::{E44E5D18-0652-4508-A4E2-8A090067BCB0} | Default Programs Default Apps | Vista-11
::{E7DE9B1A-7533-4556-9484-B26FB486475E} | Network Map | Vista-7
::{E95A4861-D57A-4BE1-AD0F-35267E261739} | Windows SideShow | Vista-7
::{E9950154-C418-419E-A90A-20C5287AE24B} | Location and Other Sensors Location Settings | 7-10
::{ECDB0924-4208-451E-8EE0-373C0956DE16} | Work Folders | 8-10
::{ED228FDF-9EA8-4870-83B1-96B02CFE0D52} | Games Explorer | Vista-10
::{ED50FC29-B964-48A9-AFB3-15EBB9B97F36} | printhood delegate folder | Vista-10
::{ED7BA470-8E54-465E-825C-99712043E01C} | All Tasks (God Mode) | Vista-11
::{ED834ED6-4B5A-4BFE-8F11-A626DCB6A921} | Personalization | Vista-10
::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C} | Network | Vista-11
::{F2DDFC82-8F12-4CDD-B7DC-D4FE1425AA4D} | Sound | 7-11
::{F6B6E965-E9B2-444B-9286-10C9152EDBC5} | File History | 8-10
::{F82DF8F7-8B9F-442E-A48C-818EA735FF9B} | Pen and Touch | 7-10
::{F86FA3AB-70D2-4FC7-9C99-FCBF05467F3A} | Videos | 10-11
::{F8C2AB3B-17BC-41DA-9758-339D7DBF2D88} | Previous Versions Results Folder | 7-11
::{F942C606-0914-47AB-BE56-1321B8035096} | Storage Spaces | 8-10
::{FF393560-C2A7-11CF-BFF4-444553540000} | History | XP


颜色名称列表 | AutoHotkey v2

颜色名称和 RGB 值

颜色名称 | RGB 值
黑色 | 000000
银色 | C0C0C0
灰色 | 808080
白色 | FFFFFF
栗色 | 800000
红色 | FF0000
紫色 | 800080
紫红色 | FF00FF
绿色 | 008000
绿黄色 | 00FF00
橄榄色 | 808000
黄色 | FFFF00
深蓝色 | 000080
蓝色 | 0000FF
青色 | 008080
浅绿色 | 00FFFF


DPI 缩放 | AutoHotkey v2

DPI 缩放

DPI 缩放是一种由操作系统或应用程序执行的功能, 用于根据显示器的 "每英寸点数" 设置以增加内容的可视大小. 一般来说, 它允许内容在具有不同显示分辨率的系统上以相同的物理大小显示, 或者至少可以在非常高分辨率的显示器上使用. 有时, 用户可能会增加 DPI 设置, 只是为了使内容更大, 阅读更舒服.

A_ScreenDPI 通常返回脚本启动时主显示器的 DPI 设置. 这就是所谓的 "系统 DPI", 尽管在不同时间启动的进程可以有不同的值.

有两种类型的 DPI 缩放与 AutoHotkey 相关: Gui DPI 缩放和系统 DPI 缩放.

Gui DPI 缩放

默认情况下, 自动缩放由 Gui 和 GuiControl 方法/属性执行, 因此具有硬编码位置, 大小和边距的 Gui 脚本将在高 DPI 屏幕上根据需要进行缩放. 如果这干扰了脚本, 或者脚本将自己进行缩放, 那么可以禁用自动缩放. 有关详情, 请参阅 -DPIScale 选项.

系统 DPI 缩放

对于不支持 dpi 的应用程序, 操作系统会自动缩放传递给某些系统函数和从某些系统函数返回的坐标. 这种类型的缩放通常在两种情况下影响 AutoHotkey:

  • 具有多个监视器的系统, 其中并非所有监视器都设置为相同的缩放比例.
  • 每当显示缩放设置不同于程序启动时.

所完成的精确缩放取决于正在调用的系统函数, 脚本的 DPI 感知以及目标窗口的潜在 DPI 感知.

每台监视器 DPI 感知

在 Windows 8.1 和更高版本中, 副屏幕可以有不同的 DPI 设置, "每监视器 DPI-感知" 应用程序可以根据它们当前所处屏幕的 DPI 来缩放它们的窗口, 当窗口在屏幕之间移动时动态调整.

对于不支持感知每个监视器 DPI 的应用程序, 系统执行位图缩放, 以允许窗口在屏幕之间移动时改变大小. 并通过报告缩放到应用程序预期的全局 DPI 设置的坐标和大小来向应用程序隐藏这一点. 例如, 在一个 11 英寸的 4K 屏幕上, 一个设计成 96 dpi(100 %) 显示的 GUI 几乎不可能使用，而将其放大 200 % 就可以使用了.

AutoHotkey v2.0 不是设计来执行每监视器缩放的, 因此没有被标记为每监视器 DPI 感知的. 这是一个好处, 例如, 当在一个 100 % DPI 的外部大屏幕和一个 200 % DPI 的小屏幕之间移动一个 GUI 窗口时. 然而, 自动缩放确实有负面影响.

为了使系统的自动缩放工作, 系统函数如 MoveWindow 和 GetWindowRect 会自动缩放它们接受或返回的坐标. 当 AutoHotkey 使用这些函数处理外部窗口时, 如果坐标不在主屏幕上, 这通常会产生意外的结果. 更加令人困惑的是, 一些函数根据脚本最后一个活动窗口显示在哪个屏幕上来缩放坐标.

解决办法

在 Windows 10 1607 及更高版本中, 可以使用 SetThreadDpiAwarenessContext 系统函数在运行时更改程序的 DPI 感知设置. 例如, 启用每监视器 DPI 感知将禁用系统执行的缩放, 因此诸如 WinMove 和 WinGetPos 之类的命令将接受或返回像素坐标, 不受 DPI 缩放的影响. 然而, 如果一个 GUI 的大小适合于 100 % DPI 的屏幕, 然后移动到 200 % DPI 的屏幕, 它将不会自动调整, 并且可能会非常难以使用.

要启用每个监视器的 DPI 感知, 请在使用通常受 DPI 缩放影响的函数之前调用以下函数:

DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr")

在 Windows 10 1703 及更高版本中, 可以使用 -4 替换 -3 以启用 "Per Monitor v2" 模式. 样就可以缩放对话框, 菜单, 工具提示和其他一些东西. 然而, 它也会导致非客户端区域(标题栏) 的缩放, 这可能会导致窗口的客户端区域太小, 除非脚本被设计为对此进行调整(例如通过响应 WM_DPICHANGED 消息). 可以在创建 GUI 之前将上下文设置为 -3, 而在创建任何工具提示, 菜单或对话框之前将上下文设置为 -4 来避免这种情况.

新线程

当系统调用窗口的窗口过程时, 它会自动将当前DPI感知上下文设置为创建窗口时正在使用的上下文. 因此, 新脚本线程的上下文取决于它是直接从 AutoHotkey 的消息循环启动还是通过窗口过程启动.

  • 在典型的情况下, 发布的消息直接从 AutoHotkey 的消息循环处理, 这意味着任何上下文已经生效并仍然有效. 这包括大多数启动新脚本线程的事件, 如热键, 热字串和计时器.
  • 与发送(非发布) 消息相对应的脚本线程是从窗口过程中启动的, 这意味着上下文始终是基于目标窗口设置的.
  • 如果在模态消息循环期间接收到已发布的消息, 则通常将其分派给窗口过程. 模态消息循环(例如) 用于模态对话框和菜单, 或者在用户移动窗口或执行拖放时使用.
  • 非 GUI 事件与脚本的主窗口相关联, 因此接收程序默认的 DPI 感知上下文. 这通常是在程序的清单中设置的, 但可以被应用程序兼容性设置覆盖.

混合设置

当接收到 WM_DPICHANGED 消息时, 每个监视器的 DPI 感知 GUI 窗口会按预期自动调整. 默认情况下, AutoHotkey v2.0 GUI 窗口不会响应此消息. 如果正确实现这种类型的动态缩放太困难, 一个更简单的替代方法是在创建 GUI 之前立即暂时禁用每个监视器的 DPI 感知. 例如:

; Set the "system DPI aware" mode which is the default in AutoHotkey v2.0:
try dac := DllCall("SetThreadDpiAwarenessContext", 'ptr', -2, 'ptr')
; Create the GUI, which will permanently be "system DPI aware":
MyGui := Gui()
; Restore the previous mode for any subsequent function calls:
IsSet(dac) && DllCall("SetThreadDpiAwarenessContext", 'ptr', dac, 'ptr')

如果操作系统不支持 SetThreadDpiAwarenessContext 或程序已经处于系统 DPI 感知模式, 则额外的行没有作用.

如果只有一些 GUI 控件不能很好地缩放, 系统 DPI 感知(或不支持 DPI 感知) 控件可以托管在每个监视器的 DPI 感知窗口上. 在创建窗口之前必须启用混合托管(需要 Windows 10 1803 版本或更高版本):

; Create a GUI window which can host less-aware child windows:
try dhb := DllCall("SetThreadDpiHostingBehavior", 'int', 1)
MyGui := Gui()
IsSet(dhb) && DllCall("SetThreadDpiHostingBehavior", 'int', dhb)

; Add a "system DPI aware" control:
try dac := DllCall("SetThreadDpiAwarenessContext", 'ptr', -2, 'ptr')
MyListView := MyGui.AddListView()
IsSet(dac) && DllCall("SetThreadDpiAwarenessContext", 'ptr', dac, 'ptr')

编译脚本

通过在编译脚本的清单(一个嵌入式 XML 资源) 中设置 "dpiAware" 和 "dpiAwareness" 元素, 可以在整个流程范围内启用每个监视器的 DPI 感知. 有关这些设置的正确使用和效果的详细信息, 请参阅使用应用程序清单设置默认感知. 例如, AutoHotkey v2.0.19 中的清单包括以下内容:

<v3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"
                 xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
  <dpiAware>true</dpiAware>
  <ws2:longPathAware>true</ws2:longPathAware>
</v3:windowsSettings>

正如 Microsoft 文档中所解释的, 可能需要同时包含 "dpiAware" 和 "dpiAwareness", 它们属于不同的 XML 名称空间. 因为 "longPathAware" 和 "dpiAwareness" 属于同一个名称空间, 所以可以通过移动一些东西来优化 XML. 以下启用每个监视器的 DPI 感知(如果可用, 则为 v2, 否则为 v1):

<v3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
  <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
  <dpiAwareness>PerMonitorV2</dpiAwareness>
  <longPathAware>true</longPathAware>
</v3:windowsSettings>

兼容性设置

程序的默认 DPI 感知可以通过兼容性设置来覆盖, 这可以在 AutoHotkey 可执行文件的属性中设置, 在快捷文件的属性中设置, 或者通过设置 __COMPAT_LAYER 环境变量来包含关键字 DpiUnaware 或关键字 HighDpiAware. 使用这种方法启用 DPI 感知可能会产生不必要的影响; 特别是, MsgBox 窗口在屏幕之间移动时可能无法自动调整.


支持 AutoHotkey 的编辑器 | AutoHotkey v2

支持 AutoHotkey 的编辑器

任何文本编辑器都可以用来编辑 AutoHotkey 脚本, 但是能够(或可以配置为) 更容易识别 AutoHotkey 的编辑器往往会使阅读, 编辑和测试脚本变得更容易. 适配 AutoHotkey 的编辑器可以提供:

  • 语法高亮显示, 就像本文档中使用的那样. 通过语法高亮, 单词, 符号和代码段都用颜色编码以表明其含义. 例如, 原义文本, 注释和变量名以不同的颜色显示.
  • 自动完成, 当您开始键入已知函数或变量的名称时, 通常会提供一个建议列表.
  • 在编写调用函数的代码时, 调用提示可以显示该函数的参数.
  • 交互式调试, 例如在 ListVars 允许的范围之外, 逐行检查脚本并在每一步检查变量, 或者查看和修改变量或对象.

推荐:

  • SciTE4AutoHotkey 是一款易于安装, 相对轻量级, 完全支持 AutoHotkey v1 和 v2, 无需进一步配置.
  • VS Code(加上扩展) 提供了更高级别的支持和更广泛的特性, 但可能会占用大量资源.

SciTE4AutoHotkey

SciTE4AutoHotkey 是 SciTE 文本编辑器的自定义版本. 其特性包括:

  • 语法高亮
  • 自动完成
  • 调用提示(也称为智能感应)
  • 智能自动缩进
  • 代码折叠
  • 交互式调试
  • 通过按下热键运行脚本
  • 辅助编写 AutoHotkey 脚本的其他工具

SciTE4AutoHotkey 可从此处下载: https://www.autohotkey.com/scite4ahk/

Visual Studio Code(VS Code)

Visual Studio Code(VS Code) 可以通过安装扩展来配置对 AutoHotkey 的高级支持.

AutoHotkey2 Language Support 提供了许多特性, 包括:

  • 语法高亮
  • 自动完成
  • 调用提示
  • 智能自动缩进
  • 代码折叠
  • 通过热键运行脚本
  • 实时诊断(检测常见错误)
  • 格式化/整理代码

其他说明:

  • 这个扩展只支持 AutoHotkey v2, 但也可以检测 v1 脚本, 并自动切换到 v1 扩展(如果安装了).
  • 这个扩展也可以用于其他编辑器, 例如 vim, neovim 和 Sublime Text 4. 有关详情, 请参阅在其他编辑器中使用. 然而, VS Code likely 可能提供了最好的体验, 最简单的设置.

vscode-autohotkey-debug 提供了对 v1 和 v2 脚本的交互式调试支持.

Notepad4

Notepad4 默认支持 AutoHotkey v2:

  • 语法高亮
  • 自动完成
  • 自动缩进
  • 代码折叠
  • 通过热键运行脚本

可以在这里找到: https://github.com/zufuliu/notepad4

其他编辑器:

其他编辑器: 要获得查找或配置其他编辑器的帮助, 请访问 Editors 子论坛.

要添加编辑器到此页面, 请在建议子论坛发帖或在 GitHub提交 Issue 或拉取请求.


转义序列 - 定义 & 使用 | AutoHotkey v2

转义序列

转义字符 `(反单引号/重音符) 用来表明在紧跟其后的字符不能像平常那样进行解释. 该字符位于大多数英式键盘的左上角. 使用这个字符而不是反斜杠, 以避免在文件路径中需要两个反斜杠.

序列 | 结果
`` | `(原义的重音符; 也就是说, 两个连续的转义字符会产生一个单独的原义字符)
`; | ;(原义的分号) 注意: 当分号的左边有任何字符时(除了 空格或制表符), 没有必要进行转义, 因为它不会被解释为注释.
`: | :(原义的冒号). 这仅在热字串触发缩写中是必要的.
`{ | {(键盘按键). 重映射按键到 { 时才有效, 并且是必需的.
`n | 新行(换行/LF)
`r | 回车(CR)
`b | 退格
`t | tab(制表符, 很典型的水平移位)
`s | 空格
`v | 垂直 tab -- 对应的 Ascii 值为 11. 在一些应用程序中可以通过键入 Ctrl+K 让它显示出来.
`a | 警告(铃) -- 对应的 Ascii 值为 7. 在一些应用程序中可以通过键入 Ctrl+G 让它显示出来.
`f | 进纸 -- 对应的 Ascii 值为 12. 在一些应用程序中可以通过键入 Ctrl+L 让它显示出来.
`" 或 `' | 单引号(') 和双引号(") 所拥有的功能相同, 只是单引号中包含的字符串可以包含原义双引号, 反之亦然. 因此, 要在原义字符串中包含实际的引号, 请转义引号或将字符串用相反类型的引号括起来. 例如: Var := "The color `"red`" was found." 或 Var := 'The color "red" was found.'.

示例

报告一个多行字符串. 各行之间用换行符隔开.

MsgBox "Line 1`nLine 2"


标准 Windows 字体 | AutoHotkey v2

标准 Windows 字体

用于 Gui.SetFont. "开始存在于" 列表示引入该字体的 Windows 版本. 表格中的常见的等宽字体有 Cascadia Mono, Consolas, Courier, Courier New, Fixedsys, Lucida Console 和 Terminal. 某些字体的可用性可能取决于操作系统的语言.

推荐使用黄色高亮显示的字体. 请注意, 这里推荐的字体是自 Windows Vista 或更早版本以来可读和系统已经引入的字体. 使用这种字体可确保在大多数操作系统上显示它们.

默认情况下, 该表按升序的字体名称进行排序. 要按其他列或其他顺序对表格进行排序, 请单击列标题.

字体名称 | 主要设计用于 | 开始存在于
Aharoni | Hebrew | 2000
Aldhabi | Arabic | 8
Andalus | Arabic | 2000
Angsana New | Thai | XP
AngsanaUPC | Thai | XP
Aparajita | Indic | 7
Arabic Typesetting | Arabic | Vista
Arial | Latin, Greek, Cyrillic | 95
Arial Black | Latin, Greek, Cyrillic | 98
Arial Nova | Latin, Greek, Cyrillic | 10
Bahnschrift | Latin | 10
Batang | 韩文 | 2000
BatangChe | 韩文 | Vista
BIZ UDGothic | Japanese | 10
BIZ UDMincho Medium | Japanese | 10
BIZ UDPGothic | Japanese | 10
Browallia New | Thai | 2000
BrowalliaUPC | Thai | 2000
Calibri | Latin, Greek, Cyrillic | Vista
Calibri Light | Latin, Greek, Cyrillic | 8
Cambria | Latin, Greek, Cyrillic | Vista
Cambria Math | 符号 | Vista
Candara | Latin, Greek, Cyrillic | Vista
Cascadia Code | Other | 11
Cascadia Mono | Other | 11
Comic Sans MS | Latin, Greek, Cyrillic | 95
Consolas | Latin, Greek, Cyrillic | Vista
Constantia | Latin, Greek, Cyrillic | Vista
Corbel | Latin, Greek, Cyrillic | Vista
Cordia New | Thai | 2000
CordiaUPC | Thai | 2000
Courier | Latin, Greek, Cyrillic | 95
Courier New | Latin, Greek, Cyrillic | 95
DaunPenh | 其他 | Vista
David | Hebrew | 2000
DengXian(等线) | 中文 | 10
DFKai-SB | 中文 | 2000
DilleniaUPC | Thai | 2000
DokChampa | 其他 | Vista
Dotum | 韩文 | Vista
DotumChe | 韩文 | Vista
Ebrima | African | 7
Estrangelo Edessa | 其他 | XP
EucrosiaUPC | Thai | 2000
Euphemia | 其他 | Vista
FangSong(仿宋) | 中文 | Vista
Fixedsys | Latin | 95
Franklin Gothic Medium | Latin, Greek, Cyrillic | XP
FrankRuehl | Hebrew | 2000
FreesiaUPC | Thai | 2000
Gabriola | Latin, Greek, Cyrillic | 7
Gadugi | 其他 | 8
Gautami | 其他 | XP
Georgia | Latin, Greek, Cyrillic | 2000
Georgia Pro | Latin, Greek, Cyrillic | 10
Gill Sans Nova | Latin, Greek, Cyrillic | 10
Gisha | Hebrew | Vista
Gulim | 韩文 | 2000
GulimChe | 韩文 | Vista
Gungsuh | 韩文 | Vista
GungsuhChe | 韩文 | Vista
HoloLens MDL2 Assets | 符号 | 10
Impact | Latin, Greek, Cyrillic | 98
Ink Free | Other | 10
IrisUPC | Thai | 2000
Iskoola Pota | 其他 | Vista
JasmineUPC | Thai | 2000
Javanese Text | Javanese | 8.1
KaiTi(楷体) | 中文 | 2000
Kalinga | 其他 | Vista
Kartika | 其他 | XP
Khmer UI | 其他 | 7
KodchiangUPC | Thai | 2000
Kokila | 其他 | 7
Lao UI | 其他 | 7
Latha | Indic | XP
Leelawadee | Thai | Vista
Leelawadee UI | Thai | 8.1
Levenim MT | Hebrew | 98
LilyUPC | Thai | 2000
Lucida Console | Latin, Greek, Cyrillic | 98
Lucida Sans | Latin, Greek, Cyrillic | 98
Lucida Sans Unicode | Latin, Greek, Cyrillic | 98
Malgun Gothic | 韩文 | Vista
Mangal | Indic | XP
Marlett | 符号 | 95
Meiryo | 日文 | Vista
Meiryo UI | 日文 | 7
Microsoft Himalaya | 其他 | Vista
Microsoft JhengHei(微软正黑) | 中文 | Vista
Microsoft JhengHei UI | 中文 | 8
Microsoft New Tai Lue | 其他 | 7
Microsoft PhagsPa | 其他 | 7
Microsoft Sans Serif | Latin, Greek, Cyrillic | 2000
Microsoft Tai Le | 其他 | 7
Microsoft Uighur | 其他 | Vista
Microsoft YaHei(微软雅黑) | 中文 | Vista
Microsoft YaHei UI | 中文 | 8
Microsoft Yi Baiti | 其他 | Vista
MingLiU(细明体) | 中文 | Vista
MingLiU_HKSCS | 中文 | Vista
MingLiU_HKSCS-ExtB | 中文 | Vista
MingLiU-ExtB | 中文 | Vista
Miriam | Hebrew | 2000
Miriam Fixed | Hebrew | 2000
Modern | Latin | 95
Mongolian Baiti | 其他 | Vista
MoolBoran | 其他 | Vista
MS Gothic | 日文 | 2000
MS Mincho | 日文 | 2000
MS PGothic | 日文 | Vista
MS PMincho | 日文 | Vista
MS Serif | Latin | 95
MS Sans Serif | Latin | 95
MS UI Gothic | 日文 | Vista
MV Boli | 其他 | XP
Myanmar Text | 其他 | 8
Narkisim | Hebrew | 2000
Neue Haas Grotesk Text Pro | Latin | 10
Nirmala UI | Indic | 8
NSimSun(新宋体) | 中文 | Vista
Nyala | African | Vista
Palatino Linotype | Latin, Greek, Cyrillic | 2000
Plantagenet Cherokee | 其他 | Vista
PMingLiU(新细明体) | 中文 | 2000
PMingLiU-ExtB | 中文 | Vista
Raavi | Indic | XP
Rockwell Nova | Latin, Greek, Cyrillic | 10
Rod | Hebrew | 2000
Roman | Latin | 98
Sakkal Majalla | Arabic | 7
Sanskrit Text | 其他 | 10
Script | Latin | 98
Segoe Fluent Icons | Symbols | 11
Segoe MDL2 Assets | 符号 | 10
Segoe Print | Latin, Greek, Cyrillic | Vista
Segoe Script | Latin, Greek, Cyrillic | Vista
Segoe UI | Latin, Greek, Cyrillic | Vista
Segoe UI Emoji | 符号 | 10
Segoe UI Historic | 其他 | 10
Segoe UI Variable | Other | 11
Segoe UI Symbol | 符号 | 7
Shonar Bangla | Indic | 7
Shruti | Indic | XP
SimHei(黑体) | 中文 | 2000
Simplified Arabic | Arabic | 2000
Simplified Arabic Fixed | Arabic | 2000
SimSun(宋体) | 中文 | 2000
SimSun-ExtB | 中文 | Vista
Sitka Banner | Latin, Greek, Cyrillic | 8.1
Sitka Display | Latin, Greek, Cyrillic | 8.1
Sitka Heading | Latin, Greek, Cyrillic | 8.1
Sitka Small | Latin, Greek, Cyrillic | 8.1
Sitka Subheading | Latin, Greek, Cyrillic | 8.1
Sitka Text | Latin, Greek, Cyrillic | 8.1
Small Fonts | Latin | 95
Sylfaen | 其他 | XP
Symbol | 符号 | 95
System | Latin | 95
Tahoma | Latin, Greek, Cyrillic | 95
Terminal | Latin | 95
Times New Roman | Latin, Greek, Cyrillic | 95
Traditional Arabic | Arabic | 2000
Trebuchet MS | Latin, Greek, Cyrillic | 2000
Tunga | Indic | XP
UD Digi Kyokasho N-B | 日文 | 10
UD Digi Kyokasho NK-B | 日文 | 10
UD Digi Kyokasho NK-R | 日文 | 10
UD Digi Kyokasho NP-B | 日文 | 10
UD Digi Kyokasho NP-R | 日文 | 10
UD Digi Kyokasho N-R | 日文 | 10
Urdu Typesetting | Arabic | 8
Utsaah | Indic | 7
Vani | Indic | 7
Verdana | Latin, Greek, Cyrillic | 95
Verdana Pro | Latin, Greek, Cyrillic | 10
Vijaya | Indic | 7
Vrinda | Indic | XP
Webdings | 符号 | 98
Wingdings | 符号 | 95
Yu Gothic | 日文 | 8.1
Yu Gothic UI | 日文 | 8.1
Yu Mincho | 日文 | 8.1


函数对象 - 定义 & 使用 | AutoHotkey v2

函数对象

"函数对象" 通常表示以下任何一项:

  • Func 或 Closure 对象, 它表示一个实际的函数; 可以是内置函数也可以是脚本定义的函数.
  • 用户定义的对象, 可以像函数一样调用. 亦称为 "函数子".
  • 任何其他可以像函数一样调用的对象, 如绑定函数对象或 COM 方法返回的 JavaScript 函数对象.

函数对象可用于以下情况:

  • CallbackCreate
  • Gui 事件
  • For ... in
  • HotIf
  • Hotkey
  • Hotstring
  • InputHook (OnEnd, OnChar, OnKeyDown, OnKeyUp)
  • Menu.Add
  • OnClipboardChange
  • OnError
  • OnExit
  • OnMessage
  • RegEx callouts
  • SetTimer
  • Sort

要确定一个对象是否可被调用, 请使用以下方法之一:

  • 默认情况下, Value.HasMethod() 适用于所有的 AutoHotkey 值和对象, 但对于某些对象或类, 允许重写 HasMethod. 对于 COM 对象, 这通常会失败(抛出异常或产生错误的结果), 除非该 COM 对象实际上是来自其他进程的 AutoHotkey 对象.
  • HasMethod(Value) 适用于所有的 AutoHotkey 值和对象, 并且不能被重写, 但如果不能确定 Call 方法的存在, 则返回 false. 如果 Value 是 ComObject, 则抛出异常.

用户自定义

用户定义的函数对象必须包含一个 "函数" 实现的 Call 方法定义.

class YourClassName {
    Call(a, b) {  ; 按需声明参数, 或 array*.
        ;...
        return c
    }
    ;...
}

这适用于 YourClassName 的 实例, 例如由 YourClassName() 返回的对象. 用 static Call 代替 Call 将覆盖 YourClassName 本身被调用时的情况.

当函数对象被赋值给属性时, 请记住方法调用语法(target.func()) 隐式地传递目标对象作为第一个参数. 对于上面的 YourClassName, this 是函数对象, 而 a 是目标对象. 可以将用于检索函数对象的表达式包装在括号中以防止这种情况, 如下面的示例所示.

示例

下面的例子定义了一个可以被调用的函数数组; 当被调用时, 它依次调用数组中的每个元素.

class FuncArrayType extends Array {
    Call(params*) {
        ; 调用函数列表.
        for fn in this
            fn(params*)
    }
}

; 创建一个函数数组.
funcArray := FuncArrayType()
; 向数组中添加函数(可以在任何位置完成).
funcArray.Push(One)
funcArray.Push(Two)
; 创建一个使用数组作为方法的对象.
obj := {method: funcArray}
; 调用方法(One 和 Two 都会被调用).
obj.method("2nd")
; 将其作为函数调用.
(obj.method)("1st", "2nd")

One(param1, param2) {
    ListVars
    MsgBox
}
Two(param1, param2) {
    ListVars
    MsgBox
}

绑定函数对象

行为像函数, 但只是将预定义的参数传递给另一个函数.

有两种建立绑定函数对象的方式:

  • 通过调用 Func.Bind 方法, 其绑定参数值至一个函数.
  • 通过调用 ObjBindMethod 函数, 其绑定参数值和方法名至目标对象.

可以调用绑定函数对象, 如下例所示. 当绑定函数对象被调用时, 它调用绑定的函数或方法, 传递绑定的参数和后面跟着的调用者传递的任何参数. 未绑定的参数位置是从调用者的参数列表中指定的位置(从左到右). 例如:

fn := RealFn.Bind(1)  ; 只绑定第一个参数
fn(2)    ; 显示 "1, 2"
fn.Call(3) ; 显示 "1, 3"

fn := RealFn.Bind( , 1)  ; 只绑定第二个参数
fn(2, 0)        ; 显示 "2, 1, 0"
fn.Call(3) ; 显示 "3, 1"
fn(, 4)     ; 错误: 'a' 被省略了

RealFn(a, b, c?) {
    MsgBox a ", " b (IsSet(c) ? ", " c : "")
}

ObjBindMethod 可用于绑定方法, 即使是在无法检索到方法本身的引用时. 例如:

Shell := ComObject("Shell.Application")
RunBox := ObjBindMethod(Shell, "FileRun")
; 显示运行对话框.
RunBox

更多复杂的例子, 请参阅 SetTimer.

其他的属性和方法都是从 Func 继承过来的, 但不反映目标函数或方法的属性(不需要作为一个函数来实现). BoundFunc 作为一个匿名的变量函数, 没有其他形式上的参数, 类似于下面的胖箭头函数:

Func_Bind(fn, bound_args*) {
    return (args*) => (args.InsertAt(1, bound_args*), fn(args*))
}


Image Handles - 语法 & 使用 | AutoHotkey v2

图像句柄

要使用图标或位图句柄代替图像文件名, 请使用以下语法:

HBITMAP:BitmapHandle
HICON:IconHandle

用实际句柄值替换 BitmapHandle 或 IconHandle. 例如, "hicon:" handle, 其中 handle 是包含图标句柄的变量.

以下内容支持此语法:

  • Gui.AddPicture(和设置图片控件的内容时的 GuiControl.Value).
  • IL_Add
  • LoadPicture
  • SB.SetIcon
  • ImageSearch
  • TraySetIcon 或 Menu.SetIcon

位图或图标句柄是一个数字值, 用于标识内存中的位图或图标. 大多数脚本不需要处理句柄, 因为在大多数情况下, AutoHotkey 会从文件中加载图像并在不再需要时释放图像. 上面的语法是当脚本从其他资源中取得图标或位图时(如发送 WM_GETICON 消息到某个窗口) 供脚本使用的. 这也可以和 LoadPicture 一起使用, 以避免多次从文件中加载图像.

默认情况下, AutoHotkey 会将句柄视为从文件中载入图像 - 例如, 销毁 GUI 时会删除 Picture 控件上使用的位图, 并且如果需要调整图像大小, 通常会立即删除该图像. 为避免这种情况, 请在冒号和句柄之间放置一个星号. 例如: "hbitmap:*" handle. 除了 ImageSearch, 这会强制该函数获取图像的副本.

示例

显示与模式匹配的前 n 个文件及其图标的菜单.

pattern := A_ScriptDir "\*"
n := 15

;创建菜单.
Fmenu := Menu()

; 为 SHFILEINFOW 结构体申请内存.
fileinfo := Buffer(fisize := A_PtrSize + 688)

Loop Files, pattern, "FD"
{
    ; 为每个文件添加一个菜单项.
    Fmenu.Add(A_LoopFileName, (*) => "") ; 什么也不做.

    ; 获取文件的图标.
    if DllCall("shell32\SHGetFileInfoW", "WStr", A_LoopFileFullPath
        , "UInt", 0, "Ptr", fileinfo, "UInt", fisize, "UInt", 0x100)
    {
        hicon := NumGet(fileinfo, 0, "Ptr")
        ; 设置菜单项的图标.
        Fmenu.SetIcon A_Index("&", "HICON:" hicon)
        ; 因为我们使用了 ":" 而不是 ":*", 在程序退出或菜单被删除时
        ; 这些图标也会被自动释放.
    }
}
until A_Index = n
Fmenu.Show()

另请参阅: LoadPicture 的示例 #1.


标签 - 语法 & 使用 | AutoHotkey v2

标签

目录

  • 语法和用法
  • 类标签
  • 动态标签
  • 命名的循环
  • 相关的

语法和用法

标签用来标识代码行, 可以作为 Goto 的目标或指定一个循环来跳出或继续. 标签由名称和冒号(:) 组成.

this_is_a_label:

除了空格和注释外, 其他代码不能和标签写在同一行.

名称: 标签名不区分大小写, 且可以由除空格, tab, 逗号以及转义字符(`) 外的其他字符组成. 然而, 考虑到命名的惯例, 通常最好仅使用字母, 数字和下划线(例如: MyListView, Menu_File_Open 和 outer_loop).

作用域: 每个函数都有自己的局部标签列表. 在一个函数内部, 只有该函数的标签对脚本可见/可及.

目标: 标签的目标是下一个可执行的代码行. 可执行代码包含函数, 赋值, 表达式和区块, 但不包括指令, 标签, 热键或热字串. 在下面的例子中, run_notepad_1 和 run_notepad_2 标签都指向 Run 行:

run_notepad_1:
run_notepad_2:
    Run "notepad"
    return

执行: 与指令类似, 正常执行到标签时标签会被忽略.

类标签

热键和热字串定义看起来类似于标签, 但不是标签.

热键由热键和双冒号组成.

^a::

热字串由一个冒号, 零或多个选项, 另一个冒号, 一个缩写和双冒号组成.

:*:btw::

动态标签

在某些情况下, 可以用变量代替标签名. 在这种情况下, 存储在变量中的名称被用来定位目标标签. 但是, 性能会稍微降低, 因为每次都必须 "查找" 目标标签名而不是只在脚本首次加载时查找一次.

命名的循环

标签还可以用来标识循环, 以便用于 Continue 和 Break 语句. 这样脚本可以很方便地继续或退出任意数目的内嵌循环.

相关

函数, IsLabel, Goto, Break, Continue


语言代码 | AutoHotkey v2

语言代码

下表包含了与语言代码(也称为本地标识符 LCID) 相关联的语言名称, A_Language 变量的值为其中的某个语言代码. 语言代码自身是第一个逗号左边的最后四位数字. 例如, 如果 A_Language 的值为 0436, 则系统的默认语言为 Afrikaans(南非).

注意: 包含字母的代码可以使用大写或小写.

您可以直接把 A_Language 和下面的一个或多个 4 位代码进行比较; 例如: if (A_Language = "0436"). 或者您可以把整个表粘贴到脚本中, 然后像列表底部演示的那样访问当前语言的名称.

LCID := Map(
  "0036", "Afrikaans",  ; af
  "0436", "Afrikaans (South Africa)",  ; af-ZA
  "001C", "Albanian",  ; sq
  "041C", "Albanian (Albania)",  ; sq-AL
  "0484", "Alsatian (France)",  ; gsw-FR
  "005E", "Amharic",  ; am
  "045E", "Amharic (Ethiopia)",  ; am-ET
  "0001", "Arabic",  ; ar
  "1401", "Arabic (Algeria)",  ; ar-DZ
  "3C01", "Arabic (Bahrain)",  ; ar-BH
  "0C01", "Arabic (Egypt)",  ; ar-EG
  "0801", "Arabic (Iraq)",  ; ar-IQ
  "2C01", "Arabic (Jordan)",  ; ar-JO
  "3401", "Arabic (Kuwait)",  ; ar-KW
  "3001", "Arabic (Lebanon)",  ; ar-LB
  "1001", "Arabic (Libya)",  ; ar-LY
  "1801", "Arabic (Morocco)",  ; ar-MA
  "2001", "Arabic (Oman)",  ; ar-OM
  "4001", "Arabic (Qatar)",  ; ar-QA
  "0401", "Arabic (Saudi Arabia)",  ; ar-SA
  "2801", "Arabic (Syria)",  ; ar-SY
  "1C01", "Arabic (Tunisia)",  ; ar-TN
  "3801", "Arabic (United Arab Emirates)",  ; ar-AE
  "2401", "Arabic (Yemen)",  ; ar-YE
  "002B", "Armenian",  ; hy
  "042B", "Armenian (Armenia)",  ; hy-AM
  "004D", "Assamese",  ; as
  "044D", "Assamese (India)",  ; as-IN
  "002C", "Azerbaijani",  ; az
  "742C", "Azerbaijani (Cyrillic)",  ; az-Cyrl
  "082C", "Azerbaijani (Cyrillic, Azerbaijan)",  ; az-Cyrl-AZ
  "782C", "Azerbaijani (Latin)",  ; az-Latn
  "042C", "Azerbaijani (Latin, Azerbaijan)",  ; az-Latn-AZ
  "0045", "Bangla",  ; bn
  "0845", "Bangla (Bangladesh)",  ; bn-BD
  "006D", "Bashkir",  ; ba
  "046D", "Bashkir (Russia)",  ; ba-RU
  "002D", "Basque",  ; eu
  "042D", "Basque (Basque)",  ; eu-ES
  "0023", "Belarusian",  ; be
  "0423", "Belarusian (Belarus)",  ; be-BY
  "0445", "Bengali (India)",  ; bn-IN
  "781A", "Bosnian",  ; bs
  "641A", "Bosnian (Cyrillic)",  ; bs-Cyrl
  "201A", "Bosnian (Cyrillic, Bosnia and Herzegovina)",  ; bs-Cyrl-BA
  "681A", "Bosnian (Latin)",  ; bs-Latn
  "141A", "Bosnian (Latin, Bosnia & Herzegovina)",  ; bs-Latn-BA
  "007E", "Breton",  ; br
  "047E", "Breton (France)",  ; br-FR
  "0002", "Bulgarian",  ; bg
  "0402", "Bulgarian (Bulgaria)",  ; bg-BG
  "0055", "Burmese",  ; my
  "0455", "Burmese (Myanmar)",  ; my-MM
  "0003", "Catalan",  ; ca
  "0403", "Catalan (Catalan)",  ; ca-ES
  "005F", "Central Atlas Tamazight",  ; tzm
  "045F", "Central Atlas Tamazight (Arabic, Morocco)",  ; tzm-Arab-MA
  "7C5F", "Central Atlas Tamazight (Latin)",  ; tzm-Latn
  "085F", "Central Atlas Tamazight (Latin, Algeria)",  ; tzm-Latn-DZ
  "785F", "Central Atlas Tamazight (Tifinagh)",  ; tzm-Tfng
  "105F", "Central Atlas Tamazight (Tifinagh, Morocco)",  ; tzm-Tfng-MA
  "0092", "Central Kurdish",  ; ku
  "7C92", "Central Kurdish",  ; ku-Arab
  "0492", "Central Kurdish (Iraq)",  ; ku-Arab-IQ
  "005C", "Cherokee",  ; chr
  "7C5C", "Cherokee",  ; chr-Cher
  "045C", "Cherokee (Cherokee, United States)",  ; chr-Cher-US
  "7804", "Chinese",  ; zh
  "0004", "Chinese (Simplified)",  ; zh-Hans
  "0804", "Chinese (Simplified, China)",  ; zh-CN
  "1004", "Chinese (Simplified, Singapore)",  ; zh-SG
  "7C04", "Chinese (Traditional)",  ; zh-Hant
  "0C04", "Chinese (Traditional, Hong Kong SAR)",  ; zh-HK
  "1404", "Chinese (Traditional, Macao SAR)",  ; zh-MO
  "0404", "Chinese (Traditional, Taiwan)",  ; zh-TW
  "0083", "Corsican",  ; co
  "0483", "Corsican (France)",  ; co-FR
  "001A", "Croatian",  ; hr
  "101A", "Croatian (Bosnia & Herzegovina)",  ; hr-BA
  "041A", "Croatian (Croatia)",  ; hr-HR
  "0005", "Czech",  ; cs
  "0405", "Czech (Czechia)",  ; cs-CZ
  "0006", "Danish",  ; da
  "0406", "Danish (Denmark)",  ; da-DK
  "0065", "Divehi",  ; dv
  "0465", "Divehi (Maldives)",  ; dv-MV
  "0013", "Dutch",  ; nl
  "0813", "Dutch (Belgium)",  ; nl-BE
  "0413", "Dutch (Netherlands)",  ; nl-NL
  "0C51", "Dzongkha (Bhutan)",  ; dz-BT
  "0066", "Edo",  ; bin
  "0466", "Edo (Nigeria)",  ; bin-NG
  "0009", "English",  ; en
  "0C09", "English (Australia)",  ; en-AU
  "2809", "English (Belize)",  ; en-BZ
  "1009", "English (Canada)",  ; en-CA
  "2409", "English (Caribbean)",  ; en-029
  "3C09", "English (Hong Kong SAR)",  ; en-HK
  "4009", "English (India)",  ; en-IN
  "3809", "English (Indonesia)",  ; en-ID
  "1809", "English (Ireland)",  ; en-IE
  "2009", "English (Jamaica)",  ; en-JM
  "4409", "English (Malaysia)",  ; en-MY
  "1409", "English (New Zealand)",  ; en-NZ
  "3409", "English (Philippines)",  ; en-PH
  "4809", "English (Singapore)",  ; en-SG
  "1C09", "English (South Africa)",  ; en-ZA
  "2C09", "English (Trinidad & Tobago)",  ; en-TT
  "4C09", "English (United Arab Emirates)",  ; en-AE
  "0809", "English (United Kingdom)",  ; en-GB
  "0409", "English (United States)",  ; en-US
  "3009", "English (Zimbabwe)",  ; en-ZW
  "0025", "Estonian",  ; et
  "0425", "Estonian (Estonia)",  ; et-EE
  "0038", "Faroese",  ; fo
  "0438", "Faroese (Faroe Islands)",  ; fo-FO
  "0064", "Filipino",  ; fil
  "0464", "Filipino (Philippines)",  ; fil-PH
  "000B", "Finnish",  ; fi
  "040B", "Finnish (Finland)",  ; fi-FI
  "000C", "French",  ; fr
  "080C", "French (Belgium)",  ; fr-BE
  "2C0C", "French (Cameroon)",  ; fr-CM
  "0C0C", "French (Canada)",  ; fr-CA
  "1C0C", "French (Caribbean)",  ; fr-029
  "300C", "French (Côte d’Ivoire)",  ; fr-CI
  "040C", "French (France)",  ; fr-FR
  "3C0C", "French (Haiti)",  ; fr-HT
  "140C", "French (Luxembourg)",  ; fr-LU
  "340C", "French (Mali)",  ; fr-ML
  "180C", "French (Monaco)",  ; fr-MC
  "380C", "French (Morocco)",  ; fr-MA
  "200C", "French (Réunion)",  ; fr-RE
  "280C", "French (Senegal)",  ; fr-SN
  "100C", "French (Switzerland)",  ; fr-CH
  "240C", "French Congo (DRC)",  ; fr-CD
  "0067", "Fulah",  ; ff
  "7C67", "Fulah (Latin)",  ; ff-Latn
  "0467", "Fulah (Latin, Nigeria)",  ; ff-Latn-NG
  "0867", "Fulah (Latin, Senegal)",  ; ff-Latn-SN
  "0056", "Galician",  ; gl
  "0456", "Galician (Galician)",  ; gl-ES
  "0037", "Georgian",  ; ka
  "0437", "Georgian (Georgia)",  ; ka-GE
  "0007", "German",  ; de
  "0C07", "German (Austria)",  ; de-AT
  "0407", "German (Germany)",  ; de-DE
  "1407", "German (Liechtenstein)",  ; de-LI
  "1007", "German (Luxembourg)",  ; de-LU
  "0807", "German (Switzerland)",  ; de-CH
  "0008", "Greek",  ; el
  "0408", "Greek (Greece)",  ; el-GR
  "0074", "Guarani",  ; gn
  "0474", "Guarani (Paraguay)",  ; gn-PY
  "0047", "Gujarati",  ; gu
  "0447", "Gujarati (India)",  ; gu-IN
  "0068", "Hausa",  ; ha
  "7C68", "Hausa (Latin)",  ; ha-Latn
  "0468", "Hausa (Latin, Nigeria)",  ; ha-Latn-NG
  "0075", "Hawaiian",  ; haw
  "0475", "Hawaiian (United States)",  ; haw-US
  "000D", "Hebrew",  ; he
  "040D", "Hebrew (Israel)",  ; he-IL
  "0039", "Hindi",  ; hi
  "0439", "Hindi (India)",  ; hi-IN
  "000E", "Hungarian",  ; hu
  "040E", "Hungarian (Hungary)",  ; hu-HU
  "0069", "Ibibio",  ; ibb
  "0469", "Ibibio (Nigeria)",  ; ibb-NG
  "000F", "Icelandic",  ; is
  "040F", "Icelandic (Iceland)",  ; is-IS
  "0070", "Igbo",  ; ig
  "0470", "Igbo (Nigeria)",  ; ig-NG
  "0021", "Indonesian",  ; id
  "0421", "Indonesian (Indonesia)",  ; id-ID
  "005D", "Inuktitut",  ; iu
  "7C5D", "Inuktitut (Latin)",  ; iu-Latn
  "085D", "Inuktitut (Latin, Canada)",  ; iu-Latn-CA
  "785D", "Inuktitut (Syllabics)",  ; iu-Cans
  "045D", "Inuktitut (Syllabics, Canada)",  ; iu-Cans-CA
  "003C", "Irish",  ; ga
  "083C", "Irish (Ireland)",  ; ga-IE
  "0034", "isiXhosa",  ; xh
  "0434", "isiXhosa (South Africa)",  ; xh-ZA
  "0035", "isiZulu",  ; zu
  "0435", "isiZulu (South Africa)",  ; zu-ZA
  "0010", "Italian",  ; it
  "0410", "Italian (Italy)",  ; it-IT
  "0810", "Italian (Switzerland)",  ; it-CH
  "0011", "Japanese",  ; ja
  "0411", "Japanese (Japan)",  ; ja-JP
  "006F", "Kalaallisut",  ; kl
  "046F", "Kalaallisut (Greenland)",  ; kl-GL
  "004B", "Kannada",  ; kn
  "044B", "Kannada (India)",  ; kn-IN
  "0071", "Kanuri",  ; kr
  "0471", "Kanuri (Latin, Nigeria)",  ; kr-Latn-NG
  "0060", "Kashmiri",  ; ks
  "0460", "Kashmiri (Arabic)",  ; ks-Arab
  "1000", "Kashmiri (Arabic)",  ; ks-Arab-IN
  "0860", "Kashmiri (Devanagari)",  ; ks-Deva-IN
  "003F", "Kazakh",  ; kk
  "043F", "Kazakh (Kazakhstan)",  ; kk-KZ
  "0053", "Khmer",  ; km
  "0453", "Khmer (Cambodia)",  ; km-KH
  "0087", "Kinyarwanda",  ; rw
  "0487", "Kinyarwanda (Rwanda)",  ; rw-RW
  "0041", "Kiswahili",  ; sw
  "0441", "Kiswahili (Kenya)",  ; sw-KE
  "0057", "Konkani",  ; kok
  "0457", "Konkani (India)",  ; kok-IN
  "0012", "Korean",  ; ko
  "0412", "Korean (Korea)",  ; ko-KR
  "0040", "Kyrgyz",  ; ky
  "0440", "Kyrgyz (Kyrgyzstan)",  ; ky-KG
  "0086", "Kʼicheʼ",  ; quc
  "7C86", "Kʼicheʼ (Latin)",  ; quc-Latn
  "0486", "Kʼicheʼ (Latin, Guatemala)",  ; quc-Latn-GT
  "0054", "Lao",  ; lo
  "0454", "Lao (Laos)",  ; lo-LA
  "0076", "Latin",  ; la
  "0476", "Latin (Vatican City)",  ; la-VA
  "0026", "Latvian",  ; lv
  "0426", "Latvian (Latvia)",  ; lv-LV
  "0027", "Lithuanian",  ; lt
  "0427", "Lithuanian (Lithuania)",  ; lt-LT
  "7C2E", "Lower Sorbian",  ; dsb
  "082E", "Lower Sorbian (Germany)",  ; dsb-DE
  "006E", "Luxembourgish",  ; lb
  "046E", "Luxembourgish (Luxembourg)",  ; lb-LU
  "002F", "Macedonian",  ; mk
  "042F", "Macedonian (North Macedonia)",  ; mk-MK
  "003E", "Malay",  ; ms
  "083E", "Malay (Brunei)",  ; ms-BN
  "043E", "Malay (Malaysia)",  ; ms-MY
  "004C", "Malayalam",  ; ml
  "044C", "Malayalam (India)",  ; ml-IN
  "003A", "Maltese",  ; mt
  "043A", "Maltese (Malta)",  ; mt-MT
  "0058", "Manipuri",  ; mni
  "0458", "Manipuri (Bangla, India)",  ; mni-IN
  "0081", "Maori",  ; mi
  "0481", "Maori (New Zealand)",  ; mi-NZ
  "007A", "Mapuche",  ; arn
  "047A", "Mapuche (Chile)",  ; arn-CL
  "004E", "Marathi",  ; mr
  "044E", "Marathi (India)",  ; mr-IN
  "007C", "Mohawk",  ; moh
  "047C", "Mohawk (Canada)",  ; moh-CA
  "0050", "Mongolian",  ; mn
  "7850", "Mongolian",  ; mn-Cyrl
  "0450", "Mongolian (Mongolia)",  ; mn-MN
  "7C50", "Mongolian (Traditional Mongolian)",  ; mn-Mong
  "0850", "Mongolian (Traditional Mongolian, China)",  ; mn-Mong-CN
  "0C50", "Mongolian (Traditional Mongolian, Mongolia)",  ; mn-Mong-MN
  "0061", "Nepali",  ; ne
  "0861", "Nepali (India)",  ; ne-IN
  "0461", "Nepali (Nepal)",  ; ne-NP
  "003B", "Northern Sami",  ; se
  "0014", "Norwegian",  ; no
  "7C14", "Norwegian Bokmål",  ; nb
  "0414", "Norwegian Bokmål (Norway)",  ; nb-NO
  "7814", "Norwegian Nynorsk",  ; nn
  "0814", "Norwegian Nynorsk (Norway)",  ; nn-NO
  "0082", "Occitan",  ; oc
  "0482", "Occitan (France)",  ; oc-FR
  "0048", "Odia",  ; or
  "0448", "Odia (India)",  ; or-IN
  "0072", "Oromo",  ; om
  "0472", "Oromo (Ethiopia)",  ; om-ET
  "0079", "Papiamento",  ; pap
  "0479", "Papiamento (Caribbean)",  ; pap-029
  "0063", "Pashto",  ; ps
  "0463", "Pashto (Afghanistan)",  ; ps-AF
  "0029", "Persian",  ; fa
  "008C", "Persian",  ; fa
  "048C", "Persian (Afghanistan)",  ; fa-AF
  "0429", "Persian (Iran)",  ; fa-IR
  "0015", "Polish",  ; pl
  "0415", "Polish (Poland)",  ; pl-PL
  "0016", "Portuguese",  ; pt
  "0416", "Portuguese (Brazil)",  ; pt-BR
  "0816", "Portuguese (Portugal)",  ; pt-PT
  "05FE", "Pseudo (Pseudo Asia)",  ; qps-ploca
  "09FF", "Pseudo (Pseudo Mirrored)",  ; qps-plocm
  "0901", "Pseudo (Pseudo Selfhost)",  ; qps-Latn-x-sh
  "0501", "Pseudo (Pseudo)",  ; qps-ploc
  "0046", "Punjabi",  ; pa
  "7C46", "Punjabi",  ; pa-Arab
  "0446", "Punjabi (India)",  ; pa-IN
  "0846", "Punjabi (Pakistan)",  ; pa-Arab-PK
  "006B", "Quechua",  ; quz
  "046B", "Quechua (Bolivia)",  ; quz-BO
  "086B", "Quechua (Ecuador)",  ; quz-EC
  "0C6B", "Quechua (Peru)",  ; quz-PE
  "0018", "Romanian",  ; ro
  "0818", "Romanian (Moldova)",  ; ro-MD
  "0418", "Romanian (Romania)",  ; ro-RO
  "0017", "Romansh",  ; rm
  "0417", "Romansh (Switzerland)",  ; rm-CH
  "0019", "Russian",  ; ru
  "0819", "Russian (Moldova)",  ; ru-MD
  "0419", "Russian (Russia)",  ; ru-RU
  "0085", "Sakha",  ; sah
  "0485", "Sakha (Russia)",  ; sah-RU
  "703B", "Sami (Inari)",  ; smn
  "7C3B", "Sami (Lule)",  ; smj
  "743B", "Sami (Skolt)",  ; sms
  "783B", "Sami (Southern)",  ; sma
  "243B", "Sami, Inari (Finland)",  ; smn-FI
  "103B", "Sami, Lule (Norway)",  ; smj-NO
  "143B", "Sami, Lule (Sweden)",  ; smj-SE
  "0C3B", "Sami, Northern (Finland)",  ; se-FI
  "043B", "Sami, Northern (Norway)",  ; se-NO
  "083B", "Sami, Northern (Sweden)",  ; se-SE
  "203B", "Sami, Skolt (Finland)",  ; sms-FI
  "183B", "Sami, Southern (Norway)",  ; sma-NO
  "1C3B", "Sami, Southern (Sweden)",  ; sma-SE
  "004F", "Sanskrit",  ; sa
  "044F", "Sanskrit (India)",  ; sa-IN
  "0091", "Scottish Gaelic",  ; gd
  "0491", "Scottish Gaelic (United Kingdom)",  ; gd-GB
  "7C1A", "Serbian",  ; sr
  "6C1A", "Serbian (Cyrillic)",  ; sr-Cyrl
  "1C1A", "Serbian (Cyrillic, Bosnia and Herzegovina)",  ; sr-Cyrl-BA
  "301A", "Serbian (Cyrillic, Montenegro)",  ; sr-Cyrl-ME
  "0C1A", "Serbian (Cyrillic, Serbia and Montenegro (Former))",  ; sr-Cyrl-CS
  "281A", "Serbian (Cyrillic, Serbia)",  ; sr-Cyrl-RS
  "701A", "Serbian (Latin)",  ; sr-Latn
  "181A", "Serbian (Latin, Bosnia & Herzegovina)",  ; sr-Latn-BA
  "2C1A", "Serbian (Latin, Montenegro)",  ; sr-Latn-ME
  "081A", "Serbian (Latin, Serbia and Montenegro (Former))",  ; sr-Latn-CS
  "241A", "Serbian (Latin, Serbia)",  ; sr-Latn-RS
  "0030", "Sesotho",  ; st
  "0430", "Sesotho (South Africa)",  ; st-ZA
  "006C", "Sesotho sa Leboa",  ; nso
  "046C", "Sesotho sa Leboa (South Africa)",  ; nso-ZA
  "0032", "Setswana",  ; tn
  "0832", "Setswana (Botswana)",  ; tn-BW
  "0432", "Setswana (South Africa)",  ; tn-ZA
  "0059", "Sindhi",  ; sd
  "7C59", "Sindhi",  ; sd-Arab
  "0459", "Sindhi (Devanagari, India)",  ; sd-Deva-IN
  "0859", "Sindhi (Pakistan)",  ; sd-Arab-PK
  "005B", "Sinhala",  ; si
  "045B", "Sinhala (Sri Lanka)",  ; si-LK
  "001B", "Slovak",  ; sk
  "041B", "Slovak (Slovakia)",  ; sk-SK
  "0024", "Slovenian",  ; sl
  "0424", "Slovenian (Slovenia)",  ; sl-SI
  "0077", "Somali",  ; so
  "0477", "Somali (Somalia)",  ; so-SO
  "000A", "Spanish",  ; es
  "2C0A", "Spanish (Argentina)",  ; es-AR
  "400A", "Spanish (Bolivia)",  ; es-BO
  "340A", "Spanish (Chile)",  ; es-CL
  "240A", "Spanish (Colombia)",  ; es-CO
  "140A", "Spanish (Costa Rica)",  ; es-CR
  "5C0A", "Spanish (Cuba)",  ; es-CU
  "1C0A", "Spanish (Dominican Republic)",  ; es-DO
  "300A", "Spanish (Ecuador)",  ; es-EC
  "440A", "Spanish (El Salvador)",  ; es-SV
  "100A", "Spanish (Guatemala)",  ; es-GT
  "480A", "Spanish (Honduras)",  ; es-HN
  "580A", "Spanish (Latin America)",  ; es-419
  "080A", "Spanish (Mexico)",  ; es-MX
  "4C0A", "Spanish (Nicaragua)",  ; es-NI
  "180A", "Spanish (Panama)",  ; es-PA
  "3C0A", "Spanish (Paraguay)",  ; es-PY
  "280A", "Spanish (Peru)",  ; es-PE
  "500A", "Spanish (Puerto Rico)",  ; es-PR
  "0C0A", "Spanish (Spain, International Sort)",  ; es-ES
  "040A", "Spanish (Spain, Traditional Sort)",  ; es-ES_tradnl
  "540A", "Spanish (United States)",  ; es-US
  "380A", "Spanish (Uruguay)",  ; es-UY
  "200A", "Spanish (Venezuela)",  ; es-VE
  "001D", "Swedish",  ; sv
  "081D", "Swedish (Finland)",  ; sv-FI
  "041D", "Swedish (Sweden)",  ; sv-SE
  "0084", "Swiss German",  ; gsw
  "005A", "Syriac",  ; syr
  "045A", "Syriac (Syria)",  ; syr-SY
  "0028", "Tajik",  ; tg
  "7C28", "Tajik (Cyrillic)",  ; tg-Cyrl
  "0428", "Tajik (Cyrillic, Tajikistan)",  ; tg-Cyrl-TJ
  "0049", "Tamil",  ; ta
  "0449", "Tamil (India)",  ; ta-IN
  "0849", "Tamil (Sri Lanka)",  ; ta-LK
  "0044", "Tatar",  ; tt
  "0444", "Tatar (Russia)",  ; tt-RU
  "004A", "Telugu",  ; te
  "044A", "Telugu (India)",  ; te-IN
  "001E", "Thai",  ; th
  "041E", "Thai (Thailand)",  ; th-TH
  "0051", "Tibetan",  ; bo
  "0451", "Tibetan (China)",  ; bo-CN
  "0073", "Tigrinya",  ; ti
  "0873", "Tigrinya (Eritrea)",  ; ti-ER
  "0473", "Tigrinya (Ethiopia)",  ; ti-ET
  "001F", "Turkish",  ; tr
  "041F", "Turkish (Turkey)",  ; tr-TR
  "0042", "Turkmen",  ; tk
  "0442", "Turkmen (Turkmenistan)",  ; tk-TM
  "0022", "Ukrainian",  ; uk
  "0422", "Ukrainian (Ukraine)",  ; uk-UA
  "002E", "Upper Sorbian",  ; hsb
  "042E", "Upper Sorbian (Germany)",  ; hsb-DE
  "0020", "Urdu",  ; ur
  "0820", "Urdu (India)",  ; ur-IN
  "0420", "Urdu (Pakistan)",  ; ur-PK
  "0080", "Uyghur",  ; ug
  "0480", "Uyghur (China)",  ; ug-CN
  "0043", "Uzbek",  ; uz
  "7843", "Uzbek (Cyrillic)",  ; uz-Cyrl
  "0843", "Uzbek (Cyrillic, Uzbekistan)",  ; uz-Cyrl-UZ
  "7C43", "Uzbek (Latin)",  ; uz-Latn
  "0443", "Uzbek (Latin, Uzbekistan)",  ; uz-Latn-UZ
  "0803", "Valencian (Spain)",  ; ca-ES-valencia
  "0033", "Venda",  ; ve
  "0433", "Venda (South Africa)",  ; ve-ZA
  "002A", "Vietnamese",  ; vi
  "042A", "Vietnamese (Vietnam)",  ; vi-VN
  "0052", "Welsh",  ; cy
  "0452", "Welsh (United Kingdom)",  ; cy-GB
  "0062", "Western Frisian",  ; fy
  "0462", "Western Frisian (Netherlands)",  ; fy-NL
  "0088", "Wolof",  ; wo
  "0488", "Wolof (Senegal)",  ; wo-SN
  "0031", "Xitsonga",  ; ts
  "0431", "Xitsonga (South Africa)",  ; ts-ZA
  "0078", "Yi",  ; ii
  "0478", "Yi (China)",  ; ii-CN
  "003D", "Yiddish",  ; yi
  "043D", "Yiddish (World)",  ; yi-001
  "006A", "Yoruba",  ; yo
  "046A", "Yoruba (Nigeria)"  ; yo-NG
)

the_language := LCID[A_Language] ; 获取系统默认语言的名称.
MsgBox the_language  ; 显示语言名称.

下面的脚本用于创建上面的列表:

G := Gui()
LV := G.Add("ListView", "w500 r20", ["LCID", "Display Name", "Locale Name"])
G.Show()

LOCALE_ALLOW_NEUTRAL_NAMES := 0x08000000
LOCALE_SENGLISHDISPLAYNAME := 0x72
LOCALE_SLOCALIZEDDISPLAYNAME := 0x2
loop 0xFFFF
{
    LCID := Format("{:04X}", A_Index)
    if (LCID ~= "(04|08|0C|14|20|24|28|2C|30|34|38|3C|40|44|48|4C)00")
        continue  ; 跳过默认和临时的 LCID.
    LocaleName := LCIDToLocaleName(A_Index, LOCALE_ALLOW_NEUTRAL_NAMES)
    if not LocaleName
        continue  ; 跳过未知的 LCID.
    DisplayName := GetLocaleInfo(LocaleName, LOCALE_SENGLISHDISPLAYNAME)
    ; DisplayName := GetLocaleInfo(LocaleName, LOCALE_SLOCALIZEDDISPLAYNAME)
    LV.Add(, LCID, DisplayName, LocaleName)
    ; A_Clipboard .= LCID "`t" DisplayName "`t" LocaleName "`n"
}
LV.ModifyCol()  ; 自动调整每个列的大小以适合其内容.

LCIDToLocaleName(LCID, Flags := 0)
{
    reqBufSize := DllCall("LCIDToLocaleName", "UInt", LCID, "Ptr", 0, "UInt", 0, "UInt", Flags)
    out := Buffer(reqBufSize*2)
    DllCall("LCIDToLocaleName", "UInt", LCID, "Ptr", out, "UInt", out.Size, "UInt", Flags)
    return StrGet(out)
}

GetLocaleInfo(LocaleName, LCType)
{
    reqBufSize := DllCall("GetLocaleInfoEx", "Str", LocaleName, "UInt", LCType, "Ptr", 0, "UInt", 0)
    out := Buffer(reqBufSize*2)
    DllCall("GetLocaleInfoEx", "Str", LocaleName, "UInt", LCType, "Ptr", out, "UInt", out.Size)
    return StrGet(out)
}


长路径 | AutoHotkey v2

长路径

一般来说, 程序受到两种路径长度限制的影响:

  1. 操作系统提供的函数通常将路径限制为 259 个字符, 也有一些例外.
  2. 程序内处理路径的代码可能依赖于第一个限制来简化代码, 从而在事实上设置了另一个 259 个字符的限制.

这些限制通常被称为 "MAX_PATH 限制", 常量 MAX_PATH, 其值为 260. 这允许驱动器字母, 冒号和斜杠(C:\), 单个文件或目录名的最大长度(255 个字符), 和一个空终止符.

AutoHotkey 在大多数情况下删除了第二种类型, 这使得脚本可以围绕第一种类型工作. 有两种方法可以做到这一点:

  • 长路径可以在 Windows 10 上为 AutoHotkey 和所有其他长路径感知程序启用. 有关详细信息, 请参阅 Microsoft 文档. 简而言之, 这使大多数命令和函数能够透明地处理长路径, 但需要 Windows 10 1607 版本或更高版本.
  • 在很多情况下, 在路径前面加上前缀 \\?\ 使其超过通常的限制. 但是, 有一些系统函数不支持(或者通常不支持长路径). 有关详细信息, 请参阅已知限制.

长路径前缀

如果底层系统函数支持, \\?\ 前缀 -- 例如, \\?\C:\My Folder -- 将限制增加到 32,767 个字符. 但是, 它通过跳过路径规范化来实现这一点. 路径的某些元素通常会被规范化删除或更改, 但它们会成为文件实际路径的一部分. 必须小心, 因为这允许创建 "正常" 程序无法访问的路径.

特别是, 规范化:

  • 解析相对路径, 如 dir\file.ext, \file.ext 和 C:file.ext(注意没有反斜杠).
  • 解析相关部分, 如 \.. 和 \..
  • 规范化组件/目录分隔符, 用 \ 替换 / 并消除多余的分隔符.
  • 删除某些字符, 如组件末尾的单个句点(dir.\file) 或尾随的空格和句点(dir\filename . .).

在应用前缀之前, 可以通过下面定义的函数将路径传递给 GetFullPathName, 从而显式地规范化路径. 例如:

MsgBox "\\?\" NormalizePath("..\file.ext")
NormalizePath(path) {
    cc := DllCall("GetFullPathName", "str", path, "uint", 0, "ptr", 0, "ptr", 0, "uint")
    buf := Buffer(cc*2)
    DllCall("GetFullPathName", "str", path, "uint", cc, "ptr", buf, "ptr", 0)
    return StrGet(buf)
}

带有 \\?\ 前缀的路径也可以被这个函数规范化. 但是, 在这种情况下, 永远不会使用工作目录, 而根目录是 \\?\(例如, \\?\C:\.. 解析为 \\?\, 而 C:\.. 解析为 C:\).

已知限制

尽管路径本身不再限制为 259 个字符, 但是每个部分(文件或目录名) 也不能超过文件系统施加的硬限制(通常为 255 个字符).

由于底层系统函数的限制, 下面这些不支持长路径:

  • DllCall(用于 DllFile 和 Function)
  • DirCopy
  • DirDelete, 除非 Recurse 为 false
  • DirMove, 除非使用 R 选项
  • FileCreateShortcut
  • FileGetShortcut
  • FileRecycle
  • SoundPlay(限制为 127 个字符)
  • DriveSetLabel 和 DriveGet 变量(除了 DriveGetType)
  • 返回特殊的文件夹路径的内置变量(长路径可能始终无法实现): A_AppData, A_Desktop, A_MyDocuments, A_ProgramFiles, A_Programs, A_StartMenu, A_Startup 和常见变量, A_Temp 和 A_WinDir

仅在 Windows 10 启用长路径感知时, SetWorkingDir 和 A_WorkingDir 才支持长路径, 因为无法使用 \\?\ 前缀. 如果工作目录长度超过 MAX_PATH, 则无法使用 Run 来启动程序. 这些限制是由操作系统强加的.

似乎无法运行完整路径超过 MAX_PATH 的可执行文件. 在这种情况下, 就不可能完全测试旨在支持更长的可执行路径的任何更改. 因此, 已为以下各项保留了 MAX_PATH 限制:

  • ahk_exe
  • 默认脚本的路径, 该路径基于当前可执行文件的路径.
  • 检索 AutoHotkey 安装目录, 该目录通过 A_AhkPath 在编译脚本中使用, 可用于启动 Window Spy 或帮助文件.
  • WinGetProcessPath.
  • WinGetProcessName(理论上这不是个问题, 因为它只应用于名称部分, 而且 NTFS 只支持最多 255 个字符的名称).

错误消息中显示的长 #Include 路径可以任意截断.


创建键盘宏或鼠标宏 | AutoHotkey v2

创建键盘宏或鼠标宏

宏是一系列按要求 "播放" 的脚本动作. 宏最常见的用法是向一个或多个窗口发送模拟键击和鼠标点击. 这些窗口会响应每个键击和鼠标点击, 就好像您手动操作一样, 这样可以让重复的任务快速可靠地自动化.

回放宏的最方便的方法之一是为它指定热键或热字串. 例如, 下面的热键会为创建空白电子邮件, 然后输入指定的内容, 并且允许您在发送之前对其进行编辑:

^!s::  ; Control+Alt+S 热键.
{
    if !WinExist("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 ..."  ; 等等.
}  ; 这个括号的作用是完成热键.

像上面这样的热键宏, 对于你每天要执行多次的任务来说特别有用. 相比之下, 较少使用的宏可以保存在独立的脚本中, 通过在开始菜单或桌面建立快捷方式来运行.

要立即创建自己的宏和热键, 请阅读快速入门教程.

-- 主页 --


脚本性能 | AutoHotkey v2

脚本性能

根据脚本的内容下面的函数可能会影响性能: SendMode, SetKeyDelay, SetMouseDelay, SetWinDelay, SetControlDelay 和 SetDefaultMouseSpeed.

内置性能特性

每个脚本在加载和语法检查的同时, 都会进行半编译. 除了能及早发现一些错误, 还能大大提升运行时的性能.

下面是优化过程(半编译) 的一些技术细节:

  • Loop, block, IF, ELSE 和其他控制流语句在脚本中被赋予相关跳点的内存地址.
  • 每个语句名都由跳转表中的地址代替.
  • 每个表达式都被标记化并从 infix 转换为 postfix.
  • 对变量或函数的每个引用都会被解析为一个内存地址, 除非它是动态的.
  • 表达式中的原义整数被替换为二进制整数.
  • 每一个 Goto 的目标都会被解析为一个内存地址, 除非它是一个变量.

此外, 在脚本执行过程中, 二进制数字被缓存在变量中, 以避免从字符串到/从字符串的转换.


Regular Expressions (RegEx) - Quick Reference | AutoHotkey v2

正则表达式(RegEx) - 快速参考

目录

  • 基础
  • 选项(区分大小写)
  • 常用符号和语法

基础

Match anywhere(在任意位置进行匹配): 默认情况下, 正则表达式匹配要搜索的字符串中任意位置的子字符串 anywhere. 例如, 正则表达式 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" 选项才能在 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 | 非贪婪. 让限定符 *, ?, + 和 {min,max} 在形成匹配时只消耗必需的那些字符, 把剩下的部分留给模式的后面部分. 没有使用 "U" 选项时, 可以在这些字符后加上问号来限定它们为非贪婪的. 相反地, 使用了 "U" 选项时, 问号会成为贪婪匹配的限定符.
X | PCRE_EXTRA. 启用不兼容 Perl 的 PCRE 特性. 目前, 这样做的唯一功能是在模式中的任意反斜杠后跟着没有特殊含义的字母时, 都会导致抛出异常. 此选项有助于保留未使用的反斜杠序列供将来使用. 如果没有此选项, 反斜杠后跟着没有特殊含义的字母时会被视为原义的(即 \g 和 g 都被识别为原义的 g). 不论是否使用此选项, 没有特殊含义的非字母反斜杠序列总是被视为原义的(即 \/ 和 / 都被视为正斜杠).
S | 研究模式来提高性能. 它可用于要执行多次的特定模式(尤其是复杂的模式). 如果 PCRE 找到了提高性能的方法, 则会把这个发现储存到缓存中模式的旁边, 供后续执行相同模式时使用(后续使用此模式时还需要指定 S 选项, 因为要找到缓存中相同的模式则它们的选项也必须完全相同, 包括它们的顺序). (这里的研究主要指在进行匹配前使用其他一些通常较简单快速的方法进行判断, 例如假设模式至少匹配 5 个字符, 而源字符串只有 3 个, 那么正则表达式引擎会直接返回 "没有匹配" 的结果, 而不会进行匹配.)
C | 启用自动调出模式. 请参阅正则表达式调出了解更多信息.
`a

启用识别额外的换行标记. 默认情况下, 只识别 `r`n, `n 和 `r. 启用该选项后, 还可识别 `v/VT/vertical tab/chr(0xB), `f/FF/formfeed/chr(0xC), NEL/next-line/chr(0x85), LS/line separator/chr(0x2028) 和 PS/paragraph separator/chr(0x2029).

`a, `n 和 `r 选项会影响锚点(^ 和 $) 和句点/句号模式的行为.

`a 也会使 (*BSR_UNICODE) 生效, 这将导致 \R 匹配任何类型的换行. 默认情况下, \R 匹配 `n, `r 和 `r`n; 这种行为可以通过以下选项组合来恢复: `a)(*BSR_ANYCRLF)
`n | 使单独的换行(`n) 成为唯一可识别的换行标记(见上文).
`r | 使单独的回车(`r) 成为唯一可识别的换行标记(见上文).

注意: 在两个选项间可以使用空格或 tab 分隔.

常用符号和语法

元素 | 描述
. 默认情况下, 句点匹配除 `r(回车) 或 `n(换行符) 外的任何单个字符, 但是这种特性可以使用 DotAll (s), linefeed (`n), carriage return (`r) 或 `a 选项进行更改. 例如, 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(whitespace), 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 字符的十六进制码.

\R 匹配 `r`n, `n 和 `r(然而, \R 在类中仅表示字母 "R").
\p{xx}
\P{xx}
\X

Unicode 字符属性. \p{xx} 匹配具有 xx 属性的字符, 而 \P{xx} 匹配任意 不具有 xx 属性的字符. 例如, \pL 匹配任意一个字母, 而 \p{Lu} 匹配任意一个大写字母. \X 匹配任意数量的扩展 Unicode 序列中的字符.

对于受支持的属性名称的完整列表和其他细节, 请在 www.pcre.org/pcre.txt 中搜索 "\p{xx}".
(*UCP)

出于性能考虑, \d, \D, \s, \S, \w, \W, \b 和 \B 只识别 ASCII 字符. 如果模式以 (*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


Regular Expression Callouts | AutoHotkey v2

正则表达式调出

正则调出提供了一种在正则表达式模式匹配过程中临时将控制权传递给脚本的方法. 关于 PCRE 标准调出功能的详细信息, 请参阅 pcre.txt.

目前只有 RegExMatch 和 RegExReplace 支持正则调出.

目录

  • 语法
  • 正则调出函数
  • EventInfo
  • 自动调出
  • 备注

语法

在 AutoHotkey 中正则调出的语法为 (?CNumber:Function), 其中 Number 和 Function 都是可选的. 只有在指定了 Function才允许使用冒号 ':', 而如果省略 Number 则冒号也可以省略.

调出函数必须通过正式定义它或将其赋值给函数范围内的变量来提供, 该函数调用 RegExMatch 或 RegExReplace(本地或全局). 如果省略 Function, 则默认为 pcre_callout. 如果没有找到变量或其值不是函数对象, 则抛出错误.

正则调出函数

MyFunction(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx)
{
    ...
}

正则调出函数最多可以定义 5 个参数:

  • Match: 接收 RegExMatchInfo 对象, 其中包含到目前为止的匹配信息.
  • CalloutNumber: 接收正则调出的 Number.
  • FoundPos: 接收当前潜在匹配的位置.
  • Haystack: 接收传递给 RegExMatch 或 RegExReplace 的 Haystack.
  • NeedleRegEx: 接收传递给 RegExMatch 或 RegExReplace 的 NeedleRegEx.

这些名称只是提示性的. 实际中可以使用其他的名称.

警告: 不支持在 RegExReplace 或 RegExMatch 在被调用期间更改其输入参数, 这可能会导致不可预测的行为.

模式匹配是继续进行或失败, 取决于正则调出函数的返回值:

  • 如果函数返回 0 或没有返回数值, 则匹配操作如常进行.
  • 如果函数返回 1 或更大的数字, 则在当前位置匹配失败, 但继续进行剩余部分的匹配测试.
  • 如果函数返回 -1, 则匹配中止.
  • 如果函数返回小于 -1, 的值, 则它被视为 PCRE 错误码且匹配中止. 这将导致 RegExMatch 和 RegExReplace 抛出异常; 异常对象的 Extra 属性包含错误码.

例如:

Haystack := "The quick brown fox jumps over the lazy dog."
RegExMatch(Haystack, "i)(The) (\w+)\b(?CCallout)")
Callout(m,*) {
    MsgBox "m[0]=" m[0] "`nm[1]=" m[1] "`nm[2]=" m[2]
    return 1
}

在上面的例子中, 对于匹配正则调出之前的那部分模式的每个子字符串都会调用一次 Callout. 使用 \b 排除匹配到不完整的单词, 例如 The quic, The qui, The qu, 等等.

如果在调出期间修改了 RegEx 函数的任何输入参数, 则该行为是未定义的.

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, "Ptr")
subject           := NumGet(A_EventInfo,  8 + A_PtrSize, "Ptr")
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, "Ptr")
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). 例如, 下面的模板可以用来调试正则表达式:

; 调用带有自动调出选项 C 的 RegExMatch.
RegExMatch("xxxabc123xyz", "C)abc.*xyz")

; 定义默认的正则调出函数.
pcre_callout(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 原来的值.

在一些可以确定不会发生匹配的情况下, 则会对 PCRE 进行优化来提早中止. 对于在这些情况中的所有正则调出, 可能需要在模式的开始处指定 (*NO_START_OPT) 来禁用这种优化.


重映射按键 (键盘, 鼠标和控制器) | AutoHotkey v2

重映射按键 (键盘, 鼠标和控制器)

目录

  • 简介
  • 重映射键盘和鼠标
  • 备注
  • 通过键盘移动鼠标光标
  • 使用注册表的 "扫描码映射" 功能进行重映射
  • 相关话题

简介

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

重映射键盘和鼠标

内置重映射功能的语法为 OriginKey::DestinationKey. 例如, 只包含下面这行内容的脚本会将 A 重映射成 B:

a::b

上面的例子并不改变 B 键本身. B 将继续发送 "b" 的键击, 除非把它重映射到其他内容, 如下面的示例所示:

a::b
b::a

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

a::B

相反, 在发送按键时, 将自动释放包含在左侧但不包含在右侧的任何修饰符. 例如, 以下两行会产生一个小写字母 "b", 当你按下 Shift+A 或 Ctrl+A 时:

A::b
^a::b

鼠标重映射

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

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

其他有用的映射

示例 | 描述
CapsLock::Ctrl | 把 CapsLock 映射成 Ctrl 键. 要保留打开及关闭 CapsLock 的功能, 需先包含重映射 +CapsLock::CapsLock. 这样, 当按住 Shift 并按下 CapsLock 时, 可切换 CapsLock 的开关状态. 因为两个重映射均允许附加修饰键被按下, 额外指定的 +CapsLock::CapsLock 重映射必须优先放置以便能正常工作.
XButton2::^LButton | 把第五个鼠标按钮(XButton2) 映射成 control-click.
RAlt::AppsKey | 把右 Alt 映射成 Menu(这是打开上下文菜单的按键).
RCtrl::RWin | 把右 Ctrl 映射成右 Win.
Ctrl::Alt | 把左右 Ctrl 映射成 Alt. 但是, 请参阅 alt-tab 的问题.
^x::^c | 把 Ctrl+X 映射成 Ctrl+C. 它也会让 Ctrl+Alt+X 映射成 Ctrl+Alt+C, 等等.
RWin::Return | 通过简单的return, 来禁用右 Win.

您可以通过将这些示例复制到一个新的文本文件(如 "Remap") 中来尝试其中任何一个示例, 然后启动文件.

有关键和鼠标按钮名称的完整列表, 请参阅按键列表.

备注

#HotIf 指令可用于仅在指定的窗口(或者当满足任何给定条件时) 激活选定的重映射. 例如:

#HotIf WinActive("ahk_class Notepad")
a::b  ; 使 'a' 键发送 'b' 键, 但仅在记事本中有效.
#HotIf  ; 这里让后续的重映射和热键对所有窗口生效.

重映射按键或按钮在以下方面是 "完全的":

  • 按住修饰符(例如 Ctrl 或 Shift) 时按下原始键, 会让那个修饰符对目标键生效. 例如, b::a 会在您按下 Ctrl+B 时产生 Ctrl+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

或者, 使用 #InputLevel 来覆盖此默认行为. 例如:

#InputLevel 1
a::b

#InputLevel 0
^!b::ToolTip "You pressed " A_ThisHotkey

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

如果 DestinationKey 是按键 {, 它必须进行转义, 例如, x::`{. 否则它将被解释为热键函数的左大括号.

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

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

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

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

  1. 当源按键为左 Ctrl 而目标键为 Alt, 会把 Send "{Blind}{LAlt DownR}" 这行语句替换为 Send "{Blind}{LCtrl up}{LAlt DownR}". 如果原按键为右 Ctrl 也会如此, 除非使用了 {RCtrl up}. 这样做是为了确保系统将 Alt 键组合转换为好像没有按住 Ctrl 一样, 但它也会导致重映射覆盖任何先前的 {Ctrl down}. [v2.0.8+]: 为了向后兼容, 仍然发送未抑制的 Ctrl 键, 但不再需要用于其原始目的. 副作用可以通过用一对显式热键替换重映射来避免, 如上所示.
  2. 当键盘按键被重映射为鼠标按钮时(例如 RCtrl::RButton), 在上面的热键中会使用 SetMouseDelay 代替 SetKeyDelay. 而且, 上面的首个热键会被替换为下面的热键, 这样避免了由于键盘的自动重复功能生成的重复的鼠标点击:
    *RCtrl::
{
    SetMouseDelay -1
    if not GetKeyState("RButton")  ; 即鼠标右键还没有按下.
        Send "{Blind}{RButton DownR}"
}
  3. 当源按键为自定义组合键时, 通配符修饰符(*) 被省略以允许热键工作.
  4. !#^+ 中的任何修饰符如果应用于源按键而不是目标按键, 则将它们插入到单词 "Blind" 之后, 以允许 Send 释放这些修饰符. 例如, ^a::b 将使用 {Blind^}. <^a::b 也会使用 {Blind^}, 如果与 RCtrl 结合使用, 可能会产生意想不到的结果. 有关详情, 请参阅 Blind 模式.

注意, SetKeyDelay 的第二个参数(按下持续时间) 在上面的热键中被省略了. 这是因为按下持续时间不适用于独立的按键按下或按键弹起事件, 例如 {b down} 和 {b up}. 但是, 它适用于修饰键(Shift, Ctrl, Alt 和 Win) 状态的改变, 这会影响像 a::B 或 a::^b 这样的重映射. 因此, 脚本在脚本启动期间设置的任何按下持续时间将会应用于所有此类重映射.

由于重映射会被简单转换为上面描述的热键, 所以 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.

要禁用按键而不进行重映射, 请把它设置为只含有 returns 的热键. 例如, F1::return 会禁用 F1.

内置的重映射方法不支持下列按键:

  • 鼠标滚轮(WheelUp/Down/Left/Right).
  • "Pause" 不能作为目标键名(因为它匹配内置函数的名称). 请使用 vk13 或对应的扫描码代替.
  • 大括号 {} 不能作为目标键. 作为替代请使用 VK/SC 方法; 例如 x::+sc01A 和 y::+sc01B.

通过键盘移动鼠标光标

键盘可以用来移动鼠标光标, 如功能齐全的键盘到鼠标脚本所示. 由于该脚本提供了鼠标平滑移动, 加速和其他特性, 所以如果您想使用键盘进行大量的鼠标操作, 那么推荐使用该脚本. 相比之下, 下面的例子是一个更简单的例子:

*#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::  ; 左 Win + 右 Control => Left-click(按住 Control/Shift 来进行 Control-Click 或 Shift-Click).
{
    SendEvent "{Blind}{LButton down}"
    KeyWait "RCtrl"  ; 防止键盘自动重复导致的重复鼠标点击.
    SendEvent "{Blind}{LButton up}"
}

*<#AppsKey::  ; 左 Win + AppsKey => Right-click
{
    SendEvent "{Blind}{RButton down}"
    KeyWait "AppsKey"  ; 防止键盘自动重复导致重复的鼠标点击.
    SendEvent "{Blind}{RButton up}"
}

使用注册表的 "扫描码映射" 功能进行重映射

优点:

  • 注册表的重映射功能通常比 AutoHotkey 的重映射更加直接有效. 例如, 它能适应于更大范围的游戏, 它不存在 alt-tab 的问题, 并且它能触发 AutoHotkey 的钩子热键(然而 AutoHotkey 的重映射需要间接的方法才行).
  • 如果您会手动修改注册表条目(下面进行阐述), 那么不需要任何额外的软件就可以重映射您的键盘. 即使您使用 KeyTweak 来修改注册表条目, 那么完成后 KeyTweak 不需要一直保持运行(而 AutoHotkey 需要一直运行, 重映射才会生效).

缺点:

  • 注册表重映射比较不灵活: 每次修改映射都必须重启后才会生效.
  • 效果是全局的: 它不能创建针对特定用户, 应用程序或环境的重映射.
  • 它无法发送含修饰键 Shift, Ctrl, Alt 或 AltGr 的组合键. 例如, 它不能把小写字符映射为大写字符.
  • 它只支持键盘(AutoHotkey 还支持鼠标重映射和一些受限的控制器重映射).

如何将更改应用于注册表: 使用注册表重映射按键至少有两种方法:

  1. 使用像 KeyTweak(免费软件) 这样的程序可视化重映射按键. 它会自动修改注册表.
  2. 通过手动创建的 .reg 文件(纯文本) 重映射按键并把其导入注册表. 演示的例子, 请参阅 www.autohotkey.com/forum/post-56216.html#56216

相关话题

  • 按键, 鼠标按钮控制器控制列表
  • GetKeyState
  • 重映射控制器


重映射控制器为键盘或鼠标 | AutoHotkey v2

重映射控制器为键盘或鼠标

目录

  • 重要事项
  • 让控制器按钮发送键击或鼠标点击
    • 不同的方法
    • 自动重复键击
    • 上下文相关的控制器按钮
    • 用控制器作为鼠标
  • 让其他控制器控制器发送按键或鼠标点击
    • 控制器轴
    • 控制器 POV 帽
    • 自动重复按键
  • 备注
  • 相关话题

重要事项

  • For historical reasons, the following button and control names begin with Joy, which stands for joystick. However, they usually also work for other game controllers such as gamepads or steering wheels.
  • Although a controller button or axis can be remapped to become a key or mouse button, it cannot be remapped to some other controller button or axis. That would be possible only with the help of a controller emulator such as vJoy.
  • AutoHotkey identifies each button on a controller with a unique number between 1 and 32. To determine these numbers, use the controller test script.
  • For Xbox controller 2013 and newer (anything newer than the Xbox 360 controller), Joy1 to Joy32 hotkeys will only work if a window owned by the script is active, such as a message box, GUI, or the script's main window. This limitation also applies to GetKeyState for Joy1 to Joy32 and JoyX, JoyY, JoyZ, JoyR, JoyU, JoyPOV (and possibly JoyV), but not for JoyName, JoyButtons, JoyAxes and JoyInfo. To detect those controller inputs for other active windows, use the XInput.ahk library.

Making a Controller Button Send Keystrokes or Mouse Clicks

Different Approaches

Below are three approaches, starting at the simplest and ending with the most complex. The most complex method works in the broadest variety of circumstances (such as games that require a key or mouse button to be held down).

方法 #1

This method sends simple keystrokes and mouse clicks. 例如:

Joy1::Send "{Left}"  ; Have button #1 send a left-arrow keystroke.
Joy2::Click  ; Have button #2 send a click of left mouse button.
Joy3::Send "a{Esc}{Space}{Enter}"  ; Have button #3 send the letter "a" followed by Escape, Space, and Enter.
Joy4::Send "Sincerely,{Enter}John Smith"  ; Have button #4 send a two-line signature.

To have a button perform more than one function, put the first function beneath the button name and make the last line a return. 例如:

Joy5::
{
    Run "notepad"
    WinWait "Untitled - Notepad"
    WinActivate
    Send "This is the text that will appear in Notepad.{Enter}"
}

See the Key List for the complete list of keys and mouse/controller buttons.

Method #2

This method is necessary in cases where a key or mouse button must be held down for the entire time that you're holding down a controller button. The following example makes the controller's second button become the left-arrow key:

Joy2::
{
    Send "{Left down}"  ; Hold down the left-arrow key.
    KeyWait "Joy2"  ; Wait for the user to release the controller button.
    Send "{Left up}"  ; Release the left-arrow key.
}

Method #3

This method is necessary in cases where you have more than one controller hotkey of the type described in Method #2, and you sometimes press and release such hotkeys simultaneously. The following example makes the controller's third button become the left mouse button:

Joy3::
{
    Send "{LButton down}"   ; Hold down the left mouse button.
    SetTimer WaitForButtonUp3, 10
}

WaitForButtonUp3()
{
    if GetKeyState("Joy3")  ; The button is still, down, so keep waiting.
        return
    ; Otherwise, the button has been released.
    Send "{LButton up}"  ; Release the left mouse button.
    SetTimer, 0
}

Auto-repeating a Keystroke

Some programs or games might require a key to be sent repeatedly (as though you are holding it down on the keyboard). The following example achieves this by sending spacebar keystrokes repeatedly while you hold down the controller's second button:

Joy2::
{
    Send "{Space down}"   ; Press the spacebar down.
    SetTimer WaitForJoy2, 30  ; Reduce the number 30 to 20 or 10 to send keys faster. Increase it to send slower.
}

WaitForJoy2()
{
    if not GetKeyState("Joy2")  ; The button has been released.
    {
        Send "{Space up}"  ; Release the spacebar.
        SetTimer, 0  ; Stop monitoring the button.
        return
    }
    ; Since above didn't "return", the button is still being held down.
    Send "{Space down}"  ; Send another Spacebar keystroke.
}

Context-sensitive Controller Buttons

The #HotIf directive can be used to make selected controller buttons perform a different action (or none at all) depending on any condition, such as the type of window that is active.

Using a Controller as a Mouse

The Controller-To-Mouse script converts a controller into a mouse by remapping its buttons and axis control.

Making Other Controller Controls Send Keystrokes or Mouse Clicks

To have a script respond to movement of a stick's axis or POV hat, use SetTimer and GetKeyState.

Controller Axes

The following example makes the stick's X and Y axes behave like the arrow key cluster on a keyboard (left, right, up, and down):

SetTimer WatchAxis, 5

WatchAxis()
{
    static KeyToHoldDown := ""
    JoyX := GetKeyState("JoyX")  ; Get position of X axis.
    JoyY := GetKeyState("JoyY")  ; Get position of Y axis.
    KeyToHoldDownPrev := KeyToHoldDown  ; Prev now holds the key that was down before (if any).

    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  ; The correct key is already down (or no key is needed).
        return  ; Do nothing.

    ; Otherwise, release the previous key and press down the new key:
    SetKeyDelay -1  ; Avoid delays between keystrokes.
    if KeyToHoldDownPrev   ; There is a previous key to release.
        Send "{" KeyToHoldDownPrev " up}"  ; Release it.
    if KeyToHoldDown   ; There is a key to press down.
        Send "{" KeyToHoldDown " down}"  ; Press it down.
}

Controller POV Hat

The following example makes the controller's POV hat behave like the arrow key cluster on a keyboard; that is, the POV hat will send arrow keystrokes (left, right, up, and down):

SetTimer WatchPOV, 5

WatchPOV()
{
    static KeyToHoldDown := ""
    POV := GetKeyState("JoyPOV")  ; Get position of the POV control.
    KeyToHoldDownPrev := KeyToHoldDown  ; Prev now holds the key that was down before (if any).

    ; Some controllers might have a smooth/continous POV rather than one in fixed increments.
    ; To support them all, use a range:
    if POV < 0   ; No angle to report
        KeyToHoldDown := ""
    else if POV > 31500                ; 315 to 360 degrees: Forward
        KeyToHoldDown := "Up"
    else if POV >= 0 and POV <= 4500      ; 0 to 45 degrees: Forward
        KeyToHoldDown := "Up"
    else if POV >= 4501 and POV <= 13500  ; 45 to 135 degrees: Right
        KeyToHoldDown := "Right"
    else if POV >= 13501 and POV <= 22500 ; 135 to 225 degrees: Down
        KeyToHoldDown := "Down"
    else                                  ; 225 to 315 degrees: Left
        KeyToHoldDown := "Left"

    if KeyToHoldDown = KeyToHoldDownPrev  ; The correct key is already down (or no key is needed).
        return  ; Do nothing.

    ; Otherwise, release the previous key and press down the new key:
    SetKeyDelay -1  ; Avoid delays between keystrokes.
    if KeyToHoldDownPrev   ; There is a previous key to release.
        Send "{" KeyToHoldDownPrev " up}"  ; Release it.
    if KeyToHoldDown   ; There is a key to press down.
        Send "{" KeyToHoldDown " down}"  ; Press it down.
}

Auto-repeating a Keystroke

Both examples above can be modified to send the key repeatedly rather than merely holding it down (that is, they can mimic physically holding down a key on the keyboard). To do this, replace the following line:

return  ; Do nothing.

With the following:

{
    if KeyToHoldDown
        Send "{" KeyToHoldDown " down}"  ; Auto-repeat the keystroke.
    return
}

备注

A controller other than first may be used by preceding the button or axis name with the number of the controller. For example, 2Joy1 would be the second controller's first button.

To find other useful controller scripts, visit the AutoHotkey forum. A keyword search such as Controller and GetKeyState and Send is likely to produce topics of interest.

Related Topics

  • Controller-To-Mouse script (using a controller as a mouse)
  • List of controller buttons, axes, and controls
  • GetKeyState
  • Remapping the keyboard and mouse


PostMessage / SendMessage 教程 | AutoHotkey v2

PostMessage / SendMessage 教程 作者: Rajat

本页解释如何通过 PostMessage 或 SendMessage 向窗口或窗口控件发送消息, 并将回答如下问题:

  • "如何按下已最小化窗口中的按钮?"
  • "当 MenuSelect 不起作用时, 我如何选择一个菜单项?!"
  • "这是个可更换皮肤的窗口....如何确保我每次发送的函数都有效?"
  • "如果是 隐藏 窗口呢?!"

需要: Winspector Spy(可在此处下载)

像第一个例子那样, 请注意 MenuSelect 对 Outlook Express 的 "New Message" 窗口中的菜单栏无效. 换句话说, 这代码不起作用:

 MenuSelect "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 自带的应用程序; 其他的程序应该不用改变):

;设置写字板(Wordpad) 字体为青色
PostMessage 0x111, 32788, 0, , "Document - WordPad"
;打开记事本(Notepad) 的关于对话框
PostMessage 0x111, 65, 0, , "Untitled - Notepad"
;切换记事本的自动换行属性
PostMessage 0x111, 32, 0, , "Untitled - Notepad"
;在 Windows Media Player 中播放/暂停
PostMessage 0x111, 32808, 0, , "Windows Media Player"
;使用 65306 来 Pause, 而 65303 来 Reload, 从而代替下面的 Suspend. (请参阅 FAQ)
PostMessage 0x111, 65305,,, "MyScript.ahk - AutoHotkey"

; 按下 CapsLock 和 Numpad2 重新加载所有 AutoHotkey 脚本
CapsLock & Numpad2::
ReloadAllAhkScripts(ThisHotkey)
{
     DetectHiddenWindows True
    for hwnd in WinGetList("ahk_class AutoHotkey")
    {
        if (hwnd = A_ScriptHwnd)  ; 重新加载时忽略当前窗口
             continue
        PostMessage 0x111, 65303,,, hwnd
     }
     Reload
 }

上面这个示例针对 PostMessage. SendMessage 的工作方式是一样的, 但另外会等待一个返回值, 这可以用于诸如在 Winamp 中获取当前正在播放的曲目(请参阅自动化 Winamp 的例子).

这里是一些注意事项:

  • 上文也提到了操作系统是 XP 且需要注意消息值随着不同的操作系统而改变. 如果您发现一个消息在您的系统上有效(对于一个软件的某个版本), 那么在其他系统上它对于这个软件的相同版本仍然是有效的. 此外, 大多数应用程序甚至会在它们的不同版本中使用相同的消息值(例如 Windows Media Player 和 Winamp).
  • 如果您已经在 Winspector Spy 中设置了过滤器来只显示 wm_command 消息, 却仍然得到大量的消息时, 请右键点击那些不需要的消息并选择隐藏(消息名)... 这些消息一般是不是由于您和目标软件交互所产生的消息.
  • 在 Winspector Spy 中, 右指向的箭头显示 msg 值, 左指向的模糊箭头显示返回值. 默认情况下, 0 值可以安全地认为是 '没有错误'.
  • 要传递消息到隐藏窗口, 请添加此行到脚本: DetectHiddenWindows True

注: 此技术对某些应用程序无效. 我对 VB 和 Delphi 编写的应用程序只能侥幸. 此技术最适用于 C, C++ 编写的应用程序. 对于 VB 应用程序相同函数的 'LParam' 参数在传递时总是变化的. 对于 Delphi 应用程序... 一些程序的 GUI 甚至不使用 wm_command. 它或许使用鼠标位置和点击吧.

去探索吧.... 并且记得在 AutoHotkey 论坛分享您的经验. 欢迎反馈!

这个指南并不是为新手们准备的(没有冒犯的意思), 因为这些函数被认为是高级功能. 所以如果读完本文, 您还是摸不着头脑, 请忘了它吧.

-Rajat


Windows 消息 | AutoHotkey v2

Windows 消息

Windows 消息用于在操作系统和应用程序之间, 以及应用程序的不同部分之间进行通信.

Windows 消息只是一个指定特定事件的数字代码. 例如, 如果用户按下鼠标左键, 窗口会收到一条消息, 消息代码如下: WM_LBUTTONDOWN(0x0201).

有些消息具有与之关联的数据. 例如, WM_LBUTTONDOWN message 消息包含鼠标光标的 X 和 Y 坐标.

消息号的范围如下:

  • 0 到 0x03FF: 保留给系统使用的消息.
  • 0x0400(WM_USER) 到 0x7FFF: 由私有窗口类使用的整数消息.
  • 0x8000(WM_APP) 到 0xBFFF: 供应用程序使用的消息. 此范围内的消息不会与系统消息冲突.
  • 0xC000 到 0xFFFF: 供应用程序使用的字符串消息. 此范围内的消息是在运行时通过系统的 RegisterWindowMessage 函数定义的.
  • 大于 0xFFFF: 表示系统保留.

有关详情, 请参阅关于消息和消息队列(Microsoft Docs).

在 AutoHotkey 中, 消息号可用于 PostMessage, SendMessage 和 OnMessage 的 MsgNumber 参数. 下面是一些值的列表. 要了解如何使用特定消息(例如 WM_VSCROLL) 的更多信息, 请在 Microsoft Docs 或您选择的搜索引擎中查找它. 另外, 请查看消息教程.

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


Window and Control Styles | AutoHotkey v2

窗口和控件的样式

本页列出了一些样式和扩展样式, 可以通过方法 Gui.Opt 和 GuiControl.Opt, 和内置函数 WinSetStyle, WinSetExStyle, WinGetStyle, WinGetExStyle, ControlSetStyle, ControlSetExStyle, ControlGetStyle 和 ControlGetExStyle 来设置或检索.

目录

  • 用于 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 总是被启用而不能被禁用.

样式 | Hex | 描述
WS_BORDER | 0x800000 | +/-Border. 创建含有薄边框的窗口.
WS_POPUP | 0x80000000 | 创建一个弹出窗口. 此样式不能和 WS_CHILD 样式一起使用.
WS_CAPTION | 0xC00000 | +/-Caption. 创建含有标题栏的窗口. 此样式是 WS_BORDER 和 WS_DLGFRAME 数值的和.
WS_CLIPSIBLINGS | 0x4000000 | 相对地剪裁子窗口; 也就是说, 当某个特定子窗口接收到 WM_PAINT 消息时, WS_CLIPSIBLINGS 样式会将所有其他重叠的子窗口从要更新的子窗口区域中剪裁出来. 如果未指定 WS_CLIPSIBLINGS 并且子窗口重叠, 则在子窗口的工作区内绘制时, 可以在相邻子窗口的工作区内绘制.
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 | 0x0 | 创建重叠的窗口. 重叠的窗口含有标题栏和边框. 等同于 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 控件样式

这些样式会影响到 Text 控件. 它既没有默认样式也没有强制样式.

样式 | Hex | 描述
SS_BLACKFRAME | 0x7 | 指定带有使用窗框颜色描绘的框架的方形框. 在默认配色方案中此颜色为黑色.
SS_BLACKRECT | 0x4 | 指定使用当前窗框颜色填充的矩形. 在默认配色方案中此颜色为黑色.
SS_CENTER | 0x1 | +/-Center. 指定简单的矩形并在其中居中显示错误值文本. 控件会自动换行其中的文本, 一行末尾多出的文本显示到下一个居中行的开始处.
SS_CENTERIMAGE | 0x200 | 如果控件包含单行文本, 则文本在控件的可用高度内垂直居中.
SS_ETCHEDFRAME | 0x12 | 使用 EDGE_ETCHED 边缘样式描绘静态控件的边框.
SS_ETCHEDHORZ | 0x10 | 使用 EDGE_ETCHED 边缘样式描绘静态控件的顶部和底部边缘.
SS_ETCHEDVERT | 0x11 | 使用 EDGE_ETCHED 边缘样式描绘静态控件的左右边缘.
SS_GRAYFRAME | 0x8 | 指定带有使用屏幕背景(桌面) 颜色描绘的框架的方形框. 在默认配色方案中此颜色为灰色.
SS_GRAYRECT | 0x5 | 指定使用当前屏幕背景颜色填充的矩形. 在默认配色方案中此颜色为灰色.
SS_LEFT | 0x0 | +/-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 控件样式

这些样式会影响到 Edit 控件. 默认情况下, 它使用 WS_TABSTOP 和 WS_EX_CLIENTEDGE(扩展样式 E0x200). 它没有强制样式.

如果一个编辑控件由于初始内容包含多行, 高度大于 1 行或明确指定大于 1 的行数而自动检测为多行控件时, 默认将自动应用下列样式: WS_VSCROLL, ES_WANTRETURN 和 ES_AUTOVSCROLL.

如果一个编辑控件被自动检测为单行, 那么它默认含有 ES_AUTOHSCROLL.

样式 | Hex | 描述
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 控件样式

这些样式会影响到 UpDown 控件. 默认情况下, 它使用 UDS_ARROWKEYS, UDS_ALIGNRIGHT, UDS_SETBUDDYINT 和 UDS_AUTOBUDDY. 它没有强制样式.

样式 | Hex | 描述
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 | 让控件展示 "热跟踪" 行为. 即鼠标从控件按钮上经过时高亮控件按钮. 如果桌面主题覆盖了这个标志, 那么这个标志可能会被忽略.

Picture 控件样式

这些样式会影响到 Picture 控件. 他没有默认样式. 样式 SS_ICON(图标和光标) 或 SS_BITMAP(其他图片类型) 总是被启用而不能被禁用.

样式 | Hex | 描述
SS_REALSIZECONTROL | 0x40 | 调整位图以适应控件的大小.
SS_CENTERIMAGE | 0x200 | 让位图在控件中居中显示. 如果位图太大, 则会对其进行裁剪.

Button, CheckBox, Radio 和 GroupBox 控件样式

这些样式会影响到 Button, CheckBox, Radio 或 GroupBox 控件.

默认情况下, 除了 GroupBox 之外, 这些控件都使用 BS_MULTILINE(除非它没有显式设置宽度或高度, 或在其文本中没有任何 CR/LF 字符) 和 WS_TABSTOP(然而, 对于 Radio 控件, 每个单选按钮组中除首个外的其他单选按钮没有 WS_TABSTOP).

以下样式总是被启用, 不能被禁用:

  • Button: BS_PUSHBUTTON 或 BS_DEFPUSHBUTTON
  • CheckBox: BS_AUTOCHECKBOX 或 BS_AUTO3STATE
  • Radio: BS_AUTORADIOBUTTON
  • GroupBox: BS_GROUPBOX
样式 | Hex | 描述
BS_AUTO3STATE | 0x6 | 创建一个与三态复选框相同的按钮, 但该框在用户选择时更改其状态. 状态在选中, 不确定和清除之间循环.
BS_AUTOCHECKBOX | 0x3 | 创建一个与复选框相同的按钮, 但每次用户选择复选框时, 复选框状态在选中和清除之间自动切换.
BS_AUTORADIOBUTTON | 0x9 | 创建一个与单选按钮相同的按钮, 但每次用户选中它时, 系统自动将按钮的选中状态设置为选中, 并自动将同一组中所有其他按钮的选中状态设置为清除.
BS_LEFT | 0x100 | +/-Left. 左对齐文本.
BS_PUSHBUTTON | 0x0 | 创建一个按钮, 当用户选择该按钮时, 将 WM_COMMAND 消息发布到所有者窗口.
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_NOTIFY | 0x4000 | 启用按钮以将 BN_KILLFOCUS 和 BN_SETFOCUS 通知代码发送到其父窗口. 请注意, 无论是否具有此样式, 按钮都会发送 BN_CLICKED 通知代码. 要获取 BN_DBLCLK 通知代码, 该按钮必须具有 BS_RADIOBUTTON 或 BS_OWNERDRAW 样式.
BS_TOP | 0x400 | 把文本放到控件可用高度的顶部.
BS_VCENTER | 0xC00 | 在控件的可用高度内垂直居中显示文本.
BS_FLAT | 0x8000 | 指定按钮为二维的; 它不使用默认的底纹来创建三维效果.
BS_GROUPBOX | 0x7 | 创建一个矩形, 其中可以对其他控件进行分组. 与此样式关联的任何文本都显示在矩形的左上角.

DropDownList 和 ComboBox 控件样式

这些样式会影响到 DropDownList 和 ComboBox 控件.

默认情况下, 这些控件都使用 WS_TABSTOP. 此外, DropDownList 控件使用 WS_VSCROLL, 而 ComboBox 控件使用 WS_VSCROLL 和 CBS_AUTOHSCROLL.

以下样式总是被启用, 不能被禁用:

  • DropDownList: CBS_DROPDOWNLIST
  • ComboBox: CBS_DROPDOWN 或 CBS_SIMPLE
样式 | Hex | 描述
CBS_AUTOHSCROLL | 0x40 | +/-Limit. 当用户在行末输入时会自动滚动编辑控件中的文本到右边. 如果未设置此样式, 那么只能输入在矩形边界中能容纳的文本数量.
CBS_DISABLENOSCROLL | 0x800 | 当列表框中不包含需要滚动的足够项目时, 在其中显示被禁用的垂直滚动条. 不含有此样式时, 当列表框中没有包含足够的项目时隐藏滚动条.
CBS_DROPDOWN | 0x2 | 与 CBS_SIMPLE 类似, 只是除非用户选择编辑控件旁边的图标, 否则不会显示列表框.
CBS_DROPDOWNLIST | 0x3 | 与 CBS_DROPDOWN 类似, 不同之处在于编辑控件被静态文本项替换, 该文本项在列表框中显示当前选择.
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 控件样式

这些样式会影响到 ListBox 控件. 默认情况下, 它使用 WS_TABSTOP, LBS_USETABSTOPS, WS_VSCROLL 和 WS_EX_CLIENTEDGE(扩展样式 E0x200). 样式 LBS_NOTIFY(支持检测双击) 总是被启用, 不能被禁用.

样式 | Hex | 描述
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_NOTIFY | 0x1 | 每当用户单击列表框项目(LBN_SELCHANGE), 双击项目(LBN_DBLCLK), 或取消选择(LBN_SELCANCEL) 时, 列表框就会向父窗口发送通知代码.
LBS_SORT | 0x2 | +/-Sort. 按字母顺序排列列表框中的项目.
LBS_USETABSTOPS | 0x80 | 启用在描绘列表框的字符串时识别并扩展 tab 字符. 默认制表符位置为 32 个对话框单位. 一个对话框单位等于当前对话框基础宽度单位的四分之一.

ListView 控件样式

这些样式会影响到 ListView 控件. 默认情况下, 它使用 WS_TABSTOP, LVS_REPORT, LVS_SHOWSELALWAYS, LVS_EX_FULLROWSELECT, LVS_EX_HEADERDRAGDROP 和 WS_EX_CLIENTEDGE(扩展样式 E0x200). 它没有强制样式.

样式 | Hex | 描述
LVS_ALIGNLEFT | 0x800 | 在图标和小图标视图中左对齐项目.
LVS_ALIGNTOP | 0x0 | 在图标和小图标视图中把项目和列表视图控件的顶部对齐. 这是默认的.
LVS_AUTOARRANGE | 0x100 | 在图标和小图标视图中让图标自动保持排列.
LVS_EDITLABELS | 0x200 | +/-ReadOnly. 指定 -ReadOnly(或 +0x200) 可以让用户编辑每行首个字段.
LVS_ICON | 0x0 | +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. 与上面相同, 不过这里是降序排列.

扩展 ListView 样式 与 Gui 方法/属性一起使用时, 需要 LV 前缀. 某些在 Windows XP 或更高版本中引入的扩展样式未在此列出. 有关完整列表, 请参阅 Microsoft Docs: Extended List-View Styles.

扩展样式 | Hex | 描述
LVS_EX_BORDERSELECT | LV0x8000 | 选择一个项目后, 会改变其背景颜色而不进行高亮(在最近的操作系统中可能不起作用).
LVS_EX_CHECKBOXES | LV0x4 | +/-Checked. 为每个项目显示一个复选框. 设置此样式后, 控件会使用 DrawFrameControl 创建和设置含两个图像的状态图像列表. 状态图像 1 为未选中的方框, 而状态图像 2 为选中的方框. 设置状态图像为零会移除复选框. 除了平铺视图模式外, 所有列表视图模式中的复选框是可见并具有功能的. 在平铺视图模式中点击复选框仅选择项目; 状态不会发生变化.
LVS_EX_DOUBLEBUFFER | LV0x10000 | 通过双缓冲绘图, 能减少闪烁. 此扩展样式还可以在受支持的系统上激活 alpha-混合 选取框选择.
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 | 当列表视图控件使用此样式时, 在显示项目的工具提示前会发送 LVN_GETINFOTIP 通知消息到父窗口.
LVS_EX_LABELTIP | LV0x4000 | 在任何列表视图模式中如果部分隐藏的标签没有工具提示文本, 那么列表视图控件会展开此标签. 如果未设置此样式, 那么列表视图控件只会在大图标模式中才展开部分隐藏的标签.
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 | 在图标视图中, 将项目的状态图像移动到大图标效果图的右上角. 不影响图标视图外的其他视图. 当用户使用空格键改变状态时, 会循环改变所有选定项目的状态, 而不是含有焦点的项目.
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 控件样式

这些样式会影响到 TreeView 控件. 默认情况下, 它使用 WS_TABSTOP, TVS_SHOWSELALWAYS, TVS_HASLINES, TVS_LINESATROOT, TVS_HASBUTTONS 和 WS_EX_CLIENTEDGE(扩展样式 E0x200). 它没有强制样式.

样式 | Hex | 描述
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 控件样式

这些样式会影响到 DateTime 控件. 默认情况下, 它使用 DTS_SHORTDATECENTURYFORMAT 和 WS_TABSTOP. 它没有强制样式.

样式 | Hex | 描述
DTS_UPDOWN | 0x1 | 在控件右边提供 up-down 控件来修改日期和时间的值, 这会替换其他的可用下拉月历.
DTS_SHOWNONE | 0x2 | 在控件中显示复选框, 取消选中此复选框可以让控件不选择日期/时间. 每当控件中没有日期/时间时, Gui.Submit 和 GuiControl.Value 将获取到空值(空字符串).
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. 让日历在控件的右边拉下而不是左边.

MonthCal 控件样式

这些样式会影响到 MonthCal 控件. 默认情况下, 它使用 WS_TABSTOP. 它没有强制样式.

样式 | Hex | 描述
MCS_DAYSTATE | 0x1 | 让控件发送 MCN_GETDAYSTATE 通知来请求哪些日子应以粗体显示的信息. [尚未支持]
MCS_MULTISELECT 0x2

命名选项 "Multi". 允许用户选择日期范围而不限制为单个日期. 默认情况下, 最大的范围为 366 天, 此设置可以通过给控件发送 MCM_SETMAXSELCOUNT 消息改变. 例如:

SendMessage 0x1004, 7, 0, "SysMonthCal321", MyGui ; 7 天. 0x1004 为 MCM_SETMAXSELCOUNT.
MCS_WEEKNUMBERS | 0x4 | 在每行日子的左边显示周数(1-52). Week 1 被定义为至少包含四天的第一周.
MCS_NOTODAYCIRCLE | 0x8 | 禁止控件中当前日期的往复循环.
MCS_NOTODAY | 0x10 | 禁止在控件的底部显示今天的日期.

Slider 控件样式

这些样式会影响到 Slider 控件. 默认情况下, 它使用 WS_TABSTOP. 它没有强制样式.

样式 | Hex | 描述
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

让控件仅显示选择范围. 在选择范围起始位置和结束位置的刻度线显示为三角形(而不是垂直的短划线), 且高亮选择范围(可能需要使用 GuiObj.Opt("-Theme") 移除主题才能高亮).

要设置选择范围, 请参照此例, 这里设置起始位置为 55 而结束位置为 66:

SendMessage 0x040B, 1, 55, "msctls_trackbar321", WinTitle
SendMessage 0x040C, 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 控件样式

这些样式会影响到 Progress 控件. 它既没有默认样式, 也没有强制样式.

样式 | Hex | 描述
PBS_SMOOTH | 0x1 | +/-Smooth. 进度条使用平滑滚动条而不是默认分段的条来显示进度状态. 含有此样式时, 在 Windows XP 或更高版本中控件会自动恢复到经典主题外观.
PBS_VERTICAL | 0x4 | +/-Vertical. 进度条垂直地显示进度状态, 从底部到顶部.
PBS_MARQUEE | 0x8 | 进度条会像大盖帽一样移动; 即每次移动时条会沿着其可用长度向前滑动直到碰到另一端. 含有此样式的条没有明确的位置. 相反, 每次试图改变位置时进度条将移动一格. 此样式常用来指示一个正在进行的完成时间未知的操作.

Tab 控件样式

这些样式会影响到 Tab 控件. 默认情况下, 它使用 WS_TABSTOP 和 TCS_MULTILINE. 样式 WS_CLIPSIBLINGS 总是被启用而不能被禁用, 而 TCS_OWNERDRAWFIXED 则根据控件的背景颜色和/或文本颜色的要求强制开启或关闭.

样式 | Hex | 描述
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 | 0x0 | +/-Wrap. 让所有选项卡显示在一行中. 必要时用户可以滚动来查看到更多的选项卡. 此样式是默认的.
TCS_MULTILINE | 0x200 | +/-Wrap. 必要时让选项卡显示在多行中, 这样可以同时看到所有的选项卡.
TCS_RIGHTJUSTIFY | 0x0 | 这是默认的. 必要时增加每个选项卡的宽度, 这样每行的选项卡会充满选项卡控件的全部宽度. 只有同时使用 TCS_MULTILINE 样式时此窗口样式才有效.
TCS_FIXEDWIDTH | 0x400 | 让所有选项卡使用相同的宽度. 此样式不能和 TCS_RIGHTJUSTIFY 样式一起组合使用.
TCS_RAGGEDRIGHT | 0x800 | 不会拉伸每行的选项卡来充满控件的全部宽度. 此样式是默认的.
TCS_FOCUSONBUTTONDOWN | 0x1000 | 点击时选项卡控件会获取输入焦点.
TCS_OWNERDRAWFIXED | 0x2000 | 父窗口负责描绘选项卡.
TCS_TOOLTIPS | 0x4000 | 选项卡控件有与其关联的工具提示控件.
TCS_FOCUSNEVER | 0x8000 | 点击时选项卡控件不获取输入焦点.

StatusBar 控件样式

这些样式会影响到 StatusBar 控件. 默认情况下, 它使用 SBARS_TOOLTIPS 和 SBARS_SIZEGRIP(后者只有在窗口可调整大小的情况下才会出现). 它没有强制样式.

样式 | Hex | 描述
SBARS_TOOLTIPS 0x800

当鼠标悬停在状态栏部分上时显示工具提示: 1) 文本过多以致无法完全显示; 或 2) 含有图标但没有文本.

工具提示的文本可以使用下面的方法设置:

SendMessage 0x411, 0, StrPtr("Text to display"), "msctls_statusbar321", MyGui ; 0x0411 is SB_SETTIPTEXTW.

上面的粗体 0 是从零开始的状态栏部分的编号. 要使用首个外的其他部分, 对第二个指定 1, 对第三个指定 2, 等等. 注意: 在某些操作系统版本中可能永远不会显示工具提示.
SBARS_SIZEGRIP | 0x100 | 在状态栏的右端包含一个大小调整手柄. 大小调整手柄类似于大小调整边框; 它是一个矩形区域, 用户可以点击并拖动它来调整父窗口的大小.


线程 - 行为 & 优先级 | AutoHotkey v2

线程

当前线程 的定义为最近事件调用的执行流; 例如包括热键, 计时器子程序, 自定义菜单项和 GUI 事件. 当前线程 可以在其自身子程序或该子程序调用的其他子程序中执行函数.

尽管 AutoHotkey 实际上并不支持多线程, 但它模拟了多线程的某些特性: 如果启动了第二个线程 -- 例如在前一个线程仍在执行时按下另一个热键 -- 那么 当前线程 会被中断(暂时停止) 以允许新线程变为 当前线程. 如果在第二个线程还在运行时又启动了第三个线程, 那么第二个和第一个线程都会进入休眠状态, 依此类推.

当 当前线程 结束时, 将恢复执行最近中断的线程, 依此类推, 直到所有线程最终结束. 当线程被恢复时, 它的设置例如 SendMode 和 SetKeyDelay 会自动恢复到中断前的状态; 换句话说, 中断不会给线程带来副作用(活动窗口可能发生的更改除外).

注意: KeyHistory 函数/菜单项会显示处于中断状态的线程数量, 而 ListHotkeys 函数/菜单项则显示拥有线程的热键.

一个脚本可以有多个同时发生的 MsgBox, InputBox, FileSelect 和 DirSelect 对话框. 这是在前一个线程已经显示对话框时, 通过启动一个新的线程(通过热键, 计时器子程序, 自定义菜单项, 等.) 来实现的.

默认情况下, 如果给定的热键或热字串子程序已经在运行, 则不能再次启动. 请使用 #MaxThreadsPerHotkey 来改变此特性.

相关: Thread 函数用于设置线程的优先级或中断性.

线程优先级

任何优先级低于 当前线程 的线程(热键, 计时子程序, 自定义菜单项, 等.), 不能中断当前线程. 在这种时候, 如计时器不会运行, 任何用户创建线程(如, 通过按下热键或 GUI 按钮) 的尝试都不会产生任何效果, 也不会被缓存起来. 由于这个原因, 通常在设计时最好让高优先级的线程快速结束, 或使用 Critical 而不将它们设置成高优先级.

默认的优先级为 0. 所有线程使用默认的优先级, 不过可以使用下列的其中一种方法来改变:

  • 通过 SetTimer 给计时子程序指定优先级.
  • 通过 Hotkey 函数给热键指定优先级.
  • 在定义热字串时指定优先级, 或通过 #Hotstring 指令给热字串指定优先级.
  • 通过 Menu.Add 方法给自定义菜单项指定优先级.
  • 通过 Thread 函数给 当前线程 设置自己的优先级.

不论 当前线程 的优先级如何, OnExit 回调函数(如果有) 被调用时总是会运行.

线程可中断性

对于大多数类型的事件, 只有在当前线程 可中断 的情况下, 才允许启动新的线程. 一个线程可以因为一些原因而 不可中断, 包括:

  • 线程已被标记为 critical. Critical 可能已经被线程本身或被自动执行线程调用.
  • 线程运行时间不够长, 无法满足线程中断设置的成为可中断的条件, 如 Thread Interrupt 设置的.
  • 脚本的一个菜单正在显示(如托盘图标菜单或菜单栏).
  • Send(最常见的是由于 SetKeyDelay), WinActivate 或 Clipboard 操作正在执行延迟.
  • OnExit 线程正在执行.
  • 由于达到了 A_MaxHotkeysPerInterval 的限制, 或者由于激活键盘或鼠标钩子的问题(非常罕见), 正在显示一个警告对话框.

不可中断线程的特性

与高优先级线程不同, 线程不可中断时产生的事件不会被丢弃. 例如, 在当前线程不可中断时用户按下了热键热键就会被无限期地缓冲, 直到当前线程结束或变得可中断时, 热键才作为新的线程启动.

在紧急情况下, 任何线程都可能被中断. 紧急情况包括:

  • 一个 OnExit 回调.
  • 任何监视没有缓冲的消息的 OnMessage 函数.
  • 任何由线程自身间接触发的回调(例如, 通过 SendMessage 或 DllCall).

要避免被这些事件中断, 可以临时禁用这些函数.

当显示 MsgBox 或其他对话框时, critical 会变得可中断. 但与 Thread Interrupt 不同的是, 在用户解除对话框后, 线程又变成了 critical(因此不可中断).


Automating Winamp | AutoHotkey v2

自动化 Winamp

这个页面演示了即使 Winamp 处于最小化或不活动状态时如何通过热键控制它. 这些代码已经在 Winamp 2.78c 上测试成功, 在其他主要版本应该也能良好运行. 请提交改进改进方法到论坛.

这个例子设置 Ctrl+Alt+P 热键为按下 Winamp 的暂停/取消暂停按钮:

^!p::
{
    if not WinExist("ahk_class Winamp v1.x")
        return
; 否则, 上面设置了下面要使用的 "上次找到的" 窗口.
ControlSend "c"  ; 暂停/取消暂停
}

这里是 Winamp 2.x (在其他版本中可能也有效) 中的一些快捷键. 上面的例子可以改用这些按键:

要发送的键 | 效果
c | 暂停/取消暂停
x | 播放/重放/取消暂停
v | 停止
+v | 渐隐停止
^v | 当前音轨结束后停止
b | 下一首
z | 上一首
{left} | 后退 5 秒
{right} | 前进 5 秒
{up} | 增大音量
{down} | 减小音量

下面这个例子获取 Winamp 中当前活动的音轨号:

TrackNumber := SendMessage(0x0400, 0, 120,, "ahk_class Winamp v1.x")
if (TrackNumber != "")
{
    TrackNumber += 1  ; Winamp 的计数从 0 开始, 所以加 1 进行调整.
    MsgBox "Track #" TrackNumber " is active or playing."
}


WinTitle & Last Found Window | AutoHotkey v2

WinTitle 参数 & 最近找到的窗口

许多内置函数都有 WinTitle 参数, 用于识别要操作的窗口. 此参数可以是窗口的标题或部分标题, 和/或本页上描述的任何其他条件.

目录

  • 窗口标题 & 匹配行为
  • A(活动窗口)
  • ahk_ Criteria
    • ahk_class(窗口类)
    • ahk_id(唯一 ID / HWND)
    • ahk_pid(进程 ID)
    • ahk_exe(进程名称/路径)
    • ahk_group(窗口组)
  • 多重条件
  • 上次找到的窗口

窗口标题 & 匹配行为

为 WinTitle 指定任意字符串, 以通过其标题标识窗口. 窗口的标题通常以文本的形式出现在窗口顶部的标题栏中. 如果不可见或只有部分可见, 完整的窗口标题可以通过 WinGetTitle 或 Window Spy 显示.

下面的例子激活计算器:

WinActivate "计算器"

SetTitleMatchMode 控制如何将部分或完整标题与每个窗口的标题进行比较. 根据这个设置, WinTitle 可以是完全匹配的标题, 也可以包含前面部分, 标题中任何位置出现的子字符串或 RegEx 模式. 该设置还控制 ahk_class 和 ahk_exe 是否解释为 RegEx 模式.

窗口标题是区分大小写的, 除非在 RegEx 模式中使用 i) 修饰符.

仅当 DetectHiddenWindows 被的打开时, 才会检测隐藏窗口, 但 WinShow 除外, 它总是检测隐藏窗口.

如果多个窗口与 WinTitle 和其他任何条件匹配, 则使用最顶层的匹配窗口. 如果活动窗口匹配条件, 则它通常优先, 因为它一般在其他所有窗口的上面. 然而, 如果某个置顶的窗口也匹配条件(且活动窗口没有置顶), 则使用这个置顶窗口.

在 [v2.0.6+] 中, 不再只考虑指定的窗口标题, ahk_class 条件值和 ahk_exe 条件值的前 1023 个字符进行匹配. 超出长度不再导致意外的结果, 这种情况很少发生, 但如果使用非常长的 RegEx 模式, 可能会更频繁地遇到这种情况.

A(活动窗口)

使用字母 A 表示 WinTitle, 并省略其他三个窗口参数(WinText, ExcludeTitle 和 ExcludeText), 对活动窗口进行操作.

以下示例检索并报告活动窗口的唯一 ID(HWND):

MsgBox WinExist("A")

下面的例子创建了一个热键, 按下它可以使活动窗口最大化:

#Up::WinMaximize "A"  ; Win+Up

ahk_ 条件

指定一个或多个下面的 ahk_ 条件(可选, 除了窗口标题), 每一个都用 一个 空格或制表符与下一个隔开(任何其他空格或制表符都被视为前一个条件的文字部分). 一个 ahk_ 条件总是由一个 _ahk 关键字和它的条件值组成, 使用零或多个空格或制表符分隔. 例如, ahk_class Notepad 表示一个记事本窗口.

ahk_ 关键字和它的条件值不需要用空格或制表符来分隔. 这主要是在指定 ahk_ 条件值为表达式并与变量结合时有用. 例如, 可以指定 "ahk_pid" PID 而不是 "ahk_pid " PID. 然而, 在所有其他情况下, 建议使用至少一个空格或制表符作为分隔, 以提高可读性.

ahk_class(窗口类)

在 WinTitle 中使用 ahk_class ClassName 通过其窗口类来识别窗口.

窗口类是系统用来创建窗口的模板的属性集. 换句话说, 窗口类表示窗口的 类型. 窗口类可以通过 Window Spy 来显示或通过 WinGetClass 获取. 如果 RegEx 标题匹配模式被激活, ClassName 接受正则表达式.

窗口类区分大小写, 但在 RegEx 模式中使用 i) 修饰符时除外.

下面的例子激活了一个控制台窗口(例如 cmd.exe):

WinActivate "ahk_class ConsoleWindowClass"

下面的示例与上面的相同, 但使用了正则表达式(注意必须事先打开 RegEx 标题匹配模式才行):

WinActivate "ahk_class ^ConsoleWindowClass$"

ahk_id(唯一 ID / HWND)

每个窗口或控件都有一个唯一 ID, 也被称为 HWND(即窗口句柄的缩写). 即使其标题或文本更改了, 此 ID 也可用于标识窗口或控件.

在 WinTitle 中使用 ahk_id HWND 或纯 HWND(作为一个整数或带有 HWND 属性的对象) 通过其唯一的 ID 来识别窗口或控件.

当使用 ahk_id HWND 时, DetectHiddenWindows 影响是否检测隐藏的顶级窗口, 但总是检测隐藏的控件. 当使用纯 HWND 时, 无论 DetectHiddenWindows 是否存在, 都会检测隐藏窗口. WinWait 和 WinWaitClose 是一个例外, 其中 ahk_id HWND 和纯 HWND 都受到 DetectHiddenWindows 的影响.

ahk_id HWND 条件也可以和给定窗口必须匹配的其他条件相结合. 例如, WinExist("ahk_id " ahwnd " ahk_class " aclass) 在窗口被 "检测到"(根据 DetectHiddenWindows) 且其窗口类别与 aclass 所包含的字符串相匹配时, 返回 ahwnd.

窗口的 ID 通常通过 WinExist 或 WinGetID 来检索. 控件的 ID 通常通过 ControlGetHwnd, MouseGetPos 或 DllCall 来检索. Gui 和 GuiControl 对象具有 Hwnd 属性, 因此可以直接在 WinTitle 中使用.

下面的示例通过存储在 VarContainingID 中的唯一 ID 对窗口进行操作:

; 传递一个整数.
WinActivate Integer(VarContainingID)
WinShow A_ScriptHwnd
WinWaitNotActive WinExist("A")

; 传递一个具有 HWND 属性的 对象.
WinWaitClose myGuiObject

; 使用 ahk_id 前缀.
WinActivate "ahk_id " VarContainingID	WinActivate "ahk_id " VarContainingID

如果对象没有 HWND 属性或该属性的值不是整数, 则抛出 PropertyError 或 TypeError.

ahk_pid(进程 ID)

在 WinTitle 中使用 ahk_pid PID 来识别属于特定进程的窗口. 进程标识符(PID) 通常由 WinGetPID, Run 或 Process 函数检索. 窗口的进程 ID 可以通过 Window Spy 来显示.

下面的例子是通过存储在 VarContainingPID 中的进程 ID 来激活一个窗口:

WinActivate "ahk_pid " VarContainingPID

ahk_exe(进程名称/路径)

在 WinTitle 中使用 ahk_exe ProcessNameOrPath 来识别属于任何具有给定名称或路径的进程的窗口.

ahk_pid 条件仅限于一个特定的进程, 而 ahk_exe 条件则考虑所有名称或完整路径与给定字符串相匹配的进程. 如果 RegEx 标题匹配模式处于活动状态, ProcessNameOrPath 接受正则表达式, 该表达式必须匹配进程的完整路径. 否则, 它接受不区分大小写的名称或完整路径; 例如, ahk_exe notepad.exe 涵盖了 ahk_exe C:\Windows\Notepad.exe, ahk_exe C:\Windows\System32\Notepad.exe 和其他变体. 窗口的进程名称可以通过 Window Spy 显示出来.

下面的例子是通过进程名称来激活一个记事本窗口:

WinActivate "ahk_exe notepad.exe"

下面的示例与上面的相同, 但使用了正则表达式(注意必须事先打开 RegEx 标题匹配模式才行):

WinActivate "ahk_exe i)\\notepad\.exe$"  ; 匹配完整路径的名称部分.

ahk_group(窗口组)

在 WinTitle 中使用 ahk_group GroupName 来识别与先前定义的窗口组

WinMinimize, WinMaximize, WinRestore, WinHide, WinShow, WinClose 和 WinKill 将对组中的 所有 窗口进行操作. 相比之下, 其他窗口函数(如 WinActivate 和 WinExist) 仅对组中最顶层的窗口进行操作.

以下示例将激活任何符合窗口组定义标准的任何窗口:

; 定义组: 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."

"上次找到的" 窗口

"上次找到的" 窗口是由最近的 WinExist, WinActive, WinWait[Not]Active 或 WinWait 发现的窗口. 这样可以让脚本更容易创建和维护, 因为目标窗口的 WinTitle 和 WinText 不需要在每个窗口函数中重复. 此外, 脚本会执行的更好, 因为在首次找到目标窗口后这些函数不需要再次搜索目标窗口.

"上次找到的" 窗口可以用于除 WinWait, WinActivateBottom, GroupAdd, WinGetCount 和 WinGetList 以外的所有窗口函数. 要使用它, 只需简单地省略所有的四个窗口参数(WinTitle, WinText, ExcludeTitle 和 ExcludeText).

每个线程保留自己的 "上次找到的" 窗口值, 这意味着如果当前线程被其他线程中断, 当原始线程恢复时它仍会拥有它原来的 "上次找到的" 窗口值, 而不是中断线程的值.

如果上次找到的窗口是一个隐藏的 Gui 窗口, 那么即使 DetectHiddenWindows 被关闭, 也可以使用它. 这通常与 GUI 的 +LastFound 选项一起使用.

下面的例子打开记事本, 等待直到它存在并激活:

Run "Notepad"
WinWait "Untitled - Notepad"
; WinWait "无标题 - 记事本"
WinActivate  ; 使用由 WinWait 找到的窗口.

下面的例子是激活并最大化由 WinExist 找到的记事本窗口:

if WinExist("Untitled - Notepad")
; if WinExist("无标题 - 记事本")
{
    WinActivate  ; 使用由 WinExist 找到的窗口.
    WinMaximize  ; 同上
    Send "Some text.{Enter}"
}

下面的例子激活由 WinExist 找到的计算器, 并移动它到一个新的位置:

if not WinExist("Calculator")
{
    ; ...
}
else
{
    WinActivate  ; 使用由 WinExist 找到的窗口.
    WinMove 40, 40  ; 同上.
}


Script 脚本展示 | AutoHotkey v2

AutoHotkey 脚本展示

本展示列出了一些由不同作者创建的脚本, 展示了 AutoHotkey 可能具备的能力. 获取更多可运行的脚本和函数, 请访问 AutoHotkey v2 Scripts and Functions Forum.

目录

  • Context Sensitive Help in Any Editor
  • Easy Window Dragging
  • Easy Window Dragging (KDE style)
  • Easy Access to Favorite Folders
  • Using a Controller as a Mouse
  • Controller Test Script
  • On-Screen Keyboard
  • Minimize Window to Tray Menu
  • Changing MsgBox's Button Names
  • Numpad 000 Key
  • Using Keyboard Numpad as a Mouse
  • Seek (Search the Start Menu)
  • ToolTip Mouse Menu
  • Volume On-Screen-Display (OSD)
  • Window Shading
  • WinLIRC Client
  • HTML Entities Encoding
  • Custom Increments for UpDown Controls
  • AutoHotkey v1 Scripts and Functions Forum

Context Sensitive Help in Any Editor(任意编辑器中的上下文相关帮助)

基于 Rajat 编写的 v1 脚本

此脚本设置 Ctrl+2(或您选择的其他热键) 来显示选择的 AutoHotkey 函数或关键字的帮助文件页面. 如果没有选择任何内容, 那么会提取当前行开始处的函数名.

显示代码

Easy Window Dragging(轻松拖曳窗口)

一般情况下, 只能通过点击标题栏来拖动窗口. 这个脚本扩展到可以在窗口中任何一点拖动窗口. 要激活这种模式, 请在点击时按住 CapsLock 或鼠标中键, 然后拖动窗口到新的位置.

显示代码

Easy Window Dragging(轻松拖曳窗口 KDE 风格)

基于 Jonny 编写的 v1 脚本

使用此脚本可以轻松移动窗口或改变它的大小: 1) 按住 Alt 键并在窗口内的任意位置点击左键来拖动窗口到新的位置; 2) 按住 Alt 并在窗口内任意位置点击右键后拖动来轻松调整它的大小; 3) 按下 Alt 两次, 但在第二次松开前, 点击左键来最小化鼠标光标下的窗口, 点击右键进行最大化或点击中键进行关闭.

显示代码

Easy Access to Favorite Folders(轻松访问收藏夹)

基于 Savage 编写的 v1 脚本

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

显示代码

Using a Controller as a Mouse(把控制器当作鼠标)

此脚本把控制器转换为三键的鼠标. 它允许每个按钮像鼠标按钮那样拖动, 且它几乎不消耗 CPU 时间. 还有, 您将手柄推离中央越远, 它会让光标移动的越快. 您可以在脚本的顶部个性化各种设置.

注意: 对于 Xbox 控制器 2013 和更新的版本(任何比 Xbox 360 控制器更新的版本), 这个脚本只有在它拥有的窗口处于活动状态时才会工作, 例如消息框, GUI, 或脚本主窗口.

显示代码

Controller Test Script(控制器测试脚本)

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

显示代码

On-Screen Keyboard(屏幕键盘)

基于 Jon 编写的 v1 脚本

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

显示代码

Minimize Window to Tray Menu(最小化窗口到托盘菜单)

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

显示代码

Changing MsgBox's Button Names(改变 MsgBox 的按钮名称)

这是个可运行示例脚本, 它使用计时器来改变消息框中按钮的名称. 尽管改变了按钮名称, 但 IfMsgBox 的返回值仍需要引用它们原始的按钮名称表示的按钮.

显示代码

Numpad 000 Key

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

显示代码

Using Keyboard Numpad as a Mouse(把小键盘作为鼠标使用)

基于deguix 编写的 v1 脚本

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

显示代码

Seek(搜索开始菜单)

基于 Phi 编写的 v1 脚本

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

显示代码

ToolTip Mouse Menu(鼠标菜单型的工具提示)

基于 Rajat 编写的 v1 脚本

此脚本显示弹出菜单来响应短暂地按住鼠标中键的动作. 左键点击来选择菜单项. 在菜单外点击来取消菜单. 最近的改进是可以根据活动的窗口类型来改变菜单的内容(这里使用了记事本和 Word 作为例子).

显示代码

Volume On-Screen-Display(OSD 音量)

基于 Rajat 编写的 v1 脚本

这个脚本指定了你选择的热键来提高和降低主音量.

显示代码

Window Shading(窗口遮帘)

基于 Rajat 编写的 v1 脚本

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

显示代码

WinLIRC Client(WinLIRC 客户端)

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

显示代码

HTML Entities Encoding

类似于 AutoHotkey v1 的 Transform HTML, 该函数通过将 ASCII 值高于 127 的字符转换成其 HTML 名称, 来将字符串转换为 HTML 等价物(例如 £ 变成 &pound;). 此外, 这四个字符 "&<> 被转换为 &quot;&amp;&lt;&gt;. 最后, 每个换行符(`n) 被转换为 <br>`n(即 <br> 后面跟着一个换行符).

显示代码

Custom Increments for UpDown Controls

基于 numEric 的 v1 脚本.

这个脚本演示了如何将 UpDown 的增量更改为 1 以外的值(例如 5 或 0.1).

显示代码

AutoHotkey v1 Scripts and Functions Forum(AutoHotkey v1 脚本与函数论坛)

这个论坛包含了更多的脚本, 但大多数脚本在 AutoHotkey v2.0 上都无法正常运行.

AutoHotkey v1 Scripts and Functions Forum

隐藏代码

加载代码...