How to Send dynamic values in an array

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
donsonmd
Posts: 55
Joined: 19 Feb 2017, 05:57

How to Send dynamic values in an array

Post by donsonmd » 30 Nov 2021, 10:50

Hello,

I have struggled to use the Hotstring.ahk function to retrieve values of a dynamic array as below:

Code: Select all

#Include Hotstring.ahk

F5::

; CPT is a dynamic array in a real script.
CPT := [99202,99203,99204,99205,99212,99213,99214,99215,99384,99385,99386,99387,99394,99395,99396,99397]

For each, value in CPT
      Hotstring("cpt" . each, value)

return
I noticed that the Hotstring function is triggered without pressing an ending character like '*' option in hotstrings, ':*:'. If 'each' in the 'for' loop is greater than 9, for example, ≥CPT10, 'CPT1' will trigger before typing the next digit.

Q1. I don't know if Hotstring.ahk has an option similar to 'o' option in hostrings, so that triggering occurs only when an ending character is pressed.

Q2. My original script is 10 thousand-line long and seems to be conflicted with Hotstring.ahk some way. The above code alone works well for CPT1-CPT9, but when I put it in my original script, it doesn't work regardless of where I place it. Any idea on this issue?

Q3. If the issues in Q1 and Q2 are not resolved, I may have to consider another method. The array is dynamic in both its length and values. Any ideas? I thought of using 'Menu,' but too difficult for me. Please help me out. Thank you so much.

User avatar
flyingDman
Posts: 2817
Joined: 29 Sep 2013, 19:01

Re: How to Send dynamic values in an array

Post by flyingDman » 30 Nov 2021, 12:19

You may want to post the code for the Hotstring.ahk script you are using. There are several out there.
14.3 & 1.3.7

donsonmd
Posts: 55
Joined: 19 Feb 2017, 05:57

Re: How to Send dynamic values in an array

Post by donsonmd » 30 Nov 2021, 12:38

My bad. Sorry. The code was obtained from https://github.com/menixator/hotstring/blob/master/Hotstring.ahk. Thank you :D :D

Code: Select all

