9 static CFRunLoopRef mainloop = 0;
10 static IONotificationPortRef notify = 0;
29 static CFMachPortRef mouse_event_tap;
30 static char current_ckb_pid;
31 static char mouse_event_tap_pid;
33 static long hidgetlong(hid_dev_t handle, CFStringRef
key){
36 if((*handle)->getProperty(handle, key, &cf) != kIOReturnSuccess)
38 if(!cf || CFGetTypeID(cf) != CFNumberGetTypeID() || !CFNumberGetValue(cf, kCFNumberLongType, &raw))
43 static void hidgetstr(hid_dev_t handle, CFStringRef key,
char* output,
int out_len){
45 if((*handle)->getProperty(handle, key, &cf) != kIOReturnSuccess){
49 if(!cf || CFGetTypeID(cf) != CFStringGetTypeID() || !CFStringGetCString(cf, output, out_len, kCFStringEncodingASCII))
54 void u16dec(
ushort* in,
char* out,
size_t* srclen,
size_t* dstlen);
56 static void usbgetstr(usb_dev_t handle, uint8 string_index,
char* output,
int out_len){
58 char buffer[256] = { 0 };
59 IOUSBDevRequest rq = { 0x80, 0x06, 0x0300 | string_index, 0x0409,
sizeof(buffer) - 2, buffer, 0};
60 kern_return_t res = (*handle)->DeviceRequest(handle, &rq);
61 if(res != kIOReturnSuccess){
65 size_t inl =
sizeof(buffer) / 2, outl = out_len;
67 output[out_len - 1] = 0;
70 #define INCOMPLETE (usb_dev_t)-1l
71 #define HAS_ALL_HANDLES(kb) ((kb)->epcount > 0 && (kb)->epcount_hid + (kb)->epcount_usb >= (kb)->epcount)
74 #define wait_loop(error, operation) do { \
76 while(((error) = (operation)) != kIOReturnSuccess){ \
79 clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = 100000000}, NULL); \
82 #define IS_TEMP_FAILURE(res) ((res) == kIOUSBTransactionTimeout || (res) == kIOUSBTransactionReturned || (res) == kIOUSBPipeStalled)
83 #define IS_DISCONNECT_FAILURE(res) ((res) == kIOReturnBadArgument || (res) == kIOReturnNoDevice || (res) == kIOReturnNotOpen || (res) == kIOReturnNotAttached || (res) == kIOReturnExclusiveAccess)
86 static int get_pipe_index(usb_iface_t handle,
int desired_direction){
88 if((*handle)->GetNumEndpoints(handle, &count) != kIOReturnSuccess)
90 for(
int i = 0; i < count; i++){
91 uchar direction, number, transfertype, interval;
93 if((*handle)->GetPipeProperties(handle, i + 1, &direction, &number, &transfertype, &maxpacketsize, &interval) == kIOReturnSuccess){
94 if(direction == desired_direction)
103 kern_return_t res = kIOReturnSuccess;
109 IOUSBDevRequestTO rq = { 0x21, 0x09, 0x0200, ep - 1,
MSG_SIZE, (
void*)out_msg, 0, 5000, 5000 };
111 if(res == kIOReturnNotOpen){
113 usb_iface_t h_usb = kb->ifusb[ep - 1];
114 hid_dev_t h_hid = kb->ifhid[ep - 1];
116 res = (*h_usb)->ControlRequestTO(h_usb, 0, &rq);
118 res = (*h_hid)->setReport(h_hid, kIOHIDReportTypeFeature, 0, out_msg, MSG_SIZE, 5000, 0, 0, 0);
124 usb_iface_t h_usb = kb->ifusb[ep - 1];
125 hid_dev_t h_hid = kb->ifhid[ep - 1];
127 res = (*h_usb)->WritePipe(h_usb, get_pipe_index(h_usb, kUSBOut), (
void*)out_msg, MSG_SIZE);
129 res = (*h_hid)->setReport(h_hid, kIOHIDReportTypeOutput, 0, out_msg, MSG_SIZE, 5000, 0, 0, 0);
131 kb->lastresult = res;
132 if(res != kIOReturnSuccess){
133 ckb_err_fn(
"Got return value 0x%x\n", file, line, res);
134 if(IS_TEMP_FAILURE(res))
144 IOUSBDevRequestTO rq = { 0xa1, 0x01, 0x0200, ep - 1,
MSG_SIZE, in_msg, 0, 5000, 5000 };
145 kern_return_t res = (*kb->
handle)->DeviceRequestTO(kb->
handle, &rq);
146 CFIndex length = rq.wLenDone;
147 if(res == kIOReturnNotOpen){
149 usb_iface_t h_usb = kb->ifusb[ep - 1];
150 hid_dev_t h_hid = kb->ifhid[ep - 1];
152 res = (*h_usb)->ControlRequestTO(h_usb, 0, &rq);
154 res = (*h_hid)->getReport(h_hid, kIOHIDReportTypeFeature, 0, in_msg, &length, 5000, 0, 0, 0);
156 kb->lastresult = res;
157 if(res != kIOReturnSuccess){
158 ckb_err_fn(
"Got return value 0x%x\n", file, line, res);
159 if(IS_TEMP_FAILURE(res))
164 if(length != MSG_SIZE)
165 ckb_err_fn(
"Read %ld bytes (expected %d)\n", file, line, length, MSG_SIZE);
170 IOUSBDevRequestTO rq = { 0x40, bRequest, wValue, 0, 0, 0, 0, 5000, 5000 };
171 kern_return_t res = (*kb->
handle)->DeviceRequestTO(kb->
handle, &rq);
172 if(res != kIOReturnSuccess){
173 ckb_err_fn(
"Got return value 0x%x\n", file, line, res);
183 leds = (kb->
ileds << 8) | 0x0001;
189 IOUSBDevRequestTO rq = { 0x21, 0x09, 0x0200, 0x00, (kb->
fwversion >= 0x300 ? 2 : 1), ileds, 0, 500, 500 };
190 kern_return_t res = (*kb->
handle)->DeviceRequestTO(kb->
handle, &rq);
191 if(res == kIOReturnNotOpen){
193 hid_dev_t handle = kb->ifhid[0];
197 long ledpage = kHIDPage_LEDs;
198 const void* keys[] = { CFSTR(kIOHIDElementUsagePageKey) };
199 const void* values[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &ledpage) };
200 CFDictionaryRef matching = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
201 CFRelease(values[0]);
203 kern_return_t res = (*handle)->copyMatchingElements(handle, matching, &leds, 0);
205 if(res != kIOReturnSuccess)
208 CFIndex count = CFArrayGetCount(leds);
209 for(CFIndex i = 0; i < count; i++){
210 IOHIDElementRef led = (
void*)CFArrayGetValueAtIndex(leds, i);
211 uint32_t usage = IOHIDElementGetUsage(led);
212 IOHIDValueRef value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, led, 0, !!(ileds & (1 << (usage - 1))));
213 (*handle)->setValue(handle, led, value, 5000, 0, 0, 0);
219 if(res != kIOReturnSuccess)
220 ckb_err(
"Got return value 0x%x\n", res);
224 kern_return_t res = kb->lastresult;
225 if(IS_DISCONNECT_FAILURE(res))
229 clock_nanosleep(CLOCK_MONOTONIC, 0, &(
struct timespec) {.tv_nsec = 100000000}, NULL);
233 static void intreport(
void* context, IOReturn result,
void* sender, IOHIDReportType reporttype, uint32_t reportid, uint8_t* data, CFIndex length){
235 pthread_mutex_lock(
imutex(kb));
282 pthread_mutex_unlock(
imutex(kb));
293 static void pipecomplete(
void* refcon, IOReturn result,
void* arg0){
294 if(result != kIOReturnSuccess)
296 intptr_t length = (intptr_t)arg0;
297 urbctx* ctx = refcon;
300 uchar* buffer = ctx->buffer;
301 intreport(kb, result, 0, 0, 0, buffer, length);
303 usb_iface_t handle = kb->ifusb[ctx->index];
304 (*handle)->ReadPipeAsync(handle, ctx->pipe, buffer, ctx->maxsize, pipecomplete, ctx);
309 CGEventRef mouse_event_modifier_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event,
void* refcon) {
310 if (type == kCGEventTapDisabledByTimeout) {
311 CGEventTapEnable(mouse_event_tap,
true);
319 CGEventFlags existingFlags = CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState);
320 for(
int i = 0; i <
DEV_MAX; i++){
326 pthread_mutex_lock(
imutex(kb));
327 CGEventSetFlags(event, (kCGEventFlagMaskNonCoalesced | kb->modifiers | existingFlags));
328 pthread_mutex_unlock(
imutex(kb));
338 void update_ckb_pid() {
340 FILE *fp = fopen(
"/tmp/ckb",
"r");
342 fgets(str,
sizeof(str), fp);
345 current_ckb_pid = *str;
351 void register_mouse_event_tap(CFRunLoopTimerRef timer,
void* info) {
352 CFRunLoopRef run_loop = info;
355 if (current_ckb_pid) {
356 if (mouse_event_tap && current_ckb_pid != mouse_event_tap_pid) {
358 CFMachPortInvalidate(mouse_event_tap);
359 mouse_event_tap = NULL;
361 if (!mouse_event_tap) {
364 CGEventMask mask = CGEventMaskBit(kCGEventLeftMouseDown) |
365 CGEventMaskBit(kCGEventLeftMouseUp) |
366 CGEventMaskBit(kCGEventRightMouseDown) |
367 CGEventMaskBit(kCGEventRightMouseUp) |
368 CGEventMaskBit(kCGEventMouseMoved) |
369 CGEventMaskBit(kCGEventLeftMouseDragged) |
370 CGEventMaskBit(kCGEventRightMouseDragged) |
371 CGEventMaskBit(kCGEventScrollWheel) |
372 CGEventMaskBit(kCGEventTabletPointer) |
373 CGEventMaskBit(kCGEventTabletProximity) |
374 CGEventMaskBit(kCGEventOtherMouseDown) |
375 CGEventMaskBit(kCGEventOtherMouseUp) |
376 CGEventMaskBit(kCGEventOtherMouseDragged);
380 mouse_event_tap = CGEventTapCreate(kCGHIDEventTap,
381 kCGHeadInsertEventTap,
382 kCGEventTapOptionDefault,
384 mouse_event_modifier_callback,
387 if (mouse_event_tap) {
389 CFRunLoopSourceRef run_loop_source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mouse_event_tap, 0);
390 if (run_loop_source) {
391 ckb_info(
"Registering EventTap for modifier keys.\n");
392 CFRunLoopAddSource(run_loop, run_loop_source, kCFRunLoopCommonModes);
393 CGEventTapEnable(mouse_event_tap,
true);
394 CFRelease(run_loop_source);
396 memcpy(&mouse_event_tap_pid, ¤t_ckb_pid,
sizeof mouse_event_tap_pid);
405 extern void keyretrigger(CFRunLoopTimerRef timer,
void* info);
414 CFRunLoopRef runloop = kb->input_loop = CFRunLoopGetCurrent();
415 for(
int i = 0; i < count; i++){
416 CFTypeRef eventsource;
419 res = (*kb->ifusb[i])->CreateInterfaceAsyncEventSource(kb->ifusb[i], (CFRunLoopSourceRef*)&eventsource);
420 else if(kb->ifhid[i])
421 res = (*kb->ifhid[i])->getAsyncEventSource(kb->ifhid[i], &eventsource);
424 if(res != kIOReturnSuccess){
425 ckb_err(
"Failed to start input thread for %s%d: %x\n",
devpath, index, res);
428 if(CFGetTypeID(eventsource) == CFRunLoopSourceGetTypeID())
429 CFRunLoopAddSource(runloop, (CFRunLoopSourceRef)eventsource, kCFRunLoopDefaultMode);
430 else if(CFGetTypeID(eventsource) == CFRunLoopTimerGetTypeID())
431 CFRunLoopAddTimer(runloop, (CFRunLoopTimerRef)eventsource, kCFRunLoopDefaultMode);
437 memset(input, 0,
sizeof(input));
438 for(
int i = 0; i < count; i++){
440 usb_iface_t handle = kb->ifusb[i];
441 int pipe = get_pipe_index(handle, kUSBIn);
442 uchar direction, number, transfertype, interval;
444 (*handle)->GetPipeProperties(handle, pipe, &direction, &number, &transfertype, &maxpacketsize, &interval);
445 if(direction != kUSBIn && direction != kUSBAnyDirn)
447 uchar* buffer = malloc(maxpacketsize);
449 input[i].buffer = buffer;
451 input[i].pipe = pipe;
452 input[i].maxsize = maxpacketsize;
453 (*handle)->ReadPipeAsync(handle, 1, buffer, maxpacketsize, pipecomplete, input + i);
454 }
else if(kb->ifhid[i]){
455 hid_dev_t handle = kb->ifhid[i];
456 long maxsize = hidgetlong(handle, CFSTR(kIOHIDMaxInputReportSizeKey));
457 uchar* buffer = malloc(maxsize);
458 input[i].buffer = buffer;
459 (*handle)->setInputReportCallback(handle, buffer, maxsize, intreport, kb, 0);
464 CFRunLoopTimerContext krctx = { 0, kb, NULL, NULL, NULL };
465 CFRunLoopTimerRef krtimer = kb->krtimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
466 CFAbsoluteTimeGetCurrent() + 0.001, 0.001,
468 keyretrigger, &krctx);
469 CFRunLoopTimerSetTolerance(krtimer, 0.015);
477 pthread_mutex_lock(
imutex(kb));
479 pthread_mutex_unlock(
imutex(kb));
482 pthread_mutex_unlock(
imutex(kb));
487 for(
int i = 0; i < count; i++)
488 free(input[i].buffer);
501 int count = kb->epcount_hid;
502 for(
int i = 0; i < count; i++){
503 hid_dev_t iface = kb->ifhid[i];
505 (*iface)->close(iface, kIOHIDOptionsTypeNone);
506 (*iface)->Release(iface);
512 count = kb->epcount_usb;
513 for(
int i = 0; i < count; i++){
514 usb_iface_t iface = kb->ifusb[i];
516 (*iface)->USBInterfaceClose(iface);
517 (*iface)->Release(iface);
522 usb_dev_t iface = kb->
handle;
524 (*iface)->USBDeviceClose(iface);
525 (*iface)->Release(iface);
530 CFRunLoopStop(kb->input_loop);
535 static void remove_device(
void* context, io_service_t device, uint32_t message_type,
void* message_argument){
536 if(message_type != kIOMessageServiceIsTerminated)
541 pthread_mutex_lock(
dmutex(kb));
543 pthread_mutex_unlock(
dmutex(kb));
545 IOObjectRelease(device);
550 static int find_device(uint16_t idvendor, uint16_t idproduct, uint32_t location,
int handle_idx){
552 for(
int i = 1; i <
DEV_MAX; i++){
553 if(pthread_mutex_trylock(
devmutex + i))
557 for(
int iface = 0; iface <=
IFACE_MAX; iface++){
558 if(
keyboard[i].location_id[iface] == location){
560 keyboard[i].location_id[handle_idx] = location;
569 for(
int i = 1; i <
DEV_MAX; i++){
570 if(pthread_mutex_trylock(
devmutex + i))
575 keyboard[i].location_id[handle_idx] = location;
586 static int seize_wait(
long location){
589 char location_var[18], location_fixed[18];
590 snprintf(location_var,
sizeof(location_var),
"@%lx", location);
591 snprintf(location_fixed,
sizeof(location_fixed),
"@%08x", (
int)location);
593 static mach_port_t master = 0;
595 if(!master && (res = IOMasterPort(bootstrap_port, &master)) != kIOReturnSuccess){
597 ckb_warn(
"Unable to open master port: 0x%08x\n", res);
600 const int max_tries = 20;
601 for(
int try = 0;
try < max_tries;
try++){
602 clock_nanosleep(CLOCK_MONOTONIC, 0, &(
struct timespec) {.tv_nsec = 100000000}, NULL);
604 io_iterator_t child_iter;
605 if((res = IORegistryCreateIterator(master, kIOServicePlane, kIORegistryIterateRecursively, &child_iter)) != kIOReturnSuccess)
608 io_registry_entry_t child_service;
609 while((child_service = IOIteratorNext(child_iter)) != 0){
611 IORegistryEntryGetPath(child_service, kIOServicePlane, path);
612 IOObjectRelease(child_service);
614 if((strstr(path, location_var) || strstr(path, location_fixed)) && strstr(path,
"HID")){
615 IOObjectRelease(child_iter);
619 IOObjectRelease(child_iter);
625 static usbdevice* add_usb(usb_dev_t handle, io_object_t** rm_notify){
626 int iface_count = 0, iface_success = 0;
627 io_iterator_t iterator = 0;
628 io_service_t iface = 0;
630 UInt16 idvendor, idproduct;
632 (*handle)->GetDeviceVendor(handle, &idvendor);
633 (*handle)->GetDeviceProduct(handle, &idproduct);
634 (*handle)->GetLocationID(handle, &location);
636 int index = find_device(idvendor, idproduct, location, 0);
646 ckb_warn(
"Tried to set up handle for device ckb%d, but it was already set up. Skipping...\n", index);
653 UInt8 serial_idx, product_idx;
654 if((*handle)->USBGetSerialNumberStringIndex(handle, &serial_idx) == kIOReturnSuccess)
656 if((*handle)->USBGetProductStringIndex(handle, &product_idx) == kIOReturnSuccess)
662 if(seize_wait(location))
663 ckb_warn(
"seize_wait failed, connecting anyway...\n");
664 IOUSBFindInterfaceRequest interfaceRequest;
665 interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;
666 interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
667 interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
668 interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;
669 (*handle)->CreateInterfaceIterator(handle, &interfaceRequest, &iterator);
671 while((iface = IOIteratorNext(iterator)) != 0){
673 ckb_warn(
"Too many interfaces. Dropping the rest.\n");
674 IOObjectRelease(iface);
678 IOCFPlugInInterface** plugin = 0;
681 wait_loop(err, IOCreatePlugInInterfaceForService(iface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score));
682 if(err != kIOReturnSuccess){
683 ckb_err(
"Failed to create interface plugin: %x\n", err);
686 usb_iface_t if_handle;
687 wait_loop(err, (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID183), (LPVOID)&if_handle));
688 if(err != kIOReturnSuccess){
689 ckb_err(
"QueryInterface failed: %x\n", err);
693 IODestroyPlugInInterface(plugin);
696 (*if_handle)->GetLocationID(if_handle, kb->location_id + iface_count + 1);
698 err = (*if_handle)->USBInterfaceOpenSeize(if_handle);
699 if(err == kIOReturnSuccess){
700 kb->ifusb[iface_count] = if_handle;
703 IOServiceAddInterestNotification(notify, iface, kIOGeneralInterest, remove_device, kb, kb->rm_notify + 1 + iface_count);
705 kb->ifusb[iface_count] = 0;
706 (*if_handle)->Release(if_handle);
711 IOObjectRelease(iface);
713 if(iface_count == 0){
716 ckb_warn(
"Unable to count endpoints, assuming %d...\n", iface_count);
719 kb->epcount_usb = iface_success;
722 if(HAS_ALL_HANDLES(kb))
725 pthread_mutex_unlock(
devmutex + index);
726 *rm_notify = kb->rm_notify;
730 pthread_mutex_unlock(
devmutex + index);
734 static void iterate_devices_usb(
void* context, io_iterator_t iterator){
737 while((device = IOIteratorNext(iterator)) != 0){
738 IOCFPlugInInterface** plugin = 0;
741 wait_loop(err, IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score));
742 if(err != kIOReturnSuccess){
743 ckb_err(
"Failed to create device plugin: %x\n", err);
748 wait_loop(err, (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID182), (LPVOID*)&handle));
749 if(err != kIOReturnSuccess){
750 ckb_err(
"QueryInterface failed: %x\n", err);
754 IODestroyPlugInInterface(plugin);
756 err = (*handle)->USBDeviceOpenSeize(handle);
757 if(err == kIOReturnExclusiveAccess){
759 ckb_warn(
"Unable to seize USB handle, continuing anyway...\n");
760 }
else if(err != kIOReturnSuccess){
761 ckb_err(
"USBDeviceOpen failed: %x\n", err);
765 io_object_t* rm_notify = 0;
766 usbdevice* kb = add_usb(handle, &rm_notify);
769 IOServiceAddInterestNotification(notify, device, kIOGeneralInterest, remove_device, kb, rm_notify);
772 (*handle)->USBDeviceClose(handle);
774 IOObjectRelease(device);
779 static usbdevice* add_hid(hid_dev_t handle, io_object_t** rm_notify){
783 long input = hidgetlong(handle, CFSTR(kIOHIDMaxInputReportSizeKey));
784 long output = hidgetlong(handle, CFSTR(kIOHIDMaxOutputReportSizeKey));
785 long feature = hidgetlong(handle, CFSTR(kIOHIDMaxFeatureReportSizeKey));
786 long fwversion = hidgetlong(handle, CFSTR(kIOHIDVersionNumberKey));
793 else if(feature == 0 &&
795 input == 15) && output == 0) ||
796 (input == 64 && output == 64) ||
797 (input <= 1 && output == 64)))
800 else if((output <= 1 && feature <= 1 &&
803 (fwversion >= 0x300 &&
809 else if(output <= 1 && feature <= 1 &&
810 (input == 21 || input == 10 ||
815 ckb_warn(
"Got unknown handle (I: %d, O: %d, F: %d)\n", (
int)input, (
int)output, (
int)feature);
820 uint16_t idvendor = hidgetlong(handle, CFSTR(kIOHIDVendorIDKey)), idproduct = hidgetlong(handle, CFSTR(kIOHIDProductIDKey));
822 uint32_t location = hidgetlong(handle, CFSTR(kIOHIDLocationIDKey));
823 int index = find_device(idvendor, idproduct, location, handle_idx + 1);
839 if(kb->ifhid[handle_idx]){
841 ckb_warn(
"Tried to set up ifhid[%d] for device ckb%d, but it was already set up. Skipping...\n", handle_idx, index);
844 kb->ifhid[handle_idx] = handle;
846 if(HAS_ALL_HANDLES(kb))
851 pthread_mutex_unlock(
devmutex + index);
852 *rm_notify = kb->rm_notify +
IFACE_MAX + 1 + handle_idx;
856 pthread_mutex_unlock(
devmutex + index);
860 static void iterate_devices_hid(
void* context, io_iterator_t iterator){
863 while((device = IOIteratorNext(iterator)) != 0){
865 IOCFPlugInInterface** plugin = 0;
868 wait_loop(err, IOCreatePlugInInterfaceForService(device, kIOHIDDeviceTypeID, kIOCFPlugInInterfaceID, &plugin, &score));
869 if(err != kIOReturnSuccess){
870 ckb_err(
"Failed to create device plugin: %x\n", err);
875 wait_loop(err, (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOHIDDeviceDeviceInterfaceID), (LPVOID*)&handle));
876 if(err != kIOReturnSuccess){
877 ckb_err(
"QueryInterface failed: %x\n", err);
881 IODestroyPlugInInterface(plugin);
883 if(seize_wait(hidgetlong(handle, CFSTR(kIOHIDLocationIDKey))))
884 ckb_warn(
"seize_wait failed, connecting anyway...\n");
885 wait_loop(err, (*handle)->open(handle, kIOHIDOptionsTypeSeizeDevice));
886 if(err != kIOReturnSuccess){
887 ckb_warn(
"Failed to open device: %x\n", err);
891 io_object_t* rm_notify = 0;
892 usbdevice* kb = add_hid(handle, &rm_notify);
895 IOServiceAddInterestNotification(notify, device, kIOGeneralInterest, remove_device, kb, rm_notify);
898 (*handle)->close(handle, kIOHIDOptionsTypeSeizeDevice);
900 IOObjectRelease(device);
909 P_K63_NRGB,
P_K65,
P_K65_NRGB,
P_K65_LUX,
P_K65_RFIRE,
P_K68,
P_K70,
P_K70_NRGB,
P_K70_LUX,
P_K70_LUX_NRGB,
P_K70_RFIRE,
P_K70_RFIRE_NRGB,
P_K95,
P_K95_NRGB,
P_K95_PLATINUM,
P_STRAFE,
P_STRAFE_NRGB,
P_STRAFE_NRGB_2,
915 notify = IONotificationPortCreate(kIOMasterPortDefault);
916 mainloop = CFRunLoopGetCurrent();
917 CFRunLoopAddSource(mainloop, IONotificationPortGetRunLoopSource(notify), kCFRunLoopDefaultMode);
927 CFMutableDictionaryRef match = IOServiceMatching(kIOUSBDeviceClassName);
928 CFNumberRef cfvendor = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor);
929 CFDictionarySetValue(match, CFSTR(kUSBVendorName), cfvendor);
931 CFMutableArrayRef cfproducts = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
932 for(uint i = 0; i <
sizeof(products) /
sizeof(
int); i++){
933 int product = products[i];
934 CFNumberRef cfproduct = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &product);
935 CFArrayAppendValue(cfproducts, cfproduct);
936 CFRelease(cfproduct);
938 CFDictionarySetValue(match, CFSTR(kUSBProductIdsArrayName), cfproducts);
939 CFRelease(cfproducts);
941 io_iterator_t iterator_usb = 0;
942 IOReturn res = IOServiceAddMatchingNotification(notify, kIOMatchedNotification, match, iterate_devices_usb, 0, &iterator_usb);
943 if(res != kIOReturnSuccess){
944 ckb_fatal(
"Failed to list USB devices: %x\n", res);
949 iterate_devices_usb(0, iterator_usb);
953 match = IOServiceMatching(kIOHIDDeviceKey);
954 cfvendor = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor);
955 CFDictionarySetValue(match, CFSTR(kIOHIDVendorIDKey), cfvendor);
957 cfproducts = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
958 for(uint i = 0; i <
sizeof(products) /
sizeof(
int); i++){
959 int product = products[i];
960 CFNumberRef cfproduct = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &product);
961 CFArrayAppendValue(cfproducts, cfproduct);
962 CFRelease(cfproduct);
964 CFDictionarySetValue(match, CFSTR(kIOHIDProductIDArrayKey), cfproducts);
965 CFRelease(cfproducts);
967 io_iterator_t iterator_hid = 0;
968 res = IOServiceAddMatchingNotification(notify, kIOMatchedNotification, match, iterate_devices_hid, 0, &iterator_hid);
969 if(res != kIOReturnSuccess){
970 ckb_fatal(
"Failed to list HID devices: %x\n", res);
975 iterate_devices_hid(0, iterator_hid);
978 CFRunLoopTimerContext rmectx = { 0, mainloop, NULL, NULL, NULL };
979 CFRunLoopTimerRef rmetimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
980 CFAbsoluteTimeGetCurrent() + 5, 5,
982 register_mouse_event_tap, &rmectx);
983 CFRunLoopAddTimer(mainloop, (CFRunLoopTimerRef)rmetimer, kCFRunLoopCommonModes);
991 CFRunLoopStop(mainloop);
void setupusb(usbdevice *kb)
int usbmain()
Start the USB main loop. Returns program exit code when finished.
#define ckb_err(fmt, args...)
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
int os_resetusb(usbdevice *kb, const char *file, int line)
os_resetusb is the os specific implementation for resetting usb
void * os_inputmain(void *context)
os_inputmain is run in a separate thread and will be detached from the main thread, so it needs to clean up its own resources.
void os_closeusb(usbdevice *kb)
os_closeusb unclaim it, destroy the udev device and clear data structures at kb
pthread_mutex_t devmutex[9]
Mutex for handling the usbdevice structure.
int os_usbrecv(usbdevice *kb, uchar *in_msg, const char *file, int line)
os_usbrecv receives a max MSGSIZE long buffer from usb device
int os_setupusb(usbdevice *kb)
os_setupusb OS-specific setup for a specific usb device.
#define ckb_fatal(fmt, args...)
#define IS_MOUSE(vendor, product)
Mouse vs keyboard test.
#define ckb_warn(fmt, args...)
void corsair_mousecopy(unsigned char *kbinput, int endpoint, const unsigned char *urbinput)
void hid_mouse_translate(unsigned char *kbinput, short *xaxis, short *yaxis, int endpoint, int length, const unsigned char *urbinput, ushort fwversion)
#define ckb_info(fmt, args...)
#define INDEX_OF(entry, array)
int closeusb(usbdevice *kb)
#define IS_RGB_DEV(kb)
For calling with a usbdevice*, vendor and product are extracted and IS_RGB() is returned.
void hid_kb_translate(unsigned char *kbinput, int endpoint, int length, const unsigned char *urbinput)
#define IS_MOUSE_DEV(kb)
For calling with a usbdevice*, vendor and product are extracted and IS_MOUSE() is returned...
#define HAS_FEATURES(kb, feat)
Definitions for using USB interface.
void os_sendindicators(usbdevice *kb)
os_sendindicators update the indicators for the special keys (Numlock, Capslock and what else...
void corsair_kbcopy(unsigned char *kbinput, int endpoint, const unsigned char *urbinput)
#define V_CORSAIR
For the following Defines please see "Detailed Description".
int _nk95cmd(usbdevice *kb, uchar bRequest, ushort wValue, const char *file, int line)
_nk95cmd If we control a non RGB keyboard, set the keyboard via ioctl with usbdevfs_ctrltransfer ...
uchar keys[((((152+22+12)+25)+7)/8)]
void usbkill()
Stop the USB system.
int os_usbsend(usbdevice *kb, const uchar *out_msg, int is_recv, const char *file, int line)
os_usbsend sends a data packet (MSG_SIZE = 64) Bytes long
void u16dec(ushort *in, char *out, size_t *srclen, size_t *dstlen)
#define ckb_err_fn(fmt, file, line, args...)
#define IS_V2_OVERRIDE(kb)
Used when a device has a firmware with a low version number that uses the new protocol.