// Keypress static void postevent_kp(io_connect_t event, int kbflags, int scancode, int down, int is_flags, int is_repeat){ NXEventData kp; memset(&kp, 0, sizeof(kp)); UInt32 type; IOOptionBits flags = kbflags; IOOptionBits options = 0; if(IS_MEDIA(scancode)){ kp.compound.subType = (scancode != KEY_POWER ? NX_SUBTYPE_AUX_CONTROL_BUTTONS : NX_SUBTYPE_POWER_KEY); kp.compound.misc.L[0] = (scancode - KEY_MEDIA) << 16 | (down ? 0x0a00 : 0x0b00) | is_repeat; type = NX_SYSDEFINED; } else { if(is_flags){ // Modifier (shift, ctrl, etc) type = NX_FLAGSCHANGED; options = kIOHIDSetGlobalEventFlags; } else // Standard key type = down ? NX_KEYDOWN : NX_KEYUP; kp.key.repeat = is_repeat; kp.key.keyCode = scancode; kp.key.origCharSet = kp.key.charSet = NX_ASCIISET; if(IS_NUMPAD(scancode)) flags |= NX_NUMERICPADMASK; else if(scancode == kVK_Help) flags |= NX_HELPMASK; } postevent(event, type, &kp, flags, options); }
// Send keyup events for every scancode in the keymap void clearkeys(usbdevice* kb){ for(int key = 0; key < N_KEYS_INPUT; key++){ int scan = keymap[key].scan; if((scan & SCAN_SILENT) || scan == BTN_WHEELUP || scan == BTN_WHEELDOWN || IS_MEDIA(scan)) continue; postevent_kp(kb->event, 0, scan, 0, 0, 0); } }
void clearkeys(usbdevice* kb){ // Send keyup events for every scancode in the keymap for(int key = 0; key < N_KEYS; key++){ int scan = keymap_system[key].scan; if(scan < 0 || IS_MEDIA(scan)) continue; postevent(kb->event, 0, scan, 0, 0, 0); } }
// Event helper void postevent(io_connect_t event, int kbflags, int scancode, int down, int is_flags, int is_repeat){ NXEventData kp; memset(&kp, 0, sizeof(kp)); UInt32 type; IOOptionBits flags = kbflags; IOOptionBits options = 0; if(IS_MEDIA(scancode)){ kp.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS; kp.compound.misc.L[0] = (scancode - KEY_MEDIA) << 16 | (down ? 0x0a00 : 0x0b00) | is_repeat; type = NX_SYSDEFINED; } else { if(is_flags){ // Modifier (shift, ctrl, etc) type = NX_FLAGSCHANGED; options = kIOHIDSetGlobalEventFlags; } else // Standard key type = down ? NX_KEYDOWN : NX_KEYUP; kp.key.repeat = is_repeat; kp.key.keyCode = scancode; kp.key.origCharSet = kp.key.charSet = NX_ASCIISET; if(IS_NUMPAD(scancode)) flags |= NX_NUMERICPADMASK; else if(scancode == kVK_Help) flags |= NX_HELPMASK; } // HACK: IOHIDPostEvent will fail with kIOReturnNotPrivileged if the event doesn't originate from the UID that owns /dev/console // You'd think being root would be good enough. You'd be wrong. ckb-daemon needs to run as root for other reasons though // (namely, being able to seize the physical IOHIDDevices) so what we do instead is change our EUID to the appropriate owner, // post the event, and then change it right back. // Yeah... uid_t uid = 0; gid_t gid = 0; struct stat file; if(!stat("/dev/console", &file)){ uid = file.st_uid; gid = file.st_gid; if(uid != 0) seteuid(uid); if(gid != 0) setegid(gid); } kern_return_t res = IOHIDPostEvent(event, type, *(IOGPoint[]){{0, 0}}, &kp, kNXEventDataVersion, flags | NX_NONCOALSESCEDMASK, options); if(res != KERN_SUCCESS) printf("Post event failed: %x\n", res); if(uid != 0) seteuid(0); if(gid != 0) setegid(0); }
static void postevent_kp(io_connect_t event, int kbflags, int scancode, int down, int is_flags, int is_repeat){ NXEventData kp; memset(&kp, 0, sizeof(kp)); UInt32 type; IOOptionBits flags = kbflags; IOOptionBits options = 0; if(scancode == KEY_CAPSLOCK){ // Caps lock emits NX_FLAGSCHANGED when pressed, but also NX_SYSDEFINED on both press and release kp.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS; kp.compound.misc.L[0] = aux_key_data(NX_KEYTYPE_CAPS_LOCK, down, is_repeat); postevent(event, NX_SYSDEFINED, &kp, flags, options, 1); if(!down) return; memset(&kp, 0, sizeof(kp)); } if(IS_MEDIA(scancode)){ kp.compound.subType = (scancode != KEY_POWER ? NX_SUBTYPE_AUX_CONTROL_BUTTONS : NX_SUBTYPE_POWER_KEY); kp.compound.misc.L[0] = aux_key_data(scancode - KEY_MEDIA, down, is_repeat); type = NX_SYSDEFINED; } else { if(is_flags){ // Modifier (shift, ctrl, etc) type = NX_FLAGSCHANGED; options = kIOHIDSetGlobalEventFlags; } else // Standard key type = down ? NX_KEYDOWN : NX_KEYUP; kp.key.repeat = is_repeat; kp.key.keyCode = scancode; kp.key.origCharSet = kp.key.charSet = NX_ASCIISET; if(IS_NUMPAD(scancode)) flags |= NX_NUMERICPADMASK; else if(scancode == kVK_Help) flags |= NX_HELPMASK; } postevent(event, type, &kp, flags, options, !down || is_repeat); // Don't print errors on key up or key repeat ^ }