Dyota's blog

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:

Not listed above, there are the following rebindings:

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.