DEV Community

Richard Francis
Richard Francis

Posted on

Setting Up Kanata with Karabiner-DriverKit-VirtualHIDDevice on macOS

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
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode

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    _    _    _
  _      _    _    _    _    _    _    _    _    _    _    _    _
  _      _    _    _    _    _    _    _    _    _    _    _    _
  _      _    _    _              _              _    _    _    _    _
)
Enter fullscreen mode Exit fullscreen mode

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 + G to open the path navigator.

  • Paste /opt/homebrew/bin/kanata and 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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Verification and Troubleshooting

Check if the services are running successfully:

sudo launchctl list | grep -E "kanata|karabiner"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)