mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2026-07-29 14:36:06 -04:00
Steelseries Apex 9 merge into Apex controller + enable onboard mode
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
#include "SteelSeriesMouseController.h"
|
||||
|
||||
#define STEELSERIES_AEORX3_NAME "SteelSeries Aerox 3"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
#include "SteelSeriesMouseController.h"
|
||||
|
||||
#define STEELSERIES_AEROX5_NAME "SteelSeries Aerox 5"
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#include "SteelSeriesAeroxWirelessController.h"
|
||||
#include "LogManager.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
|
||||
SteelSeriesAeroxWirelessController::SteelSeriesAeroxWirelessController(hid_device* dev_handle, steelseries_type proto_type, const char* path, std::string dev_name) : SteelSeriesMouseController(dev_handle, proto_type, path, dev_name)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
#include "SteelSeriesMouseController.h"
|
||||
|
||||
#define STEELSERIES_AEROX3_WIRELESS_NAME "SteelSeries Aerox 3 Wireless (2.4 GHz wireless mode)"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
|
||||
#define STEELSERIES_APEX3_BRIGHTNESS_MIN 0x00
|
||||
#define STEELSERIES_APEX3_HID_TIMEOUT 100
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
#include "SteelSeriesApex3Controller.h"
|
||||
|
||||
#define STEELSERIES_8Z_LED_COUNT 8
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SteelSeriesApex9Controller.cpp |
|
||||
| |
|
||||
| Driver for SteelSeries Apex 9 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <cstring>
|
||||
#include "SteelSeriesApex9Controller.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
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,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, //40
|
||||
0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||
0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, //60
|
||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
|
||||
0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x64, 0xE0, //80
|
||||
0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xF0, 0x31, 0x87,
|
||||
0x88, 0x89, 0x8A, 0x8B, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, //100
|
||||
0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62,
|
||||
0x63 };
|
||||
|
||||
SteelSeriesApex9Controller::SteelSeriesApex9Controller(hid_device* dev_handle, steelseries_type type, const char* path, std::string dev_name) : SteelSeriesApexBaseController (dev_handle, path, dev_name)
|
||||
{
|
||||
proto_type = type;
|
||||
}
|
||||
|
||||
SteelSeriesApex9Controller::~SteelSeriesApex9Controller()
|
||||
{
|
||||
hid_close(dev);
|
||||
}
|
||||
|
||||
void SteelSeriesApex9Controller::SetMode(unsigned char mode /*mode*/, std::vector<RGBColor> /*colors*/ )
|
||||
{
|
||||
unsigned char mode_colors[9];
|
||||
|
||||
active_mode = mode;
|
||||
|
||||
memset(mode_colors, 0x00, sizeof(mode_colors));
|
||||
}
|
||||
|
||||
void SteelSeriesApex9Controller::SetLEDsDirect(std::vector<RGBColor> colors)
|
||||
{
|
||||
unsigned char buf[APEX_9_PACKET_LENGTH];
|
||||
int num_keys = 0;
|
||||
|
||||
num_keys = sizeof(keys) / sizeof(*keys);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Zero out buffer |
|
||||
\*-----------------------------------------------------*/
|
||||
memset(buf, 0x00, sizeof(buf));
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Set up Direct packet |
|
||||
\*-----------------------------------------------------*/
|
||||
buf[0x00] = 0;
|
||||
buf[0x01] = APEX_9_PACKET_ID_DIRECT;
|
||||
buf[0x02] = num_keys;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Fill in color data |
|
||||
\*-----------------------------------------------------*/
|
||||
for(int i = 0; i < num_keys; i++)
|
||||
{
|
||||
buf[(i*4)+3] = keys[i];
|
||||
buf[(i*4)+4] = RGBGetRValue(colors[i]);
|
||||
buf[(i*4)+5] = RGBGetGValue(colors[i]);
|
||||
buf[(i*4)+6] = RGBGetBValue(colors[i]);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Send packet |
|
||||
\*-----------------------------------------------------*/
|
||||
hid_send_feature_report(dev, buf, APEX_9_PACKET_LENGTH);
|
||||
|
||||
}
|
||||
|
||||
std::string SteelSeriesApex9Controller::GetSerial()
|
||||
{
|
||||
std::string return_string = "";
|
||||
|
||||
switch(proto_type)
|
||||
{
|
||||
case APEX_9_TKL:
|
||||
return_string = "64847";
|
||||
break;
|
||||
case APEX_9_MINI:
|
||||
return_string = "64837";
|
||||
break;
|
||||
default:
|
||||
return_string = "Apex 9 GetSerial() error";
|
||||
}
|
||||
|
||||
return(return_string);
|
||||
}
|
||||
|
||||
std::string SteelSeriesApex9Controller::GetVersion()
|
||||
{
|
||||
std::string return_string = "Unsupported protocol";
|
||||
|
||||
unsigned char obuf[STEELSERIES_PACKET_OUT_SIZE];
|
||||
unsigned char ibuf[STEELSERIES_PACKET_IN_SIZE];
|
||||
int result;
|
||||
|
||||
memset(obuf, 0x00, sizeof(obuf));
|
||||
obuf[0x00] = 0;
|
||||
obuf[0x01] = 0x90;
|
||||
hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE);
|
||||
result = hid_read_timeout(dev, ibuf, STEELSERIES_PACKET_IN_SIZE, 2);
|
||||
|
||||
if(result > 0)
|
||||
{
|
||||
std::string fwver(ibuf, ibuf+STEELSERIES_PACKET_IN_SIZE);
|
||||
fwver = fwver.substr(2, fwver.size());
|
||||
fwver = fwver.c_str();
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Find 2 periods in string, if found we can |
|
||||
| form a X.Y.Z revision. |
|
||||
\*---------------------------------------------*/
|
||||
std::size_t majorp = fwver.find('.');
|
||||
if(majorp != std::string::npos)
|
||||
{
|
||||
std::size_t minorp = fwver.find('.', majorp+1);
|
||||
if(minorp != std::string::npos)
|
||||
{
|
||||
std::string major = fwver.substr(0, majorp);
|
||||
std::string minor = fwver.substr(majorp+1, (minorp-majorp-1));
|
||||
std::string build = fwver.substr(minorp+1);
|
||||
return_string = "KBD: " + major + "." + minor + "." + build;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(return_string);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------*\
|
||||
| Private packet sending functions. |
|
||||
\*-------------------------------------------------------------------------------------------------*/
|
||||
|
||||
void SteelSeriesApex9Controller::SelectProfile(unsigned char profile)
|
||||
{
|
||||
unsigned char buf[65];
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Zero out buffer, set up packet and send |
|
||||
\*-----------------------------------------------------*/
|
||||
memset(buf, 0x00, sizeof(buf));
|
||||
buf[0x00] = 0;
|
||||
buf[0x01] = 0x89;
|
||||
buf[0x02] = profile;
|
||||
hid_send_feature_report(dev, buf, 65);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SteelSeriesApex9Controller.h |
|
||||
| |
|
||||
| Driver for SteelSeries Apex 9 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesApexBaseController.h"
|
||||
|
||||
enum
|
||||
{
|
||||
APEX_9_PACKET_ID_DIRECT = 0x40, /* Direct mode */
|
||||
APEX_9_PACKET_LENGTH = 513,
|
||||
};
|
||||
|
||||
class SteelSeriesApex9Controller : public SteelSeriesApexBaseController
|
||||
{
|
||||
public:
|
||||
SteelSeriesApex9Controller(hid_device* dev_handle, steelseries_type type, const char* path, std::string dev_name);
|
||||
~SteelSeriesApex9Controller();
|
||||
|
||||
void SetMode(unsigned char mode, std::vector<RGBColor> colors);
|
||||
void SetLEDsDirect(std::vector<RGBColor> colors);
|
||||
|
||||
std::string GetSerial() override;
|
||||
std::string GetVersion() override;
|
||||
|
||||
private:
|
||||
void SelectProfile(unsigned char profile);
|
||||
};
|
||||
@@ -37,7 +37,7 @@ std::string SteelSeriesApexBaseController::GetName()
|
||||
/*---------------------------------------------------------*\
|
||||
| Gen 1 Apex Pro stores the unit serial number in firmware. |
|
||||
| The first 5 digits determine the region of the keyboard. |
|
||||
| This is not the case for Gen 3, call to this function |
|
||||
| This is not the case for Gen 2+, calls to this function |
|
||||
| will be ignored. |
|
||||
\*---------------------------------------------------------*/
|
||||
std::string SteelSeriesApexBaseController::GetSerial()
|
||||
@@ -51,7 +51,7 @@ std::string SteelSeriesApexBaseController::GetSerial()
|
||||
|
||||
memset(obuf, 0x00, sizeof(obuf));
|
||||
obuf[0x00] = 0;
|
||||
obuf[0x01] = 0xFF;
|
||||
obuf[0x01] = APEX_GEN1_PACKET_ID_SERIAL;
|
||||
hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE);
|
||||
|
||||
result = hid_read_timeout(dev, ibuf, STEELSERIES_PACKET_IN_SIZE, 2);
|
||||
@@ -97,8 +97,8 @@ std::string SteelSeriesApexBaseController::GetVersion()
|
||||
if(proto_type == APEX)
|
||||
{
|
||||
/*-------------------------------------------------*\
|
||||
| Gen 1 & 2 Apex Pro report KBD and LED firmware |
|
||||
| Gen 3 only reports the KBD firmware, ignoring |
|
||||
| Gen 1 Apex Pro reports KBD and LED firmware |
|
||||
| Gen 2+ only reports the KBD firmware, ignoring |
|
||||
| requests to read the LED version |
|
||||
\*-------------------------------------------------*/
|
||||
unsigned char obuf[STEELSERIES_PACKET_OUT_SIZE];
|
||||
@@ -107,7 +107,7 @@ std::string SteelSeriesApexBaseController::GetVersion()
|
||||
|
||||
memset(obuf, 0x00, sizeof(obuf));
|
||||
obuf[0x00] = 0;
|
||||
obuf[0x01] = 0x90;
|
||||
obuf[0x01] = APEX_PACKET_ID_FIRMWARE;
|
||||
hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE);
|
||||
result = hid_read_timeout(dev, ibuf, STEELSERIES_PACKET_IN_SIZE, 2);
|
||||
|
||||
@@ -117,9 +117,9 @@ std::string SteelSeriesApexBaseController::GetVersion()
|
||||
fwver.erase(std::remove(fwver.begin(), fwver.end(), '\0'), fwver.end());
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Apex Pro Gen 3 needs the first char dropped |
|
||||
| Apex Pro Gen 2+ needs the first char dropped |
|
||||
\*---------------------------------------------*/
|
||||
if(kbd_quirk == APEX_GEN3)
|
||||
if(ibuf[0] == APEX_PACKET_ID_FIRMWARE)
|
||||
{
|
||||
fwver.erase(0,1);
|
||||
}
|
||||
@@ -128,9 +128,9 @@ std::string SteelSeriesApexBaseController::GetVersion()
|
||||
}
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Clear and reuse buffer |
|
||||
| Get LED firmware for Gen 1 |
|
||||
\*-------------------------------------------------*/
|
||||
if(kbd_quirk != APEX_GEN3)
|
||||
if(kbd_quirk == APEX_GEN1)
|
||||
{
|
||||
memset(ibuf, 0x00, sizeof(ibuf));
|
||||
obuf[0x02] = 0x01;
|
||||
|
||||
@@ -13,18 +13,23 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
|
||||
#define STEELSERIES_PACKET_IN_SIZE 64
|
||||
#define STEELSERIES_PACKET_OUT_SIZE STEELSERIES_PACKET_IN_SIZE + 1
|
||||
#define STEELSERIES_PACKET_IN_SIZE 64
|
||||
#define STEELSERIES_PACKET_OUT_SIZE STEELSERIES_PACKET_IN_SIZE + 1
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Gen 1: 2019-22 models (all FW) & 2023 FW < 1.19.7 |
|
||||
| Gen 2: 2023 models with FW >= 1.19.7 |
|
||||
| Gen 3: 2025+ and may feature Gen 3 in the name |
|
||||
| Protocol quirk applicability |
|
||||
| |
|
||||
| Gen 1: 2019-22 models with original case design, |
|
||||
| all FW releases. |
|
||||
| Gen 2: '2023' USB-C + Apex 9 series TKL and |
|
||||
| smaller, wired/wireless with pre-prism FW |
|
||||
| Gen 3: All models with Omnipoint 3.0 switches and |
|
||||
| Gen 2 models with prism FW update |
|
||||
\*-------------------------------------------------*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
APEX_GEN1 = 0x00,
|
||||
@@ -33,6 +38,28 @@ typedef enum
|
||||
|
||||
} protocol_quirk;
|
||||
|
||||
enum
|
||||
{
|
||||
APEX_MODE_DIRECT,
|
||||
APEX_MODE_ONBOARD,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
APEX_PACKET_LENGTH = 643,
|
||||
APEX_9_PACKET_LENGTH = 513, /* Test if required */
|
||||
APEX_PACKET_ID_PROFILE = 0x89, /* Profile */
|
||||
APEX_PACKET_ID_FIRMWARE = 0x90, /* Firmware version */
|
||||
APEX_GEN1_PACKET_ID_DIRECT = 0x3A, /* Direct mode */
|
||||
APEX_GEN1_PACKET_ID_ONBOARD = 0x3B, /* Onboard mode */
|
||||
APEX_GEN1_PACKET_ID_SERIAL = 0xFF, /* Serial number */
|
||||
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_ID_ONBOARD = 0x41, /* New Wired onboard mode */
|
||||
APEX_2023_PACKET_ID_REGION = 0xF5, /* Region byte */
|
||||
};
|
||||
|
||||
class SteelSeriesApexBaseController
|
||||
{
|
||||
public:
|
||||
@@ -56,4 +83,6 @@ protected:
|
||||
std::string location;
|
||||
std::string name;
|
||||
protocol_quirk kbd_quirk;
|
||||
unsigned short device_pid;
|
||||
unsigned char reset_cmd;
|
||||
};
|
||||
|
||||
@@ -55,11 +55,18 @@ RGBController_SteelSeriesApex::RGBController_SteelSeriesApex(SteelSeriesApexBase
|
||||
|
||||
mode Direct;
|
||||
Direct.name = "Direct";
|
||||
Direct.value = 0x00;
|
||||
Direct.value = APEX_MODE_DIRECT;
|
||||
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
|
||||
Direct.color_mode = MODE_COLORS_PER_LED;
|
||||
modes.push_back(Direct);
|
||||
|
||||
mode Onboard;
|
||||
Onboard.name = "Onboard";
|
||||
Onboard.value = APEX_MODE_ONBOARD;
|
||||
Onboard.flags = 0;
|
||||
Onboard.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Onboard);
|
||||
|
||||
SetupZones();
|
||||
}
|
||||
|
||||
@@ -97,13 +104,13 @@ void RGBController_SteelSeriesApex::SetupZones()
|
||||
new_zone.matrix_map.width = MATRIX_WIDTH;
|
||||
new_zone.matrix_map.map.resize(MATRIX_HEIGHT * MATRIX_WIDTH);
|
||||
|
||||
if((proto_type == APEX) || (proto_type == APEX_M) || (proto_type == APEX_9_TKL) || (proto_type == APEX_9_MINI))
|
||||
if((proto_type == APEX) || (proto_type == APEX_M))
|
||||
{
|
||||
SetSkuRegion(&new_zone.matrix_map, sku);
|
||||
}
|
||||
}
|
||||
|
||||
if((proto_type == APEX) || (proto_type == APEX_M) || (proto_type == APEX_9_TKL) || (proto_type == APEX_9_MINI))
|
||||
if((proto_type == APEX) || (proto_type == APEX_M))
|
||||
{
|
||||
new_zone.leds_min = zone_sizes[zone_idx];
|
||||
new_zone.leds_max = zone_sizes[zone_idx];
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <chrono>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesApexBaseController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
|
||||
class RGBController_SteelSeriesApex : public RGBController
|
||||
{
|
||||
|
||||
@@ -20,81 +20,101 @@
|
||||
|
||||
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,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, //40
|
||||
0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||
0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, //60
|
||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
|
||||
0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x64, 0xE0, //80
|
||||
0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xF0, 0x31, 0x87,
|
||||
0x88, 0x89, 0x8A, 0x8B, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, //100
|
||||
0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62,
|
||||
0x63, 0xFB
|
||||
};
|
||||
|
||||
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,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, //40
|
||||
0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||
0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, //60
|
||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
|
||||
0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x64, 0xE0, //80
|
||||
0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xF0, 0x31, 0x87,
|
||||
0x88, 0x89, 0x8A, 0x8B, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, //100
|
||||
0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62,
|
||||
0x63, 0xFB };
|
||||
inline static const std::map<unsigned short, protocol_quirk> protocol_map =
|
||||
{
|
||||
{STEELSERIES_APEX_9_TKL_PID, APEX_GEN2},
|
||||
{STEELSERIES_APEX_9_MINI_PID, APEX_GEN2},
|
||||
{STEELSERIES_APEX_PRO_TKL_2023_PID, APEX_GEN2},
|
||||
{STEELSERIES_APEX_PRO_TKL_2023_WL_PID_1, APEX_GEN3},
|
||||
{STEELSERIES_APEX_PRO_TKL_2023_WL_PID_2, APEX_GEN3},
|
||||
{STEELSERIES_APEX_PRO_TKL_GEN3_PID, APEX_GEN3},
|
||||
{STEELSERIES_APEX_PRO_TKL_GEN3_WL_PID_1, APEX_GEN3},
|
||||
{STEELSERIES_APEX_PRO_TKL_GEN3_WL_PID_2, APEX_GEN3},
|
||||
};
|
||||
|
||||
SteelSeriesApexController::SteelSeriesApexController(hid_device* dev_handle, steelseries_type type, const char* path, std::string dev_name) : SteelSeriesApexBaseController(dev_handle, path, dev_name)
|
||||
SteelSeriesApexController::SteelSeriesApexController(hid_device* dev_handle, steelseries_type type, const char* path, unsigned short pid, std::string dev_name) : SteelSeriesApexBaseController(dev_handle, path, dev_name)
|
||||
{
|
||||
proto_type = type;
|
||||
kbd_quirk = APEX_GEN1;
|
||||
|
||||
device_pid = pid;
|
||||
if(protocol_map.count(device_pid) > 0)
|
||||
{
|
||||
kbd_quirk = protocol_map.at(device_pid);
|
||||
}
|
||||
SendInitialization();
|
||||
}
|
||||
|
||||
SteelSeriesApexController::~SteelSeriesApexController()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Gen 3 models must be explicitly cleared for on-board |
|
||||
| config selection to apply without power cycling after |
|
||||
| OpenRGB shuts down. |
|
||||
\*-----------------------------------------------------*/
|
||||
if(kbd_quirk == APEX_GEN3)
|
||||
{
|
||||
unsigned char obuf[STEELSERIES_PACKET_OUT_SIZE];
|
||||
memset(obuf, 0x00, sizeof(obuf));
|
||||
obuf[0x00] = 0;
|
||||
obuf[0x01] = APEX_GEN3_PACKET_CLEAR_LIGHTING;
|
||||
hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE);
|
||||
}
|
||||
SendDeinitialization();
|
||||
hid_close(dev);
|
||||
}
|
||||
|
||||
void SteelSeriesApexController::SetMode
|
||||
(
|
||||
unsigned char mode,
|
||||
std::vector<RGBColor> /*colors*/
|
||||
)
|
||||
/*---------------------------------------------------*\
|
||||
| OpenRGB must clear initialized keyboards during |
|
||||
| shutdown as hardware lighting profiles won't apply |
|
||||
| otherwise. Keyboards not needing initialization are |
|
||||
| also cleared, though selecting a hardware profile |
|
||||
| will override the leds unlike the former. |
|
||||
\*---------------------------------------------------*/
|
||||
void SteelSeriesApexController::SendDeinitialization()
|
||||
{
|
||||
unsigned char mode_colors[9];
|
||||
unsigned char obuf[STEELSERIES_PACKET_OUT_SIZE];
|
||||
memset(obuf, 0x00, sizeof(obuf));
|
||||
obuf[0x00] = 0;
|
||||
obuf[0x01] = reset_cmd;
|
||||
hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE);
|
||||
}
|
||||
|
||||
void SteelSeriesApexController::SetMode(unsigned char mode, std::vector<RGBColor>)
|
||||
{
|
||||
if(active_mode != mode)
|
||||
{
|
||||
if(active_mode == APEX_MODE_ONBOARD && kbd_quirk != APEX_GEN1)
|
||||
{
|
||||
SendInitialization();
|
||||
}
|
||||
if(mode == APEX_MODE_ONBOARD)
|
||||
{
|
||||
SendDeinitialization();
|
||||
}
|
||||
}
|
||||
active_mode = mode;
|
||||
|
||||
memset(mode_colors, 0x00, sizeof(mode_colors));
|
||||
}
|
||||
|
||||
void SteelSeriesApexController::SetLEDsDirect(std::vector<RGBColor> colors)
|
||||
{
|
||||
unsigned char buf[643];
|
||||
int num_keys = 0;
|
||||
|
||||
unsigned char packet_id = APEX_PACKET_ID_DIRECT;
|
||||
|
||||
num_keys = sizeof(keys) / sizeof(*keys);
|
||||
unsigned char buf[APEX_PACKET_LENGTH];
|
||||
int num_keys = sizeof(keys) / sizeof(*keys);
|
||||
unsigned char packet_id = APEX_GEN1_PACKET_ID_DIRECT;
|
||||
|
||||
if(kbd_quirk >= APEX_GEN2)
|
||||
{
|
||||
struct hid_device_info* info = hid_get_device_info(dev);
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Apparently Gen 3 wireless models reuse this |
|
||||
| protocol, make sure to place their PID here and |
|
||||
| protocol, make sure to place their model here and |
|
||||
| further below when developing. |
|
||||
\*-------------------------------------------------*/
|
||||
if(info && (info->product_id == 0x1630 || info->product_id == 0x1632
|
||||
|| info->product_id == 0x162C || info->product_id == 0x162D
|
||||
|| info->product_id == 0x1644 || info->product_id == 0x1646))
|
||||
if(device_pid == STEELSERIES_APEX_PRO_TKL_GEN3_WL_PID_1 ||
|
||||
device_pid == STEELSERIES_APEX_PRO_TKL_GEN3_WL_PID_2 ||
|
||||
device_pid == STEELSERIES_APEX_PRO_TKL_2023_WL_PID_1 ||
|
||||
device_pid == STEELSERIES_APEX_PRO_TKL_2023_WL_PID_2)
|
||||
{
|
||||
packet_id = APEX_2023_PACKET_ID_DIRECT_WIRELESS;
|
||||
}
|
||||
@@ -130,189 +150,151 @@ void SteelSeriesApexController::SetLEDsDirect(std::vector<RGBColor> colors)
|
||||
/*-----------------------------------------------------*\
|
||||
| Send packet |
|
||||
\*-----------------------------------------------------*/
|
||||
hid_send_feature_report(dev, buf, 643);
|
||||
hid_send_feature_report(dev, buf, APEX_PACKET_LENGTH);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Private packet sending functions. |
|
||||
\*---------------------------------------------------------*/
|
||||
void SteelSeriesApexController::SelectProfile
|
||||
(
|
||||
unsigned char profile
|
||||
)
|
||||
void SteelSeriesApexController::SelectProfile(unsigned char profile)
|
||||
{
|
||||
unsigned char buf[65];
|
||||
unsigned char buf[STEELSERIES_PACKET_OUT_SIZE];
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Zero out buffer, set up packet and send |
|
||||
\*-----------------------------------------------------*/
|
||||
memset(buf, 0x00, sizeof(buf));
|
||||
buf[0x00] = 0;
|
||||
buf[0x01] = 0x89;
|
||||
buf[0x01] = APEX_PACKET_ID_PROFILE;
|
||||
buf[0x02] = profile;
|
||||
hid_send_feature_report(dev, buf, 65);
|
||||
hid_send_feature_report(dev, buf, STEELSERIES_PACKET_OUT_SIZE);
|
||||
}
|
||||
|
||||
void SteelSeriesApexController::SendInitialization()
|
||||
{
|
||||
unsigned char buf[FIRMWARE_REQ_LEN];
|
||||
unsigned char read_buf[65];
|
||||
int res = 0;
|
||||
char version_str[65] = "Unknown";
|
||||
|
||||
struct hid_device_info* info = hid_get_device_info(dev);
|
||||
unsigned short pid = (info) ? info->product_id : 0;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Firmware check for TKL 2023 |
|
||||
\*-----------------------------------------------------*/
|
||||
if(pid == 0x1628)
|
||||
/*---------------------------------------------------*\
|
||||
| Check models which can be Gen 3 via firmware update |
|
||||
\*---------------------------------------------------*/
|
||||
if(device_pid == STEELSERIES_APEX_PRO_TKL_PID ||
|
||||
device_pid == STEELSERIES_APEX_9_TKL_PID ||
|
||||
device_pid == STEELSERIES_APEX_9_MINI_PID)
|
||||
{
|
||||
/*-------------------------------------------------*\
|
||||
| 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)
|
||||
std::string fwver = GetVersion();
|
||||
fwver.erase(0,4);
|
||||
int major = 0, minor = 0, patch = 0;
|
||||
int count = sscanf(fwver.c_str(), "%d.%d.%d", &major, &minor, &patch);
|
||||
if(count == 3)
|
||||
{
|
||||
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)
|
||||
/*--------------------------------------------*\
|
||||
| Assume Gen 3 protocol from 1.19.7 or newer. |
|
||||
\*--------------------------------------------*/
|
||||
if(major > 1)
|
||||
{
|
||||
/*-----------------------------------------*\
|
||||
| Currently set to 1.19.7 or newer. |
|
||||
\*-----------------------------------------*/
|
||||
if(major > 1)
|
||||
kbd_quirk = APEX_GEN3;
|
||||
}
|
||||
else if(major == 1)
|
||||
{
|
||||
if(minor > 19)
|
||||
{
|
||||
kbd_quirk = APEX_GEN2;
|
||||
kbd_quirk = APEX_GEN3;
|
||||
}
|
||||
else if(major == 1)
|
||||
else if(minor == 19 && patch >= 7)
|
||||
{
|
||||
if(minor > 19)
|
||||
{
|
||||
kbd_quirk = APEX_GEN2;
|
||||
}
|
||||
else if(minor == 19 && patch >= 7)
|
||||
{
|
||||
kbd_quirk = APEX_GEN2;
|
||||
}
|
||||
kbd_quirk = APEX_GEN3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------*\
|
||||
| Apparently Gen 3 models reuse this protocol, make |
|
||||
| sure to place their PID here and further above for |
|
||||
| wireless when developing. |
|
||||
\*-----------------------------------------------------*/
|
||||
else if(pid == 0x1630 || pid == 0x1632
|
||||
|| pid == 0x162C || pid == 0x162D
|
||||
|| pid == 0x1642 || pid == 0x1644 || pid == 0x1646)
|
||||
{
|
||||
kbd_quirk = APEX_GEN3;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Send Initialization packet on new protocol. |
|
||||
| Send Initialization packet for Gen 3 protocol. This |
|
||||
| seems to be required for some models and not others, |
|
||||
| regardless there is no harm in sending it. |
|
||||
\*-----------------------------------------------------*/
|
||||
if(kbd_quirk >= APEX_GEN2)
|
||||
if(kbd_quirk >= APEX_GEN3)
|
||||
{
|
||||
unsigned char buf[STEELSERIES_PACKET_OUT_SIZE];
|
||||
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);
|
||||
reset_cmd = APEX_2023_PACKET_ID_ONBOARD;
|
||||
buf[0x00] = 0x00;
|
||||
buf[0x01] = APEX_2023_PACKET_ID_INIT;
|
||||
hid_send_feature_report(dev, buf, STEELSERIES_PACKET_OUT_SIZE);
|
||||
LOG_DEBUG("[%s] Using Apex 2023/Gen3 protocol.", name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("[%s] Using Apex Legacy protocol. FW: %s", name.c_str(), version_str);
|
||||
reset_cmd = APEX_GEN1_PACKET_ID_ONBOARD;
|
||||
LOG_DEBUG("[%s] Using Apex Legacy protocol.", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string SteelSeriesApexController::GetSerial()
|
||||
{
|
||||
if(kbd_quirk == APEX_GEN1)
|
||||
{
|
||||
return SteelSeriesApexBaseController::GetSerial();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Gen 3 doesn't expose the serial number in |
|
||||
| Gen 2+ doesn't expose the serial number in |
|
||||
| firmware. A region code is instead set by the |
|
||||
| user and subsequently read back. This region code |
|
||||
| is used by all 5 on-board configs. |
|
||||
| For consistency with other Apex keyboards, this |
|
||||
| region code in combination with the PID is mapped |
|
||||
| region code in tandem with the model is mapped |
|
||||
| to an approximate product number as the region |
|
||||
| patch logic from that point is identical. |
|
||||
| The product number used may not be an exact match |
|
||||
| for the keyboard but should reflect the form |
|
||||
| factor, region and RGB layout |
|
||||
\*-------------------------------------------------*/
|
||||
if(kbd_quirk >= APEX_GEN2)
|
||||
unsigned char obuf[STEELSERIES_PACKET_OUT_SIZE];
|
||||
unsigned char ibuf[STEELSERIES_PACKET_IN_SIZE];
|
||||
int result;
|
||||
|
||||
memset(obuf, 0x00, sizeof(obuf));
|
||||
|
||||
if(device_pid == STEELSERIES_APEX_PRO_TKL_GEN3_PID)
|
||||
{
|
||||
unsigned char obuf[STEELSERIES_PACKET_OUT_SIZE];
|
||||
unsigned char ibuf[STEELSERIES_PACKET_IN_SIZE];
|
||||
int result;
|
||||
struct hid_device_info* info = hid_get_device_info(dev);
|
||||
unsigned short pid = (info) ? info->product_id : 0;
|
||||
obuf[0x00] = 0;
|
||||
obuf[0x01] = APEX_2023_PACKET_ID_REGION;
|
||||
hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE);
|
||||
result = hid_read_timeout(dev, ibuf, STEELSERIES_PACKET_IN_SIZE, 2);
|
||||
|
||||
memset(obuf, 0x00, sizeof(obuf));
|
||||
|
||||
if(pid == 0x1642)
|
||||
if(result > 3 && ibuf[0] == APEX_2023_PACKET_ID_REGION)
|
||||
{
|
||||
obuf[0x00] = 0;
|
||||
obuf[0x01] = 0xF5;
|
||||
hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE);
|
||||
result = hid_read_timeout(dev, ibuf, STEELSERIES_PACKET_IN_SIZE, 2);
|
||||
|
||||
if(result > 3 && ibuf[0] == 0xF5)
|
||||
switch(ibuf[2])
|
||||
{
|
||||
switch(ibuf[2])
|
||||
{
|
||||
case 0x1:
|
||||
return "64740";
|
||||
break;
|
||||
case 0x3:
|
||||
return "64741";
|
||||
break;
|
||||
case 0x4:
|
||||
return "64743";
|
||||
break;
|
||||
case 0x6:
|
||||
return "64744";
|
||||
break;
|
||||
case 0xA:
|
||||
return "64742";
|
||||
break;
|
||||
case 0xD:
|
||||
return "64745";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case 0x1:
|
||||
return "64740";
|
||||
break;
|
||||
case 0x3:
|
||||
return "64741";
|
||||
break;
|
||||
case 0x4:
|
||||
return "64743";
|
||||
break;
|
||||
case 0x6:
|
||||
return "64744";
|
||||
break;
|
||||
case 0xA:
|
||||
return "64742";
|
||||
break;
|
||||
case 0xD:
|
||||
return "64745";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "64865";
|
||||
}
|
||||
|
||||
return SteelSeriesApexBaseController::GetSerial();
|
||||
if(device_pid == STEELSERIES_APEX_9_TKL_PID)
|
||||
{
|
||||
return "64847";
|
||||
}
|
||||
if(device_pid == STEELSERIES_APEX_9_MINI_PID)
|
||||
{
|
||||
return "64837";
|
||||
}
|
||||
return "64865";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SteelSeriesApexController.cpp |
|
||||
| SteelSeriesApexController.h |
|
||||
| |
|
||||
| Driver for SteelSeries Apex Keyboards |
|
||||
| |
|
||||
@@ -18,42 +18,20 @@
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
#include "SteelSeriesApexBaseController.h"
|
||||
|
||||
enum
|
||||
{
|
||||
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,
|
||||
APEX_GEN3_PACKET_CLEAR_LIGHTING = 0x41,
|
||||
};
|
||||
|
||||
class SteelSeriesApexController : public SteelSeriesApexBaseController
|
||||
{
|
||||
public:
|
||||
SteelSeriesApexController(hid_device* dev_handle, steelseries_type type, const char* path, std::string dev_name);
|
||||
SteelSeriesApexController(hid_device* dev_handle, steelseries_type type, const char* path, unsigned short pid, std::string dev_name);
|
||||
~SteelSeriesApexController();
|
||||
|
||||
void SetMode
|
||||
(
|
||||
unsigned char mode,
|
||||
std::vector<RGBColor> colors
|
||||
);
|
||||
|
||||
void SetLEDsDirect(std::vector<RGBColor> colors);
|
||||
|
||||
void SetMode(unsigned char mode, std::vector<RGBColor> colors) override;
|
||||
void SetLEDsDirect(std::vector<RGBColor> colors) override;
|
||||
std::string GetSerial() override;
|
||||
|
||||
private:
|
||||
|
||||
void SelectProfile
|
||||
(
|
||||
unsigned char profile
|
||||
);
|
||||
|
||||
void SendInitialization();
|
||||
|
||||
void SelectProfile(unsigned char profile);
|
||||
void SendInitialization();
|
||||
void SendDeinitialization();
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
#include "SteelSeriesApexBaseController.h"
|
||||
|
||||
class SteelSeriesApexMController : public SteelSeriesApexBaseController
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
#include "SteelSeriesApex3Controller.h"
|
||||
|
||||
#define STEELSERIES_TZ_LED_COUNT 10
|
||||
|
||||
@@ -9,12 +9,11 @@
|
||||
|
||||
#include <hidapi.h>
|
||||
#include "DetectionManager.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
#include "SteelSeriesAeroxWirelessController.h"
|
||||
#include "SteelSeriesAerox5Controller.h"
|
||||
#include "SteelSeriesArctis5Controller.h"
|
||||
#include "SteelSeriesApex8ZoneController.h"
|
||||
#include "SteelSeriesApex9Controller.h"
|
||||
#include "SteelSeriesApexController.h"
|
||||
#include "SteelSeriesApexMController.h"
|
||||
#include "SteelSeriesApexTZoneController.h"
|
||||
@@ -34,99 +33,7 @@
|
||||
#include "RGBController_SteelSeriesSensei.h"
|
||||
#include "RGBController_SteelSeriesSiberia.h"
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Vendor ID |
|
||||
\*---------------------------------------------------------*/
|
||||
#define STEELSERIES_VID 0x1038
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Mouse product IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define STEELSERIES_AEROX_3_PID 0x1836
|
||||
#define STEELSERIES_AEROX_3_WIRELESS_PID 0x1838
|
||||
#define STEELSERIES_AEROX_3_WIRELESS_WIRED_PID 0x183A
|
||||
#define STEELSERIES_AEROX_3_CS2_WIRELESS_PID 0x1878
|
||||
#define STEELSERIES_AEROX_3_CS2_WIRELESS_WIRED_PID 0x187A
|
||||
#define STEELSERIES_AEROX_5_WIRELESS_PID 0x1852
|
||||
#define STEELSERIES_AEROX_5_WIRELESS_WIRED_PID 0x1854
|
||||
#define STEELSERIES_AEROX_5_DESTINY_WIRELESS_PID 0x185C
|
||||
#define STEELSERIES_AEROX_5_DESTINY_WIRELESS_WIRED_PID 0x185E
|
||||
#define STEELSERIES_AEROX_5_DIABLO_WIRELESS_PID 0x1860
|
||||
#define STEELSERIES_AEROX_5_DIABLO_WIRELESS_WIRED_PID 0x1862
|
||||
#define STEELSERIES_AEROX_9_WIRELESS_PID 0x1858
|
||||
#define STEELSERIES_AEROX_9_WIRELESS_WIRED_PID 0x185A
|
||||
#define STEELSERIES_AEROX_5_PID 0x1850
|
||||
#define STEELSERIES_AEROX_9_PID 0x185A
|
||||
#define STEELSERIES_RIVAL_100_PID 0x1702
|
||||
#define STEELSERIES_RIVAL_100_DOTA_PID 0x170C
|
||||
#define STEELSERIES_RIVAL_105_PID 0x1814
|
||||
#define STEELSERIES_RIVAL_106_PID 0x1816
|
||||
#define STEELSERIES_RIVAL_110_PID 0x1729
|
||||
#define STEELSERIES_RIVAL_300_PID 0x1710
|
||||
#define ACER_PREDATOR_RIVAL_300_PID 0x1714
|
||||
#define STEELSERIES_RIVAL_300_CSGO_PID 0x1394
|
||||
#define STEELSERIES_RIVAL_300_CSGO_STM32_PID 0x1716
|
||||
#define STEELSERIES_RIVAL_300_CSGO_HYPERBEAST_PID 0x171A
|
||||
#define STEELSERIES_RIVAL_300_DOTA_PID 0x1392
|
||||
#define STEELSERIES_RIVAL_300_HP_PID 0x1718
|
||||
#define STEELSERIES_RIVAL_300_BLACKOPS_PID 0x1710
|
||||
#define STEELSERIES_RIVAL_310_PID 0x1720
|
||||
#define STEELSERIES_RIVAL_310_CSGO_HOWL_PID 0x171E
|
||||
#define STEELSERIES_RIVAL_310_PUBG_PID 0x1736
|
||||
#define STEELSERIES_RIVAL_600_PID 0x1724
|
||||
#define STEELSERIES_RIVAL_600_DOTA_2_PID 0x172E
|
||||
#define STEELSERIES_RIVAL_650_PID 0x172B
|
||||
#define STEELSERIES_RIVAL_650_WIRELESS_PID 0x1726
|
||||
#define STEELSERIES_RIVAL_700_PID 0x1700
|
||||
#define STEELSERIES_RIVAL_710_PID 0x1730
|
||||
#define STEELSERIES_RIVAL_3_OLD_PID 0x1824
|
||||
#define STEELSERIES_RIVAL_3_PID 0x184C
|
||||
#define STEELSERIES_SENSEI_TEN_PID 0x1832
|
||||
#define STEELSERIES_SENSEI_TEN_CSGO_NEON_RIDER_PID 0x1834
|
||||
#define STEELSERIES_SENSEI_310_PID 0x1722
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Headset product IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define STEELSERIES_SIBERIA_350_PID 0x1229
|
||||
#define STEELSERIES_ARCTIS_5_PID 0x1250
|
||||
#define STEELSERIES_ARCTIS_5_V2_PID 0x12AA
|
||||
|
||||
/*--------------------------------------------------------------------*\
|
||||
| Mousemat product IDs |
|
||||
\*--------------------------------------------------------------------*/
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_MED_PID 0x150A
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_PID 0x150D
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_DESTINY_PID 0x151E
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_CSGO_NEON_RIDER_PID 0x1514
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_CSGO_NEO_NOIR_PID 0x151C
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_3XL_PID 0x1516
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_4XL_PID 0x1518
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_5XL_PID 0x151A
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_DESTINY_2_LIGHTFALL_ED_PID 0x1520
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Keyboard product IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define STEELSERIES_APEX_3_PID 0x161A
|
||||
#define STEELSERIES_APEX_3_TKL_PID 0x1622
|
||||
#define STEELSERIES_APEX_5_PID 0x161C
|
||||
#define STEELSERIES_APEX_7_PID 0x1612
|
||||
#define STEELSERIES_APEX_7_TKL_PID 0x1618
|
||||
#define STEELSERIES_APEX_9_TKL_PID 0x1634
|
||||
#define STEELSERIES_APEX_9_MINI_PID 0x1620
|
||||
#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_PRO_TKL_GEN3_PID 0x1642
|
||||
#define STEELSERIES_APEX_PRO_TKL_GEN3_WL_PID_1 0x1644
|
||||
#define STEELSERIES_APEX_PRO_TKL_GEN3_WL_PID_2 0x1646
|
||||
#define STEELSERIES_APEX_M750_PID 0x0616
|
||||
#define STEELSERIES_APEX_OG_PID 0x1202
|
||||
#define STEELSERIES_APEX_350_PID 0x1206
|
||||
#define STEELSERIES_APEX_PRO3_PID 0x1640
|
||||
|
||||
DetectedControllers DetectSteelSeriesAerox3(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
@@ -277,7 +184,7 @@ DetectedControllers DetectSteelSeriesApex(hid_device_info* info, const std::stri
|
||||
|
||||
if(dev)
|
||||
{
|
||||
SteelSeriesApexController* controller = new SteelSeriesApexController(dev, APEX, info->path, name);
|
||||
SteelSeriesApexController* controller = new SteelSeriesApexController(dev, APEX, info->path, info->product_id, name);
|
||||
RGBController_SteelSeriesApex* rgb_controller = new RGBController_SteelSeriesApex(controller);
|
||||
|
||||
detected_controllers.push_back(rgb_controller);
|
||||
@@ -286,34 +193,6 @@ DetectedControllers DetectSteelSeriesApex(hid_device_info* info, const std::stri
|
||||
return(detected_controllers);
|
||||
}
|
||||
|
||||
DetectedControllers DetectSteelSeriesApex9(hid_device_info* info, const std::string& name, steelseries_type proto_type)
|
||||
{
|
||||
DetectedControllers detected_controllers;
|
||||
hid_device* dev;
|
||||
|
||||
dev = hid_open_path(info->path);
|
||||
|
||||
if(dev)
|
||||
{
|
||||
SteelSeriesApex9Controller* controller = new SteelSeriesApex9Controller(dev, proto_type, info->path, name);
|
||||
RGBController_SteelSeriesApex* rgb_controller = new RGBController_SteelSeriesApex(controller);
|
||||
|
||||
detected_controllers.push_back(rgb_controller);
|
||||
}
|
||||
|
||||
return(detected_controllers);
|
||||
}
|
||||
|
||||
DetectedControllers DetectSteelSeriesApex9TKL(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
return(DetectSteelSeriesApex9(info, name, APEX_9_TKL));
|
||||
}
|
||||
|
||||
DetectedControllers DetectSteelSeriesApex9Mini(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
return(DetectSteelSeriesApex9(info, name, APEX_9_MINI));
|
||||
}
|
||||
|
||||
DetectedControllers DetectSteelSeriesApexM(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
DetectedControllers detected_controllers;
|
||||
@@ -604,8 +483,8 @@ REGISTER_HID_DETECTOR_IPU("SteelSeries Apex 3 TKL", Dete
|
||||
REGISTER_HID_DETECTOR_I ("SteelSeries Apex 5", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_5_PID, 1 );
|
||||
REGISTER_HID_DETECTOR_I ("SteelSeries Apex 7", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_7_PID, 1 );
|
||||
REGISTER_HID_DETECTOR_I ("SteelSeries Apex 7 TKL", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_7_TKL_PID, 1 );
|
||||
REGISTER_HID_DETECTOR_I ("SteelSeries Apex 9 TKL", DetectSteelSeriesApex9TKL, STEELSERIES_VID, STEELSERIES_APEX_9_TKL_PID, 1 );
|
||||
REGISTER_HID_DETECTOR_I ("SteelSeries Apex 9 Mini", DetectSteelSeriesApex9Mini, STEELSERIES_VID, STEELSERIES_APEX_9_MINI_PID, 1 );
|
||||
REGISTER_HID_DETECTOR_I ("SteelSeries Apex 9 TKL", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_9_TKL_PID, 1 );
|
||||
REGISTER_HID_DETECTOR_I ("SteelSeries Apex 9 Mini", DetectSteelSeriesApex, 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 Wired", DetectSteelSeriesApex, STEELSERIES_VID, STEELSERIES_APEX_PRO_TKL_2023_PID, 1 );
|
||||
|
||||
137
Controllers/SteelSeriesController/SteelSeriesDevices.h
Normal file
137
Controllers/SteelSeriesController/SteelSeriesDevices.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SteelSeriesDevices.h |
|
||||
| |
|
||||
| Device list for SteelSeries devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Vendor ID |
|
||||
\*---------------------------------------------------------*/
|
||||
#define STEELSERIES_VID 0x1038
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Mouse product IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define STEELSERIES_AEROX_3_PID 0x1836
|
||||
#define STEELSERIES_AEROX_3_WIRELESS_PID 0x1838
|
||||
#define STEELSERIES_AEROX_3_WIRELESS_WIRED_PID 0x183A
|
||||
#define STEELSERIES_AEROX_3_CS2_WIRELESS_PID 0x1878
|
||||
#define STEELSERIES_AEROX_3_CS2_WIRELESS_WIRED_PID 0x187A
|
||||
#define STEELSERIES_AEROX_5_WIRELESS_PID 0x1852
|
||||
#define STEELSERIES_AEROX_5_WIRELESS_WIRED_PID 0x1854
|
||||
#define STEELSERIES_AEROX_5_DESTINY_WIRELESS_PID 0x185C
|
||||
#define STEELSERIES_AEROX_5_DESTINY_WIRELESS_WIRED_PID 0x185E
|
||||
#define STEELSERIES_AEROX_5_DIABLO_WIRELESS_PID 0x1860
|
||||
#define STEELSERIES_AEROX_5_DIABLO_WIRELESS_WIRED_PID 0x1862
|
||||
#define STEELSERIES_AEROX_9_WIRELESS_PID 0x1858
|
||||
#define STEELSERIES_AEROX_9_WIRELESS_WIRED_PID 0x185A
|
||||
#define STEELSERIES_AEROX_5_PID 0x1850
|
||||
#define STEELSERIES_AEROX_9_PID 0x185A
|
||||
#define STEELSERIES_RIVAL_100_PID 0x1702
|
||||
#define STEELSERIES_RIVAL_100_DOTA_PID 0x170C
|
||||
#define STEELSERIES_RIVAL_105_PID 0x1814
|
||||
#define STEELSERIES_RIVAL_106_PID 0x1816
|
||||
#define STEELSERIES_RIVAL_110_PID 0x1729
|
||||
#define STEELSERIES_RIVAL_300_PID 0x1710
|
||||
#define ACER_PREDATOR_RIVAL_300_PID 0x1714
|
||||
#define STEELSERIES_RIVAL_300_CSGO_PID 0x1394
|
||||
#define STEELSERIES_RIVAL_300_CSGO_STM32_PID 0x1716
|
||||
#define STEELSERIES_RIVAL_300_CSGO_HYPERBEAST_PID 0x171A
|
||||
#define STEELSERIES_RIVAL_300_DOTA_PID 0x1392
|
||||
#define STEELSERIES_RIVAL_300_HP_PID 0x1718
|
||||
#define STEELSERIES_RIVAL_300_BLACKOPS_PID 0x1710
|
||||
#define STEELSERIES_RIVAL_310_PID 0x1720
|
||||
#define STEELSERIES_RIVAL_310_CSGO_HOWL_PID 0x171E
|
||||
#define STEELSERIES_RIVAL_310_PUBG_PID 0x1736
|
||||
#define STEELSERIES_RIVAL_600_PID 0x1724
|
||||
#define STEELSERIES_RIVAL_600_DOTA_2_PID 0x172E
|
||||
#define STEELSERIES_RIVAL_650_PID 0x172B
|
||||
#define STEELSERIES_RIVAL_650_WIRELESS_PID 0x1726
|
||||
#define STEELSERIES_RIVAL_700_PID 0x1700
|
||||
#define STEELSERIES_RIVAL_710_PID 0x1730
|
||||
#define STEELSERIES_RIVAL_3_OLD_PID 0x1824
|
||||
#define STEELSERIES_RIVAL_3_PID 0x184C
|
||||
#define STEELSERIES_SENSEI_TEN_PID 0x1832
|
||||
#define STEELSERIES_SENSEI_TEN_CSGO_NEON_RIDER_PID 0x1834
|
||||
#define STEELSERIES_SENSEI_310_PID 0x1722
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Headset product IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define STEELSERIES_SIBERIA_350_PID 0x1229
|
||||
#define STEELSERIES_ARCTIS_5_PID 0x1250
|
||||
#define STEELSERIES_ARCTIS_5_V2_PID 0x12AA
|
||||
|
||||
/*--------------------------------------------------------------------*\
|
||||
| Mousemat product IDs |
|
||||
\*--------------------------------------------------------------------*/
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_MED_PID 0x150A
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_PID 0x150D
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_DESTINY_PID 0x151E
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_CSGO_NEON_RIDER_PID 0x1514
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_CSGO_NEO_NOIR_PID 0x151C
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_3XL_PID 0x1516
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_4XL_PID 0x1518
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_5XL_PID 0x151A
|
||||
#define STEELSERIES_QCK_PRISM_CLOTH_XL_DESTINY_2_LIGHTFALL_ED_PID 0x1520
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Keyboard product IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define STEELSERIES_APEX_3_PID 0x161A
|
||||
#define STEELSERIES_APEX_3_TKL_PID 0x1622
|
||||
#define STEELSERIES_APEX_5_PID 0x161C
|
||||
#define STEELSERIES_APEX_7_PID 0x1612
|
||||
#define STEELSERIES_APEX_7_TKL_PID 0x1618
|
||||
#define STEELSERIES_APEX_9_TKL_PID 0x1634
|
||||
#define STEELSERIES_APEX_9_MINI_PID 0x1620
|
||||
#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_PRO_TKL_GEN3_PID 0x1642
|
||||
#define STEELSERIES_APEX_PRO_TKL_GEN3_WL_PID_1 0x1644
|
||||
#define STEELSERIES_APEX_PRO_TKL_GEN3_WL_PID_2 0x1646
|
||||
#define STEELSERIES_APEX_M750_PID 0x0616
|
||||
#define STEELSERIES_APEX_OG_PID 0x1202
|
||||
#define STEELSERIES_APEX_350_PID 0x1206
|
||||
#define STEELSERIES_APEX_PRO3_PID 0x1640
|
||||
|
||||
/*--------------------------------------------------------*\
|
||||
| Allows us to handle variation in the protocol. |
|
||||
| Defined in a single enum so we can keep the device_list |
|
||||
| struct the same for every possible device. |
|
||||
\*--------------------------------------------------------*/
|
||||
typedef enum
|
||||
{
|
||||
RIVAL_100 = 0x00,
|
||||
RIVAL_300 = 0x01,
|
||||
RIVAL_650 = 0x02,
|
||||
SIBERIA_350 = 0x03,
|
||||
APEX = 0x04,
|
||||
APEX_M = 0x05,
|
||||
APEX_OLD = 0x06,
|
||||
SENSEI = 0x07,
|
||||
RIVAL_600 = 0x08,
|
||||
RIVAL_3 = 0x09,
|
||||
APEX_TZONE = 0x0A,
|
||||
RIVAL_700 = 0x0B,
|
||||
AEROX_3 = 0x0C,
|
||||
APEX_8ZONE = 0x0D,
|
||||
AEROX_3_WIRELESS = 0x0E,
|
||||
AEROX_3_WIRELESS_WIRED = 0x0F,
|
||||
AEROX_5_WIRELESS = 0x10,
|
||||
AEROX_5_WIRELESS_WIRED = 0x11,
|
||||
AEROX_5_DESTINY_WIRELESS = 0x12,
|
||||
AEROX_5_DESTINY_WIRELESS_WIRED = 0x13,
|
||||
AEROX_5_DIABLO_WIRELESS = 0x14,
|
||||
AEROX_5_DIABLO_WIRELESS_WIRED = 0x15,
|
||||
AEROX_9_WIRELESS = 0x16,
|
||||
AEROX_9_WIRELESS_WIRED = 0x17,
|
||||
} steelseries_type;
|
||||
@@ -1,48 +0,0 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SteelSeriesGeneric.h |
|
||||
| |
|
||||
| Generic file for SteelSeries devices |
|
||||
| |
|
||||
| B Horn (bahorn) 17 May 2020 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
|
||||
/* Allows us to handle variation in the protocol.
|
||||
* Defined in a single enum so we can keep the device_list struct the same
|
||||
* for every possible device. */
|
||||
typedef enum
|
||||
{
|
||||
RIVAL_100 = 0x00,
|
||||
RIVAL_300 = 0x01,
|
||||
RIVAL_650 = 0x02,
|
||||
SIBERIA_350 = 0x03,
|
||||
APEX = 0x04,
|
||||
APEX_M = 0x05,
|
||||
APEX_OLD = 0x06,
|
||||
SENSEI = 0x07,
|
||||
RIVAL_600 = 0x08,
|
||||
RIVAL_3 = 0x09,
|
||||
APEX_TZONE = 0x0A,
|
||||
RIVAL_700 = 0x0B,
|
||||
AEROX_3 = 0x0C,
|
||||
APEX_8ZONE = 0x0D,
|
||||
AEROX_3_WIRELESS = 0x0E,
|
||||
AEROX_3_WIRELESS_WIRED = 0x0F,
|
||||
AEROX_5_WIRELESS = 0x10,
|
||||
AEROX_5_WIRELESS_WIRED = 0x11,
|
||||
AEROX_5_DESTINY_WIRELESS = 0x12,
|
||||
AEROX_5_DESTINY_WIRELESS_WIRED = 0x13,
|
||||
AEROX_5_DIABLO_WIRELESS = 0x14,
|
||||
AEROX_5_DIABLO_WIRELESS_WIRED = 0x15,
|
||||
AEROX_9_WIRELESS = 0x16,
|
||||
AEROX_9_WIRELESS_WIRED = 0x17,
|
||||
APEX_9_TKL = 0x18,
|
||||
APEX_9_MINI = 0x19,
|
||||
} steelseries_type;
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <hidapi.h>
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
|
||||
#define STEELSERIES_MOUSE_BRIGHTNESS_MAX 0x64
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "color32.h"
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
|
||||
/* Mode, we then use these to set actual effect based on speed. */
|
||||
enum
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
#include "SteelSeriesMouseController.h"
|
||||
|
||||
static const steelseries_mouse rival_3 =
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
|
||||
/* Mode, we then use these to set actual effect based on speed. */
|
||||
enum
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "SteelSeriesGeneric.h"
|
||||
#include "SteelSeriesDevices.h"
|
||||
|
||||
/*-------------------------------------------------------------*\
|
||||
| Mode, we then use these to set actual effect based on speed. |
|
||||
|
||||
Reference in New Issue
Block a user