- 标题:
动态创建按键 / 用户定义的按键 / 可修改的按键 - 标签:
AutoHotkey | AHK | IniRead | 读取配置文件 | IniWrite | 写入配置文件 | Try | Catch | 尝试 | 守护 | 异常 | Hotkey | 动态热键 | 灵活 | 适应 | 参数 | 面向用户 - 标注:
https://www.jianshu.com/p/bbdddfad1f08
https://www.jianshu.com/u/1275d25b625e
在编写对灵活性有一定要求的脚本时,我们希望脚本能通过某种媒介与用户达成一定程度上的客制化约定;这时,直接把热键固定在脚本中的写法就显得不那么妥当。
本文将为您介绍,如何通过读取配置文件来为脚本动态创建和变更热键。
-
读取配置文件
动态创建热键有强制创建和适应创建两种情况,前者在需要脚本内部提供热键默认值方面区别于后者。
Global 原始按键_A1 := "c" Global 原始按键_A2 := "e" Global 映射按键_A1 := "m" Global 映射按键_A2 := "r" Global 原始按键_B1 := "k" Global 映射按键_B1 := A_Space ; 若不强制创建热键则使用此内置变量配合IniRead语句.
随后,使用IniRead语句读取配置文件。
Global 配置文件名 := "配置文件.ini" ; 配置文件名也可通过其他方式动态获取. IniRead, 原始按键_A1, %配置文件名%, 按键A组, 原键1, %原始按键_A1% IniRead, 原始按键_A2, %配置文件名%, 按键A组, 原键2, %原始按键_A2% IniRead, 映射按键_A1, %配置文件名%, 按键A组, 热键1, %映射按键_A1% IniRead, 映射按键_A2, %配置文件名%, 按键A组, 热键2, %映射按键_A2% IniRead, 原始按键_B1, %配置文件名%, 按键B组, 原键1, %原始按键_B1% IniRead, 映射按键_B1, %配置文件名%, 按键B组, 热键1, %映射按键_B1%
IniRead, 输出变量, 文件名称, 配置段名, 配置键名, 默认值
输出变量:脚本定义的变量;语句会在执行后修改此值,不存在则创建。
文件名称、配置段名、配置键名、默认值:字符串;可用百分号语法置入变量。该语句对于空键和空值两种情形不总是采用默认值。您可能会想,为何不把
映射按键_B1
初始化为""
而是采用了A_Space
呢?- 如果文件不存在,或文件中没有相关键名,该语句会将输出变量设置为默认值;
- 其中,如果复制于默认值处的变量值为空(
""
),语句执行结果为"ERROR"
。Global 映射按键_B1 := "" IniRead, 映射按键_B1, %配置文件名%, 按键B组, 热键1, %映射按键_B1% ; 映射按键_B1 = "ERROR"
- 而如果默认值处直接填写
""
,语句执行结果为""""
。IniRead, 映射按键_B1, %配置文件名%, 按键B组, 热键1, "" ; 映射按键_B1 = """"
- 若使用
A_Space
,语句执行结果可正确为空(""
)。Global 映射按键_B1 := A_Space IniRead, 映射按键_B1, %配置文件名%, 按键B组, 热键1, %映射按键_B1% ; 映射按键_B1 = ""
IniRead, 映射按键_B1, %配置文件名%, 按键B组, 热键1, %A_Space% ; 映射按键_B1 = ""
- 其中,如果复制于默认值处的变量值为空(
- 文件内有键而没有值,该语句通常将输出变量设置为空(
""
)。[按键B组] 热键1=
IniRead, 映射按键_B1, %配置文件名%, 按键B组, 热键1, 我是默认值 ; 映射按键_B1 = ""
为使得两种情况皆可使用空值表达式进行判断,非强制创建的热键默认值应初始化为
A_Space
。 - 如果文件不存在,或文件中没有相关键名,该语句会将输出变量设置为默认值;
-
写入配置文件
为避免因用户错误修改配置而导致的问题持续存在,在每次读取配置后应当及时刷新文件。
If FileExist(配置文件名) FileDelete, %配置文件名%
通过FileExist和FileDelete删除配置文件;随后,使用IniWrite语句写入配置文件。
IniWrite, %原始按键_A1%, %配置文件名%, 按键A组, 原键1 IniWrite, %原始按键_A2%, %配置文件名%, 按键A组, 原键2 IniWrite, %映射按键_A1%, %配置文件名%, 按键A组, 热键1 IniWrite, %映射按键_A2%`n, %配置文件名%, 按键A组, 热键2 IniWrite, %原始按键_B1%, %配置文件名%, 按键B组, 原键1 IniWrite, %映射按键_B1%, %配置文件名%, 按键B组, 热键1
IniWrite, 配置键值, 文件名称, 配置段名, 配置键名
配置键值、文件名称、配置段名、配置键名:字符串;可用百分号语法置入变量。 -
检查按键有效性
AutoHotkey没有在If var is [not] type中提供类似
key
的类型,我们需要用其它判定逻辑赶在脚本抛出错误之前得知用户所提供的的按键是否是一个有效的按键;其意义不仅仅是将冗长难懂的报错翻译成简短精炼的信息以彰显脚本的健壮程度,更多是因为经过编译的可执行文件甚至没有报错环节来告知用户脚本正在发生的问题——错误会潜伏在不知觉中向未来带去危险。检查按键有效性(按键名称) { ; 函数: 当参数不是有效按键时告知用户并退出脚本. If !是有效按键(按键名称) { ; 如果不是有效按键, MsgBox , 16, ERROR, 无法解析的按键名称: "%按键名称%".;通过消息框显示问题, IfMsgBox, OK, ExitApp ; 然后在用户确认后退出脚本. } } ; END FUNC : 检查按键有效性 / 是有效按键(按键名称) { ; 函数: 当参数不是有效按键时返回0, 否则返回1. Try Hotkey, %按键名称%, 是有效按键_内部标签, Off ; 尝试以关闭模式创建临时热键; Catch ; 当热键创建失败时- Return 0 ; 返回0, Return 1 ; 否则返回1. 是有效按键_内部标签: ; 不会被调用的空标签. } ; END FUNC : 是有效按键 /
将使用Try-Catch和Hotkey语句的逻辑封入函数,随后按顺序调用检查。
; 对于需要大量检查的情况请考虑使用数组和循环. 检查按键有效性(原始按键_A1) 检查按键有效性(原始按键_A2) 检查按键有效性(映射按键_A1) 检查按键有效性(映射按键_A2) 检查按键有效性(原始按键_B1) If (映射按键_B1 != "") ; 对于非强制创建的热键应先判断其内容是否为空. 检查按键有效性(映射按键_B1)
Hotkey, 按键名称, 标签名称/状态选项, 选项
按键名称、标签名称:字符串;可用百分号语法置入变量。
状态选项、选项:特定值。 -
检查和创建热键
检查与创建流程通常发生在相近位置,除非有特殊需求将它们分离。
创建热键(按键名称, 标签名称, 启用检查 := 1) { ; 函数: 检查按键名称并为指定标签创建热键. If 启用检查 ; 如果需要对按键进行名称检查- 检查按键有效性(按键名称) ; 则调用检查函数, Hotkey, 按键名称, 标签名称, On ; 否则直接以启用模式创建热键. } ; END FUNC : 创建热键 /
将检测逻辑与创建语句一同封入函数,上文所展示的顺序检查可替换如下。
检查按键有效性(原始按键_A1) 检查按键有效性(原始按键_A2) 创建热键(映射按键_A1, "测试标签") 创建热键(映射按键_A2, "测试标签") If (映射按键_B1 != "") { ; 对于非强制创建的热键应先判断其内容是否为空. 检查按键有效性(原始按键_B1) 创建热键(映射按键_B1, "测试标签") } Return ; END AUTO-EXECUTE | 测试标签: ; 标签: 仅供测试. MsgBox, %A_ThisHotkey% Return ; END LABEL : 测试标签 /
可用IsLabel语句检查动态标签是否存在,就像动态按键那样。
一个标签可对应多个热键,而单个热键只能对应一个标签;基于此特性,上述文中先把所有按键创建于同一标签,然后再逐一顶替和启用。
至此,脚本已可动态创建按键。