Understanding Label Names and Subroutines (Beginning AutoHotkey Tip)

Once You Know How AutoHotkey Label Names Work, You Can Add More Tricks to Your Bag of AutoHotkey Skills

cheeseburger-ingredientsWhile in the past I often used the terms AutoHotkey Label and subroutine interchangeably, that’s not exactly accurate—although the two terms maintain a close relationship. Misunderstanding how Label names work can be a source of errors for new AutoHotkey script writers. However, knowing the differences between what constitutes a Label and a subroutine opens up new scripting opportunities. The CheeseBurgerRecipe.ahk script uses little-known Label behavior to either walk through all the steps or jump to individual sections of the recipe for a “Jack Stuffed Cheeseburger.”

AutoHotkey Label Names as Markers

AutoHotkey Library Deal
AutoHotkey Library Deal

In AutoHotkey, what we refer to as a Label name consists of text followed by a colon (e.g. LabelName:). During the first pass of a loading AutoHotkey script and prior to running the auto-execute section (at the top of the script), AutoHotkey processes all Label names—along with Hotkeys, Hotstrings, and #Directives—marking the physical location of each. After that, Label names do nothing more than identify specific spots in the script. They can be equated to the line numbers used in GOTO statements in early programming languages.

To prevent conflicts, each Label name must be unique with nothing other than AutoHotkey comments (e.g. ; notes) appearing to the right of the colon. After the first phase of loading and starting with the processing of the auto-execute section of the script, AutoHotkey completely ignores the Label names—except when called by a command such as GUI gLabel, Hotkey, Menu, SetTimer, GoTo, and GoSub. Even then, the Label name only tells AutoHotkey where to jump in the script.

Think of each Label name as a signpost, marker, or pointer permanently embedded at one unique position in the script. You can fix that Label virtually anywhere within the code—although calling a Label sitting within a block of code surrounded by braces ({…}) will likely generate an error.

After loading a script, AutoHotkey does not process Label names as executable code—including Hotkey (^!#a::) and Hotstring (::lol::) definitions (which also act as Labels). Label names are invisible—except when specifically called by an AutoHotkey command.  Even then, the processing starts on the first line of command code appearing below the Label name.

Since, as described by Lexikos in this older AutoHotkey post, AutoHotkey also ignores Hotkey Labels (e.g. ^!a::) and Hotstring Labels (e.g. ::lol::), this creates some interesting opportunities when running Hotkeys (or Hotstring routines) within scripts.

Note: AutoHotkey also ignores function definitions while running code. That means a function definition may be placed almost anywhere within a script without affecting runtime processing.

Running Hotkeys with Labels

Since Hotkeys are also Label names (and invisible to AutoHotkey processing), placing another Label name before any Hotkey runs that same Hotkey routine:

NewLabel:
^!#a::
  Msgbox, Hotkey routine.
Return

Calling NewLabel jumps processing to the first line of code after the Label name. Since, the Hotkey Label name (^!#a::) is also invisible to AutoHotkey, processing starts on the MsgBox command line. While interesting, you might wonder, “Why not just directly call the Hotkey?”

Suppose you want to add or change a parameter before running the Hotkey? Using a separate Label name allows you to insert code without making it part of the Hotkey routine:

NewLabel:
  a = This is new data!
^!#a::
  Msgbox, %a%
Return

While it appears that the Hotkey routine runs after setting the variable a to “This is new data!”, AutoHotkey actually ignores the invisible Hotkey Label name and merely continues processing until hitting the Return command. In fact, you can add any number of Label names and they all get passed over.

NewLabel:
  a = This is new data!
NewLabel2:
NewLabel3:
^!#a::
  Msgbox, %a%
Return

Calling either NewLabel2 or NewLabel3 skips the code appearing after NewLabel.

Multiple Hotkey Tip: This pass-over feature of Label names explains why you can create multiple Hotkey combinations for the same routine by stacking the Hotkey definitions. From the online AutoHotkey documentation:

Multiple hotkeys can be stacked vertically to have them perform the same action. For example:

^Numpad0::
^Numpad1::
MsgBox Control+Numpad0 or Control+Numpad1 displays this message.
return

Regardless of which key combination you activate, AutoHotkey drops through to run the command code until it encounters the Return command. You can add any number of Label names to the top of this snippet and they all work.

Turn a Label into a Subroutine

You can insert as many free-floating Label names as you like almost anywhere in a script—as long as each has a unique name. AutoHotkey tracks all of them, but they are invisible during processing unless called from another command. Until you turn them into subroutines, they merely act as location identification posts planted in the script.

Label transforms into a subroutine when you encapsulate the subsequent command lines with the Return command. Without the Return command, a Label name only acts as a marker for jumps rather than an independent subroutine module. The Return command marks the point at which the Label subroutine terminates. Without a Return command, AutoHotkey continues processing everything in its path. It will even pass over entire functions until encountering a Return outside of the function. (Since AutoHotkey assumes the Return in single-line Hotkeys, e.g. ^!#m::MsgBox, Text Message!, and Hotstrings, e.g. ::lol::laugh out loud, they interrupt any processing.)

You may wonder why you might want to place multiple Label names in a script without turning each into its own subroutine?

Three Label Name Tricks

Other than assigning the same Hotkey routine to multiple Hotkey combinations or Label names as mentioned in the multiple Hotkey tip above, there are a number of possible ways to use this AutoHotkey Label name pass-over feature. I list three here, but you can probably come up with more. For the noobie script writer, these examples may expose possible scripting errors which arise from forgetting to add the Return command which seals off subroutines from the remainder of the script. Creating these self-contained Label subroutine modules prevents routines from running amok and causing unexpected behavior. However, once properly understood, the invisibility of Label names can work to your advantage. Three Label name tricks:

  1. Change parameters for a Hotkey on the fly.
  2. Run initial setup routine for the auto-execute section.
  3. Create an automatic timeline for a series of steps or instructions.

Change Parameters for a Hotkey

In this first example, the script can jump directly to NewLabel: setting a variable value before automatically dropping into the Hotkey routine (^!#a::):

NewLabel:
  var := % (toggle := !toggle) ? "The toggle is on!" : "The toggle is off!"
^!#a::
  Msgbox, %var%
Return

Calling NewLabel: causes the toggle to turn off or on through the ternary operator, then displays the state of the toggle when the Hotkey code runs. Using the Hotkey combination from the keyboard does not affect the state of the toggle while calling the Label does.

When located outside the auto-execute section, this setup code only runs when calling the Label. Since AutoHotkey ignores all following Labels (including the Hotkey definition), the Hotkey routine runs immediately after executing all the previous code.

When activating the Hotkey combination from the keyboard, the NewLabel code located before the Hotkey does not execute. Of course, you could seal NewLabel as a separate subroutine by adding the Return command prior to the Hotkey, then run it independently. However, without the Return, this structure runs the Hotkey every time you change the setting via the Label. While I have yet to use this trick in one of my scripts, I see its potential for modifying the behavior/features of a Hotkey or Hotstring routine.

Run Setup for the Auto-Execute Section

I took this next example from the note at the end of the blog “Change Script Features on the Fly with the Windows System Tray Icon Context Menu (AutoHotkey Tip).” The Label subroutine SaveData: toggles the check mark on and off for the System Tray menu Save Data item, as well as, the SaveOn tracking variable for the save-to-file feature. Removing the Return command from the end of the auto-execute section allows the script to drop into this first subroutine and set (as a default) the check mark on and the variable SaveOn to true:

; Part One: Add the menu item to auto-execute
Menu, tray, add, Save Data, SaveData
; Return command at the end of auto-execute section removed
; Part Two: Include the check toggle tracking routine
SaveData:  ; tracking the checked status
  Menu, tray, togglecheck, Save Data
  SaveOn := !SaveOn 
Return

While this works for the first subroutine in the script, once AutoHotkey reaches any Return command, it stops. If you want additional subroutines to run at startup, then you’ll find using the GoSub command in the auto-execute section more useful.

Create a Timeline for a Series of Steps

One of the more innovative uses for the invisible characteristics of Label names comes in the form of a series of steps or instructions where you might want to start at different points without repeating all the previous steps. I used this technique in the CheeseBurgerRecipe.ahk script:

Ingredients:  ; Step 1
MsgBox,1, Jack Stuffed Cheeseburger, Ingredients:`r`r%Ingredients%

Prepare:      ; Step 2
MsgBox,1, Jack Stuffed Cheeseburger, Prepare:`r`r%Mix%

Cook:         ; Step 3
MsgBox,1, Jack Stuffed Cheeseburger, Cook:`r`r%Cook%

Serve:        ; Step 4
MsgBox,0, Jack Stuffed Cheeseburger, %Serve%
Return

This series of steps contains only one subroutine as shown by the lone Return at the end. However, with the use of multiple Label names, the subroutine can launch at the point of any named incremental step. In this case, the System Tray icon right-click menu setup in the auto-execute section of the script executes the Label calls for the individual starting points:

Menu, tray, add, Ingredients, Ingredients
Menu, tray, add, Prepare, Prepare
Menu, tray, add, Cook, Cook
Menu, tray, add, Serve, Serve

(See the original CheeseBurger.ahk script in its entirety at the end of this blog after my signature GIF.)

While you can find many other methods for creating a series of incremental steps in AutoHotkey scripts, taking advantage of Label name invisibility makes it incredibly simple. In addition to the CheeseBurgerRecipe.ahk script, I ponder a number of other possibilities. But those ideas involve the use of both the GoTo command and the GoSub command and taking advantage of the difference between the two. That’s a blog for another time.

*          *          *

Like anybody else, I have expenses and a need to make ends meet. As Jack’s AutoHotkey Blog increases in popularity, coding the test scripts and writing the blogs takes up more of my time. That means I’ve less time to pursue other income earning opportunities. I don’t plan to ever move Jack’s AutoHotkey Blog behind a paywall, but if you think my efforts are worth a bit of your hard-earned cash, then you can offer a token of your appreciation by purchasing one or two of my AutoHotkey books. You may not need the references yourself, but you might know someone who can benefit from one or two of them.

Thank you,

jack

Original CheeseBurger.ahk Script

#Persistent
FileInstall, CheeseBurgerWhiteIcon.ico, CheeseBurgerWhiteIcon.ico ; include icon in EXE file

Menu, tray, add, Ingredients, Ingredients
Menu, tray, add, Prepare, Prepare
Menu, tray, add, Cook, Cook
Menu, tray, add, Serve, Serve
Menu, tray, Icon, CheeseBurgerWhiteIcon.ico      ; add System Tray icon
Menu, tray, Tip, Jack Stuffed Cheeseburger  ; set ToolTip message for icon
Return

; *** For new recipes, paste new ingredients between the two parentheses below

Ingredients:
Ingredients =
( 
1 1/2 pounds ground beef chuck
4 1/2-inch cubes pepper jack cheese (about 1 ounce total)
Kosher salt and freshly ground pepper
1/2 tablespoon vegetable oil 
4 slices cheddar cheese (about 2 ounces)
4 hamburger buns
Ketchup, mustard and/or mayonnaise, for spreading (optional)
Lettuce leaves, sliced tomato and/or sliced red onion, for topping
Pickles, for serving (optional)
)
MsgBox,1, Jack Stuffed Cheeseburger, Ingredients:`r`r%Ingredients%
IfMsgBox Cancel
    Return

; *** For new recipes, paste new preparations between the two parentheses below

Prepare:
Mix =
(
Divide the beef into 4 equal portions. Press a cube of pepper jack into
the center of each and shape the meat around the cheese; form into patties,
about 4 inches wide and 3/4 inch thick. Season the patties with salt and pepper.
)
MsgBox,1, Jack Stuffed Cheeseburger, Prepare:`r`r%Mix%
IfMsgBox Cancel
    Return

; *** For new recipes, paste new cooking instructions between the two parentheses below

Cook:
Cook =
(
Heat the vegetable oil in a large skillet over medium-high heat. Add the
patties and cook until browned on the bottom, about 4 minutes. Flip the
patties and top each with a slice of cheddar; cook 4 to 5 more minutes.
)
MsgBox,1, Jack Stuffed Cheeseburger, Cook:`r`r%Cook%
IfMsgBox Cancel
    Return

; *** For new recipes, paste new serving instructions between the two parentheses below

Serve:
Serve =
(
Meanwhile, toast the hamburger buns and spread with ketchup, mustard
and/or mayonnaise. Fill with the burgers and top with lettuce, tomato
and/or red onion. Serve with pickles.  
)
MsgBox,0, Jack Stuffed Cheeseburger, %Serve%
Return

Advertisements

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