AutoHotKey key SEQUENCE, not just single-key hotkey
Categories:
AutoHotkey: Mastering Key Sequences for Advanced Automation

Unlock powerful automation by creating AutoHotkey hotkeys that trigger on a sequence of keys, not just a single keypress. Learn how to implement and manage these advanced shortcuts.
AutoHotkey is a powerful scripting language for Windows that allows users to automate tasks, remap keys, and create custom shortcuts. While many users are familiar with creating hotkeys for single keypresses (e.g., ^c
for Ctrl+C), its true power often lies in its ability to respond to key sequences. This article will guide you through creating hotkeys that activate only after a specific series of keys has been pressed, offering a more nuanced and less intrusive way to trigger your scripts.
Understanding Key Sequences vs. Hotstrings
Before diving into implementation, it's crucial to differentiate between key sequences and AutoHotkey's built-in hotstrings. Hotstrings (::text::replacement
) are designed to replace typed text with other text or trigger actions after a string of characters is typed and followed by an ending character (like space or enter). Key sequences, however, are about detecting a specific order of key presses, regardless of whether they form a 'word' or are followed by a terminator. This distinction allows for more flexible and powerful automation scenarios, especially when dealing with non-textual inputs or system-wide shortcuts.
flowchart TD A[User Presses Key] --> B{Is it a Hotkey?} B -->|Yes| C[Execute Hotkey Action] B -->|No| D{Is it part of a Sequence?} D -->|Yes| E[Add Key to Buffer] E --> F{Does Buffer Match Sequence?} F -->|Yes| G[Execute Sequence Action] F -->|No| H[Continue Monitoring] D -->|No| I[Process as Normal Input]
Decision flow for AutoHotkey input processing, distinguishing single hotkeys from sequence detection.
Implementing Key Sequences with a Buffer
To implement a key sequence, you'll typically need to maintain a 'buffer' or 'history' of recent key presses. Each time a relevant key is pressed, you add it to this buffer. Then, you check if the end of the buffer matches your desired sequence. If it does, you trigger your action and often clear the buffer to prevent accidental re-triggers. A common approach involves using a global variable to store the key history and a timer to clear it after a short delay, ensuring that the sequence must be typed within a reasonable timeframe.
SequenceBuffer := ""
SequenceTimeout := 500 ; milliseconds
; Define your sequence and action
; Example: Pressing 'a' then 's' then 'd' opens Notepad
; Intercept relevant keys
; Use ~ to allow the key to pass through to the active window
~a:: AddToSequenceBuffer("a")
~s:: AddToSequenceBuffer("s")
~d:: AddToSequenceBuffer("d")
AddToSequenceBuffer(key)
{
global SequenceBuffer, SequenceTimeout
SequenceBuffer .= key
SetTimer, ClearSequenceBuffer, -%SequenceTimeout%
; Check for specific sequences
if (SequenceBuffer = "asd")
{
MsgBox, Sequence 'asd' detected! Opening Notepad.
Run, notepad.exe
ClearSequenceBuffer()
}
else if (SequenceBuffer = "qs")
{
MsgBox, Sequence 'qs' detected! Quitting script.
ExitApp
ClearSequenceBuffer()
}
}
ClearSequenceBuffer()
{
global SequenceBuffer
SequenceBuffer := ""
SetTimer, ClearSequenceBuffer, Off
}
Basic AutoHotkey script for detecting key sequences using a buffer and a timeout.
F1 F2 F3
is less likely to be typed accidentally than a s d
.Advanced Sequence Management and Best Practices
When implementing multiple key sequences, managing the buffer and preventing false positives becomes important. You might want to use a more robust buffer management system, perhaps an array or a more sophisticated string matching algorithm. Additionally, consider the user experience: sequences should be intuitive and not interfere with normal typing. A short timeout for the buffer is crucial to ensure sequences are typed deliberately.
; A more advanced approach using a list of sequences and a dynamic check
SequenceBuffer := ""
SequenceTimeout := 750 ; milliseconds
; Define sequences as an object for easier management
Sequences := {
"open_calc": {keys: "cc", action: Func("OpenCalculator")},
"toggle_mute": {keys: "mm", action: Func("ToggleMute")},
"exit_script": {keys: "qq", action: Func("ExitScript")}
}
; Intercept all keys that might be part of a sequence
; This example intercepts 'c', 'm', 'q'. Add more as needed.
~c:: AddToSequenceBuffer("c")
~m:: AddToSequenceBuffer("m")
~q:: AddToSequenceBuffer("q")
AddToSequenceBuffer(key)
{
global SequenceBuffer, SequenceTimeout, Sequences
SequenceBuffer .= key
SetTimer, ClearSequenceBuffer, -%SequenceTimeout%
; Check if the current buffer matches any defined sequence
for name, seq in Sequences
{
if (SequenceBuffer = seq.keys)
{
seq.action.Call()
ClearSequenceBuffer()
return
}
}
; Optional: If buffer gets too long and doesn't match anything, clear it
if (StrLen(SequenceBuffer) > 5) ; Adjust max length as needed
{
ClearSequenceBuffer()
}
}
ClearSequenceBuffer()
{
global SequenceBuffer
SequenceBuffer := ""
SetTimer, ClearSequenceBuffer, Off
}
; --- Sequence Actions ---
OpenCalculator()
{
MsgBox, Opening Calculator...
Run, calc.exe
}
ToggleMute()
{
MsgBox, Toggling Mute...
SoundSet, +1, , mute
}
ExitScript()
{
MsgBox, Exiting Script...
ExitApp
}
Advanced AutoHotkey script for managing multiple key sequences with an object-based definition.
~
prefix with hotkeys that are part of a sequence. While it allows the key to pass through, if your sequence triggers an action that changes the active window or input focus, the subsequent keys in the sequence might not be processed as expected by the original application.