Tips for Optimizing the Standard AutoHotkey Message Box (MsgBox) Command (AutoHotkey Quick Reference Part Six)

AutoHotkey MsgBox Tricks for Adding Power and Flexibility to Your Scripts. If You Want a Simple, Quick Way to Display Data and Execute Action, You’ll Love These Techniques!

As I go back to work on the AutoHotkey Quick Reference script (based upon the hidden index in the AutoHotkey Web site), I ponder what enhancements I should add next. I find fourbuttonmsgboxthat I now regularly activate the lookup Hotkey combination which displays AutoHotkey command, function, or variable formats—often just to check syntax. The usefulness of this reference script motivates me to do more with it.

After adding a special section to the script which parses the math function Web page (not yet discussed) and planning a future implementation of some pop-up menus—possibly using the Input command (discussed in the Beginning AutoHotkey Hotstrings book)—I finally settled upon including a feature which inserts the text format for commands, functions, and variables from the message box directly into any editing field.

AutoHotkey Library Deal
AutoHotkey Library Deal

*          *          *

New to AutoHotkey? See “Introduction to AutoHotkey: A Review and Guide for Beginners” page.

*          *          *

I initially thought that I would construct a GUI (Graphical User Interface) window for this problem. It wouldn’t take much time to code and the GUI would provide future expandability. But I decided to leave that for later and, for now, make the most of the message window (MsgBox) currently in use. All I needed to do was make a few modifications to the standard pop-up.

Note: While the techniques discussed in this blog contain unusual methods which stretch the limits of the MsgBox command, they are not quite as tedious as creating a new GUI window from scratch. However, once reaching those built-in limitations, you’ll find AutoHotkey GUI windows offer much more flexibility and expandability.

coverepub-250This is not the first time that I’ve discussed using the MsgBox command as more than merely an informational window. In “Chapter Thirty-Three” of AutoHotkey Applications, I covered “Adding a Help Window to the AutoHotkey Reminder Script (OnMessage Command).” I now use those same techniques to not only add a Help button to the MsgBox but change the names and actions of the other buttons.

I may not have pointed out in earlier blogs in this series that I switched the MsgBox for the built-in AutoHotkey variables display to a three-button window (Yes, No, and Cancel), as shown below. That format allows me to offer as an option “continue AutoHotkey search” (No) to proceed with a search for commands or functions rather than exiting.

a_space
Instruction included within the message box explain the function of the Yes, No, and Cancel buttons. Wouldn’t it be better to change the button names?

The most notable use for the Continue button comes when looking up the term GUI. The first window displays the variable A_Gui. After continuing the search, the Gui command syntax appears in the MsgBox.

The Windows message box follows a pretty rigid structure. While MsgBox options offer only a few different button lineups and the size of the window depends on its contents, you can tailor a limited number of items to your needs. For example, I added option number 3 to the command for a three-button format:

MsgBox, 3, %Clipboard%, %CmdRef%

Unfortunately, the MsgBox only allows a maximum of three buttons through the standard options. If I plan to include a feature for inserting the built-in variable syntax into any document, then I’ll need four buttons.

In this blog, I demonstrate how to:

  • Add a fourth button to a MsgBox.
  • Change the names of the MsgBox buttons.
  • Change the action of the MsgBox buttons.

I could have created a Hotkey for inserting the AutoHotkey command/function/variable format into a document, but I wanted to maximize the value of the MsgBox pop-up. After the modifications, the new built-in AutoHotkey variables MsgBox window includes four buttons with new names and tailored actions:

fourbuttonmsgbox
The AutoHotkey variables MsgBox includes a special fourth button (Help) with all the button names changed to match their action.

Eventually, when I need more than four buttons, I may be forced to switch to a GUI window.

Adding a Fourth Button (Help) to the Message Box

Unlike options for most other AutoHotkey commands which allow for the placement of multiple items within the command line, the MsgBox command only accepts a single number— even when including several alternative options. AutoHotkey accomplishes this by adding the options numbers together. From the online documentation, “For example, to specify a Yes/No box with the default button being No instead of Yes, the Options value would be 256+4 (260). In hex, it would be 0x100+0x4 (0x104).”

