# AutoHotkey 初学者向导 by tidbit

## 目录表

1. 基础
   1. 下载和安装 AutoHotkey
   2. 如何创建一个脚本
   3. 你不能合并命令
   4. 如何在你的电脑上找到帮助文件
2. 热键 & 热字符串
   1. 按键和其神秘符号
   2. 窗口特定的热键/热字符串
   3. 一个脚本里使用多个热键/热字串
   4. 示例
3. 发送按键
   1. 游戏
4. 打开程序 & 网站
5. 命令 vs. 函数
   1. 代码块
6. 变量
   1. 什么时候使用百分号
   2. 获取用户输入
   3. 其他示例?
7. 对象
   1. 创建对象
   2. 使用对象
8. 其他有用的东西
   1. 神秘的方括号 [ ]
   2. 查找你的 AHK 版本
   3. 尝试与错误
   4. 缩进
   5. 寻求帮助
   6. 其他链接

## 1 - 基础

在我们开始旅程之前, 请允许我提些建议. 在本向导中, 你会看到大量的文字和代码. 为了更有效的学习, 建议你阅读这些文字并尝试运行这些代码. 然后再深入学习这些代码. 你可以复制并粘贴此页上的大多数示例. 如果你弄糊涂了, 试着再看一遍.

### a. 下载并安装 AutoHotkey

如果你是在本地查看此文档, 你可能已经安装了 AutoHotkey 并且可以跳转到 b 部分.

在学习使用 AutoHotkey(AHK) 之前, 你需要下载它. 下载后, 你可能会需要安装它. 但这取决于你下载的版本. 对于本指南, 我们将使用安装版, 因为对于新手来说, 它最容易设置.

文字指导:

1. 访问 AutoHotkey 主页: https://autohotkey.com/
2. 点击下载: https://autohotkey.com/download/ahk-install.exe
3. 在安装 Autohotkey 过程中, 需要你选择安装 UNICODE 或者 ANSI 版本. 你很可能需要 UNICODE 版本, 简单点说, 如果你想要它支持非英文字符和数字, 那就选择 UNICODE 版. 版本选择之后, 一直点下一步直到你看到安装(Install) 按钮.
4. 装完了? 棒极了! 我们接着往下看.

视频指导, 请在 YouTube(可能您无法打开) 网站观看 Install and Hello World

### b. 如何创建一个脚本

Autohotkey 安装完成后, 你也许会想它能做些什么. AutoHotkey 不是魔法, 虽然我们都希望它是. 所以需要我们告诉它要去干什么. 而这个过程叫做 "写脚本".

文字指导:

1. 右键点桌面空白处.
2. 点击 "新建" 菜单.
3. 点击里面的 "AutoHotkey Script" 新建一个脚本.
4. 给脚本命名. 备注: 文件名必须带 .ahk 后缀, 例如 MyScript.ahk
5. 找到刚刚新建的脚本并右键点击它.
6. 点击 "Edit Script".
7. 一个新窗口被弹出, 也许是记事本. 如果是这样就成功了!

   现在你已经创建了一个脚本, 我们需要加点内容到脚本中. 如果需要用到内置命令, 函数和变量, 请查看第 5 节.

   这是一个使用 Send 命令创建的一个包含热键的简单脚本, 当你按下热键后, 它会向窗口发送一段文字.

       ^j::
       Send, My First Script
       Return

   稍后我们将进行更深入的研究. 在此之前, 我们先解释一下上面的代码:

   - 第一行: `^j::` 是热键. `^` 代表 `Ctrl`, `j` 是字母 `J`. 任何在 `::` 左边的字符表示您需要按下的热键.
   - 第二行: `Send, My First Script` 表示如何发送按键. `Send` 是命令, 任何在逗号(,) 之后的内容将会被键入.
   - 第三行: `Return`. Return 将会成为你最好的朋友. 从字面上看, 它将停止代码继续往下. 当你的脚本包含越来越多的东西时, 使用 Return 会避免很多问题.
8. 保存文件.
9. 双击桌面上的文件来运行它, 打开记事本或者其他可以输入文字的地方然后按下 `Ctrl` 和 `J`.
10. 太好了! 你的第一个脚本完成了. 给自己一些奖励, 然后返回阅读本教程的其余部分.

