动态创建按键/用户定义的按键/可修改的按键[AutoHotkey|AHK][IniRead|读取配置文件][IniWrite|写入配置文件][Try|Catch|尝试|守护|异常][Hotkey...


在编写对灵活性有一定要求的脚本时,我们希望脚本能通过某种媒介与用户达成一定程度上的客制化约定;这时,直接把热键固定在脚本中的写法就显得不那么妥当。
本文将为您介绍,如何通过读取配置文件来为脚本动态创建和变更热键。

  • 读取配置文件

    动态创建热键有强制创建和适应创建两种情况,前者在需要脚本内部提供热键默认值方面区别于后者。

    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, %配置文件名%
    

    通过FileExistFileDelete删除配置文件;随后,使用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-CatchHotkey语句的逻辑封入函数,随后按顺序调用检查。

    ; 对于需要大量检查的情况请考虑使用数组和循环.
    检查按键有效性(原始按键_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语句检查动态标签是否存在,就像动态按键那样。

一个标签可对应多个热键,而单个热键只能对应一个标签;基于此特性,上述文中先把所有按键创建于同一标签,然后再逐一顶替和启用。

至此,脚本已可动态创建按键。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342