Karabiner God Mode

Karabiner is a low level macOS kernel extension that gives you a virtual keyboard you can heavily customize to your own liking.

I found out about the power of Karabiner by reading an old article on how you could remap caps lock key into a key that’s actually useful. That is you could remap caps lock to act as escape key when pressed alone and some four/five key modifier when held together. With that article, the notion of a hyper (dual purpose) key was born but most people seemed to have stopped there. This article is about how to take this idea of a hyper key and apply it to every key on your keyboard using Karabiner and a special DSL named Goku that makes editing your Karabiner configuration a breeze.

Karabiner Elements uses JSON to define rules which lets you program keys in various ways. The most powerful of which is the ability to create custom hyper keys. Like the useful caps lock I mentioned earlier but applied to every other key on the keyboard. It is not enough to talk about this and praise how game changing this concept is in using a computer until you try it though. So let’s do that.

The problem with using JSON to define Karabiner rules is that it gets unwieldy complex and nearly impossible to edit by hand. Here is a gist of what my Karabiner configuration looks like in JSON format. It’s a 22,692 lines long file. Inside it there are definitions for how to make all of my QWERTY keyboard (minus some letters and delete/return keys because those are too far from the hjkl hand position) into custom hyper keys. There is no way a sane person would open this file and try to modify it in any meaningful way. It contains too much ‘boilerplate’ that Karabiner actually needs to make its magic. When as all you really need is to just point to a key that you want to make a hyper key, then point to a key that when inside that hyper key would do some custom action (run applescript/shell-script/open-app/..).

Fortunately this problem was solved by creating a special DSL that has the minimum amount of syntax needed to define these kind of hyper key definitions and more. Goku tool actually supports all of Karabiner Elements features but abstracts away the JSON mess so you don’t have to deal with it. Here is my 600 line Karabiner configuration written with Goku. 600 line file that generates 20,000+ lines of JSON that not only is a joy to edit but has the nice feature of auto reloading config. Meaning that as soon as I press save on that Goku config file, I have my keyboard modifications applied instantly.

Defining our first hyper key

If this sparked your interest and you are reading this article on a mac. Let’s try this magic in action and you can see for yourself if that’s something you may fancy doing to your computer.

Let’s install all the stuff we need first.

  1. Install Karabiner Elements (Press the big blue button to install latest version)
  2. Install Goku (Karabiner DSL) (brew install yqrashawn/goku/goku)
  3. Run goku service to watch over Goku file and instantly apply changes (brew services start goku)
  4. Open Karabiner Elements (with Alfred/Spotlight) and create a Goku profile

More instructions on how Goku works are in the README alongside its short tutorial that goes over all its features. There is also a Telegram chat where you can ask for help in any Karabiner modification you like to make.

Now that we have everything we need installed and running on our system, we can get to work.

Goku’s config file by default lives inside ~/.config/karabiner.edn. Since I like to keep all my useful config files in my dotfiles dir, I only keep a symlink there and original Goku config is placed inside ~/.dotfiles/karabiner/karabiner.edn.

Make caps lock great again

I have my caps lock mapped to escape key when pressed alone (VIM is life) and ⌥ ⌃ when held. This one is actually quite easy, especially since macOS already provides you with ability to map caps lock to escape key in System Preferences.

Of course we could of done that in Goku configuration itself too but since macOS gives us ability to do it in settings, let’s use that.

Assuming you’ve done that and everything worked, you can now press caps lock key and instead of going into caps lock mode, you will trigger escape instead. Pretty useful given that new macbooks don’t even ship with a physical escape key (although it was too far away anyway and TouchBar is genuinely useful). But holding onto the caps lock key now does nothing useful. Let’s change that.

Open ~/.config/karabiner.edn file in your favorite editor (create it if doesn’t exist). I edit my config with neovim. Then Paste this inside and save the file:

