让热键动起来

供新手入门和老手参考的教程和相关资料,包括中文帮助
User avatar
amnesiac
Posts: 186
Joined: 22 Nov 2013, 03:08
Location: Egret Island, China
Contact:

让热键动起来

18 Aug 2014, 01:38

导言:有些文章只看它的标题,您就看不出它的内容,则很可能错过它的精彩,本文即是其中一例。

使用双冒号语法可以快速创建热键,简单、直接,非常方便。有时我们需要经常修改一些热键或把脚本给别人使用, 通常必须考虑把热键放在专门的配置中以方便修改,此时就需要动态实现热键了。

使用 Hotkey 命令

这个命令本身的用法简单,这里结合常见的具体场景介绍:

Code: [Select all] [Expand] [Download] (Script.ahk)GeSHi © Codebox Plus


下面进行简单的分析:

Code: [Select all] [Download] (Script.ahk)GeSHi © Codebox Plus

Hotkey, IfWinActive, ahk_class Notepad

设置热键生效的窗口条件,可使用窗口存在/不存在/活动/不活动(IfWinActive/IfWinNotActive/IfWinExist/IfWinNotExist),效果等同于对应的系列指令(不过作用对象有区别,一个是双冒号热键,一个是 hotkey 热键)。

Code: [Select all] [Download] (Script.ahk)GeSHi © Codebox Plus

Hotkey, IfWinActive

取消热键条件,其中的 IfWinActive 可替换为 IfWinExist/IfWinNotActive/IfWinNotExist/If(注:这里还包括 If)。

Code: [Select all] [Download] (Script.ahk)GeSHi © Codebox Plus

Hotkey, IfWinActive, ahk_class Notepad
Hotkey, IfWinActive, ahk_class WordPadClass
Hotkey, %MyHotkey%, MyLabel_1

这种条件与对应指令类似,效果是互斥的,所以上面这个热键不会在记事本和写字板中都生效。

Code: [Select all] [Download] (Script.ahk)GeSHi © Codebox Plus

Hotkey, If, WinActive("ahk_class Notepad") || WinActive("ahk_class WordPadClass")

尽管这里的条件仍与窗口有关,不过实际上可以任意表达式,只需满足存在相应的 #If 指令且它们包含的表达式完全一致。

Code: [Select all] [Download] (Script.ahk)GeSHi © Codebox Plus

#If, WinActive("ahk_class Notepad") || WinActive("ahk_class WordPadClass")

原本 #If 指令是与位置有关,但由于这个脚本中没有双冒号热键和热字串,所以这里放在什么位置关系不大。

关于热键优先级:一般而言,钩子热键优先级最高,最近启用的优先级更高,局部变体优先级高于全局变体(多个局部变体都有效时最先启用的优先级更高)。前面的有些结论可能仅适用于同一脚本而言,不同脚本及与其他程序之间实际情况比较复杂。

热键的优先级与启用顺序和作用范围有关,但先创建的并不总是高优先级。

双冒号热键和 Hotkey 创建的热键是分别管理的,后者是通过该命令的选项管理自身创建的热键,具体请参阅帮助。Hotkey 命令不能直接启用或禁用脚本中不是它创建的热键,但在大多数情况下它可以通过创建或启用相同的热键来覆盖它们。

使用 Input 命令
请用 AutoHotkey 实现按任意键继续的功能。

请思考,您会如何实现?很容易想到命令提示符中的 pause 命令,在批处理中执行某些操作前先提示用户,随意按某个键后继续执行,AutoHotkey 中应如何实现相同功能?也许实际中不一定需要,但思考可以锻炼思维。先看看我的实现:

Code: [Select all] [Expand] [Download] (Script.ahk)GeSHi © Codebox Plus


按任意键,就建立“任意键”的热键,思路很明确。现在要转换成“提示用户一些信息并按任意键继续”就简单了,加上一对 ToolTip(在该片段前加带参数的 ToolTip 而 Operation 子程序中加不带参数的)或使用类似的方法。

上面虽然实现了功能,不过从编写效率或移植角度看这种实现不好(如果都用双冒号会更糟糕),热键功能是 AutoHotkey 的特色,有更好的实现吗(其他脚本中蹩脚是正常的)?

Code: [Select all] [Download] (Script.ahk)GeSHi © Codebox Plus

; 来自帮助(一行命令,干净简洁):
Input, SingleKey, L1, {LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{BS}{Capslock}{Numlock}{PrintScreen}{Pause}
; 需要注意,由于 SingleKey 只记录按键按下后生成的字符,所以产生不可见字符的按键应放在 EndKeys 参数中。

这里实际上创建了一批热键,比较而言,Hotkey 创建单个热键很方便,但创建批量热键时应优先考虑 Input。创建批量热键的一种典型的情况是类似码表式输入法,其中需要批量转译输入为对应的输出,一个码表(保存了输入字符组与输出字符组的对应关系),一个平台(脚本中实现转换功能),该平台中核心功能就是 Input:

Code: [Select all] [Download] (Script.ahk)GeSHi © Codebox Plus

Input, Code, C I L4, {Space}{Enter}{Esc} ; 码表式输入法核心示例。

例如五笔输入法的特点:最长四码,按空格键可输入一、二、三级简码。当然,实际情况比较复杂,需要处理全角、半角、标点符号和特殊按键,加上候选框就更复杂了。到这里,您理解我之前曾说热字串是序列键(热键的一种)吗?刚才谈论的功能和热字串本源上都是热键。

说到这个命令,必须和大家分享一段代码,实现很精妙(原本想放到 AutoHotKey 常用函数或小技巧有哪些分享?上的,但可能不容易理解):

Code: [Select all] [Expand] [Download] (Script.ahk)GeSHi © Codebox Plus


前面几句可能不好理解,我们考察开始的几次循环:i=1 时接受一位输入并与 Key 中的第一位比较,相同则 i 自增,否则继续从新开始。i=2 时(第一次的输入已经匹配 Key 中的第一位),继续接受输入一位与 Key 中的第二位比较……若连续 i 位都与 Key 中的第 i 位相同,即刚才输入的字符串已经完全匹配 Key。

为什么不按下面这样实现?

Code: [Select all] [Download] (Script.ahk)GeSHi © Codebox Plus

Key := "test"
i := 1
Loop
{
Input, a, % "L" StrLen(Key)
If (a = Key)
{
MsgBox, 您输入了正确的通行码。
Break
}
}

乍一看,他们的功能好像没什么区别,自己动动手比较吧(如果不实践,永远不会知道看起来正常的代码却不会按预期运行的原因)。另外,小众屏幕密码锁也是个很实用的功能,输入密码时别人看不到,也不容易猜出来(先输一些错的字符)。

使用 A_PriorKey

上面没有提到,实际上使用 Input 是有局限性的,如不支持鼠标按键,而通过 A_PriorKey 不仅能检测到按键,还能检测到按钮(需要安装钩子):

之前说到任意键,您意识到按钮了吗?

小结

动态热键的用途不限于本文开头介绍的情况, 例如还可以快速创建大量热键。
AutoHotkey 学习指南(Beauty of AutoHotkey)
I do not make codes, and only a porter of AutoHotkey: from official to Chinese, from other languages to AutoHotkey, and show AutoHotkey to ordinary users sometimes.

Return to “教程资料”

Who is online

Users browsing this forum: No registered users and 1 guest