视频指导, 请在 YouTube 网站观看 Install and Hello World.

### c. 不要合并命令

当你在写代码的时候, 你可能有强烈的冲动想在同一行放下几个命令, 或者在一个命令中嵌套多个命令, 千万不要这样做. 在第 5 节我们将会告诉你为什么不要这么做, 同时, 我们还将告诉你应该怎么做.

### d. 如何在你的电脑上找到帮助文件

有几种方法可以做到这一点, 假设你已将 AutoHotkey 安装到默认位置:

方案 1:

1. 找到开始菜单或屏幕上的开始按钮, 通常在左下角.
2. 点击程序或者所有程序.
3. 在列表中查找 AutoHotkey.
4. 你会看到 AutoHotkey Help File. 点击它.
5. 完成!

方案 2:

1. 去你的桌面.
2. 找到我的电脑或者计算机. 然后打开它.
3. 进入安装 AutoHotkey 的硬盘. 可能是 C:\ 盘.
4. 在 Program Files 文件夹里找到 AutoHotkey.
5. 查找 AutoHotkey.chm 或者找一个名叫 Autohotkey 并带有黄色问号图标的文件.
6. 完成!

## 2 - 快捷键 & 热字串

什么是热键? 热键是一个发热的按键, 开个玩笑. 热键是用来触发某些动作的按键或组合按键. 例如:

    ^j::
       Send, My First Script
    Return

什么是热字串? 当你键入它们时, 热字串主要用于扩展缩写(自动替换). 当然, 它也可以用来启动任何脚本动作. 例如:

    ::ftw::Free the whales

这两个例子的区别在于, 当你按下 `Ctrl`+`J` 时, 热键将会触发, 而热字串会将你输入的 "ftw" 转换为 "Free the whales".

"那么, 该如何创建一个热键?" 好问题. 热键是通过一对 :: 创建的. 按键名或组合按键名必须在 `::` 左边. 代码则跟在下面, 然后以 `Return` 结束.

注意: 当然也有例外情况, 但很多时候容易引起混乱, 所以在向导页中不会涉及到它, 至少不是现在.

    esc::
       MsgBox Escape!!!!
    Return

热字串在要触发文本替换的文本两边各有一对冒号(::). 而替代键入文本的文本在第二对冒号 :: 的右边.

如上所述, 热字串也可以启动脚本动作. 和热键一样能干好多事, 真棒!

    ::btw::
       MsgBox You typed "btw".
    Return

有一个好消息是: 你可以为每一个热键, 热字串, 标签等写上多行的代码.

    ^j::
    MsgBox Wow!
    MsgBox this is
    Run, Notepad.exe
    Winactivate, Untitled - Notepad  ; 无标题 - 记事本
    WinWaitActive, Untitled - Notepad  ; 无标题 - 记事本
    Send, 7 lines{!}{enter}
    SendInput, inside the ctrl{+}j hotkey
    Return

### a. 键和其神秘符号

你可能会问"我怎么知道 ^ 代表 `Ctrl`?!". 好问题! 为了帮助你学习 ^ 和其他符号的意思, 注意看这个表:

符号 | 描述
--- | ---
# | `Win`(Windows 徽标键)
! | `Alt`
^ | `Ctrl`
+ | `Shift`
& | 用于连接两个按键(含鼠标按键) 合并成一个自定义热键.

(完整的符号列表, 请查看热键页面)

此外, 对于所有/大多数能用于热键双冒号左边的热键名称, 请参阅按键列表.

你可以通过在两个按键(除手柄键) 之间, 使用 `&` 来定义一个组合热键. 在下面的例子中, 你要按下 `Numpad0`, 再按下 `Numpad1` 或 `Numpad2`, 才能触发热键:

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

    Numpad0 & Numpad2::
    Run Notepad
    Return

如果你想知道热字串是否和热键一样有很酷的修饰符, 答案是有! 热字串的修饰符在第一对 :: 之间, 例如:

    :*:ftw::Free the whales

想要查看更多关于热键和热字串修饰符的信息和实例, 请访问: 热键和热字串.

### b. 窗口特定的热键/热字串

有时候你也许想要热键或热字串只在某些特定窗口上工作(或禁用). 要做到这一点, 您需要使用其中的任意一个 "高级" 命令, 在它们前面带有一个 #:

    #IfWinActive
    #IfWinExist

