static void intreport(void* context, IOReturn result, void* sender, IOHIDReportType reporttype, uint32_t reportid, uint8_t* data, CFIndex length){ usbdevice* kb = context; pthread_mutex_lock(imutex(kb)); if(IS_MOUSE(kb->vendor, kb->product)){ if(length == 10) hid_mouse_translate(kb->input.keys, &kb->input.rel_x, &kb->input.rel_y, -2, length, data); } else if(HAS_FEATURES(kb, FEAT_RGB)){ switch(length){ case 8: // RGB EP 1: 6KRO (BIOS mode) input hid_kb_translate(kb->input.keys, -1, length, data); break; case 21: case 5: // RGB EP 2: NKRO (non-BIOS) input. Accept only if keyboard is inactive if(!kb->active) hid_kb_translate(kb->input.keys, -2, length, data); break; case MSG_SIZE: // RGB EP 3: Corsair input memcpy(kb->input.keys, data, N_KEYBYTES_KB); break; } } else { switch(length){ case 8: // Non-RGB EP 1: 6KRO input hid_kb_translate(kb->input.keys, 1, length, data); break; case 4: // Non-RGB EP 2: media keys hid_kb_translate(kb->input.keys, 2, length, data); break; case 15: // Non-RGB EP 3: NKRO input hid_kb_translate(kb->input.keys, 3, length, data); break; } } inputupdate(kb); pthread_mutex_unlock(imutex(kb)); }
void* os_inputmain(void* context){ usbdevice* kb = context; int fd = kb->handle; short vendor = kb->vendor, product = kb->product; int index = INDEX_OF(kb, keyboard); ckb_info("Starting input thread for %s%d\n", devpath, index); // Monitor input transfers on all endpoints int urbcount = 3; struct usbdevfs_urb urbs[urbcount]; memset(urbs, 0, sizeof(urbs)); urbs[0].buffer_length = 8; if(IS_RGB(vendor, product)){ if(IS_MOUSE(vendor, product)) urbs[1].buffer_length = 10; else urbs[1].buffer_length = 21; urbs[2].buffer_length = MSG_SIZE; urbs[3].buffer_length = MSG_SIZE; } else { urbs[1].buffer_length = 4; urbs[2].buffer_length = 15; } // Submit URBs for(int i = 0; i < urbcount; i++){ urbs[i].type = USBDEVFS_URB_TYPE_INTERRUPT; urbs[i].endpoint = 0x80 | (i + 1); urbs[i].buffer = malloc(urbs[i].buffer_length); ioctl(fd, USBDEVFS_SUBMITURB, urbs + i); } // Start monitoring input while(1){ struct usbdevfs_urb* urb = 0; if(ioctl(fd, USBDEVFS_REAPURB, &urb)){ if(errno == ENODEV || errno == ENOENT || errno == ESHUTDOWN) // Stop the thread if the handle closes break; else if(errno == EPIPE && urb){ // On EPIPE, clear halt on the endpoint ioctl(fd, USBDEVFS_CLEAR_HALT, &urb->endpoint); // Re-submit the URB if(urb) ioctl(fd, USBDEVFS_SUBMITURB, urb); urb = 0; } } if(urb){ // Process input (if any) pthread_mutex_lock(imutex(kb)); if(IS_MOUSE(vendor, product)){ if(urb->endpoint == 0x82){ // RGB mouse input hid_mouse_translate(kb->input.keys, &kb->input.rel_x, &kb->input.rel_y, -(urb->endpoint & 0xF), urb->actual_length, urb->buffer); } } else if(IS_RGB(vendor, product)){ switch(urb->endpoint){ case 0x81: // RGB EP 1: 6KRO (BIOS mode) input hid_kb_translate(kb->input.keys, -1, urb->actual_length, urb->buffer); break; case 0x82: // RGB EP 2: NKRO (non-BIOS) input. Accept only if keyboard is inactive if(!kb->active) hid_kb_translate(kb->input.keys, -2, urb->actual_length, urb->buffer); break; case 0x83: // RGB EP 3: Corsair input memcpy(kb->input.keys, urb->buffer, N_KEYBYTES_KB); break; } } else // Non-RGB input hid_kb_translate(kb->input.keys, urb->endpoint & 0xF, urb->actual_length, urb->buffer); inputupdate(kb); pthread_mutex_unlock(imutex(kb)); // Re-submit the URB ioctl(fd, USBDEVFS_SUBMITURB, urb); urb = 0; } } // Clean up ckb_info("Stopping input thread for %s%d\n", devpath, index); for(int i = 0; i < urbcount; i++){ ioctl(fd, USBDEVFS_DISCARDURB, urbs + i); free(urbs[i].buffer); } return 0; }