From 8a831cef040a726793a0c9ddc4d8d54db09beba3 Mon Sep 17 00:00:00 2001 From: Ilya Miller Date: Fri, 24 Jul 2026 18:53:06 +0000 Subject: [PATCH] Add Dark Project KD104A support to the Keyrox Classic driver --- .../RedSquareKeyroxControllerDetect.cpp | 23 -- .../RedSquareKeyroxTKLClassicController.cpp | 169 ----------- .../RedSquareKeyroxTKLClassicController.h | 78 ----- .../RGBController_WitmodKeyboard.cpp} | 133 +++++--- .../RGBController_WitmodKeyboard.h} | 24 +- .../WitmodKeyboardController.cpp | 283 ++++++++++++++++++ .../WitmodKeyboardController.h | 103 +++++++ .../WitmodKeyboardControllerDetect.cpp | 43 +++ 8 files changed, 533 insertions(+), 323 deletions(-) delete mode 100644 Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RedSquareKeyroxTKLClassicController.cpp delete mode 100644 Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RedSquareKeyroxTKLClassicController.h rename Controllers/{RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RGBController_RedSquareKeyroxTKLClassic.cpp => WitmodKeyboardController/RGBController_WitmodKeyboard.cpp} (58%) rename Controllers/{RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RGBController_RedSquareKeyroxTKLClassic.h => WitmodKeyboardController/RGBController_WitmodKeyboard.h} (52%) create mode 100644 Controllers/WitmodKeyboardController/WitmodKeyboardController.cpp create mode 100644 Controllers/WitmodKeyboardController/WitmodKeyboardController.h create mode 100644 Controllers/WitmodKeyboardController/WitmodKeyboardControllerDetect.cpp diff --git a/Controllers/RedSquareKeyroxController/RedSquareKeyroxControllerDetect.cpp b/Controllers/RedSquareKeyroxController/RedSquareKeyroxControllerDetect.cpp index b4788117b..782a2791f 100644 --- a/Controllers/RedSquareKeyroxController/RedSquareKeyroxControllerDetect.cpp +++ b/Controllers/RedSquareKeyroxController/RedSquareKeyroxControllerDetect.cpp @@ -12,22 +12,18 @@ #include #include "DetectionManager.h" #include "RedSquareKeyroxController.h" -#include "RedSquareKeyroxTKLClassicController.h" #include "RGBController_RedSquareKeyrox.h" -#include "RGBController_RedSquareKeyroxTKLClassic.h" /*---------------------------------------------------------*\ | Red Square vendor ID | \*---------------------------------------------------------*/ #define RED_SQUARE_VID 0x1A2C -#define RED_SQUARE_KEYROX_TKL_CLASSIC_VID 0x0416 /*---------------------------------------------------------*\ | Red Square product ID | \*---------------------------------------------------------*/ #define RED_SQUARE_KEYROX_TKL_PID 0x1511 #define RED_SQUARE_KEYROX_TKL_V2_PID 0x2511 -#define RED_SQUARE_KEYROX_TKL_CLASSIC_PID 0xC345 DetectedControllers DetectRedSquareKeyroxTKL(hid_device_info* info, const std::string& name) { @@ -47,24 +43,5 @@ DetectedControllers DetectRedSquareKeyroxTKL(hid_device_info* info, const std::s return(detected_controllers); } -DetectedControllers DetectRedSquareKeyroxTKLClassic(hid_device_info* info, const std::string& name) -{ - DetectedControllers detected_controllers; - hid_device* dev; - - dev = hid_open_path(info->path); - - if(dev) - { - RedSquareKeyroxTKLClassicController* controller = new RedSquareKeyroxTKLClassicController(dev, *info, name); - RGBController_RedSquareKeyroxTKLClassic* rgb_controller = new RGBController_RedSquareKeyroxTKLClassic(controller); - - detected_controllers.push_back(rgb_controller); - } - - return(detected_controllers); -} - REGISTER_HID_DETECTOR_IPU("Red Square Keyrox TKL", DetectRedSquareKeyroxTKL, RED_SQUARE_VID, RED_SQUARE_KEYROX_TKL_PID, 3, 0xFF00, 2); REGISTER_HID_DETECTOR_IPU("Red Square Keyrox TKL V2", DetectRedSquareKeyroxTKL, RED_SQUARE_VID, RED_SQUARE_KEYROX_TKL_V2_PID, 3, 0xFF00, 2); -REGISTER_HID_DETECTOR_I( "Red Square Keyrox TKL Classic", DetectRedSquareKeyroxTKLClassic, RED_SQUARE_KEYROX_TKL_CLASSIC_VID, RED_SQUARE_KEYROX_TKL_CLASSIC_PID, 2); diff --git a/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RedSquareKeyroxTKLClassicController.cpp b/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RedSquareKeyroxTKLClassicController.cpp deleted file mode 100644 index 66c127b47..000000000 --- a/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RedSquareKeyroxTKLClassicController.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/*---------------------------------------------------------*\ -| RedSquareKeyroxTKLClassicController.cpp | -| | -| Driver for Red Square Keyrox TKL Classic | -| | -| vlack 03 May 2023 | -| | -| This file is part of the OpenRGB project | -| SPDX-License-Identifier: GPL-2.0-or-later | -\*---------------------------------------------------------*/ - -#include "LogManager.h" -#include "RedSquareKeyroxTKLClassicController.h" - -using namespace std::chrono_literals; - -RedSquareKeyroxTKLClassicController::RedSquareKeyroxTKLClassicController(hid_device *dev_handle, const hid_device_info &info, std::string dev_name) -{ - dev = dev_handle; - location = info.path; - name = dev_name; -} - -RedSquareKeyroxTKLClassicController::~RedSquareKeyroxTKLClassicController() -{ - hid_close(dev); -} - -std::string RedSquareKeyroxTKLClassicController::GetDeviceLocation() -{ - return("HID: " + location); -} - -std::string RedSquareKeyroxTKLClassicController::GetNameString() -{ - return(name); -} - -std::string RedSquareKeyroxTKLClassicController::GetSerialString() -{ - wchar_t serial_wchar[128]; - hid_get_serial_number_string(dev, serial_wchar, 128); - std::wstring serial_wstring(serial_wchar); - - std::string serial_string; - std::transform(serial_wstring.begin(), serial_wstring.end(), std::back_inserter(serial_string), [] (wchar_t i) - { - return (char)i; - }); - - return serial_string; -} - -int RedSquareKeyroxTKLClassicController::GetDirection(int direction) -{ - switch(direction) - { - case MODE_DIRECTION_LEFT: - return 0x00; - case MODE_DIRECTION_RIGHT: - return 0x01; - case MODE_DIRECTION_UP: - return 0x02; - case MODE_DIRECTION_DOWN: - return 0x03; - case MODE_DIRECTION_HORIZONTAL: // actually direction out - return 0x04; - case MODE_DIRECTION_VERTICAL: // actually direction in - return 0x05; - default: - return 0x00; - } -} - -int RedSquareKeyroxTKLClassicController::GetDirectionRound(int direction) -{ - switch(direction) - { - case MODE_DIRECTION_LEFT: // actually anticlockwise - return 0x07; - case MODE_DIRECTION_RIGHT: // actually clockwise - return 0x06; - default: - return 0x00; - } -} - -void RedSquareKeyroxTKLClassicController::SetMode(mode m) -{ - /*---------------------------------------------*\ - | Mode set command | - \*---------------------------------------------*/ - - unsigned char usb_buf[CLASSIC_PACKET_DATA_LENGTH]; - memset(usb_buf, 0x00, CLASSIC_PACKET_DATA_LENGTH); - - usb_buf[0] = 0x01; - usb_buf[1] = 0x07; - usb_buf[6] = m.value; - usb_buf[7] = m.brightness; // brightness - usb_buf[8] = m.speed; // speed - - if(m.colors_max == 1 || m.colors_max == 2) - { - usb_buf[9] = RGBGetRValue(m.colors[0]); // front R - usb_buf[10] = RGBGetGValue(m.colors[0]); // front G - usb_buf[11] = RGBGetBValue(m.colors[0]); // front B - } - - if(m.colors_max == 2 && m.color_mode != MODE_COLORS_RANDOM) - { - usb_buf[12] = RGBGetRValue(m.colors[1]); // back R - usb_buf[13] = RGBGetGValue(m.colors[1]); // back G - usb_buf[14] = RGBGetBValue(m.colors[1]); // back B - } - - if(m.value == CLASSIC_RADAR_MODE_VALUE || m.value == CLASSIC_RUNNING_LINE_MODE_VALUE) - { - usb_buf[15] = GetDirectionRound(m.direction); - } - else - { - usb_buf[15] = GetDirection(m.direction); - } - - usb_buf[16] = m.color_mode == MODE_COLORS_RANDOM; - - hid_write(dev, usb_buf, CLASSIC_PACKET_DATA_LENGTH); - // sleep is necessary - std::this_thread::sleep_for(10ms); -} - -void RedSquareKeyroxTKLClassicController::SetLEDsData(std::vector colors, std::vector leds) -{ - /*---------------------------------------------*\ - | LEDs data set command | - \*---------------------------------------------*/ - - unsigned char usb_buf[CLASSIC_PACKET_DATA_LENGTH * 8]; - memset(usb_buf, 0x00, CLASSIC_PACKET_DATA_LENGTH * 8); - - for(unsigned int i = 0; i < colors.size(); i++) - { - int offset = leds[i].value; - usb_buf[offset - 1] = RGBGetRValue(colors[i]); - usb_buf[offset] = RGBGetGValue(colors[i]); - usb_buf[offset + 1] = RGBGetBValue(colors[i]); - } - - for(unsigned int i = 0; i < 8; i++) - { - unsigned char packet[CLASSIC_PACKET_DATA_LENGTH]; - memset(packet, 0x00, CLASSIC_PACKET_DATA_LENGTH); - - packet[0] = 0x01; - packet[1] = 0x0F; - packet[4] = i; // package number - packet[5] = i == 7 ? 0x12 : 0x36; // package size - - for (int x = 6; x < CLASSIC_PACKET_DATA_LENGTH; x++) - { - packet[x] = usb_buf[CLASSIC_PACKET_DATA_LENGTH * i + x]; - } - hid_write(dev, packet, CLASSIC_PACKET_DATA_LENGTH); - } - - // sleep is necessary - std::this_thread::sleep_for(10ms); -} diff --git a/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RedSquareKeyroxTKLClassicController.h b/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RedSquareKeyroxTKLClassicController.h deleted file mode 100644 index 5455fa11a..000000000 --- a/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RedSquareKeyroxTKLClassicController.h +++ /dev/null @@ -1,78 +0,0 @@ -/*---------------------------------------------------------*\ -| RedSquareKeyroxTKLClassicController.h | -| | -| Driver for Red Square Keyrox TKL Classic | -| | -| vlack 03 May 2023 | -| | -| This file is part of the OpenRGB project | -| SPDX-License-Identifier: GPL-2.0-or-later | -\*---------------------------------------------------------*/ - -#pragma once - -#include -#include -#include "RGBController.h" - -#define CLASSIC_PACKET_DATA_LENGTH 64 - -/*---------------------------------------*\ -| Modes | -\*---------------------------------------*/ -enum -{ - CLASSIC_CONST_MODE_VALUE = 0x00, // static - CLASSIC_BREATHE_MODE_VALUE = 0x01, // breath - CLASSIC_WAVE_MODE_VALUE = 0x02, // wave - CLASSIC_FADE_MODE_VALUE = 0x03, // neon - CLASSIC_RADAR_MODE_VALUE = 0x04, // radar - CLASSIC_STAR_MODE_VALUE = 0x06, // интерактив - CLASSIC_LINE_MODE_VALUE = 0x07, // сияние - CLASSIC_RIPPLE_MODE_VALUE = 0x08, // рябь интерактив - CLASSIC_STARS_MODE_VALUE = 0x09, // мерцание - CLASSIC_CUSTOM_MODE_VALUE = 0x0A, - CLASSIC_CROSS_MODE_VALUE = 0x0B, // скрещивание - CLASSIC_WTF_MODE_VALUE = 0x0C, // быстрый отклик - CLASSIC_RIPPLE_RANDOM_MODE_VALUE = 0x0E, // рябь - CLASSIC_RUNNING_LINE_MODE_VALUE = 0x0F, // бегущая строка - CLASSIC_FIREWORK_MODE_VALUE = 0x10, // firework -}; - -/*-----------------------------*\ -| Other settings | -\*-----------------------------*/ -enum -{ - CLASSIC_KEYROX_BRIGHTNESS_MIN = 0x00, - CLASSIC_KEYROX_BRIGHTNESS_MAX = 0x04, - CLASSIC_KEYROX_SPEED_MIN = 0x00, - CLASSIC_KEYROX_SPEED_MAX = 0x04, -}; - - -class RedSquareKeyroxTKLClassicController -{ -public: - RedSquareKeyroxTKLClassicController(hid_device *dev_handle, const hid_device_info &info, std::string dev_name); - ~RedSquareKeyroxTKLClassicController(); - - std::string GetDeviceLocation(); - std::string GetNameString(); - std::string GetSerialString(); - - int GetDirection(int direction); - int GetDirectionRound(int direction); - - void SetMode(mode m); - void SetLEDsData(std::vector colors, std::vector leds); - -protected: - hid_device* dev; - -private: - std::string location; - std::string name; - std::string serial_number; - std::vector led_sequence_positions; -}; diff --git a/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RGBController_RedSquareKeyroxTKLClassic.cpp b/Controllers/WitmodKeyboardController/RGBController_WitmodKeyboard.cpp similarity index 58% rename from Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RGBController_RedSquareKeyroxTKLClassic.cpp rename to Controllers/WitmodKeyboardController/RGBController_WitmodKeyboard.cpp index 754f3ca99..f33d8a2f6 100644 --- a/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RGBController_RedSquareKeyroxTKLClassic.cpp +++ b/Controllers/WitmodKeyboardController/RGBController_WitmodKeyboard.cpp @@ -1,7 +1,7 @@ /*---------------------------------------------------------*\ -| RGBController_RedSquareKeyroxTKLClassic.cpp | +| RGBController_WitmodKeyboard.cpp | | | -| RGBController for Red Square Keyrox TKL Classic | +| RGBController for Witmod keyboards | | | | vlack 03 May 2023 | | | @@ -9,17 +9,21 @@ | SPDX-License-Identifier: GPL-2.0-or-later | \*---------------------------------------------------------*/ -#include "RGBController_RedSquareKeyroxTKLClassic.h" +#include "RGBController_WitmodKeyboard.h" /**------------------------------------------------------------------*\ - @name Keyrox + @name Witmod Keyboard @category Keyboard @type USB @save :robot: @direct :white_check_mark: @effects :white_check_mark: - @detectors DetectRedSquareKeyroxTKLClassic - @comment Also named Dark Project KD87a + @detectors DetectWitmodKeyboard + @comment Witmod platform. The GK8110 (87 key) and GK8120 (104 key) + boards are resold under several brands, including Dark Project KD87A + and KD104A and the Red Square Keyrox TKL Classic. The sizes share + the same USB IDs and are told apart by the model reported in the + device info string. \*-------------------------------------------------------------------*/ typedef struct @@ -27,12 +31,12 @@ typedef struct std::string name; int value; int flags; -} keyrox_effect; +} witmod_effect; /*--------------------*\ -| Keyrox TKL Classic | +| GK8110 (87 keys) | \*--------------------*/ -layout_values keyrox_tkl_offset_values = +layout_values gk8110_offset_values = { { /* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */ @@ -53,90 +57,115 @@ layout_values keyrox_tkl_offset_values = } }; -RGBController_RedSquareKeyroxTKLClassic::RGBController_RedSquareKeyroxTKLClassic(RedSquareKeyroxTKLClassicController* controller_ptr) +/*--------------------*\ +| GK8120 (104 keys) | +\*--------------------*/ +layout_values gk8120_offset_values = +{ + { + /* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */ + 7, 13, 16, 19, 22, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, + /* BKTK 1 2 3 4 5 6 7 8 9 0 - = BSPC INS HOME PGUP NLCK NUM/ NUM* NUM- */ + 83, 86, 89, 92, 95, 98, 101, 104, 107, 110, 113, 116, 119, 135, 138, 141, 144, 147, 150, 153, 156, + /* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NUM7 NUM8 NUM9 NUM+ */ + 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 199, 202, 205, 211, 214, 217, 220, 223, 226, 229, 232, + /* CPLK A S D F G H J K L ; " # ENTR NUM4 NUM5 NUM6 */ + 235, 241, 244, 247, 250, 263, 266, 269, 272, 275, 278, 281, 284, 287, 299, 302, 305, + /* LSFT ISO\ Z X C V B N M , . / RSFT ARWU NUM1 NUM2 NUM3 NENT */ + 311, 314, 327, 330, 333, 336, 339, 342, 345, 348, 351, 354, 363, 369, 375, 378, 391, 394, + /* LCTL LWIN LALT SPC RALT RFNC RMNU RCTL ARWL ARWD ARWR NUM0 NUM. */ + 397, 400, 403, 415, 427, 430, 433, 436, 442, 455, 458, 461, 467 + }, + { + /* Add more regional layout fixes here */ + } +}; + +RGBController_WitmodKeyboard::RGBController_WitmodKeyboard(WitmodKeyboardController* controller_ptr) { controller = controller_ptr; name = controller->GetNameString(); - vendor = "Red Square"; + vendor = controller->GetVendorString(); type = DEVICE_TYPE_KEYBOARD; - description = "Red Square Keyrox TKL Classic Device"; + description = "Witmod Keyboard Device"; + version = controller->GetVersionString(); location = controller->GetDeviceLocation(); serial = controller->GetSerialString(); int BASE_EFFECT_FLAGS = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR; const int EFFECTS_COUNT = 14; - keyrox_effect keyrox_effects[EFFECTS_COUNT] = + witmod_effect witmod_effects[EFFECTS_COUNT] = { { "Static", - CLASSIC_CONST_MODE_VALUE, + WITMOD_CONST_MODE_VALUE, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR }, { "Direct", - CLASSIC_CUSTOM_MODE_VALUE, + WITMOD_CUSTOM_MODE_VALUE, MODE_FLAG_HAS_PER_LED_COLOR }, { "Wave", - CLASSIC_WAVE_MODE_VALUE, + WITMOD_WAVE_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR | MODE_FLAG_HAS_DIRECTION_UD | MODE_FLAG_HAS_DIRECTION_HV }, { "Breathing", - CLASSIC_FADE_MODE_VALUE, + WITMOD_FADE_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED }, { "Radar", - CLASSIC_RADAR_MODE_VALUE, + WITMOD_RADAR_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR // round animation }, { "Star (Interactive)", - CLASSIC_STAR_MODE_VALUE, + WITMOD_STAR_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED }, { "Line (Interactive)", - CLASSIC_LINE_MODE_VALUE, + WITMOD_LINE_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_HV }, { "Ripple (Interactive)", - CLASSIC_RIPPLE_MODE_VALUE, + WITMOD_RIPPLE_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED }, { "Stars", - CLASSIC_STARS_MODE_VALUE, + WITMOD_STARS_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED }, { "Cross (Interactive)", - CLASSIC_CROSS_MODE_VALUE, + WITMOD_CROSS_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED }, { "Horizontal bars (Interactive)", - CLASSIC_WTF_MODE_VALUE, + WITMOD_WTF_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_DIRECTION_UD }, { "Ripple random", - CLASSIC_RIPPLE_RANDOM_MODE_VALUE, + WITMOD_RIPPLE_RANDOM_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED }, { "Running line", - CLASSIC_RUNNING_LINE_MODE_VALUE, + WITMOD_RUNNING_LINE_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR // round direction }, { "Fireworks (Interactive)", - CLASSIC_FIREWORK_MODE_VALUE, + WITMOD_FIREWORK_MODE_VALUE, BASE_EFFECT_FLAGS | MODE_FLAG_HAS_SPEED }, }; @@ -144,11 +173,11 @@ RGBController_RedSquareKeyroxTKLClassic::RGBController_RedSquareKeyroxTKLClassic for(int i = 0; i < EFFECTS_COUNT; i++) { mode m; - m.name = keyrox_effects[i].name; - m.value = keyrox_effects[i].value; - m.flags = keyrox_effects[i].flags | MODE_FLAG_HAS_BRIGHTNESS; + m.name = witmod_effects[i].name; + m.value = witmod_effects[i].value; + m.flags = witmod_effects[i].flags | MODE_FLAG_HAS_BRIGHTNESS; - if(m.flags & MODE_FLAG_HAS_MODE_SPECIFIC_COLOR && m.value != CLASSIC_CONST_MODE_VALUE) + if(m.flags & MODE_FLAG_HAS_MODE_SPECIFIC_COLOR && m.value != WITMOD_CONST_MODE_VALUE) { // background and foreground m.color_mode = MODE_COLORS_MODE_SPECIFIC; @@ -176,15 +205,15 @@ RGBController_RedSquareKeyroxTKLClassic::RGBController_RedSquareKeyroxTKLClassic if(m.flags & MODE_FLAG_HAS_SPEED) { - m.speed_min = CLASSIC_KEYROX_SPEED_MIN; - m.speed_max = CLASSIC_KEYROX_SPEED_MAX; - m.speed = (CLASSIC_KEYROX_SPEED_MAX - CLASSIC_KEYROX_SPEED_MIN) / 2; + m.speed_min = WITMOD_SPEED_MIN; + m.speed_max = WITMOD_SPEED_MAX; + m.speed = (WITMOD_SPEED_MAX - WITMOD_SPEED_MIN) / 2; } if(m.flags & MODE_FLAG_HAS_BRIGHTNESS) { - m.brightness_min = CLASSIC_KEYROX_BRIGHTNESS_MIN; - m.brightness_max = CLASSIC_KEYROX_BRIGHTNESS_MAX; + m.brightness_min = WITMOD_BRIGHTNESS_MIN; + m.brightness_max = WITMOD_BRIGHTNESS_MAX; m.brightness = m.brightness_max; } @@ -194,16 +223,32 @@ RGBController_RedSquareKeyroxTKLClassic::RGBController_RedSquareKeyroxTKLClassic SetupZones(); } -RGBController_RedSquareKeyroxTKLClassic::~RGBController_RedSquareKeyroxTKLClassic() +RGBController_WitmodKeyboard::~RGBController_WitmodKeyboard() { Shutdown(); delete controller; } -void RGBController_RedSquareKeyroxTKLClassic::SetupZones() +void RGBController_WitmodKeyboard::SetupZones() { - KeyboardLayoutManager new_kb(KEYBOARD_LAYOUT_ANSI_QWERTY, KEYBOARD_SIZE_TKL, keyrox_tkl_offset_values); + /*---------------------------------------------------------*\ + | Pick the layout for the size the controller reported. | + | The number pad sits in the four matrix columns to the | + | right of the GK8110 keys, so the map has to be built | + | wider or those keys are dropped from it. | + \*---------------------------------------------------------*/ + KEYBOARD_SIZE keyboard_size = controller->GetKeyboardSize(); + const layout_values* offset_values = &gk8110_offset_values; + unsigned char matrix_width = GK8110_WIDTH; + + if(keyboard_size == KEYBOARD_SIZE_FULL) + { + offset_values = &gk8120_offset_values; + matrix_width = GK8120_WIDTH; + } + + KeyboardLayoutManager new_kb(KEYBOARD_LAYOUT_ANSI_QWERTY, keyboard_size, *offset_values); /*---------------------------------------------------------*\ | Create the keyboard zone usiung Keyboard Layout Manager | @@ -214,7 +259,7 @@ void RGBController_RedSquareKeyroxTKLClassic::SetupZones() new_zone.leds_count = new_kb.GetKeyCount(); new_zone.leds_min = new_zone.leds_count; new_zone.leds_max = new_zone.leds_count; - new_zone.matrix_map = new_kb.GetKeyMap(KEYBOARD_MAP_FILL_TYPE_COUNT, KEYROX_TKL_CLASSIC_HEIGHT, KEYROX_TKL_CLASSIC_WIDTH); + new_zone.matrix_map = new_kb.GetKeyMap(KEYBOARD_MAP_FILL_TYPE_COUNT, WITMOD_MATRIX_HEIGHT, matrix_width); /*---------------------------------------------------------*\ | Create LEDs for the Matrix zone | @@ -234,22 +279,22 @@ void RGBController_RedSquareKeyroxTKLClassic::SetupZones() SetupColors(); } -void RGBController_RedSquareKeyroxTKLClassic::DeviceUpdateLEDs() +void RGBController_WitmodKeyboard::DeviceUpdateLEDs() { controller->SetLEDsData(colors, leds); } -void RGBController_RedSquareKeyroxTKLClassic::DeviceUpdateZoneLEDs(int /*zone*/) +void RGBController_WitmodKeyboard::DeviceUpdateZoneLEDs(int /*zone*/) { DeviceUpdateLEDs(); } -void RGBController_RedSquareKeyroxTKLClassic::DeviceUpdateSingleLED(int /*led*/) +void RGBController_WitmodKeyboard::DeviceUpdateSingleLED(int /*led*/) { DeviceUpdateLEDs(); } -void RGBController_RedSquareKeyroxTKLClassic::DeviceUpdateMode() +void RGBController_WitmodKeyboard::DeviceUpdateMode() { controller->SetMode(modes[active_mode]); } diff --git a/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RGBController_RedSquareKeyroxTKLClassic.h b/Controllers/WitmodKeyboardController/RGBController_WitmodKeyboard.h similarity index 52% rename from Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RGBController_RedSquareKeyroxTKLClassic.h rename to Controllers/WitmodKeyboardController/RGBController_WitmodKeyboard.h index 843b79ac0..30bbea748 100644 --- a/Controllers/RedSquareKeyroxController/RedSquareKeyroxTKLClassicController/RGBController_RedSquareKeyroxTKLClassic.h +++ b/Controllers/WitmodKeyboardController/RGBController_WitmodKeyboard.h @@ -1,7 +1,7 @@ /*---------------------------------------------------------*\ -| RGBController_RedSquareKeyroxTKLClassic.h | +| RGBController_WitmodKeyboard.h | | | -| RGBController for Red Square Keyrox TKL Classic | +| RGBController for Witmod keyboards | | | | vlack 03 May 2023 | | | @@ -14,16 +14,22 @@ #include "RGBController.h" #include "RGBControllerKeyNames.h" #include "KeyboardLayoutManager.h" -#include "RedSquareKeyroxTKLClassicController.h" +#include "WitmodKeyboardController.h" -#define KEYROX_TKL_CLASSIC_WIDTH 17 -#define KEYROX_TKL_CLASSIC_HEIGHT 6 +/*---------------------------------------------------------*\ +| Both sizes share the same six row hardware matrix. The | +| GK8120 adds the number pad in the four columns to the | +| right of the GK8110 keys. | +\*---------------------------------------------------------*/ +#define GK8110_WIDTH 17 +#define GK8120_WIDTH 21 +#define WITMOD_MATRIX_HEIGHT 6 -class RGBController_RedSquareKeyroxTKLClassic : public RGBController +class RGBController_WitmodKeyboard : public RGBController { public: - RGBController_RedSquareKeyroxTKLClassic(RedSquareKeyroxTKLClassicController* controller_ptr); - ~RGBController_RedSquareKeyroxTKLClassic(); + RGBController_WitmodKeyboard(WitmodKeyboardController* controller_ptr); + ~RGBController_WitmodKeyboard(); void SetupZones(); @@ -34,5 +40,5 @@ public: void DeviceUpdateMode(); private: - RedSquareKeyroxTKLClassicController* controller; + WitmodKeyboardController* controller; }; diff --git a/Controllers/WitmodKeyboardController/WitmodKeyboardController.cpp b/Controllers/WitmodKeyboardController/WitmodKeyboardController.cpp new file mode 100644 index 000000000..73dde00ff --- /dev/null +++ b/Controllers/WitmodKeyboardController/WitmodKeyboardController.cpp @@ -0,0 +1,283 @@ +/*---------------------------------------------------------*\ +| WitmodKeyboardController.cpp | +| | +| Driver for Witmod keyboards | +| | +| vlack 03 May 2023 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "LogManager.h" +#include "WitmodKeyboardController.h" + +using namespace std::chrono_literals; + +WitmodKeyboardController::WitmodKeyboardController(hid_device *dev_handle, const hid_device_info &info, std::string dev_name) +{ + dev = dev_handle; + location = info.path; + name = dev_name; + vendor = "Witmod"; + keyboard_size = KEYBOARD_SIZE_TKL; + + ReadDeviceInfo(); +} + +WitmodKeyboardController::~WitmodKeyboardController() +{ + hid_close(dev); +} + +std::string WitmodKeyboardController::GetDeviceLocation() +{ + return("HID: " + location); +} + +std::string WitmodKeyboardController::GetNameString() +{ + return(name); +} + +std::string WitmodKeyboardController::GetSerialString() +{ + wchar_t serial_wchar[128]; + hid_get_serial_number_string(dev, serial_wchar, 128); + std::wstring serial_wstring(serial_wchar); + + std::string serial_string; + std::transform(serial_wstring.begin(), serial_wstring.end(), std::back_inserter(serial_string), [] (wchar_t i) + { + return (char)i; + }); + + return serial_string; +} + +std::string WitmodKeyboardController::GetVendorString() +{ + return(vendor); +} + +std::string WitmodKeyboardController::GetVersionString() +{ + return(version); +} + +KEYBOARD_SIZE WitmodKeyboardController::GetKeyboardSize() +{ + return(keyboard_size); +} + +/*---------------------------------------------------------*\ +| Ask the keyboard which model it is. The boards share | +| their vendor ID, product ID and product string, so the | +| model in the reply to this request is the only way to | +| tell the sizes apart. A board that does not answer, or | +| reports an unknown model, keeps the default TKL layout. | +\*---------------------------------------------------------*/ +void WitmodKeyboardController::ReadDeviceInfo() +{ + unsigned char usb_buf[WITMOD_PACKET_DATA_LENGTH]; + memset(usb_buf, 0x00, WITMOD_PACKET_DATA_LENGTH); + + usb_buf[0] = 0x01; + usb_buf[1] = WITMOD_INFO_COMMAND; + + hid_write(dev, usb_buf, WITMOD_PACKET_DATA_LENGTH); + + for(int retry = 0; retry < WITMOD_INFO_RETRIES; retry++) + { + /*-----------------------------------------*\ + | The extra byte keeps the reply string | + | terminated if it fills the packet | + \*-----------------------------------------*/ + char reply[WITMOD_PACKET_DATA_LENGTH + 1]; + memset(reply, 0x00, WITMOD_PACKET_DATA_LENGTH + 1); + + int reply_size = hid_read_timeout(dev, (unsigned char *)reply, WITMOD_PACKET_DATA_LENGTH, WITMOD_INFO_TIMEOUT); + + if(reply_size <= 0) + { + continue; + } + + /*-----------------------------------------*\ + | Effects send reports of their own, so | + | skip anything that is not the answer | + \*-----------------------------------------*/ + if((reply[0] != 0x01) || (reply[1] != WITMOD_INFO_COMMAND)) + { + continue; + } + + /*-----------------------------------------*\ + | Step over the command bytes and the | + | padding ahead of the string | + \*-----------------------------------------*/ + const char* info = &reply[2]; + + for(int idx = 2; idx < WITMOD_PACKET_DATA_LENGTH; idx++, info++) + { + if(*info > ' ') + { + break; + } + } + + if(*info == '\0') + { + continue; + } + + LOG_INFO("[%s] Device info: %s", name.c_str(), info); + + const char* version_field = strrchr(info, 'V'); + + if(version_field != NULL) + { + version = version_field; + } + + if(strstr(info, WITMOD_MODEL_GK8120) != NULL) + { + LOG_INFO("[%s] GK8120 full size board, using the 104 key layout", name.c_str()); + + keyboard_size = KEYBOARD_SIZE_FULL; + name = "Witmod GK8120"; + } + else if(strstr(info, WITMOD_MODEL_GK8110) != NULL) + { + LOG_INFO("[%s] GK8110 TKL board, using the 87 key layout", name.c_str()); + + keyboard_size = KEYBOARD_SIZE_TKL; + name = "Witmod GK8110"; + } + else + { + LOG_WARNING("[%s] Unrecognised model, defaulting to the 87 key layout", name.c_str()); + } + + return; + } + + LOG_WARNING("[%s] Device info request went unanswered, defaulting to the 87 key layout", name.c_str()); +} + +int WitmodKeyboardController::GetDirection(int direction) +{ + switch(direction) + { + case MODE_DIRECTION_LEFT: + return 0x00; + case MODE_DIRECTION_RIGHT: + return 0x01; + case MODE_DIRECTION_UP: + return 0x02; + case MODE_DIRECTION_DOWN: + return 0x03; + case MODE_DIRECTION_HORIZONTAL: // actually direction out + return 0x04; + case MODE_DIRECTION_VERTICAL: // actually direction in + return 0x05; + default: + return 0x00; + } +} + +int WitmodKeyboardController::GetDirectionRound(int direction) +{ + switch(direction) + { + case MODE_DIRECTION_LEFT: // actually anticlockwise + return 0x07; + case MODE_DIRECTION_RIGHT: // actually clockwise + return 0x06; + default: + return 0x00; + } +} + +void WitmodKeyboardController::SetMode(mode m) +{ + /*---------------------------------------------*\ + | Mode set command | + \*---------------------------------------------*/ + + unsigned char usb_buf[WITMOD_PACKET_DATA_LENGTH]; + memset(usb_buf, 0x00, WITMOD_PACKET_DATA_LENGTH); + + usb_buf[0] = 0x01; + usb_buf[1] = 0x07; + usb_buf[6] = m.value; + usb_buf[7] = m.brightness; // brightness + usb_buf[8] = m.speed; // speed + + if(m.colors_max == 1 || m.colors_max == 2) + { + usb_buf[9] = RGBGetRValue(m.colors[0]); // front R + usb_buf[10] = RGBGetGValue(m.colors[0]); // front G + usb_buf[11] = RGBGetBValue(m.colors[0]); // front B + } + + if(m.colors_max == 2 && m.color_mode != MODE_COLORS_RANDOM) + { + usb_buf[12] = RGBGetRValue(m.colors[1]); // back R + usb_buf[13] = RGBGetGValue(m.colors[1]); // back G + usb_buf[14] = RGBGetBValue(m.colors[1]); // back B + } + + if(m.value == WITMOD_RADAR_MODE_VALUE || m.value == WITMOD_RUNNING_LINE_MODE_VALUE) + { + usb_buf[15] = GetDirectionRound(m.direction); + } + else + { + usb_buf[15] = GetDirection(m.direction); + } + + usb_buf[16] = m.color_mode == MODE_COLORS_RANDOM; + + hid_write(dev, usb_buf, WITMOD_PACKET_DATA_LENGTH); + // sleep is necessary + std::this_thread::sleep_for(10ms); +} + +void WitmodKeyboardController::SetLEDsData(std::vector colors, std::vector leds) +{ + /*---------------------------------------------*\ + | LEDs data set command | + \*---------------------------------------------*/ + + unsigned char usb_buf[WITMOD_PACKET_DATA_LENGTH * 8]; + memset(usb_buf, 0x00, WITMOD_PACKET_DATA_LENGTH * 8); + + for(unsigned int i = 0; i < colors.size(); i++) + { + int offset = leds[i].value; + usb_buf[offset - 1] = RGBGetRValue(colors[i]); + usb_buf[offset] = RGBGetGValue(colors[i]); + usb_buf[offset + 1] = RGBGetBValue(colors[i]); + } + + for(unsigned int i = 0; i < 8; i++) + { + unsigned char packet[WITMOD_PACKET_DATA_LENGTH]; + memset(packet, 0x00, WITMOD_PACKET_DATA_LENGTH); + + packet[0] = 0x01; + packet[1] = 0x0F; + packet[4] = i; // package number + packet[5] = i == 7 ? 0x12 : 0x36; // package size + + for (int x = 6; x < WITMOD_PACKET_DATA_LENGTH; x++) + { + packet[x] = usb_buf[WITMOD_PACKET_DATA_LENGTH * i + x]; + } + hid_write(dev, packet, WITMOD_PACKET_DATA_LENGTH); + } + + // sleep is necessary + std::this_thread::sleep_for(10ms); +} diff --git a/Controllers/WitmodKeyboardController/WitmodKeyboardController.h b/Controllers/WitmodKeyboardController/WitmodKeyboardController.h new file mode 100644 index 000000000..bedc9be73 --- /dev/null +++ b/Controllers/WitmodKeyboardController/WitmodKeyboardController.h @@ -0,0 +1,103 @@ +/*---------------------------------------------------------*\ +| WitmodKeyboardController.h | +| | +| Driver for Witmod keyboards | +| | +| vlack 03 May 2023 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include "RGBController.h" +#include "KeyboardLayoutManager.h" + +#define WITMOD_PACKET_DATA_LENGTH 64 + +/*---------------------------------------------------------*\ +| The device info request answers with a string such as | +| | +| 2M252,01,KB,JC,GK8120SKRGB,V1.04.04 | +| | +| where the fifth field is the board model and the last is | +| the firmware version. GK8120 is the full size board and | +| GK8110 the TKL sized one. These are Witmod platform | +| codes; the same boards are resold under several brands. | +\*---------------------------------------------------------*/ +#define WITMOD_INFO_COMMAND 0x0D +#define WITMOD_INFO_RETRIES 10 +#define WITMOD_INFO_TIMEOUT 150 +#define WITMOD_MODEL_GK8110 "GK8110" +#define WITMOD_MODEL_GK8120 "GK8120" + +/*---------------------------------------*\ +| Modes | +\*---------------------------------------*/ +enum +{ + WITMOD_CONST_MODE_VALUE = 0x00, // static + WITMOD_BREATHE_MODE_VALUE = 0x01, // breath + WITMOD_WAVE_MODE_VALUE = 0x02, // wave + WITMOD_FADE_MODE_VALUE = 0x03, // neon + WITMOD_RADAR_MODE_VALUE = 0x04, // radar + WITMOD_STAR_MODE_VALUE = 0x06, // интерактив + WITMOD_LINE_MODE_VALUE = 0x07, // сияние + WITMOD_RIPPLE_MODE_VALUE = 0x08, // рябь интерактив + WITMOD_STARS_MODE_VALUE = 0x09, // мерцание + WITMOD_CUSTOM_MODE_VALUE = 0x0A, + WITMOD_CROSS_MODE_VALUE = 0x0B, // скрещивание + WITMOD_WTF_MODE_VALUE = 0x0C, // быстрый отклик + WITMOD_RIPPLE_RANDOM_MODE_VALUE = 0x0E, // рябь + WITMOD_RUNNING_LINE_MODE_VALUE = 0x0F, // бегущая строка + WITMOD_FIREWORK_MODE_VALUE = 0x10, // firework +}; + +/*-----------------------------*\ +| Other settings | +\*-----------------------------*/ +enum +{ + WITMOD_BRIGHTNESS_MIN = 0x00, + WITMOD_BRIGHTNESS_MAX = 0x04, + WITMOD_SPEED_MIN = 0x00, + WITMOD_SPEED_MAX = 0x04, +}; + + +class WitmodKeyboardController +{ +public: + WitmodKeyboardController(hid_device *dev_handle, const hid_device_info &info, std::string dev_name); + ~WitmodKeyboardController(); + + std::string GetDeviceLocation(); + std::string GetNameString(); + std::string GetSerialString(); + std::string GetVendorString(); + std::string GetVersionString(); + KEYBOARD_SIZE GetKeyboardSize(); + + int GetDirection(int direction); + int GetDirectionRound(int direction); + + void SetMode(mode m); + void SetLEDsData(std::vector colors, std::vector leds); + +protected: + hid_device* dev; + +private: + void ReadDeviceInfo(); + + std::string location; + std::string name; + std::string serial_number; + std::string vendor; + std::string version; + KEYBOARD_SIZE keyboard_size; + std::vector led_sequence_positions; +}; diff --git a/Controllers/WitmodKeyboardController/WitmodKeyboardControllerDetect.cpp b/Controllers/WitmodKeyboardController/WitmodKeyboardControllerDetect.cpp new file mode 100644 index 000000000..5da6aa9e8 --- /dev/null +++ b/Controllers/WitmodKeyboardController/WitmodKeyboardControllerDetect.cpp @@ -0,0 +1,43 @@ +/*---------------------------------------------------------*\ +| WitmodKeyboardControllerDetect.cpp | +| | +| Detector for Witmod keyboards | +| | +| vlack 03 May 2023 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include +#include "DetectionManager.h" +#include "WitmodKeyboardController.h" +#include "RGBController_WitmodKeyboard.h" + +/*---------------------------------------------------------*\ +| Witmod uses the Nuvoton/Winbond USB vendor ID. The | +| GK8110 and GK8120 boards share this VID and PID and are | +| told apart by the model in the device info reply. | +\*---------------------------------------------------------*/ +#define WITMOD_VID 0x0416 +#define WITMOD_KEYBOARD_PID 0xC345 + +DetectedControllers DetectWitmodKeyboard(hid_device_info* info, const std::string& name) +{ + DetectedControllers detected_controllers; + hid_device* dev; + + dev = hid_open_path(info->path); + + if(dev) + { + WitmodKeyboardController* controller = new WitmodKeyboardController(dev, *info, name); + RGBController_WitmodKeyboard* rgb_controller = new RGBController_WitmodKeyboard(controller); + + detected_controllers.push_back(rgb_controller); + } + + return(detected_controllers); +} + +REGISTER_HID_DETECTOR_I("Witmod Keyboard", DetectWitmodKeyboard, WITMOD_VID, WITMOD_KEYBOARD_PID, 2);