ramblings of joe / posts

Hammerspoon

A while ago, I got into mechanical keyboards. I was intrigued by a picture posted to Twitter by @garrettmurray. All three of the keyboards he showed were interesting, but the bottom one – the little guy – was the one that caught my eye the most. I had to have it.

That keyboard is called a MiniVan, and it’s what’s referred to as a 40% in the mechanical keyboard world, which roughly means that it has 40% of the keys that would be found on a full-size keyboard. Most 40% keyboard layouts are limited to: a full set of letters, a bottom row of modifier keys, and ~one modifier key on each side of the letters.

I now own several 40% keyboards with variations of the MiniVan layout, and the first question I’m asked whenever anyone sees one on my desk is: “how do you type numbers?!”. Great question! The answer is a concept called “layers”. If you take a look at Garrett’s MiniVan, you can see that the top row of his keyboard isn’t actually QWERTY, but a full1 number row. Those number keycaps are actually serving as a reminder for what’s “underneath” the top row of letters.

Underneath?! What sorcery is this? 🤯

Layers are a mechanism that’s used to add additional functionality to your keyboard. In fact, every single person already has access to a layer you use every day: uppercase letters (and symbols above numbers). When you press and hold your shift key, you gain access to a new set of characters using the same set of keys. It’s magic! So what if you could add additional layers to your keyboard? You could fit additional functionality into the same set of keys, keeping functionality you use often right at your fingertips.

On a 40% board, using layers is a necessity. You don’t have enough keys to fit all of the functionality of a full-size keyboard in unless some keys are pulling double (or triple) duty. The first thing I had to get used to on my new MiniVan was arrow keys. As a software engineer, I use my arrow keys a lot. Retraining my muscle memory from reaching down to the little inverse “T” arrow cluster at the bottom right of my keyboard to a new configuration was rough. I adopted the arrow layout that the MiniVan’s creator uses, a modified vim2 layout:

key combo mapping
fn + j
fn + k
fn + l
fn + ;

While it may seem a little weird at first, I have gotten fully used to having access to all four directional keys without having to move my right hand off the home row. And I can layer the arrows with macOS modifers without thinking about it.

The Problem

So with all of that introduction out of the way… what are we talking about here and what is a “Hammerspoon”?

Well, having my arrow keys underneath my j/k/l/; keys became second nature to me, which was great! Unless I was using a different keyboard. As soon as I tried typing on my MacBook Pro keyboard, I’d run into all sorts of problems. For starters, on my MiniVan, I use my caps lock key location as my “fn” key to go to layer one. So on my Mac, I’d try to move my cursor by typing caps lock and k, which would result in a ‘K’ being typed, not my cursor being moved. Minor inconveinance, I’ll just hit backspace, move my hand down to the arrow key cluster, and navigate like normal. But now caps lock is turned on, so the next thing I’d start typing would end up being LOUD loud. So then I’d need to turn off the caps lock, delete the word I started typing, and continue on. A major pain in the butt.

One day I was fed up by this happening and decided to do something about it. I’d simply have to build in the arrow keys I wanted under my home row. There was no other way.

After some googling, I stumbled upon something that looked promising: Karabiner and Hammerspoon.

The Solution

So what are Karabiner and Hammerspoon? Karabiner is a system extension that creates a virtualized keyboard, essentially creating a software layer between your laptop keyboard and macOS. Hammerspoon is a system extension that allows you to automate macOS using a scripting language called lua, including what I was interested in: the keyboard.

After stumbling upon these two extensions on my own, I got pretty close to what I wanted, but then I found the icing on the cake: someone had already built something similar to what I wanted. Jason Rudolph’s keyboard repository on GitHub had a lot of similar functionality to what I wanted, so I could tweak what he already had to add some nice polish to my new software keyboard layer.

My stripped down and extended version is published in my dotfiles repo, with most of the functionality I’ve talked about here in fn-layer.lua.

Now whether I’m using a MiniVan or the built-in keyboard on my MacBook Pro, I have the same layered functionality on my keyboard, allowing me to switch between keyboards with much less cognative overhead and 100% fewer accidental caps-lock encounters.


  1. For the eagle-eyed: you’re right, it’s not a full number row, it’s missing the dash and equals buttons due to the shortened width. ↩︎

  2. vim is a text editor that has an extremely passionate userbase and many different key mappings. ↩︎