Keyboard rebindings with AutoHotKey
Right hand
NumPad
This was actually the instigator of the whole thing. I work on a laptop every way, and the external keyboard that I have is also very laptop-like. It has a numpad, but the arrow keys are small, and tucked under the right Shift key.
The way I normally use the numpad is as the alternate function, with NumLock off, as the arrow keys and Home/End/PgUp/PgDn. However, sometimes I do need to type out numbers in sequence, and I miss having a dedicated numpad.
I wanted to have a toggle so that I can hold down a key to activate NumLock while the button is held down. I don't like tapping on the NumLock key to turn it on and off temporarily.
My first choice was to use the left Alt key, but that didn't work, because Alt+NumPad on Windows generates special characters.
I landed on Caps Lock as the toggle key. When it is held down, it will turn on NumLock, and I can type out numbers. On release, it returns the numpad to its arrow keys functions.
Symbols
The next thing was symbols. I write a lot of code, and that means a lot of special characters. One that I use frequently, because I code in PowerShell a lot, is the dollar sign ($) for variables, and also the pound sign (#) for indicating comments. Both of these are kind of the middle, and while I'm kind of used to it now, it would be really convenient if I could reach these with my hand on the home row and without looking.
So, piggybacking of the Caps Lock alternate function, while it's being held down, it also activates another "layer", where the symbols are mapped onto the region of the home row of my right hand.
Normal mode:
u i o p [ ]
h j k l ;
n m , . /
Symbols mode:
! @ # $ ( )
= % ^ & `
_ + - . ~
Some special notes:
- Symbols 1 through 7 are mapped in order onto
uiopjkl - The tick symbol ` is mapped onto '
- The tilde symbol ~ is mapped below `
- The brackets symbols are mapped onto [ and ] respectively
- The equals sign = is mapped onto h. This is because I need to access this key for writing Excel formulas, and I think it spatially makes sense to be close and to the left
- I mapped _, +, and - to
m,.
Not listed above, there are the following rebindings:
- Spacebar as Enter
- Backspace as Escape
- Enter as F5 (often used to run scripts, especially PowerShell scripts in VS Code)
Left hand
Arrow keys
The arrow keys are just fine on the numpad, but sometimes I want to reduce the hand travel just that little bit further, especially at times when I want my right hand on the mouse.
The directions are mapped onto WASD.
x and c are Home and End, respectively.
e and r are the above, with Ctrl, so that it goes all the way up or all the way down.
These bindings, paired with Spacebar as Enter, enables me to do a lot more operations with one hand on the mouse and the other on the keyboard.
Full script
+BackSpace::Send("{Delete}")
; Claude Sonnet 4.5 (claude-sonnet-4-5-20250929)
; 2025-10-28
; This script makes CapsLock work as:
; - Tap (< 200ms) = normal caps lock toggle
; - Hold (>= 200ms) = NumPad toggle when NumLock is OFF
; Claude Sonnet 4.5 (claude-sonnet-4-5-20250929)
; 2025-10-29
#SingleInstance Force
; Track whether we artificially turned on NumLock
numLockWasOff := false
capsLockPressTime := 0
holdThreshold := 200 ; milliseconds
wasHeld := false ; Track if it was held long enough
; CapsLock down
*CapsLock::{
global numLockWasOff, capsLockPressTime, wasHeld
; Record when CapsLock was pressed
capsLockPressTime := A_TickCount
wasHeld := false
; Check if NumLock is currently OFF
if !GetKeyState("NumLock", "T") {
; NumLock is OFF, so turn it ON temporarily after threshold
SetTimer(EnableNumPad, -holdThreshold)
}
}
; CapsLock up
*CapsLock Up::{
global numLockWasOff, capsLockPressTime, holdThreshold, wasHeld
; Calculate how long CapsLock was held
holdDuration := A_TickCount - capsLockPressTime
; Cancel the timer if it hasn't fired yet
SetTimer(EnableNumPad, 0)
; If it was a short tap AND wasn't held, toggle CapsLock
if (holdDuration < holdThreshold && !wasHeld) {
SetCapsLockState(!GetKeyState("CapsLock", "T"))
}
; If we turned NumLock on, turn it back off
if (numLockWasOff) {
SetNumLockState(false)
numLockWasOff := false
}
}
; Timer function to enable NumPad after threshold
EnableNumPad() {
global numLockWasOff, wasHeld
; Only enable if CapsLock is still held down
if GetKeyState("CapsLock", "P") {
if !GetKeyState("NumLock", "T") {
SetNumLockState(true)
numLockWasOff := true
wasHeld := true ; Mark that we entered hold mode
}
}
}
; Symbol layer - only active when CapsLock is held
#HotIf GetKeyState("CapsLock", "P")
u::Send("{!}")
i::Send("@")
o::Send("{#}")
p::Send("$")
j::Send("%")
k::Send("{^}")
l::Send("&")
`;::Send("*")
[::Send("(")
]::Send(")")
h::Send("=")
n::Send("_")
m::Send("{+}")
,::Send("-")
'::Send("{``}")
/::Send("~")
c::Send("{Home}")
v::Send("{End}")
e::Send("^{Home}")
r::Send("^{End}}")
w::Send("{Up}")
a::Send("{Left}")
s::Send("{Down}")
d::Send("{Right}")
Enter::Send("{F5}")
Space::Send("{Enter}")
BackSpace::Send("{Escape}")
#HotIf
A note about AI use
For this exercise, Claude AI pretty much wrote the entire thing from scratch, and all I did was tell it if it was working or not. It's odd for me to be making a post, as all of this code was not my own product. In the past, most of the code would have been written by me, especially the problem-solving aspects. It feels odd that it at once feels diminished but also still worth putting up online.