daemon: Add support for K70 Core RGB

Squashed commit of the following:

    commit 6690642900
    Author: Joseph Crowell <[email protected]>
    Date:   Thu Jul 3 08:25:40 2025 +1000

        don't spam on key up

    commit 5310cd14ac
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jul 2 20:17:06 2025 +1000

        make alignment pretty

    commit 2b55d3d755
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jul 2 20:16:44 2025 +1000

        patch dialpress to mute instead of making it it's own thing

    commit 790882680c
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jul 2 20:15:41 2025 +1000

        fix key play patch

    commit 0594f5a378
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jul 2 20:15:10 2025 +1000

        make  handle_bragi_media_keys static inline

    commit 200275fb44
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jul 2 19:46:02 2025 +1000

        fix keymaps

    commit 333dc57f81
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jul 2 19:39:07 2025 +1000

        move handle_bragi_media_keys to seperate function

    commit 74063c75e9
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jul 2 16:41:11 2025 +1000

        rework dial handling

    commit 49da20fb08
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jul 2 13:47:32 2025 +1000

        change dialpress to KEY_CORSAIR

    commit a3307409eb
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jul 2 13:20:20 2025 +1000

        use BRAGI_INPUT_DIAL define properly and get volume dial working without clearing keybits

    commit ba4d25bf70
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Jun 11 13:28:34 2025 +1000

        handle NKRO_MEDIA_IN with both length 3 and 5 with a single if statement

    commit 98be649794
    Author: Joseph Crowell <[email protected]>
    Date:   Sat May 31 18:31:52 2025 +1000

        change "knobpress" to "dialpress"

    commit 0476625cd7
    Author: Joseph Crowell <[email protected]>
    Date:   Sun May 25 02:12:19 2025 +1000

        remove K70 Core RGB from USES_FILE_HWSAVE define

    commit d0fcfe0e12
    Author: Joseph Crowell <[email protected]>
    Date:   Sun May 25 02:01:08 2025 +1000

        put the error on a single line

    commit 37656d0a74
    Author: Joseph Crowell <[email protected]>
    Date:   Sun May 25 01:33:40 2025 +1000

        remove extra whitespace

    commit cf42962df4
    Author: Joseph Crowell <[email protected]>
    Date:   Sun May 25 00:58:37 2025 +1000

        Revert "define some key in constants and use them"

        This reverts commit 9617b16dd9.

    commit b157f58ebc
    Author: Joseph Crowell <[email protected]>
    Date:   Fri Apr 11 12:03:34 2025 +1000

        remove the the K70 Core RGB from DEV_HAS_VOLWHEEL exclusions

    commit f49213b565
    Author: Joseph Crowell <[email protected]>
    Date:   Fri Apr 11 10:36:44 2025 +1000

        correct the comment

    commit 0549ed5997
    Author: Joseph Crowell <[email protected]>
    Date:   Thu Apr 10 20:04:19 2025 +1000

        remove debug messages

    commit f932d83df6
    Author: Joseph Crowell <[email protected]>
    Date:   Thu Apr 10 19:59:02 2025 +1000

        get all media keys working in GUI mode

    commit 59de92473b
    Author: Joseph Crowell <[email protected]>
    Date:   Thu Apr 10 19:57:18 2025 +1000

        add K70 Core RGB check

    commit 1b8e78fbb4
    Author: Joseph Crowell <[email protected]>
    Date:   Thu Apr 10 00:47:40 2025 +1000

        add urbinput[0] == NKRO_MEDIA_IN && length == 5 back in. this works when the daemon is running without the GUI

    commit 910de31f79
    Author: Joseph Crowell <[email protected]>
    Date:   Thu Apr 10 00:46:32 2025 +1000

        add error handling for unrecognized keys

    commit 9617b16dd9
    Author: Joseph Crowell <[email protected]>
    Date:   Thu Apr 10 00:45:06 2025 +1000

        define some key in constants and use them

    commit 0701a3d44a
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Apr 9 18:28:31 2025 +1000

        correct comment

    commit 9bcffbdbbf
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Apr 9 18:28:01 2025 +1000

        remove extra space

    commit 876e6da61b
    Author: Joseph Crowell <[email protected]>
    Date:   Wed Apr 9 16:32:55 2025 +1000

        remove NKRO_MEDIA_IN && length == 5 input handling because it wasn't doing anything

    commit 47de05de18
    Author: Trashguy <[email protected]>
    Date:   Fri Dec 6 05:34:22 2024 -0500

        Knob functionality

    commit 378c0555ea
    Author: Trashguy <[email protected]>
    Date:   Wed Dec 4 00:57:30 2024 -0500

        Added support for k70 core rgb

