How to Turn AutoHotkey Hotstring AutoCorrect Pop-up Menus into a Function, (Part 5, Beginning Hotstrings)

Save Redundant AutoHotkey Code by Creating a Function for Pop-up Hotstring Menus

*          *          *

Beginning AutoHotkey Hotstrings 200pxAs a convenience for people who want to get this entire series (plus more) in one place, I have now published the e-book Beginning AutoHotkey Hotstrings which is available on the ComputorEdge E-Books site (in three formats—EPUB for mobile devices, MOBI for Kindle, and PDF for printing and computer) and through Amazon. Regardless of whether you’re interested in the book or not, it’s worth your time to peruse some of the blogs linked at “Beginning AutoHotkey Hotstring Techniques” found under the “AutoHotkey Topics and Series” tab in the top menu bar. They just might inspire your next AutoHotkey script.

*          *          *

In the last blog I introduced a technique for creating AutoHotkey selection menus whenever there are multiple possible choices for common misspellings or typos. That snippet of code can be reused by merely changing the activation Hotstring and including a Menu, Add command line for each possible correction. The primary problem with this approach is the number of possible selections adds many additional lines of code to the script for each new AutoCorrect word. By building a function the redundant code is written only one time and used over and over again. At most, each new Hotstring menu only requires three lines of code. Let’s start with the agin example from last time:

::agin::
 Menu, MyMenu, add, again, MenuAction
 Menu, MyMenu, add, a gin, MenuAction
 Menu, MyMenu, add, aging, MenuAction
 Menu, MyMenu, Show
Return

MenuAction:
 SendInput %A_ThisMenuItem%
 Menu, MyMenu, DeleteAll
Return

The plan is to place all the Menu commands inside a function which builds a new AutoCorrect menu each time it is called. One calling function will set up a menu for all of the AutoCorrect options:

TextMenu(Words)

I’ve named the function TextMenu. Any parameters needed by the function appear within the parentheses. In this case the parameter Words contains the list of possible replacement options for the AutoCorrect menu. We can directly add the words to the function by enclosing the list in double quotes. For example, using agin as the Hotstring:

::agin::
  TextMenu("again,a gin,aging")
Return

If the TextMenu() function is properly constructed, this is all that will be needed to set up an individual Hotstring menu. Although almost any separating character may be used, here commas are placed between the option words in the list. The commas make it easy to separate the list into individual words using another AutoHotkey trick inside the function. The plan is to parse the list of Words to create a menu item for each entry with the following function:

