; Functions for holding and repeating keys

;
; Private Functions
;

_HoldRepeat_LoopState := Map()
_HoldRepeat_IsActive := Map()

_HoldRepeat_Handler(Mode, TargetKey, CancelKeys:=[], HoldKey?, BlindMode:="{Blind}") {
    global _HoldRepeat_IsActive
    if (_HoldRepeat_IsActive.Has(TargetKey) AND _HoldRepeat_IsActive[TargetKey]) {
        return
    }
    _HoldRepeat_IsActive[TargetKey] := true

    Send BlindMode "{" TargetKey " down}"
    if (Mode == "Hold") {
        if _HoldRepeat_LoopState.Has(TargetKey) {
            _HoldRepeat_LoopState.Delete(TargetKey)
        }
    } else if (Mode == "Repeat") {
        _HoldRepeat_LoopState[TargetKey] := true
    } else {
        return
    }
    SetTimer _HoldRepeat_Loop.Bind(TargetKey,CancelKeys,HoldKey?,BlindMode), 50
}

_HoldRepeat_Loop(TargetKey, CancelKeys, HoldKey?, BlindMode:="{Blind}") {
    global _HoldRepeat_LoopState
    global _HoldRepeat_IsActive

    endLoop := false
    for index,key in CancelKeys {
        if GetKeyState(key,"P") {
            Send BlindMode "{" TargetKey " up}"
            endLoop := true
        }
    }
    if IsSet(HoldKey) {
        if !GetKeyState(HoldKey,"P") {
            Send BlindMode "{" TargetKey " up}"
            endLoop := true
        }
    } else {
        if GetKeyState(TargetKey,"P") {
            endLoop := true
        }
    }
    if endLoop {
        SetTimer , 0
        _HoldRepeat_IsActive[TargetKey] := false
        return
    }

    if _HoldRepeat_LoopState.Has(TargetKey) {
        updown := (_HoldRepeat_LoopState[TargetKey] ? "up" : "down")
        Send BlindMode "{" TargetKey " " updown "}"
        _HoldRepeat_LoopState[TargetKey] := !_HoldRepeat_LoopState[TargetKey]
    }
}

;
; Public Functions
;

Hold := _HoldRepeat_Handler.Bind("Hold")
Repeat := _HoldRepeat_Handler.Bind("Repeat")

; Sets key to hold if single tap, or repeat if double tap
HoldOrRepeat(TargetKey, CancelKeys?, BlindMode:="{Blind}") {
    Send BlindMode "{" TargetKey " down}"
    if KeyWait(TargetKey, "D T0.2") {
        mode := "Repeat"
    } else {
        mode := "Hold"
    }
    _HoldRepeat_Handler(mode, TargetKey, CancelKeys,, BlindMode)
}

; Press Target button extremely rapidly while Hold button is held down
Turbo(TargetKey, HoldKey:=TargetKey,BlindMode:="{Blind}") {
    While GetKeyState(HoldKey,"P") {
        Send BlindMode "{" TargetKey "}"
    }
}