AutoHotkey Tip of the Week: Flexible AutoHotkey Hotstring Menus Using Arrays

New Parameters for the HotstringMenu() Function Adds Flexibility and Power to Pop-up Menus

In my last blog, I started looking at adding the variadic parameter (accepts multiple inputs) and a Menu subroutine parameter to the HotstringMenu() function. While in the process of creating alternative Label subroutines, I found that changing a subroutine often called for a new menu-creating function. Rather than resorting to multiple functions, I decided to add one more parameter for tailoring the master function.

CoverImage200
A Multitude of AutoHotkey Tips and Tricks

Note: This blog discusses the use of AutoHotkey object-based arrays (simple and associative) with the function’s variadic parameter. A review of my books demonstrated that most included discussions of arrays (pseudo-arrays and object-based arrays). In particular,  Chapter 12.1.5 “Using Associative Arrays to Solve the Instant Hotkey Data Recall Problem” in the book Jack’s Motley Assortment of AutoHotkey Tips explains the difference between the various array types while offering a practical example of an associative array.

A Three-Parameter Function

To add more flexibility to the HotstringMenu() function discussed last time, I inserted an additional parameter (MenuType) to the function tailoring the menu before executing the SendInput subroutine:

HotstringMenuV(MenuType,Handle,MenuArray*)

This allows the changing of menu items based upon the MenuType parameter.

Note: While adding more parameters to the function does make it more flexible, it does not necessarily make it simpler. For that reason, I continue to include the original HotstringMenu() function in the master script and changed the name of the variadic form of the function to HotstringMenuV(). Some people may find the original function easier to use (as described in the blogs “AutoHotkey Hotstring Menus for Text Replacement Options” and “Hotstring Menu Techniques for Inserting Symbols and Emojis“).

When added to the new HotstringMenuV() function, the following conditions create alternative tailored menus.

Add Numeric Single-Key Shortcuts

MenuNumShortcutWhen added to the For Each, Item in MenuArray loop, the following menu command creates a numeric single-key shortcut. Using “N” as the MenuType code, the script inserts the following menu item:

If (MenuType = "N")
  Menu, MyMenu, Add, % "&" Each " " Item, % Handle

The script uses the Menu command to add the next array item to the Hotstring menu. The numeric default value of the simple array key Each (or A_Indexcreates the menu shortcut keys (&1, &2, &3, …) while appending the replacement text (Item) to the menu item.

Called with the following Hotstring:

:x:bn::HotstringMenuV("N","MenuShortcut","Ox"
                         ,"Water Buffalo","Cow")

Note: Many of the code snippets in this blog use line continuation techniques to wrap lines of code for display purposes. In most cases, the wrapped lines start with a comma. AutoHotkey reads those broken lines of code as part of the previous command or function.

The new MenuShortcut subroutine automatically removes the added menu single-key shortcut characters before text replacement:

MenuShortcut:
  TextOut := SubStr(A_ThisMenuItem, 4)
  SendInput {raw}%TextOut%%A_EndChar%
Return

The SubStr(A_ThisMenuItem, 4) function eliminates the first three characters of the output text which include the single-key shortcut and one space.

Add Alphabetical Single-Key Shortcuts

MenuAlphaShortcut.pngWhen added to the For Each, Item in MenuArray loop, the following menu command creates an alphabetic single-key shortcut. Using “A” as the MenuType code, the script inserts the following menu item:

If (MenuType = "A")
  Menu, MyMenu, Add, % "&" Chr(Each+96) " " Item, % Handle

Adding 97 to the numeric default value of Each and converting to the ASCII character value (Chr(Each+96)) creates an alphabetic menu shortcut key (&a, &b, &c, …) and appends the replacement text (Item) to the menu item.

Called with the following Hotstring:

:x:ba::HotstringMenuV("A","MenuShortcut","Ox"
                         ,"Water Buffalo","Cow")

This alphabetical conditional uses the same MenuShortcut subroutine as the previous numeric shortcut key conditional.

Adding Simple Array Menu Items

The following two simple array function calls operate identically. The simple array definition format:

:x*?:c``::HotstringMenuV(""
          ,"HotstringMenuAction",["⇐ | Left arrow &1"
          ,"⇔ | Double arrow &2","⇒ | Right arrow &3"
          ,"⇑ | Up arrow &4","⇓ |Down arrow &5"]*)

Adding the asterisk to the end of the variadic parameter call forces evaluation as an array. However, the variadic format shown next in the next example works just as well without the square brackets and asterisk ([]*):

:x*?:c``::HotstringMenuV(""
          ,"HotstringMenuAction","⇐ | Left arrow &1"
          ,"⇔ | Double arrow &2","⇒ | Right arrow &3"
          ,"⇑ | Up arrow &4","⇓ |Down arrow &5")

While the variadic function parameter can force a simple array definition with square brackets and the asterisk ([…]*) (as shown in the previous example), you’ll find no advantage in doing so—the variadic parameter assumes a simple array for any comma-delimited list (“text1″,var1,”text2”,var2) without using the array definition format ([“text1″,var1,”text2”,var2]*).

However, calling an established simple array by name can save space when calling the function. First, define the array (normally in the AutoExecute portion of the script):

Arrows := ["⇐ | Left arrow &1","⇔ | Double arrow &2"
          ,"⇒ | Right arrow &3","⇑ | Up arrow &4"
          ,"⇓ |Down arrow &5"]

Second, add the array name to the variadic parameter appending the asterisk (*):

:x*?:c``::HotstringMenuV("","HotstringMenuAction",Arrows*)

This produces an easier-to-read calling function and makes array editing simpler—especially if you use the array in more than one place in a script.

Using a blank MenuType code defaults to using the original Menu command:

Menu, MyMenu, add, % Item , % Handle

This Menu command, when used in conjunction with the original HotstringMenuAction subroutine, performs in the same manner as the old HotstringMenu() function discussed last time.

The original subroutine using the same criteria as the previous function follows:

HotstringMenuAction:
  InsertText := StrSplit(A_ThisMenuItem, "|")
  TextOut := StrReplace(RTrim(InsertText[1]), "&")
  SendInput {raw}%TextOut%%A_EndChar%
Return

Adding Associative Array Menu Items

MenuArrowsAssociativeWhile the above variadic function calls create a simple array from the list of values or the array name included in the parameter, you can pass an associative array (key and value) directly by name or create such an array inside the calling function.

 If (MenuType = "T")  ; Associative array
  Menu, MyMenu, Add, % Each " | " Item, % Handle

I assigned the code “T” to associative arrays which use both an assigned key and value in the menu item.

To define the associative array inside the calling function, use the asterisk (*) after the array list ({…}*):

:x*?:a``::HotstringMenuV("T"
          ,"HotstringMenuAction",{⇐: "Left arrow &1"
          ,⇔: "Double arrow &5",⇒: "Right arrow &3"
          ,⇑: "Up arrow &2",⇓: "Down arrow &4"}*)

To call an associative array by name:

1) Define the array:

