轻松定义双击热键(或三击、四击等)

; 来源:https://www.autohotkey.com/boards/viewtopic.php?f=6&t=95596
#Persistent
#NoEnv
#SingleInstance, force
SetTitleMatchMode, RegEx
SetBatchLines, -1
mk := new MultiHotkeys()

; Use hotkey command before definition to make context sensitive:
; Hotkey, IfWinActive, Notepad

mk.Add("d"                  , "t200" , "d")      ; send d if the below times out
mk.Add("dd"                 ,        , "Test"    , "Double hotkey") ; Calling functions
mk.Add("ddd"                ,        , "Test"    , "Triple hotkey!")
mk.Add("dddd"               ,        , "Test"    , "Quadruple hotkey!!")
mk.Add("{F1}{F1}"           ,        , "Test2")  ; Calling a label; F1 > F1
mk.Add("^{F1}{F1}"          ,        , "Test3")  ; Sending a string; Ctrl+F1 > F1
mk.Add("+t"                 ,        , "T")      ; Capital T if Shift+t times out
mk.Add("+thisisatest"       , "t1000", "Test"    , "Hello,"  ,"World!") ; Sending 2 parameters ; Shift+t > hisisatest
mk.Add("#{Capslock}{F2}{F3}", "t800" , "Test"    , "Wow, this is a long hotkey!") ; Win+Caps > F2 > F3
return

Test(param1:="",param2:="") {
    global mk
    str := mk.inputStr
    if param1
        str .= "`r`n" param1
    if param2
        str .= "`r`n" param2
    tooltip, % str
    SetTimer, Tooltipoff, -3000
    return
    TooltipOff:
    tooltip
    return
}

Test2:
msgbox, % A_ThisLabel "`r`n" mk.inputStr
return

;---------------------------------------------------------------------------------------------------------------------------------------
;
;   Class_Multihotkeys.ahk v0.1 by evilmanimani
;
;
;   Easily set up double, triple, or more hotkeys, and more for pseudo hotstrings, with a configurable timeout
;   Can go functions with parameters, labels, or just send characters if it doesn't match a function/label
;   If two input strings are similar i.e. (!aa, !aaa, !aaaa), it will trigger the shorter ones after the timeout
;   , the longest will be triggered immediately.
;
;   mh := new MultiHotkeys() to start
;   
;   The only public method is Add, see examples for details:
;   
;       - keys:        string of letter keys, optionally starting with modifiers the modifier only needs to be held for the first key
;                      should support ~, but not really tested.
;       - options:     at the moment, only supports a timeout in milliseconds, this is the timeout period between each keypress
;                      of the full input string, entered as t400, t1000, etc; defaults to 400ms; the timeout applies to any configured
;                      input string that shares the same starting hotkey (the modifiers and first character)
;       - function:    either a function or label name, any other text not matching a function onr label will be sent as-is
;       - params:      if passing a Function, any amount of associated params are supported
;
;
Class MultiHotkeys {

    __New(options:="") { ; not much for options here yet
        this.ih := InputHook(Options)
        this.KeyDict := {}
    }

    Add(keys, options:="", function :="", params*) {
        static optLookup := {"T":"timeout","t":"timeout"}
        for i, opt in StrSplit(options, A_Space) {
            if optLookup.HasKey(SubStr(opt,1,1)) {
                var := optLookup[SubStr(opt,1,1)]
                %var% := SubStr(opt,2)
            }
        }
        RegExMatch(keys, "O)^(?<mods>[~!^+#]{1,4})?(?<keys>.*)", keys)
        mods := StrReplace(keys.mods,"~",,noHide)
        keyStr := keys.keys
        If IsFunc(function) {
            if params
                func := Func(function).Bind(params*)
            else
                func := Func(function)
            
        }
        if IsObject(keyStr) {
            ; to-do: put in support for simple remaps via passing an array, i.e. mp.Add({"aa":"b","bb":"c","cc":"d"},,"Test")
        } else {
            hotkeyFunc := ObjBindMethod(this,"HotkeyHandler")
            pos := 1
            loop {
                pos := RegExMatch(keyStr,"({.*?})|(\w)",key,pos)
                if (A_Index = 1) {
                    pos += StrLen(key)
                    firstKey := key
                    hk := ( noHide ? "~" : "$") . mods . RegExReplace(key, "[{}]")
                    HotKey, % hk, % hotkeyFunc
                } else {
                    this.ih.KeyOpt(key, "+E+S")
                    pos += StrLen(key)
                }
            } Until (!key)
            
            keyStr := StrReplace(keyStr, firstKey, , , 1)
            keyStr := RegExReplace(keyStr, "[{}]")
            for i, e in StrSplit(keys) {
                if (e = "{")
                this.ih.KeyOpt(e, "+E+S")
            }
            if !isObject(this.KeyDict[hk]) {
                this.KeyDict[hk] := {}
                this.KeyDict[hk].timeout := timeout ? Format("{:.1f}", timeout / 1000) : 0.4
            }
            this.KeyDict[hk][keyStr] := {}
            this.KeyDict[hk][keyStr].function := func
            this.KeyDict[hk][keyStr].funcName := function
            if mods
                this.KeyDict[hk][keyStr].mods := mods
        }
    }

    HotkeyHandler() {
        Suspend, On
        thisHotkey := A_ThisHotkey
        Mods := RegExReplace(thisHotkey, "i)^[~\$]*([!^+#]{0,4}).*$", "$1")
        timeout := this.KeyDict[thisHotkey].timeout
        loop {
            matched := []
            this.ih.Start()
            EndReason := this.ih.Wait(timeout)
            inputStr .= this.ih.EndKey
            for k, v in this.KeyDict[thisHotkey] {
                if IsObject(v) {
                    if InStr(k, inputStr)
                        matched.Push(k)
                    maxLen := StrLen(k) > maxLen ? StrLen(k) : maxLen
                }
            }
            if ((matched.MaxIndex() = 1 && this.KeyDict[thisHotkey].HasKey(inputStr))
            || !EndReason || StrLen(inputStr) >= maxLen)
                break
        }
        this.ih.Stop()
        matchConfirm := []
        for i, e in matched {
            if this.KeyDict[thisHotkey][e].HasKey("mods") {
                for _, char in StrSplit(mods) {
                    if InStr(this.KeyDict[thisHotkey][inputStr].mods,char) {
                        matchConfirm.Push(e)
                        continue 2
                    }
                }
            } else if !mods {
                matchConfirm.Push(e)
            }
        }
        if ((matched.MaxIndex() = 0 && this.KeyDict[thisHotkey].HasKey(""))
            || (this.KeyDict[thisHotkey].HasKey(matchConfirm.1) && (!Endreason || matchConfirm.MaxIndex() = 1))) {
            this.inputStr := SubStr(thisHotkey,2) . inputStr
            funcName := this.KeyDict[thisHotkey][inputStr].funcName
            if IsFunc(funcName) {
                this.KeyDict[thisHotkey][inputStr].function.Call()
            } else if IsLabel(funcName) {
                Gosub, % funcName
            } else {
                Send, % "{raw}" funcName
            }
        } else {
            this.inputStr := ""
        }
        Suspend, Off
    }
}

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。