TextMenu(TextOptions)
{
  StringSplit, MenuItems, TextOptions , `,
  Loop %MenuItems0%
  {
    Item := MenuItems%A_Index%
    Menu, MyMenu, add, %Item%, MenuAction
  }
  Menu, MyMenu, Show
}

This function may look a little more complex than merely repeating the code from the last blog, but once understood, this snippet will add more power to your AutoCorrect script. A new menu building command called TextMenu() is added to your bag of tricks. There are two important AutoHotkey commands used to build this menu function.

ComputorEdge AutoHotkey E-BooksThe first is the StringSplit command which separates (parses) the list of Words into individual pieces. In the above function, StringSplit automatically breaks up the TextOptions word list into each word and stores it in a different numbered variable. Note that the function assigned the variable TextOptions (inside the parentheses) to the list of words passed to the function. The variable TextOptions only temporarily exists within the function and does not affect any other part of the script.

The line of code (StringSplit, MenuItems, TextOptions , `,) saves the parsed words to a set of MenuItems variables (i.e.MenuItems1, MenuItems2, and MenuItems3). There is an additional variable created (MenuItems0) which contains the number of words in the list. Any character may be used to delimit and separate the words (designated by the parameter at the the end of the StringSplit command line), but, since the comma is commonly used in lists, here it acts as the delimiter. However, since the comma is a special character it needs escaping with the backtick character (`,).

The StringSplit output is used to build the menu with the Loop command—the second new command:

  Loop %MenuItems0%
  {
    Item := MenuItems%A_Index%
    Menu, MyMenu, add, %Item%, MenuAction
  }

The Loop command repeats the code between the two curly brackets a designated number of times (%MenuItems0%) or until it encounters the Break command. Since the number of menu items is known (MenuItems0) there is no need to use the Break command. (Placing MenuItems0 between percent signs % inserts the value of MenuItems0 into the Loop command.)

The Loop command includes the built-in variable A_Index which keeps track of the current iteration of the loop. A_Index can be used to recall the variable for each word in the menu (Item := MenuItems%A_Index%). When first executed the loop assigns the variable name MenuItems1 to Item. On the second iteration MenuItems2 is stored to Item—and so on.

In the same Loop, by placing Item between percent signs (%Item%) the variable evaluates to the corresponding variable name (e.g. MenuItems1, MenuItems2,…) for use in the menu (Menu, MyMenu, add, %Item%, MenuAction). The menu is created. Now, all that’s needed is to Show the Menu:

 Menu, MyMenu, Show

As discussed last time, the Label subroutine MenuAction: must exist.

MenuAction:
  SendInput %A_ThisMenuItem%
  Menu, MyMenu, DeleteAll
Return

First, I notice that I was remiss last time in not adding the activating end character to the MenuAction: subroutine (A_EndChar—first introduced in Part 3).

MenuAction:
  SendInput %A_ThisMenuItem%%A_EndChar%
  Menu, MyMenu, DeleteAll
Return

By adding the built-in variable A_EndChar which stores the last activating key pressed, the replacement will restore that ending character.

One more change. Move the Menu, MyMenu, DeleteAll from the Label subroutine MenuAction: to the end of the function TextMenu(). This will ensure that the menu items are deleted after the menu is activated. If the menu deletion line remains in MenuAction:, then, when no selection is made (Escape or mouse click off the menu), the old menu items could appear in a new Hotstring menu. The final function and Label subroutine appear as follows:

TextMenu(TextOptions)
{
  StringSplit, MenuItems, TextOptions , `,
  Loop %MenuItems0%
  {
    Item := MenuItems%A_Index%
    Menu, MyMenu, add, %Item%, MenuAction
  }
  Menu, MyMenu, Show
  Menu, MyMenu, DeleteAll      ;Moved from MenuAction:
}
MenuAction:
  SendInput %A_ThisMenuItem%%A_EndChar%
Return

I just noticed that the exclamation point (!) does not automatically get added to the end of the replacement string when used as the activating character. The exclamation point is the special character for the ALT key in HotKey combinations. Normally, to get a plain vanilla exclamation point, it must be escaped with the backtick (`!)—which is unworkable in this situation. The solution could be to remove the exclamation point’s magical powers by using the SendRaw command. However, when using SendInput, merely adding the term {Raw} before the terminating variable has the same effect.

MenuAction:
  SendInput %A_ThisMenuItem%{Raw}%A_EndChar%
Return

Now, if you want to add a new Hotstring menu with multiple options to your AutoCorrect file, all you need to do is call the new function TextMenu():

::duh::
  TextMenu("what,huh,you're joking")
Return

Next time, we’ll look at other practical ways to use this Hotstring menu function, such as, a menu for inserting currency symbols.

*         *          *

Find Jack’s AutoHotkey e-Books at ComputorEdgeBooks.com.

Advertisements

One thought on “How to Turn AutoHotkey Hotstring AutoCorrect Pop-up Menus into a Function, (Part 5, Beginning Hotstrings)

  1. Hi Jack,

    I really like your blog. This is very useful information. Thanks a lot for sharing. I’ve only made a small adjustment to the “Pop-up Hotstring Menu” that I wanted to share. To make it easier to select the menu entries via keyboard I’m just adding “&” to the Menu entries. That way the entries can be selected by typing the first letter of the respective entry. (If multiple entries have the same first letter typing the letter repeatedly will jump from entry to entry.):

    TextMenu(TextOptions)
    {
    StringSplit, MenuItems, TextOptions , `,
    Loop %MenuItems0%
    {
    Item := MenuItems%A_Index%
    Menu, MyMenu, add, &%Item%, MenuAction
    }
    Menu, MyMenu, Show
    Menu, MyMenu, DeleteAll
    }
    MenuAction:
    StringReplace, ThisMenuItem, A_ThisMenuItem, &
    SendInput %ThisMenuItem%{Raw}%A_EndChar%
    Return

    Dirk

    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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s