Kanata is a powerful cross-platform software keyboard remapper. On macOS, achieving the lowest latency and most reliable hardware interception requires pairing Kanata with the Karabiner-DriverKit-VirtualHIDDevice driver rather than relying solely on the standard macOS accessibility APIs.
Install the Virtual HID Driver
Kanata needs this driver to create a virtual keyboard that macOS recognizes as physical hardware.
Download the latest .pkg installer from the Karabiner-DriverKit GitHub Releases.
Run the installer.
Activate the system extension by running the following command in your terminal:
/Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager activate
Open System Settings > Privacy & Security, scroll down to the Security section, and click Allow for software from "pqrs.org".
Verify the driver is active by running systemextensionsctl list. Look for [activated enabled] next to the Karabiner DriverKit entry.
Install Kanata
The most straightforward installation on macOS is via Homebrew.
brew install kanata
or
cargo install kanata
Create the Kanata Configuration
Create a configuration file to define your hardware and your mappings. For system daemons, it is safer to use absolute paths to a direct source file rather than relying on symlinks, which can cause permission crashes.
Create a file at /Users/YOUR_USERNAME/.config/kanata/kanata.kbd (or directly in your dotfiles repository).
The below config defines the keyboards kanata should work on, a variable tap-hold, the default source and two layers. The first layer (default) swaps lctl and caps, so when pressing the caps you'll get a lctl. For the second layer you need to hold n, which converts the qwertyuiop keys to 1234567890.
(defcfg
concurrent-tap-hold yes
macos-dev-names-include (
"Apple Internal Keyboard / Trackpad"
"Karabiner DriverKit VirtualHIDKeyboard 1.8.0"
)
)
(defvar
tap-hold 200
)
(defsrc
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ] \
caps a s d f g h j k l ; ' ret
lsft z x c v b n m , . / up rsft
fn lctl lalt lmet spc rmet ralt left down rght
)
(defalias
n_layer (tap-hold 200 200 n (layer-toggle numbers))
)
(deflayer default
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ] \
lctl a s d f g h j k l ; ' ret
lsft z x c v b @n_layer m , . / up rsft
fn caps lalt lmet spc rmet ralt left down rght
)
(deflayer numbers
_ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _
_ 1 2 3 4 5 6 7 8 9 0 _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _
)
Configure macOS Security Permissions
macOS requires explicit user intent for a binary to intercept keyboard inputs. You must manually add the Kanata binary to the TCC (Transparency, Consent, and Control) database.
Open System
Settings > Privacy & Security > Input Monitoring.Click the
+button.Press
Cmd + Shift + Gto open the path navigator.Paste
/opt/homebrew/bin/kanataand press Enter.
Select the binary and ensure the toggle is set to ON.
Repeat this exact process for Privacy & Security > Accessibility. (Optional)
Setup Background Services (LaunchDaemons)
To run Kanata seamlessly without an open terminal window, configure two LaunchDaemons: one for the Karabiner communication bridge and one for Kanata itself. These must run as root.
The Karabiner Daemon
Create /Library/LaunchDaemons/org.pqrs.karabiner-daemon.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.pqrs.karabiner-daemon</string>
<key>ProgramArguments</key>
<array>
<string>/Library/Application Support/org.pqrs/Karabiner-DriverKit-VirtualHIDDevice/Applications/Karabiner-VirtualHIDDevice-Daemon.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Daemon</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
The Kanata Daemon
Create /Library/LaunchDaemons/com.kanata.daemon.plist (Replace YOUR_USERNAME with your actual macOS shortname):
<?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.kanata.daemon</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/kanata</string>
<string>--cfg</string>
<string>/Users/YOUR_USERNAME/.config/kanata/kanata.kbd</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/kanata.out.log</string>
<key>StandardErrorPath</key>
<string>/tmp/kanata.err.log</string>
</dict>
</plist>
Set Ownership and Boot the Services
Ensure the .plist files are owned by the system, make sure the path to your config file is traversable by the root user, and start the daemons.
sudo chown root:wheel /Library/LaunchDaemons/org.pqrs.karabiner-daemon.plist
sudo chown root:wheel /Library/LaunchDaemons/com.kanata.daemon.plist
# Optional
sudo chmod 644 /Users/YOUR_USERNAME/.config/kanata
sudo launchctl load -w /Library/LaunchDaemons/org.pqrs.karabiner-daemon.plist
sudo launchctl load -w /Library/LaunchDaemons/com.kanata.daemon.plist
Verification and Troubleshooting
Check if the services are running successfully:
sudo launchctl list | grep -E "kanata|karabiner"
You should see a numerical PID in the first column for both entries, and a 0 in the second column.
Run to view the errors from kanata
cat /tmp/kanata.err.log
Common Errors:
Exit code 1 for Kanata: Usually indicates a file path issue. Ensure there are no tildes (~) in your .plist path.
not permitted in /tmp/kanata.err.log: The Kanata binary was dropped from the Input Monitoring list. Remove it from System Settings and re-add it manually using Cmd + Shift + G.
asio:61 or asio:2: Kanata cannot reach the Karabiner driver. Ensure org.pqrs.karabiner-daemon is actively running.
Top comments (0)