{:simlayers {:caps_lock-mode {:key :caps_lock}},
:main [{:des "capskey",
:rules [:caps_lock-mode
[:open_bracket :!TOopen_bracket]
[:close_bracket :!TOclose_bracket]
[:semicolon :!TOsemicolon]
[:quote :!TOquote]
[:comma :!TOcomma]
[:period :!TOperiod]
[:slash :!TOslash]
[:a :!TOa]
[:b :!TOb]
[:c :!TOc]
[:d :!TOd]
[:e :!TOe]
[:f :!TOf]
[:g :!TOg]
[:h :!TOh]
[:i :!TOi]
[:j :!TOj]
[:k :!TOk]
[:l :!TOl]
[:m :!TOm]
[:n :!TOn]
[:o :!TOo]
[:p :!TOp]
[:q :!TOq]
[:r :!TOr]
[:s :!TOs]
[:t :!TOt]
[:u :!TOu]
[:v :!TOv]
[:w :!TOw]
[:x :!TOx]
[:y :!TOy]
[:z :!TOz]
[:1 :!TO1]
[:2 :!TO2]
[:3 :!TO3]
[:4 :!TO4]
[:5 :!TO5]
[:6 :!TO6]
[:7 :!TO7]
[:8 :!TO8]
[:9 :!TO9]
[:0 :!TO0]]}]}

Goku is still a tool that is in beta so unfortunately the only way to check if your Goku configuration worked without any errors is to type in goku in the terminal. When I do that, I get:

~
❯ goku
Done!

Which means success. If there is a mistake anywhere in the configuration, you will get a nasty stack trace which usually means you forgot to close out some bracket.

If you did get Done! like me printed, congratulations! You now have yourself your first hyper key. Now if you hold caps lock and press another key, you will trigger ⌥ ⌃ + another-key. ⌃ ⌥ + keys are by default empty keys so you have to map them to something. Let’s map one of these keys to one of my favorite mappings on macOS.

Go to System Preferences -> Keyboard -> Shortcuts -> Services -> Find Search With Google action -> Add shortcut -> Press and hold caps lock briefly and with caps lock still held press g key. It should show the same hotkey as I have in screenshot below.

Now select some text in any app (not VS Code because electron) and press caps lock (hold), then press g key. If everything worked, it should make a Google query with the selected text. Pretty damn useful to have this action at your finger tips.

Hope you now got the idea of what these hyper keys are. You have to play a bit with it to get comfortable because if you hold onto your hyper key for long, it will trigger repeating of escape key and not leave you in the hyper key mode. You have to press caps lock key, hold it and instantly (whilst caps lock key is held) press on the activation key (any other key on the keyboard). In the case of our caps lock key, the activation keys will simply trigger our ⌥ ⌃ hotkeys. But macOS and Karabiner is a lot more awesome and powerful than that. Let’s take this power to its limits.

Actual God Mode

To fully appreciate what Karabiner can do for you, you need to buy and use these two very powerful macOS apps. Keyboard Maestro and Alfred.

Alfred is a programmable launcher for macOS. Like Spotlight but better because you can search anything with it and use a wide array of powerful workflows people have built and freely shared for anyone to use. I also wrote an article on how to start writing these workflows in Go.

Keyboard Maestro is an automation tool that lets you create macros and execute them. A macro is a series of actions to do things. It’s like shell scripting for macOS but better because it just makes sense and is intuitive. Here is a simple macro that activates Safari app on macOS.

I ran this macro this many times:

And that’s because I have this macro mapped nicely to w + k keys. So w key is my hyper key and k my activation key. Only instead of some boring hotkey, I now run a KM macro. I have 1,000’s of KM macros I’ve made and use and if you look into my Goku config you will see on 1st line, this code:

