Zero-Latency Keyboard Remapper for macOS External Keyboards
bhkey remaps modifier keys on external keyboards using Apple's native hidutil kernel property API — no virtual driver, no background daemon eating CPU. Mapping is applied at the kernel level with zero input latency. Unlike Karabiner-Elements, bhkey installs nothing into the system; all files live inside your home directory.
It targets only your external keyboard (matched by VendorID+ProductID), so your built-in keyboard or Magic Keyboard is never touched.
| bhkey | Karabiner-Elements | |
|---|---|---|
| Input latency | 0ms (kernel-level hidutil) | ~1–2ms (userspace daemon) |
| Installation | Home directory only, no sudo | System extension + reboot required |
| macOS upgrades | Never breaks | Frequently requires reinstall |
| CPU / memory | Zero (apply-and-forget) | Persistent background process |
| Scope | Modifier key remapping | Full keyboard customization engine |
Use bhkey if you just want to swap modifier keys on a Windows-layout keyboard with zero overhead.
Use Karabiner-Elements if you need complex rules, layers, or non-modifier key remapping.
- macOS 10.12 Sierra or later (
hidutilwas introduced in Sierra) bash
curl -fsSL https://raw.githubusercontent.com/baekho-lim/bhkey/main/install.sh | bashbrew tap baekho-lim/bhkey
brew install bhkeycurl -L https://github.com/baekho-lim/bhkey/releases/latest/download/bhkey.sh -o bhkey.sh
chmod +x bhkey.sh
bash bhkey.sh applygit clone https://github.com/baekho-lim/bhkey.git
cd bhkey
chmod +x bhkey.sh
bash bhkey.sh applyThe apply command runs 5 pre-flight checks, applies the mapping via hidutil, and installs a LaunchAgent for persistence across reboots and USB hot-plug events.
| Physical Key | macOS Behavior | Note |
|---|---|---|
| Left Alt | Left Command (⌘) | Windows → Mac layout |
| Left Win | Left Option (⌥) | Windows → Mac layout |
| Right Alt | Right Command (⌘) | |
| Right Win | F19 | Voice input trigger |
| 한/영 key (0x90) | F18 | Input source switch |
| 한자 key (0x91) | F19 | Same as Right Win |
This default layout is designed for Windows-layout keyboards (e.g., Corsair, Leopold) used on macOS.
bash bhkey.sh apply # Run anti-thesis checks and apply mapping
bash bhkey.sh reset # Remove all custom mappings
bash bhkey.sh status # Show current hidutil state and LaunchAgent status
bash bhkey.sh version # Print version- hidutil: bhkey calls
hidutil property --setwith a JSON mapping payload. This is a macOS-native API that sets kernel-level key translation — no driver, no process, no latency. - Per-device targeting: The
--matchingflag filters byVendorIDandProductID, so only the specified external keyboard is affected. - LaunchAgent persistence: bhkey installs a plist at
~/Library/LaunchAgents/com.bh.keymapping.plistwithRunAtLoad: trueandWatchPaths: /dev. The mapping auto-applies on login and whenever a USB device is connected.
After running bhkey apply, assign the F18/F19 keys in System Settings:
- Input source switch (F18): System Settings > Keyboard > Keyboard Shortcuts > Input Sources > assign F18 to "Select the previous input source" or "Select next source in input menu"
- Voice input / dictation (F19): System Settings > Keyboard > Dictation > set the shortcut to F19 (press Right Win key in the shortcut field)
bhkey runs 5 checks before applying any mapping:
- Detects macOS System Settings modifier key overrides — warns if a key would be double-mapped
- Checks for Karabiner-Elements or Corsair iCUE running — both can conflict with
hidutil - Detects the target external keyboard — aborts if the device is not found
- Handles
hidutilpermission errors and provides asudohint for macOS 14.2+ - Validates the LaunchAgent plist syntax via
plutil -lintbefore loading
To change the key mappings, see docs/CUSTOMIZE.md for the HID usage table, how to find your keyboard's VendorID/ProductID, and how to modify the mapping payload.
- v1.0 — Shell CLI with hidutil and 5 anti-thesis guards
- v2.0 — Swift menu bar app with real-time mapping toggle and keyboard profile manager
- v3.0 — Per-keyboard profiles with automatic switching on connect/disconnect
Contributions and ideas welcome — open a Discussion or Issue.
MIT