/*
Hotstring(
	trigger:
		A string or a regular expression to trigger the hotstring. (If you use a regex here, the mode should be 3 for the regex to work)
	
	label:  	
		A string to replace the trigger / A label to go to / A function to call when the hotstring is triggered.
		If you used a regular expression as the trigger and mode was set to three, backreferences like $0, $1 would work.
		If a function name was passed, the function will be called with the phrase that triggered the hotstring(If the trigger was a string)
			or the Match object(If the trigger was a regex & mode equals 3).
		If this parameter was a label, the global variable '$' will contain the string/match object.
		If you wish to remove a hotstring, Pass the trigger with this parameter empty.
	
	Mode:	
		A number between 1 and 3 that determines the properties of the hotstring.
		If Mode == 1 then the hotstring is case insensitive.
		If Mode == 2 then the hostrings is case sensitive.
		If Mode == 3 then you can use regex in the trigger.
		
		1 is the defualt.
	
	clearTrigger:
			Determines if the trigger is erased after the hotstring is triggered.
	
	cond:
			A name of a function that allows the conditional trigerring of the hotstring.
	
)
*/
Hotstring(trigger, label, mode := 1, clearTrigger := 1, cond := ""){
	global $
	static keysBound := false,hotkeyPrefix := "~$", hotstrings := {}, typed := "", keys := {"symbols": "!""#$%&'()*+,-./:;<=>?@[\]^_``{|}~", "num": "0123456789", "alpha":"abcdefghijklmnopqrstuvwxyz", "other": "BS,Return,Tab,Space", "breakKeys":"Left,Right,Up,Down,Home,End,RButton,LButton,LControl,RControl,LAlt,RAlt,AppsKey,Lwin,Rwin,WheelDown,WheelUp,f1,f2,f3,f4,f5,f6,f7,f8,f9,f6,f7,f9,f10,f11,f12", "numpad":"Numpad0,Numpad1,Numpad2,Numpad3,Numpad4,Numpad5,Numpad6,Numpad7,Numpad8,Numpad9,NumpadDot,NumpadDiv,NumpadMult,NumpadAdd,NumpadSub,NumpadEnter"}, effect := {"Return" : "`n", "Tab":A_Tab, "Space": A_Space, "Enter":"`n", "Dot": ".", "Div":"/", "Mult":"*", "Add":"+", "Sub":"-"}
	
	if (!keysBound){
		;Binds the keys to watch for triggers.
		for k,v in ["symbols", "num", "alpha"]
		{
			;alphanumeric/symbols
			v := keys[v]
			Loop,Parse, v
				Hotkey,%hotkeyPrefix%%A_LoopField%,__hotstring
		}
		
		v := keys.alpha
		Loop,Parse, v
			Hotkey, %hotkeyPrefix%+%A_Loopfield%,__hotstring
		for k,v in ["other", "breakKeys", "numpad"]
		{
			;comma separated values
			v := keys[v]
			Loop,Parse, v,`,
				Hotkey,%hotkeyPrefix%%A_LoopField%,__hotstring
		}
		keysBound := true ;keysBound is a static varible. Now, the keys won't be bound twice.
	}
	if (mode == "CALLBACK"){
		; Callback for the hotkey.s
		Hotkey := SubStr(A_ThisHotkey,3)
		if (StrLen(Hotkey) == 2 && Substr(Hotkey,1,1) == "+" && Instr(keys.alpha, Substr(Hotkey, 2,1))){
			Hotkey := Substr(Hotkey,2)
			if (!GetKeyState("Capslock", "T")){
				StringUpper, Hotkey,Hotkey
			}
		}
		
		shiftState := GetKeyState("Shift", "P")
		uppercase :=  GetKeyState("Capslock", "T") ? !shiftState : shiftState 
		;If capslock is down, shift's function is reversed.(ie pressing shift and a key while capslock is on will provide the lowercase key)
		if (uppercase && Instr(keys.alpha, Hotkey)){
			StringUpper, Hotkey,Hotkey
		}
		if (Instr("," . keys.breakKeys . ",", "," . Hotkey . ",")){
			typed := ""
			return
		} else if Hotkey in Return,Tab,Space
		{
			typed .= effect[Hotkey]
		} else if (Hotkey == "BS"){
			; trim typed var if Backspace was pressed.
			StringTrimRight,typed,typed,1
			return
		} else if (RegExMatch(Hotkey, "Numpad(.+?)", numKey)) {
			if (numkey1 ~= "\d"){
				typed .= numkey1
			} else {
				typed .= effect[numKey1]
			}
		} else {
			typed .= Hotkey
		}
		matched := false
		for k,v in hotstrings
		{
			matchRegex := (v.mode == 1 ? "Oi)" : "")  . (v.mode == 3 ? RegExReplace(v.trigger, "\$$", "") : "\Q" . v.trigger . "\E") . "$"
			
			if (v.mode == 3){
				if (matchRegex ~= "^[^\s\)\(\\]+?\)"){
					matchRegex := "O" . matchRegex
				} else {
					matchRegex := "O)" . matchRegex
				}
			}
			if (RegExMatch(typed, matchRegex, local$)){
				matched := true
				if (v.cond != "" && IsFunc(v.cond)){
					; If hotstring has a condition function.
					A_LoopCond := Func(v.cond)
					if (A_LoopCond.MinParams >= 1){
						; If the function has atleast 1 parameters.
						A_LoopRetVal := A_LoopCond.(v.mode == 3 ? local$ : local$.Value(0))
					} else {
						A_LoopRetVal := A_LoopCond.()
					}
					if (!A_LoopRetVal){
						; If the function returns a non-true value.
						matched := false
						continue
					}
				}
				if (v.clearTrigger){
					;Delete the trigger
					SendInput % "{BS " . StrLen(local$.Value(0))  . "}"
				}
				if (IsLabel(v.label)){
					$ := v.mode == 3 ? local$ : local$.Value(0)
					gosub, % v.label
				} else if (IsFunc(v.label)){
					callbackFunc := Func(v.label)
					if (callbackFunc.MinParams >= 1){
						callbackFunc.(v.mode == 3 ? local$ : local$.Value(0))
					} else {
						callbackFunc.()
					}
				} else {
					toSend := v.label
				
					;Working out the backreferences
					Loop, % local$.Count()
						StringReplace, toSend,toSend,% "$" . A_Index,% local$.Value(A_index),All
					toSend := RegExReplace(toSend,"([!#\+\^\{\}])","{$1}") ;Escape modifiers
					SendInput,%toSend%
				}
				
			}
		}
		if (matched){
			typed := ""
		} else if (StrLen(typed) > 350){
			StringTrimLeft,typed,typed,200
		}
	} else {
		if (hotstrings.HasKey(trigger) && label == ""){
			; Removing a hotstring.
			hotstrings.remove(trigger)
		} else {
			; Add to hotstrings object.
			hotstrings[trigger] := {"trigger" : trigger, "label":label, "mode":mode, "clearTrigger" : clearTrigger, "cond": cond}
		}
		
	}
	return

	__hotstring:
	; This label is triggered every time a key is pressed.
	Hotstring("", "", "CALLBACK")
	return
}

donsonmd
Posts: 55
Joined: 19 Feb 2017, 05:57

Re: How to Send dynamic values in an array

Post by donsonmd » 30 Nov 2021, 20:57

I was able to figure out how to make this work thanks to the idea obtained from viewtopic.php?t=3329. So the issues in my Q1 and Q3 are resolved. However, the issue in Q3 persists when I put the code in my original ten thousand line-long script. No duplicate hotstrings exist in the original scripts. I can't think of any cause. Could anyone tell why?

Also, I don't understand why Send, % $.value(1)[$.value(2)$.value(3)] in the code below does not work, either. Please explain if anyone knows. Many thanks.

Code: Select all

#Include Hotstring.ahk

+^#9::
CPTlist =
ICDlist =

;The arrays in the original script are actually dynamic. They were modified to a static array for simplicity.
CPT := [99202,99203,99204,99205,99212,99213,99214,99215,99384,99385,99386,99387,99394,99395,99396,99397]
ICD := [202,203,204,205,212,213,214,215,384,385,386,387,394,395,396,397]

For each, value in CPT
    CPTlist .= "`nCPT [" each "]:`t" value
For each, value in ICD
    ICDlist .= "`nICD [" each "]:`t" value

Hotstring("(cpt|icd)(\d)(\d)?\s","expand",3)

MsgBox, 4096, TEST, % "▪▪▪▪▪▪▪ CPT List ▪▪▪▪▪▪▪" CPTlist "`n`n▪▪▪▪▪▪▪ ICD List ▪▪▪▪▪▪▪" ICDlist
Return

Expand:
;Send, % $.value(1)[$.value(2)$.value(3)]
If ($.value(1) = "cpt")
    Send, % CPT[$.value(2)$.value(3)]
If ($.value(1) = "icd")
    Send, % ICD[$.value(2)$.value(3)]
Return

Post Reply

Return to “Ask for Help (v1)”