Here is a AHK script I came up with a while back that does exactly what the original poster was looking for. It’s scripted for 2 keys, “1” and “2”, but you only need to modify 2 lines of code to make it work for whichever 2 keys you want it to toggle spamming on and off.
To have the script use keys on the number pad, you would change “1” and “2” to “numpad1” and “numpad2” or whichever 2 keys you wanted to use.
Edited script June 23rd: fixed an issue with Numpad keys not being sent correctly by Sendinput
; Title: WoWscripts - Spamming macro hotkeys that Toggle themselves ON and OFF
; author: David J Rosenheim
; date: July 16, 2016
; purpose: Reposition and resize World of Warcraft window as soon as it's opened
; then setup multiple hotkeys capable of toggling themselves on and off.
/* ChangeLog
0.9.1.0 Beta Date: 06/22/20 11:36 PM
- rewrote script to simplify defining of hotkeys and to make logic a bit more straight forward
- added logic to detect when special keys are used as hotkeys (i.e. Numpad0 or F1) and to then enclose
hotkey name in curly braces "{}" so that SendInput command will send the correct key.
0.9.0.2 Beta Date: 06/03/20 5:51 PM
- Fixed issue with hotkey continuing to fire repeatedly while Active window is NOT same window loop started in
- added a line that can be uncommented to allow testing hotkeys using windows program Notepad.exe
- added hotkey Ctrl+Alt+R to allow user to quickly Reload this script (needed when chgs made while running)
- added hotkey Ctrl+Win+X to allow user to Immediately terminate this script and unload it from memory
0.9.0.1 Beta Date: 05/15/20 7:09 PM
- removed WinMaximize and chgd back to WinMove as maximized WoW windows were causing issues when alt-tabbing to other windows
- script defines 2 winProcesses - 1st for World of Warcraft Retail, 2nd for World of Warcraft Classic
- created _winGroup and modified script so that hot keys are context-sensitive to only windows in the Group
0.8.0.1 Beta Date: 9/03/19 1:09:10 PM
- Changed WinMove to WinMaximize as game window extends beyond left/right side of screen when full height
0.8.0.0 Beta Date: 9/09/18 3:36:41 PM
- Added logic that detects if the current Hotkey is the same as previous hotkey
- Changed new behaviour that causing currently running spamming loop to switch to a new hotkey character without toggling OFF first.
- Added _swapHotKeys boolen variable to allow user to turn new "swapping hotkey character" behaviour ON or OFF.
0.7.1.0 Beta Date: 9/09/18 12:54:14 PM
- small number of updates to some comments to make logic more clear
0.7.0.0 Beta Date: 8/11/16 11:26:26 PM
- Moved main code to SpamHotKey label so that multiple hotkeys can be processed using the same code
- changed method of defining hotkeys from double-colon to Hotkey command
- changed method of specifing context-sensitivity for hotkeys from "#If WinActive(" to "Hotkey, IfWinActive"
- #MaxThreadsPerHotkey is now 2 instead of 1 and is only defined under the SpamHotKey label
- Now parsing A_ThisHotkey to get the keystroke for the SendInput command. Parsing removes "$", if first character.
Since a hotkey's modifiers (ctrl,alt,shift) are included in its name, parsing A_ThisHotkey ensures that the
modifiers will be included as part of the keystroke sent by the SendInput command.
- Suspend hotkey is now working correctly
- all hotkeys (including Suspend hotkey) are correctly context-sensitive and only working in the _winProcess window.
*/
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases
#Warn ; Enable warnings to assist with detecting common errors
SendMode Input ; Recommended for new scripts due to its superior speed and reliability
SetWorkingDir %A_ScriptDir% ; Ensure a consistent working directory by making script unconditionally use its own folder
_keepFiring := False ; whether to keep spamming hotkey or not
_prevHK := "" ; Previous hotkey (needs to be global so 2nd thread sees what hotkey 1st thread is spamming)
_swapHKs := True ; true = Press same hotkey to toggle OFF; otherwise, switch to new hotkey and keep spamming
; false = Pressing any hotkey toggles OFF current spamming hotkey
_notepad := "ahk_exe notepad.exe"
;GroupAdd, _winGrp, % _notepad ; uncomment for testing and debugging using Notepad
GroupAdd, _winGrp, ahk_exe Wow.exe ; add this process to Group
GroupAdd, _winGrp, ahk_exe WowClassic.exe ; add this process to Group
; Only continue after any window in Group becomes Active
WinWaitActive, ahk_group _winGrp
; move and resize the active window
if WinActive(_notepad)
WinMove, ,, 150, 150, 1000, 650 ; chg x,y,width,height to match preference for Notepad ;
else
WinMove, ,, -7, -9, 1933, 1049 ; chg x,y,width,height to match preference for WoW game client
#MaxThreadsPerHotkey 2 ; 2 threads are needed so that hotkey loop can be interrupted
#MaxThreadsBuffer On ; while loop running, allows 2nd hotkey to be buffered instead of ignored
#IfWinActive, ahk_group _winGrp ; make following hotkeys context-sensitive (i.e. only work in Group windows)
^!s::Suspend ; Ctrl+Alt+S - Toggles ON/OFF the Suspend function for all hotkeys
^#x::ExitApp ; Ctrl+Win+X - Immediately terminate this script and unload it from memory
$1::
$2::
$Numpad5::
Gosub, SpamHotKey ; rapidfire hotkeys ("$" in front prevents SendInput cmd from triggering hotkey again)
return
SpamHotKey:
_thisHK := A_ThisHotkey
If SubStr(_thisHK,1,1) = "$"
_thisHK := SubStr(_thisHK,2) ; trim "$" char from beginning of hotkey name
if StrLen(_thisHK) > 1 ; If length of hotkey name is greater than 1, then
_thisHK := "{" . _thisHK . "}" ; hotkey is special keyname and must be enclosed in curly braces
; If this is 1st thread, start loop that sends hotkey until toggled OFF
If NOT _keepFiring {
_keepFiring := true
_prevHK := _thisHK
_thisID := WinActive("A") ; get Active Window's unique ID nbr (HWND)
Loop { ; this loop keeps running until 2nd thread signals to stop spamming any hotkey
if NOT WinActive("ahk_id" . _thisID) ; if NOT same window as when this loop started, then...
WinWaitActive, ahk_id _thisID ; pause loop here and wait for original window to become Active again
sendinput, %_thisHK% ; send the hotkey pressed
sleep 59 ; speed of clicks... smaller=faster, larger=slower
if not _keepFiring ; If 2nd thread signaled for this loop to stop spamming hotkey, then...
break ; Break out of this loop
}
}
Else { ; ... this is 2nd thread and 1st thread is already running its loop
If (_thisHK = _prevHK or _swapHKs = False) ; if hotkey same as previous hotkey OR no swapping hotkeys, then...
_keepFiring := false ; Signal 1st thread to stop looping
else ; otherwise, keep loop running and now spam new hotkey
_prevHK := _thisHK
}
return ; Ends thread. If this is 2nd thread, 1st thread will resume looping and see any changes made