这些特殊的命令(技术上称为 "指令") 可以创建对上下文敏感的热键和热字串. 只需指定一个窗口标题. 但在某些情况下, 你可能需要指定一个窗口句柄, 组或类. 如果想深入了解这些高级内容, 点这里: WinTitle 参数 & 最近找到的窗口.

    #IfWinActive Untitled - Notepad  ; 无标题 - 记事本
    #space::
    MsgBox You pressed Win+Spacebar in Notepad.
    Return

要关闭后续热键或热字串的上下文敏感性, 请指定任意 #IfWin 指令, 但将其所有参数留空. 例如:

    ; 无标题 - 记事本
    #IfWinActive Untitled - Notepad
    !q::
    MsgBox, You pressed Alt+Q in Notepad.
    Return

    ; 任何不是无标题 - 记事本的窗口
    #IfWinActive
    !q::
    MsgBox, You pressed Alt+Q in any window.
    Return

当 #ifwin 指令在脚本中从未使用, 所有的热键和热字串对所有窗口生效.

#IfWin 指令是与位置相关的: 它们将影响脚本中的位于他们之间所有热键和热字串. 它们也相互排斥的; 也就是说, 只有最近的一个会有效.

    ; 记事本
    #IfWinActive ahk_class Notepad
    #space::
    MsgBox, You pressed Win+Spacebar in Notepad.
    Return
    ::msg::You typed msg in Notepad

    ; 画图
    #IfWinActive Untitled - Paint  ; 无标题 - 画图
    #space::
    MsgBox, You pressed Win+Spacebar in MSPaint!
    Return
    ::msg::You typed msg in MSPaint!

想要了解更多信息以及相似的命令, 请查看: #IfWinActive 页面.

### c. 一个文件包含多个热键/热字串

这是一些人的想法. 因此, 我在这里声明一下: AutoHotkey 有能力将任意多 的热键和热字串放在一个文件中. 不管是 1 个, 还是 3253 个(或者更多).

    #i::
    Run, https://www.google.com/
    Return

    ^p::
    Run, notepad.exe
    Return

    ~j::
    Send, ack
    Return

    :*:acheiv::achiev
    ::achievment::achievement
    ::acquaintence::acquaintance
    :*:adquir::acquir
    ::aquisition::acquisition
    :*:agravat::aggravat
    :*:allign::align
    ::ameria::America

上面的代码是完全可以接受的. 多个热键, 多个热字串, 都包含在一个大的脚本文件里.

### d. 示例

    ::btw::By the way  ; 替换 "btw" 为 "By the way", 当你按下默认的终止符的时候.

    :*:btw::By the way  ; 替换 "btw" 为 "By the way" 而不需要按下终止符.

    ^n::  ; Ctrl+N 热键.
    Run, notepad.exe  ; 当你按下 Ctrl+N, 将启动记事本.
    Return   ; 热键内容结束. 当按下热键时, 下面的代码不会被执行.

    ^b::  ; Ctrl+B 热键
    Send, {ctrl down}c{ctrl up}  ; 复制选定的文本. 也可以使用 ^c, 但这种方法更加可靠.
    SendInput, [b]{ctrl down}v{ctrl up}[/b] ; 粘贴所复制的文本, 并在文本前后加上加粗标签.
    Return  ; 热键内容结束, 这之后的内容将不会触发.

## 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
    Return

    ; 正确的
    LCtrl::
    Send, AutoHotkey
    Return

很多人都有一个共同的问题, 他们认为花括号(大括号) 放在文档中仅仅是为了好玩. 而实际上花括号是需要的. 它将告诉 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}    ; 然后松开向上键.

现在你可能会想, "怎样才能让我在发送超长文本时保证文本的可读性?". 很简单. 使用我们所说的延续片段. 只需要在新行指定一个开括号, 然后是内容, 最后在它自己的行上加上一个闭括号. 想了解更多信息, 请阅读有关的 Continuation Sections(延续片段).

    Send,
    (
    Line 1
    Line 2
    Apples are a fruit.
    )

