karabiner_grabber
- Run with root privilege.
- Seize the input devices and modify events then post events to
karabiner_console_user_server
.
karabiner_console_user_server
- Run with console user privilege.
- Receive input events from
karabiner_grabber
and post them to IOHIDSystem.
karabiner_grabber
and karabiner_console_user_server
are connected by unix domain socket.
If a cracked karabiner_console_user_server
is connected, the input events will be leaked.
To avoid this problem, karabiner_grabber
checks the codesign certificate of karabiner_console_user_server
.
If the both process are not signed with the same certificate, karabiner_grabber
does not send events to karabiner_console_user_server
.
- Run
karabiner_grabber
. - Open grabber server unix domain socket.
- Polling session state in grabber.
- When session state is changed, grabber change the unix domain socket owner to console user.
- Run
karabiner_console_user_server
. - Try to open console_user_server unix domain socket.
- Send
KRBN_OPERATION_TYPE_CONNECT
to grabber from console_user_server. - grabber connects to console_user_server.
- grabber seizes input devices.
We have to modify events in karabiner_grabber
because the caps lock handling requires root privilege.
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
.
It requires posting mac events.
IOHIDPostEvent
will be failed if the process is not running in the current session user.
(The root user is also forbidden.)
karabiner_console_user_server uses this method.
It requires posting HID events.
The IOHIKeyboard processes the reports by passing reports to handleReport
.
However, this method is not enough polite.
Calling the handleReport
method directly causes a problem that OS X ignores EnableSecureEventInput
.
So we have to reject this approach for security reason.
It requires posting HID events.
We have to make a complete set of virtual devices to post the IOHIDValue.
It requires posting mac events.
We have to make a complete set of virtual devices to post the IOHIDValue.
It requires posting mac 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 unknown;
uint8_t modifiers;
uint8_t reserved;
uint8_t keys[6];
uint8_t extra_modifiers; // fn