AutoHotkey - Windows key, home row arrow keys, mouse shortcuts
Constantly switching between your keyboard and mouse can be frustrating, especially once you start paying attention to just how much you do it every day. (And now that I’ve made you start thinking about it, you won’t be able to stop. It’s the pink elephant game all over again. You’re welcome.)
So I’ve been on a quest to use my keyboard and mouse more efficiently, and here’s what I have so far. Before we get to AutoHotkey, the big enchilada of productivity boosters, let’s start with a few other apps full of handy shortcuts. Most of these are for Windows, but all of them have counterparts in MacOS and Linux, so at least the concepts still apply.
Small time-saving apps
Clipboard manager: Ditto. I can’t tell you how great it is to have an infinite clipboard.
Text expander: Beeftext. Great for code snippets, often-used phrases for emails, and emojis. đź‘Ť
Keyboard web navigation: Vimium for Chrome, VimiumFF for Firefox turns the Web into a keyboard-navigable land of magic. See the readme to get started. You’ll want to customize the key mappings, unless you’re familiar with Vim.
Gmail shortcuts. Like trading your puny dagger for a flaming sword to vanquish the dark forces of email.
SharpKeys for key remapping
In Windows, AutoHotkey is the Swiss Army knife of productivity. But I use SharpKeys for lower-level key remapping, and my AutoHotkey scripts only make sense in the context of those remappings, so let’s start there.
In SharpKeys I’ve remapped the following keys:
- Caps Lock to Backspace
- Right Shift to Delete
- Backspace to Calculator
- Left Windows to F13
The first two are to bring Backspace and Delete closer to the home row. (I hardly ever used Caps Lock and Right Shift anyway.) The third is just to make use of the now-replaced Backspace key. Or you could remap it to F14 and make a script for F14 in AutoHotkey (see below).
The last remapping in the list disables Windows shortcuts, which are more annoying than useful, and in the process you gain a whole new modifier key. We’ll now use this wiped-clean Windows key to set up app hotkeys on the left side of the keyboard, and home row arrow keys on the right side.
AutoHotkey: opening apps with the Windows key
Previously I’ve shared how to set up a Windows Terminal hotkey using this same technique of remapping the Windows key. Here are some other essential hotkeys for our wiped-clean Windows key. You can also add hotkeys for favorite apps: for example, for work apps I have several “Run” lines under F13 & w::
(i.e. Win+W).
#NoEnv
SendMode Input
blockContextMenu := false ; so that right-click menu is not shown after using right button as modifier (see mouse shortcuts below)
; = = = = = = = PROGRAMS = = = = = = =
; LWin is remapped to F13 in SharpKeys, to avoid Windows shortcuts
F13 & q::Send ^{Esc} ; start menu
F13 & e::Run explore C:\Users\User1\Downloads ; open Explorer
F13 & t::Run "C:\Program Files\Microsoft VS Code\Code.exe" C:\Users\User1\Dropbox\.archive\.bin\Felipe-hotkeys.ahk
F13 & s::Reload ; make AutoHotkey reload this script (do it right after saving the file)
return
; = = = = = = = USABILITY = = = = = = =
; context menu
RWin::Send {AppsKey}
return
; Esc closer to home row (and closes frequently-used apps)
; CapsLock is remapped to Backspace in Sharpkeys
F13 & Backspace::
WinGet, active_proc, ProcessName, A
if (active_proc = "explorer.exe" || active_proc = "cloudapp.exe" || active_proc = "jpegview64.exe")
Send !{F4}
else if !CloseBeeftext()
Send {Esc}
return
More keyboard shortcuts shortly, but first let’s switch over to the mouse.
AutoHotkey: mouse shortcuts
A lot of power users scorn the mouse. Yes, it is far from ideal for many tasks. If I’m typing an email and I want to check on something in another tab, it’s quicker to hop over with keyboard shortcuts—Vimium makes it even easier. But I’m going to side with the masses and say that the mouse was a wonderful invention. It’s indispensable for browsing the web, photo editing, and many other tasks.
Maybe the reason I love my mouse is that it’s so much more convenient now that I’ve given it some AutoHotkey love. The key is to cram useful navigation functions into the mouse buttons. I use a very basic mouse, but now its 7 buttons can do wonders. In particular, I constantly use the side buttons (XButton1
and XButton2
below) to switch windows and close tabs.
There’s a lot going on in the snippet below, so here’s a visual summary of my mouse shortcuts:
; = = = = = = = MOUSE SHORTCUTS = = = = = = =
; mouse buttons to switch windows and tabs
XButton1:: ; back button
if (GetKeyState("LButton", "P")) { ; left or right button modifier: browser back
Send !{Left}
} else if (GetKeyState("RButton", "P")) {
blockContextMenu := true
Send !{Left}
} else { ; no mouse modifier: switch window
Send {LAlt Down}{Tab}
}
return
XButton1 Up:: ; allows back button to be pressed for Alt+Tab window menu to stay up
if !(GetKeyState("LButton", "P") || GetKeyState("RButton", "P")) {
Send {LAlt Up}
}
return
XButton2:: ; forward button
if (GetKeyState("LButton", "P")) { ; left or right button modifier: refresh
Send {F5}
} else if (GetKeyState("RButton", "P")) {
blockContextMenu := true
Send {F5}
} else { ; no mouse modifier: close tab or window
WinGet, active_proc, ProcessName, A
if (active_proc = "chrome.exe" || active_proc = "firefox.exe" || active_proc = "Code.exe")
Send ^{F4}
else if !CloseBeeftext()
Send !{F4}
}
return
MButton::
if !(WinActive("ahk_class CabinetWClass"))
{
if (GetKeyState("LButton", "P")) { ; left or right button modifier: browser forward
Send !{Right}
} else if (GetKeyState("RButton", "P")) {
blockContextMenu := true
Send !{Right}
} else ; no mouse modifier
Send {MButton}
} else { ; delete in Explorer (best combined with Explorer's single-click mode)
Send {MButton}
Sleep 50
Send {Delete}
Sleep 50
Send {Space}
}
return
WheelLeft::
if !(WinActive("ahk_class CabinetWClass"))
Send ^+{Tab} ; switch tabs left
else
Send !{Up} ; up one level in Explorer
return
WheelRight::
if !(WinActive("ahk_class CabinetWClass"))
Send ^{Tab} ; switch tabs right
else
Send !{Left} ; back in Explorer (i.e. down one level if went up one level)
return
; right click as wheel modifier: mega scroll
; the simpler method RButton & WheelUp causes problems with click state
WheelUp::
if (GetKeyState("RButton", "P")) {
blockContextMenu := true
Send {WheelUp 15}
} else
Send {WheelUp}
return
WheelDown::
if (GetKeyState("RButton", "P")) {
blockContextMenu := true
Send {WheelDown 15}
} else
Send {WheelDown}
return
; do not show context menu if mega scrolled
RButton Up::
if (blockContextMenu)
blockContextMenu := false
else
Send {RButton}
return
AutoHotkey: home row arrow keys
The more you use the keyboard instead of the mouse, the more you’ll be annoyed with another common switch: from the home row down to the arrow keys. There is the traditional way of doing this with hjkl
, but I’ve opted for my own setup: ijkl
for arrow keys, plus h
and ;
for Home and End, plus u
and o
for Page Up and Page Down. All of these are activated with our faux Windows key pressed down. See the next section for an explanation of the modifier functions Shift()
, Alt()
, etc.
Here’s a summary of all my keyboard shortcuts and remappings, with a friendly wizard denoting our transformed Windows key. The icons on letter keys are for when Windows key is pressed.
; = = = = = = = HOME ROW ARROW KEYS + home/end, page up/down = = = = = = =
F13 & j::
if Shift()
Send +{Left}
else if Alt()
Send !{Left}
else if Ctrl()
Send ^{Left}
else if CtrlShift()
Send ^+{Left}
else if AltShift()
Send !+{Left}
else if CtrlAlt()
Send ^!{Left}
else if CtrlAltShift()
Send ^!+{Left}
else Send {Left}
return
F13 & l::
if Shift()
Send +{Right}
else if Alt()
Send !{Right}
else if Ctrl()
Send ^{Right}
else if CtrlShift()
Send ^+{Right}
else if AltShift()
Send !+{Right}
else if CtrlAlt()
Send ^!{Right}
else if CtrlAltShift()
Send ^!+{Right}
else Send {Right}
return
F13 & i::
if Shift()
Send +{Up}
else if Alt()
Send !{Up}
else if Ctrl()
Send ^{Up}
else if CtrlShift()
Send ^+{Up}
else if AltShift()
Send !+{Up}
else if CtrlAlt()
Send ^!{Up}
else if CtrlAltShift()
Send ^!+{Up}
else Send {Up}
return
F13 & k::
if Shift()
Send +{Down}
else if Alt()
Send !{Down}
else if Ctrl()
Send ^{Down}
else if CtrlShift()
Send ^+{Down}
else if AltShift()
Send !+{Down}
else if CtrlAlt()
Send ^!{Down}
else if CtrlAltShift()
Send ^!+{Down}
else Send {Down}
return
F13 & h::
if Shift()
Send +{Home}
else Send {Home}
return
F13 & `;::
if Shift()
Send +{End}
else Send {End}
return
F13 & u::
if Shift()
Send +{PgUp}
else Send {PgUp}
return
F13 & o::
if Shift()
Send +{PgDn}
else Send {PgDn}
return
AutoHotkey: modifier functions
We’ve been using AutoHotkey’s custom combinations feature to make our remapped Windows key act like a modifier, so that F13 & j
is analogous to #j
(where #
is the regular Windows key). The limitation of this feature is that it doesn’t accept any additional modifiers: F13 & ^j
doesn’t work, nor does F13 & Ctrl & j
. So I’ve made functions that check for each modifier.
; = = = = = MODIFIERS FOR F13 (LWIN REMAPPED) = = = = =
Ctrl() {
if (GetKeyState("LAlt") || GetKeyState("LShift"))
return 0
else return GetKeyState("LCtrl")
}
Alt() {
if (GetKeyState("LCtrl") || GetKeyState("LShift"))
return 0
else return GetKeyState("LAlt")
}
Shift() {
if (GetKeyState("LCtrl") || GetKeyState("LAlt"))
return 0
else return GetKeyState("LShift")
}
CtrlAlt() {
if (GetKeyState("LShift"))
return 0
else return (GetKeyState("LCtrl") && GetKeyState("LAlt"))
}
CtrlShift() {
if (GetKeyState("LAlt"))
return 0
else return (GetKeyState("LCtrl") && GetKeyState("LShift"))
}
AltShift() {
if (GetKeyState("LCtrl"))
return 0
else return (GetKeyState("LAlt") && GetKeyState("LShift"))
}
CtrlAltShift() {
return (GetKeyState("LCtrl") && GetKeyState("LAlt") && GetKeyState("LShift"))
}
The upshot
Is this yet another case of spending more time than I save? Or getting sidetracked by automation? I don’t think so. Actually the time spent writing these scripts is trivial compared to how long it takes to train myself to use the dang shortcuts. But once you do, navigating windows, tabs, text, and the web is entirely different. Your fingers are like lightning—nay, “tempestuous as the sea, and stronger than the foundations of the earth!“—to borrow the words of a similarly empowered person.
Well… just don’t let it get to your head, that’s all.
For more keyboard adventures, see my more recent post Learning Colemak.