karabiner_grabber
- Run with root privilege.
- Seize the input devices and modify events then post events using
Karabiner-VirtualHIDDevice
.
karabiner_console_user_server
- Run with console user privilege.
- Monitor system preferences values (key repeat, etc) and notify them to
karabiner_grabber
. - Monitor a karabiner configuration file and notify changes to
karabiner_grabber
. karabiner_grabber
seizes devices only whenkarabiner_console_user_server
is running.
karabiner_grabber
- Run
karabiner_grabber
. karabiner_grabber
opens grabber server unix domain socket.karabiner_grabber
start polling the session state.- When session state is changed,
karabiner_grabber
changes the unix domain socket owner to console user.
- Run
karabiner_console_user_server
. - Try to open console_user_server unix domain socket.
- grabber seizes input devices.
IOHIDSystem requires the process is running with the console user privilege.
Thus, karabiner_grabber
cannot send events to IOHIDSystem directly.
IOKit allows you to read raw HID input events from kernel.
The highest layer is IOHIDQueue which provides us the HID values.
karabiner_grabber
uses this method.
CGEventTapCreate
is a limited approach.
It does not work with Secure Keyboard Entry even if we use kCGHIDEventTap
and root privillege.
Thus, it does not work in Terminal.
You can confirm this behavior in appendix/eventtap
.
However, we should modify mouse event's modifier flags manually.
Thus, karabiner_grabber
uses this method to modify mouse events.
It requires posting HID usage page and usage.
karabiner_grabber
uses this method by using Karabiner-VirtualHIDDevice
.
It requires posting HID events.
The IOHIKeyboard processes the reports by passing reports to handleReport
.
It requires posting coregraphics events.
IOHIDPostEvent
will be failed if the process is not running in the current session user.
(The root user is also forbidden.)
It requires posting coregraphics events.
CGEventPost
does not support some key events in OS X 10.12.
- Mission Control key
- Launchpad key
- Option-Command-Escape
Thus, karabiner_grabber
does not use CGEventPost
.
It requires posting HID events.
We have to make a complete set of virtual devices to post the IOHIDValue.
The modifier flag events are handled in the following sequence in macOS 10.12.
- Receive HID reports from device.
- Treat reports in the keyboard device driver.
- Treat flags in accessibility functions. (eg. sticky keys, zoom)
- Treat flags in mouse events.
- Treat flags in IOHIDSystem.
- Treat flags in Coregraphics.
Thus, IOHIDPostEvent
will be ignored in accessibility functions and mouse events.
We can get hid reports from devices via IOHIDDeviceRegisterInputReportCallback
.
The hid report contains a list of pressed keys, so it seems suitable information to observe.
But karabiner_grabber
does not use it in order to reduce the device dependancy.
Apple keyboards does not use generic HID keyboard report descriptor.
Thus, we have to handle them by separate way.
uint8_t modifiers;
uint8_t reserved;
uint8_t keys[6];
0x1 << 0 : left control
0x1 << 1 : left shift
0x1 << 2 : left option
0x1 << 3 : left command
0x1 << 4 : right control
0x1 << 5 : right shift
0x1 << 6 : right option
0x1 << 7 : right command
uint8_t record_id;
uint8_t modifiers;
uint8_t reserved;
uint8_t keys[6];
uint8_t extra_modifiers; // fn