What is Karabiner-Elements?
Karabiner-Elements is a powerful keyboard customizer for macOS that intercepts keyboard events at the lowest possible level, transforms them according to user-defined rules, and injects the modified events back into the system via a virtual HID device. It enables complex remappings, application-specific shortcuts, and advanced keyboard workflows.
High-Level Architecture
┌─────────────────────────────────────────────────────────────────┐
│ User Applications │
│ (SettingsWindow, EventViewer, Menu, etc.) │
└────────────────────────────┬────────────────────────────────────┘
│ LaunchAgents
┌────────────────────────────▼────────────────────────────────────┐
│ karabiner_console_user_server (user privilege) │
│ • Monitors frontmost app, input source, system prefs │
│ • Executes shell_command, software_function │
│ • Watches configuration files (~/.config/karabiner/) │
└────────────────────────────┬────────────────────────────────────┘
│ Unix datagram socket
┌────────────────────────────▼────────────────────────────────────┐
│ Karabiner-Core-Service (root privilege / LaunchDaemon) │
│ • Event grabbing (IOKit device seizure) │
│ • Event manipulation pipeline │
│ • Virtual HID device injection │
└────────────────┬───────────────────┬────────────────────────────┘
│ │
┌────────────▼────┐ ┌─────────▼─────────┐
│ Physical Devices │ │ Virtual HID Device │
│ (IOKit seizure) │ │ (DriverKit) │
└─────────────────┘ └───────────────────┘Runtime Topology
Karabiner-Core-Service
The heart of Karabiner. Owns device access and event modification. Exposes Unix domain sockets and talks to the DriverKit virtual HID device.
- • IOKit device seizure (kIOHIDOptionsTypeSeizeDevice)
- • Event manipulation pipeline
- • Virtual HID report generation
- • Socket-based IPC with user processes
karabiner_session_monitor
Determines the current console user via CGSessionCopyCurrentDictionary and informs Core Service which UID should own its socket.
- • Console user detection
- • Socket ownership handoff
- • Fast user switching support
karabiner_console_user_server
Bridge to user context. Activates virtual HID driver, registers agents, watches configuration, and forwards environment changes to Core Service.
- • Virtual HID driver activation
- • Configuration file monitoring
- • Frontmost app / input source tracking
- • shell_command execution
Virtual HID Device
DriverKit-based virtual keyboard/mouse that produces HID reports macOS treats as real hardware input.
- • Virtual keyboard reports
- • Virtual pointing device reports
- • Transparent to macOS
- • Special keys work correctly
Event Capture Mechanisms
IOKit Device Seizure
Primary capture path. Opens HID devices with kIOHIDOptionsTypeSeizeDevice flag, giving Karabiner exclusive access to keyboard/mouse events.
// device_grabber.hpp
hid_manager_ = std::make_unique<
pqrs::osx::iokit_hid_manager>(
weak_dispatcher_,
run_loop_thread,
matching_dictionaries,
std::chrono::milliseconds(1000)
);
// Each device opened with:
IOHIDDeviceOpen(device,
kIOHIDOptionsTypeSeizeDevice);- Keyboards (generic_desktop::keyboard)
- Mice and Pointers
- Joysticks/Gamepads
- Consumer devices (headsets, buttons)
CGEventTap (Trackpad)
Apple trackpad drivers bypass IOKit, requiring a separate CGEventTap in listen-only mode to capture trackpad events.
// event_tap_monitor.hpp event_tap_ = CGEventTapCreate( kCGHIDEventTap, kCGTailAppendEventTap, kCGEventTapOptionListenOnly, mask, static_callback, this );
- Mouse down/up (all buttons)
- Mouse motion and dragging
- Scroll wheel events
- Modifier flags changed
Event Processing Pipeline
Events flow through a deterministic queue-based transformation chain. Each stage processes events in timestamp order, ensuring consistent behavior.
Event Types
Physical Events
- • momentary_switch_event (keyboard keys)
- • pointing_motion (mouse movement)
- • pointing_button (mouse buttons)
Virtual Events
- • shell_command
- • select_input_source
- • set_variable
- • software_function
- • sticky_modifier
Passive Events
- • device_grabbed / ungrabbed
- • caps_lock_state_changed
- • frontmost_application_changed
- • input_source_changed
Manipulator System
Basic Manipulator
The workhorse of Karabiner. Handles key-to-key remapping with advanced features like "to_if_alone" and "to_if_held_down".
{
"type": "basic",
"from": {
"key_code": "caps_lock",
"modifiers": { "optional": ["any"] }
},
"to": [
{ "key_code": "left_control" }
],
"to_if_alone": [
{ "key_code": "escape" }
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": ["^com\.apple\.Terminal$"]
}
]
}Advanced Features
Conditions System
Sophisticated filtering allows rules to activate only in specific contexts.
Filter by vendor/product ID, device type
"vendor_id": 1452, "product_id": 832App-specific rules using bundle identifiers
"bundle_identifiers": ["^com\.apple\.Terminal$"]Language/keyboard layout specific rules
"input_sources": [{ "language": "en" }]Custom variables set by set_variable events
"name": "vim_mode", "value": 1Profile-specific keyboard types
"keyboard_types": ["ansi", "iso"]Complex boolean expressions
"expression": "vim_mode == 1 && shift_held"Inter-Process Communication
Core ⇄ Console User Server
/Library/Application Support/org.pqrs/tmp/krbn_core_service/*.sock- • connect_console_user_server
- • frontmost_application_changed
- • input_source_changed
- • system_preferences_updated
- • temporarily_ignore_all_devices
Core ⇐ Session Monitor
/Library/Application Support/org.pqrs/tmp/rootonly/krbn_session/*.sock// session_monitor_receiver // Receives console UID // Core service uses to chown // main socket for correct user
Virtual HID Injection
Instead of using CGEventPost, Karabiner streams events to a DriverKit virtual HID device. macOS consumes these reports as if they came from real hardware, ensuring special keys (Mission Control, Launchpad, etc.) work correctly.
// post_event_to_virtual_devices.hpp 1. Front event from input queue 2. Convert to HID report: • momentary_switch_event → keyboard report (key codes + modifiers) • pointing_motion → pointing device report (x/y/buttons) 3. Send via virtual_hid_device_service_client_ 4. macOS processes as real hardware input
- • Special keys work (Mission Control, etc.)
- • Input Monitoring rules satisfied
- • No API limitations
- • Transparent to applications
- • Monitor driver activation
- • Handle version mismatches
- • Recovery from connection loss
- • Re-grab devices on reconnect
Configuration System
Configuration Structure
// ~/.config/karabiner/karabiner.json
{
"global": {
"check_for_updates_on_startup": true,
"show_in_menu_bar": true
},
"profiles": [{
"name": "Default",
"selected": true,
"simple_modifications": [...],
"complex_modifications": {
"rules": [...],
"parameters": {
"basic.to_if_alone_timeout_milliseconds": 800
}
},
"devices": [{
"identifiers": {
"vendor_id": 1234,
"product_id": 5678
},
"simple_modifications": [...]
}]
}]
}Hot Reload
Configuration changes are detected immediately and applied without restart.
// configuration_monitor.hpp 1. FSEvents watches karabiner.json 2. On modification: → Parse new configuration → Send to Core Service via socket 3. Core Service: → Invalidate manipulators → Rebuild pipeline from JSON → Continue processing
~/.config/karabiner/karabiner.json~/.local/share/karabiner/assets/complex_modifications/
Startup & Permissions Sequence
Example: caps_lock → control
Security Considerations
Root Privilege Justification
- • kIOHIDOptionsTypeSeizeDevice requires root
- • Socket ownership managed per-user
- • Session monitor prevents privilege escalation
Code Signing Verification
- • EventViewer connections verified via team ID
- • Prevents non-Karabiner apps from manipulating state
Input Monitoring Permission
- • Requires explicit user grant in macOS settings
- • Checked at startup and on reconnection
Virtual HID Driver
- • System extension signed and notarized
- • Loaded only after DriverKit activation
Source Code Structure
/src
├── apps/ # User-facing applications
│ ├── SettingsWindow/ # Configuration UI
│ ├── EventViewer/ # Event debugging tool
│ ├── Menu/ # Menu bar app
│ └── MultitouchExtension/ # Trackpad gesture handler
├── core/
│ ├── CoreService/ # Main daemon (root)
│ │ └── include/core_service/
│ │ ├── device_grabber.hpp # IOKit seizure
│ │ ├── receiver.hpp # IPC handler
│ │ └── device_grabber_details/ # Per-device manipulators
│ ├── console_user_server/ # User context bridge
│ └── session_monitor/ # Console user detector
└── share/ # Shared libraries
├── event_queue/ # Event pipeline queues
├── manipulator/ # Transformation system
│ ├── manipulators/
│ │ ├── basic/ # Simple key remapping
│ │ ├── mouse_basic/ # Mouse manipulation
│ │ └── post_event_to_virtual_devices/
│ └── conditions/ # Filtering predicates
└── monitor/ # File/app/session monitoring