Skip to content

Commit 05b4f00

Browse files
rodrigost23CalcProgrammer1
authored andcommitted
Add support for Aula F99 and Aula F75
1 parent 946383b commit 05b4f00

7 files changed

Lines changed: 544 additions & 0 deletions

Controllers/SinowealthController/SinowealthControllerDetect.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
\*---------------------------------------------------------*/
99

1010
#include "Detector.h"
11+
#include "RGBController_SinowealthKeyboard10c.h"
1112
#include "SinowealthController.h"
1213
#include "SinowealthController1007.h"
14+
#include "SinowealthKeyboard10cController.h"
15+
#include "SinowealthKeyboard10cDevices.h"
1316
#include "SinowealthKeyboardController.h" // Disabled
1417
#include "SinowealthKeyboard16Controller.h" // Disabled
1518
#include "SinowealthKeyboard90Controller.h"
@@ -40,6 +43,7 @@
4043
#define RGB_KEYBOARD_0016PID 0x0016
4144
#define GENESIS_THOR_300_PID 0x0090
4245
#define GENESIS_XENON_200_PID 0x1007
46+
#define RGB_KEYBOARD_010CPID 0x010C
4347

4448
/******************************************************************************************\
4549
* *
@@ -59,6 +63,7 @@ struct expected_report
5963
unsigned int cmd_size;
6064
hid_device* cmd_device = nullptr;
6165
hid_device* device = nullptr;
66+
unsigned char* response = nullptr;
6267

6368
expected_report(unsigned int id, unsigned size) : id(id), size(size) {}
6469
expected_report(unsigned int id, unsigned size, unsigned char* cmd_buf, unsigned int cmd_size) : id(id), size(size), cmd_buf(cmd_buf), cmd_size(cmd_size) {}
@@ -185,6 +190,10 @@ static bool DetectUsages(hid_device_info* info, std::string name, unsigned int d
185190
device_count++;
186191
report_found = true;
187192
report.device = device;
193+
194+
report.response = new unsigned char[report.size];
195+
std::memcpy(report.response, tmp_buf, report.size);
196+
188197
LOG_TRACE("[%s] Successfully requested feature ReportId 0x%02X from device at location \"HID: %s\", handle: %08X", name.c_str(), report.id, info_temp->path, device);
189198
}
190199
}
@@ -216,6 +225,11 @@ static bool DetectUsages(hid_device_info* info, std::string name, unsigned int d
216225
{
217226
for(expected_report& report: reports)
218227
{
228+
if(report.response != nullptr)
229+
{
230+
delete[] report.response;
231+
report.response = nullptr;
232+
}
219233
if(report.device != nullptr)
220234
{
221235
hid_close(report.device);
@@ -416,6 +430,28 @@ static void DetectSinowealthGenesisKeyboard(hid_device_info* info, const std::st
416430
}
417431
}
418432

433+
static void DetectSinowealthKeyboard10c(hid_device_info* info, const std::string& name)
434+
{
435+
unsigned char command[7] = {0x06, 0x82, 0x01, 0x00, 0x01, 0x00, 0x06};
436+
expected_reports reports{expected_report(0x06, 520, command, 520)};
437+
438+
if(!DetectUsages(info, name, 3, reports))
439+
{
440+
return;
441+
}
442+
443+
hid_device *dev = reports.at(0).device;
444+
unsigned char model_id = reports.at(0).response[13];
445+
446+
if(dev && sinowealth_10c_keyboards.find(model_id) != sinowealth_10c_keyboards.end())
447+
{
448+
SinowealthKeyboard10cController* controller = new SinowealthKeyboard10cController(dev, info->path, sinowealth_10c_keyboards.at(model_id).device_name);
449+
RGBController_SinowealthKeyboard10c* rgb_controller = new RGBController_SinowealthKeyboard10c(controller, model_id);
450+
451+
ResourceManager::get()->RegisterRGBController(rgb_controller);
452+
}
453+
}
454+
419455
#ifdef USE_HID_USAGE
420456
REGISTER_HID_DETECTOR_P("Glorious Model O / O-", DetectSinowealthMouse, SINOWEALTH_VID, Glorious_Model_O_PID, 0xFF00 );
421457
REGISTER_HID_DETECTOR_P("Glorious Model D / D-", DetectSinowealthMouse, SINOWEALTH_VID, Glorious_Model_D_PID, 0xFF00 );
@@ -427,6 +463,7 @@ REGISTER_HID_DETECTOR_PU("Glorious Model D / D- Wireless", DetectGMOW_Dongle,
427463
REGISTER_HID_DETECTOR_PU("Glorious Model D / D- Wireless", DetectGMOW_Cable, SINOWEALTH_VID, Glorious_Model_DW_PID2, 0xFFFF, 0x0000 );
428464
REGISTER_HID_DETECTOR_PU("Genesis Xenon 200", DetectGenesisXenon200, SINOWEALTH_VID, GENESIS_XENON_200_PID, 0xFF00, 1 );
429465
REGISTER_HID_DETECTOR_IPU("Genesis Thor 300", DetectSinowealthGenesisKeyboard, SINOWEALTH_VID, GENESIS_THOR_300_PID, 1, 0xFF00, 1 );
466+
REGISTER_HID_DETECTOR_IPU("Sinowealth Keyboard", DetectSinowealthKeyboard10c, SINOWEALTH_VID, RGB_KEYBOARD_010CPID, 1, 0xFF00, 1 );
430467

431468
// Sinowealth keyboards are disabled due to VID/PID pairs being reused from Redragon keyboards, which ended up in bricking the latter
432469
//REGISTER_HID_DETECTOR_P("FL ESPORTS F11", DetectSinowealthKeyboard, SINOWEALTH_VID, Fl_Esports_F11_PID, 0xFF00 );
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*---------------------------------------------------------*\
2+
| RGBController_SinowealthKeyboard10c.cpp |
3+
| |
4+
| RGBController for Sinowealth Keyboards with PID 010C |
5+
| |
6+
| Rodrigo Tavares 27 Nov 2025 |
7+
| |
8+
| This file is part of the OpenRGB project |
9+
| SPDX-License-Identifier: GPL-2.0-or-later |
10+
\*---------------------------------------------------------*/
11+
12+
#include "KeyboardLayoutManager.h"
13+
#include "RGBControllerKeyNames.h"
14+
#include "SinowealthKeyboard10cController.h"
15+
#include "SinowealthKeyboard10cDevices.h"
16+
#include "RGBController_SinowealthKeyboard10c.h"
17+
18+
using namespace kbd10c;
19+
using namespace std::chrono_literals;
20+
21+
/**------------------------------------------------------------------*\
22+
@name Sinowealth Keyboard
23+
@category Keyboard
24+
@type USB
25+
@save :x:
26+
@direct :white_check_mark:
27+
@effects :x:
28+
@detectors DetectSinowealthKeyboard10c
29+
@comment
30+
\*-------------------------------------------------------------------*/
31+
32+
RGBController_SinowealthKeyboard10c::RGBController_SinowealthKeyboard10c(
33+
SinowealthKeyboard10cController* controller_ptr, unsigned char model_id)
34+
: model_id(model_id)
35+
{
36+
controller = controller_ptr;
37+
38+
name = controller->GetName();
39+
type = DEVICE_TYPE_KEYBOARD;
40+
vendor = "Sinowealth";
41+
description = "Sinowealth Keyboard Device";
42+
location = controller->GetLocation();
43+
serial = controller->GetSerialString();
44+
45+
mode Off;
46+
Off.name = "Off";
47+
Off.flags = 0;
48+
Off.color_mode = MODE_COLORS_NONE;
49+
Off.value = MODE_OFF;
50+
modes.push_back(Off);
51+
52+
mode Direct;
53+
Direct.name = "Direct";
54+
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
55+
Direct.color_mode = MODE_COLORS_PER_LED;
56+
Direct.value = MODE_DIRECT;
57+
modes.push_back(Direct);
58+
59+
active_mode = MODE_DIRECT;
60+
61+
SetupZones();
62+
63+
/*---------------------------------------------------------*\
64+
| The Sinowealth 010C Keyboard requires a steady stream |
65+
| of packets in order to not revert out of direct mode. |
66+
| Start a thread to continuously refresh the device |
67+
\*---------------------------------------------------------*/
68+
keepalive_thread_run = true;
69+
keepalive_thread = new std::thread(&RGBController_SinowealthKeyboard10c::KeepaliveThreadFunction, this);
70+
}
71+
72+
RGBController_SinowealthKeyboard10c::~RGBController_SinowealthKeyboard10c()
73+
{
74+
keepalive_thread_run = false;
75+
keepalive_thread->join();
76+
delete keepalive_thread;
77+
delete controller;
78+
}
79+
80+
void RGBController_SinowealthKeyboard10c::SetupZones()
81+
{
82+
/*---------------------------------------------------------*\
83+
| Create the keyboard zone usiung Keyboard Layout Manager |
84+
\*---------------------------------------------------------*/
85+
zone new_zone;
86+
new_zone.name = ZONE_EN_KEYBOARD;
87+
new_zone.type = ZONE_TYPE_MATRIX;
88+
89+
sinowealth_device device = sinowealth_10c_keyboards.at(model_id);
90+
91+
KeyboardLayoutManager new_kb(KEYBOARD_LAYOUT_ANSI_QWERTY, device.keyboard_layout.base_size,
92+
device.keyboard_layout.key_values);
93+
new_kb.ChangeKeys(device.keyboard_layout.edit_keys);
94+
95+
matrix_map_type* new_map = new matrix_map_type;
96+
new_zone.matrix_map = new_map;
97+
new_zone.matrix_map->height = new_kb.GetRowCount();
98+
new_zone.matrix_map->width = new_kb.GetColumnCount();
99+
100+
new_zone.matrix_map->map = new unsigned int[new_map->height * new_map->width];
101+
new_zone.leds_count = new_kb.GetRowCount() * new_kb.GetColumnCount();
102+
new_zone.leds_min = new_zone.leds_count;
103+
new_zone.leds_max = new_zone.leds_count;
104+
105+
/*---------------------------------------------------------*\
106+
| These keyboards use sparse LED indexes — for example, a |
107+
| 99-key board might use LED indexes 0–112, leaving some |
108+
| numbers unused. Empty positions are marked 0xFFFFFFFF. |
109+
| |
110+
| We map each key to its actual LED index, filling the |
111+
| `leds` vector by those indexes and leaving gaps where no |
112+
| LED exists. |
113+
\*---------------------------------------------------------*/
114+
115+
new_kb.GetKeyMap(new_map->map, KEYBOARD_MAP_FILL_TYPE_VALUE, new_map->height, new_map->width);
116+
117+
leds.resize(new_zone.leds_count);
118+
119+
for(unsigned int i = 0, j = 0; i < new_zone.leds_count; i++)
120+
{
121+
if(new_map->map[i] == 0xFFFFFFFF)
122+
{
123+
continue;
124+
}
125+
126+
led new_led;
127+
128+
new_led.name = new_kb.GetKeyNameAt(j);
129+
new_led.value = new_kb.GetKeyValueAt(j);
130+
131+
leds[new_map->map[i]] = new_led;
132+
133+
j++;
134+
}
135+
136+
zones.push_back(new_zone);
137+
138+
SetupColors();
139+
}
140+
141+
void RGBController_SinowealthKeyboard10c::ResizeZone(int /*zone*/, int /*new_size*/)
142+
{
143+
/*---------------------------------------------------------*\
144+
| This device does not support resizing zones |
145+
\*---------------------------------------------------------*/
146+
}
147+
148+
void RGBController_SinowealthKeyboard10c::DeviceUpdateLEDs()
149+
{
150+
last_update_time = std::chrono::steady_clock::now();
151+
controller->SetLEDsDirect(colors);
152+
}
153+
154+
void RGBController_SinowealthKeyboard10c::UpdateZoneLEDs(int /*zone*/)
155+
{
156+
DeviceUpdateLEDs();
157+
}
158+
159+
void RGBController_SinowealthKeyboard10c::UpdateSingleLED(int /*led*/)
160+
{
161+
DeviceUpdateLEDs();
162+
}
163+
164+
void RGBController_SinowealthKeyboard10c::DeviceUpdateMode()
165+
{
166+
}
167+
168+
void RGBController_SinowealthKeyboard10c::KeepaliveThreadFunction()
169+
{
170+
while(keepalive_thread_run.load())
171+
{
172+
if(active_mode == MODE_DIRECT && (std::chrono::steady_clock::now() - last_update_time) > 1s)
173+
{
174+
UpdateLEDs();
175+
}
176+
std::this_thread::sleep_for(500ms);
177+
}
178+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*---------------------------------------------------------*\
2+
| RGBController_SinowealthKeyboard10c.h |
3+
| |
4+
| RGBController for Sinowealth Keyboards with PID 010C |
5+
| |
6+
| Rodrigo Tavares 27 Nov 2025 |
7+
| |
8+
| This file is part of the OpenRGB project |
9+
| SPDX-License-Identifier: GPL-2.0-or-later |
10+
\*---------------------------------------------------------*/
11+
12+
#pragma once
13+
14+
#include "RGBController.h"
15+
#include "SinowealthKeyboard10cController.h"
16+
17+
class RGBController_SinowealthKeyboard10c : public RGBController
18+
{
19+
public:
20+
RGBController_SinowealthKeyboard10c(SinowealthKeyboard10cController* controller_ptr, unsigned char model_id);
21+
~RGBController_SinowealthKeyboard10c();
22+
23+
void SetupZones();
24+
void ResizeZone(int zone, int new_size);
25+
26+
void DeviceUpdateLEDs();
27+
void UpdateZoneLEDs(int zone);
28+
void UpdateSingleLED(int led);
29+
30+
void DeviceUpdateMode();
31+
32+
private:
33+
void KeepaliveThreadFunction();
34+
35+
std::chrono::time_point<std::chrono::steady_clock> last_update_time;
36+
unsigned char model_id;
37+
SinowealthKeyboard10cController* controller;
38+
std::atomic<bool> keepalive_thread_run;
39+
std::thread* keepalive_thread;
40+
};
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*---------------------------------------------------------*\
2+
| SinowealthKeyboard10cController.cpp |
3+
| |
4+
| Driver for Sinowealth Keyboards with PID 010C |
5+
| |
6+
| Rodrigo Tavares 27 Nov 2025 |
7+
| |
8+
| This file is part of the OpenRGB project |
9+
| SPDX-License-Identifier: GPL-2.0-or-later |
10+
\*---------------------------------------------------------*/
11+
12+
#include <cstring>
13+
#include "SinowealthKeyboard10cController.h"
14+
#include "RGBController.h"
15+
#include "StringUtils.h"
16+
17+
using namespace kbd10c;
18+
19+
SinowealthKeyboard10cController::SinowealthKeyboard10cController(hid_device* dev_handle, char* path,
20+
std::string dev_name)
21+
{
22+
dev = dev_handle;
23+
name = dev_name;
24+
25+
current_mode = MODE_DIRECT;
26+
27+
location = path;
28+
}
29+
30+
SinowealthKeyboard10cController::~SinowealthKeyboard10cController()
31+
{
32+
hid_close(dev);
33+
}
34+
35+
std::string SinowealthKeyboard10cController::GetLocation()
36+
{
37+
return ("HID: " + location);
38+
}
39+
40+
std::string SinowealthKeyboard10cController::GetName()
41+
{
42+
return (name);
43+
}
44+
45+
unsigned char SinowealthKeyboard10cController::GetCurrentMode()
46+
{
47+
return current_mode;
48+
}
49+
50+
std::string SinowealthKeyboard10cController::GetSerialString()
51+
{
52+
wchar_t serial_string[128];
53+
int ret = hid_get_serial_number_string(dev, serial_string, 128);
54+
55+
if(ret != 0)
56+
{
57+
return ("");
58+
}
59+
60+
return (StringUtils::wstring_to_string(serial_string));
61+
}
62+
63+
void SinowealthKeyboard10cController::SetLEDsDirect(std::vector<RGBColor> colors)
64+
{
65+
const int buffer_size = 520;
66+
unsigned char buf[buffer_size];
67+
memset(buf, 0x00, buffer_size);
68+
69+
buf[0x00] = 0x06;
70+
buf[0x01] = 0x08;
71+
buf[0x04] = 0x01;
72+
buf[0x06] = 0x7A;
73+
buf[0x07] = 0x01;
74+
75+
for(size_t i = 0; i < colors.size(); ++i)
76+
{
77+
buf[0x08 + i * 3] = RGBGetRValue(colors[i]);
78+
buf[0x08 + i * 3 + 1] = RGBGetGValue(colors[i]);
79+
buf[0x08 + i * 3 + 2] = RGBGetBValue(colors[i]);
80+
}
81+
82+
hid_send_feature_report(dev, buf, buffer_size);
83+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
84+
}

0 commit comments

Comments
 (0)