Tilde (~) and plus-minus (±) in wrong place on keyboard

Here’s a solution that does not use any external tools.

Run this in Terminal.app:

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

Now try your ~ and ± keys: they should be switched around.

Problem is, this fix will only work until the next restart. To make it permanent, you have to automatically run it on system load.

You can do that in three Terminal.app commands:

  1. cat << 'EOF' > ~/.tilde-switch && chmod +x ~/.tilde-switch
    hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x700000035,"HIDKeyboardModifierMappingDst":0x700000064},{"HIDKeyboardModifierMappingSrc":0x700000064,"HIDKeyboardModifierMappingDst":0x700000035}]}'
    EOF
    

    (This is all a single command.) This stores the script from above in an invisible executable file in your home directory, ~/.tilde-switch.

  2. sudo /usr/bin/env bash -c "cat > /Library/LaunchDaemons/org.custom.tilde-switch.plist" << EOF
    <?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.tilde-switch</string>
        <key>Program</key>
        <string>${HOME}/.tilde-switch</string>
        <key>RunAtLoad</key>
        <true/>
        <key>KeepAlive</key>
        <false/>
      </dict>
    </plist>
    EOF
    

    (This is all a single command.) This creates a system task: ‘run the file from step 1 on every startup.’

  3. sudo launchctl load -w -- /Library/LaunchDaemons/org.custom.tilde-switch.plist
    

    This loads (activates) the task from step 2.

Steps 2 and 3 will prompt for your password. And now, your ~ and ± keys are permanently switched.

Note 1

This appears to work not only on the MacBook's build-in internal physical keyboard, but on the external keyboards as well.

Note 2

To undo the switching script (not the three steps), here’s the reverse script:

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

Note 3

To undo the three steps:

sudo launchctl unload -w -- /Library/LaunchDaemons/org.custom.tilde-switch.plist; sudo rm -f -- /Library/LaunchDaemons/org.custom.tilde-switch.plist ~/.tilde-switch

Credit

This solution is inspired by this article:

http://homeowmorphism.com/articles/17/Remap-CapsLock-Backspace-Sierra


Using Karabiner Elements, you can add a "Simple Modification" as follows:

"Karabiner Elements Preferences" window, "Simple Modifications" tab, "Target Device" dropdown is set to "Apple Internal Keyboard / Trackpad (No manufacturer name)". Two rows are shown in the configuration table. The first row contains "From key": "non_us_backslash", "To key": "grave_accent_and_tilde (<code>)". The second row contains "From key": "grave_accent_and_tilde (</code>)", "To key": "non_us_backslash".

Basically, you need to know that the name of the § (±) key in Karabiner's configuration screen is non_us_backslash

In my case, I used this method specifically for the built-in keyboard, leaving my external keyboards unchanged.


Here is Apple documentation with table containing all the keys and corresponding hexes. https://developer.apple.com/library/archive/technotes/tn2450/_index.html

Initial state is no active key remappings:

hidutil property --get UserKeyMapping
(null)

Remap ~ to §± one way:

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

Swap them both ways:

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

For removing any remappings back to initial just pass an empty array:

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

Building on CBlew's solution, one can do without the extra file (which wouldn't work as-is for a multi-user system). Write a plist file like

<?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>com.example.setkeyboard</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/bin/hidutil</string>
      <string>property</string>
      <string>--matching</string>
      <string>{"VendorID": 5426, "ProductID": 579}</string>
      <string>--set</string>
      <string>{"UserKeyMapping":[{"HIDKeyboardModifierMappingDst":0x7000000e3,"HIDKeyboardModifierMappingSrc":0x7000000e2},{"HIDKeyboardModifierMappingDst":0x7000000e2,"HIDKeyboardModifierMappingSrc":0x7000000e3},{"HIDKeyboardModifierMappingDst":0x7000000e7,"HIDKeyboardModifierMappingSrc":0x7000000e6},{"HIDKeyboardModifierMappingDst":0x7000000e6,"HIDKeyboardModifierMappingSrc":0x700000065}]}</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
  </dict>
</plist>

then set it with sudo launchctl load -w -- /Library/LaunchDaemons/com.example.setkeyboard.plist.

For generating the hidutil invocation I am using this simple Python script.