注意: Send 命令有几种不同的形式. 每种形式有其特性. 如果一种形式的 Send 命令不能满足你的需要, 可以试试另一种形式. 只需要将 "Send" 命令替换成接下来的其中一个: SendRaw, 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://autohotkey.com/. 如果你想打开一个已经安装好的程序, 也很简单, 就像这样:

    ; 运行一个程序. 注意: 大部分的程序可能需要完整路径.
    Run, %A_ProgramFiles%\Some_Program\Program.exe

    ; 打开一个网址
    Run, https://autohotkey.com

还有其他一些高级特性, 比如命令行参数和 CLSID(Windows 类标识符).

下面是一些关于 Run 命令的示例:

    ; 一些程序并不需要完整路径, 如 Windows 标准程序.
    Run, notepad.exe
    Run, msPaint.exe

    ; 使用 AHK 内置变量来打开 "我的文档"
    Run, %A_MyDocuments%

    ; 打开一些网页:
    Run, https://autohotkey.com
    Run, https://www.google.com

想要深入了解更多信息和示例, 请查看: Run 页面.

## 5 - 命令和函数

AutoHotkey 有两个重要的工具供开发者使用: 命令和函数.

所有命令和内置函数的列表可以在这里找到.

### 命令

你可以通过语法来分辨命令和函数. 命令后面的参数无需使用圆括号, 而函数需要使用. 所以命令就像下面这样:

    Command, 参数1, 参数2, 参数3

当你使用命令时, 不能将几条命令放在同一行(IfEqual 除外). 也不能将一个命令作为参数插入到另一个命令. 例如:

    MsgBox, Hello Run, Notepad.exe   ; 错误
    MsgBox, Hello, Run, Notepad.exe  ; 错误

    MsgBox, Hello      ; 正确
    Run, Notepad.exe

跟函数不同的是, 命令使用 "传统语法". 这意味着 需要 在变量的前后加上 %, 比如 `%Var%`. 而文本和数字则不需要加双引号, 例如 `This is some text`. 另外, 与函数不同, 命令的参数不能进行运算.

如果确实想要在参数中进行运算, 可以使用单个 `%` 来强制定义一个表达式, 但我们这里将不涉及这些内容.

### 函数

如上所述, 函数不同于命令的地方在于函数需要使用圆括号. 一个典型的函数是这样的:

    Function(参数1, 参数2, 参数3)

与命令相比, 函数有下面几个主要差异:

1. 你可以使用运算.

       SubStr(37 * 12, 1, 2)
       SubStr(A_Hour - 12, 2)

2. 变量不需要加上百分号:

       SubStr(A_Now, 7, 2)

3. 函数可以嵌套另一个函数:

       SubStr(A_AhkPath, InStr(A_AhkPath, "AutoHotkey"))

4. 文本前后需要加上双引号:

       SubStr("I'm scripting, awesome!", 16)

函数通常会返回一个值, 这一点与命令也不一样. 命令需要设置 OutputVar 参数来保存结果, 而函数不需要. 将函数值赋给变量的最常用方法, 只需要这样做:

    MyVar := SubStr("I'm scripting, awesome!", 16)

这不是赋值的唯一方法, 但这是最常用的. 您使用 MyVar 来存储函数的返回值, 即写在 := 操作符的右边, 更多信息, 请参阅函数页面.

简而言之:

    ; 这些是命令
    MsgBox, This is some text.
    StringReplace, Output, Input, AutoHotKey, AutoHotkey, ALL
    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, We are now 'outside' of the if-statement. We did not need curly brackets since there was only one line below it.

## 6 - 变量

变量就像一个包含信息的便利贴. 它可以用于函数, 命令或数学表达式中, 充当存储文本, 数字, 数据的作用. 如果没有变量, 程序和脚本将会非常乏味.

给变量赋值有很多方法, 我们将会讨论最常见的几种方法. 请特别留意等号(`=`).

传统的文本赋值

      MyVar = Text

  这是给变量赋值最简单的方法, 也是传统的赋值方法. 只需要在等号后面输入文本就行了.

传统的变量赋值

      MyVar = %MyVar2%

  和上面的方法类似, 只是你将一个变量所对应的值赋给了另一个变量.

传统的混合赋值

      MyVar = %MyVar2% some text %MyVar3%.

  以上两个传统赋值的组合.

表达式文本赋值

      MyVar := "Text"

  这是一个表达式赋值, 因为 `:` 在 `=` 之前. 任何文本都需要在引号中间.

表达式变量赋值

      MyVar := MyVar2

  在表达式模式中, 变量不需要百分号.

表达式数字赋值

      MyVar := 6 + 8 / 3 * 2 - Sqrt(9)

  感谢表达式, 你能进行计算!

表达式混合赋值

      MyVar := "The value of 5 + " MyVar2 " is: " 5 + MyVar2

  以上三个表达式赋值的组合.

等号(=) 和它前面的符号, 如 `:=` `+=` `-=` `.=` 等等, 这些被称为赋值运算符, 并且总是需要一个表达式.

### a. 什么时候使用百分号

关于变量一个最常见的问题是什么时候使用百分号(%). 希望下面这些内容能够消除一些困惑.

什么时候要使用百分号:

- 当你使用命令时(见前文), 参数是输出变量 OutputVar 或输入变量 InputVar 时除外.
- 当你使用传统模式(等号前面没有其他符号) 给一个变量赋值时.

什么时候不要使用百分号:

- 参数中的输入或输出变量. 例如: `StringLen, OutputVar, InputVar`
- 赋值时左边的变量: 例如: `Var = 123abc`
- 在传统 If 语句(不包括表达式) 中, 中左边的变量: `If Var1 < %Var2%`
- 在表达式中的变量, 例如:

      If (Var1 != Var2)
        Var1 := Var2 + 100

### b. 获取用户输入

有时候你想让用户来选择某些值. 这可以有很多种方法, 但其中最简单的办法就是使用 InputBox 命令. 下面的例子展示了如何向用户提出一堆问题并根据用户的输入完成一些事情:

    InputBox, OutputVar, Question 1, What is your first name?
    if (OutputVar="Bill")
       MsgBox, That's an awesome name`, %OutputVar%.

    InputBox, OutputVar2, Question 2, Do you like AutoHotkey?
    if (OutputVar2 = "yes")
       MsgBox, Thank you for answering %OutputVar2%`, %OutputVar%! We will become great friends.
     else
       MsgBox, %OutputVar%`, That makes me sad.

### c. 其他示例

    MsgBox, 4,, Would you like to continue?
    IfMsgBox, No
        return  ; 如果选择 No, 脚本将会终止.
    MsgBox You pressed YES.  ; 否则, 用户选择了 YES.

    ; 下面的例子展示了什么时候该使用百分号, 什么时候不该.
    Var = Text  ; 赋值一些文本给一个变量(传统的).
    Number := 6  ; 赋值一个数字给一个变量(表达式).
    Var2 = %Var%  ; 赋值一个变量给另一个(传统的).
    Var3 := Var  ; 赋值一个变量给另一个(表达式).
    Var4 .= Var  ; 追加一个变量到另一个的末尾(表达式).
    Var5 += Number  ; 将变量的值与另一个相加(表达式).
    Var5 -= Number  ; 将变量的值减去另一个(表达式).
    Var6 := SubStr(Var, 2, 2)  ; 变量在函数中. 这总是一个表达式.
    Var7 = %Var% Text  ; 赋值一个变量给另一个变量并带有一些额外的文本(传统的).
    Var8 := Var " Text"  ; 赋值一个变量给另一个变量并带有一些额外的文本(表达式).
    MsgBox, %Var%  ; 变量在命令中.
    StringSplit, Var, Var, x  ; 在命令中的变量, 但是它们作为输入或输出变量.
    if (Number = 6)  ; 只要 IF 有括号, 它就是一个表达式, 所以不需要百分号.
    if (Var != Number)  ; 只要 IF 有括号, 它就是一个表达式, 所以不需要百分号.
    if Number = 6  ; 如果没有括号, 那么 IF 是传统的. 不过, 只有赋值语句 "右边" 的变量需要百分号.
    if Var1 < %Var2%  ; 如果没有括号, 那么 IF 是传统的. 不过, 只有赋值语句 "右边" 的变量需要百分号.

## 7 - 对象

对象是一种组织数据以实现更高效使用的方法. 有时候对象被当作数组, 在这重点声明一下所有的数组都是对象. 我们调用对象不同的东西取决于我们使用它们的目的, 但是所有对象都是相同的.

对象基本上是变量的集合. 变量的名称叫做 "键", 变量的内容叫做 "值".

当你听到人们把一个对象叫做 数组 或 索引数组时, 说明这个对象的键是从 1 开始递增的连续数字. 当你听到人们把一个对象叫做 关联数组, 说明这个对象的键要么使用字符串(或文本), 要么使用不连续的数字. 有时可能是两者的混合, 也有可能是数列!

一个对象的键和值可以是什么, 没有任何限制, 它们甚至可以是另一个数组! 如果一个对象的值也是数组, 我们把它叫做 嵌套数组, 这个我们以后再解释.

您可能想要使用对象的原因有很多, 一些例子:

- 当你需要描述一组有序列表时, 比如杂货店列表(这种情况最好使用索引数组)
- 当你需要描述一个图形方格时, 比如一个棋盘游戏(这种情况最好使用嵌套对象)
- 当你需要描述一组事物而每样事物都有自己的名称时, 比如描述水果的特性(这种情况最好使用关联数组)

### a. 创建对象

我们有很多方法可以创建对象, 下面介绍最常用的几种方法:

方括号语法

      MyObject := ["one", "two", "three", 17]

  这将从有时被称为 "索引数组" 的内容开始. 索引数组是一个表示项目列表的对象, 索引号从 1 开始连续递增. 在本例中, 值 `"one"` 存储在对象键 `1`(又叫做索引号1), 值 `17` 存储在对象键 `4`(又叫做索引号 4).

大括号语法

      Banana := {"Color": "Yellow", "Taste": "Delicious", "Price": 3}

  这将通过定义有时被称为 "关联数组" 来开始. 关联数组是数据的集合, 其中每个条目都有自己的名称. 在这个例子中, 值 `"Yellow"` 存储在对象键 `"Color"` 中. 同样的, 值 `3` 存储在对象键 `"Price"` 中.

数组函数

      MyObject := Array("one", "two", "three", 17)

  这种方式跟方括号语法形式一样, 区别仅仅是采用了函数的形式.

对象函数

      Banana := Object("Color", "Yellow", "Taste", "Delicious", "Price", 3)

  这种方式跟大括号语法形式一样, 区别仅仅是采用了函数的形式.

请注意, 所有这些方法都创建了同一样东西(也就是对象), 区别仅仅是对象的键不一样.

### b. 使用对象

使用对象有很多方式, 包括检索值, 设置值, 添加更多的值等等.

#### 设置值:

方括号表示法

      Banana["Pickled"] := True ; 这个香蕉烂透了. 呃...

  在对象中设置值跟设置变量的值一样简单. 你需要做的是把方括号所代表的值在表达式赋值运算符 `:=` 的左边.

句点表示法

      Banana.Consistency := "Mushy"

  和上面一样, 但是用点(.) 符号.

#### 检索值:

方括号表示法

      Value := Banana["Color"]

  这允许你使用表达式作为键从对象中获取值. 在这个例子中, 我使用表达式 `"Color"`, 不要惊讶我仅使用键 `Color` 就会得到一个包含单词 "Yellow" 的值, 因为我们事先(在上一节) 就设置了键 `Color`.

句点表示法

      Value := Banana.Color

  仅允许使用原样的字串作为键名. 在句点表示法中, 键名不能使用变量.

#### 增加新的键和值:

方括号表示法

      MyObject["NewerKey"] := 3.1415

  想要直接添加一对键和值, 只需设置一个尚不存在的键即可.

句点表示法

      MyObject.NewKey := "Shiny"

  和上面一样, 但是用点符号.

InsertAt(在..插入) 法

      MyObject.InsertAt(Index, Value1, Value2, Value3...)

  Index(索引) 为任意整数键. 这会将所有更高的整数键的索引向上移动插入值的数量, 即使是空缺的也一样(例如, 假设只有键 1 和 100 存在, 当插入一个值到第 50 个键的位置时, 将导致原来位于 100 的键的索引变成 101).

Push(推送) 法

      MyObject.Push(Value1, Value2, Value3...)

  "追加" 值到数组 MyObject 的尾部. 换句话说, 它将插入的值放在 最高整数键 + 1 的位置.

#### 移除键和值:

