diff -Nru ckb-next-0.6.0-1/cmake/modules/CkbNextCompileFlags.cmake ckb-next-0.6.0-20/cmake/modules/CkbNextCompileFlags.cmake --- ckb-next-0.6.0-1/cmake/modules/CkbNextCompileFlags.cmake 2022-06-06 11:00:03.000000000 +0000 +++ ckb-next-0.6.0-20/cmake/modules/CkbNextCompileFlags.cmake 2023-06-26 11:00:03.000000000 +0000 @@ -82,3 +82,15 @@ string(REPLACE "-O2" "-O3" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") string(REPLACE "-O2" "-O3" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + +if(WERROR) + list(APPEND CKB_NEXT_EXTRA_C_FLAGS + -Werror + -Wno-error=cpp + -Wno-error=cast-align + ) + list(APPEND CKB_NEXT_EXTRA_CXX_FLAGS + -Werror + -Wno-error=cpp + ) +endif() diff -Nru ckb-next-0.6.0-1/CMakeLists.txt ckb-next-0.6.0-20/CMakeLists.txt --- ckb-next-0.6.0-1/CMakeLists.txt 2023-06-22 22:17:12.000000000 +0000 +++ ckb-next-0.6.0-20/CMakeLists.txt 2023-06-26 11:00:04.000000000 +0000 @@ -65,7 +65,7 @@ # Get more precise version from git, fallback on release include(CkbNextDetermineVersion) find_package(Git) -set(ckb-next_VERSION "0.6.0-1-g3506dc6") +set(ckb-next_VERSION "0.6.0-20-g932ff43") find_package(Sanitizers) @@ -121,6 +121,7 @@ option(NO_FAIR_MUTEX_QUEUEING "Disable fair mutex queueing. Debugging only." OFF) option(DEBUG_INPUT_SYNC "Print a debug message every time an event bundle is delivered to the OS." OFF) option(FPS_COUNTER "Enable FPS counters." OFF) +option(WERROR "Enable Werror (for CI)" OFF) # Make sure NO_FAIR_MUTEX_QUEUEING is set if TSAN is enabled # Otherwise you end up with threading issues that are not detected diff -Nru ckb-next-0.6.0-1/debian/changelog ckb-next-0.6.0-20/debian/changelog --- ckb-next-0.6.0-1/debian/changelog 2023-06-22 22:17:25.000000000 +0000 +++ ckb-next-0.6.0-20/debian/changelog 2023-06-26 11:00:17.000000000 +0000 @@ -1,3 +1,9 @@ +ckb-next (0.6.0-20-g932ff43~kinetic) kinetic; urgency=low + + * 0.6.0-20-g932ff43 git upstream + + -- Tasos Sahanidis Mon, 26 Jun 2023 14:00:17 +0300 + ckb-next (0.6.0-1-g3506dc6~kinetic) kinetic; urgency=low * 0.6.0-1-g3506dc6 git upstream diff -Nru ckb-next-0.6.0-1/.github/actions/cmake/build/action.yml ckb-next-0.6.0-20/.github/actions/cmake/build/action.yml --- ckb-next-0.6.0-1/.github/actions/cmake/build/action.yml 2022-08-01 11:00:03.000000000 +0000 +++ ckb-next-0.6.0-20/.github/actions/cmake/build/action.yml 2023-06-26 11:00:03.000000000 +0000 @@ -17,7 +17,8 @@ -DFORCE_INIT_SYSTEM=systemd \ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX:-/usr} \ -DSAFE_INSTALL=ON \ - -DSAFE_UNINSTALL=ON + -DSAFE_UNINSTALL=ON \ + -DWERROR=ON shell: bash --noprofile --norc -euxo pipefail {0} - name: Build diff -Nru ckb-next-0.6.0-1/.github/actions/dependencies/install/yum/action.yml ckb-next-0.6.0-20/.github/actions/dependencies/install/yum/action.yml --- ckb-next-0.6.0-1/.github/actions/dependencies/install/yum/action.yml 2022-08-01 11:00:03.000000000 +0000 +++ ckb-next-0.6.0-20/.github/actions/dependencies/install/yum/action.yml 2023-06-26 11:00:03.000000000 +0000 @@ -20,6 +20,13 @@ shell: bash --noprofile --norc -euxo pipefail {0} if: matrix.image == 'almalinux:8' || matrix.image == 'rockylinux:8' + - name: Enable CRB repository (AlmaLinux 9/Rocky Linux 9) + run: | + dnf --assumeyes --skip-broken install "dnf-command(config-manager)" + dnf config-manager --set-enabled crb + shell: bash --noprofile --norc -euxo pipefail {0} + if: matrix.image == 'almalinux:9' || matrix.image == 'rockylinux:9' + - name: Enable EPEL repository (Amazon Linux 2) run: amazon-linux-extras install epel -y shell: bash --noprofile --norc -euxo pipefail {0} diff -Nru ckb-next-0.6.0-1/.github/workflows/build.yml ckb-next-0.6.0-20/.github/workflows/build.yml --- ckb-next-0.6.0-1/.github/workflows/build.yml 2022-08-01 11:00:03.000000000 +0000 +++ ckb-next-0.6.0-20/.github/workflows/build.yml 2023-06-26 11:00:03.000000000 +0000 @@ -3,6 +3,7 @@ on: - push + - pull_request jobs: Linux: @@ -11,18 +12,22 @@ strategy: matrix: image: - - 'amazonlinux:2' - 'archlinux:latest' - 'almalinux:8' + - 'almalinux:9' - 'rockylinux:8' + - 'rockylinux:9' - 'debian:10' - 'debian:11' - - 'fedora:35' - - 'fedora:36' + - 'debian:12' + - 'fedora:37' + - 'fedora:38' + - 'fedora:rawhide' - 'ubuntu:20.04' - 'ubuntu:22.04' + - 'ubuntu:rolling' build_type: - - Release + - Debug compiler: - GNU fail-fast: false diff -Nru ckb-next-0.6.0-1/scripts/nxp_rgb_count.py ckb-next-0.6.0-20/scripts/nxp_rgb_count.py --- ckb-next-0.6.0-1/scripts/nxp_rgb_count.py 1970-01-01 00:00:00.000000000 +0000 +++ ckb-next-0.6.0-20/scripts/nxp_rgb_count.py 2023-06-26 11:00:03.000000000 +0000 @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +import sys + +# Reads an NXP (single colour) frame from stdin and returns the index of the first led that's fully on +# Args are indices to ignore (for buttons that can not be turned off) +ignore = set([int(x) for x in sys.argv[1:]]) +cmdi = 0 +leds = [] +while cmdi < 3: + expected = f"7f 0{cmdi + 1} " + cmd = input().lower().strip() + if not cmd.startswith(expected): + print("Try again. Expecting " + expected) + continue + + cmdi += 1 + + cmdl = cmd.split(" ") + leds += cmdl[4:] + +for i in range(len(leds)): + if len(leds[i]) != 2: + print(f"Invalid data at {i}") + elif leds[i] == "ff": + if i in ignore: + continue + print(f"LED found at {i} {hex(i)}") + break diff -Nru ckb-next-0.6.0-1/src/daemon/bragi_proto.h ckb-next-0.6.0-20/src/daemon/bragi_proto.h --- ckb-next-0.6.0-1/src/daemon/bragi_proto.h 2023-06-07 23:10:44.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/bragi_proto.h 2023-06-26 11:00:03.000000000 +0000 @@ -59,12 +59,17 @@ // Resources (used to get handles) #define BRAGI_RES_LIGHTING 0x01 #define BRAGI_RES_LIGHTING_MONOCHROME 0x10 +// Used for devices that have RGBRGBRGB packets instead of RRRGGGBBB +#define BRAGI_RES_ALT_LIGHTING 0x22 +// Secondary lighting packet +#define BRAGI_RES_LIGHTING_EXTRA 0x2e #define BRAGI_RES_PAIRINGID 0x05 #define BRAGI_RES_ENCRYPTIONKEY 0x06 // ckb-specific macros #define BRAGI_LIGHTING_HANDLE 0x00 #define BRAGI_GENERIC_HANDLE 0x01 // This is used for quick read/writes. Do NOT leave it open. +#define BRAGI_2ND_LIGHTING_HANDLE 0x02 // This one is opened if a device needs a secondary lighting hangle // HID input (2 bytes) #define BRAGI_INPUT_0 0x00 diff -Nru ckb-next-0.6.0-1/src/daemon/device_bragi.c ckb-next-0.6.0-20/src/daemon/device_bragi.c --- ckb-next-0.6.0-1/src/daemon/device_bragi.c 2023-06-07 23:10:44.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/device_bragi.c 2023-06-26 11:00:03.000000000 +0000 @@ -1,3 +1,4 @@ +#include #include "command.h" #include "device.h" #include "devnode.h" @@ -8,6 +9,7 @@ #include "bragi_proto.h" #include "bragi_common.h" #include "utils.h" +#include "led.h" // CUE polls devices every 52 seconds const struct timespec bragi_poll_delay = { .tv_sec = 50 }; @@ -34,8 +36,10 @@ } static int setactive_bragi(usbdevice* kb, int active){ - if(active == BRAGI_MODE_HARDWARE) + if(active == BRAGI_MODE_HARDWARE){ bragi_close_handle(kb, BRAGI_LIGHTING_HANDLE); + bragi_close_handle(kb, BRAGI_2ND_LIGHTING_HANDLE); + } const int ckb_id = INDEX_OF(kb, keyboard); if(bragi_set_property(kb, BRAGI_MODE, active)){ @@ -86,9 +90,51 @@ // Check if the device returned an error // Non fatal for now. Should first figure out what the error codes mean. // Device returns 0x03 on writes if we haven't opened the handle. - if(light) - ckb_err("ckb%d: Bragi light init returned error 0x%hhx", ckb_id, (uchar)light); + if(light == 0x01) { + // A K100 has been observed to return 0x01, so it probably means "not supported" + // If we get that response, we instead try to open the alt rgb lighting resource + ckb_warn("ckb%d: Bragi light init returned not supported", ckb_id); + light = bragi_open_handle(kb, BRAGI_LIGHTING_HANDLE, BRAGI_RES_ALT_LIGHTING); + if(light < 0) + return light; + + if(light) { + ckb_err("ckb%d: Bragi alt light init returned error 0x%hhx", ckb_id, (uchar)light); + } else { + // Swap the RGB function if we're using alt lighting + kb->vtable.updatergb = updatergb_keyboard_bragi_alt; + + // Open the second lighting handle + // We don't yet know if this is K100 specific or if it has to be opened along with the alt one + light = bragi_open_handle(kb, BRAGI_2ND_LIGHTING_HANDLE, BRAGI_RES_LIGHTING_EXTRA); + if(light < 0) + return light; + if(light){ + ckb_err("ckb%d: Bragi extra light init returned error 0x%hhx", ckb_id, (uchar)light); + } else { + // FIXME: Figure out what this is. It is definitely lighting related. + // It has been observed to break lighting on specific keys (such has the '3' key) + // but only on a specific K100 (fw 0.32.6, bld 0.10.45) + // It remains commented out for now + /*uchar pkt2[BRAGI_JUMBO_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // header + 0x1b, 0x00, 0x20, 0xe7, 0xca, 0x2f, 0x88, 0x9f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x01, 0x00, 0x0d, 0x00, 0x01, 0x01, 0x00, 0x04, 0x00, 0x00, 0x08, 0x06, 0x02, 0x48, 0x00, + 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, + 0x00, 0x00, 0xff, 0x72, 0x00, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0x89, 0x00, 0x00, + 0x00, 0xff, 0xb6, 0x00, 0x00, 0x00, 0xff, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xb8, 0x00, 0x00, 0x00, + 0xff, 0xb9, 0x00, 0x00, 0x00, 0xff, 0xba, 0x00, 0x00, 0x00, 0xff, 0xbb, 0x00, 0x00, 0x00, 0xff, + 0xbc, 0x00, 0x00, 0x00, 0xff, 0xbd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + if(bragi_write_to_handle(kb, pkt2, BRAGI_2ND_LIGHTING_HANDLE, sizeof(pkt2), 0x48)) + return 1;*/ + } + } + } else if(light) { + ckb_err("ckb%d: Bragi light init returned error 0x%hhx", ckb_id, (uchar)light); + } return 0; } diff -Nru ckb-next-0.6.0-1/src/daemon/keymap.c ckb-next-0.6.0-20/src/daemon/keymap.c --- ckb-next-0.6.0-1/src/daemon/keymap.c 2023-06-07 20:45:26.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/keymap.c 2023-06-26 11:00:03.000000000 +0000 @@ -202,6 +202,28 @@ // Strafe logo backlight { "logo", 0x7d, KEY_CORSAIR }, + // 20 empty entries for the K100 (patched by the bragi keymap) + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + { 0, -1, KEY_NONE }, + // Keys not present on any device { "lightup", -1, KEY_BRIGHTNESSUP }, { "lightdn", -1, KEY_BRIGHTNESSDOWN }, @@ -294,7 +316,6 @@ /* { "ro", -1, KEY_RO }, { "hanja", -1, KEY_HANJA }, -{ "profswitch", 128, KEY_CORSAIR }, { "katahira", -1, KEY_KATAKANAHIRAGANA }, { "hangul", -1, KEY_HANGEUL }, the G keys after G6, if they ever make another keyboard with them @@ -431,7 +452,7 @@ { "next", 125, KEY_NEXTSONG }, { "prev", 126, KEY_PREVIOUSSONG }, { "mr", -1, KEY_CORSAIR }, - { 0, -1, KEY_NONE }, + { "profswitch", 128, KEY_CORSAIR }, { 0, -1, KEY_NONE }, { 0, -1, KEY_NONE }, { "g1", 131, KEY_CORSAIR }, @@ -440,40 +461,63 @@ { "g4", 134, KEY_CORSAIR }, { "g5", 135, KEY_CORSAIR }, { "g6", 136, KEY_CORSAIR }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, - { 0, -1, KEY_NONE }, + { "ctrlwheelb", 137, KEY_NONE }, + { "topbar1", 138, KEY_NONE }, + { "topbar2", 139, KEY_NONE }, + { "topbar3", 140, KEY_NONE }, + { "topbar4", 141, KEY_NONE }, + { "topbar5", 142, KEY_NONE }, + { "topbar6", 143, KEY_NONE }, + { "topbar7", 144, KEY_NONE }, + { "topbar8", 145, KEY_NONE }, + { "topbar9", 146, KEY_NONE }, + { "topbar10", 147, KEY_NONE }, + { "topbar11", 148, KEY_NONE }, + { "topbar12", 149, KEY_NONE }, + { "topbar13", 150, KEY_NONE }, + { "topbar14", 151, KEY_NONE }, + { "topbar15", 152, KEY_NONE }, + { "topbar16", 153, KEY_NONE }, + { "topbar17", 154, KEY_NONE }, + { "topbar18", 155, KEY_NONE }, + { "topbar19", 156, KEY_NONE }, + { "topbar20", 157, KEY_NONE }, + { "topbar21", 158, KEY_NONE }, + { "topbar22", 159, KEY_NONE }, + { "leftbar1", 160, KEY_NONE }, + { "leftbar2", 161, KEY_NONE }, + { "leftbar3", 162, KEY_NONE }, + { "leftbar4", 163, KEY_NONE }, + { "leftbar5", 164, KEY_NONE }, + { "leftbar6", 165, KEY_NONE }, + { "leftbar7", 166, KEY_NONE }, + { "leftbar8", 167, KEY_NONE }, + { "leftbar9", 168, KEY_NONE }, + { "leftbar10", 169, KEY_NONE }, + { "leftbar11", 170, KEY_NONE }, + { "rightbar1", 171, KEY_NONE }, + { "rightbar2", 172, KEY_NONE }, + { "rightbar3", 173, KEY_NONE }, + { "rightbar4", 174, KEY_NONE }, + { "rightbar5", 175, KEY_NONE }, + { "rightbar6", 176, KEY_NONE }, + { "rightbar7", 177, KEY_NONE }, + { "rightbar8", 178, KEY_NONE }, + { "rightbar9", 179, KEY_NONE }, + { "rightbar10", 180, KEY_NONE }, + { "rightbar11", 181, KEY_NONE }, + { "ctrlwheel2", 182, KEY_NONE }, + { "ctrlwheel3", 183, KEY_NONE }, + { "ctrlwheel4", 184, KEY_NONE }, + { "ctrlwheel5", 185, KEY_NONE }, + { "ctrlwheel6", 186, KEY_NONE }, + { "ctrlwheel7", 187, KEY_NONE }, + { "ctrlwheel8", 188, KEY_NONE }, + { "ctrlwheel1", 189, KEY_NONE }, // We want top right to be 1 and top left to be 8 + { "logoleft", 190, KEY_NONE }, + { "logo", 191, KEY_NONE }, + { "logoright", 192, KEY_NONE }, { "status", 0, KEY_NONE }, // This might need to be moved elsewhere - { "topbar1", 137, KEY_NONE }, - { "topbar2", 138, KEY_NONE }, - { "topbar3", 139, KEY_NONE }, - { "topbar4", 140, KEY_NONE }, - { "topbar5", 141, KEY_NONE }, - { "topbar6", 142, KEY_NONE }, - { "topbar7", 143, KEY_NONE }, - { "topbar8", 144, KEY_NONE }, - { "topbar9", 145, KEY_NONE }, - { "topbar10", 146, KEY_NONE }, - { "topbar11", 147, KEY_NONE }, - { "topbar12", 148, KEY_NONE }, - { "topbar13", 149, KEY_NONE }, - { "topbar14", 150, KEY_NONE }, - { "topbar15", 151, KEY_NONE }, - { "topbar16", 152, KEY_NONE }, - { "topbar17", 153, KEY_NONE }, - { "topbar18", 154, KEY_NONE }, - { "topbar19", 155, KEY_NONE }, }; // LUT for HID -> Corsair scancodes (-1 for no scan code, -2 for currently unsupported) diff -Nru ckb-next-0.6.0-1/src/daemon/keymap.h ckb-next-0.6.0-20/src/daemon/keymap.h --- ckb-next-0.6.0-1/src/daemon/keymap.h 2022-03-07 18:03:08.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/keymap.h 2023-06-26 11:00:03.000000000 +0000 @@ -26,8 +26,8 @@ #define N_KEYS_HW 152 #define N_KEYBYTES_HW ((N_KEYS_HW + 7) / 8) // Light zones (have LED codes but don't generate input) -// Two strafe side lights (although really they are tied into one control) + logo backlight + Platinum top bar -#define N_KEY_ZONES 22 +// Two strafe side lights (although really they are tied into one control) + logo backlight + Platinum top bar + K100 (20) extra leds +#define N_KEY_ZONES 42 // Additional keys recognized by the driver but may not be present on keyboard #define N_KEYS_EXTRA 16 // Generic RGB Zones (Polaris/K55/...) @@ -57,7 +57,7 @@ #define N_KEYS_EXTENDED (N_KEYS_INPUT + N_MOUSE_ZONES_EXTENDED) #define N_KEYBYTES_EXTENDED ((N_KEYS_EXTENDED + 7) / 8) -#define N_KEYS_BRAGI_PATCH 171 +#define N_KEYS_BRAGI_PATCH 194 // Map from key name to LED code and USB scan code typedef struct { diff -Nru ckb-next-0.6.0-1/src/daemon/keymap_patch.c ckb-next-0.6.0-20/src/daemon/keymap_patch.c --- ckb-next-0.6.0-1/src/daemon/keymap_patch.c 2023-06-07 20:45:26.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/keymap_patch.c 2023-06-26 11:00:03.000000000 +0000 @@ -81,6 +81,16 @@ { 248, "bar4", LED_MOUSE + 4, KEY_NONE }, // "bar3" }; +keypatch k100patch[] = { + {114, "lock", 114, KEY_CORSAIR }, +}; + +keypatch k70tklpatch[] = { + { 114, "lock", 114, KEY_CORSAIR }, + { 1, "logo", 1, KEY_NONE }, +}; + + #define ADD_PATCH(vendor, product, patch) \ { (vendor), (product), (patch), sizeof(patch)/sizeof(*patch) } @@ -99,7 +109,11 @@ ADD_PATCH(V_CORSAIR, P_K55_PRO_XT, k55proxtpatch), ADD_PATCH(V_CORSAIR, P_DARK_CORE_RGB_PRO, DCRGBPpatch), ADD_PATCH(V_CORSAIR, P_DARK_CORE_RGB_PRO_SE, DCRGBPpatch), + ADD_PATCH(V_CORSAIR, P_K100_OPTICAL, k100patch), + ADD_PATCH(V_CORSAIR, P_K100_MECHANICAL, k100patch), + ADD_PATCH(V_CORSAIR, P_K70_TKL, k70tklpatch), }; + #define KEYPATCHES_LEN sizeof(mappatches)/sizeof(*mappatches) #define CLEAR_KEYMAP_ENTRY(x) { \ diff -Nru ckb-next-0.6.0-1/src/daemon/led_bragi.c ckb-next-0.6.0-20/src/daemon/led_bragi.c --- ckb-next-0.6.0-1/src/daemon/led_bragi.c 2023-06-07 23:10:44.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/led_bragi.c 2023-06-26 11:00:03.000000000 +0000 @@ -41,6 +41,10 @@ LED_CASE_K(P_K55_PRO_XT, 137); LED_CASE_M(P_DARK_CORE_RGB_PRO, 12); LED_CASE_M(P_DARK_CORE_RGB_PRO_SE, 12); + LED_CASE_K(P_K100_OPTICAL, 193); + LED_CASE_K(P_K100_MECHANICAL, 193); + LED_CASE_K(P_K65_MINI, 123); + LED_CASE_K(P_K70_TKL, 193); default: ckb_err("Unknown product 0x%hx", kb->product); return 0; @@ -110,3 +114,47 @@ int updatergb_keyboard_bragi(usbdevice* kb, int force){ return updatergb_bragi(kb, force, 0); } + +#define BRAGI_ALT_RGB_HEADER 2 +static inline int updatergb_alt_bragi(usbdevice* kb, int force){ + if(!kb->active) + return 0; + lighting* lastlight = &kb->profile->lastlight; + lighting* newlight = &kb->profile->currentmode->light; + + // Ideally this will be moved to the usbdevice struct at some point + const size_t zones = bragi_led_count(kb); + + // Don't do anything if the lighting hasn't changed + if(!force && !lastlight->forceupdate && !newlight->forceupdate + && !rgbcmp(lastlight, newlight, zones, 0)) + return 0; + + uchar pkt1[BRAGI_JUMBO_SIZE] = {0}; + pkt1[7] = 0x12; // Some kind of header? + + uchar* start = pkt1 + 7 + BRAGI_ALT_RGB_HEADER; + // Copy red first + for(size_t i = 0; i < zones; i++) + start[i * 3] = newlight->r[i]; + + // Green + for(size_t i = 0; i < zones; i++) + start[i * 3 + 1] = newlight->g[i]; + + // Blue + for(size_t i = 0; i < zones; i++) + start[i * 3 + 2] = newlight->b[i]; + + if(bragi_write_to_handle(kb, pkt1, BRAGI_LIGHTING_HANDLE, sizeof(pkt1), 3 * zones + BRAGI_ALT_RGB_HEADER)) + return 1; + + lastlight->forceupdate = newlight->forceupdate = 0; + + memcpy(lastlight, newlight, sizeof(lighting)); + return 0; +} + +int updatergb_keyboard_bragi_alt(usbdevice* kb, int force){ + return updatergb_alt_bragi(kb, force); +} diff -Nru ckb-next-0.6.0-1/src/daemon/led.h ckb-next-0.6.0-20/src/daemon/led.h --- ckb-next-0.6.0-1/src/daemon/led.h 2021-06-29 10:45:25.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/led.h 2023-06-26 11:00:03.000000000 +0000 @@ -15,6 +15,7 @@ void apply_hwanim(usbdevice* kb, short zone, uchar anim, uchar speed, uchar rand_or_dir, uchar r[2], uchar g[2], uchar b[2]); int updatergb_mouse_bragi(usbdevice* kb, int force); int updatergb_keyboard_bragi(usbdevice* kb, int force); +int updatergb_keyboard_bragi_alt(usbdevice* kb, int force); // Saves RGB data to device memory. Returns 0 on success. int savergb_kb(usbdevice* kb, lighting* light, int mode); diff -Nru ckb-next-0.6.0-1/src/daemon/usb_bragi.c ckb-next-0.6.0-20/src/daemon/usb_bragi.c --- ckb-next-0.6.0-1/src/daemon/usb_bragi.c 2022-08-08 11:00:06.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/usb_bragi.c 2023-06-26 11:00:03.000000000 +0000 @@ -30,6 +30,10 @@ case P_K57_U: case P_K55_PRO: case P_K55_PRO_XT: + case P_K100_OPTICAL: + case P_K100_MECHANICAL: + case P_K65_MINI: + case P_K70_TKL: kb->bragi_out_ep = 0x1; kb->bragi_in_ep = 0x82; break; diff -Nru ckb-next-0.6.0-1/src/daemon/usb.c ckb-next-0.6.0-20/src/daemon/usb.c --- ckb-next-0.6.0-1/src/daemon/usb.c 2023-06-19 11:00:04.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/usb.c 2023-06-26 11:00:03.000000000 +0000 @@ -74,6 +74,7 @@ { V_CORSAIR, P_K70_MK2, }, { V_CORSAIR, P_K70_MK2SE, }, { V_CORSAIR, P_K70_MK2LP, }, + { V_CORSAIR, P_K70_TKL, }, { V_CORSAIR, P_K90_LEGACY, }, { V_CORSAIR, P_K95, }, { V_CORSAIR, P_K95_LEGACY, }, @@ -85,6 +86,9 @@ { V_CORSAIR, P_K95_PLATINUM_XT, }, { V_CORSAIR, P_K57_D, }, { V_CORSAIR, P_K57_U, }, + { V_CORSAIR, P_K100_OPTICAL, }, + { V_CORSAIR, P_K100_MECHANICAL, }, + { V_CORSAIR, P_K65_MINI, }, // Mice { V_CORSAIR, P_M55_RGB_PRO, }, { V_CORSAIR, P_M65, }, @@ -186,6 +190,8 @@ /// product_str() needs the \a product \a ID /// const char* product_str(ushort product){ + if(product == P_K100_OPTICAL || product == P_K100_MECHANICAL) + return "k100"; if(product == P_K95_LEGACY) return "k95l"; if(product == P_K95) @@ -196,10 +202,14 @@ return "k70"; if(product == P_K70_MK2 || product == P_K70_MK2SE || product == P_K70_MK2LP) return "k70mk2"; + if(product == P_K70_TKL) + return "k70tkl"; if(product == P_K68 || product == P_K68_NRGB) return "k68"; if(product == P_K65 || product == P_K65_LEGACY || product == P_K65_LUX || product == P_K65_RFIRE) return "k65"; + if(product == P_K65_MINI) + return "k65_mini"; if(product == P_K66) return "k66"; if(product == P_K63_NRGB) diff -Nru ckb-next-0.6.0-1/src/daemon/usb.h ckb-next-0.6.0-20/src/daemon/usb.h --- ckb-next-0.6.0-1/src/daemon/usb.h 2023-06-19 11:00:04.000000000 +0000 +++ ckb-next-0.6.0-20/src/daemon/usb.h 2023-06-26 11:00:03.000000000 +0000 @@ -70,7 +70,8 @@ #define P_K65_LEGACY 0x1b07 #define P_K65_LUX 0x1b37 #define P_K65_RFIRE 0x1b39 -#define IS_K65(kb) ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K65 || (kb)->product == P_K65_LEGACY || (kb)->product == P_K65_LUX || (kb)->product == P_K65_RFIRE)) +#define P_K65_MINI 0x1baf +#define IS_K65(kb) ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K65 || (kb)->product == P_K65_LEGACY || (kb)->product == P_K65_LUX || (kb)->product == P_K65_RFIRE || (kb)->product == P_K65_MINI)) #define P_K66 0x1b41 #define IS_K66(kb) ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K66)) @@ -88,7 +89,8 @@ #define P_K70_MK2 0x1b49 #define P_K70_MK2SE 0x1b6b #define P_K70_MK2LP 0x1b55 -#define IS_K70(kb) ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K70 || (kb)->product == P_K70_LEGACY || (kb)->product == P_K70_RFIRE || (kb)->product == P_K70_RFIRE_NRGB || (kb)->product == P_K70_LUX || (kb)->product == P_K70_LUX_NRGB || (kb)->product == P_K70_MK2 || (kb)->product == P_K70_MK2SE || (kb)->product == P_K70_MK2LP)) +#define P_K70_TKL 0x1b73 +#define IS_K70(kb) ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K70 || (kb)->product == P_K70_LEGACY || (kb)->product == P_K70_RFIRE || (kb)->product == P_K70_RFIRE_NRGB || (kb)->product == P_K70_LUX || (kb)->product == P_K70_LUX_NRGB || (kb)->product == P_K70_MK2 || (kb)->product == P_K70_MK2SE || (kb)->product == P_K70_MK2LP || (kb)->product == P_K70_TKL)) // The Legacy K90 behaves like a Legacy K95. #define P_K90_LEGACY 0x1b02 @@ -104,7 +106,11 @@ #define P_STRAFE_MK2 0x1b48 #define IS_STRAFE(kb) ((kb)->vendor == V_CORSAIR && ((kb)->product == P_STRAFE || (kb)->product == P_STRAFE_NRGB || (kb)->product == P_STRAFE_NRGB_2 || (kb)->product == P_STRAFE_MK2)) +#define P_K100_OPTICAL 0x1b7c +#define P_K100_MECHANICAL 0x1b7d + #define P_M55_RGB_PRO 0x1b70 + #define P_M65 0x1b12 #define P_M65_PRO 0x1b2e #define P_M65_RGB_ELITE 0x1b5a @@ -240,7 +246,7 @@ #define IS_MOUSEPAD_DEV(kb) IS_MOUSEPAD((kb)->vendor, (kb)->product) // Devices that are considered experimental and are either not fully tested, or aren't fully implemented -#define IS_EXPERIMENTAL(vendor, product) ((vendor) == V_CORSAIR && ((product) == P_K63_NRGB_WL || (product) == P_K63_NRGB_WL2 || (product) == P_K63_NRGB_WL3 || (product) == P_K63_NRGB_WL4 || (product) == P_DARK_CORE || (product) == P_DARK_CORE_WL || (product) == P_DARK_CORE_SE || (product) == P_DARK_CORE_SE_WL || (product) == P_IRONCLAW_W_U || (product) == P_IRONCLAW_W_D || (product) == P_DARK_CORE_RGB_PRO_SE || (product) == P_DARK_CORE_RGB_PRO_SE_WL || (product) == P_HARPOON_WL_U || (product) == P_HARPOON_WL_D || (product) == P_K57_U || (product) == P_K57_D || (product) == P_DARK_CORE_RGB_PRO || (product) == P_DARK_CORE_RGB_PRO_WL || (product) == P_GENERIC_BRAGI_DONGLE)) +#define IS_EXPERIMENTAL(vendor, product) ((vendor) == V_CORSAIR && ((product) == P_K63_NRGB_WL || (product) == P_K63_NRGB_WL2 || (product) == P_K63_NRGB_WL3 || (product) == P_K63_NRGB_WL4 || (product) == P_DARK_CORE || (product) == P_DARK_CORE_WL || (product) == P_DARK_CORE_SE || (product) == P_DARK_CORE_SE_WL || (product) == P_IRONCLAW_W_U || (product) == P_IRONCLAW_W_D || (product) == P_DARK_CORE_RGB_PRO_SE || (product) == P_DARK_CORE_RGB_PRO_SE_WL || (product) == P_HARPOON_WL_U || (product) == P_HARPOON_WL_D || (product) == P_K57_U || (product) == P_K57_D || (product) == P_DARK_CORE_RGB_PRO || (product) == P_DARK_CORE_RGB_PRO_WL || (product) == P_GENERIC_BRAGI_DONGLE || (product) == P_K65_MINI)) /// Some devices cause usbhid to spend a long time initialising it. To work around this, we intentionally uncleanly /// deinitialise the device, skipping the usbhid handover. @@ -288,10 +294,10 @@ clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = 30000000}, NULL) // This should be removed in the future when we implement autodetection -#define USES_BRAGI(vendor, product) ((vendor) == (V_CORSAIR) && ((product) == (P_M55_RGB_PRO) || (product) == (P_IRONCLAW_W_U) || (product) == (P_IRONCLAW_W_D) || (product) == (P_K95_PLATINUM_XT) || (product) == (P_DARK_CORE_RGB_PRO_SE) || (product) == (P_DARK_CORE_RGB_PRO_SE_WL) || (product) == P_HARPOON_WL_U || (product) == P_HARPOON_WL_D || (product) == P_K57_U || (product) == P_K57_D || (product) == P_KATAR_PRO_XT || (product) == P_KATAR_PRO || (product) == P_K60_PRO_RGB || (product) == P_K60_PRO_RGB_LP || (product) == P_K60_PRO_RGB_SE || (product) == P_K60_PRO_MONO || (product) == P_K60_PRO_TKL || (product) == P_K55_PRO || (product) == P_K55_PRO_XT || (product) == (P_DARK_CORE_RGB_PRO) || (product) == (P_DARK_CORE_RGB_PRO_WL) || (product) == P_GENERIC_BRAGI_DONGLE)) +#define USES_BRAGI(vendor, product) ((vendor) == (V_CORSAIR) && ((product) == (P_M55_RGB_PRO) || (product) == (P_IRONCLAW_W_U) || (product) == (P_IRONCLAW_W_D) || (product) == (P_K95_PLATINUM_XT) || (product) == (P_DARK_CORE_RGB_PRO_SE) || (product) == (P_DARK_CORE_RGB_PRO_SE_WL) || (product) == P_HARPOON_WL_U || (product) == P_HARPOON_WL_D || (product) == P_K57_U || (product) == P_K57_D || (product) == P_KATAR_PRO_XT || (product) == P_KATAR_PRO || (product) == P_K60_PRO_RGB || (product) == P_K60_PRO_RGB_LP || (product) == P_K60_PRO_RGB_SE || (product) == P_K60_PRO_MONO || (product) == P_K60_PRO_TKL || (product) == P_K55_PRO || (product) == P_K55_PRO_XT || (product) == (P_DARK_CORE_RGB_PRO) || (product) == (P_DARK_CORE_RGB_PRO_WL) || (product) == P_GENERIC_BRAGI_DONGLE || (product) == P_K100_OPTICAL || (product) == P_K100_MECHANICAL || (product) == P_K65_MINI || (product) == P_K70_TKL)) // Devices that use bragi jumbo packets (1024 bytes) -#define USES_BRAGI_JUMBO(vendor, product) ((vendor) == (V_CORSAIR) && 0) +#define USES_BRAGI_JUMBO(vendor, product) ((vendor) == (V_CORSAIR) && ((product) == P_K100_OPTICAL || (product) == P_K100_MECHANICAL || (product) == P_K65_MINI || (product) == P_K70_TKL)) // Used for devices that have the scroll wheel packet in the hardware hid packet only #define SW_PKT_HAS_NO_WHEEL(kb) ((kb)->vendor == V_CORSAIR && ((kb)->product == P_M55_RGB_PRO || (kb)->product == P_KATAR_PRO_XT || (kb)->product == P_KATAR_PRO)) diff -Nru ckb-next-0.6.0-1/src/gui/ckbsystemquirks.cpp ckb-next-0.6.0-20/src/gui/ckbsystemquirks.cpp --- ckb-next-0.6.0-1/src/gui/ckbsystemquirks.cpp 2023-06-07 23:10:44.000000000 +0000 +++ ckb-next-0.6.0-20/src/gui/ckbsystemquirks.cpp 2023-06-26 11:00:03.000000000 +0000 @@ -46,7 +46,7 @@ QDir d = fi.dir(); QProcess p; - p.start(d.filePath(utility)); + p.start(d.filePath(utility), QStringList()); // Note: On some UNIX operating systems, this function may return true // but the process may later report a QProcess::FailedToStart error. // ^ Applies to waitForFinished() too as it internally calls waitForStarted() in this scenario @@ -54,7 +54,7 @@ if(!started || p.error() == QProcess::FailedToStart) { d.setPath(CKB_NEXT_UTILITIES_PATH); - p.start(d.filePath(utility)); + p.start(d.filePath(utility), QStringList()); started = p.waitForFinished(5000); } if(!started || p.error() != QProcess::UnknownError || p.exitStatus() != QProcess::NormalExit || diff -Nru ckb-next-0.6.0-1/src/gui/kbperf.cpp ckb-next-0.6.0-20/src/gui/kbperf.cpp --- ckb-next-0.6.0-1/src/gui/kbperf.cpp 2023-06-07 20:45:26.000000000 +0000 +++ ckb-next-0.6.0-20/src/gui/kbperf.cpp 2023-06-26 11:00:03.000000000 +0000 @@ -510,9 +510,10 @@ } } // KB indicators - // Disable the M indicators for the K70MK2 and the STRAFE_MK2. + // Disable the M indicators for the K70MK2, the STRAFE_MK2, and the K70_TKL. // FIXME: Only enable them for devices that need them instead - if(iEnable[MODE] && !(this->modeParent()->bind()->map().model() == KeyMap::K70MK2 || this->modeParent()->bind()->map().model() == KeyMap::STRAFE_MK2)){ + if(iEnable[MODE] && !(this->modeParent()->bind()->map().model() == KeyMap::K70MK2 || + this->modeParent()->bind()->map().model() == KeyMap::STRAFE_MK2)){ for(uchar i = 0; i < Kb::HWMODE_MAX; i++){ char name[4]; snprintf(name, sizeof(name), "m%d", i + 1); diff -Nru ckb-next-0.6.0-1/src/gui/keymap.cpp ckb-next-0.6.0-20/src/gui/keymap.cpp --- ckb-next-0.6.0-1/src/gui/keymap.cpp 2023-06-19 11:00:04.000000000 +0000 +++ ckb-next-0.6.0-20/src/gui/keymap.cpp 2023-06-26 11:00:03.000000000 +0000 @@ -227,6 +227,9 @@ #define K95P_X_START 20 #define K95P_WIDTH (K95_WIDTH - K95P_X_START + 1) +#define K100_HEIGHT (K95P_HEIGHT + 6) +#define K100_WIDTH (K95P_WIDTH + 10) + // K70 cuts off the G keys on the left, as well as MR/M1/M2/M3 #define K70_X_START 38 #define K70_WIDTH (K95_WIDTH - K70_X_START) @@ -239,6 +242,9 @@ #define K65_WIDTH 209 #define K65_HEIGHT K70_HEIGHT +#define K65_MINI_WIDTH 162 +#define K65_MINI_HEIGHT 48 + // K63 is the same as the K65 in terms of size #define K63_WIDTH K65_WIDTH #define K63_HEIGHT K65_HEIGHT @@ -252,6 +258,17 @@ #define K60_TKL_HEIGHT K60_HEIGHT +static const Key K70TklTopRow[] = { + {nullptr, "Stop", "stop", K70_X_START - 37, 0, 12, 8, true, true}, + {nullptr, "Previous", "prev", K70_X_START - 26, 0, 12, 8, true, true}, + {nullptr, "Play/Pause", "play", K70_X_START - 15, 0, 12, 8, true, true}, + {nullptr, "Next", "next", K70_X_START - 4, 0, 12, 8, true, true}, + {nullptr, "Logo", "logo", 140 - K70_X_START, 0, 12, 12, true, false}, + {nullptr, "Profile Switch", "profswitch", 178 - K70_X_START, 0, 12, 8, true, true}, + {nullptr, "Mute", "mute", 222 - K70_X_START, 0, 12, 8, true, true}, +}; +#define K70_TKL_TOP_COUNT (sizeof(K70TklTopRow) / sizeof(Key)) + static const Key K68TopRow[] = { {nullptr, "Volume Down", "voldn", 285 - K70_X_START, 0, 13, 8, true, true}, {nullptr, "Volume Up", "volup", 297 - K70_X_START, 0, 13, 8, true, true}, }; @@ -419,10 +436,10 @@ // K95 Platinum lightbar static const Key K95PLbar[] = { - {nullptr, nullptr, "topbar1", 4, -3, LBS, true, false}, {nullptr, nullptr, "topbar2", 19, -3, LBS, true, false}, {nullptr, nullptr, "topbar3", 34, -3, LBS, true, false}, {nullptr, nullptr, "topbar4", 49, -3, LBS, true, false}, {nullptr, nullptr, "topbar5", 64, -3, LBS, true, false}, {nullptr, nullptr, "topbar6", 79, -3, LBS, true, false}, - {nullptr, nullptr, "topbar7", 94, -3, LBS, true, false}, {nullptr, nullptr, "topbar8", 109, -3, LBS, true, false}, {nullptr, nullptr, "topbar9", 124, -3, LBS, true, false}, {nullptr, nullptr, "topbar10", 139, -3, LBS, true, false}, {nullptr, nullptr, "topbar11", 154, -3, LBS, true, false}, {nullptr, nullptr, "topbar12", 169, -3, LBS, true, false}, - {nullptr, nullptr, "topbar13", 184, -3, LBS, true, false}, {nullptr, nullptr, "topbar14", 199, -3, LBS, true, false}, {nullptr, nullptr, "topbar15", 214, -3, LBS, true, false}, {nullptr, nullptr, "topbar16", 229, -3, LBS, true, false}, {nullptr, nullptr, "topbar17", 244, -3, LBS, true, false}, {nullptr, nullptr, "topbar18", 259, -3, LBS, true, false}, - {nullptr, nullptr, "topbar19", 274, -3, LBS, true, false}, + {nullptr, "Top Light Bar 1", "topbar1", 4, -3, LBS, true, false}, {nullptr, "Top Light Bar 2", "topbar2", 19, -3, LBS, true, false}, {nullptr, "Top Light Bar 3", "topbar3", 34, -3, LBS, true, false}, {nullptr, "Top Light Bar 4", "topbar4", 49, -3, LBS, true, false}, {nullptr, "Top Light Bar 5", "topbar5", 64, -3, LBS, true, false}, {nullptr, "Top Light Bar 6", "topbar6", 79, -3, LBS, true, false}, + {nullptr, "Top Light Bar 7", "topbar7", 94, -3, LBS, true, false}, {nullptr, "Top Light Bar 8", "topbar8", 109, -3, LBS, true, false}, {nullptr, "Top Light Bar 9", "topbar9", 124, -3, LBS, true, false}, {nullptr, "Top Light Bar 10", "topbar10", 139, -3, LBS, true, false}, {nullptr, "Top Light Bar 11", "topbar11", 154, -3, LBS, true, false}, {nullptr, "Top Light Bar 12", "topbar12", 169, -3, LBS, true, false}, + {nullptr, "Top Light Bar 13", "topbar13", 184, -3, LBS, true, false}, {nullptr, "Top Light Bar 14", "topbar14", 199, -3, LBS, true, false}, {nullptr, "Top Light Bar 15", "topbar15", 214, -3, LBS, true, false}, {nullptr, "Top Light Bar 16", "topbar16", 229, -3, LBS, true, false}, {nullptr, "Top Light Bar 17", "topbar17", 244, -3, LBS, true, false}, {nullptr, "Top Light Bar 18", "topbar18", 259, -3, LBS, true, false}, + {nullptr, "Top Light Bar 19", "topbar19", 274, -3, LBS, true, false}, }; #define LBARCOUNT_K95P (sizeof(K95PLbar) / sizeof(Key)) @@ -732,6 +749,82 @@ break; } + case KeyMap::K100:{ + map = getMap(KeyMap::K95P, layout); + // Shift everything down except the existing topbar + QMutableHashIterator i(map); + while(i.hasNext()){ + i.next(); + if(!i.key().contains("topbar")) + i.value().y += (K100_HEIGHT - K95P_HEIGHT); + + i.value().x += (K100_WIDTH - K95P_WIDTH)/2; + } + // Shrink the top lightbar and add the extra three items + for(int j = 0; j < 19; j++){ + QString key = QString("topbar%1").arg(j + 1); + map[key].width = 15; // maybe 15 + map[key].x -= j * 2 + 1; + } + map["topbar20"] = {nullptr, "Top Light Bar 20", "topbar20", 255, -3, 15, 6, true, false}; + map["topbar21"] = {nullptr, "Top Light Bar 21", "topbar21", 268, -3, 15, 6, true, false}; + map["topbar22"] = {nullptr, "Top Light Bar 22", "topbar22", 281, -3, 15, 6, true, false}; + + // Add the left and right bars + map["leftbar1"] = {nullptr, "Left Light Bar 1", "leftbar1", -2, -2, 6, 9, true, false}; + map["leftbar2"] = {nullptr, "Left Light Bar 2", "leftbar2", -2, 7, 6, 9, true, false}; + map["leftbar3"] = {nullptr, "Left Light Bar 3", "leftbar3", -2, 16, 6, 9, true, false}; + map["leftbar4"] = {nullptr, "Left Light Bar 4", "leftbar4", -2, 25, 6, 9, true, false}; + map["leftbar5"] = {nullptr, "Left Light Bar 5", "leftbar5", -2, 34, 6, 9, true, false}; + map["leftbar6"] = {nullptr, "Left Light Bar 6", "leftbar6", -2, 43, 6, 9, true, false}; + map["leftbar7"] = {nullptr, "Left Light Bar 7", "leftbar7", -2, 52, 6, 9, true, false}; + map["leftbar8"] = {nullptr, "Left Light Bar 8", "leftbar8", -2, 61, 6, 9, true, false}; + map["leftbar9"] = {nullptr, "Left Light Bar 9", "leftbar9", -2, 70, 6, 9, true, false}; + map["leftbar10"] = {nullptr, "Left Light Bar 10", "leftbar10", -2, 79, 6, 9, true, false}; + map["leftbar11"] = {nullptr, "Left Light Bar 11", "leftbar11", -2, 88, 6, 9, true, false}; + + map["rightbar1"] = {nullptr, "Right Light Bar 1", "rightbar1", 292, -2, 6, 9, true, false}; + map["rightbar2"] = {nullptr, "Right Light Bar 2", "rightbar2", 292, 7, 6, 9, true, false}; + map["rightbar3"] = {nullptr, "Right Light Bar 3", "rightbar3", 292, 16, 6, 9, true, false}; + map["rightbar4"] = {nullptr, "Right Light Bar 4", "rightbar4", 292, 25, 6, 9, true, false}; + map["rightbar5"] = {nullptr, "Right Light Bar 5", "rightbar5", 292, 34, 6, 9, true, false}; + map["rightbar6"] = {nullptr, "Right Light Bar 6", "rightbar6", 292, 43, 6, 9, true, false}; + map["rightbar7"] = {nullptr, "Right Light Bar 7", "rightbar7", 292, 52, 6, 9, true, false}; + map["rightbar8"] = {nullptr, "Right Light Bar 8", "rightbar8", 292, 61, 6, 9, true, false}; + map["rightbar9"] = {nullptr, "Right Light Bar 9", "rightbar9", 292, 70, 6, 9, true, false}; + map["rightbar10"] = {nullptr, "Right Light Bar 10", "rightbar10", 292, 79, 6, 9, true, false}; + map["rightbar11"] = {nullptr, "Right Light Bar 11", "rightbar11", 292, 88, 6, 9, true, false}; + + map["ctrlwheelb"] = map["light"]; + map["ctrlwheelb"].name = "ctrlwheelb"; + map["ctrlwheelb"]._friendlyName = "Control Wheel Button"; + map["ctrlwheelb"].height = map["ctrlwheelb"].width; + map["ctrlwheelb"].y -= 3; + + map["profswitch"].height += 1; + map["lock"].height = map["mute"].height = map["profswitch"].height; + map["mute"].y = map["profswitch"].y = map["lock"].y = map["ctrlwheelb"].y; + map["volup"].y = map["ctrlwheelb"].y - 2; + map["voldn"].y = map["ctrlwheelb"].y + 2; + map["profswitch"].x -= 1; + map["lock"].x += 1; + + map["ctrlwheel1"] = {nullptr, "Control Wheel 22.5°", "ctrlwheel1", 60+2, 10, 8, 6, true, false}; + map["ctrlwheel2"] = {nullptr, "Control Wheel 67.5°", "ctrlwheel2", 60+3, 10+1, 5, 8, true, false}; + map["ctrlwheel3"] = {nullptr, "Control Wheel 112.5°", "ctrlwheel3", 60+3, 10+2, 5, 8, true, false}; + map["ctrlwheel4"] = {nullptr, "Control Wheel 157.5°", "ctrlwheel4", 60+2, 10+3, 8, 6, true, false}; + map["ctrlwheel5"] = {nullptr, "Control Wheel 202.5°", "ctrlwheel5", 60+1, 10+3, 8, 6, true, false}; + map["ctrlwheel6"] = {nullptr, "Control Wheel 247.5°", "ctrlwheel6", 60, 10+2, 5, 8, true, false}; + map["ctrlwheel7"] = {nullptr, "Control Wheel 292.5°", "ctrlwheel7", 60, 10+1, 5, 8, true, false}; + map["ctrlwheel8"] = {nullptr, "Control Wheel 337.5°", "ctrlwheel8", 60+1, 10, 8, 6, true, false}; + + map["logoleft"] = {nullptr, "Logo Left", "logoleft", 134, 10, 10, 10, true, false}; + map["logo"] = {nullptr, "Logo", "logo", 144, 10, 10, 10, true, false}; + map["logoright"] = {nullptr, "Logo Right", "logoright", 154, 10, 10, 10, true, false}; + + map.remove("light"); + break; + } case KeyMap::K70:{ // The K70 maps are based on the K95 maps. However all the keys are shifted left and the G keys are removed map = getMap(KeyMap::K95, layout); @@ -776,6 +869,21 @@ map["voldn"].x -= 10; break; } + case KeyMap::K70_TKL:{ + // Same width as the K63 but with a top row more like the K70 + map = getMap(KeyMap::K63, layout); + for(const Key* key = K70TklTopRow; key < K70TklTopRow + K70_TKL_TOP_COUNT; key++) + map[key->name] = *key; + + map.remove("rwin"); + map["fn"] = KStrafeKeys[3]; + map["fn"].x -= 12; + map["light"].x = 190 - K70_X_START; + map["light"].height = 8; + map["lock"].x = 202 - K70_X_START; + map["lock"].height = 8; + break; + } case KeyMap::STRAFE_MK2:{ map = getMap(KeyMap::K70MK2, layout); // move everything right to make the space for the left sidelight @@ -828,6 +936,26 @@ // Done! break; } + case KeyMap::K65_MINI:{ + map = getMap(KeyMap::K65, layout); + + // Move Esc so that it doesn't get deleted + map["esc"].y += 13; + map.remove("grave"); + + // Remove the whole top bar and shift everything up + QMutableHashIterator i(map); + while(i.hasNext()){ + i.next(); + + if((i.value().y -= 27) < 0) + i.remove(); + else if((i.value().x -= 3) > K65_MINI_WIDTH + 2) + i.remove(); + } + + break; + } case KeyMap::K63:{ // Similar to the K65 but without the Fn key and a modified top row map = getMap(KeyMap::K70, layout); @@ -900,7 +1028,7 @@ map["fn"] = KStrafeKeys[3]; map["fn"].x = map["rwin"].x; map.remove("rwin"); - + QMutableHashIterator i(map); while(i.hasNext()){ i.next(); @@ -1490,6 +1618,8 @@ return ST100; if(lower == "k70mk2") return K70MK2; + if(lower == "k70tkl") + return K70_TKL; if(lower == "strafe_mk2") return STRAFE_MK2; if(lower == "m65e") @@ -1510,6 +1640,10 @@ return K55PRO; if(lower == "bragi_dongle") return BRAGI_DONGLE; + if(lower == "k100") + return K100; + if(lower == "k65_mini") + return K65_MINI; return NO_MODEL; } @@ -1569,6 +1703,8 @@ return "st100"; case K70MK2: return "k70mk2"; + case K70_TKL: + return "k70tkl"; case STRAFE_MK2: return "strafe_mk2"; case M65E: @@ -1587,6 +1723,10 @@ return "glaivepro"; case BRAGI_DONGLE: return "bragi_dongle"; + case K100: + return "k100"; + case K65_MINI: + return "k65_mini"; default: return ""; } @@ -1607,9 +1747,12 @@ return K60_TKL_WIDTH; case K63: case K63_WL: + case K70_TKL: return K63_WIDTH; case K65: return K65_WIDTH; + case K65_MINI: + return K65_MINI_WIDTH; case K66: case K68: return K68_WIDTH; @@ -1625,6 +1768,8 @@ case K55: case K57_WL: return K95P_WIDTH; + case K100: + return K100_WIDTH; case STRAFE: case STRAFE_MK2: return KSTRAFE_WIDTH; @@ -1666,6 +1811,7 @@ case K68: case K70: case K70MK2: + case K70_TKL: case K95: case K95L: case STRAFE: @@ -1673,10 +1819,14 @@ return K95_HEIGHT; case K95P: return K95P_HEIGHT; + case K100: + return K100_HEIGHT; case K60: return K60_HEIGHT; case K60_TKL: return K60_TKL_HEIGHT; + case K65_MINI: + return K65_MINI_HEIGHT; case M55: case M65: case M65E: diff -Nru ckb-next-0.6.0-1/src/gui/keymap.h ckb-next-0.6.0-20/src/gui/keymap.h --- ckb-next-0.6.0-1/src/gui/keymap.h 2023-06-19 11:00:04.000000000 +0000 +++ ckb-next-0.6.0-20/src/gui/keymap.h 2023-06-26 11:00:03.000000000 +0000 @@ -88,6 +88,9 @@ DARKCORERGBPRO, K60_TKL, BRAGI_DONGLE, + K100, + K65_MINI, + K70_TKL, _MODEL_MAX }; // Key layouts (ordered alphabetically by name) diff -Nru ckb-next-0.6.0-1/src/gui/keywidget.cpp ckb-next-0.6.0-20/src/gui/keywidget.cpp --- ckb-next-0.6.0-1/src/gui/keywidget.cpp 2023-06-22 22:16:39.000000000 +0000 +++ ckb-next-0.6.0-20/src/gui/keywidget.cpp 2023-06-26 11:00:03.000000000 +0000 @@ -63,8 +63,56 @@ #endif } +static inline int calculateControlWheelOffset(int d){ + //return abs((d % 7) - 3); + switch(d) + { + case 1: + case 8: + case 9: + return 0; + case 2: + case 7: + case 10: + return 1; + case 3: + case 6: + return 2; + case 4: + case 5: + return 3; + default: + return -1; + } +} + static inline QRectF getKeyRect(const Key& key){ - return QRectF(QPointF(key.x, key.y) - QPointF(key.width, key.height) / 2.f + QPointF(1.f, 1.f), QSize(key.width, key.height) - QSize(2, 2)); + QRectF keyRect(QPointF(key.x, key.y) - QPointF(key.width, key.height) / 2.f + QPointF(1.f, 1.f), QSize(key.width, key.height) - QSize(2, 2)); + // Special case for the pie-shaped ctrl wheel segments + // We pretend they are small rectangles instead + if(!strncmp(key.name, "ctrlwheel", 9)){ + int d; + if(sscanf(key.name + 9, "%d", &d) == 1) { + const int offX = calculateControlWheelOffset(d + 2); + const int offY = calculateControlWheelOffset(d); + float newX = keyRect.x() + offX * 5.5f - 6.5f; + float newY = keyRect.y() + offY * 5.5f - 6.5f; + + // These are intended to "stack" + if(offX > 0) + newX -= 2.7f; + if(offX == 3) + newX -= 4.f; + + if(offY > 0) + newY -= 2.7f; + if(offY == 3) + newY -= 4.f; + + keyRect.moveTo(newX, newY); + } + } + return keyRect; } void KeyWidget::map(const KeyMap& newMap){ @@ -292,6 +340,7 @@ // Draw key backgrounds painter.setPen(Qt::NoPen); int i = -1; + int d; for(const Key& key : keyMap){ i++; float x = key.x + drawInfoOffset.x() - key.width / 2.f + 1.f; @@ -327,8 +376,9 @@ painter.setOpacity(0.7); } } - if((model != KeyMap::STRAFE && model != KeyMap::K95P && model != KeyMap::K70MK2 && model != KeyMap::STRAFE_MK2) && (!strcmp(key.name, "mr") || !strcmp(key.name, "m1") || !strcmp(key.name, "m2") || !strcmp(key.name, "m3") - || !strcmp(key.name, "light") || !strcmp(key.name, "lock") || !strcmp(key.name, "lghtpgm") || (model == KeyMap::K65 && !strcmp(key.name, "mute")))){ + if(((model != KeyMap::STRAFE && model != KeyMap::K95P && model != KeyMap::K100 && model != KeyMap::K70MK2 && model != KeyMap::STRAFE_MK2 && model != KeyMap::K70_TKL) && (!strcmp(key.name, "mr") || !strcmp(key.name, "m1") || !strcmp(key.name, "m2") || !strcmp(key.name, "m3") + || !strcmp(key.name, "light") || !strcmp(key.name, "lock") || !strcmp(key.name, "lghtpgm") || (model == KeyMap::K65 && !strcmp(key.name, "mute")))) || + !strcmp(key.name, "ctrlwheelb")){ // Not all devices have circular buttons x += w / 8.f; y += h / 8.f; @@ -355,12 +405,42 @@ drawTopLeftCorner(&painter, x, y, w, h, drawInfoScale); } else painter.drawRect(QRectF(x * drawInfoScale, y * drawInfoScale, w * drawInfoScale, h * drawInfoScale)); - } else if ((model == KeyMap::K70MK2 || model == KeyMap::STRAFE_MK2) && key.friendlyName().startsWith("Logo")) { + } else if ((model == KeyMap::K70MK2 || model == KeyMap::STRAFE_MK2 || model == KeyMap::K70_TKL) && key.friendlyName().startsWith("Logo")) { w += 10.f; x -= 5.f; painter.drawRect(QRectF(x * drawInfoScale, y * drawInfoScale, w * drawInfoScale, h * drawInfoScale)); } else if (model == KeyMap::M95) { painter.drawRect(QRectF(x * drawInfoScale, y * drawInfoScale, w * drawInfoScale, h * drawInfoScale)); + } else if (sscanf(key.name, "ctrlwheel%d", &d) == 1) { + // Undo the offset in the keymap definition + // Hardcode (20, 20) here so that key.width and key.height can be used for the hover rectangles + x = key.x - calculateControlWheelOffset(d + 2) + drawInfoOffset.x() - 20 / 2.f + 1.f; + y = key.y - calculateControlWheelOffset(d) + drawInfoOffset.y() - 20 / 2.f + 1.f; + w = h = 20 - 2.f; + float bx = x + 5.f; + float by = y + 5.f; + float bw = w - 10.f; + float bh = h - 10.f; + + int angle = 90 - 45 * (d - 1); + + // Create a pie + QPainterPath p; + QRectF rect = QRectF(x * drawInfoScale, y * drawInfoScale, w * drawInfoScale, h * drawInfoScale); + p.moveTo(rect.center()); + p.arcTo(rect, angle, -45); + + // Create a smaller inner circle + QPainterPath p2; + QRectF rect2 = QRectF(bx * drawInfoScale, by * drawInfoScale, bw * drawInfoScale, bh * drawInfoScale); + p2.moveTo(rect2.center()); + p2.arcTo(rect2, angle, 360); + + // Draw their difference + painter.drawPath(p-p2); + //QPainterPath diff = p - p2; + + //bgPainter.drawRect(diff.boundingRect() - QMarginsF(1*scale, 1*scale, 1*scale, 1*scale)); } else { if(!strcmp(key.name, "enter")){ if(key.height == 24){ @@ -462,7 +542,36 @@ painter.drawRect(QRectF(x * drawInfoScale, y * drawInfoScale, w * drawInfoScale, h * drawInfoScale)); else if ((model == KeyMap::K70MK2 || model == KeyMap::STRAFE_MK2) && key.friendlyName() == "Logo 2") painter.drawRect(QRectF((key.x + drawInfoOffset.x() - key.width / 2.f - 2.f) * drawInfoScale, y * drawInfoScale, (key.width + 4.f) * drawInfoScale, h * drawInfoScale)); - else + else if (sscanf(key.name, "ctrlwheel%d", &d) == 1){ + // Hardcode (20, 20) here so that key.width and key.height can be used for the hover rectangles + x = key.x - calculateControlWheelOffset(d + 2) + drawInfoOffset.x() - 20 / 2.f + 2.5f; + y = key.y - calculateControlWheelOffset(d) + drawInfoOffset.y() - 20 / 2.f + 2.5f; + w = 20 - 5.f; + h = 20 - 5.f; + + float bx = x + 2.f; + float by = y + 2.f; + float bw = w - 4.f; + float bh = h - 4.f; + + int angle = 90 - 45 * (d - 1); + + // Create a pie + QPainterPath p; + QRectF rect = QRectF(x * drawInfoScale, y * drawInfoScale, w * drawInfoScale, h * drawInfoScale); + p.moveTo(rect.center()); + p.arcTo(rect, angle, -45); + + // Create a smaller inner circle + QPainterPath p2; + QRectF rect2 = QRectF(bx * drawInfoScale, by * drawInfoScale, bw * drawInfoScale, bh * drawInfoScale); + p2.moveTo(rect2.center()); + p2.arcTo(rect2, angle, 360); + + // Draw their difference + painter.drawPath(p-p2); + + } else painter.drawEllipse(QRectF(x * drawInfoScale, y * drawInfoScale, w * drawInfoScale, h * drawInfoScale)); } } else {