Skip to content

Instantly share code, notes, and snippets.

@mjtorn
Created January 2, 2016 12:37
Show Gist options
  • Save mjtorn/da746153f5e04ef35b1e to your computer and use it in GitHub Desktop.
Save mjtorn/da746153f5e04ef35b1e to your computer and use it in GitHub Desktop.
Capture Razer Orbweaver HID traffic
/*
* License: WTFPL
* Markus Törnqvist <mjt@nysv.org>
*
* Influenced heavily by http://www.linuxquestions.org/questions/programming-9/read-from-a-usb-barcode-scanner-that-simulates-a-keyboard-495358/
* and the hidapi README example
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "hidapi/hidapi.h"
// Orbweaver
#define VENDOR_ID 0x1532
#define PRODUCT_ID 0x0113
// Kinesis
//#define VENDOR_ID 0x05f3
//#define PRODUCT_ID 0x0007
#define TIMEOUT_MS 30
#define PACKET_LEN 3
#define L_CTRL 1
#define L_SHIFT 2
#define L_ALT 4
#define CLEAN_AND_RETURN(x) {hid_free_enumeration(x); return NULL;}
// from /usr/src/linux/drivers/usb/input/usbkbd.c
static char usb_kbd_scancode[256] = {
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
150,158,159,128,136,177,178,176,142,152,173,140
};
char scancodelist(int scancode) {
char ret = NULL;
switch (usb_kbd_scancode[scancode]) {
case 0x02: ret ='1'; break;
case 0x03: ret ='2'; break;
case 0x04: ret ='3'; break;
case 0x05: ret ='4'; break;
case 0x06: ret ='5'; break;
case 0x07: ret ='6'; break;
case 0x08: ret ='7'; break;
case 0x09: ret ='8'; break;
case 0x0a: ret ='9'; break;
case 0x0b: ret ='0'; break;
case 0x0f: ret ='T'; break; // TAB
case 0x1e: ret ='a'; break;
case 0x30: ret ='b'; break;
case 0x2e: ret ='c'; break;
case 0x20: ret ='d'; break;
case 0x12: ret ='e'; break;
case 0x21: ret ='f'; break;
case 0x22: ret ='g'; break;
case 0x23: ret ='h'; break;
case 0x17: ret ='i'; break;
case 0x24: ret ='j'; break;
case 0x25: ret ='k'; break;
case 0x26: ret ='l'; break;
case 0x29: ret ='X'; break; // backtick, to remap
case 0x32: ret ='m'; break;
case 0x31: ret ='n'; break;
case 0x3a: ret ='C'; break; // capslock, could be l-ctrl
case 0x18: ret ='o'; break;
case 0x19: ret ='p'; break;
case 0x10: ret ='q'; break;
case 0x13: ret ='r'; break;
case 0x1f: ret ='s'; break;
case 0x14: ret ='t'; break;
case 0x16: ret ='u'; break;
case 0x2f: ret ='v'; break;
case 0x11: ret ='w'; break;
case 0x2d: ret ='x'; break;
case 0x15: ret ='y'; break;
case 0x2c: ret ='z'; break;
case 0x0c: ret ='-'; break;
default: break;
}
return ret;
}
hid_device* get_hid() {
hid_device *hid = NULL;
struct hid_device_info *devs;
struct hid_device_info *cur_dev = NULL;
devs = hid_enumerate(0x0, 0x0);
cur_dev = devs;
do {
if (cur_dev->vendor_id == VENDOR_ID && cur_dev->product_id == PRODUCT_ID) {
printf("Found!\n");
printf("0x%x, 0x%x, %ls\n", cur_dev->vendor_id, cur_dev->product_id, cur_dev->serial_number);
break;
}
} while ((cur_dev = cur_dev->next));
if (!cur_dev) {
printf("Warning, returning NULL device\n");
CLEAN_AND_RETURN(devs);
}
hid = hid_open(cur_dev->vendor_id, cur_dev->product_id, cur_dev->serial_number);
if (hid == NULL) {
perror("Open failed :( errno");
CLEAN_AND_RETURN(devs);
}
hid_free_enumeration(devs);
return hid;
}
char* read_hid(hid_device *hid) {
int read_retval;
unsigned char data[PACKET_LEN];
int modifier;
int scancode;
int code;
memset(data, 0, PACKET_LEN);
while (1) {
read_retval = hid_read_timeout(hid, data, PACKET_LEN, TIMEOUT_MS);
modifier = (int) data[0]; // No idea what data[1] is :/
scancode = (int) data[2];
if (modifier) {
// Do not allow slapping down two of these, only one bit set
if ((modifier & (modifier - 1))) continue;
/* FIXME: this does not make sense
if (modifier & L_CTRL) {
scancode = 29; // Index 29 resolves to ,
} else if (modifier & L_SHIFT) {
scancode = 6; // Index 6 resolves to ,
} else if (modifier & L_ALT) {
scancode = 27; // Index 27 resolves to -
}
*/
}
/* printf("read_retval %d\n", read_retval); */
/* printf("data |%s|\n", data); */
/* printf("m data[0] |%d|\n", modifier); */
/* printf(" data[1] |%d|\n", (int) data[1]); */
/* printf("s data[2] |%d|\n", scancode); */
code = scancodelist(scancode);
if (code) {
printf("code %c\n", code);
if (code == 'q') break;
}
if (read_retval == 0) {
/* printf("Skipped a read?"); */
} else if (read_retval == -1) {
perror("hid_read returned -1");
break;
}
}
return NULL;
}
int main(int argc, char *argv[]) {
hid_device *hid = get_hid();
if (!hid) {
printf("No matching device found\n");
return ENODEV;
}
read_hid(hid);
hid_close(hid);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment