Using hidutil to map macOS keyboard keys

I am a Karabiner Elements user and had donated to it previously and even talked about some custom key mappings I use. Things had a been a bit spotty with it since macOS Big Sur but with the latest version 13.0 and macOS 11.0, 11.1, and 11.2 things were fine. However, yesterday I updated one of my Macs to 11.3 Beta and that broke Karabiner. In addition to it I noticed that my M1 Mac always reports that it restarted due to a kernel panic whenever I restart; and when I Googled for the panic report entries the first hit was Karabiner. Looks like things aren’t entirely with Karabiner and macOS Big Sur after all.

Part of me feels sorry for all macOS developers. Can’t be much fun having your software break due to ground breaking changes in macOS… it’s a game of catch-up with not much dividends, especially if you are a free product like Karabiner. Even paid products like Carbon Copy Cloner have a tough time I imagine as they have to spend time fixing things for Big Sur rather than working on new features. I started using Carbon Copy Cloner recently and was struck by this blog post:

Every year we spend hundreds of hours making changes to CCC to accommodate the new OS. Every year. CCC isn’t like other apps that can easily roll with the changes; our solution is tied so closely to the logistics of the startup process, and that happens to be something that Apple has been changing a lot since the introduction of APFS. The logic changes required to accommodate APFS volume groups alone are mind blowing. All of that time spent is subtracted from the time we can spend on feature work. To put it plainly, we spend about a quarter to half of our year just making CCC work with the next year’s OS. That’s not a shiny new feature that users can swoon about (and pay for!), it’s typically thankless work, and – fair or not – work that users have come to expect us to provide for free.

The blog post goes on to talk how things are better now with Big Sur, but it’s something I too as an end user often take for granted – that all a developer has to do is spend time creating new features (the fun and sexy part of being a developer), while in reality a major part of their time also goes into just keeping the product working across OS upgrades (the not so fun and sexy part of being a developer). I know I get irritated when a PowerShell script I’ve written stops working because something in the software (e.g. Exchange) it talks to has changed; I can only imagine how much more frustrating it must be for more complex software.

Anyways, enough digression. I decided to uninstall Karabiner as it wasn’t working at all on one machine and seemed to be causing kernel panics on the other. I use Karabiner mainly coz I have a Microsoft Sculpt keyboard and I’d like to set some keymappings for that. One of these – swapping Ctrl and Cmd is easy to do from macOS’s System Preferences itself – but the rest are what I chiefly needed Karabiner for (as I mentioned in the earlier post I want to swap the accent and \ keys as what’s shown on the keyboard is not what appears when I press it).

Hello hidutil

I remembered someone mentioned hidutil in the Karabiner issues threads in the past so Googled on that and came across this Apple technical note. It’s pretty easy as per the article; all you need to do is run a command like this:

This swaps the key with code 0x700000004 with the key with code 0x700000005. You can find a table with these codes in the technical note (which in turns points to a missing page from the USB forum). I’ve take a screenshot it and will include here in case the Apple page too goes missing (but we don’t really need this screenshot as I’ll explain later).

Add 0x700000000 to the number in the table. For example the @ sign is code 0x1F so in the hidutil command above you will put it as 0x70000001F. In my case I want to swap the “Grave Accent and Tilde” (0x35) with “Non-US \ and |” (0x64) so my command would be:

This doesn’t return any output but I can see this keymapping (and any others) via the following command:

In the --set block above first I map 0x35 to 0x64 and then I map 0x64 to 0x35 (as I am swapping these) – that’s why I have two set of mappings. It is basically a JSON block that looks like this:

Surviving Reboots

Turns out after a reboot the above mapping disappears. So you need to do something to make this survive that. I know macOS has an equivalent to systemd and others called launchd and I had dabbled with it in the past. When I Googled on creating a launchd service file I came across another Apple note. Using the info in that and this site I made a service file that will run the above hidutil command whenever macOS reboots.

I created the following as ~/Library/LaunchAgents/local.hidutilKeyMapping.plist. (One of my Macs didn’t have the LaunchAgents folder so I had to create that folder too).

What I’ve done is split the earlier command into separate lines under the <array> element. One difference is I removed the ' before and after the "UserKeyMapping" block – I discovered that with it the file wasn’t working.

After saving I loaded it as follows:

If all went well you won’t see any output. I could confirm it had loaded though like this:

My service name is local.hidutilKeyMapping (it’s the <Label> entry in the service file above) so that’s why I am searching for all services with the word local in them. I could see local.hidutilKeyMapping so that was good. Next I started it:

Again, no output. But now after a reboot I can see the key mappings are created via

Discovering the Generator

At this point I was pretty pleased with myself and thinking about creating this blog post. I wanted to see if there was a way of discovering the keycodes for any keys not in the above table. For instance, the Sculpt keyboard has these media keys and previously I was able to map them using Karabiner. If I could find the keycodes for them and the corresponding destination keycodes that macOS needs for controlling media I was golden. Googling on that however got me to this site: https://hidutil-generator.netlify.app/. Whoa!

This was a site where one could select source and destination keys and it will create the .plist file I did above. That is so cool! Someone made a website to do that. I love it.

I was able to add the following mappings:

Sweet!

I then added the generated .plist file into mine (this was just a case of me having a NIH syndrome – I could have just added the accent and \ keys to the website and replaced my .plist file with the result). The end result is that I now have all the mappings I was using Karabiner for but without using Karabiner. :) I knew I wasn’t a heavy user of Karabiner but now I realize I didn’t even need it to begin with! This way I am using a native macOS tool for the keymapping and hopefully it is less prone to breaking between macOS updates.

That’s all for now!

Update: To reset the mappings: