static void* _setupusb(void* context){ usbdevice* kb = context; // Set standard fields short vendor = kb->vendor, product = kb->product; const devcmd* vt = kb->vtable = get_vtable(vendor, product); kb->features = (IS_RGB(vendor, product) ? FEAT_STD_RGB : FEAT_STD_NRGB) & features_mask; if(IS_MOUSE(vendor, product)) kb->features |= FEAT_ADJRATE; if(IS_MONOCHROME(vendor, product)) kb->features |= FEAT_MONOCHROME; kb->usbdelay = USB_DELAY_DEFAULT; // Perform OS-specific setup DELAY_LONG(kb); if(os_setupusb(kb)) goto fail; // Make up a device name and serial if they weren't assigned if(!kb->serial[0]) snprintf(kb->serial, SERIAL_LEN, "%04x:%04x-NoID", kb->vendor, kb->product); if(!kb->name[0]) snprintf(kb->name, KB_NAME_LEN, "%s %s", vendor_str(kb->vendor), product_str(kb->product)); // Set up an input device for key events if(os_inputopen(kb)) goto fail; if(pthread_create(&kb->inputthread, 0, os_inputmain, kb)) goto fail; pthread_detach(kb->inputthread); if(os_setupindicators(kb)) goto fail; // Set up device vt->allocprofile(kb); vt->updateindicators(kb, 1); pthread_mutex_unlock(imutex(kb)); if(vt->start(kb, 0) && usb_tryreset(kb)) goto fail_noinput; // Make /dev path if(mkdevpath(kb)) goto fail_noinput; // Finished. Enter main loop int index = INDEX_OF(kb, keyboard); ckb_info("Setup finished for %s%d\n", devpath, index); updateconnected(); return devmain(kb); fail: pthread_mutex_unlock(imutex(kb)); fail_noinput: closeusb(kb); pthread_mutex_unlock(dmutex(kb)); 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)); }
// Vtable selector static const devcmd* get_vtable(short vendor, short product){ return IS_MOUSE(vendor, product) ? &vtable_mouse : IS_RGB(vendor, product) ? &vtable_keyboard : &vtable_keyboard_nonrgb; }
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 editor (char *filename, int startpos) { int stop = FALSE; // exit main loop? int fline = 0; // no. of first displayed line int cline = 0; // no. of line with cursor int shift = 0; // shift to the right int ccol = 0; // column of the cursor position in the file window int k, i, ndisp, rc, reply; char *p, buf[1024]; if (editor_open_file (filename) < 0) return; cline = min1 (startpos, nl-1); fline = max1 (0, cline - video_vsize()/2); // enter the loop while (1) { if (stop) { rc = 0; if (changed) { rc = -1; reply = fly_ask (0, " Save file `%s'? ", " Yes \n No \n Cancel ", filename); if (reply == 1) rc = editor_save_file (filename); if (reply == 2) rc = 0; if (reply == 3) stop = FALSE; } if (rc == 0) break; } ndisp = video_vsize()-1; // draw the screen for (i=0; i<ndisp; i++) { video_put_n_cell (' ', _BackWhite+_Black, video_hsize(), i, 0); if (i+fline < nl) editor_display_line (i, fline+i, shift); } video_put_n_cell (' ', _BackBlue+_White, video_hsize(), video_vsize()-1, 0); snprintf1 (buf, sizeof(buf), "L%d:C%d:S%d %c %s%s", cline, ccol, shift, fl_sym.v, changed ? "*" : "", filename); video_put (buf, video_vsize()-1, 0); video_set_cursor (cline-fline, ccol-shift); video_update (0); // get a keyboard/mouse event and process it k = getmessage (-1); if (IS_KEY(k)) { switch (k) { // Navigation keys case _Up: case _Down: case _PgUp: case _PgDn: fly_scroll_it (k, &fline, &cline, nl, video_vsize()-1); break; case _Right: ccol++; if (ccol-shift > video_hsize()-1) shift = ccol-video_hsize()+1; break; case _Left: ccol = max1 (ccol-1, 0); if (ccol < shift) shift = ccol; break; case _Home: ccol = 0; shift = 0; break; case _End: ccol = strlen(lines[cline]); if (ccol-shift > video_hsize()-1) shift = ccol-video_hsize()+1; break; case _CtrlHome: fline = 0; cline = 0; ccol = 0; shift = 0; break; case _CtrlEnd: fline = max1 (0, nl-video_vsize()+1); cline = min1 (fline+video_vsize()-1, nl-1); shift = 0; ccol = 0; break; // Action keys case _CtrlY: put_clipboard (lines[cline]); free (lines[cline]); for (i=cline; i<nl-1; i++) lines[i] = lines[i+1]; nl--; changed = TRUE; break; case _ShiftInsert: case _CtrlV: p = get_clipboard (); if (p == NULL || *p == '\0') break; if (nl == na) { na *= 2; lines = realloc (lines, sizeof(char *) * na); } for (i=nl-1; i>cline; i--) lines[i+1] = lines[i]; lines[cline+1] = p; ccol = 0; shift = 0; cline++; if (cline-fline == video_vsize()-1) fline++; nl++; changed = TRUE; break; case _BackSpace: if (ccol == 0) { // ccol == 0: glue this line to the previous if (cline == 0) break; p = malloc (strlen (lines[cline])+strlen(lines[cline-1])+1); strcpy (p, lines[cline-1]); strcat (p, lines[cline]); ccol = strlen (lines[cline-1]); if (ccol-shift > video_hsize()-1) shift = ccol-video_hsize()+1; free (lines[cline-1]); free (lines[cline]); lines[cline-1] = p; for (i=cline; i<nl-1; i++) lines[i] = lines[i+1]; cline--; nl--; } else { // ccol != 0: delete char at ccol-1, move cursor left str_delete (lines[cline], lines[cline]+ccol-1); ccol--; if (ccol < shift) shift = ccol; } changed = TRUE; break; case _Enter: if (nl == na) { na *= 2; lines = realloc (lines, sizeof(char *) * na); } for (i=nl-1; i>cline; i--) lines[i+1] = lines[i]; if (ccol < strlen (lines[cline])) { lines[cline+1] = strdup (lines[cline]+ccol); lines[cline][ccol] = '\0'; } else { lines[cline+1] = strdup (""); } ccol = 0; shift = 0; cline++; if (cline-fline == video_vsize()-1) fline++; nl++; changed = TRUE; break; case _Delete: if (ccol >= strlen (lines[cline])) { // glue previous line to this one if (cline == nl-1) break; p = malloc (ccol+strlen(lines[cline+1])+1); strcpy (p, lines[cline]); memset (p+strlen(lines[cline]), ' ', ccol-strlen(lines[cline])); strcpy (p+ccol, lines[cline+1]); free (lines[cline]); free (lines[cline+1]); lines[cline] = p; for (i=cline+1; i<nl-1; i++) lines[i] = lines[i+1]; nl--; } else { // ccol != 0: delete char at ccol-1, move cursor left str_delete (lines[cline], lines[cline]+ccol); } changed = TRUE; break; case _F2: rc = editor_save_file (filename); if (rc == 0) changed = FALSE; break; case _Esc: case _F10: stop = TRUE; break; // character keys default: if (k >= ' ' && k <= 255) { str_insert_at (cline, k, ccol); ccol++; changed = TRUE; } } } else if (IS_MOUSE(k)) { } else if (IS_SYSTEM(k)) { switch (SYS_TYPE(k)) { case SYSTEM_QUIT: stop = TRUE; break; } } } if (nl != 0 && lines != NULL) for (i=0; i<nl; i++) free (lines[i]); if (na != 0 && lines != NULL) free (lines); na = 0; lines = NULL; }