int setactive_mouse(usbdevice* kb, int active){ if(NEEDS_FW_UPDATE(kb)) return 0; uchar msg[2][MSG_SIZE] = { { 0x07, 0x04, 0 }, // Disables or enables HW control for DPI and Sniper button { 0x07, 0x40, 0x08, 0, 1, 0x80, 2, 0x80, 3, 0x80, 4, 0x80, 5, 0x80, 6, 0x80, 7, 0x80, 8, 0x80 }, // Enable button input. This is similar to the keyboard input selection, but we want everything to come through the HID reports. }; if(active) // Put the mouse into SW mode msg[0][2] = 2; else // Restore HW mode msg[0][2] = 1; pthread_mutex_lock(imutex(kb)); kb->active = !!active; kb->profile->lastlight.forceupdate = 1; // Clear input memset(&kb->input.keys, 0, sizeof(kb->input.keys)); inputupdate(kb); pthread_mutex_unlock(imutex(kb)); if(!usbsend(kb, msg[0], 1)) return -1; if(active && !usbsend(kb, msg[1], 1)) return -1; return 0; }
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* intreap(void* context){ usbdevice* kb = context; int fd = kb->handle; while(1){ struct usbdevfs_urb* urb; if(ioctl(fd, USBDEVFS_REAPURB, &urb) && errno == ENODEV){ // Stop the thread if the handle closes break; } if(urb){ // Otherwise, re-submit the URB ioctl(fd, USBDEVFS_SUBMITURB, urb); // And process input (if any) if(urb->actual_length == MSG_SIZE) inputupdate(kb); // Mark the keyboard as having received input kb->INPUT_TEST = 1; } } return 0; }
void reportcallback(void* context, IOReturn result, void* sender, IOHIDReportType reporttype, uint32_t reportid, uint8_t* data, CFIndex length){ usbdevice* kb = context; if(HAS_FEATURES(kb, FEAT_RGB)){ switch(length){ case 8: // RGB EP 1: 6KRO (BIOS mode) input hid_translate(kb->kbinput, -1, 8, kb->urbinput); inputupdate(kb); break; case 21: case 5: // RGB EP 2: NKRO (non-BIOS) input. Accept only if keyboard is inactive if(!kb->active){ hid_translate(kb->kbinput, -2, 21, kb->urbinput + 8); inputupdate(kb); } break; case MSG_SIZE: // RGB EP 3: Corsair input inputupdate(kb); break; } } else { switch(length){ case 8: // Non-RGB EP 1: 6KRO input hid_translate(kb->kbinput, 1, 8, kb->urbinput); inputupdate(kb); break; case 4: // Non-RGB EP 2: media keys hid_translate(kb->kbinput, 2, 4, kb->urbinput + 8); inputupdate(kb); break; case 15: // Non-RGB EP 3: NKRO input hid_translate(kb->kbinput, 3, 15, kb->urbinput + 8 + 4); inputupdate(kb); break; } } }
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; }
void reportcallback(void* context, IOReturn result, void* sender, IOHIDReportType reporttype, uint32_t reportid, uint8_t* data, CFIndex length){ usbdevice* kb = context; if(length == MSG_SIZE) inputupdate(kb); }