; Creates Hotkeys on-the-fly for inserting text into any document or ; Editing field — Jack Dunning ; https://jacksautohotkeyblog.wordpress.com/ /* October 12, 2017 In the original version of InstantHotkey running multiple Hotkeys required loading the script multiple time. This version allows multiple Hotkeys with only one loading. This new version of the Instant Hotkey script offers a number of changes: 1. Multiple GUIs running in same script. 2. Easy to integrate with another script or run solo. 3. Uses pseudo array to track GUIs and Menu items. 4. Uses true array to connect Hotkey combination with the insertion text. 5. Short auto-execute for initiation. 6. Click icon or menu item for first Instant Hotkey setup. This script features a number of scripting techniques. October 18, 2017 The function for creating two-deep variable from illegal characters gets replaced with a Loop in the TextAdd: Lable subroutine which matches the correct Hotkey combination and inserts text. October 23, 2017 I removed the above mentions loop and replaced it with a single line courtesy of an associative array which connects the Hotkey combination with the insertion text. Added a Help windows (CTRL+F1) which uses the "For index, element in array" loop to list Hotkeys. */ #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. /* This first label acts as the auto-execute section for the script. It initializes the variable IH_Count which tracks the number of GUIs and Menu items. At first, only the menu item "Instant Hotkey" appears in the System Tray icon right-click menu. Once clicked, "Instant Hotkey" becomes the parent menu for the new GUIs and Hotkeys. Set as the default, a click of the System Tray icon launches a new Instant Hotkey. Combine with another script by adding "GoSub, InstantHotkey" to the auto-execute section of the combo script and "#Include, [path]\InstantHotkeyTwoDeep.ahk" somewhere after the auto- execute section of the master script. */ InstantHotkey: IH_Count := 0 ; One of the following array declarations must appear before using an array. InstantHotkey := [] ; InstantHotkey := {} ; InstantHotkey := Object() ; InstantHotkey := Array() ; Must use Array(), otherwise AutoHotkey thinks it's a function. Menu, Tray, UseErrorLevel ; prevents various strange errors from stopping the script Menu, HotkeyMenu, Add, New Instant Hotkey, AddNewHotkey Menu, Tray, Add, Instant Hotkeys, AddNewHotkey Menu, Tray, Icon, InstantHotkey.ico, 1 Menu, Tray, Icon, Instant Hotkeys, InstantHotkey.ico, 1 Menu, HotkeyMenu, Icon, New Instant Hotkey, C:\Windows\System32\shell32.dll, 319 Menu, Tray, Default, Instant Hotkeys Menu, Tray, Click, 1 Menu, Tray, Tip, Click for New Instant Hotkey! Return /* The subroutine AddNewHotkey setup a new GUI for creating an Instant Hotkey. It uses the name "InstantHotkey" with IH_Count concatenated to create a pseudo array for tracking GUI pop-ups. */ AddNewHotkey: IH_Count++ ; Instant Hotkey GUI number If IH_Count = 1 Menu, Tray, Add, Instant Hotkeys, :HotkeyMenu ; Create a GUIName variable for naming new GUIs and act as a two-deep variable. GUIName := "InstantHotkey" . IH_Count Gui, %GUIName%: new ; Create a new GUI Gui, %GUIName%:Add, Text,, Enter Hotkeys (ALT, SHIFT, and/or CTRL plus Key) ; The following hidden edit field tracks the GUI/menu item number. Gui, %GUIName%:Add, edit, hidden ys vGuiNum,%IH_Count% Gui, %GUIName%:Add, Hotkey, vKeyCombo ys Limit1 Gui, %GUIName%:Add, Edit, w400 vTextInsert xs, Gui, %GUIName%:Add, Button, gSetupKey , Set Key Combo ; The "Insert" option places the new menu item before "New Instant Hotkey" ; which preserves the matchup between the GUI numbers and menu item numbers. Menu, HotkeyMenu, Insert, New Instant Hotkey, %GUIName%, ShowHotkey Menu, HotkeyMenu, Icon, %GUIName%, InstantHotkey.ico, 1 Menu, InsertText, Add, %GUIName%, TrayTextAdd Menu, InsertText, Icon, %GUIName%, InstantHotkey.ico, 1 ; On the first run, attach submenus to Tray menu items. If IH_Count = 1 { Menu, Tray, Add, Instant Hotkeys, :HotkeyMenu Menu, Tray, Insert, Instant Hotkeys, Add Text, :InsertText Menu, Tray, Icon, Add Text, InstantHotkey.ico, 1 Menu, Tray, Add, New Instant Hotkey, AddNewHotkey Menu, Tray, Icon, New Instant Hotkey, C:\Windows\System32\shell32.dll, 319 Menu, Tray, Default, New Instant Hotkey } Gui, Show, , Instant Hotkey %IH_Count% Return SetupKey: Gui, Submit ; The array InstantHotkey[] saves the Hotkey combination KeyCombo ; and the insertion text TextInsert. You must use the If (expression) ; form of If conditional with arrays unless you first store array value ; to another variable. If (InstantHotkey[GuiNum] != "" ) ; Turn off OldHotkey { Hotkey,% InstantHotkey[GuiNum], Off ; e.g. InstantHotkey[ ] => Hotkey value "^!o" } If KeyCombo != Hotkey, %KeyCombo%, TextAdd, On ; Create pseudo-array variable value for insertion text using Hotkey combination as key. If KeyCombo != InstantHotkey[KeyCombo] := TextInsert ; Save Hotkey combination to InstantHotkey[] array. InstantHotkey[GuiNum] := KeyCombo ; An ampersand (&) appended to a menu number calls that menu item. Menu, InsertText, Rename, %GuiNum%& , % TextInsert Menu, HotkeyMenu, Rename, %GuiNum%& , % KeyCombo . " " . TextInsert Return TrayTextAdd: SendInput, !{Escape} ; Jump to last window SendInput, {raw}%A_ThisMenuItem% Return ; The Hotkey text insertion subroutine now uses InstantHotkey[] array to insert ; the text using the recently pressed Hotkey (A_ThisHotkey) as the array key. TextAdd: SendInput, % "{raw}" . InstantHotkey[A_ThisHotkey] Return ShowHotkey: Gui, InstantHotkey%A_ThisMenuItemPos%:show Return ; Remove comma to activate Hotkey CTRL+ALT+H for new Instant Hotkey ; ^!h::GoSub, AddNewHotkey ; Help window which list active Hotkey combinations and text. ^F1:: HotkeyHelp := "Hotkey ⇒ Insertion Text" for index, element in InstantHotkey ; Recommended approach in most cases. { ; Using "Loop", indices must be consecutive numbers from 1 to the number ; of elements in the array (or they must be calculated within the loop). ; MsgBox % "Element number " . A_Index . " is " . Array[A_Index] ; Using "for", both the index (or "key") and its associated value ; are provided, and the index can be *any* value of your choosing. ; MsgBox % "Element number " . index . " is " . element If index is integer If element ; Hotkey not blank HotkeyHelp := % HotkeyHelp . "`r" . Upper(element) . " ⇒ " . InstantHotkey[InstantHotkey[index]] } MsgBox % HotkeyHelp Return /* ^F2:: HotkeyHelp := "Hotkey ⇒ Insertion Text" for index, element in InstantHotkey ; Recommended approach in most cases. MsgBox % "Element number " . index . " is " . element { ; Using "Loop", indices must be consecutive numbers from 1 to the number ; of elements in the array (or they must be calculated within the loop). ; MsgBox % "Element number " . A_Index . " is " . Array[A_Index] ; Using "for", both the index (or "key") and its associated value ; are provided, and the index can be *any* value of your choosing. MsgBox % "Element number " . index . " is " . element ; HotkeyHelp := % HotkeyHelp . "`r" . Upper(element) . " ⇒ " . InstantHotkey[Index] } ; MsgBox % index . element Return */ Upper(InputVar) { IfInString, InputVar, `+ StringReplace, InputVar, InputVar, `+ , SHIFT`+, all IfInString, InputVar, `^ StringReplace, InputVar, InputVar, `^ , CTRL`+, all IfInString, InputVar, `! StringReplace, InputVar, InputVar, `! , ALT`+, all StringUpper, OutputVar, InputVar Return OutputVar }