Skip to content

Instantly share code, notes, and snippets.

@simonw
Last active July 22, 2022 17:05
Show Gist options
  • Select an option

  • Save simonw/43706c96c3dcdedb7d2abc7c4d6a5a9c to your computer and use it in GitHub Desktop.

Select an option

Save simonw/43706c96c3dcdedb7d2abc7c4d6a5a9c to your computer and use it in GitHub Desktop.
How I got a Yubikey working with a Dvorak keyboard and Karabiner-Elements

How I got a Yubikey working with a Dvorak keyboard and Karabiner-Elements

I needed to set up a new Yubikey device, which plugs into my Mac laptop via USB-C and injects one-time codes by pretending to be a keyboard.

Problem: I use Dvorak... so the Yubikey codes were coming through incorrectly and failing to work.

https://superuser.do/2014/10/22/yubikey-support-for-non-qwerty-keyboard-layouts-on-mac-os-x/ has a recipe for fixing this using Karabiner. But... those instructions are for an older Karabiner which is configured using XML files.

The latest Karabiner - Karabiner-Elements - uses a JSON configuration instead.

Here's how I got it working:

  1. Installed Karabiner Elements 12.1.0 from https://pqrs.org/osx/karabiner/

  2. Launched Karabiner Elements for the first time (to ensure it would create its config files). Enabled it for the Yubikey in devices:

2018-10-30 at 1 55 pm

  1. Added a single key mapping specific to the Yubijey, in order to see how that looks in the config:

2018-10-30 at 2 11 pm

  1. Opened up the freshly generated ~/.config/karabiner/karabiner.json file to see what it looks like.

  2. Rebuilt the JSON section for the "simple_modifications" for that keyboard, starting with the XML example here: https://gist.github.com/sudowork/c7f182752a929d08a5ac - the hardest part was figuring out the keywords for non-alphanumeric-characters - I ended up consulting the Karabiner source code for those: https://github.com/tekezo/Karabiner-Elements/blob/d9cdf3312d3aa2f9887fd270a59e30f9670fc39c/src/share/types.hpp#L231-L448

The JSON is attached to this gist.

  1. Saved the new JSON in ~/.config/karabiner/karabiner.json. Useful tip: just hitting "save" on that file causes Karabiner to refresh its configuration - and the "Log" tab in the UI is really helpful here as it will directly display any validation errors in the JSON.

2018-10-30 at 2 26 pm

I tested the Yubikey in a text file, by running it in Dvorak and QWERTY mode and with and without the Karabiner modifications enabled. This gave me confidence that it was doing the right thing.

And... it worked! I can now use my Yubikey to sign in even though my regular keyboard layout is Dvorak.

