Created
January 2, 2016 12:37
-
-
Save mjtorn/da746153f5e04ef35b1e to your computer and use it in GitHub Desktop.
Capture Razer Orbweaver HID traffic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* License: WTFPL | |
* Markus Törnqvist <[email protected]> | |
* | |
* 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