8 #define IS_NUMPAD(scancode) ((scancode) >= kVK_ANSI_KeypadDecimal && (scancode) <= kVK_ANSI_Keypad9 && (scancode) != kVK_ANSI_KeypadClear && (scancode) != kVK_ANSI_KeypadEnter)
10 pthread_mutex_t _euid_guard = PTHREAD_MUTEX_INITIALIZER;
13 static void postevent(io_connect_t event, UInt32 type, NXEventData* ev, IOOptionBits flags, IOOptionBits options,
int silence_errors){
22 if(!stat(
"/dev/console", &file)){
27 IOGPoint location = {0, 0};
28 if((options & kIOHIDSetRelativeCursorPosition) && type != NX_MOUSEMOVED){
31 CGEventRef cge = CGEventCreate(nil);
32 CGPoint loc = CGEventGetLocation(cge);
34 location.x = floor(loc.x + ev->mouseMove.dx);
35 location.y = floor(loc.y + ev->mouseMove.dy);
36 options = (options & ~kIOHIDSetRelativeCursorPosition) | kIOHIDSetCursorPosition;
45 kern_return_t res = IOHIDPostEvent(event, type, location, ev, kNXEventDataVersion, flags | NX_NONCOALSESCEDMASK, options);
46 if(res != kIOReturnSuccess && !silence_errors)
47 ckb_warn(
"Post event failed: %x\n", res);
57 #define aux_key_data(scancode, down, is_repeat) ((scancode) << 16 | ((down) ? 0x0a00 : 0x0b00) | !!(is_repeat))
58 static void postevent_kp(io_connect_t event,
int kbflags,
int scancode,
int down,
int is_flags,
int is_repeat){
60 memset(&kp, 0,
sizeof(kp));
62 IOOptionBits flags = kbflags;
63 IOOptionBits options = 0;
64 if(scancode == KEY_CAPSLOCK){
66 kp.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
67 kp.compound.misc.L[0] = aux_key_data(NX_KEYTYPE_CAPS_LOCK, down, is_repeat);
68 postevent(event, NX_SYSDEFINED, &kp, flags, options, 1);
71 memset(&kp, 0,
sizeof(kp));
73 if(IS_MEDIA(scancode)){
74 kp.compound.subType = (scancode != KEY_POWER ? NX_SUBTYPE_AUX_CONTROL_BUTTONS : NX_SUBTYPE_POWER_KEY);
75 kp.compound.misc.L[0] = aux_key_data(scancode - KEY_MEDIA, down, is_repeat);
80 type = NX_FLAGSCHANGED;
81 options = kIOHIDSetGlobalEventFlags;
84 type = down ? NX_KEYDOWN : NX_KEYUP;
85 kp.key.repeat = is_repeat;
86 kp.key.keyCode = scancode;
87 kp.key.origCharSet = kp.key.charSet = NX_ASCIISET;
88 if(IS_NUMPAD(scancode))
89 flags |= NX_NUMERICPADMASK;
90 else if(scancode == kVK_Help)
93 postevent(event, type, &kp, flags, options, !down || is_repeat);
98 static void postevent_mb(io_connect_t event,
int button,
int down){
100 memset(&mb, 0,
sizeof(mb));
101 mb.compound.subType = NX_SUBTYPE_AUX_MOUSE_BUTTONS;
102 mb.compound.misc.L[0] = (1 << button);
103 mb.compound.misc.L[1] = down ? (1 << button) : 0;
104 postevent(event, NX_SYSDEFINED, &mb, 0, 0, !down);
106 memset(&mb, 0,
sizeof(mb));
108 mb.mouse.buttonNumber = button;
111 type = down ? NX_LMOUSEDOWN : NX_LMOUSEUP;
114 type = down ? NX_RMOUSEDOWN : NX_RMOUSEUP;
117 type = down ? NX_OMOUSEDOWN : NX_OMOUSEUP;
120 mb.mouse.pressure = 255;
121 postevent(event, type, &mb, 0, 0, 1);
125 extern void wheel_accel(io_connect_t event,
int* deltaAxis1, SInt32* fixedDeltaAxis1, SInt32* pointDeltaAxis1);
126 extern void mouse_accel(io_connect_t event,
int*
x,
int*
y);
129 static void postevent_wheel(io_connect_t event,
int scroll_rate,
int value){
131 memset(&mm, 0,
sizeof(mm));
133 wheel_accel(event, &value, &mm.scrollWheel.fixedDeltaAxis1, &mm.scrollWheel.pointDeltaAxis1);
134 mm.scrollWheel.deltaAxis1 = value;
137 mm.scrollWheel.deltaAxis1 = value * scroll_rate;
139 postevent(event, NX_SCROLLWHEELMOVED, &mm, 0, 0, 0);
143 static void postevent_mm(io_connect_t event,
int x,
int y,
int use_accel,
uchar buttons){
145 memset(&mm, 0,
sizeof(mm));
146 UInt32 type = NX_MOUSEMOVED;
148 mouse_accel(event, &x, &y);
154 type = NX_LMOUSEDRAGGED;
156 type = NX_RMOUSEDRAGGED;
158 type = NX_OMOUSEDRAGGED;
161 while(!(buttons & 1)){
165 mm.mouse.pressure = 255;
166 mm.mouse.buttonNumber = button;
168 postevent(event, type, &mm, 0, kIOHIDSetRelativeCursorPosition, 1);
172 long repeattime(io_connect_t event,
int first){
174 IOByteCount actualSize = 0;
175 if(IOHIDGetParameter(event, first ? CFSTR(kIOHIDInitialKeyRepeatKey) : CFSTR(kIOHIDKeyRepeatKey),
sizeof(
long), &delay, &actualSize) != KERN_SUCCESS || actualSize == 0)
186 postevent_kp(kb->event, 0, scan, 0, 0, 0);
191 static int open_iohid(io_connect_t* connection){
193 io_service_t service;
195 static mach_port_t master = 0;
197 if(!master && (res = IOMasterPort(bootstrap_port, &master)) != kIOReturnSuccess){
199 ckb_err(
"Unable to open master port: 0x%08x\n", res);
203 if((res = IOServiceGetMatchingServices(master, IOServiceMatching(kIOHIDSystemClass), &iter)) != kIOReturnSuccess)
205 service = IOIteratorNext(iter);
207 res = kIOReturnNotOpen;
208 goto failure_release_iter;
210 if((res = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, connection)) != kIOReturnSuccess){
212 goto failure_release_iter;
215 IOObjectRelease(service);
216 failure_release_iter:
217 IOObjectRelease(iter);
225 while((res = open_iohid(&kb->event)) != kIOReturnSuccess){
226 if(res != kIOReturnNotOpen){
228 ckb_err(
"Unable to open HID system: 0x%08x\n", res);
232 clock_nanosleep(CLOCK_MONOTONIC, 0, &(
struct timespec) {.tv_nsec = 10000000}, NULL);
242 IOServiceClose(kb->event);
250 CFRunLoopRemoveTimer(kb->input_loop, kb->krtimer, kCFRunLoopCommonModes);
252 CFRunLoopAddTimer(kb->input_loop, kb->krtimer, kCFRunLoopCommonModes);
256 static void _keyretrigger(
usbdevice* kb){
257 int scancode = kb->lastkeypress;
258 postevent_kp(kb->event, kb->modifiers, scancode, 1, 0, 1);
260 long repeat = repeattime(kb->event, 0);
267 void keyretrigger(CFRunLoopTimerRef timer,
void* info){
270 struct timespec time;
271 clock_gettime(CLOCK_MONOTONIC, &time);
280 static void* indicator_update(
void* context){
282 pthread_mutex_lock(
dmutex(kb));
284 pthread_mutex_lock(
imutex(kb));
285 IOOptionBits modifiers = kb->modifiers;
288 pthread_mutex_unlock(
imutex(kb));
290 uchar ileds = 1 | !!(modifiers & NX_ALPHASHIFTMASK) << 1;
292 kb->
vtable->updateindicators(kb, 0);
294 pthread_mutex_unlock(
dmutex(kb));
300 keyretrigger(NULL, kb);
305 postevent_wheel(kb->event, kb->scroll_rate, 1);
309 postevent_wheel(kb->event, kb->scroll_rate, -1);
312 int button = scancode & ~SCAN_MOUSE;
315 if(IOHIDGetMouseButtonMode(kb->event, &mode) == kIOReturnSuccess){
316 if(mode == kIOHIDButtonMode_ReverseLeftRightClicks && button == 0)
318 else if(mode != kIOHIDButtonMode_EnableRightClick && button == 1)
321 postevent_mb(kb->event, button, down);
323 kb->mousestate |= (1 << button);
325 kb->mousestate &= ~(1 << button);
333 else if(scancode == KEY_BACKSLASH)
337 scancode = KEY_BACKSLASH;
340 if(scancode == KEY_GRAVE)
341 scancode = KEY_102ND;
342 else if(scancode == KEY_102ND)
343 scancode = KEY_GRAVE;
347 IOOptionBits mod = 0;
348 if(scancode == KEY_CAPSLOCK){
350 kb->modifiers ^= NX_ALPHASHIFTMASK;
353 if(!kb->indicthread){
357 if(!pthread_create(&kb->indicthread, 0, indicator_update, kb))
358 pthread_detach(kb->indicthread);
361 else if(scancode == KEY_LEFTSHIFT) mod = NX_DEVICELSHIFTKEYMASK;
362 else if(scancode == KEY_RIGHTSHIFT) mod = NX_DEVICERSHIFTKEYMASK;
363 else if(scancode == KEY_LEFTCTRL) mod = NX_DEVICELCTLKEYMASK;
364 else if(scancode == KEY_RIGHTCTRL) mod = NX_DEVICERCTLKEYMASK;
365 else if(scancode == KEY_LEFTMETA) mod = NX_DEVICELCMDKEYMASK;
366 else if(scancode == KEY_RIGHTMETA) mod = NX_DEVICERCMDKEYMASK;
367 else if(scancode == KEY_LEFTALT) mod = NX_DEVICELALTKEYMASK;
368 else if(scancode == KEY_RIGHTALT) mod = NX_DEVICERALTKEYMASK;
369 else if(scancode == KEY_FN) mod = NX_SECONDARYFNMASK;
373 mod |= kb->modifiers;
375 mod = kb->modifiers & ~mod;
376 if((mod & NX_DEVICELSHIFTKEYMASK) || (mod & NX_DEVICERSHIFTKEYMASK)) mod |= NX_SHIFTMASK;
else mod &= ~NX_SHIFTMASK;
377 if((mod & NX_DEVICELCTLKEYMASK) || (mod & NX_DEVICERCTLKEYMASK)) mod |= NX_CONTROLMASK;
else mod &= ~NX_CONTROLMASK;
378 if((mod & NX_DEVICELCMDKEYMASK) || (mod & NX_DEVICERCMDKEYMASK)) mod |= NX_COMMANDMASK;
else mod &= ~NX_COMMANDMASK;
379 if((mod & NX_DEVICELALTKEYMASK) || (mod & NX_DEVICERALTKEYMASK)) mod |= NX_ALTERNATEMASK;
else mod &= ~NX_ALTERNATEMASK;
386 long repeat = repeattime(kb->event, 1);
388 kb->lastkeypress = scancode;
389 clock_gettime(CLOCK_MONOTONIC, &kb->keyrepeat);
397 postevent_kp(kb->event, kb->modifiers, scancode, down, isMod, 0);
const key keymap[(((152+22+12)+25)+12)]
#define SCROLL_ACCELERATED
#define ckb_err(fmt, args...)
#define KEY_BACKSLASH_ISO
long gid
Group ID for the control nodes. -1 to give read/write access to everybody.
#define ckb_warn(fmt, args...)
#define timespec_ge(left, right)
const union devcmd * vtable
#define HAS_ANY_FEATURE(kb, feat)
#define HAS_FEATURES(kb, feat)
void timespec_add(struct timespec *timespec, long nanoseconds)