diff --git a/KD100.c b/KD100.c index 574e003..e463674 100644 --- a/KD100.c +++ b/KD100.c @@ -1,9 +1,9 @@ /* - V1.4 + V1.4.1 https://github.com/mckset/KD100.git KD100 Linux driver for X11 desktops Other devices can be supported by modifying the code to read data received by the device - At the moment, only the KD100 mini keypad is supported by this code officially + At the moment, only the KD100 mini keydial is supported by this code officially */ #include @@ -37,19 +37,22 @@ const int vid = 0x256c; const int pid = 0x006d; void GetDevice(int debug, int accept, int dry){ - int err=0, wheelFunction=0, c=0, b=-1, tButtons=0, wheelType=0, lWheels=0, rWheels=0, tWheels=0; + int err=0, wheelFunction=0, button=-1, totalButtons=0, wheelType=0, leftWheels=0, rightWheels=0, totalWheels=0; char* data = malloc(512*sizeof(char)); // Data received from the config file and the USB event* events = malloc(1*sizeof(*events)); // Stores key events and functions wheel* wheelEvents = malloc(1*sizeof(wheel)); // Stores wheel functions - event prevEvent; + event prevEvent; uid_t uid=getuid(); // Used to check if the driver was ran as root + // Not important + int c=0; // Index of the loading character to display when waiting for a device + system("clear"); if (debug > 0){ if (debug > 2) debug=2; - printf("Version 1.4\nDebug level: %d\n", debug); + printf("Version 1.4.1\nDebug level: %d\n", debug); } // Load config file @@ -61,9 +64,22 @@ void GetDevice(int debug, int accept, int dry){ if (strcmp(file, "default.cfg")){ f = fopen(file, "r"); if (f == NULL){ - printf("CONFIG FILE NOT FOUND\n"); - return; - } + char* home = getpwuid(getuid())->pw_dir; + char* config = "/.config/KD100/"; + char temp[strlen(home)+strlen(config)+strlen(file)+1]; + for (int i = 0; i < strlen(home); i++) + temp[i] = home[i]; + for (int i = 0; i < strlen(config); i++) + temp[i+strlen(home)] = config[i]; + for (int i = 0; i < strlen(file); i++) + temp[i+strlen(home)+strlen(config)] = file[i]; + temp[strlen(home)+strlen(config)+strlen(file)] = '\0'; + f = fopen(temp, "r"); + if (f == NULL){ + printf("CONFIG FILE NOT FOUND\n"); + return; + } + } }else{ f = fopen(file, "r"); if (f == NULL){ @@ -74,7 +90,7 @@ void GetDevice(int debug, int accept, int dry){ temp[i] = home[i]; for (int i = 0; i < strlen(file); i++) temp[i+strlen(home)] = file[i]; - temp[strlen(temp)] = '\0'; + temp[strlen(home) + strlen(file)] = '\0'; f = fopen(temp, "r"); if (f == NULL){ @@ -86,44 +102,42 @@ void GetDevice(int debug, int accept, int dry){ } while (fscanf(f, "%[^\n] ", data) == 1){ for (int i = 0; i < strlen(data) && strlen(data)-6 > 0; i++){ - if (strcmp(Substring(data, i, 5), "type:") == 0 && b != -1){ - events[b].type = atoi(Substring(data, i+6, strlen(data)-(i+6))); + if (strcmp(Substring(data, i, 5), "type:") == 0 && button != -1){ + events[button].type = atoi(Substring(data, i+6, strlen(data)-(i+6))); break; }else if (strcmp(Substring(data, i, 6), "Button") == 0){ - b = atoi(Substring(data, i+7, strlen(data)-(i+7))); - if (b >= tButtons){ - event* temp = realloc(events, (b+1)*sizeof(*events)); + button = atoi(Substring(data, i+7, strlen(data)-(i+7))); + if (button >= totalButtons){ + event* temp = realloc(events, (button+1)*sizeof(*events)); events = temp; - tButtons = b+1; + totalButtons = button+1; } break; - }else if (strcmp(Substring(data, i, 9), "function:") == 0 && b != -1){ + }else if (strcmp(Substring(data, i, 9), "function:") == 0 && button != -1){ if (!wheelType) - events[b].function = Substring(data, i+10, strlen(data)-(i+10)); + events[button].function = Substring(data, i+10, strlen(data)-(i+10)); else if (wheelType == 1){ - if (rWheels != 0){ - wheel* temp = realloc(wheelEvents, (rWheels+1)*sizeof(*wheelEvents)); + if (rightWheels != 0){ + wheel* temp = realloc(wheelEvents, (rightWheels+1)*sizeof(*wheelEvents)); wheelEvents = temp; - wheelEvents[rWheels].right = Substring(data, i+10, strlen(data)-(i+10)); - wheelEvents[rWheels].left = "NULL"; + wheelEvents[rightWheels].right = Substring(data, i+10, strlen(data)-(i+10)); + wheelEvents[rightWheels].left = "NULL"; }else{ wheelEvents[0].right = Substring(data, i+10, strlen(data)-(i+10)); wheelEvents[0].left = "NULL"; } - rWheels++; + rightWheels++; }else{ - if (lWheels < rWheels) - wheelEvents[lWheels].left = Substring(data, i+10, strlen(data)-(i+10)); + if (leftWheels < rightWheels) + wheelEvents[leftWheels].left = Substring(data, i+10, strlen(data)-(i+10)); else{ - wheel* temp = realloc(wheelEvents, (lWheels+1)*sizeof(*wheelEvents)); + wheel* temp = realloc(wheelEvents, (leftWheels+1)*sizeof(*wheelEvents)); wheelEvents = temp; - wheelEvents[lWheels].left = Substring(data, i+10, strlen(data)-(i+10)); - wheelEvents[lWheels].right = "NULL"; + wheelEvents[leftWheels].left = Substring(data, i+10, strlen(data)-(i+10)); + wheelEvents[leftWheels].right = "NULL"; } - lWheels++; - } - - + leftWheels++; + } break; }else if (strcmp(Substring(data, i, 6), "Wheel ") == 0){ wheelType++; @@ -131,21 +145,21 @@ void GetDevice(int debug, int accept, int dry){ } } wheelFunction=0; - if (rWheels > lWheels) - tWheels = rWheels; + if (rightWheels > leftWheels) + totalWheels = rightWheels; else - tWheels = lWheels; + totalWheels = leftWheels; if (debug > 0){ - for (int i = 0; i < tButtons; i++) + for (int i = 0; i < totalButtons; i++) printf("Button: %d | Type: %d | Function: %s\n", i, events[i].type, events[i].function); printf("\n"); - for (int i = 0; i < tWheels; i++) + for (int i = 0; i < totalWheels; i++) printf("Wheel Right: %s | Wheel Left: %s\n", wheelEvents[i].right, wheelEvents[i].left); printf("\n"); } free(data); - int i = 0; + int devI = 0; char indi[] = "|/-\\"; while (err == 0 || err == LIBUSB_ERROR_NO_DEVICE){ libusb_device **devs; // List of USB devices @@ -160,8 +174,8 @@ void GetDevice(int debug, int accept, int dry){ } // Gets a list of devices and looks for ones that have the same vid and pid - int d=0; - i=0; + int d=0, found=0; + devI=0; libusb_device *savedDevs[sizeof(devs)]; while ((dev = devs[d++]) != NULL){ struct libusb_device_descriptor devDesc; @@ -197,20 +211,20 @@ void GetDevice(int debug, int accept, int dry){ if (debug > 0){ printf("\n#%d | %04x:%04x : %s\n", d, vid, pid, info); } - if (strlen(info) == 0){ + if (strlen(info) == 0 || strcmp("Huion Tablet_KD100", info) == 0){ break; }else{ libusb_close(handle); handle = NULL; + found++; } } }else{ - savedDevs[i] = dev; - i++; + savedDevs[devI] = dev; + devI++; } } } - if (accept == 0){ int in=-1; while(in == -1){ @@ -218,14 +232,14 @@ void GetDevice(int debug, int accept, int dry){ printf("\n"); system("lsusb"); printf("\n"); - for(d=0; d < i; d++){ + for(d=0; d < devI; d++){ printf("%d) %04x:%04x (Bus: %03d Device: %03d)\n", d, vid, pid, libusb_get_bus_number(savedDevs[d]), libusb_get_device_address(savedDevs[d])); } printf("Select a device to use: "); fflush(stdout); fgets(buf, 10, stdin); in = atoi(buf); - if (in >= i || in < 0){ + if (in >= devI || in < 0){ in=-1; } system("clear"); @@ -239,11 +253,13 @@ void GetDevice(int debug, int accept, int dry){ return; } } + }else if (found > 0){ + printf("Error: Found device does not appear to be the keydial\n"); + printf("Try running without the -a flag\n"); + return; } - - - i=0; + int interfaces=0; if (handle == NULL){ printf("\rWaiting for a device %c", indi[c]); fflush(stdout); @@ -258,141 +274,138 @@ void GetDevice(int debug, int accept, int dry){ system("clear"); } - i = 0; + interfaces = 0; printf("Starting driver...\n"); // Read device and claim interfaces dev = libusb_get_device(handle); libusb_get_config_descriptor(dev, 0, &desc); - i = desc->bNumInterfaces; + interfaces = desc->bNumInterfaces; libusb_free_config_descriptor(desc); libusb_set_auto_detach_kernel_driver(handle, 1); if (debug == 1) printf("Claiming interfaces... \n"); - for (int x = 0; x < i; x++){ + for (int x = 0; x < interfaces; x++){ libusb_kernel_driver_active(handle, x); int err = libusb_claim_interface(handle, x); if (err != LIBUSB_SUCCESS && debug == 1) printf("Failed to claim interface %d\n", x); } + printf("Driver is running!\n"); err = 0; - // Listen for events - printf("Driver is running!\n"); - - prevEvent.function = ""; - prevEvent.type = 0; - while (err >=0){ - unsigned char data[40]; // Stores device input - int keycode = 0; // Keycode read from the device - err = libusb_interrupt_transfer(handle, 0x81, data, sizeof(data), NULL, 0); // Get data - - // Potential errors - if (err == LIBUSB_ERROR_TIMEOUT) - printf("\nTIMEDOUT\n"); - if (err == LIBUSB_ERROR_PIPE) - printf("\nPIPE ERROR\n"); - if (err == LIBUSB_ERROR_NO_DEVICE) - printf("\nDEVICE DISCONNECTED\n"); - if (err == LIBUSB_ERROR_OVERFLOW) - printf("\nOVERFLOW ERROR\n"); - if (err == LIBUSB_ERROR_INVALID_PARAM) - printf("\nINVALID PARAMETERS\n"); - if (err == -1) - printf("\nDEVICE IS ALREADY IN USE\n"); - if (err < 0){ - if (debug == 1){ - printf("Unable to retrieve data: %d\n", err); + prevEvent.function = ""; + prevEvent.type = 0; + while (err >=0){ // Listen for events + unsigned char data[40]; // Stores device input + int keycode = 0; // Keycode read from the device + err = libusb_interrupt_transfer(handle, 0x81, data, sizeof(data), NULL, 0); // Get data + + // Potential errors + if (err == LIBUSB_ERROR_TIMEOUT) + printf("\nTIMEDOUT\n"); + if (err == LIBUSB_ERROR_PIPE) + printf("\nPIPE ERROR\n"); + if (err == LIBUSB_ERROR_NO_DEVICE) + printf("\nDEVICE DISCONNECTED\n"); + if (err == LIBUSB_ERROR_OVERFLOW) + printf("\nOVERFLOW ERROR\n"); + if (err == LIBUSB_ERROR_INVALID_PARAM) + printf("\nINVALID PARAMETERS\n"); + if (err == -1) + printf("\nDEVICE IS ALREADY IN USE\n"); + if (err < 0){ + if (debug == 1){ + printf("Unable to retrieve data: %d\n", err); + } + break; } - break; - } - // Convert data to keycodes - if (data[4] != 0) - keycode = data[4]; - else if (data[5] != 0) - keycode = data[5] + 128; - else if (data[6] != 0) - keycode = data[6] + 256; - if (data[1] == 241) - keycode+=512; - if (dry) - keycode = 0; - - // Compare keycodes to data and trigger events - if (debug == 1 && keycode != 0){ - printf("Keycode: %d\n", keycode); - } - if (keycode == 0 && prevEvent.type != 0){ // Reset key held - Handler(prevEvent.function, prevEvent.type); - prevEvent.function = ""; - prevEvent.type = 0; - } - if (keycode == 641){ // Wheel clockwise - Handler(wheelEvents[wheelFunction].right, -1); - }else if (keycode == 642){ // Counter clockwise - Handler(wheelEvents[wheelFunction].left, -1); - }else{ - for (int k = 0; k < 19; k++){ - if (keycodes[k] == keycode){ - if (events[k].function){ - if (strcmp(events[k].function, "NULL") == 0){ - if (prevEvent.type != 0){ - Handler(prevEvent.function, prevEvent.type); - prevEvent.type = 0; - prevEvent.function = ""; - } - break; - } - if (events[k].type == 0){ - if (strcmp(events[k].function, prevEvent.function)){ + // Convert data to keycodes + if (data[4] != 0) + keycode = data[4]; + else if (data[5] != 0) + keycode = data[5] + 128; + else if (data[6] != 0) + keycode = data[6] + 256; + if (data[1] == 241) + keycode+=512; + if (dry) + keycode = 0; + + // Compare keycodes to data and trigger events + if (debug == 1 && keycode != 0){ + printf("Keycode: %d\n", keycode); + } + if (keycode == 0 && prevEvent.type != 0){ // Reset key held + Handler(prevEvent.function, prevEvent.type); + prevEvent.function = ""; + prevEvent.type = 0; + } + if (keycode == 641){ // Wheel clockwise + Handler(wheelEvents[wheelFunction].right, -1); + }else if (keycode == 642){ // Counter clockwise + Handler(wheelEvents[wheelFunction].left, -1); + }else{ + for (int k = 0; k < 19; k++){ + if (keycodes[k] == keycode){ + if (events[k].function){ + if (strcmp(events[k].function, "NULL") == 0){ if (prevEvent.type != 0){ Handler(prevEvent.function, prevEvent.type); + prevEvent.type = 0; + prevEvent.function = ""; } - prevEvent.function = events[k].function; - prevEvent.type=1; + break; } - Handler(events[k].function, 0); - }else if (strcmp(events[k].function, "swap") == 0){ - if (wheelFunction != tWheels-1){ - wheelFunction++; - }else - wheelFunction=0; - if (debug == 1){ - printf("Function: %s | %s\n", wheelEvents[wheelFunction].left, wheelEvents[wheelFunction].right); - } - }else if (strcmp(events[k].function, "mouse1") == 0 || strcmp(events[k].function, "mouse2") == 0 || strcmp(events[k].function, "mouse3") == 0 || strcmp(events[k].function, "mouse4") == 0 || strcmp(events[k].function, "mouse5") == 0){ - if (strcmp(events[k].function, prevEvent.function)){ - if (prevEvent.type != 0){ - Handler(prevEvent.function, prevEvent.type); + if (events[k].type == 0){ + if (strcmp(events[k].function, prevEvent.function)){ + if (prevEvent.type != 0){ + Handler(prevEvent.function, prevEvent.type); + } + prevEvent.function = events[k].function; + prevEvent.type=1; + } + Handler(events[k].function, 0); + }else if (strcmp(events[k].function, "swap") == 0){ + if (wheelFunction != totalWheels-1){ + wheelFunction++; + }else + wheelFunction=0; + if (debug == 1){ + printf("Function: %s | %s\n", wheelEvents[wheelFunction].left, wheelEvents[wheelFunction].right); } - prevEvent.function = events[k].function; - prevEvent.type=3; + }else if (strcmp(events[k].function, "mouse1") == 0 || strcmp(events[k].function, "mouse2") == 0 || strcmp(events[k].function, "mouse3") == 0 || strcmp(events[k].function, "mouse4") == 0 || strcmp(events[k].function, "mouse5") == 0){ + if (strcmp(events[k].function, prevEvent.function)){ + if (prevEvent.type != 0){ + Handler(prevEvent.function, prevEvent.type); + } + prevEvent.function = events[k].function; + prevEvent.type=3; + } + Handler(events[k].function, 2); + }else{ + system(events[k].function); } - Handler(events[k].function, 2); - }else{ - system(events[k].function); + break; } - break; } } } - } - if(debug == 2 || dry){ - printf("DATA: [%d", data[0]); - for (int i = 1; i < sizeof(data); i++){ - printf(", %d", data[i]); + if(debug == 2 || dry){ + printf("DATA: [%d", data[0]); + for (int i = 1; i < sizeof(data); i++){ + printf(", %d", data[i]); + } + printf("]\n"); } - printf("]\n"); } - } - // Cleanup - for (int x = 0; x **_NOTICE:_** When updating from **v1.31** or below, make sure you updated your config file to follow the new format shown in the default config file @@ -43,16 +43,23 @@ sudo ./KD100 [options] Configuring ---------- -Edit or copy **default.cfg** to add your own keys/commands and use the '-c' flag to specify the location of the config file. New config files do not need to end in ".cfg". +Edit or copy **default.cfg** to add your own keys/commands and use the **-c** flag to specify the location of the config file. New config files do not need to end in ".cfg". If the config file is not found in the current directory, the driver while look for it in ~/.config/KD100/ Caveats ------- -- This only works on X11 based desktops (because it relies on xdotool) but can be patched for wayland desktops by altering the "handler" function -- You do not need to run this with sudo if you set a udev rule for the device. Create/edit a rule file in /etc/udev/rules.d/ and add the following, then save and reboot or reload your udev rules +- Because the driver relies on xdotool, it only works on X11 desktops but it can be patched for wayland desktops by altering the "handler" function +- You do not need to run this with sudo if you set a udev rule for the device. Create/edit a rule file in /etc/udev/rules.d/ and add the following: ``` -SUBSYSTEM=="usb",ATTRS{idVendor}=="256c",ATTRS{idProduct}=="006d",MODE="0666",GROUP="plugdev" +SUBSYSTEM=="usb",ATTRS{idVendor}=="256c",ATTRS{idProduct}=="006d",MODE="0666" ``` -- Technically speaking, this can support other devices, especially if they send the same type of byte information, otherwise the code should be easy enough to edit and add support for other usb devices. If you want to see the information sent by different devices, change the vid and pid in the program and run it with two debug flags +Save and then reboot or reload your udev rules with: +``` +sudo udevadm control --reload +sudo udevadm trigger +``` +> **_NOTE:_** Some systems might require you to run "sudo udevadm trigger" on boot + +- Technically speaking, this can support other devices, especially if they send the same type of byte information, otherwise the code should be easy enough to edit and add support for other usb devices. If you want to see the information sent by different devices, change the vid and pid in the program and run it with the **-dry** flag Tested Distros -------------- @@ -65,5 +72,3 @@ Known Issues ------------ - Setting shortcuts like "ctrl+c" will close the driver if it ran from a terminal and it's active - The driver cannot trigger keyboard shortcuts from combining multiple buttons on the device -> Because of how the data is packaged, there currently is no work around for this -