E.g. LooksLikeHotkey("+^#!q")
E.g. StrIsTypeHotkey("RAlt & Enter")
Code: Select all
;before/after:
q::MsgBox, % "hello"
q::MsgBox("hello")
Code: Select all
;before/after:
q::MsgBox, % "hello"
q::MsgBox("hello")
Code: Select all
#NoEnv
#SingleInstance Force
SetBatchLines -1
fn := Func("isLikeHotkey")
eq := Func("assert").Bind(true, fn)
neq := Func("assert").Bind(false, fn)
valid := "Testing valid hotkeys`n`n"
valid .= eq.Call("Up Up")
valid .= eq.Call("Up")
valid .= eq.Call("``") ; hotkey is meant to be single `::
valid .= eq.Call("`; Up")
valid .= eq.Call(":")
valid .= eq.Call(" & & & ")
valid .= eq.Call(" & & k")
valid .= eq.Call("h & j Up")
valid .= eq.Call("~*>$>>+!^#<g Up")
valid .= eq.Call("vk24 & vk23")
valid .= eq.Call("sc123")
valid .= eq.Call("z")
MsgBox % valid
invalid := "Testing invalid hotkeys`n`n"
invalid .= neq.Call("") ; blank hotkey, ie ::
invalid .= neq.Call(" * g & h Up")
invalid .= neq.Call("not_a_hotkey")
invalid .= neq.Call("g Up & g Up")
invalid .= neq.Call("vk12sc123")
invalid .= neq.Call("vk123456")
MsgBox % invalid
Clipboard := valid invalid
ExitApp
Esc::ExitApp
isLikeHotkey(str) {
static VALID_HOTKEY := "(\b(LButton|RButton|MButton|XButton1|XButton2|WheelDown|WheelUp|WheelLeft|WheelRight|CapsLock|Space|Tab|Enter|Return|Escape|Esc|Backspace|BS|ScrollLock|Delete|Del|Insert|Ins|Home|End|PgUp|PgDn|Up|Down|Left|Right|Numpad0|NumpadIns|Numpad1|NumpadEnd|Numpad2|NumpadDown|Numpad3|NumpadPgDn|Numpad4|NumpadLeft|Numpad5|NumpadClear|Numpad6|NumpadRight|Numpad7|NumpadHome|Numpad8|NumpadUp|Numpad9|NumpadPgUp|NumpadDot|NumpadDel|NumLock|NumpadDiv|NumpadMult|NumpadAdd|NumpadSub|NumpadEnter|F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|F13|F14|F15|F16|F17|F18|F19|F20|F21|F22|F23|F24|LWin|RWin|Control|Ctrl|Alt|Shift|LControl|LCtrl|RControl|RCtrl|LShift|RShift|LAlt|RAlt|Browser_Back|Browser_Forward|Browser_Refresh|Browser_Stop|Browser_Search|Browser_Favorites|Browser_Home|Volume_Mute|Volume_Down|Volume_Up|Media_Next|Media_Prev|Media_Stop|Media_Play_Pause|Launch_Mail|Launch_Media|Launch_App1|Launch_App2|AppsKey|PrintScreen|CtrlBreak|Pause|Break|Help|Sleep|vk[a-fA-F0-9]{2}|sc[a-fA-F0-9]{3})\b|`;|([^\s](?!\w)))"
, OPTIONAL_PASSTHROUGH := "(~?)"
, WHITESPACE := "(\s*)"
, AMPERSAND_JOIN := "(&)"
, OPTIONAL_UP := "(Up)?"
, BOL := "^"
, SINGLE_HOTKEY_MODIFIERS := "([~*$+^!#<>]*)"
if (str = "")
return false
Loop ; count how many '&' in hotkey
{
Pos := InStr(str, "&", , Pos + 1)
numAmpersands := A_Index - 1
} Until !Pos
if numAmpersands in 0 ; single hotkey check
return !!RegExMatch(str, BOL
. WHITESPACE
. SINGLE_HOTKEY_MODIFIERS
. VALID_HOTKEY
. WHITESPACE
. OPTIONAL_UP)
else if numAmpersands in 1,2,3 ; multihotkey check
return !!RegExMatch(str, BOL
. WHITESPACE
. OPTIONAL_PASSTHROUGH
. VALID_HOTKEY
. WHITESPACE
. AMPERSAND_JOIN
. WHITESPACE
. OPTIONAL_PASSTHROUGH
. VALID_HOTKEY
. WHITESPACE
. OPTIONAL_UP)
else ; invalid hotkey, too many & & & & ...
return false
throw new Exception(Format("Error: {}(""{}"") wasnt caught by any of the checks", A_ThisFunc, str))
}
assert(condition, fn, arg) {
static MESSAGE := "<{}>: {}(""{}"") == '{}'`n"
return Format(MESSAGE
, fn.Call(arg) == condition ? "PASS" : "FAIL"
, fn.Name
, arg
, condition ? "true" : "false")
}
Code: Select all
;fails (but the hotkey is valid):
invalid .= neq.Call("&")
;fails (as expected):
invalid .= neq.Call("a up & b up")
;succeed (and are valid):
valid .= eq.Call("LCtrl & &")
valid .= eq.Call("& & &")
valid .= eq.Call("LCtrl & LCtrl")
valid .= eq.Call("Ctrl & Ctrl")
valid .= eq.Call("a & a")
valid .= eq.Call("a & b")
valid .= eq.Call("a & b up")
valid .= eq.Call("a & &")
valid .= eq.Call("& & a")
Code: Select all
;&::SoundBeep
;LCtrl & &::SoundBeep ;works if press Ctrl+7 (without Shift)
;& & &::SoundBeep
;LCtrl & LCtrl::SoundBeep ;doesn't work (but doesn't trigger error either)
;Ctrl & Ctrl::SoundBeep ;doesn't work if press LCtrl by itself, does work if use LCtrl and RCtrl
;a & a::SoundBeep ;doesn't work (but doesn't trigger error either)
;a & b::SoundBeep
;a & b up::SoundBeep
;a & &::SoundBeep ;can work, a bit unreliable
;& & a::SoundBeep ;can work, a bit unreliable
;a up & b up::SoundBeep ;error message: 'Invalid hotkey'
Code: Select all
#NoEnv
#SingleInstance Force
SetBatchLines -1
fn := Func("isLikeHotkey")
eq := Func("assert").Bind(true, fn)
neq := Func("assert").Bind(false, fn)
valid := "Testing valid hotkeys`n`n"
valid .= eq.Call("Up Up")
valid .= eq.Call("Up")
valid .= eq.Call("``") ; hotkey is meant to be single `::
valid .= eq.Call("`; Up")
valid .= eq.Call(":")
valid .= eq.Call(" & & & ")
valid .= eq.Call(" & & k")
valid .= eq.Call("h & j Up")
valid .= eq.Call("~*>$>>+!^#<g Up")
valid .= eq.Call("vk24 & vk23")
valid .= eq.Call("sc123")
valid .= eq.Call("z")
valid .= eq.Call("LCtrl & &")
valid .= eq.Call("& & &")
valid .= eq.Call("LCtrl & LCtrl")
valid .= eq.Call("Ctrl & Ctrl")
valid .= eq.Call("a & a")
valid .= eq.Call("a & b")
valid .= eq.Call("a & b up")
valid .= eq.Call("a & &")
valid .= eq.Call("& & a")
valid .= eq.Call("&")
MsgBox % valid
invalid := "Testing invalid hotkeys`n`n"
invalid .= neq.Call("") ; blank hotkey, ie ::
invalid .= neq.Call(" * g & h Up")
invalid .= neq.Call("not_a_hotkey")
invalid .= neq.Call("g Up & g Up")
invalid .= neq.Call("vk12sc123")
invalid .= neq.Call("vk123456")
invalid .= neq.Call("a up & b up")
MsgBox % invalid
Clipboard := valid "`n" invalid
ExitApp
Esc::ExitApp
isLikeHotkey(str) {
static VALID_HOTKEY := "(\b(LButton|RButton|MButton|XButton1|XButton2|WheelDown|WheelUp|WheelLeft|WheelRight|CapsLock|Space|Tab|Enter|Return|Escape|Esc|Backspace|BS|ScrollLock|Delete|Del|Insert|Ins|Home|End|PgUp|PgDn|Up|Down|Left|Right|Numpad0|NumpadIns|Numpad1|NumpadEnd|Numpad2|NumpadDown|Numpad3|NumpadPgDn|Numpad4|NumpadLeft|Numpad5|NumpadClear|Numpad6|NumpadRight|Numpad7|NumpadHome|Numpad8|NumpadUp|Numpad9|NumpadPgUp|NumpadDot|NumpadDel|NumLock|NumpadDiv|NumpadMult|NumpadAdd|NumpadSub|NumpadEnter|F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|F13|F14|F15|F16|F17|F18|F19|F20|F21|F22|F23|F24|LWin|RWin|Control|Ctrl|Alt|Shift|LControl|LCtrl|RControl|RCtrl|LShift|RShift|LAlt|RAlt|Browser_Back|Browser_Forward|Browser_Refresh|Browser_Stop|Browser_Search|Browser_Favorites|Browser_Home|Volume_Mute|Volume_Down|Volume_Up|Media_Next|Media_Prev|Media_Stop|Media_Play_Pause|Launch_Mail|Launch_Media|Launch_App1|Launch_App2|AppsKey|PrintScreen|CtrlBreak|Pause|Break|Help|Sleep|vk[a-fA-F0-9]{2}|sc[a-fA-F0-9]{3})\b|`;|([^\s](?!\w)))"
, OPTIONAL_PASSTHROUGH := "(~?)"
, WHITESPACE := "(\s*)"
, AMPERSAND := "(&)"
, OPTIONAL_UP := "(\s*Up)?"
, BOL := "^"
, SINGLE_HOTKEY_MODIFIERS := "([~*$+^!#<>]*)"
, AMPERSAND_HOTKEY := BOL WHITESPACE SINGLE_HOTKEY_MODIFIERS AMPERSAND WHITESPACE OPTIONAL_UP
, SINGLE_HOTKEY := BOL WHITESPACE SINGLE_HOTKEY_MODIFIERS VALID_HOTKEY WHITESPACE OPTIONAL_UP
, MULTI_HOTKEY := BOL WHITESPACE OPTIONAL_PASSTHROUGH VALID_HOTKEY WHITESPACE AMPERSAND WHITESPACE OPTIONAL_PASSTHROUGH VALID_HOTKEY WHITESPACE OPTIONAL_UP
if (str = "") ; bail early
return false
StrReplace(strCopy := str, "&",, numAmpersands) ; count how many '&' in hotkey
; handle case, where ampersand is a single hotkey '&::',
; and not a joining char or left/right part of a multihotkey
if (numAmpersands = 1 && RegExMatch(str, AMPERSAND_HOTKEY))
numAmpersands := 0 ; this forces the ampersand hotkey to be evaluated as a single hotkey
if numAmpersands in 0 ; single hotkey check
return !!RegExMatch(str, SINGLE_HOTKEY)
else if numAmpersands in 1,2,3 ; multihotkey check
return !!RegExMatch(str, MULTI_HOTKEY)
else ; invalid hotkey, too many & & & & ...
return false
throw new Exception(Format("Error: {}(""{}"") wasnt caught by any of the checks", A_ThisFunc, str))
}
assert(condition, fn, arg) {
static MSG := "<{}>: {}(""{}"") == '{}'`n"
return Format(MSG
, fn.Call(arg) == condition ? "PASS" : "FAIL"
, fn.Name
, arg
, condition ? "true" : "false")
}
Code: Select all
:*?://::{#} ;idle (python) - send text - autocorrect comment character
. "`r`n" ":c*:" vTitle "::"
. "`r`n" ":*:" vLower "::"
. "`r`n" ":c*:" vTitle "-::"
. "`r`n" ":*:" vLower "-::"
Code: Select all
#NoEnv
#SingleInstance Force
SetBatchLines -1
fn := Func("isLikeHotkey")
eq := Func("assert").Bind(true, fn)
neq := Func("assert").Bind(false, fn)
valid := "Testing valid hotkeys`n`n"
valid .= eq.Call("Up Up")
valid .= eq.Call("Up")
valid .= eq.Call("``") ; hotkey is meant to be single `::
valid .= eq.Call("`; Up")
valid .= eq.Call(":")
valid .= eq.Call(" & & & ")
valid .= eq.Call(" & & k")
valid .= eq.Call("h & j Up")
valid .= eq.Call("~*>$>>+!^#<g Up")
valid .= eq.Call("vk24 & vk23")
valid .= eq.Call("sc123")
valid .= eq.Call("z")
valid .= eq.Call("LCtrl & &")
valid .= eq.Call("& & &")
valid .= eq.Call("LCtrl & LCtrl")
valid .= eq.Call("Ctrl & Ctrl")
valid .= eq.Call("a & a")
valid .= eq.Call("a & b")
valid .= eq.Call("a & b up")
valid .= eq.Call("a & &")
valid .= eq.Call("& & a")
valid .= eq.Call("&")
MsgBox % valid
invalid := "Testing invalid hotkeys`n`n"
invalid .= neq.Call("") ; blank hotkey, ie ::
invalid .= neq.Call(" * g & h Up")
invalid .= neq.Call("not_a_hotkey")
invalid .= neq.Call("g Up & g Up")
invalid .= neq.Call("vk12sc123")
invalid .= neq.Call("vk123456")
invalid .= neq.Call("a up & b up")
invalid .= neq.Call(";")
invalid .= neq.Call(";asdq")
invalid .= neq.Call(";q")
MsgBox % invalid
Clipboard := valid "`n" invalid
ExitApp
Esc::ExitApp
isLikeHotkey(str) {
static VALID_HOTKEY := "(\b(LButton|RButton|MButton|XButton1|XButton2|WheelDown|WheelUp|WheelLeft|WheelRight|CapsLock|Space|Tab|Enter|Return|Escape|Esc|Backspace|BS|ScrollLock|Delete|Del|Insert|Ins|Home|End|PgUp|PgDn|Up|Down|Left|Right|Numpad0|NumpadIns|Numpad1|NumpadEnd|Numpad2|NumpadDown|Numpad3|NumpadPgDn|Numpad4|NumpadLeft|Numpad5|NumpadClear|Numpad6|NumpadRight|Numpad7|NumpadHome|Numpad8|NumpadUp|Numpad9|NumpadPgUp|NumpadDot|NumpadDel|NumLock|NumpadDiv|NumpadMult|NumpadAdd|NumpadSub|NumpadEnter|F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|F13|F14|F15|F16|F17|F18|F19|F20|F21|F22|F23|F24|LWin|RWin|Control|Ctrl|Alt|Shift|LControl|LCtrl|RControl|RCtrl|LShift|RShift|LAlt|RAlt|Browser_Back|Browser_Forward|Browser_Refresh|Browser_Stop|Browser_Search|Browser_Favorites|Browser_Home|Volume_Mute|Volume_Down|Volume_Up|Media_Next|Media_Prev|Media_Stop|Media_Play_Pause|Launch_Mail|Launch_Media|Launch_App1|Launch_App2|AppsKey|PrintScreen|CtrlBreak|Pause|Break|Help|Sleep|vk[a-fA-F0-9]{2}|sc[a-fA-F0-9]{3})\b|```;|([^\s;](?!\w)))"
, OPTIONAL_PASSTHROUGH := "(~?)"
, WHITESPACE := "(\s*)"
, AMPERSAND := "(&)"
, OPTIONAL_UP := "(\s*Up)?"
, BOL := "^"
, SINGLE_HOTKEY_MODIFIERS := "([~*$+^!#<>]*)"
, AMPERSAND_HOTKEY := BOL WHITESPACE SINGLE_HOTKEY_MODIFIERS AMPERSAND WHITESPACE OPTIONAL_UP
, SINGLE_HOTKEY := BOL WHITESPACE SINGLE_HOTKEY_MODIFIERS VALID_HOTKEY WHITESPACE OPTIONAL_UP
, MULTI_HOTKEY := BOL WHITESPACE OPTIONAL_PASSTHROUGH VALID_HOTKEY WHITESPACE AMPERSAND WHITESPACE OPTIONAL_PASSTHROUGH VALID_HOTKEY WHITESPACE OPTIONAL_UP
if (str = "") ; bail early
return false
StrReplace(strCopy := str, "&",, numAmpersands) ; count how many '&' in hotkey
; handle case, where ampersand is a single hotkey '&::',
; and not a joining char or left/right part of a multihotkey
if (numAmpersands = 1 && RegExMatch(str, AMPERSAND_HOTKEY))
numAmpersands := 0 ; this forces the ampersand hotkey to be evaluated as a single hotkey
if numAmpersands in 0 ; single hotkey check
return !!RegExMatch(str, SINGLE_HOTKEY)
else if numAmpersands in 1,2,3 ; multihotkey check
return !!RegExMatch(str, MULTI_HOTKEY)
else ; invalid hotkey, too many & & & & ...
return false
throw new Exception(Format("Error: {}(""{}"") wasnt caught by any of the checks", A_ThisFunc, str))
}
assert(condition, fn, arg) {
static MSG := "<{}>: {}(""{}"") == '{}'`n"
return Format(MSG
, fn.Call(arg) == condition ? "PASS" : "FAIL"
, fn.Name
, arg
, condition ? "true" : "false")
}
Code: Select all
:*?://::{#} ;idle (python) - send text - autocorrect comment character
. "`r`n" ":c*:" vTitle "::"
. "`r`n" ":*:" vLower "::"
. "`r`n" ":c*:" vTitle "-::"
. "`r`n" ":*:" vLower "-::"
;in each case above, the text before the :: is being interpreted as a hotkey:
:*?://
. "`r`n" ":c*:" vTitle "
. "`r`n" ":*:" vLower "
. "`r`n" ":c*:" vTitle "-
. "`r`n" ":*:" vLower "-
Users browsing this forum: morkovka18, Shifted_Right and 173 guests