ArrowsA := {⇐: "Left arrow &1"
          ,⇔: "Double arrow &5",⇒: "Right arrow &3"
          ,⇑: "Up arrow &2",⇓: "Down arrow &4"}

2) Use the array name as the variadic parameter followed by the asterisk (*):

:x*?:c``::HotstringMenuV("T","HotstringMenuAction",ArrowsA*)

New HotstringMenuV() Function

The HotstringMenuV() function:

HotstringMenuV(MenuType,Handle,MenuArray*)
{
  For Each, Item in MenuArray
    If (MenuType = "A")
      Menu, MyMenu, Add, % "&" Chr(Each+64) " " Item, % Handle
    Else If (MenuType = "N")
      Menu, MyMenu, Add, % "&" Each " " Item, % Handle
    Else If (MenuType = "T")
      Menu, MyMenu, Add, % Each " | " Item, % Handle
    Else
      Menu, MyMenu, add, % Item , % Handle
  Menu, MyMenu, Show
  Menu, MyMenu, DeleteAll
}

If you want to add another Menu command, create a new MenuType code and plug it in as an additional Else If statement.

Label Subroutines

Control the menu output by writing additional subroutines and calling them through the function.

Original menu output subroutine:

HotstringMenuAction:
  InsertText := StrSplit(A_ThisMenuItem, "|")
  TextOut := StrReplace(RTrim(InsertText[1]), "&")
  SendInput {raw}%TextOut%%A_EndChar%
Return

Single-key shortcut output subroutine:

MenuShortcut:
  TextOut := SubStr(A_ThisMenuItem, 4)
  SendInput {raw}%TextOut%%A_EndChar%
Return

Add the HotstringMenuV() function plus the needed Label subroutines to your master Hotstring file to create flexible Hotstring menus for your AutoHotkey scripts.

Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)

jack

This post was proofread by Grammarly
(Any other mistakes are all mine.)

(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)

2 thoughts on “AutoHotkey Tip of the Week: Flexible AutoHotkey Hotstring Menus Using Arrays

  1. This one is tough. He must be tired after writing all these because this one has some problem sentences. He also uses a term in italics “mlk.” I don’t know what it means, but in one case he has it in a phrase: “Amalickiah has a mlk-name…” Is mlk a Hebrew word and is pronounced, or is it an acronym and pronounced m-l-k (in which case the article would be “an”)?

    Like

    • I certainly may have some problem sentences, (I usually do), but I was unable to find “Amalickiah has a mlk-name…” in the text. Sounds like your browser has a delivery problem. Try rebooting and look again. Let me know.

      Like

Leave a Reply

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

WordPress.com Logo

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

Facebook photo

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

Connecting to %s