Using Karabiner Elements with BetterTouchTool

I had this draft sitting in Bear for around nine months now and never published it. I no longer use the crazy fn + modifier shortcuts I describe, but the info about how to trigger BetterTouchTool commands via Karabiner is still useful so I’m publishing this now.

This is a story about how I figured out how to set up modifiers in Karabiner Elements to trigger actions in BetterTouchTool.

For years I’ve used BetterTouchTool keyboard shortcuts for window management. To keep from overcomplicating this, let’s just say that I have four shortcuts for four common window management commands. If I hold down ⌃⌥⌘ I can then tap the four arrow keys to resize/reposition windows:

Shortcut Action
⌃⌥⌘← Fill left half of screen
⌃⌥⌘→ Fill right half of screen
⌃⌥⌘↑ Fill entire screen1
⌃⌥⌘↓ Center window on screen

Like I said, I’ve done this for years, and it works fine. But I wanted to try something different and get a little crazy. I wondered if it was possible to hold down the fn key to enter a sort of “Window Management Mode.” The idea was bigger than that, really. It was more along the lines of “I’ve got this fn key. Why don’t I add a bunch of new shortcuts that use it?” We’ve got the Command, Option, and Control keys and holding down each one gives you an entire new layer of commands. Why not do the same with the fn key?

My trimmed down idea was to set up the following shortcuts2:

Shortcut Action
fn+⌃ Fill left half of screen
fn+⌘ Fill right half of screen
fn+⇧ Fill entire screen
fn+⌥ Center window on screen

So while holding down the fn key I could tap any of the other modifier keys on the left side of the keyboard to control windows. The upside of this is two-fold. First, it’s a single-handed operation. Second, it frees up the ⌃⌥⌘+arrow shortcuts for something more useful, probably in my editor, but I haven’t yet figure out what magic to invoke with that very special combination.

But how to set up those key combos? Things are complicated by the fact that I want to trigger a command by tapping a modifier key (like command or control) rather than a standard key. Now it is sort of possible to set up these shortcuts in BetterTouchTool by setting up a Key Sequence. But there is an issue with it. With BTT Key Sequences you set a maximum delay between keystrokes. So it would be possible for the command to not fire if too much time passed between holding down fn and tapping the other modifier key. The bigger issue is that I would not be able to move a window to the right side of the screen and then immediately center it, which is something I like to do all the time. I mean I could, but I’d have to lift my finger off of the fn key after I tapped the ⌘ key and then press fn again before tapping ⌥. And that rubs me the wrong way.

Enter Karabiner Elements.

With Karabiner I can set up shortcuts (or “modifications,” in Karabiner-speak) exactly how I want for this situation. If I tap the left ⌘ key while fn is held down, it will do something. Period. The end. Perfect. The problem is that Karabiner, unlike BTT, doesn’t know anything about managing windows. But Karabiner can trigger shell scripts. And BTT can be scripted with Apple Script.

Here’s my first attempt at getting Karabiner to fire a trigger defined in a BetterTouchTool :

{
  "description": "fn + Left ⌃ | Maximize Window Left",
  "manipulators": [
    {
      "type": "basic",
      "from": {
        "key_code": "left_control",
        "modifiers": {
          "mandatory": [
            "fn"
          ]
        }
      },
      "to": [
        {
          "shell_command": "osascript -e 'tell application \"BetterTouchTool\" to execute_assigned_actions_for_trigger \"14915871-78D8-49F7-A95E-F292366825EA\"'"
        }
      ]
    }
  ]
}

In plain English, this says: “when you tap the left Control key while the fn key is held down, run this shell command: osascript -e 'tell application "BetterTouchTool" to execute_assigned_actions_for_trigger "14915871-78D8-49F7-A95E-F292366825EA"'

Where did that UUID come from? You can right-click on a trigger in BTT and copy that trigger’s UUID.

That was my first attempt: using Apple Script to run the actions assigned to a specific trigger. And it works. BUT, I had to keep that trigger in BTT which means having that keyboard shortcut set up in BTT and a big reason I wanted to go through this exercise was to free up my precious ⌃⌥⌘← shortcut for something else!

Attempt two is nearly identical to my first attempt. The only difference is the shell command that’s getting run:

"shell_command": "osascript ~/Dropbox/scripts/window-management/fill-left-side-of-screen.scpt"

Rather than running an inline Apple Script, it’s running one saved in an external file. Here’s the contents of that script:

var BTT = Application('BetterTouchTool');
var action = {
  "BTTPredefinedActionType" : 19
}

BTT.trigger_action(JSON.stringify(action));

You can find the value of "BTTPredefinedActionType" by right-clicking on the action in BTT and selecting Copy (or Copy JSON in older version of BTT). That copies a lot of data you don’t need, so paste it all in an editor window and pull out only what you need.

Now Karabiner is running an external Apple Script that contains all the info BTT needs to resize the window so you’re free to delete the shortcut from BTT!


  1. Fill the screen without going into full-screen mode. Not that there’s anything wrong with full-screen mode, that’s just not what I wanted in this case. 
  2. There’s actually logic to the shortcuts I came up with. ⌃ is the left-most modifier (not counting the fn key) so that acts the same as my previous ⌃⌥⌘← command. Likewise the ⌘ key is the right-most modifier so it takes on the action I had assigned to the right arrow.