Sierra broke my keyboard modifier keys and I refused to wait for a fix

I’m addicted to staying up to date on software. I seem to do this to myself because of a healthy mix of personal and professional curiosity with a sprinkle of masochism. The latest update to Apple’s Desktop Operating System — titled Sierra — dropped this week and its actually been pretty stable. For years I had issues with my code for days or weeks after a major update, but that seems to have improved in the last few updates. That’s not to say there are no issues though:

  • Plugged into a display, my computer won’t wake up without opening the laptop lid
  • Logitech mice are barely functioning
  • Keyboard key modifiers have stopped working

I’m a heavy keyboard user — I barely use a mouse at all — so that last bullet point is really tough for me to deal with. First let’s talk about what the keyboard modifiers are for. I work remotely so a lot of the time I’m working on my Macbook, using the builtin keyboard. However, sometimes I work at home with an Apple Display and an external Keyboard. I prefer a mechanical keyboard, which tend to have the more common Windows/Linux key layout. A Macbook keyboard looks something like this:

Whereas the more common layout looks more like this:

Note the that the Windows button (bottom left) acts as basically the same key as the Mac’s Command button. In Mac world, the Command button is heavily used, though. So the Alt (option) and Command (Windows key) are flipped between the two keyboards. This is a problem because my muscle memory has me used to the Command button being next to the space bar and the Option key being to the left of that.

So before Sierra, you would follow the instructions here and move on with your life. It was a supported configuration out-of-the-box from Apple. Well, that menu still exists but the functionality seems to have broken. So, the Engineer in me went looking for a couple rolls of duct tape, because I’m not about to change my workflow.

After some searching I came across Karabiner. This let’s you remap keys and do somewhat complicated things. It has a whole application and user interface. Rather than deal with a new user interface, I simply installed the little tool that remaps keys on the fly from here. With that I configured my key mapping in “~/.karabiner.d/configuration/karabiner.json”:

{
“profiles”: [
{
“name”: “Keyboard”,
“selected”: true,
“simple_modifications”: {
“caps_lock”: “escape”,
"left_command": "left_option",
"left_option": "left_command"
}
}
]
}

Sweet, 🍰 (Piece of cake). I returned to work as normal. Later in the day I moved to my front-porch to work and was immediately discombobulated as my Macbook keyboard was now messed up (reversed Option and Command). I could edit that config each time I switch keyboards, but that seems fairly tedious. With a little bit of research, I found a Github issue complaining about the same thing (thanks again, Internet) which referenced a tool called Hammerspoon. Hammerspoon allows you to plug-in to certain OS events like USB device changes. This’ll work great. After installing Hammerspoon, I needed another keyboard configuration as well as a simple way to swap them:

// new karabiner config
{
"profiles": [
{
"name": "Macbook Keyboard",
"selected": false,
"simple_modifications": {
"caps_lock": "escape"
}
},
{
"name": "External Keyboard",
"selected": true,
"simple_modifications": {
"caps_lock": "escape",
"left_command": "left_option",
"left_option": "left_command"
}
}
]
}
-- ~/.hammerspoon/init.lua
local usbWatcher = nil
local home = os.getenv("HOME")
function usbDeviceCallback(data)
if (data["productName"] == "QuickFire Rapid keyboard") then
if (data["eventType"] == "added") then
hs.execute(home .. '/.hammerspoon/karabiner-switcher 1')
elseif (data["eventType"] == "removed") then
hs.execute(home .. '/.hammerspoon/karabiner-switcher 0')
end
end
end
usbWatcher = hs.usb.watcher.new(usbDeviceCallback)
usbWatcher:start()

Look at that little Lua function that checks the keyboard being plugged in. You’ll need to make sure that “productName” matches your keyboard. I got the product name by plugging in my keyboard, going to System Preferences > Keyboard > Modifier Keys and check what your keyboard name is in that keyboard dropdown. Note that “~jonphenow/.hammerspoon/karabiner-switcher” is just a little script I wrote to switch the Karabiner config around. This hasn’t been written yet, so let’s do that:

#!/usr/bin/env ruby
require 'json'
select = ARGV[0].to_i
filename = "#{ENV["HOME"]}/.karabiner.d/configuration/karabiner.json"
file = File.open(filename)
data = JSON.parse(file.read)
file.close
data["profiles"][0]["selected"] = select == 0
data["profiles"][1]["selected"] = select == 1
json = JSON.generate(data)
file = File.new(filename, "w")
file.write(json)
file.close

Then you’ll need “chmod +x” that file so it can be executed. I’m partial to Ruby to so I whipped that up quick, but this would be just as easy to write in another language. Basically all it does is take an index of an array and flip a boolean on the configuration. Now, select the Hammerspoon menu item and “Reload Config” and you should be able to switch between keyboards at will.

With a little bit of tinkering I’m back to my normal workflow with keyboards, now if someone would write a Logitech mouse driver real quick, that’d be 👌 by me.


If you enjoyed this, hit the little ❤️ and let me know @jphenow.