Co-authored-by: Trashguy <[email protected]>
This commit is contained in:
Joseph Crowell
2025-07-28 22:40:47 +03:00
committed by Tasos Sahanidis
co-authored by Trashguy
parent b2fa170855
commit 234ade8128
5 changed files with 138 additions and 57 deletions
+120 -52
View File
@@ -375,7 +375,7 @@ const key keymap_bragi[N_KEYS_BRAGI_PATCH] = {
{ "lbrace", 47, KEY_LEFTBRACE },
{ "rbrace", 48, KEY_RIGHTBRACE },
{ "bslash", 49, KEY_BACKSLASH },
{ "hash", 50, KEY_BACKSLASH_ISO },
{ "hash", 50, KEY_BACKSLASH_ISO },
{ "colon", 51, KEY_SEMICOLON },
{ "quote", 52, KEY_APOSTROPHE },
{ "grave", 53, KEY_GRAVE },
@@ -439,23 +439,23 @@ const key keymap_bragi[N_KEYS_BRAGI_PATCH] = {
{ "ralt", 111, KEY_RIGHTALT },
{ "rwin", 112, KEY_RIGHTMETA },
{ "light", 113, KEY_CORSAIR },
{ "lock", 1, KEY_CORSAIR },
{ "lock", 1, KEY_CORSAIR },
{ "ro", 115, KEY_RO },
{ 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 },
{ "fn", 122, KEY_FN },
{ "stop", 123, KEY_STOPCD },
{ "play", 124, KEY_PLAYPAUSE },
{ "next", 125, KEY_NEXTSONG },
{ "prev", 126, KEY_PREVIOUSSONG },
{ "mr", -1, KEY_CORSAIR },
{ "mr", -1, KEY_CORSAIR },
{ "profswitch", 128, KEY_CORSAIR },
{ 0, -1, KEY_NONE },
{ 0, -1, KEY_NONE },
{ 0, -1, KEY_NONE },
{ 0, -1, KEY_NONE },
{ "g1", 131, KEY_CORSAIR },
{ "g2", 132, KEY_CORSAIR },
{ "g3", 133, KEY_CORSAIR },
@@ -601,7 +601,7 @@ static inline void handle_bragi_key_input(unsigned char* kbinput, const unsigned
} else {
ckb_warn("Unhandled NKRO_KEY_IN length %d in handle_bragi_key_input(), international keys will not function", length);
}
} else if(urbinput[0] == NKRO_MEDIA_IN && length == 3) {
} else if(urbinput[0] == NKRO_MEDIA_IN && (length == 3 || length == 5)) {
// This section is similar to handle_nkro_media_keys(), but with different indices due to the different keymap
// This works because these keys can not be pressed at the same time
CLEAR_KEYBIT(kbinput, 125); // next
@@ -636,12 +636,102 @@ static inline void handle_bragi_key_input(unsigned char* kbinput, const unsigned
case 234:
SET_KEYBIT(kbinput, 104); // voldn
break;
case 0:
break; // key up
default:
ckb_err("Unhandled NKRO_MEDIA_IN length %d first:0x%hhx in handle_bragi_key_input()", length, urbinput[1]);
break;
}
} else {
ckb_err("Invalid length %d and header 0x%hhx combination in handle_bragi_key_input()", length, urbinput[0]);
}
}
static inline void handle_bragi_media_keys(usbdevice* targetkb){
if(BRAGI_HAS_MEDIA_MACRO(targetkb)){
if(IS_K60PRORGB(targetkb)){
// if Fn is pressed
if(ISSET_KEYBIT(targetkb->input.keys, 122)){
// As awful as this hack
bool matched = true;
if(ISSET_KEYBIT(targetkb->input.keys, 62)) { // F5 -> mute
CLEAR_KEYBIT(targetkb->input.keys, 62);
SET_KEYBIT(targetkb->input.keys, 102);
} else if (ISSET_KEYBIT(targetkb->input.keys, 64)) { // F7 -> voldn
CLEAR_KEYBIT(targetkb->input.keys, 64);
SET_KEYBIT(targetkb->input.keys, 104);
} else if (ISSET_KEYBIT(targetkb->input.keys, 65)) { // F8 -> volup
CLEAR_KEYBIT(targetkb->input.keys, 65);
SET_KEYBIT(targetkb->input.keys, 103);
} else if (ISSET_KEYBIT(targetkb->input.keys, 66)) { // F9 -> stop
CLEAR_KEYBIT(targetkb->input.keys, 66);
SET_KEYBIT(targetkb->input.keys, 123);
} else if (ISSET_KEYBIT(targetkb->input.keys, 67)) { // F10 -> prev
CLEAR_KEYBIT(targetkb->input.keys, 67);
SET_KEYBIT(targetkb->input.keys, 126);
} else if (ISSET_KEYBIT(targetkb->input.keys, 68)) { // F11 -> playpause
CLEAR_KEYBIT(targetkb->input.keys, 68);
SET_KEYBIT(targetkb->input.keys, 124);
} else if (ISSET_KEYBIT(targetkb->input.keys, 69)) { // F12 -> next
CLEAR_KEYBIT(targetkb->input.keys, 69);
SET_KEYBIT(targetkb->input.keys, 125);
} else if (ISSET_KEYBIT(targetkb->input.keys, 58)) { // F1 -> winlock
CLEAR_KEYBIT(targetkb->input.keys, 58);
SET_KEYBIT(targetkb->input.keys, 114);
} else if (ISSET_KEYBIT(targetkb->input.keys, 60)) { // F3 -> brightnessdn (not supported, map to generic "light")
CLEAR_KEYBIT(targetkb->input.keys, 60);
SET_KEYBIT(targetkb->input.keys, 113);
} else if (ISSET_KEYBIT(targetkb->input.keys, 61)) { // F4 -> brightnessup (not supported, map to generic "light")
CLEAR_KEYBIT(targetkb->input.keys, 61);
SET_KEYBIT(targetkb->input.keys, 113);
} else {
matched = false;
}
if(matched)
CLEAR_KEYBIT(targetkb->input.keys, 122);
}
}else if(IS_K70CORERGB(targetkb)){
// if Fn is pressed
if(ISSET_KEYBIT(targetkb->input.keys, 122)){
// As awful as this hack
bool matched = true;
if(ISSET_KEYBIT(targetkb->input.keys, 62)) { // F5 -> stop
CLEAR_KEYBIT(targetkb->input.keys, 62);
SET_KEYBIT(targetkb->input.keys, 123);
} if(ISSET_KEYBIT(targetkb->input.keys, 63)) { // F6 -> prev
CLEAR_KEYBIT(targetkb->input.keys, 63);
SET_KEYBIT(targetkb->input.keys, 126);
} else if (ISSET_KEYBIT(targetkb->input.keys, 64)) { // F7 -> play/pause
CLEAR_KEYBIT(targetkb->input.keys, 64);
SET_KEYBIT(targetkb->input.keys, 124);
} else if (ISSET_KEYBIT(targetkb->input.keys, 65)) { // F8 -> next
CLEAR_KEYBIT(targetkb->input.keys, 65);
SET_KEYBIT(targetkb->input.keys, 125);
} else if (ISSET_KEYBIT(targetkb->input.keys, 69)) { // F12 -> supposed to switch knob function (map to ctrlwheelb)
CLEAR_KEYBIT(targetkb->input.keys, 69);
SET_KEYBIT(targetkb->input.keys, 137);
} else if (ISSET_KEYBIT(targetkb->input.keys, 58)) { // F1 -> winlock
CLEAR_KEYBIT(targetkb->input.keys, 58);
SET_KEYBIT(targetkb->input.keys, 114);
} else if (ISSET_KEYBIT(targetkb->input.keys, 59)) { // F2 -> profile switch
CLEAR_KEYBIT(targetkb->input.keys, 59);
SET_KEYBIT(targetkb->input.keys, 128);
} else if (ISSET_KEYBIT(targetkb->input.keys, 60)) { // F3 -> brightnessdn (not supported, map to generic "light")
CLEAR_KEYBIT(targetkb->input.keys, 60);
SET_KEYBIT(targetkb->input.keys, 113);
} else if (ISSET_KEYBIT(targetkb->input.keys, 61)) { // F4 -> brightnessup (not supported, map to generic "light")
CLEAR_KEYBIT(targetkb->input.keys, 61);
SET_KEYBIT(targetkb->input.keys, 113);
} else {
matched = false;
}
if(matched)
CLEAR_KEYBIT(targetkb->input.keys, 122);
}
}
}
}
// We just need the first few buttons only, so realistically it doesn't matter
#define BUTTON_BLD_COUNT 5
@@ -790,46 +880,21 @@ void process_input_urb(void* context, unsigned char* buffer, int urblen, ushort
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
if(BRAGI_HAS_MEDIA_MACRO(targetkb)){
// if Fn is pressed
if(ISSET_KEYBIT(targetkb->input.keys, 122)){
// As awful as this hack
bool matched = true;
if(ISSET_KEYBIT(targetkb->input.keys, 62)) { // F5 -> mute
CLEAR_KEYBIT(targetkb->input.keys, 62);
SET_KEYBIT(targetkb->input.keys, 102);
} else if (ISSET_KEYBIT(targetkb->input.keys, 64)) { // F7 -> voldn
CLEAR_KEYBIT(targetkb->input.keys, 64);
SET_KEYBIT(targetkb->input.keys, 104);
} else if (ISSET_KEYBIT(targetkb->input.keys, 65)) { // F8 -> volup
CLEAR_KEYBIT(targetkb->input.keys, 65);
SET_KEYBIT(targetkb->input.keys, 103);
} else if (ISSET_KEYBIT(targetkb->input.keys, 66)) { // F9 -> stop
CLEAR_KEYBIT(targetkb->input.keys, 66);
SET_KEYBIT(targetkb->input.keys, 123);
} else if (ISSET_KEYBIT(targetkb->input.keys, 67)) { // F10 -> prev
CLEAR_KEYBIT(targetkb->input.keys, 67);
SET_KEYBIT(targetkb->input.keys, 126);
} else if (ISSET_KEYBIT(targetkb->input.keys, 68)) { // F11 -> playpause
CLEAR_KEYBIT(targetkb->input.keys, 68);
SET_KEYBIT(targetkb->input.keys, 124);
} else if (ISSET_KEYBIT(targetkb->input.keys, 69)) { // F12 -> next
CLEAR_KEYBIT(targetkb->input.keys, 69);
SET_KEYBIT(targetkb->input.keys, 125);
} else if (ISSET_KEYBIT(targetkb->input.keys, 58)) { // F1 -> winlock
CLEAR_KEYBIT(targetkb->input.keys, 58);
SET_KEYBIT(targetkb->input.keys, 114);
} else if (ISSET_KEYBIT(targetkb->input.keys, 60)) { // F3 -> brightnessdn (not supported, map to generic "light")
CLEAR_KEYBIT(targetkb->input.keys, 60);
SET_KEYBIT(targetkb->input.keys, 113);
} else if (ISSET_KEYBIT(targetkb->input.keys, 61)) { // F4 -> brightnessup (not supported, map to generic "light")
CLEAR_KEYBIT(targetkb->input.keys, 61);
SET_KEYBIT(targetkb->input.keys, 113);
} else {
matched = false;
}
if(matched)
CLEAR_KEYBIT(targetkb->input.keys, 122);
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
SET_KEYBIT(targetkb->input.keys, 103); // volup
} else {
// Apply fresh key data
SET_KEYBIT(targetkb->input.keys, 104); // voldn
}
}
} else {
@@ -944,6 +1009,9 @@ void handle_nkro_media_keys(unsigned char* kbinput, const unsigned char* urbinpu
case 234:
SET_KEYBIT(kbinput, 131); // voldn
break;
default:
ckb_err("Unhandled NKRO_MEDIA_IN length %d first:0x%hhx in handle_nkro_media_keys()", length, urbinput[1]);
break;
}
}
}
+7 -1
View File
@@ -95,6 +95,11 @@ keypatch k70propatch[] = {
{ 138, "logo", 138, KEY_NONE },
};
keypatch k70corergbpatch[] = {
{ 124, "mr", -1, KEY_CORSAIR },
{ 127, "play", -1, KEY_PLAY },
{ 129, "mute", -1, KEY_MUTE },
};
#define ADD_PATCH(vendor, product, patch) \
{ (vendor), (product), (patch), sizeof(patch)/sizeof(*patch) }
@@ -120,7 +125,8 @@ static const keypatches mappatches[] = {
ADD_PATCH(V_CORSAIR, P_K70_TKL, k70tklpatch),
ADD_PATCH(V_CORSAIR, P_K70_TKL_CHAMP_OPTIC, k70tklpatch),
ADD_PATCH(V_CORSAIR, P_K70_PRO, k70propatch),
ADD_PATCH(V_CORSAIR, P_K70_PRO_OPTIC, k70propatch)
ADD_PATCH(V_CORSAIR, P_K70_PRO_OPTIC, k70propatch),
ADD_PATCH(V_CORSAIR, P_K70_CORE_RGB, k70corergbpatch),
};
#define KEYPATCHES_LEN sizeof(mappatches)/sizeof(*mappatches)
+2
View File
@@ -50,6 +50,8 @@ static inline size_t bragi_led_count(usbdevice* kb){
LED_CASE_K(P_MM700, 3);
LED_CASE_K(P_K70_PRO, 193);
LED_CASE_K(P_K70_PRO_OPTIC, 193);
LED_CASE_K(P_K70_CORE_RGB, 123);
default:
ckb_err("Unknown product 0x%hx", kb->product);
return 0;
+3
View File
@@ -78,6 +78,7 @@ const device_desc models[] = {
{ V_CORSAIR, P_K70_TKL_CHAMP_OPTIC, },
{ V_CORSAIR, P_K70_PRO, },
{ V_CORSAIR, P_K70_PRO_OPTIC, },
{ V_CORSAIR, P_K70_CORE_RGB, },
{ V_CORSAIR, P_K90_LEGACY, },
{ V_CORSAIR, P_K95, },
{ V_CORSAIR, P_K95_LEGACY, },
@@ -211,6 +212,8 @@ const char* product_str(ushort product){
return "k70tkl";
if(product == P_K70_PRO || product == P_K70_PRO_OPTIC)
return "k70pro";
if(product == P_K70_CORE_RGB)
return "k70_core_rgb";
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)
+6 -4
View File
@@ -93,7 +93,9 @@
#define P_K70_TKL_CHAMP_OPTIC 0x1bb9
#define P_K70_PRO 0x1bb3
#define P_K70_PRO_OPTIC 0x1bd4
#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 || (kb)->product == P_K70_PRO || (kb)->product == P_K70_PRO_OPTIC || (kb)->product == P_K70_TKL_CHAMP_OPTIC))
#define P_K70_CORE_RGB 0x2b0a
#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 || (kb)->product == P_K70_PRO || (kb)->product == P_K70_PRO_OPTIC || (kb)->product == P_K70_TKL_CHAMP_OPTIC) || IS_K70CORERGB(kb))
#define IS_K70CORERGB(kb) ((kb)->vendor == V_CORSAIR && ((kb)->product == P_K70_CORE_RGB))
// The Legacy K90 behaves like a Legacy K95.
#define P_K90_LEGACY 0x1b02
@@ -286,10 +288,10 @@ const char* product_str(ushort product);
#define SUPPORTS_ADJRATE(kb) ((kb)->product == P_K60_PRO_TKL || (kb)->product == P_K60_PRO_RGB || (kb)->product == P_K60_PRO_MONO || (kb)->product == P_K60_PRO_RGB_LP || (kb)->product == P_K60_PRO_RGB_SE || (kb)->product == P_K63_NRGB || (kb)->product == P_K66 || (kb)->product == P_K68 || (kb)->product == P_K68_NRGB || (kb)->product == P_K70_MK2 || (kb)->product == P_K70_MK2SE || (kb)->product == P_K70_MK2LP || (kb)->product == P_K95_PLATINUM || (kb)->product == P_STRAFE || (kb)->product == P_STRAFE_NRGB || (kb)->product == P_STRAFE_NRGB_2 || (kb)->product == P_STRAFE_MK2 || (kb)->product == P_M55_RGB_PRO || (kb)->product == P_M65 || (kb)->product == P_M65_PRO || (kb)->product == P_M65_RGB_ELITE || (kb)->product == P_M95 || (kb)->product == P_SABRE_O || (kb)->product == P_SABRE_L || (kb)->product == P_SABRE_N || (kb)->product == P_SABRE_O2 || (kb)->product == P_SCIMITAR || (kb)->product == P_SCIMITAR_ELITE || (kb)->product == P_SCIMITAR_PRO || (kb)->product == P_HARPOON || (kb)->product == P_HARPOON_PRO || (kb)->product == P_GLAIVE || (kb)->product == P_KATAR || (kb)->product == P_KATAR_PRO_XT || (kb)->product == P_KATAR_PRO || (kb)->product == P_NIGHTSWORD || IS_DARK_CORE_NXP(kb) || (kb)->product == P_K95_PLATINUM_XT || (kb)->product == P_GLAIVE_PRO || (kb)->product == P_K55_PRO || (kb)->product == P_K55_PRO_XT || (kb)->product == P_GENERIC_BRAGI_DONGLE)
// Bragi devices that use macros for media keys. Currently used to apply a terrible workaround.
#define BRAGI_HAS_MEDIA_MACRO(kb) (IS_K60PRORGB(kb))
#define BRAGI_HAS_MEDIA_MACRO(kb) (IS_K60PRORGB(kb) || IS_K70CORERGB(kb))
// 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) || BRAGI_HAS_MEDIA_MACRO(kb)))
#define DEV_HAS_VOLWHEEL(kb) (!(IS_K65(kb) || IS_K63(kb) || (kb)->product == P_K57_U || IS_K55(kb) || IS_K60PRORGB(kb)))
// 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)))
@@ -302,7 +304,7 @@ const char* product_str(ushort product);
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 || (product) == P_K100_OPTICAL || (product) == P_K100_MECHANICAL || (product) == P_K100_OPTICAL_VARIANT || (product) == P_K65_MINI || (product) == P_K70_TKL || (product) == P_K70_TKL_CHAMP_OPTIC || (product) == P_MM700 || (product) == P_K70_PRO || (product) == P_K70_PRO_OPTIC))
#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_K100_OPTICAL_VARIANT || (product) == P_K65_MINI || (product) == P_K70_TKL || (product) == P_K70_TKL_CHAMP_OPTIC || (product) == P_MM700 || (product) == P_K70_PRO || (product) == P_K70_PRO_OPTIC || (product) == P_K70_CORE_RGB))
// Devices that use bragi jumbo packets (1024 bytes)
#define USES_BRAGI_JUMBO(vendor, product) ((vendor) == (V_CORSAIR) && ((product) == P_K100_OPTICAL || (product) == P_K100_MECHANICAL || (product) == P_K100_OPTICAL_VARIANT || (product) == P_K65_MINI || (product) == P_K70_TKL || (product) == P_K70_TKL_CHAMP_OPTIC || (product) == P_K70_PRO || (product) == P_K70_PRO_OPTIC))