I recently published a Karabiner trick that turned ; plus J/I/K/L into arrow keys. I’ve determined that my implementation could use some work. Here’s the redux.

More from "KeyBinding"

The original tip used Karabiner to turn ; into a Fn key when pressed with other keys, and allowed a double tap to add additional functionality. Then the arrow keys were assigned with BetterTouchTool. This implementation ended up being a bit flaky when it came to switching directions, key repeats, and the normal functionality of the semicolon key.

I completely re-implemented this using just Karabiner, which is much smoother and solves all of the above issues. The only difference in actual usage is that instead of a double tap to get Fn+arrow functionality, it uses the quote key (to the right of semicolon). The result functions perfectly with other modifier keys like and for selections.

All of the snippets in this post are gathered into this gist.

To use this setup, you need four new rules in Karabiner. For each of the following snippets, go to Complex Modifications, select Add your own rule, and paste each snippet into its own rule.

Obviously with a tiny bit of editing you can make any of these function with Vim-style H/J/K/L keys.

First, we make the ; function as Left-Fn+ when pressed with other keys, posting ; as usual when pressed and released alone.

semicolon-to-left-cmd-fn.json raw
{
    "description": "Change ; to Left_command + Fn if pressed with other keys (Post ; when pressed alone)",
    "manipulators": [
        {
            "from": {
                "key_code": "semicolon",
                "modifiers": { "optional": ["any"] }
            },
            "to": [
                {
                    "key_code": "fn",
                    "modifiers": ["left_command"]
                }
            ],
            "to_if_alone": [{ "key_code": "semicolon" }],
            "type": "basic"
        }
    ]
}

Next, we make the ' key function as Right-Fn+ when held with other keys, posting ' when pressed alone.

quote-to-right-cmd-fn.json raw
{
    "description": "Change ' to Right_command + Fn if pressed with other keys (Post ' when pressed alone)",
    "manipulators": [
        {
            "from": {
                "key_code": "quote",
                "modifiers": { "optional": ["any"] }
            },
            "to": [
                {
                    "key_code": "fn",
                    "modifiers": ["right_command"]
                }
            ],
            "to_if_alone": [{ "key_code": "quote" }],
            "type": "basic"
        }
    ]
}

Now we assign our J/I/K/L keys to /// when pressed along with the ; key (which is now Left-Fn+).

To make this into H/J/K/L navigation, change the "key_code": "k" lines to h, j, k, and l, in that order.

left-cmd-fn-jkil-to-arrow.json raw
{
    "description": "Change Left_command + Fn + J/K/I/L to Arrow Keys",
    "manipulators": [
        {
            "from": {
                "key_code": "j",
                "modifiers": {
                    "mandatory": ["left_command", "fn"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "left_arrow" }],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "k",
                "modifiers": {
                    "mandatory": ["left_command", "fn"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "down_arrow" }],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "i",
                "modifiers": {
                    "mandatory": ["left_command", "fn"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "up_arrow" }],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "l",
                "modifiers": {
                    "mandatory": ["left_command", "fn"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "right_arrow" }],
            "type": "basic"
        }
    ]
}

And lastly, we assign J/I/K/L keys to /// when pressed along with the ' key.

right-cmd-fn-jkil-to-fn-arrow.json raw
{
    "description": "Change Right_command + Fn + J/K/I/L to Home / Page Down / Page Up / End",
    "manipulators": [
        {
            "from": {
                "key_code": "j",
                "modifiers": {
                    "mandatory": ["right_command", "fn"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "home" }],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "k",
                "modifiers": {
                    "mandatory": ["right_command", "fn"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "page_down" }],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "i",
                "modifiers": {
                    "mandatory": ["right_command", "fn"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "page_up" }],
            "type": "basic"
        },
        {
            "from": {
                "key_code": "l",
                "modifiers": {
                    "mandatory": ["right_command", "fn"],
                    "optional": ["any"]
                }
            },
            "to": [{ "key_code": "end" }],
            "type": "basic"
        }
    ]
}

Now you can hold down ; and use J/I/K/L as arrow keys, and key repeat, switching between directions, and modifier-based selections will all work smoothly. Hold down ' and use the same keys to navigate with ///. Enjoy!