How to remap single Mac keyboard key

How to remap one Mac OS X keyboard key to the other without using any external tools? Is it even possible to do without being a mac developer? It turns out to be pretty simple in the new macOS X 10.12 Sierra using a little util named hidutil.

Problem

You don't like your Mac keyboard layout, or worse you have to work with a different layout at work than you have at home. In either case you can install some external tool which will do the remapping for you but maybe you don't like to have additional application just for remapping a single key? My problem was connected with having British keyboard at home and American at work. While it is IMO not a problem to get used to any of those switching between them on a daily basis is annoying. There was one key in particular which makes things a bit hard from a developer perspective. It was a tilde key `. Tilde key is placed next to the 1/! on the American keyboard and replaced by a section sign § key on the British one.

Solution

As it turns out for macOS X 10.12 Sierra you don't have to do anything more than running a short piece of code to do the required remapping.

Here is an simple example for the problem which I was facing which was remapping §/£ to `/~ key.

hidutil property --set '{"UserKeyMapping":
    [{"HIDKeyboardModifierMappingSrc":0x700000064,
      "HIDKeyboardModifierMappingDst":0x700000035}]
}'

As you can see you have to place appropriate values (usage ID) for HIDKeyboardModifierMappingSrc and HIDKeyboardModifierMappingDst which you will have to find in a table in the official docs. What is more for each "Usage ID (hex)" you will have to calculate bitwise "OR" with 0x700000000 which is very easy in most cases, but if you are facing any difficulties with that you can also use the following Bash command:

printf '%X\n' "$(( 0x700000000 | 0x64 ))"

Where 0x64 should be replaced with a value from "Usage ID (hex)" column.

In order to check current/effective mappings you can run:

hidutil property --get "UserKeyMapping"

And last but not least. In order to reset everything you have setup so far just execute:

hidutil property --set '{"UserKeyMapping":
    []
}'

NOTE

All changes made with hidutil are immediate, so you don't have to restart anything.

Automatically set custom key mapping after each reboot

Create plist file e.g. /Library/LaunchDaemons/org.custom.keyboard-remap.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>org.custom.keyboard-remap</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/bin/hidutil</string>
      <string>property</string>
      <string>--set</string>
      <string>{"UserKeyMapping": [{"HIDKeyboardModifierMappingSrc":0x700000064, "HIDKeyboardModifierMappingDst":0x700000035}] }</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
  </dict>
</plist>

Then load it with sudo launchctl load -w /Library/LaunchDaemons/org.custom.keyboard-remap.plist so it will be loaded on each system reboot.

If you want to check if your plist file was loaded successfully you can use sudo launchctl list | grep org.custom.keyboard-remap.plist.

NOTE In order to unload plist file from system autostart use sudo launchctl unload /Library/LaunchDaemons/org.custom.keyboard-remap.plist

Issues

I have only one issue with this problem which was finding an appropriate "Usage ID (hex)" for the section sign § key. As it turns out it was named in the Apple docs as Keyboard Non-US \ and |. In order to find that out I've used trial and error approach, so nothing fancy. If you will come across any better way of finding "Usage ID (hex)" codes please share.

In case of are receiving Invalid property list error message after loading plist file you are most probably trying to use the old syntax for plist file with <key>Program</key> instead of mentioned <key>ProgramArguments</key>.

Sources