9 static CFRunLoopRef mainloop = 0;
10 static IONotificationPortRef notify = 0;
29 static CFMachPortRef mouse_event_tap;
31 static long hidgetlong(hid_dev_t handle, CFStringRef
key){
34 if((*handle)->getProperty(handle, key, &cf) != kIOReturnSuccess)
36 if(!cf || CFGetTypeID(cf) != CFNumberGetTypeID() || !CFNumberGetValue(cf, kCFNumberLongType, &raw))
41 static void hidgetstr(hid_dev_t handle, CFStringRef key,
char* output,
int out_len){
43 if((*handle)->getProperty(handle, key, &cf) != kIOReturnSuccess){
47 if(!cf || CFGetTypeID(cf) != CFStringGetTypeID() || !CFStringGetCString(cf, output, out_len, kCFStringEncodingASCII))
52 void u16dec(
ushort* in,
char* out,
size_t* srclen,
size_t* dstlen);
54 static void usbgetstr(usb_dev_t handle, uint8 string_index,
char* output,
int out_len){
56 char buffer[256] = { 0 };
57 IOUSBDevRequest rq = { 0x80, 0x06, 0x0300 | string_index, 0x0409,
sizeof(buffer) - 2, buffer, 0};
58 kern_return_t res = (*handle)->DeviceRequest(handle, &rq);
59 if(res != kIOReturnSuccess){
63 size_t inl =
sizeof(buffer) / 2, outl = out_len;
65 output[out_len - 1] = 0;
68 #define INCOMPLETE (usb_dev_t)-1l
69 #define HAS_ALL_HANDLES(kb) ((kb)->epcount > 0 && (kb)->epcount_hid + (kb)->epcount_usb >= (kb)->epcount)
72 #define wait_loop(error, operation) do { \
74 while(((error) = (operation)) != kIOReturnSuccess){ \
80 #define IS_TEMP_FAILURE(res) ((res) == kIOUSBTransactionTimeout || (res) == kIOUSBTransactionReturned || (res) == kIOUSBPipeStalled)
81 #define IS_DISCONNECT_FAILURE(res) ((res) == kIOReturnBadArgument || (res) == kIOReturnNoDevice || (res) == kIOReturnNotOpen || (res) == kIOReturnNotAttached || (res) == kIOReturnExclusiveAccess)
84 static int get_pipe_index(usb_iface_t handle,
int desired_direction){
86 if((*handle)->GetNumEndpoints(handle, &count) != kIOReturnSuccess)
88 for(
int i = 0; i < count; i++){
89 uchar direction, number, transfertype, interval;
91 if((*handle)->GetPipeProperties(handle, i + 1, &direction, &number, &transfertype, &maxpacketsize, &interval) == kIOReturnSuccess){
92 if(direction == desired_direction)
101 kern_return_t res = kIOReturnSuccess;
107 IOUSBDevRequestTO rq = { 0x21, 0x09, 0x0200, ep - 1,
MSG_SIZE, (
void*)out_msg, 0, 5000, 5000 };
109 if(res == kIOReturnNotOpen){
111 usb_iface_t h_usb = kb->ifusb[ep - 1];
112 hid_dev_t h_hid = kb->ifhid[ep - 1];
114 res = (*h_usb)->ControlRequestTO(h_usb, 0, &rq);
116 res = (*h_hid)->setReport(h_hid, kIOHIDReportTypeFeature, 0, out_msg, MSG_SIZE, 5000, 0, 0, 0);
121 usb_iface_t h_usb = kb->ifusb[ep - 1];
122 hid_dev_t h_hid = kb->ifhid[ep - 1];
124 res = (*h_usb)->WritePipe(h_usb, get_pipe_index(h_usb, kUSBOut), (
void*)out_msg, MSG_SIZE);
126 res = (*h_hid)->setReport(h_hid, kIOHIDReportTypeOutput, 0, out_msg, MSG_SIZE, 5000, 0, 0, 0);
128 kb->lastresult = res;
129 if(res != kIOReturnSuccess){
130 ckb_err_fn(
"Got return value 0x%x\n", file, line, res);
131 if(IS_TEMP_FAILURE(res))
141 IOUSBDevRequestTO rq = { 0xa1, 0x01, 0x0200, ep - 1,
MSG_SIZE, in_msg, 0, 5000, 5000 };
142 kern_return_t res = (*kb->
handle)->DeviceRequestTO(kb->
handle, &rq);
143 CFIndex length = rq.wLenDone;
144 if(res == kIOReturnNotOpen){
146 usb_iface_t h_usb = kb->ifusb[ep - 1];
147 hid_dev_t h_hid = kb->ifhid[ep - 1];
149 res = (*h_usb)->ControlRequestTO(h_usb, 0, &rq);
151 res = (*h_hid)->getReport(h_hid, kIOHIDReportTypeFeature, 0, in_msg, &length, 5000, 0, 0, 0);
153 kb->lastresult = res;
154 if(res != kIOReturnSuccess){
155 ckb_err_fn(
"Got return value 0x%x\n", file, line, res);
156 if(IS_TEMP_FAILURE(res))
161 if(length != MSG_SIZE)
162 ckb_err_fn(
"Read %ld bytes (expected %d)\n", file, line, length, MSG_SIZE);
167 IOUSBDevRequestTO rq = { 0x40, bRequest, wValue, 0, 0, 0, 0, 5000, 5000 };
168 kern_return_t res = (*kb->
handle)->DeviceRequestTO(kb->
handle, &rq);
169 if(res != kIOReturnSuccess){
170 ckb_err_fn(
"Got return value 0x%x\n", file, line, res);
177 IOUSBDevRequestTO rq = { 0x21, 0x09, 0x0200, 0x00, 1, &kb->
ileds, 0, 500, 500 };
178 kern_return_t res = (*kb->
handle)->DeviceRequestTO(kb->
handle, &rq);
179 if(res == kIOReturnNotOpen){
181 hid_dev_t handle = kb->ifhid[0];
185 long ledpage = kHIDPage_LEDs;
186 const void* keys[] = { CFSTR(kIOHIDElementUsagePageKey) };
187 const void* values[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &ledpage) };
188 CFDictionaryRef matching = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
189 CFRelease(values[0]);
191 kern_return_t res = (*handle)->copyMatchingElements(handle, matching, &leds, 0);
193 if(res != kIOReturnSuccess)
196 CFIndex count = CFArrayGetCount(leds);
197 for(CFIndex i = 0; i < count; i++){
198 IOHIDElementRef led = (
void*)CFArrayGetValueAtIndex(leds, i);
199 uint32_t usage = IOHIDElementGetUsage(led);
200 IOHIDValueRef value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, led, 0, !!(ileds & (1 << (usage - 1))));
201 (*handle)->setValue(handle, led, value, 5000, 0, 0, 0);
207 if(res != kIOReturnSuccess)
208 ckb_err(
"Got return value 0x%x\n", res);
212 kern_return_t res = kb->lastresult;
213 if(IS_DISCONNECT_FAILURE(res))
221 static void intreport(
void* context, IOReturn result,
void* sender, IOHIDReportType reporttype, uint32_t reportid, uint8_t* data, CFIndex length){
223 pthread_mutex_lock(
imutex(kb));
270 pthread_mutex_unlock(
imutex(kb));
281 static void pipecomplete(
void* refcon, IOReturn result,
void* arg0){
282 if(result != kIOReturnSuccess)
284 intptr_t length = (intptr_t)arg0;
285 urbctx* ctx = refcon;
288 uchar* buffer = ctx->buffer;
289 intreport(kb, result, 0, 0, 0, buffer, length);
291 usb_iface_t handle = kb->ifusb[ctx->index];
292 (*handle)->ReadPipeAsync(handle, ctx->pipe, buffer, ctx->maxsize, pipecomplete, ctx);
297 CGEventRef mouse_event_modifier_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event,
void* refcon) {
298 if (type == kCGEventTapDisabledByTimeout) {
299 CGEventTapEnable(mouse_event_tap,
true);
307 CGEventFlags existingFlags = CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState);
308 for(
int i = 0; i <
DEV_MAX; i++){
314 pthread_mutex_lock(
imutex(kb));
315 CGEventSetFlags(event, (kCGEventFlagMaskNonCoalesced | kb->modifiers | existingFlags));
316 pthread_mutex_unlock(
imutex(kb));
328 void register_mouse_event_tap(CFRunLoopRef run_loop) {
333 CGEventMask mask = CGEventMaskBit(kCGEventLeftMouseDown) |
334 CGEventMaskBit(kCGEventLeftMouseUp) |
335 CGEventMaskBit(kCGEventRightMouseDown) |
336 CGEventMaskBit(kCGEventRightMouseUp) |
337 CGEventMaskBit(kCGEventMouseMoved) |
338 CGEventMaskBit(kCGEventLeftMouseDragged) |
339 CGEventMaskBit(kCGEventRightMouseDragged) |
340 CGEventMaskBit(kCGEventScrollWheel) |
341 CGEventMaskBit(kCGEventTabletPointer) |
342 CGEventMaskBit(kCGEventTabletProximity) |
343 CGEventMaskBit(kCGEventOtherMouseDown) |
344 CGEventMaskBit(kCGEventOtherMouseUp) |
345 CGEventMaskBit(kCGEventOtherMouseDragged);
349 mouse_event_tap = CGEventTapCreate(kCGHIDEventTap,
350 kCGHeadInsertEventTap,
351 kCGEventTapOptionDefault,
353 mouse_event_modifier_callback,
357 if (mouse_event_tap) {
358 CFRunLoopSourceRef run_loop_source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mouse_event_tap, 0);
359 if (run_loop_source) {
360 ckb_info(
"Registering EventTap for modifier keys.\n");
361 CFRunLoopAddSource(run_loop, run_loop_source, kCFRunLoopCommonModes);
362 CGEventTapEnable(mouse_event_tap,
true);
363 CFRelease(run_loop_source);
370 extern void keyretrigger(CFRunLoopTimerRef timer,
void* info);
379 CFRunLoopRef runloop = kb->input_loop = CFRunLoopGetCurrent();
380 for(
int i = 0; i < count; i++){
381 CFTypeRef eventsource;
384 res = (*kb->ifusb[i])->CreateInterfaceAsyncEventSource(kb->ifusb[i], (CFRunLoopSourceRef*)&eventsource);
385 else if(kb->ifhid[i])
386 res = (*kb->ifhid[i])->getAsyncEventSource(kb->ifhid[i], &eventsource);
389 if(res != kIOReturnSuccess){
390 ckb_err(
"Failed to start input thread for %s%d: %x\n",
devpath, index, res);
393 if(CFGetTypeID(eventsource) == CFRunLoopSourceGetTypeID())
394 CFRunLoopAddSource(runloop, (CFRunLoopSourceRef)eventsource, kCFRunLoopDefaultMode);
395 else if(CFGetTypeID(eventsource) == CFRunLoopTimerGetTypeID())
396 CFRunLoopAddTimer(runloop, (CFRunLoopTimerRef)eventsource, kCFRunLoopDefaultMode);
402 memset(input, 0,
sizeof(input));
403 for(
int i = 0; i < count; i++){
405 usb_iface_t handle = kb->ifusb[i];
406 int pipe = get_pipe_index(handle, kUSBIn);
407 uchar direction, number, transfertype, interval;
409 (*handle)->GetPipeProperties(handle, pipe, &direction, &number, &transfertype, &maxpacketsize, &interval);
410 if(direction != kUSBIn && direction != kUSBAnyDirn)
412 uchar* buffer = malloc(maxpacketsize);
414 input[i].buffer = buffer;
416 input[i].pipe = pipe;
417 input[i].maxsize = maxpacketsize;
418 (*handle)->ReadPipeAsync(handle, 1, buffer, maxpacketsize, pipecomplete, input + i);
419 }
else if(kb->ifhid[i]){
420 hid_dev_t handle = kb->ifhid[i];
421 long maxsize = hidgetlong(handle, CFSTR(kIOHIDMaxInputReportSizeKey));
422 uchar* buffer = malloc(maxsize);
423 input[i].buffer = buffer;
424 (*handle)->setInputReportCallback(handle, buffer, maxsize, intreport, kb, 0);
429 CFRunLoopTimerContext krctx = { 0, kb, NULL, NULL, NULL };
430 CFRunLoopTimerRef krtimer = kb->krtimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
431 CFAbsoluteTimeGetCurrent() + 0.001, 0.001,
433 keyretrigger, &krctx);
434 CFRunLoopTimerSetTolerance(krtimer, 0.015);
442 pthread_mutex_lock(
imutex(kb));
444 pthread_mutex_unlock(
imutex(kb));
447 pthread_mutex_unlock(
imutex(kb));
452 for(
int i = 0; i < count; i++)
453 free(input[i].buffer);
466 int count = kb->epcount_hid;
467 for(
int i = 0; i < count; i++){
468 hid_dev_t iface = kb->ifhid[i];
470 (*iface)->close(iface, kIOHIDOptionsTypeNone);
471 (*iface)->Release(iface);
477 count = kb->epcount_usb;
478 for(
int i = 0; i < count; i++){
479 usb_iface_t iface = kb->ifusb[i];
481 (*iface)->USBInterfaceClose(iface);
482 (*iface)->Release(iface);
487 usb_dev_t iface = kb->
handle;
489 (*iface)->USBDeviceClose(iface);
490 (*iface)->Release(iface);
495 CFRunLoopStop(kb->input_loop);
500 static void remove_device(
void* context, io_service_t device, uint32_t message_type,
void* message_argument){
501 if(message_type != kIOMessageServiceIsTerminated)
506 pthread_mutex_lock(
dmutex(kb));
508 pthread_mutex_unlock(
dmutex(kb));
510 IOObjectRelease(device);
515 static int find_device(uint16_t idvendor, uint16_t idproduct, uint32_t location,
int handle_idx){
517 for(
int i = 1; i <
DEV_MAX; i++){
518 if(pthread_mutex_trylock(
devmutex + i))
522 for(
int iface = 0; iface <=
IFACE_MAX; iface++){
523 if(
keyboard[i].location_id[iface] == location){
525 keyboard[i].location_id[handle_idx] = location;
534 for(
int i = 1; i <
DEV_MAX; i++){
535 if(pthread_mutex_trylock(
devmutex + i))
540 keyboard[i].location_id[handle_idx] = location;
551 static int seize_wait(
long location){
554 char location_var[18], location_fixed[18];
555 snprintf(location_var,
sizeof(location_var),
"@%lx", location);
556 snprintf(location_fixed,
sizeof(location_fixed),
"@%08x", (
int)location);
558 static mach_port_t master = 0;
560 if(!master && (res = IOMasterPort(bootstrap_port, &master)) != kIOReturnSuccess){
562 ckb_warn(
"Unable to open master port: 0x%08x\n", res);
565 const int max_tries = 20;
566 for(
int try = 0;
try < max_tries;
try++){
569 io_iterator_t child_iter;
570 if((res = IORegistryCreateIterator(master, kIOServicePlane, kIORegistryIterateRecursively, &child_iter)) != kIOReturnSuccess)
573 io_registry_entry_t child_service;
574 while((child_service = IOIteratorNext(child_iter)) != 0){
576 IORegistryEntryGetPath(child_service, kIOServicePlane, path);
577 IOObjectRelease(child_service);
579 if((strstr(path, location_var) || strstr(path, location_fixed)) && strstr(path,
"HID")){
580 IOObjectRelease(child_iter);
584 IOObjectRelease(child_iter);
590 static usbdevice* add_usb(usb_dev_t handle, io_object_t** rm_notify){
591 int iface_count = 0, iface_success = 0;
592 io_iterator_t iterator = 0;
593 io_service_t iface = 0;
595 UInt16 idvendor, idproduct;
597 (*handle)->GetDeviceVendor(handle, &idvendor);
598 (*handle)->GetDeviceProduct(handle, &idproduct);
599 (*handle)->GetLocationID(handle, &location);
601 int index = find_device(idvendor, idproduct, location, 0);
611 ckb_warn(
"Tried to set up handle for device ckb%d, but it was already set up. Skipping...\n", index);
618 UInt8 serial_idx, product_idx;
619 if((*handle)->USBGetSerialNumberStringIndex(handle, &serial_idx) == kIOReturnSuccess)
621 if((*handle)->USBGetProductStringIndex(handle, &product_idx) == kIOReturnSuccess)
627 if(seize_wait(location))
628 ckb_warn(
"seize_wait failed, connecting anyway...\n");
629 IOUSBFindInterfaceRequest interfaceRequest;
630 interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;
631 interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
632 interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
633 interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;
634 (*handle)->CreateInterfaceIterator(handle, &interfaceRequest, &iterator);
636 while((iface = IOIteratorNext(iterator)) != 0){
638 ckb_warn(
"Too many interfaces. Dropping the rest.\n");
639 IOObjectRelease(iface);
643 IOCFPlugInInterface** plugin = 0;
646 wait_loop(err, IOCreatePlugInInterfaceForService(iface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score));
647 if(err != kIOReturnSuccess){
648 ckb_err(
"Failed to create interface plugin: %x\n", err);
651 usb_iface_t if_handle;
652 wait_loop(err, (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID183), (LPVOID)&if_handle));
653 if(err != kIOReturnSuccess){
654 ckb_err(
"QueryInterface failed: %x\n", err);
658 IODestroyPlugInInterface(plugin);
661 (*if_handle)->GetLocationID(if_handle, kb->location_id + iface_count + 1);
663 err = (*if_handle)->USBInterfaceOpenSeize(if_handle);
664 if(err == kIOReturnSuccess){
665 kb->ifusb[iface_count] = if_handle;
668 IOServiceAddInterestNotification(notify, iface, kIOGeneralInterest, remove_device, kb, kb->rm_notify + 1 + iface_count);
670 kb->ifusb[iface_count] = 0;
671 (*if_handle)->Release(if_handle);
676 IOObjectRelease(iface);
678 if(iface_count == 0){
681 ckb_warn(
"Unable to count endpoints, assuming %d...\n", iface_count);
684 kb->epcount_usb = iface_success;
687 if(HAS_ALL_HANDLES(kb))
690 pthread_mutex_unlock(
devmutex + index);
691 *rm_notify = kb->rm_notify;
695 pthread_mutex_unlock(
devmutex + index);
699 static void iterate_devices_usb(
void* context, io_iterator_t iterator){
702 while((device = IOIteratorNext(iterator)) != 0){
703 IOCFPlugInInterface** plugin = 0;
706 wait_loop(err, IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score));
707 if(err != kIOReturnSuccess){
708 ckb_err(
"Failed to create device plugin: %x\n", err);
713 wait_loop(err, (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID182), (LPVOID*)&handle));
714 if(err != kIOReturnSuccess){
715 ckb_err(
"QueryInterface failed: %x\n", err);
719 IODestroyPlugInInterface(plugin);
721 err = (*handle)->USBDeviceOpenSeize(handle);
722 if(err == kIOReturnExclusiveAccess){
724 ckb_warn(
"Unable to seize USB handle, continuing anyway...\n");
725 }
else if(err != kIOReturnSuccess){
726 ckb_err(
"USBDeviceOpen failed: %x\n", err);
730 io_object_t* rm_notify = 0;
731 usbdevice* kb = add_usb(handle, &rm_notify);
734 IOServiceAddInterestNotification(notify, device, kIOGeneralInterest, remove_device, kb, rm_notify);
737 (*handle)->USBDeviceClose(handle);
739 IOObjectRelease(device);
744 static usbdevice* add_hid(hid_dev_t handle, io_object_t** rm_notify){
748 long input = hidgetlong(handle, CFSTR(kIOHIDMaxInputReportSizeKey));
749 long output = hidgetlong(handle, CFSTR(kIOHIDMaxOutputReportSizeKey));
750 long feature = hidgetlong(handle, CFSTR(kIOHIDMaxFeatureReportSizeKey));
756 else if(feature == 0 &&
758 input == 15) && output == 0) ||
759 (input == 64 && output == 64) ||
760 (input <= 1 && output == 64)))
763 else if(output <= 1 && feature <= 1 &&
768 else if(output <= 1 && feature <= 1 &&
769 (input == 21 || input == 10 ||
774 ckb_warn(
"Got unknown handle (I: %d, O: %d, F: %d)\n", (
int)input, (
int)output, (
int)feature);
779 uint16_t idvendor = hidgetlong(handle, CFSTR(kIOHIDVendorIDKey)), idproduct = hidgetlong(handle, CFSTR(kIOHIDProductIDKey));
781 uint32_t location = hidgetlong(handle, CFSTR(kIOHIDLocationIDKey));
782 int index = find_device(idvendor, idproduct, location, handle_idx + 1);
798 if(kb->ifhid[handle_idx]){
800 ckb_warn(
"Tried to set up ifhid[%d] for device ckb%d, but it was already set up. Skipping...\n", handle_idx, index);
803 kb->ifhid[handle_idx] = handle;
805 if(HAS_ALL_HANDLES(kb))
810 pthread_mutex_unlock(
devmutex + index);
811 *rm_notify = kb->rm_notify +
IFACE_MAX + 1 + handle_idx;
815 pthread_mutex_unlock(
devmutex + index);
819 static void iterate_devices_hid(
void* context, io_iterator_t iterator){
822 while((device = IOIteratorNext(iterator)) != 0){
824 IOCFPlugInInterface** plugin = 0;
827 wait_loop(err, IOCreatePlugInInterfaceForService(device, kIOHIDDeviceTypeID, kIOCFPlugInInterfaceID, &plugin, &score));
828 if(err != kIOReturnSuccess){
829 ckb_err(
"Failed to create device plugin: %x\n", err);
834 wait_loop(err, (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOHIDDeviceDeviceInterfaceID), (LPVOID*)&handle));
835 if(err != kIOReturnSuccess){
836 ckb_err(
"QueryInterface failed: %x\n", err);
840 IODestroyPlugInInterface(plugin);
842 if(seize_wait(hidgetlong(handle, CFSTR(kIOHIDLocationIDKey))))
843 ckb_warn(
"seize_wait failed, connecting anyway...\n");
844 wait_loop(err, (*handle)->open(handle, kIOHIDOptionsTypeSeizeDevice));
845 if(err != kIOReturnSuccess){
846 ckb_warn(
"Failed to open device: %x\n", err);
850 io_object_t* rm_notify = 0;
851 usbdevice* kb = add_hid(handle, &rm_notify);
854 IOServiceAddInterestNotification(notify, device, kIOGeneralInterest, remove_device, kb, rm_notify);
857 (*handle)->close(handle, kIOHIDOptionsTypeSeizeDevice);
859 IOObjectRelease(device);
868 P_K65,
P_K65_NRGB,
P_K65_LUX,
P_K65_RFIRE,
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,
874 notify = IONotificationPortCreate(kIOMasterPortDefault);
875 mainloop = CFRunLoopGetCurrent();
876 CFRunLoopAddSource(mainloop, IONotificationPortGetRunLoopSource(notify), kCFRunLoopDefaultMode);
886 CFMutableDictionaryRef match = IOServiceMatching(kIOUSBDeviceClassName);
887 CFNumberRef cfvendor = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor);
888 CFDictionarySetValue(match, CFSTR(kUSBVendorName), cfvendor);
890 CFMutableArrayRef cfproducts = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
891 for(uint i = 0; i <
sizeof(products) /
sizeof(
int); i++){
892 int product = products[i];
893 CFNumberRef cfproduct = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &product);
894 CFArrayAppendValue(cfproducts, cfproduct);
895 CFRelease(cfproduct);
897 CFDictionarySetValue(match, CFSTR(kUSBProductIdsArrayName), cfproducts);
898 CFRelease(cfproducts);
900 io_iterator_t iterator_usb = 0;
901 IOReturn res = IOServiceAddMatchingNotification(notify, kIOMatchedNotification, match, iterate_devices_usb, 0, &iterator_usb);
902 if(res != kIOReturnSuccess){
903 ckb_fatal(
"Failed to list USB devices: %x\n", res);
908 iterate_devices_usb(0, iterator_usb);
912 match = IOServiceMatching(kIOHIDDeviceKey);
913 cfvendor = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor);
914 CFDictionarySetValue(match, CFSTR(kIOHIDVendorIDKey), cfvendor);
916 cfproducts = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
917 for(uint i = 0; i <
sizeof(products) /
sizeof(
int); i++){
918 int product = products[i];
919 CFNumberRef cfproduct = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &product);
920 CFArrayAppendValue(cfproducts, cfproduct);
921 CFRelease(cfproduct);
923 CFDictionarySetValue(match, CFSTR(kIOHIDProductIDArrayKey), cfproducts);
924 CFRelease(cfproducts);
926 io_iterator_t iterator_hid = 0;
927 res = IOServiceAddMatchingNotification(notify, kIOMatchedNotification, match, iterate_devices_hid, 0, &iterator_hid);
928 if(res != kIOReturnSuccess){
929 ckb_fatal(
"Failed to list HID devices: %x\n", res);
934 iterate_devices_hid(0, iterator_hid);
936 register_mouse_event_tap(mainloop);
944 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().
uchar keys[((((152+3+12)+25)+7)/8)]
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.
void hid_mouse_translate(unsigned char *kbinput, short *xaxis, short *yaxis, int endpoint, int length, const unsigned char *urbinput)
#define ckb_warn(fmt, args...)
void corsair_mousecopy(unsigned char *kbinput, int endpoint, const unsigned char *urbinput)
const char *const devpath
#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 ...
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...)