用空白填充值

      Banana.Consistency := ""

  最简单的删除值的方法就是用空白填充. 你可以将其赋值为 ""(两个连续的双引号), 也就是常说的 空字符串. 这不会删除键, 但是它将使值看起来与从未赋值一样. 可以通过使用 HasKey 方法得知键依然存在, 而且键也会出现在 For 循环中. (我们一会再解释 For 循环)

删除法

      RemovedValue := MyObject.Delete(AnyKey)

  这和接下来的方法将删除键 和 值. `MyObject[AnyKey]` 先前的值将存储在 RemovedValue 中.

      NumberOfRemovedKeys := MyObject.Delete(FirstKey, LastKey)

  允许你删除 FirstKey 和 LastKey 之间的一系列的编号/整数或字符串键. 它给出的值将是被删除的键的数量, 如果你的键之间有间隙, 这是有用的(例如你指定键从 1 到 4, 但是键 2 不存在, 这将设置 NumberOfRemovedKeys 为 3, 因为只有三个键被移除).

Pop(抛出) 法

      MyObject.Pop()

  这将删除最高的整数键, 并返回这个键对应的值. 而且这种形式不会影响其他键的索引顺序(因为没有比它更高的序列了).

RemoveAt(在..删除) 方法

      RemovedValue := MyObject.RemoveAt(Index)

      NumberOfRemovedKeys := MyObject.RemoveAt(Index, Length)

  这将移除从 Index 到 Index + Length - 1(包含) 之间的所有键(例如 Index 为 5, Length 为 3, 则将删除键 5, 6, 7 这三个键). 如果 Length 省略则默认为 1. 移除这些键之后, 更高数字或整数的键将向下填充空缺, 所以如果有个值位于 Index + Length 那么它现在的位置就是 Index. 这很像 InsertAt 方法操作多个指定值的操作.

## 8 - 其他有用的东西

亲爱的朋友, 当你阅读到这里, 说明快要结束我们这段旅程了. 我希望你有所收获. 最后, 我将告诉你一些我认为你可能有用的东西. 希望你过的愉快!

### a. 神秘的 [ ]

在帮助文档中, 你可能会发现有两个符号(`[` 和 `]`) 经常出现在几乎每一页开头的黄色代码框中. 方括号中的内容代表可选的. 也就是说, 如果你不需要这些参数你完全可以不管它. 不过要强调一点, 当你在写代码时, 千万不要把 [ ] 也写上了.

p>例如, 在 ControlGetText 命令页面, 你可能会看到这段代码:

    ControlGetText, OutputVar , Control, WinTitle, WinText, ExcludeTitle, ExcludeText

所以你可以简单的写成这样:

    ControlGetText, OutputVar

或者再加上一些细节:

    ControlGetText, OutputVar, Control, WinTitle

如果你想只使用参数 ExcludeTitle 而不想使用参数 WinText 或 WinTitle, 怎么办? 很简单!

    ControlGetText, OutputVar, Control,,, ExcludeTitle

请注意, 你不能忽略参数, 只是需要将它们的位置留空. 如果你像下面这样忽略 `WinTitle, WinText`, 将会产生错误:

    ControlGetText, OutputVar, Control, ExcludeTitle

### b. 查找你的 AHK 版本

你可以运行下面的代码来查看你的 AHK 版本信息:

    MsgBox, %A_AhkVersion%

你也可以到开始菜单或安装路径下的帮助文件(即本文) 中去找.

### 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. 寻求帮助

在你提问之前, 最好自己先研究一下或者自己先动手试着写代码. 如果自己实在得不到满意的结果, 请往下看.

- 不要害怕提问, 即使是世界上最聪明的人也需要别人的帮助.
- 不要害怕给别人看你写的代码, 就算你觉得代码有点弱智.
- 将所有你尝试的代码都贴出来.
- 假设其他人 都是门外汉. 把你掌握的所有信息都教给我们这些门外汉. 帮助我们就是帮助你自己.
- 耐心.
- 礼貌.
- 开放.
- 友善.
- 祝你好运.

如果你没有马上得到答案, 至少等一天再提问. 我们乐于助人, 但是我们也是在自己的空余时间里免费提供帮助. 也许我们正在工作, 睡觉, 玩游戏, 和家人在一起或太忙了, 没有时间帮忙.

在等待帮助时, 你也可以试着自己动手解决. 独立解决问题的感觉相当不错.

### f. 其他链接

常见问题(FAQ)

dftg