diff --git a/src/ckbnextconfig.h.in b/src/ckbnextconfig.h.in index 3d9590ed..ee93356f 100644 --- a/src/ckbnextconfig.h.in +++ b/src/ckbnextconfig.h.in @@ -18,3 +18,12 @@ #define CKB_NEXT_COPYRIGHT_YEAR "${ckb-next_COPYRIGHT_YEAR}" #cmakedefine ckb_next_VERSION_IS_RELEASE #define CKB_NEXT_DESCRIPTION "Open Source Driver for Corsair devices." + +#include +// Number of characters allowed for key names. +#define N_KEYNAME_LENGTH 40 +#define N_KEYNAME_STRLEN 39 +#define N_KEYNAME_STR_REAL(x) #x +#define N_KEYNAME_STR(x) N_KEYNAME_STR_REAL(x) +#define N_SCANF_KEYNAME N_KEYNAME_STR(N_KEYNAME_STRLEN) +static_assert((N_KEYNAME_LENGTH == N_KEYNAME_STRLEN + 1), "N_KEYNAME_LENGTH must be 1 greater than N_KEYNAME_STRLEN"); diff --git a/src/daemon/command.c b/src/daemon/command.c index 193fec92..8eebf56f 100644 --- a/src/daemon/command.c +++ b/src/daemon/command.c @@ -332,8 +332,8 @@ int readcmd(usbdevice* kb, char* line){ } // Scan the left side for key names and run the requested command int position = 0, field = 0; - char keyname[11] = { 0 }; - while(position < left && sscanf(word + position, "%10[^:,]%n", keyname, &field) == 1){ + char keyname[N_KEYNAME_LENGTH] = { 0 }; + while(position < left && sscanf(word + position, "%"N_SCANF_KEYNAME"[^:,]%n", keyname, &field) == 1){ uint keycode; if(!strcmp(keyname, "all")){ // Set all keys diff --git a/src/daemon/input.c b/src/daemon/input.c index b48768bb..2b12f9c3 100644 --- a/src/daemon/input.c +++ b/src/daemon/input.c @@ -9,6 +9,9 @@ #define IS_SCROLLWHEEL_V(scan) ((scan) == BTN_WHEELUP || (scan) == BTN_WHEELDOWN) #define IS_SCROLLWHEEL_H(scan) ((scan) == BTN_WHEELLEFT || (scan) == BTN_WHEELRIGHT) #define IS_VOLWHEEL(scan) (((scan) == KEY_VOLUMEUP || (scan) == KEY_VOLUMEDOWN) && DEV_HAS_VOLWHEEL(kb)) +// Lookup control wheel events by index in keymap. Alternatively one could check for non-null key->name to start with "ctrlwheel". +// FIXME: Replace by proper lookup of map in keymap. +#define IS_CTRLWHEEL(kb, index) ((kb)->protocol == PROTO_BRAGI && ((index) == 129 || (index) == 130)) static int macromask(const uchar* keys, const uchar* macro){ // Scan a macro against key input. Return 0 if any of them don't match @@ -229,18 +232,19 @@ static void* play_macro(void* param) { // Checks if the macro mask contains any wheels to prevent it from looping endlessly static inline int is_wheel_keybit(const usbdevice* kb, const uchar* macro){ - for(int i = 0; i < N_KEYBYTES_INPUT; i++){ + for(int byte = 0; byte < N_KEYBYTES_INPUT; byte++){ // Most entries are probably going to be 0, so skip over them - if(!macro[i]) + if(!macro[byte]) continue; // Go through each bit - for(int j = 0; j < 8; j++){ - if(!((macro[i] >> j) & 1)) + for(int bit = 0; bit < 8; bit++){ + int keyindex = byte * 8 + bit; + if(!((macro[byte] >> bit) & 1)) continue; // Get the index of the item and look it up in the keymap - const key* ckey = kb->keymap + i * 8 + j; + const key* ckey = kb->keymap + keyindex; // If there's at least a single wheel, return true - if(IS_VOLWHEEL(ckey->scan) || IS_SCROLLWHEEL_V(ckey->scan) || IS_SCROLLWHEEL_H(ckey->scan)) + if(IS_VOLWHEEL(ckey->scan) || IS_SCROLLWHEEL_V(ckey->scan) || IS_SCROLLWHEEL_H(ckey->scan) || IS_CTRLWHEEL(kb, keyindex)) return 1; } } @@ -390,7 +394,7 @@ static inline void inputupdate_keys(usbdevice* kb, int* sync_kb, int* sync_mouse // If it's a volume wheel, just add a single keyup event to the FIFO // Else if the event originated from a scroll wheel, and is bound to something other than a scroll wheel, // multiply the last few events by the amount of events received from the hid report - if(IS_VOLWHEEL(map->scan)){ + if(IS_VOLWHEEL(map->scan) || IS_CTRLWHEEL(kb, keyindex)){ // Make room for it memmove(events + modcount + keycount + 1, events + modcount + keycount, sizeof(int) * rmodcount); // Duplicate the last event, but with keyup @@ -416,7 +420,7 @@ static inline void inputupdate_keys(usbdevice* kb, int* sync_kb, int* sync_mouse } } // Clear the key bit so that we can receive events of this type in the next run - if(IS_VOLWHEEL(map->scan) || IS_SCROLLWHEEL_V(map->scan)) + if(IS_VOLWHEEL(map->scan) || IS_SCROLLWHEEL_V(map->scan) || IS_CTRLWHEEL(kb, keyindex)) input->keys[byte] &= ~mask; } @@ -641,8 +645,8 @@ static void _cmd_macro(usbmode* mode, const char* keys, const char* assignment, int empty = 1; int left = strlen(keys), right = strlen(assignment); int position = 0, field = 0; - char keyname[40]; - while(position < left && sscanf(keys + position, "%10[^+]%n", keyname, &field) == 1){ + char keyname[N_KEYNAME_LENGTH]; + while(position < left && sscanf(keys + position, "%"N_SCANF_KEYNAME"[^+]%n", keyname, &field) == 1){ // Find this key in the keymap for(unsigned i = 0; i < N_KEYS_INPUT; i++){ if(kb->keymap[i].name && !strcmp(keyname, kb->keymap[i].name)){ @@ -669,7 +673,7 @@ static void _cmd_macro(usbmode* mode, const char* keys, const char* assignment, position = 0; field = 0; // max action = old 11 chars plus 12 chars which is the max 32-bit unsigned int 4294967295 size * 2 + 1 for range underscore - while(position < right && sscanf(assignment + position, "%36[^,]%n", keyname, &field) == 1){ + while(position < right && sscanf(assignment + position, "%"N_SCANF_KEYNAME"[^,]%n", keyname, &field) == 1){ if(!strcmp(keyname, "clear")) break; @@ -678,12 +682,13 @@ static void _cmd_macro(usbmode* mode, const char* keys, const char* assignment, int64_t long_delay_range = 0; uint32_t delay = UINT32_MAX; // computed delay value. UINT32_MAX means use the default value. uint32_t delay_range = 0; - char real_keyname[12]; // temp to hold the left side (key) of the = - int scan_matches = sscanf(keyname, "%11[^=]=%"SCNd64"_%"SCNd64, real_keyname, &long_delay, &long_delay_range); + char real_keyname[N_KEYNAME_LENGTH]; // temp to hold the left side (key) of the = + int scan_matches = sscanf(keyname, "%"N_SCANF_KEYNAME"[^=]=%"SCNd64"_%"SCNd64, real_keyname, &long_delay, &long_delay_range); if (scan_matches == 2 || scan_matches == 3) { if (0 <= long_delay && long_delay < UINT32_MAX) { delay = (uint32_t)long_delay; - strcpy(keyname, real_keyname); // keyname[40], real_keyname[12] + static_assert(sizeof(keyname) >= sizeof(real_keyname), ""); + strcpy(keyname, real_keyname); if(0 < long_delay_range && long_delay_range < UINT32_MAX && long_delay_range > long_delay) { delay_range = (uint32_t)long_delay_range; diff --git a/src/daemon/keymap.c b/src/daemon/keymap.c index 86f31a0a..e6d34dc3 100644 --- a/src/daemon/keymap.c +++ b/src/daemon/keymap.c @@ -897,26 +897,31 @@ void process_input_urb(void* context, unsigned char* buffer, int urblen, ushort // We need to split the bragi code because the size check needs to go first if(kb->protocol == PROTO_BRAGI) { +#define BRAGI_MEDIA_MASK 0x60 + // Always clear the control wheel key bits. + // This will enable the daemon to emulate keyup events in inputupdate_keys(). + if (DEV_HAS_CTRLWHEEL(kb)) { + CLEAR_KEYBIT(targetkb->input.keys, 129); + CLEAR_KEYBIT(targetkb->input.keys, 130); + } + if(urblen == 64) { if(buffer[1] == BRAGI_INPUT_HID) { corsair_kbcopy(targetkb->input.keys, buffer + 2); // Check if we need to apply an awful hack to get media keys working handle_bragi_media_keys(targetkb); - } else if(buffer[1] == BRAGI_INPUT_DIAL) { - #define MEDIA_MASK 0x60 - if(buffer[1] == BRAGI_INPUT_DIAL && buffer[2] == MEDIA_MASK) { - // This is a packet from the volume dial - // We need to handle it appropriately then clear the keys so we stop getting garbage - int32_t wheel; - memcpy(&wheel, buffer + 4, sizeof(int32_t)); - if(wheel > 0) { - // Apply fresh key data: clockwise rotation - SET_KEYBIT(targetkb->input.keys, 129); - } else { - // Apply fresh key data: counter-clockwise rotation - SET_KEYBIT(targetkb->input.keys, 130); - } + } else if(buffer[1] == BRAGI_INPUT_DIAL && buffer[2] == BRAGI_MEDIA_MASK) { + // This is a packet from the control dial + // We need to handle it appropriately then clear the keys so we stop getting garbage + int32_t wheel; + memcpy(&wheel, buffer + 4, sizeof(int32_t)); + if(wheel > 0) { + // Apply fresh key data: clockwise rotation + SET_KEYBIT(targetkb->input.keys, 129); + } else { + // Apply fresh key data: counter-clockwise rotation + SET_KEYBIT(targetkb->input.keys, 130); } } else { ckb_err("Unimplemented bragi input packet %hhx\n", buffer[1]); diff --git a/src/daemon/led.c b/src/daemon/led.c index 4ece826c..30196b77 100644 --- a/src/daemon/led.c +++ b/src/daemon/led.c @@ -157,13 +157,13 @@ char* printrgb(const lighting* light, const usbdevice* kb){ b[i] = mb[k]; } // Make a buffer to track key names and to filter out duplicates - char names[N_KEYS_EXTENDED][11]; + char names[N_KEYS_EXTENDED][N_KEYNAME_LENGTH]; for(int i = 0; i < N_KEYS_EXTENDED; i++){ const char* name = kb->keymap[i].name; if(kb->keymap[i].led < 0 || !has_key(name, kb)) names[i][0] = 0; else - strncpy(names[i], name, 11); + strncpy(names[i], name, N_KEYNAME_LENGTH); } // Check to make sure these aren't all the same color int same = 1; diff --git a/src/daemon/usb.h b/src/daemon/usb.h index 295c694d..19b5d4a5 100644 --- a/src/daemon/usb.h +++ b/src/daemon/usb.h @@ -296,6 +296,9 @@ const char* product_str(ushort product); // Devices that have volume wheels (or don't) #define DEV_HAS_VOLWHEEL(kb) (!(IS_K65(kb) || IS_K63(kb) || (kb)->product == P_K57_U || IS_K55(kb) || IS_K60PRORGB(kb))) +// Devices that have a control wheel +#define DEV_HAS_CTRLWHEEL(kb) ((kb)->vendor == V_CORSAIR && (IS_K70CORERGB(kb) || (kb)->product == P_K100_MECHANICAL || (kb)->product == P_K100_OPTICAL || (kb)->product == P_K100_OPTICAL_VARIANT)) + // Devices that use the NXP protocol and have the DPI stage RGB data in the DPI packet #define NXP_RGB_IN_DPI_PKT(kb) ((kb)->vendor == V_CORSAIR && ((kb)->product == P_GLAIVE_PRO || IS_DARK_CORE_NXP(kb))) diff --git a/src/gui/animscript.cpp b/src/gui/animscript.cpp index 52fa106f..0198001d 100644 --- a/src/gui/animscript.cpp +++ b/src/gui/animscript.cpp @@ -447,9 +447,9 @@ void AnimScript::readProcess(){ } if(line.startsWith("argb ")){ // Add a color to the buffer - char keyName[31]; + char keyName[N_KEYNAME_LENGTH]; QRgb keyColor = 0; - if(sscanf(line, "argb %30s %x", keyName, &keyColor) != 2) + if(sscanf(line, "argb %" N_SCANF_KEYNAME "s %x", keyName, &keyColor) != 2) continue; QRgb* inMap = _colorBuffer.colorForName(keyName); if(!inMap) diff --git a/src/libs/ckb-next/include/ckb-next/animation.h b/src/libs/ckb-next/include/ckb-next/animation.h index ee51b39c..92acc903 100644 --- a/src/libs/ckb-next/include/ckb-next/animation.h +++ b/src/libs/ckb-next/include/ckb-next/animation.h @@ -127,7 +127,7 @@ #define CKB_REAL_ANGLE(angle) fmod((-(angle) + 90.) * M_PI / 180. + M_PI * 2., M_PI * 2.) // Key definition -#define CKB_KEYNAME_MAX 12 +#define CKB_KEYNAME_MAX 40 typedef struct { char name[CKB_KEYNAME_MAX+1]; int x, y;