{
"global": {
"check_for_updates_on_startup": true,
"show_in_menu_bar": true,
"show_profile_name_in_menu_bar": false
},
"profiles": [
{
"complex_modifications": {
"parameters": {
"basic.simultaneous_threshold_milliseconds": 50,
"basic.to_delayed_action_delay_milliseconds": 500,
"basic.to_if_alone_timeout_milliseconds": 1000,
"basic.to_if_held_down_threshold_milliseconds": 500
},
"rules": []
},
"devices": [
{
"disable_built_in_keyboard_if_exists": false,
"fn_function_keys": [],
"identifiers": {
"is_keyboard": true,
"is_pointing_device": false,
"product_id": 1031,
"vendor_id": 4176
},
"ignore": false,
"manipulate_caps_lock_led": false,
"simple_modifications": [
{
"from": {
"key_code": "open_bracket"
},
"to": {
"key_code": "hyphen"
}
},
{
"from": {
"key_code": "close_bracket"
},
"to": {
"key_code": "equal_sign"
}
},
{
"from": {
"key_code": "c"
},
"to": {
"key_code": "i"
}
},
{
"from": {
"key_code": "comma"
},
"to": {
"key_code": "w"
}
},
{
"from": {
"key_code": "d"
},
"to": {
"key_code": "h"
}
},
{
"from": {
"key_code": "period"
},
"to": {
"key_code": "e"
}
},
{
"from": {
"key_code": "e"
},
"to": {
"key_code": "d"
}
},
{
"from": {
"key_code": "equal_sign"
},
"to": {
"key_code": "close_bracket"
}
},
{
"from": {
"key_code": "f"
},
"to": {
"key_code": "y"
}
},
{
"from": {
"key_code": "g"
},
"to": {
"key_code": "u"
}
},
{
"from": {
"key_code": "h"
},
"to": {
"key_code": "j"
}
},
{
"from": {
"key_code": "i"
},
"to": {
"key_code": "g"
}
},
{
"from": {
"key_code": "j"
},
"to": {
"key_code": "c"
}
},
{
"from": {
"key_code": "k"
},
"to": {
"key_code": "v"
}
},
{
"from": {
"key_code": "l"
},
"to": {
"key_code": "p"
}
},
{
"from": {
"key_code": "hyphen"
},
"to": {
"key_code": "quote"
}
},
{
"from": {
"key_code": "n"
},
"to": {
"key_code": "l"
}
},
{
"from": {
"key_code": "o"
},
"to": {
"key_code": "s"
}
},
{
"from": {
"key_code": "p"
},
"to": {
"key_code": "r"
}
},
{
"from": {
"key_code": "q"
},
"to": {
"key_code": "x"
}
},
{
"from": {
"key_code": "quote"
},
"to": {
"key_code": "q"
}
},
{
"from": {
"key_code": "r"
},
"to": {
"key_code": "o"
}
},
{
"from": {
"key_code": "s"
},
"to": {
"key_code": "semicolon"
}
},
{
"from": {
"key_code": "semicolon"
},
"to": {
"key_code": "z"
}
},
{
"from": {
"key_code": "slash"
},
"to": {
"key_code": "open_bracket"
}
},
{
"from": {
"key_code": "t"
},
"to": {
"key_code": "k"
}
},
{
"from": {
"key_code": "u"
},
"to": {
"key_code": "f"
}
},
{
"from": {
"key_code": "v"
},
"to": {
"key_code": "period"
}
},
{
"from": {
"key_code": "w"
},
"to": {
"key_code": "comma"
}
},
{
"from": {
"key_code": "x"
},
"to": {
"key_code": "b"
}
},
{
"from": {
"key_code": "y"
},
"to": {
"key_code": "t"
}
},
{
"from": {
"key_code": "b"
},
"to": {
"key_code": "n"
}
}
]
},
{
"disable_built_in_keyboard_if_exists": false,
"fn_function_keys": [],
"identifiers": {
"is_keyboard": true,
"is_pointing_device": false,
"product_id": 632,
"vendor_id": 1452
},
"ignore": true,
"manipulate_caps_lock_led": true,
"simple_modifications": []
}
],
"fn_function_keys": [
{
"from": {
"key_code": "f1"
},
"to": {
"consumer_key_code": "display_brightness_decrement"
}
},
{
"from": {
"key_code": "f2"
},
"to": {
"consumer_key_code": "display_brightness_increment"
}
},
{
"from": {
"key_code": "f3"
},
"to": {
"key_code": "mission_control"
}
},
{
"from": {
"key_code": "f4"
},
"to": {
"key_code": "launchpad"
}
},
{
"from": {
"key_code": "f5"
},
"to": {
"key_code": "illumination_decrement"
}
},
{
"from": {
"key_code": "f6"
},
"to": {
"key_code": "illumination_increment"
}
},
{
"from": {
"key_code": "f7"
},
"to": {
"consumer_key_code": "rewind"
}
},
{
"from": {
"key_code": "f8"
},
"to": {
"consumer_key_code": "play_or_pause"
}
},
{
"from": {
"key_code": "f9"
},
"to": {
"consumer_key_code": "fastforward"
}
},
{
"from": {
"key_code": "f10"
},
"to": {
"consumer_key_code": "mute"
}
},
{
"from": {
"key_code": "f11"
},
"to": {
"consumer_key_code": "volume_decrement"
}
},
{
"from": {
"key_code": "f12"
},
"to": {
"consumer_key_code": "volume_increment"
}
}
],
"name": "Default profile",
"selected": true,
"simple_modifications": [],
"virtual_hid_keyboard": {
"country_code": 0
}
}
]
}
@april

april commented Jul 22, 2022

Copy link
Copy Markdown

Note that if you have a remotely new-ish Yubikey, you can instead run:

ykpersonalize -S0c110b071c180d0a0619130f120e09378c918b879c988d8a8699938f928e89b7271e1f202122232425269e2b28

And it should work anytime you're in the Dvorak layout, without having to use something like Karabiner Elements. This is as documented by Yubico and works with my Yubikey Nano.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment