Karabiner is a keyboard customizer for macOS. I’ve used it for a while to map my caps lock key to cmd + ctrl + option + shift. This key combination is sometimes called a hyper key. With this keyboard override, I use other programs like Hammerspoon and Alfred to do things like toggle apps and open links. Karabiner provides an out-of-the-box, predefined rule to perform this complex modification. I’ve used this approach for a while but recently learned about Goku which adds a lot of additional functionality to Karabiner using Clojure’s extensible data notation (edn) to declaratively configure Karabiner.

For me, there has been a steep learning curve to use Goku that goes along with its power. The examples are a good place to start learning. My initial aim was to reimplement my existing Karabiner rule, described above. After installing goku, I created a configuration file at ~/.config/karabiner.edn. Inside it, I added

{:main [{:des "caps lock" :rules [[:##caps_lock :!QWEright_shift nil {:alone :escape}]]}]}

I actually didn’t figure this out from the docs, but rather from an open source karabiner.edn on Github by yqchilde. Huge thanks for them for open sourcing their work, as I was having a tough time finding a solution to this using the docs alone. The Clojure is a bit hard to read if you’re not used to it. I also installed Calva to format the karabiner.edn file, but for a file this simple, it didn’t add any whitespace. The rule above encodes two behaviors

  • when caps lock is pressed alone, it acts as the escape key
  • when caps lock is pressed as a modifier (with another key, like a or 1), it acts as the hyper key

This edn configuration replicates my existing Karabiner config. Finally, I ran goku from ~/.config/karabiner.edn and the config is loaded into Karabiner.

❯ goku
Done!

You can also run brew services start goku, to watch this file and load the config into Karabiner automatically on changes.

As a bonus, right below the hyper key definition, that same karabiner.edn file also redefines behavior for the default cap locks behavior by pressing caps lock, then escape. The caps lock light turns on with this key combination and pressing it again, turns it off. The rule looks like this

[:!QWER#Pescape :caps_lock]

My final karabiner.edn looks like this

{:main [{:des "caps lock" :rules [[:##caps_lock :!QWEright_shift nil {:alone :escape}]
                                  [:!QWER#Pescape :caps_lock]]}]}

The result is a nice improvement, as I’ve regained access to the caps lock functionality.