Two-Deep Variables for Tracking Data (AutoHotkey Trick)

When You Find No Obvious Way to Link Specific Data to an Object or Another Value, You Might Try Saving It to a Variable within a Variable

Sometimes you encounter a scripting situation where saving data to just any random variable doesn’t do the job. While creating variables and storing values is simple enough, you may find it difficult to recall those values at the right time. It’s important to know you’re getting the right data when you want it. Maybe using the value of a variable as a variable name (two-deep) will give you what you need.

Saving Unique Variable Names


“Alas, it’s all two-deep for me.”

As in the InstantHotkeyTwoDeep.ahk script, variable names get reused each time AutoHotkey loads a new InstantHotkey GUI. In the last blog, we created a pseudo-array by adding an incremental number to the end of the “InstantHotkey” term. This created unique GUI names for each of our pop-up windows (e.g. InstantHotkey1, InstantHotkey2, InstantHotkey3). This technique provides us with all the information we need while a particular GUI remains active. However, after setting the new Hotkey combination, the problem of both tracking the Hotkey combination itself and the associated insertion text arises.

First, we must save the Hotkey combination just in case we decide to change it later. If we don’t turn off the old Hotkey, it remains in effect—even though we created a new one:

  Gui, Submit

  OldHotkey := %A_Gui% ; e.g. OldHotkey = value of "Hotkey1"

  If OldHotkey != ; Turn off OldHotkey
    Hotkey, %OldHotkey%, Off ; e.g. %OldHotkey% => Hotkey1 value or "^!o"
  If KeyCombo !=
    Hotkey, %KeyCombo%, TextAdd, On

   %A_Gui% := KeyCombo

By clicking the Set Key Combo button after a change to a new Hotkey combination or in the insertion text, the SetupKey: subroutine fires. But, since multiple Instant Hotkey GUIs may exist, how do we know which variables to use?

ComputorEdge AutoHotkey E-BooksWhen accessing a GUI pop-up, the build-in AutoHotkey variable A_Gui contains the name assigned to the GUI (e.g. InstantHotkey1, InstantHotkey2, InstantHotkey3). By assigning the value of the value of A_Gui (%A_Gui%) to a new variable, OldHotkey, we effectively store the Hotkey combination from the last time (if any) in the variable with the same name as the GUI.

This gets a little confusing. The built-in variable A_Gui contains the name (not the title) assigned to the GUI window (e.g. InstantHotkey1). If previously assigned by the GUI, the variable name contained in A_Gui (e.g. InstantHotkey1) holds the value of the Hotkey combination (e.g. ^!o). (This variable assignment—%A_Gui% := KeyCombo—occurred at end of the snippet above when the subroutine ran on the last submit.)

By assigning the contents (e.g. ^!o) of the variable name (e.g. InstantHotkey1) found in A_Gui to OldHotkey, we effective capture the old Hotkey value (e.g. OldHotkey := %A_Gui% or A_GuiInstantHotkey1^!o). We use the name assigned to the GUI to create a two-deep variable for tracking data—in this case, the Hotkey combination—which we can recall any time we know the GUI name.

Ultimately, at the end of the subroutine, we assign the current value of the Hotkey combination to the variable name within the variable A_Gui (%A_Gui% := KeyCombo).

Linking the Insertion Text to the Hotkey Combination with a Two-Deep Variable

When multiple Instant Hotkey GUIs exist, the TextAdd: subroutine from the original InstantHotkey.ahk has no immediate link to which Hotkey connects with which GUI insertion text value:

 SendInput, %TextInsert%

After establishing the Hotkey and even saving the associated text to a unique variable, I found no method for instantly recall the matching text from the appropriate GUI variables. Activating a Hotkey does not offer any extra variables for assigning unique values. In fact, the only variable with any promise for saving data is A_ThisHotkey.

Once the GUI assigns the Hotkey value, the GUI number has no meaning to the launching key combination. I needed a method for connecting the Hotkey combination directly to the Insertion text. I determined a number of ways to do this, but my first example uses a two-deep variable created from the Hotkey combination itself.

Creating a Legal Variable Name

I’ve found that using unique built-in variables to store variable names can make relating different types of information easier. However, for the most part, using Hotkey combinations as a variable name doesn’t work because Hotkeys usually contain illegal variable name characters (^!+). To solve the problem, I wrote a function which converts the illegal characters to legal characters for the two-deep variable. I effectively continue to use the Hotkey combination as the key for the new variable name where I store the insertion text:

IH_VarText(var)  ; the input parameter is a Hotkey combo
IfInString, var, `^
  StringReplace, var, var, `^ , A
IfInString, var, `+
  StringReplace, var, var, `+ , B
IfInString, var, `!
  StringReplace, var, var, `! , C
IfInString, var, [
  StringReplace, var, var, [ , D
IfInString, var, ]
  StringReplace, var, var, ] , E
Return, var     ; the output is a clean variable name

I store the insertion text from the GUI in the new variable in the SetupKey: subroutine with:

If KeyCombo !=
  IH_VarText := "IH_" . IH_VarText(KeyCombo) 
  %IH_VarText% := TextInsert ; Save text to two-deep variable 

This allows me to associate the target text with a variable name based on the Hotkey combination itself. That means whenever I activate the Hotkey combination, I can recall the insertion text by recreating the variable:

  IH_VarText := "IH_" . IH_VarText(A_ThisHotkey)
  SendInput, % %IH_VarText% ; Send two-deep variable value

The classic way to recall the value of a two-deep variable includes the forced expression operator (%) and the macro substitution notation (%variable%) which replaces a variable in a line of code with its contents—also called the traditional variable retrieval method in AutoHotkey documentation. This creates an expression which returns the value of the value of a variable.

Note: You’ll find other—probably better—methods for relating data. One of the most powerful includes associative arrays which allow the creation of sets of data without some of the gymnastics involved two-deep variables. In fact, I’ve found a method for using an ad-hoc array for quickly solving the problem. I plan to explore these options in future blogs using the same InstantHotkey.ahk script. Which approach you use depends upon the task and your inclinations.

You might ask, “If associative arrays work so well, why ever use two-deep variables?” Maybe you use them for pure convenience. Many built-in AutoHotkey variables and Windows parameters can act as containers for variable names which store additional data.

For example, The WinGet command can retrieve a multitude of window data (e.g.  unique ID number (HWND/handle) of a window, the Process ID (PID) of a window, etc). These values might act as a two-deep variable for linking other characteristics to specific windows (e.g. %PID% := “yellow”). When returning to the window, you can retrieve these extra values with the expressions similar to: % %PID%.

While this two-deep variable works for most Hotkey combinations, it excludes any other keys,  such as a semicolon (;) or a slash (/), in the Hotkey combination. I could add more conditions to the IH_VarText(var) function shown above, but I prefer a more universal approach. In the next few blogs, I plan to show the evolution of my thought by introducing alternative approaches before I finally settle on one which seems to solve most of the problems: associative arrays.







One thought on “Two-Deep Variables for Tracking Data (AutoHotkey Trick)

  1. I sure wish you had videos to accompany your amazing tutorials! Or even just a lot of screenshots. (I think my brain maxed out on AHK for the day, I’ll have to try getting through the rest of this post tmw.) Thank you so much for all the time & effort you’ve put into helping others learn how to make the most of this incredible tool!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s