Using the Hotkey Command to Toggle Hotkeys On and Off
There are a number of reasons why you may want to turn Hotkey combinations off (and on again)—at least temporarily. That is one of the primary uses for the Hotkey command since once a Hotkey is set up with the standard double-colon format, there is no other way to turn it off—short of suspending all the Hotkeys in the script (right-click on the AHK script icon in the Windows Systems Tray and select “Suspend Hotkeys” from the menu).
This beginning Hotkey blog builds upon the discussions in the previous parts. If you find any of the information too confusing, then reviewing earlier blogs may be worthwhile.
New to AutoHotkey? See “Introduction to AutoHotkey: A Review and Guide for Beginners.”
* * *
Protecting Against Repeating Error Causing Hotkeys
One of my first uses of this Hotkey command technique was when I contained one script within a Hotkey, thus making it possible to #Include it in another AHK file. By doing this I was saved the work of splitting up the script into the auto-execute portion and the remainder of the code (subroutines, functions, etc.) in order to embed it in the main script. An #Include directive by itself would not do the job.
This Hotkey code encapsulating technique worked fine for the first activation of the Hotkey script, but, after the first loading, if I reactivated the key combination, I encountered errors. There are a number of ways to deal with this problem, but by far the easiest is to turn off the Hotkey itself on each launching of the code, then reactivate it just before exiting the Hotkey script. This approach protects the script from errors while the Hotkey routine runs, then reactivates the Hotkey just before the routine ends.
It the following example, I use the Reminder script discussed in “Part VII: Building the Reminder App Step by Step” of the book Digging Deeper Into AutoHotkey—later extended in Chapters Thirty-two and Thirty-three of AutoHotkey Applications. (A short description of the app and where to download it can be found at the ComputorEdge AutoHotkey Free Scripts page.) I wanted to #Include the Reminder script in my main script, but I didn’t want to rewrite it merely for integration.
When launched, the Reminder script creates a GUI (Graphical User Interface) pop-up window using the GUI command. This setup only needs to be done once. In fact, any attempt to recreate it after the initial setup causes an error. Therefore, turning off the activating Hotkey combination prevents the rerunning of the app’s setup routine while the app is active.
(The various GUI windows available in AutoHotkey are discussed and demonstrated with practical examples in the e-book AutoHotkey Applications.)
Initially, I established the Hotkey CTRL+WIN+R (^#R) as the activating key combination using the double-colon format—which is loaded by AutoHotkey before any commands run:
^#R:: Hotkey, ^#R, SetReminder, On Menu, Tray, Add,Set Reminder,SetReminder Menu, Tray, Tip, Editing Utilities . . ; remainder of the subroutines . Return
Since this entire script is loaded as a Hotkey, it won’t run until the keyboard combination is activated. Not even the original setup in the Hotkey code’s auto-execute will load. Therefore, if there’s initial work to be done (as is the case here), then the Hotkey combination must be executed by command in the auto-execute section of the main script. There are a couple of ways to do this:
The SendInput command executes the Hotkey combination when the main script first runs. By adding this Send command to the auto-execute section of the main script any setup required during startup gets executed inside the Hotkey without needing to move the code from the Hotkey routine into the main script. (In the case of the Reminder script, an INI file is checked during setup for any saved future reminder. This ensures that the app continues working even when the script reloads or the computer reboots between the reminder’s set time and that of the appointment.)
Another option is the GoSub command:
or the Goto command. They all seem to work. (Remember that when a Hotkey is created, the key combination also becomes the Label name of the subroutine. This Label name makes it easier to call the Hotkey routines through other commands, such as, Menu and SetTimer.)
The first line in the routine uses the Hotkey command to turn on the identical Hotkey. You might ask, “Why turn on the Hotkey again (Hotkey, ^#R, SetReminder, On) in the first step in the routine?” This serves two purposes.
The first is the Hotkey command (Hotkey, ^#R, SetReminder, On) assigns the Label subroutine (SetReminder:) rather than the entire script to the Hotkey. All future uses of the key combination skip the setup (auto-execute) portion of the script (reading the INI data file). Second, it locates exactly where in the script (the SetReminder: subroutine) the Hotkey combination should be turned off:
SetReminder: HotKey, ^#R, Off Menu, Tray, Disable, Set Reminder . . . Return
Later, when exiting the Hotkey app, we turn the key combination back on:
ReminderGuiClose: Gui Reminder:Destroy HotKey, ^#R, On Menu, Tray, Enable, Set Reminder DllCall("DestroyCursor","Uint", hCursor) Return
Destroying the GUI window prevents a variable error the next time the GUI is created. As an alternative, rather than destroying the GUI window, we could have checked for the existence of the window and skipped the creation if it was found, but then the window would be continually sitting in the background whether we needed it or not. If we had taken that approach, then the Hotkey command could be used to run a Label subroutine which merely displays the GUI window:
HotKey, ^#R, ReminderShow, On ReminderShow: Gui Reminder:Show, , Reminder Return
Implementing this last variation would have taken a little more work since I had not envisioned it at the inception of the Reminder script. But, I’m sure that it would have worked and possibly been a better solution.
Using Hotkeys to Turn Other Hotkeys On and Off (Toggling Hotkeys)
You may have a set of Hotkeys which you would like to turn off and on at will. Maybe there are a number of programs where you like to use them, but it becomes annoying to have them on all the time. As a convenience, wouldn’t it be great to include a separate Hotkey to toggle your Hotkeys?
The following script setups up one Hotkey, then assigns another Hotkey for turning it on and off:
^J::MsgBox This is a test!
^B:: Hotkey, ^j, Toggle Return
The Hotkey CTRL+J (^j) open a MsgBox which displays, “This is a test!” Its action can be turned off and on with the Hotkey combination CTRL+B (^b). Each time the combination is pressed, the first Hotkey, CTRL+J, flips to the opposite state. Any number of other Hotkey combinations may be included in the CTRL+B toggle by adding more Hotkey commands to the list.
Is the Hotkey On or Off?
However, with this approach, we only know the current state of the Hotkey (on or off) by testing it. This may not always be desirable. It might be a good idea to add a MsgBox command telling us whether the other Hotkey is on or off:
^B:: KeyState :=! KeyState Hotkey, ^j, Toggle If KeyState MsgBox, CTRL+J Key Off! Else MsgBox, CTRL+J Key On! Return
While this example adds a few more lines of code, it provides us much more visibility into the state of the Hotkey.
The first command (KeyState :=! KeyState) creates the variable Keystate which initially contains a true value. Using the not equal :=! operator, each time it runs, Keystate toggles to the opposite value (true to false or false to true). The variable toggles in sync with the Hotkey command toggle. By using the value of the variable KeyState, a window opens telling us the condition of the CTRL+J Hotkey (on or off).
(To be honest, I can never remember the initial state of a toggling variable. I usually test the script and adjust the MsgBox as necessary.)
Tip for Making the Hotkey Command Work
While I haven’t seen much discussion about it, if you use any context-sensitive #Directives in your Hotkey setups, then you need to repeat those same conditions whenever you use the Hotkey command to modify them. Only Hotkeys which meet the exact same conditions will be affected.
For example, the following snippet sets up the key combination CTRL+Y (^Y) for four different actions when various windows are active:
#IfWinActive, ahk_class Notepad ^Y::MsgBox, This is Notepad! #IfWinActive, ahk_class Notepad++ ^Y::MsgBox, This is Notepad++! #IfWinActive, ahk_class WordPadClass ^Y::MsgBox, This is WordPad! #IfWinActive ;when none of the above is active ^Y::MsgBox, I'm not sure what this is!
Any of these Hotkeys can be modified, but each must be called with the same conditions as the original setup. For example to change the active Notepad CTRL+Y combination using the Hotkey command:
Hotkey, IfWinActive, ahk_class Notepad Hotkey, ^Y, WishWordPad Hotkey, IfWinActive
WishWordPad: MsgBox, I wish this were WordPad! Return
In this case, the Hotkey command (Hotkey, ^Y, WishWordPad) only affects the Notepad CTRL+Y Hotkey. All remaining Hotkeys remain untouched.
If you want to change all the Hotkeys except those created with the context-sensitive #IfWinActive directives, then include no conditional parameters with the Hotkey command:
Hotkey, IfWinActive ;all other windows Hotkey, ^Y, NewActionLabel ;or Off/On
Then, the action changes everywhere except when Notepad, Notepad++, or Wordpad is activated.
Next time, I’ll take a look at a couple of cool editing Hotkeys for the dyslexic—techniques for swapping letters and words.