AutoHotKey初学指南
最开始的时候, 同学在工作中需要为服务器安装软件, 但多台服务器的重复工作让他想寻找一种自动化的方式, 于是拜托我找一找. 但这方面我没有研究, 随便找了下, 也就是基于打包软件的命令行安装, 以及类似AutoHotKey
这样的自动化软件. 如果没听过AutoHotKey, 你可以理解为按键精灵之类的.
第一种方式, 由于安装文件的打包软件有很多种, 像Nullsoft
、InstallShield
,Advanced Installer
等, 我自己没有开发过像样的Windows程序, 这方面不了解. 查资料的结果是不同打包形式需要不同的命令和参数, 有得似乎并不提供静默安装的方式. 另外, 得针对不同软件, 辨别打包形式, 也挺麻烦.
至于第二种, 熟悉Linux平台的应该都习惯于使用脚本做一些自动化操作. 这里的脚本包括shell
, python
, ruby
等. 所以, 基于学习另一种语言的想法, 便看了AutoHotKey
的初学指南.
注意: 此处并不是原文翻译, 只是自学笔记和感受, 主观成份很多.
AutoHotKey
(以下简称AHK
)是Windows
平台下一款免费开源的自动化软件, 方便用户处理重复性的任务. 它是一种脚本语言, 最开始只用于定义热键(hotkey
)和相应的动作.
快速开始
在官网https://autohotkey.com/
下载软件并安装. 任意目录右击新建Autohotkey script
, 追加^w::MsgBox, hello, world
文本, 保存并双击脚本运行. 在任务栏右下脚会出现AutoHotKey
的运行图标. 此时, 按键Ctrl+w
会弹出对话框, 显示hello, world
, 说明软件工作正常.
追加文本有这样的形式, hotkey::action
. 此处, ^
表示Ctrl
键, 如果一定要区别左右, 可以使用<^
和>^
的形式. 还有!
表示Alt
键, #
表示Win
键, +
表示Shift
键, 且都可以使用<>
前缀表示左右键. ^w
表示快捷键Ctrl+w
, ^!w
表示快捷键Ctrl+Alt+w
, 依此类推. 而动作部分是一个命令MsgBox
, 表示弹出对话框, 并显示文本. 可以有更多的参数, 以自定义标题栏文本, 选择按钮(如yes/no/cancel
还是drop/save/ignore
).
所谓的组合键, 字面意思是同时按下多个键, 但如果你的多个键都是正常键, 即没有`Ctrl`, `Alt`, `Shift`, `Win`键的话, 需要`&`来组合. 如同时按`a`和`b`, 表示为`a & b`. 另外, 如果热键只有`Ctrl`单键, 则需要用`Ctrl`来表示, 左右为`LCtrl`和`RCtrl`, 不区分大小写. 其余键类同.
此处, 因为动作只有一个, 因此写到::
后即可, 多个动作从第二行起, 每行一个动作, 最后写上Return
表示此热键定义的动作完毕, 下面的内容属于另一个热键的.
除了定义热键外, AHK
另一个常用法是文本替换, 或者说热字串(hotstring
). 如::hw::hello, world
. 重载入后, 在任意输入框, 包括所有的文本编辑器, 浏览器地址栏, 百度搜索框等, 当键入hw
后, 任意结束符EndChar
都会触发文本替换. 此处的结束符, 可能理解为非数字字母. 本质上, 当键入结束符, 由AHK
发出退格键N次再键入入替换文本.
注意, 每添加一个新的热键或热字串, 都需要重新载入脚本. 可在右下脚的运行图标上右击, 选择Reload this script
. 或者可以自定义热键来重载入脚本.
hotkey::action ;1, 单行定义
hotkey:: ;2, 多行定义 action1 action2 ...Return
::hotstring::text ;3, 热字串, 文本替换
::hotstring:: ;4, 热字串, 动作触发
action
Return
虽然我这里区分了大小写, 但事实上AHK
并不区分大小写, 但仍然推荐驼峰写法以方便辨认.
通过这种方式定义的热键或热字串都是全局性的, 如果想定义针对特定窗口的热键或热字串, 可以用如下形式
#IfWinActive Untiled - Notepad ;标题栏文本#space:: MsgBox You pressed Win+Spacebar in notepad.Return#IfWinActive
此处在无标题记事本中创建了热键Win+space
.
AHK
还提供了简单的条件语句
if (var = 5) { ; equal? msgbox, var equals %var%} else { MsgBox, var not equals %var%}
以上4种形式, 就基本是AHK
的主要内容了.
分点细讲
AHK
最主要的部分是热键, 函数, 和命令. 热键方面, 要知道你想要的热键如何表示. 函数和命令则是需要查表和记忆. 其余还有变量, 各种语句等.
函数和命令是AHK
最奇怪的部分. 命令没有返回值, 函数有; 命令行参数文本默认为字串, 函数参数的字串必须'
包围; 命令参数不能嵌套命令, 而函数参数可以是另一个函数的返回值; 命令参数文本中的+!#^
被解析为特殊热键, 需要{}
包围来表示原符号, 而函数参数中的字串不需要; 命令的参数中变量以%
包围, 函数不需要; 命令参数中数学表达式并不运算, 函数会.
以上的不同, 并不是针对函数和命令的参数, 在其他方面也适用. 我一般将命令参数表现出来的特性理解成文本
, 而函数参数表现出来的特性理解成表达式
. 以下会提到在赋值语句中的差异. 其实在条件语句中, 当有()
时, 适用表达式, 而没有()
时, 适用文本. 但即使在文本中, 也只有在操作符如=<>
右边才需要%
包围变量.
这些差异大部分时候让我觉得很奇怪, 不明白语言为什么如此设计. 我相信这对任何一个学习过通用编程语言的人来说, 都是不可接受的. 但考虑到AHK
其实并不是作为脚本语言被精心设计, 而是在autoit
软件的基础上扩展起来的. 这是自己的理解, 我对AHK
的历史以及开发记录并不了解.
变量
使用变量并不需要类型声明, 这点类似动态语言.
var = textvar := expression
上面说的文本和表达式的差异在此处也适用. 如num = 5*3
, 实际上, num
并不是15
, 而是字串5*3
. 此处数学表达式不运算, 而:=
则会. 另外, var1=var2
并不是将var2
的内容给var1
, 而是将字串var2
给var1
. 需要var1=%var2%
来达到目的. 而var1:=var2
则可以.
其实差异还是挺多的, 所以我一直认为这里的语法设计的太冗余了. 建议大家可以的话, 尽量使用:=
.
命令
因为命令比较经常使用, 先介绍经常使用的命令. 再声明一遍, 命令名不区分大小写.
cmd, arg1[, arg2, arg3...]
, 这是命令的一般形式, []
内的参数表示可以省略. 如果只想省略中间的某个参数, 用,,
连续两个,
来将此位置的参数空过.
注意上面提到的, 在命令参数中, 有特殊的注意事项.
参数使用变量用%
包围, 文本和数字无需'
包围, 参数不进行数字运算. 一行一条命令.
Send, text
: 发送文本, 本质上是发送敲击的键. 对于数字字母就是对应的符号, 而+!#^
则是对应的热键, 请以{}
包围. 另外, 还有些特殊键, 如回车{enter}
, 删除{del}
, 大写{CapsLock}
等.
Run, program
: 运行程序, AHK
会在%path%
中查找. 如Run, NotePad.exe
, 其中后缀可省略. 除了程序, 也可以直接打开网页run, www.baidu.com
会调用默认浏览器打开百度首页. 也可以打开目录, 如run, %A_MyDocuments
将打开我的文档
. 此处的%A_MyDocuments
是AHK
预定义变量.
WinActivate, title_text
: 激活指定标题栏的窗口, 注意操作系统环境不同, 标题栏文本的语言也不同. 如打开记事本, 在英文环境下, 标题栏文本是Untitled - notepad
, 中文环境下是无标题 - 记事本
. 我想, 这里是AHK
唯一区分大小写的地方了吧.
WinWaitActive, title_text
: 等待指定窗口的激活, 往往同上一起使用, 以确保接下来的命令运行在正确的窗口中.
sleep, num
, 停止毫秒
MsgBox, text
: 显示对话窗口, 跟文本参数, 只有确定
按键.
MsgBox [, options, title, text, timeout]
: 单独一个msgbox
会提示press ok to continue
, 选项显示不同的按钮, 如4yes/no
或1ok/cancel
,2abort/retry/ignore
,3yes/no/cancel
等.
InputBox, output_var, title_text, question_text
, 以窗口形式获取用户输入
IfMsgBox, Yes/No
: 如果对话框点击确定或否, 或者依据选项的不同输入, 来决定下一步
函数
函数一般有这样的形式, var:=func(arg1, arg2, ...)
.
变量直接用, 字串以'
包围, 参数进行数字运算, 函数可嵌套, 有返回值.
SubStr(string, num)
, 返回从num位置的字串, 1索引
FileExist(path)
, 文件存在判断
特殊按键
{f1}-{f12}
{enter/space/esc/tab}
{bs/del/ins}
{up/down/left/right}
{home/end/pgup/pgdn}
{capslock/scrolllock/numlock}
{ctrl/lctrl/rctrl down/up}
,alt
,shift
,win
同{+!^#{}}
, 仅表示+
,!
,^
,#
,{
,}
{numpad0-9}
,{numpaddot/enter/mult/div/add/sub}
数字键盘的键, 按下numlock
键时{numpadup/down/left/right/home/end/pgup/pgdn/del/ins/clear}
数字键盘的控制键,numlock
未按下时{browser_back/forward/refresh/stop/search/favorites/home}
, 浏览器的按键{volume_mute/down/up
音量键{media_next/prev/stop/play_pause}
媒体控制键
预定义变量
以%
包围, 如%A_WorkingDir%
.
脚本属性:
1, 2, 3
, 脚本的命令行参数,0
表示参数数目A_ScriptDir, A_ScriptName, A_ScriptFullPath, A_ScriptHwnd
运行脚本的目录,文件名,全路径,主窗口句柄.A_LineFile, A_LineNumber, A_ThisFunc, A_ThisLabel
表示当前运行命令的文件,行号,函数,标号, 用于错误处理A_AhkVersion, A_AhkPath
本程序的版本和路径A_IsUnicode, A_IsCompiled, A_ExitReason
是否是unicode, 是否编译, 退出原因
对象
创建对象: (数组或列表, 字典或哈希, 在不同语言中叫法不同)
MyObject := ['one', 'two', 'three', 17] ; 字面量创建
banana := {'Shape': 'Elongated', 'Color': 'Yellow'}
MyObject := Array('one', 'two', 'three', 17) ; 函数创建
Banana := Object('Shape', 'Elongated', 'Color', 'Yellow')
添加新元素或改变原键值:
Banana.Consistency := 'Mushy' Banana['Pickled'] := True ;两种方式索引, `.`和`[]`操作符 MyObject.NewKey := 'Shiny' ;给数组添加键值对 MyObject.InsertAt(Index, Value1, Value2, Value3, ...) ;多元素插入MyObject.Push(Value1, Value2, Value3, ...) ;追加元素
移除键值:
MyObject.NewKey := '' ; 移除值
RemovedValue := MyObject.Delete(AnyKey) ; 移除键
NumberOfRemovedKeys := MyObject.Delete(FirstKey, LastKey)
MyObject.Pop() ; 弹出尾元素
RemovedValue := MyObject.RemoveAt(Index) ; 移除索引处键
NumberOfRemovedKeys := MyObject.RemoveAt(Index, Length)
这里需要说明的是, Array
和Object
是相同的对象, 数组默认的数字索引, 但也可以添加键值对. 则之前的值通过1,2,3
索引, 加入的值通过键索引.
对于数组, 第一个元素的索引为1.
另外, 在命令中, 默认的是文本, 似乎不能直接输出MyObject.NewKey
, 无论是否以%
包围. 变通的方法是赋值给变量, 再将变量以%
输出.