From c13f031119139cac49d85a32efa9fa6bb8fb8b74 Mon Sep 17 00:00:00 2001 From: filipesn Date: Sat, 10 Jan 2026 05:51:32 +0000 Subject: [PATCH] Fix support for SteelSeries Apex Pro TKL 2023 --- .../SteelSeriesApexController.cpp | 127 +++++++++++++++++- .../SteelSeriesApexController.h | 20 ++- .../SteelSeriesControllerDetect.cpp | 6 +- 3 files changed, 145 insertions(+), 8 deletions(-) diff --git a/Controllers/SteelSeriesController/SteelSeriesApexController/SteelSeriesApexController.cpp b/Controllers/SteelSeriesController/SteelSeriesApexController/SteelSeriesApexController.cpp index 19f7e714a..db607a788 100644 --- a/Controllers/SteelSeriesController/SteelSeriesApexController/SteelSeriesApexController.cpp +++ b/Controllers/SteelSeriesController/SteelSeriesApexController/SteelSeriesApexController.cpp @@ -1,19 +1,27 @@ /*---------------------------------------------------------*\ | SteelSeriesApexController.cpp | | | -| Driver for SteelSeries Apex 7 | +| Driver for SteelSeries Apex Keyboards | +| | +| New driver based on SignalRGB Plugins | +| https://gitlab.com/signalrgb/signal-plugins/ | | | | Eric Samuelson (edbgon) 05 Jul 2020 | +| Filipe S. (filipesn) 5 Jan 2026 | | | | This file is part of the OpenRGB project | | SPDX-License-Identifier: GPL-2.0-or-later | \*---------------------------------------------------------*/ #include +#include #include "SteelSeriesApexController.h" +#include "LogManager.h" using namespace std::chrono_literals; +#define FIRMWARE_REQ_LEN 645 + static unsigned int keys[] = {0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, //20 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, @@ -29,7 +37,10 @@ static unsigned int keys[] = {0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x SteelSeriesApexController::SteelSeriesApexController(hid_device* dev_handle, steelseries_type type, const char* path, std::string dev_name) : SteelSeriesApexBaseController(dev_handle, path, dev_name) { - proto_type = type; + proto_type = type; + use_new_protocol = false; + + SendInitialization(); } SteelSeriesApexController::~SteelSeriesApexController() @@ -55,8 +66,23 @@ void SteelSeriesApexController::SetLEDsDirect(std::vector colors) unsigned char buf[643]; int num_keys = 0; + unsigned char packet_id = APEX_PACKET_ID_DIRECT; + num_keys = sizeof(keys) / sizeof(*keys); + if(use_new_protocol) + { + struct hid_device_info* info = hid_get_device_info(dev); + if(info && (info->product_id == 0x162C || info->product_id == 0x162D)) // Aparently Gen 3 wireless models reuse this protocol, make sure to place their PID here and further below when developing. + { + packet_id = APEX_2023_PACKET_ID_DIRECT_WIRELESS; + } + else + { + packet_id = APEX_2023_PACKET_ID_DIRECT; + } + } + /*-----------------------------------------------------*\ | Zero out buffer | \*-----------------------------------------------------*/ @@ -66,8 +92,8 @@ void SteelSeriesApexController::SetLEDsDirect(std::vector colors) | Set up Direct packet | \*-----------------------------------------------------*/ buf[0x00] = 0; - buf[0x01] = APEX_PACKET_ID_DIRECT; - buf[0x02] = num_keys; + buf[0x01] = packet_id; + buf[0x02] = (use_new_protocol) ? (unsigned char)colors.size() : num_keys; /*-----------------------------------------------------*\ | Fill in color data | @@ -106,3 +132,96 @@ void SteelSeriesApexController::SelectProfile buf[0x02] = profile; hid_send_feature_report(dev, buf, 65); } + +void SteelSeriesApexController::SendInitialization() +{ + unsigned char buf[FIRMWARE_REQ_LEN]; + unsigned char read_buf[65]; + int res = 0; + char version_str[32] = "Unknown"; + + struct hid_device_info* info = hid_get_device_info(dev); + unsigned short pid = (info) ? info->product_id : 0; + + // Firmware check + if(pid == 0x1628) + { + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(buf, 0x00, sizeof(buf)); + buf[0x00] = 0x00; + buf[0x01] = 0x90; + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, buf, 65); + + /*-----------------------------------------------------*\ + | Read Response | + \*-----------------------------------------------------*/ + memset(read_buf, 0x00, sizeof(read_buf)); + res = hid_read_timeout(dev, read_buf, sizeof(read_buf), 200); + + /*-----------------------------------------------------*\ + | Firmware Check | + \*-----------------------------------------------------*/ + if(res > 2 && read_buf[0] == 0x90) + { + int major = 0, minor = 0, patch = 0; + char* fw_ptr = (char*)&read_buf[2]; + + snprintf(version_str, sizeof(version_str), "%s", fw_ptr); + + int count = sscanf(version_str, "%d.%d.%d", &major, &minor, &patch); + + if(count == 3) + { + // Currently set to 1.19.7 or newer. + if(major > 1) + { + use_new_protocol = true; + } + else if(major == 1) + { + if(minor > 19) + { + use_new_protocol = true; + } + else if(minor == 19 && patch >= 7) + { + use_new_protocol = true; + } + } + } + } + } + // // Aparently Gen 3 models reuse this protocol, make sure to place their PID here and further above for wireless when developing. + else if(pid == 0x162C || pid == 0x162D) + { + use_new_protocol = true; + } + + /*-----------------------------------------------------*\ + | Send Initialization packet on new protocol. | + \*-----------------------------------------------------*/ + if(use_new_protocol) + { + memset(buf, 0x00, sizeof(buf)); + buf[0x00] = 0x00; + buf[0x01] = APEX_2023_PACKET_ID_INIT; + hid_send_feature_report(dev, buf, APEX_2023_PACKET_LENGTH); + + LOG_DEBUG("[%s] Using Apex 2023 protocol. FW: %s", name.c_str(), version_str); + } + else + { + LOG_DEBUG("[%s] Using Apex Legacy protocol. FW: %s", name.c_str(), version_str); + } +} + +std::string SteelSeriesApexController::GetSerial() +{ + return "64865"; +} diff --git a/Controllers/SteelSeriesController/SteelSeriesApexController/SteelSeriesApexController.h b/Controllers/SteelSeriesController/SteelSeriesApexController/SteelSeriesApexController.h index 22fc5df3e..2ea12dd4e 100644 --- a/Controllers/SteelSeriesController/SteelSeriesApexController/SteelSeriesApexController.h +++ b/Controllers/SteelSeriesController/SteelSeriesApexController/SteelSeriesApexController.h @@ -1,9 +1,13 @@ /*---------------------------------------------------------*\ -| SteelSeriesApexController.h | +| SteelSeriesApexController.cpp | | | -| Driver for SteelSeries Apex 7 | +| Driver for SteelSeries Apex Keyboards | +| | +| New driver based on SignalRGB Plugins | +| https://gitlab.com/signalrgb/signal-plugins/ | | | | Eric Samuelson (edbgon) 05 Jul 2020 | +| Filipe S. (filipesn) 5 Jan 2026 | | | | This file is part of the OpenRGB project | | SPDX-License-Identifier: GPL-2.0-or-later | @@ -19,7 +23,11 @@ enum { - APEX_PACKET_ID_DIRECT = 0x3a, /* Direct mode */ + APEX_PACKET_ID_DIRECT = 0x3a, /* Direct mode */ + APEX_2023_PACKET_ID_DIRECT = 0x40, /* New Wired Direct mode */ + APEX_2023_PACKET_ID_DIRECT_WIRELESS = 0x61, /* New Wireless Direct mode */ + APEX_2023_PACKET_ID_INIT = 0x4B, /* New Initialization */ + APEX_2023_PACKET_LENGTH = 643, }; class SteelSeriesApexController : public SteelSeriesApexBaseController @@ -36,10 +44,16 @@ public: void SetLEDsDirect(std::vector colors); + std::string GetSerial() override; + private: void SelectProfile ( unsigned char profile ); + + void SendInitialization(); + + bool use_new_protocol; }; diff --git a/Controllers/SteelSeriesController/SteelSeriesControllerDetect.cpp b/Controllers/SteelSeriesController/SteelSeriesControllerDetect.cpp index e79abee13..8590f0719 100644 --- a/Controllers/SteelSeriesController/SteelSeriesControllerDetect.cpp +++ b/Controllers/SteelSeriesController/SteelSeriesControllerDetect.cpp @@ -116,6 +116,8 @@ #define STEELSERIES_APEX_PRO_PID 0x1610 #define STEELSERIES_APEX_PRO_TKL_PID 0x1614 #define STEELSERIES_APEX_PRO_TKL_2023_PID 0x1628 +#define STEELSERIES_APEX_PRO_TKL_2023_WL_PID_1 0x1630 +#define STEELSERIES_APEX_PRO_TKL_2023_WL_PID_2 0x1632 #define STEELSERIES_APEX_M750_PID 0x0616 #define STEELSERIES_APEX_OG_PID 0x1202 #define STEELSERIES_APEX_350_PID 0x1206 @@ -504,7 +506,9 @@ REGISTER_HID_DETECTOR_I ("SteelSeries Apex 9 TKL", Dete REGISTER_HID_DETECTOR_I ("SteelSeries Apex 9 Mini", DetectSteelSeriesApex9Mini, STEELSERIES_VID, STEELSERIES_APEX_9_MINI_PID, 1 ); REGISTER_HID_DETECTOR_I ("SteelSeries Apex Pro", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_PRO_PID, 1 ); REGISTER_HID_DETECTOR_I ("SteelSeries Apex Pro TKL", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_PRO_TKL_PID, 1 ); -REGISTER_HID_DETECTOR_I ("SteelSeries Apex Pro TKL 2023", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_PRO_TKL_2023_PID, 1 ); +REGISTER_HID_DETECTOR_I ("SteelSeries Apex Pro TKL 2023 Wired", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_PRO_TKL_2023_PID, 1 ); +REGISTER_HID_DETECTOR_IPU("SteelSeries Apex Pro TKL 2023 Wireless", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_PRO_TKL_2023_WL_PID_1, 3, 0xFFC0, 1); +REGISTER_HID_DETECTOR_IPU("SteelSeries Apex Pro TKL 2023 Wireless", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_PRO_TKL_2023_WL_PID_2, 3, 0xFFC0, 1); REGISTER_HID_DETECTOR_I ("SteelSeries Apex M750", DetectSteelSeriesApexM, STEELSERIES_VID, STEELSERIES_APEX_M750_PID, 2 ); REGISTER_HID_DETECTOR_I ("SteelSeries Apex (OG)/Apex Fnatic", DetectSteelSeriesApexOld, STEELSERIES_VID, STEELSERIES_APEX_OG_PID, 0 ); REGISTER_HID_DETECTOR_I ("SteelSeries Apex 350", DetectSteelSeriesApexOld, STEELSERIES_VID, STEELSERIES_APEX_350_PID, 0 );