The special option code 16384 places an additional button (Help) in the AutoHotkey message box window. Combining this numeric code with all the other codes gets the job done. In our example, the three-button Yes/No/Cancel button (option number 3) merges with the Help button code (option number 16384) for the result 16387 (3 + 16384 16387):

MsgBox, 16387, %Clipboard%, %CmdRef%

Now the MsgBox displays the three standard buttons plus a fourth Help button. However, as discussed in both the online AutoHotkey documentation and Chapter Thirty-three of the AutoHotkey Applications e-book, we need to insert addition code to make the Help button useful.

Prerequisites for activating the Help button include adding dialogue ownership (Gui +OwnDialogs) to the appropriate subroutine and the OnMessage command to monitor the Windows WM_HELP message (0x53). This enables the Windows Help message which responds to the pressing of the F1 key. If properly implemented the new message box (or other action) will pop up when clicking the Help button or pressing the F1 key in the active message box window.

It’s important that the ownership code appears before issuing the MsgBox command inside the subroutine:

Gui +OwnDialogs
MsgBox, 16387, %Clipboard%, %CmdRef%

Otherwise, the feature will not work. (The Gui +OwnDialogs command may appear anywhere before the MsgBox command. In fact, in the AutoHotkeyQuickRef.ahk script, the command appears just once at the beginning of the script—even though the script uses the MsgBox command four times…so far.)

The OnMessage function sets up the monitoring and designates the function WM_HELP() called for execution:

OnMessage(0x53, "WM_HELP")

The numerical label (0x53) is the designator for the standard Windows Message. The function name must be in quotes (“WM_HELP”) but need not be the same as the Windows Message name. Any function name works as long as the function exists somewhere in the script. Although, using the same name as the Windows Message may make it easier to remember the purpose of the OnMessage function.

I’ve used two different function names (WM_CANCEL and WM_HELP)—the first for the AutoHotkey built-in variable format window which cancels the routine execution and the second for all the other message boxes which display a help message.

The function WM_CANCEL() merely enables the canceling of the thread by storing “Yes” in the variable Terminate, then closes the MsgBox window:

WM_CANCEL()
{
  Terminate := "Yes"
  WinClose, %clipboard%
}

I used this seemingly unusual function due to peculiarities in how the Help message box button works…but more on this WM_CANCEL() function later.

For all other MsgBox windows, the function called when the clicking the Help button follows:

WM_HELP()
{
MsgBox,4096, Info!
     , Click "Load Page" to accesss Web page
     .`rClick "Insert Code" to copy text to document
     .`rClick "Cancel" to Exit.
}

(Line continuation was implemented to wrap the long lines for display purposes only. AutoHotkey reads these wrapped fragments as all one line.)

The function WM_HELP() opens a message box titled “Info!” and displays the text stating the purpose of each button.

These functions may appear anywhere in the script, but should not be located inside subroutines (i.e. between the beginning of the subroutine (Label) and the Return at the end). All functions and subroutines in a script must be self-contained modules. A function begins with an open curly bracket ( { ) and ends with a closed curly bracket ( } ) while a subroutine begins with the Label name followed by a colon (e.g. SubroutineName:) and ends with a Return.

Changing Message Box Button Names

In the AutoHotkeyQuickRef.ahk script, the standard names of the buttons in the Windows Message dialog boxes may serve as a source of confusion. We want Yes to load the Web page, No to insert the code, and Cancel to continue the site search. Plus, for a couple of reasons, the Help button worked out best as the new Cancel button. Better button names, such as Load Page, Insert Code, and Skip to Next, help eliminate ambiguity in their purpose. While Windows by default fixes the message box button names, there exists an AutoHotkey trick for changing MsgBox button names. However, the MsgBox pop-up window must exist before executing the name change. The SetTimer command provides the technique needed to change MsgBox button names:

