You could remapping keys via the macOS embedded command line tool hidutil.
Key IDs Table
| Usage | Usage ID (hex) | Usage | Usage ID (hex) | Usage | Usage ID (hex) | Usage | Usage ID (hex) |
|---|---|---|---|---|---|---|---|
| Keyboard a and A | 0x700000004 | Keyboard 5 and % | 0x700000022 | Keyboard F7 | 0x700000040 | Keypad 6 and Right Arrow | 0x70000005E |
| Keyboard b and B | 0x700000005 | Keyboard 6 and ^ | 0x700000023 | Keyboard F8 | 0x700000041 | Keypad 7 and Home | 0x70000005F |
| Keyboard c and C | 0x700000006 | Keyboard 7 and & | 0x700000024 | Keyboard F9 | 0x700000042 | Keypad 8 and Up Arrow | 0x700000060 |
| Keyboard d and D | 0x700000007 | Keyboard 8 and * | 0x700000025 | Keyboard F10 | 0x700000043 | Keypad 9 and Page Up | 0x700000061 |
| Keyboard e and E | 0x700000008 | Keyboard 9 and ( | 0x700000026 | Keyboard F11 | 0x700000044 | Keypad 0 and Insert | 0x700000062 |
| Keyboard f and F | 0x700000009 | Keyboard 0 and ) | 0x700000027 | Keyboard F12 | 0x700000045 | Keypad . and Delete | 0x700000063 |
| Keyboard g and G | 0x70000000A | Keyboard Return (Enter) | 0x700000028 | Keyboard Print Screen | 0x700000046 | Keyboard Non-US \ and | | 0x700000064 |
| Keyboard h and H | 0x70000000B | Keyboard Escape | 0x700000029 | Keyboard Scroll Lock | 0x700000047 | Keyboard Application | 0x700000065 |
| Keyboard i and I | 0x70000000C | Keyboard Delete (Backspace) | 0x70000002A | Keyboard Pause | 0x700000048 | Keyboard Power | 0x700000066 |
| Keyboard j and J | 0x70000000D | Keyboard Tab | 0x70000002B | Keyboard Insert | 0x700000049 | Keypad = | 0x700000067 |
| Keyboard k and K | 0x70000000E | Keyboard Spacebar | 0x70000002C | Keyboard Home | 0x70000004A | Keyboard F13 | 0x700000068 |
| Keyboard l and L | 0x70000000F | Keyboard - and _ | 0x70000002D | Keyboard Page Up | 0x70000004B | Keyboard F14 | 0x700000069 |
| Keyboard m and M | 0x700000010 | Keyboard = and + | 0x70000002E | Keyboard Delete Forward | 0x70000004C | Keyboard F15 | 0x70000006A |
| Keyboard n and N | 0x700000011 | Keyboard [ and { | 0x70000002F | Keyboard End | 0x70000004D | Keyboard F16 | 0x70000006B |
| Keyboard o and O | 0x700000012 | Keyboard ] and } | 0x700000030 | Keyboard Page Down | 0x70000004E | Keyboard F17 | 0x70000006C |
| Keyboard p and P | 0x700000013 | Keyboard \ and | | 0x700000031 | Keyboard Right Arrow | 0x70000004F | Keyboard F18 | 0x70000006D |
| Keyboard q and Q | 0x700000014 | Keyboard Non-US # and ~ | 0x700000032 | Keyboard Left Arrow | 0x700000050 | Keyboard F19 | 0x70000006E |
| Keyboard r and R | 0x700000015 | Keyboard ; and : | 0x700000033 | Keyboard Down Arrow | 0x700000051 | Keyboard F20 | 0x70000006F |
| Keyboard s and S | 0x700000016 | Keyboard ' and " | 0x700000034 | Keyboard Up Arrow | 0x700000052 | Keyboard F21 | 0x700000070 |
| Keyboard t and T | 0x700000017 | Keyboard Grave Accent and Tilde | 0x700000035 | Keypad Num Lock and Clear | 0x700000053 | Keyboard F22 | 0x700000071 |
| Keyboard u and U | 0x700000018 | Keyboard , and "<" | 0x700000036 | Keypad / | 0x700000054 | Keyboard F23 | 0x700000072 |
| Keyboard v and V | 0x700000019 | Keyboard . and ">" | 0x700000037 | Keypad * | 0x700000055 | Keyboard F24 | 0x700000073 |
| Keyboard w and W | 0x70000001A | Keyboard / and ? | 0x700000038 | Keypad - | 0x700000056 | Keyboard Left Control | 0x7000000E0 |
| Keyboard x and X | 0x70000001B | Keyboard Caps Lock | 0x700000039 | Keypad + | 0x700000057 | Keyboard Left Shift | 0x7000000E1 |
| Keyboard y and Y | 0x70000001C | Keyboard F1 | 0x70000003A | Keypad Enter | 0x700000058 | Keyboard Left Alt | 0x7000000E2 |
| Keyboard z and Z | 0x70000001D | Keyboard F2 | 0x70000003B | Keypad 1 and End | 0x700000059 | Keyboard Left GUI | 0x7000000E3 |
| Keyboard 1 and ! | 0x70000001E | Keyboard F3 | 0x70000003C | Keypad 2 and Down Arrow | 0x70000005A | Keyboard Right Control | 0x7000000E4 |
| Keyboard 2 and @ | 0x70000001F | Keyboard F4 | 0x70000003D | Keypad 3 and Page Down | 0x70000005B | Keyboard Right Shift | 0x7000000E5 |
| Keyboard 3 and # | 0x700000020 | Keyboard F5 | 0x70000003E | Keypad 4 and Left Arrow | 0x70000005C | Keyboard Right Alt | 0x7000000E6 |
| Keyboard 4 and $ | 0x700000021 | Keyboard F6 | 0x70000003F | Keypad 5 | 0x70000005D | Keyboard Right GUI | 0x7000000E7 |
If you want to remap the key 'CapsLock(0x700000039)' to 'F18(0x70000006D)'. type below in terminal
$ hidutil property --set '{"UserKeyMapping":[
{
"HIDKeyboardModifierMappingSrc": 0x700000039, # source key
"HIDKeyboardModifierMappingDst": 0x70000006D # destination key
}
]}'$ hidutil property --get "UserKeyMapping"
# If there is no remapped key, you will receive (null).Above way will be undone whenever you reboot your Mac, so one way to persist the remapping is to run the hidutil command every time your Mac boots. For that, we can rely on Launch Agents.
Create a file named ~/Library/LaunchAgents/com.example.KeyRemapping.plist, that makes macOS run the hidutil tool every time it starts up.
<!--
Put this file in ~/Library/LaunchAgents/com.example.KeyRemapping.plist to
automatically remap your keys when macOS starts.
-->
<?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.KeyRemapping</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/hidutil</string>
<string>property</string>
<string>--set</string>
<string>{"UserKeyMapping":[
{
"HIDKeyboardModifierMappingSrc": 0x700000039,
"HIDKeyboardModifierMappingDst": 0x70000006D
}
]}</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
hidutil key remapping applied via launchd does not take effect, but works when run manually from Terminal
macOS version: Tahoe 26.5
Hardware: MacBook Air M5 US International (built-in keyboard)
Description
I have a LaunchAgent that runs
hidutil property --setat login to remap two keys on the built-in keyboard. The agent loads successfully andhidutil property --get UserKeyMappingconfirms the mapping is applied, but the keys do not behave differently.When I run the exact same
hidutilcommand manually from Terminal, the remapping works as expected immediately.I also tried adding the script as a Login Item via System Settings → General → Login Items — same result: mapping shows up in
hidutil --getbut keys do not respond differently.No third-party keyboard software (e.g. Karabiner-Elements) is installed.
Steps to reproduce
~/Library/LaunchAgents/com.example.remapkeys.plistwith the following content:Output confirms the mapping is present (correct decimal values).
Press the remapped keys — they behave as if no remapping is in effect.
Run the same command manually from Terminal:
hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x700000035,"HIDKeyboardModifierMappingDst":0x700000064},{"HIDKeyboardModifierMappingSrc":0x700000064,"HIDKeyboardModifierMappingDst":0x700000035}]}'The keys now remap correctly.
Expected behavior
hidutilapplied via launchd or Login Items should produce the same result as running the command manually from Terminal.Actual behavior
hidutil --getconfirms the mapping is registered, but the physical key behavior does not change. Running the same command from Terminal works correctly.What I have tried
sleep 2andsleep 5before thehidutilcall to account for possible timing issues — no changehidutildirectly from the plist — no changeQuestion
Is there a difference in the HID session context between a launchd agent / Login Item and an interactive Terminal session that would cause
hidutilto register the mapping but not apply it to the physical keyboard?