{:templates {:alfred "osascript -e 'tell application \"Alfred 3\" to run trigger \"%s\" in workflow \"%s\" with argument \"\"'"
:km "osascript -e 'tell application \"Keyboard Maestro Engine\" to do script \"%s\"'"}

Specifically this line:

:km "osascript -e 'tell application \"Keyboard Maestro Engine\" to do script \"%s\"'"

Creates an alias :km that will call a KM macro by name I pass into it. What it’s doing is actually calling an AppleScript code via osascript shell command (can man osascript if you like). The same thing happens here:

:alfred "osascript -e 'tell application \"Alfred 3\" to run trigger \"%s\" in workflow \"%s\" with argument \"\"'"

Only instead of KM macro, it calls an Alfred Workflow. To call Alfred workflows with AppleScript, you need 2 things. The external trigger name:

And the bundle.id of the workflow in which this trigger lives which can be found in the description of the workflow here:

And here is an example of calling this specific Alfred workflow in Goku:

[:n [:alfred "search lists" "nikivi.learn.anything"]]

Although you can’t just paste this in into Goku config. This just defines what happens when n key is pressed in some hyper key. What hyper key? Well that is defined as a block of code.

For example in my keyboard configuration I activate this Alfred Learn Anything workflow by pressing o key and then pressing n key inside my o key layer. In code that looks like this:

{:des "okey (alfred)"
:rules [:o-mode
[:n [:alfred "search lists" "nikivi.learn.anything"]]]}

Goku syntax is odd, I agree, it’s optimized for typing less (thus iterating on config faster), not necessarily clarity. But that short snippet actually defines a hyper key only now this hyper key lives on the actual keys you type on. The letter o. So I can still type things away (like this article I am writing) but if I ever want to search curated lists with a workflow, I press o key briefly and whilst not releasing it, press n key. And I get an Alfred prompt show up just as I programmed my keyboard to do this:

Of course my actual o key definition doesn’t just have a binding for :n key. In reality it looks like this:

{:des "okey (alfred)"
:rules [:o-mode
[:1 :!C1]
[:2 :!C2]
[:3 :!C3]
[:4 :!C4]
[:5 :!C5]
[:6 :!C6]
[:w :!CObackslash]
[:v :!CT4]
[:spacebar [:alfred "search PDF files" "nikivi.search.files"]]
[:g [:alfred "search snippets" "com.renfei.SnippetsLab.AlfredWorkflow"]]
[:grave_accent_and_tilde [:alfred "search processes" "com.vitorgalvao.alfred.processcontrol"]]
[:e [:km "Make 2Do task"]]
[:r [:km "Make 2Do task with Safari title as name"]]
[:q [:alfred "search downloads" "recentdownloads.ddjfreedom"]]
[:t [:km "2Do with current url as note (read)"]]
[:b [:km "2Do task (ask)"]]
[:tab [:km "2Do with current url as note (check)"]]
[:h [:km "2Do with current url as note (watch)"]]
[:a [:alfred "search files" "nikivi.manage.wiki"]]
[:y [:alfred "search trash" "com.vitorgalvao.alfred.directories"]]
[:c [:alfred "search emoji" "com.github.jsumners.alfred-emoji"]]
[:i [:alfred "search tty sessions" "net.isometry.alfred.tty"]]
[:f [:alfred "search repos" "net.deanishe.alfred-git-repos"]]
[:n [:alfred "search lists" "nikivi.learn.anything"]]
[:m [:alfred "search lists" "nikivi.awesome.lists"]]
[:s [:alfred "search clones" "com.vitorgalvao.alfred.directories"]]
[:d [:alfred "search desktop" "com.vitorgalvao.alfred.directories"]]
[:j [:alfred "search km macros" "iansinnott.keyboardmaestro"]]
[:caps_lock [:alfred "search folders" "nikivi.search.folders"]]
[:z [:alfred "search workflows" "org.jeef.workflowdirectory"]]
[:k [:alfred "search menu bar" "com.tedwise.menubarsearch"]]]}

Now the description okey (alfred) makes more sense. My o key layer is responsible for calling various Alfred workflows. Making layer mappings by theme makes things easier to remember. For example my w key is used to activate my most used applications (VSCode/Safari/iTerm/2Do/..). Here is how it looks in code:

{:des "wkey (apps)"
:rules [:w-mode
[:k [:km "open: Safari"]]
[:h [:km "open: Activity Monitor"]]
[:i [:km "open: Chrome Canary"]]
[:g [:km "open: Bee"]]
[:t [:km "open: Trello"]]
[:spacebar :!CSO7]
[:comma [:km "open: Spotify"]]
[:caps_lock [:km "open: Finder"]]
[:m [:km "open: Tower"]]
[:b [:km "open: BetterTouchTool"]]
[:r [:km "open: Fantastical"]]
[:e :!OSC1] ; Open Dash
[:semicolon [:km "open: Xcode"]]
[:period [:km "open: SnippetsLab"]]
[:f [:km "open: 2do"]]
[:j [:km "open: iTerm"]]
[:n [:km "open: Sublime Text"]]
[:l [:km "open: VS Code"]]
[:o [:km "open: Keyboard Maestro"]]]}

In this layer, instead of Alfred workflows, I am calling KM macros. Like the one I showed above:

I share all these KM macros I made and use here alongside all the Alfred workflows.

Go wild

I’ve been using Karabiner with custom modifier keys for over 3 years now. I am still in awe that we have this ability to modify our computers to this degree. It’s beyond powerful what you can do with it and I am sad that this isn’t known to the public. Aside from mine and creator’s of Goku configuration, there seems to be no one doing this! And that’s a shame. 😞

Hopefully this article changes it. Because I want to live in a world where everyone pushes the boundaries of what computers can do for us.


If you enjoyed reading this, give it a 👏. And look into other articles I wrote. You can support me on Patreon and get updates on next articles I write on Twitter.💜