SetTimer, ChangeButtonNamesVar, 50
OnMessage(0x53, "WM_CANCEL")
MsgBox, 16387,%Clipboard%, %CmdRef%`r`rClick "Load Page" to open AutoHotkey page
    .`rClick "Insert Code" to add AutoHotkey code
    .`rClick "Skip to Next" to continue search
    .`rClick Cancel to Exit.`r`rTickCount %ElapsedTime%

The SetTimer command runs the Label (subroutine) ChangeButtonNamesVar every 50 milliseconds. Although executed prior to the opening of the MsgBox window, the button names update as soon as the window exists:

ChangeButtonNamesVar: 
  IfWinNotExist, %clipboard%
    Return ; Keep waiting.
  SetTimer, ChangeButtonNamesVar, off 
  WinActivate 
  ControlSetText, Button1, Load Page, %clipboard%
  ControlSetText, Button2, Insert Code, %clipboard%
  ControlSetText, Button3, Skip to Next, %clipboard%
  ControlSetText, Button4, Cancel, %clipboard%
Return

The subroutine ChangeButtonNamesVar continues to check for the existence of the window until found. The timer turns off, ensures windows activation (WinActivate), then, using the ControlSetText command changes the text name of each button.

Since the other MsgBox windows in this script need different button names, they use an alternative setup:

SetTimer, ChangeButtonNames, 50
OnMessage(0x53, "WM_HELP")
MsgBox, 16387,%Clipboard%
      , %CmdRef%`r`rClick "Load Page" to open AutoHotkey page
      .`r`rTickCount %ElapsedTime%

and subroutine (ChangeButtonNames):

ChangeButtonNames: 
  IfWinNotExist, %clipboard%
    Return ; Keep waiting.
  SetTimer, ChangeButtonNames, off 
  WinActivate 
  ControlSetText, Button1, Load Page, %clipboard%
  ControlSetText, Button2, Insert Code, %clipboard%
  ControlSetText, Button3, Cancel, %clipboard%
  ControlSetText, Button4, Help, %clipboard%
Return

Note that Button3 now acts as the Cancel button and Button4 becomes a Help button.

Changing Message Box Button Actions

Even though we changed the names on the buttons, the embedded button variable names needed for adding conditional action don’t change. The IfMsgBox command contains a fixed list of button names which create conditional action opportunities. These work great for modifying the action of every button except for the Help button—which does not have a corresponding built-in variable name. The AutoHotkey built-in variable’s MsgBox executes the following actions:

 IfMsgBox Yes
 {
   Run https://autohotkey.com/docs/Variables.htm#%VarTerm%
   Clipboard := OldClipboard
   Exit
 }
 IfMsgBox No
 {
   WinActivate
   SendInput, %ReplaceRef%
   Clipboard := OldClipboard
   Exit
 }
 IfMsgBox Cancel     
 {
   Exit
 }

However, the Help button (having become the Cancel button) requires special handling. The MsgBox Help button does not respond to the button name Help. In fact, conditional IfMsgBox Help generates an error.

Since the Help button calls a function and does not contain a variable for checking action, we must create a new one. First, we add a Global variable (Terminate) and set the value to 0 every time the Hotkey launches:

Global Terminate
Terminate := 0

Remember that unless defined as Global variables, the values are not available inside called functions.

Next, we use the WM_CANCEL() function to set the global variable Terminate to “Yes” and close the MsgBox (WinClose, %clipboard%):

WM_CANCEL()
{
  Terminate := "Yes"
  WinClose, %clipboard%
}

Next, the variable Terminate causes the routine to exit:

 If (Terminate = "Yes")
 {
   Exit
 }

The actions for the other MsgBox windows are similar except the added Help button actually acts as a Help pop-up:

 IfMsgBox Yes
   Run https://autohotkey.com/docs/%Clipboard%
 IfMsgBox No
 {
   WinActivate
   SendInput, %ReplaceRef%
   Clipboard := OldClipboard
   Exit
 }
 IfMsgBox Cancel
 {
   WinActivate
   Clipboard := OldClipboard
   Exit
 }

The Help button does not require IfMsgBox since its action comes from the WM_HELP() function which opens a Help window and does not close the MsgBox pop-up.

Reaching MsgBox Limits

By including these techniques, we have approached the limits of the MsgBox command. If while working on this script, I get to a point where I need more than four buttons (actions) in AutoHotkeyQuickReg.ahk, then I most likely will move to the more flexible GUI commands.

 

jack

 

 

 

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