From 92d82403841444eb1b0c7cd2c01b064007b23235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Jord=C3=A3o?= Date: Fri, 9 May 2025 16:36:37 +0000 Subject: [PATCH] HyperX Origin Core variant --- .../HyperXAlloyOriginsCoreController.cpp | 88 ++++-- .../HyperXAlloyOriginsCoreController.h | 1 + .../RGBController_HyperXAlloyOriginsCore.cpp | 281 ++++++++++-------- .../RGBController_HyperXAlloyOriginsCore.h | 4 + RGBController/RGBControllerKeyNames.cpp | 1 + RGBController/RGBControllerKeyNames.h | 1 + qt/DeviceView.cpp | 1 + 7 files changed, 241 insertions(+), 136 deletions(-) diff --git a/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/HyperXAlloyOriginsCoreController.cpp b/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/HyperXAlloyOriginsCoreController.cpp index 6ab625ec..32e76226 100644 --- a/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/HyperXAlloyOriginsCoreController.cpp +++ b/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/HyperXAlloyOriginsCoreController.cpp @@ -5,6 +5,7 @@ | | | Volodymyr Nazarchuk (Vavooon) 28 Apr 2021 | | Mike White (kamaaina) 09 Jun 2021 | +| carlos jordao 15 Mar 2025 | | | | This file is part of the OpenRGB project | | SPDX-License-Identifier: GPL-2.0-only | @@ -13,9 +14,8 @@ #include #include "HyperXAlloyOriginsCoreController.h" #include "StringUtils.h" +#include "LogManager.h" -// Skip these indices in the color output -static unsigned int skip_idx[] = {6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 44, 46, 47, 54, 55, 58, 60, 61, 62, 63, 70, 71, 78, 79, 86, 87, 94, 95, 101, 102, 103, 109, 110, 111, 118, 119}; HyperXAlloyOriginsCoreController::HyperXAlloyOriginsCoreController(hid_device* dev_handle, hid_device_info* dev_info) { @@ -62,6 +62,38 @@ std::string HyperXAlloyOriginsCoreController::GetFirmwareVersion() return(firmware_version); } +unsigned int HyperXAlloyOriginsCoreController::GetVariant() +{ + unsigned char packet[65]; + unsigned int variant = 0; + int actual = 0; + + memset(packet, 0x00, sizeof(packet)); + + /*---------------------------------------*\ + | Command 10 asks some data from keyboard | + | The answer looks like: | + | * command answer header (bytes 0-4) | + | * data length: byte 4 | + | * version (bytes 5-6) | + | * Product string (bytes 9-33) | + | * Layout variant (byte 56) | + \*---------------------------------------*/ + packet[1] = 0x10; + hid_write(dev, packet, 65); + memset(packet, 0x00, sizeof(packet)); + actual = hid_read(dev, packet, 65); + + if(actual > 0) + variant = packet[56]; + else + variant = 0x09; + + LOG_DEBUG("[HyperX Alloy Origins Core] variant: 0x%02X", variant); + return variant; +} + + void HyperXAlloyOriginsCoreController::SetBrightness(unsigned int brightness) { unsigned char packet[65]; @@ -77,30 +109,46 @@ void HyperXAlloyOriginsCoreController::SetBrightness(unsigned int brightness) void HyperXAlloyOriginsCoreController::SetLEDsDirect(std::vector colors) { - for(unsigned int skip_cnt = 0; skip_cnt < (sizeof(skip_idx) / sizeof(skip_idx[0])); skip_cnt++) - { - colors.insert(colors.begin() + skip_idx[skip_cnt], 0x00000000); - } - + /*------------------------------------------------------------------------------*\ + | * Always send 380 bytes to the keyboard and a total of 94 led indexes. | + | The colors are grouped into segments of 48 bytes. | + | Each one is divided into: | + | 6 Green + 2 zeroes + 6 Green + 2 zeroes + | + | 6 Red + 2 zeroes + 6 Red + 2 zeroes + | + | 6 Blue + 2 zeroes + 6 Blue + 2 zeroes | + | \=---> sector 0 \=--> sector 1 | + | Every 6 colors form a sector. The names are arbitrary, just to make clear how | + | to set the colors into the buffer. | + | So each segment has 2 sectors and 12 colors. | + | The last 10 colors don't fill completely the last segment. | + | * All 94 colors can be sent even if some of them aren't used by the physical | + | keyboard. This allows to lit every key, even if not mapped directly. | + \*------------------------------------------------------------------------------*/ + unsigned int segment = 0, sector = 0, sequence = 0; + unsigned int total_colors = 0; unsigned char buf[380]; memset(buf, 0x00, sizeof(buf)); - int offset = 0; - int rowPos = 0; + /*---------------------------------------------------------------------------*\ + | transfer the colors to the buffer. Max 94 colors to avoid buffer overflow. | + \*---------------------------------------------------------------------------*/ + if(colors.size() > 94) + total_colors = 94; + else + total_colors = colors.size(); - for(unsigned int color_idx = 0; color_idx < colors.size(); color_idx++) + for(unsigned int color_idx = 0; color_idx < total_colors; color_idx++) { - if (color_idx > 0 && color_idx % 16 == 0) - { - offset += 48; - rowPos = 0; - } + unsigned int pos = 0; + segment = (color_idx / 12) * 48; + sector = ((color_idx / 6) & 1) * 8; + sequence = color_idx % 6; - buf[rowPos + offset] = RGBGetGValue(colors[color_idx]); - buf[rowPos + offset + 16] = RGBGetRValue(colors[color_idx]); - buf[rowPos + offset + 32] = RGBGetBValue(colors[color_idx]); + pos = segment + sector + sequence; - rowPos++; + buf[pos ] = RGBGetGValue(colors[color_idx]); + buf[pos + 16] = RGBGetRValue(colors[color_idx]); + buf[pos + 32] = RGBGetBValue(colors[color_idx]); } unsigned int sentBytes = 0; @@ -123,7 +171,7 @@ void HyperXAlloyOriginsCoreController::SetLEDsDirect(std::vector color packet[4] = payloadSize; memcpy(&packet[5], &buf[sentBytes], payloadSize); - hid_write(dev, packet, 65); + hid_write(dev, packet, payloadSize + 5); sentBytes += payloadSize; } diff --git a/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/HyperXAlloyOriginsCoreController.h b/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/HyperXAlloyOriginsCoreController.h index 5288c461..4e1394f0 100644 --- a/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/HyperXAlloyOriginsCoreController.h +++ b/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/HyperXAlloyOriginsCoreController.h @@ -24,6 +24,7 @@ public: std::string GetDeviceLocation(); std::string GetSerialString(); std::string GetFirmwareVersion(); + unsigned int GetVariant(); void SetLEDsDirect(std::vector colors); void SetBrightness(unsigned int brightness); diff --git a/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/RGBController_HyperXAlloyOriginsCore.cpp b/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/RGBController_HyperXAlloyOriginsCore.cpp index 4acbbc11..627a7223 100644 --- a/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/RGBController_HyperXAlloyOriginsCore.cpp +++ b/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/RGBController_HyperXAlloyOriginsCore.cpp @@ -4,6 +4,7 @@ | RGBController for HyperX Alloy Origins Core keyboard | | | | Volodymyr Nazarchuk (Vavooon) 28 Apr 2021 | +| carlos jordao 15 Mar 2025 | | | | This file is part of the OpenRGB project | | SPDX-License-Identifier: GPL-2.0-only | @@ -17,17 +18,20 @@ using namespace std::chrono_literals; #define HYPERX_MIN_BRIGHTNESS 0 #define HYPERX_MAX_BRIGHTNESS 255 -//0xFFFFFFFF indicates an unused entry in matrix #define NA 0xFFFFFFFF +/*----------------------------------*\ +| Maps LED position number to keys | +| * based on ANSI QWERTY | +\*----------------------------------*/ static unsigned int matrix_map[6][19] = { - { 0, NA, 1, 2, 3, 4, 5, 6, 7, 44, NA, 45, 46, 47, 48, NA, 49, 50, 51 }, - { 8, 9, 10, 11, 12, 13, 14, 15, 16, 52, 53, 54, 55, 56, NA, NA, 57, 58, 59 }, - { 17, NA, 18, 19, 20, 21, 22, 23, 24, 60, 61, 62, 63, 64, 65, NA, 66, 67, 68 }, - { 25, NA, 26, 27, 28, 29, 30, 31, 32, 69, 70, 71, 72, 73, NA, NA, NA, NA, NA }, - { 33, NA, 34, 35, 36, 37, 38, NA, 39, 74, 75, 76, 77, 78, NA, NA, NA, 79, NA }, - { 40, 41, 42, NA, NA, NA, 43, NA, NA, NA, NA, 80, 81, 82, 83, NA, 84, 85, 86 } + { 0, NA, 1, 2, 3, 4, 5, 6, 7, 48, NA, 49, 50, 51, 52, NA, 53, 54, 55 }, + { 8, 9, 10, 11, 12, 13, 14, 15, 16, 56, 57, 58, 59, 60, NA, NA, 61, 62, 63 }, + { 17, NA, 18, 19, 20, 21, 22, 23, 24, 64, 65, 66, 67, 68, 69, NA, 70, 71, 72 }, + { 25, NA, 26, 27, 28, 29, 30, 31, 32, 73, 74, 75, 76, 78, NA, NA, NA, NA, NA }, + { 33, NA, 35, 36, 37, 38, 39, 40, 79, 80, 81, NA, 83, 84, NA, NA, NA, 85, NA }, + { 41, 42, 43, NA, NA, NA, 45, NA, NA, NA, NA, 86, 87, 88, 89, NA, 90, 91, 92 } }; static const char* zone_names[] = @@ -40,115 +44,133 @@ static zone_type zone_types[] = ZONE_TYPE_MATRIX, }; -static const unsigned int zone_sizes[] = + +/*--------------------------------------------------------------------------------*\ +| This keyboard (TKL) always receives 93 led colors. | +| * Some indexes are just blank (unused). | +| * Regional layouts have a few different enabled or disabled led indexes. | +| * All indexes need to be sent anyway. Declaring all of them makes it easier to | +| add new layouts without creating a new matrix map. | +| * led_names contains the indexes used by the HyperX keyboard | +\*--------------------------------------------------------------------------------*/ +struct led_index { - 87, + const char *name; + unsigned int index; }; -static const char *led_names[] = +static led_index led_names[] = { - KEY_EN_ESCAPE, - KEY_EN_F1, - KEY_EN_F2, - KEY_EN_F3, - KEY_EN_F4, - KEY_EN_F5, - KEY_EN_F6, - KEY_EN_F7, + {KEY_EN_ESCAPE, 0}, + {KEY_EN_F1, 1}, + {KEY_EN_F2, 2}, + {KEY_EN_F3, 3}, + {KEY_EN_F4, 4}, + {KEY_EN_F5, 5}, + {KEY_EN_F6, 6}, + {KEY_EN_F7, 7}, - KEY_EN_BACK_TICK, - KEY_EN_1, - KEY_EN_2, - KEY_EN_3, - KEY_EN_4, - KEY_EN_5, - KEY_EN_6, - KEY_EN_7, - KEY_EN_8, + {KEY_EN_BACK_TICK, 8}, + {KEY_EN_1, 9}, + {KEY_EN_2, 10}, + {KEY_EN_3, 11}, + {KEY_EN_4, 12}, + {KEY_EN_5, 13}, + {KEY_EN_6, 14}, + {KEY_EN_7, 15}, + {KEY_EN_8, 16}, - KEY_EN_TAB, - KEY_EN_Q, - KEY_EN_W, - KEY_EN_E, - KEY_EN_R, - KEY_EN_T, - KEY_EN_Y, - KEY_EN_U, + {KEY_EN_TAB, 17}, + {KEY_EN_Q, 18}, + {KEY_EN_W, 19}, + {KEY_EN_E, 20}, + {KEY_EN_R, 21}, + {KEY_EN_T, 22}, + {KEY_EN_Y, 23}, + {KEY_EN_U, 24}, - KEY_EN_CAPS_LOCK, - KEY_EN_A, - KEY_EN_S, - KEY_EN_D, - KEY_EN_F, - KEY_EN_G, - KEY_EN_H, - KEY_EN_J, + {KEY_EN_CAPS_LOCK, 25}, + {KEY_EN_A, 26}, + {KEY_EN_S, 27}, + {KEY_EN_D, 28}, + {KEY_EN_F, 29}, + {KEY_EN_G, 30}, + {KEY_EN_H, 31}, + {KEY_EN_J, 32}, - KEY_EN_LEFT_SHIFT, - KEY_EN_Z, - KEY_EN_X, - KEY_EN_C, - KEY_EN_V, - KEY_EN_B, - KEY_EN_N, + {KEY_EN_LEFT_SHIFT, 33}, + {KEY_EN_UNUSED, 34}, + {KEY_EN_Z, 35}, + {KEY_EN_X, 36}, + {KEY_EN_C, 37}, + {KEY_EN_V, 38}, + {KEY_EN_B, 39}, + {KEY_EN_N, 40}, - KEY_EN_LEFT_CONTROL, - KEY_EN_LEFT_WINDOWS, - KEY_EN_LEFT_ALT, - KEY_EN_SPACE, + {KEY_EN_LEFT_CONTROL, 41}, + {KEY_EN_LEFT_WINDOWS, 42}, + {KEY_EN_LEFT_ALT, 43}, + + {KEY_EN_UNUSED, 44}, + {KEY_EN_SPACE, 45}, + {KEY_EN_UNUSED, 46}, + {KEY_EN_UNUSED, 47}, // End of first section - KEY_EN_F8, - KEY_EN_F9, - KEY_EN_F10, - KEY_EN_F11, - KEY_EN_F12, - KEY_EN_PRINT_SCREEN, - KEY_EN_SCROLL_LOCK, - KEY_EN_PAUSE_BREAK, + {KEY_EN_F8, 48}, + {KEY_EN_F9, 49}, + {KEY_EN_F10, 50}, + {KEY_EN_F11, 51}, + {KEY_EN_F12, 52}, + {KEY_EN_PRINT_SCREEN, 53}, + {KEY_EN_SCROLL_LOCK, 54}, + {KEY_EN_PAUSE_BREAK, 55}, - KEY_EN_9, - KEY_EN_0, - KEY_EN_MINUS, - KEY_EN_EQUALS, - KEY_EN_BACKSPACE, - KEY_EN_INSERT, - KEY_EN_HOME, - KEY_EN_PAGE_UP, + {KEY_EN_9, 56}, + {KEY_EN_0, 57}, + {KEY_EN_MINUS, 58}, + {KEY_EN_EQUALS, 59}, + {KEY_EN_BACKSPACE, 60}, + {KEY_EN_INSERT, 61}, + {KEY_EN_HOME, 62}, + {KEY_EN_PAGE_UP, 63}, + {KEY_EN_I, 64}, + {KEY_EN_O, 65}, + {KEY_EN_P, 66}, + {KEY_EN_LEFT_BRACKET, 67}, + {KEY_EN_RIGHT_BRACKET, 68}, + {KEY_EN_ANSI_BACK_SLASH, 69}, - KEY_EN_I, - KEY_EN_O, - KEY_EN_P, - KEY_EN_LEFT_BRACKET, - KEY_EN_RIGHT_BRACKET, - KEY_EN_ANSI_BACK_SLASH, - KEY_EN_DELETE, - KEY_EN_END, - KEY_EN_PAGE_DOWN, + {KEY_EN_DELETE, 70}, + {KEY_EN_END, 71}, + {KEY_EN_PAGE_DOWN, 72}, + {KEY_EN_K, 73}, + {KEY_EN_L, 74}, + {KEY_EN_SEMICOLON, 75}, + {KEY_EN_QUOTE, 76}, + {KEY_EN_POUND, 77}, + {KEY_EN_ANSI_ENTER, 78}, - KEY_EN_K, - KEY_EN_L, - KEY_EN_SEMICOLON, - KEY_EN_QUOTE, - KEY_EN_ANSI_ENTER, + {KEY_EN_M, 79}, + {KEY_EN_COMMA, 80}, + {KEY_EN_PERIOD, 81}, + {KEY_EN_UNUSED, 82}, + {KEY_EN_FORWARD_SLASH, 83}, + {KEY_EN_RIGHT_SHIFT, 84}, + {KEY_EN_UP_ARROW, 85}, - KEY_EN_M, - KEY_EN_COMMA, - KEY_EN_PERIOD, - KEY_EN_FORWARD_SLASH, - KEY_EN_RIGHT_SHIFT, - KEY_EN_UP_ARROW, - KEY_EN_RIGHT_ALT, - KEY_EN_RIGHT_FUNCTION, - KEY_EN_MENU, - KEY_EN_RIGHT_CONTROL, - KEY_EN_LEFT_ARROW, - KEY_EN_DOWN_ARROW, - KEY_EN_RIGHT_ARROW + {KEY_EN_RIGHT_ALT, 86}, + {KEY_EN_RIGHT_FUNCTION, 87}, + {KEY_EN_MENU, 88}, + {KEY_EN_RIGHT_CONTROL, 89}, + + {KEY_EN_LEFT_ARROW, 90}, + {KEY_EN_DOWN_ARROW, 91}, + {KEY_EN_RIGHT_ARROW, 92} }; /**------------------------------------------------------------------*\ @@ -173,6 +195,7 @@ RGBController_HyperXAlloyOriginsCore::RGBController_HyperXAlloyOriginsCore(Hyper location = controller->GetDeviceLocation(); serial = controller->GetSerialString(); version = controller->GetFirmwareVersion(); + variant = controller->GetVariant(); mode Direct; Direct.name = "Direct"; @@ -218,19 +241,56 @@ RGBController_HyperXAlloyOriginsCore::~RGBController_HyperXAlloyOriginsCore() void RGBController_HyperXAlloyOriginsCore::SetupZones() { - unsigned int total_led_count = 0; + const unsigned int total_leds = sizeof(led_names) / sizeof(led_names[0]); + zone new_zone; + for(unsigned int zone_idx = 0; zone_idx < 1; zone_idx++) { - zone new_zone; - new_zone.name = zone_names[zone_idx]; - new_zone.type = zone_types[zone_idx]; - new_zone.leds_min = zone_sizes[zone_idx]; - new_zone.leds_max = zone_sizes[zone_idx]; - new_zone.leds_count = zone_sizes[zone_idx]; + new_zone.name = zone_names[zone_idx]; + new_zone.type = zone_types[zone_idx]; + + /*-----------------------------------------------------*\ + | Regional configuration can be done by setting | + | the relevant keys based on the led map. | + \*-----------------------------------------------------*/ + if(variant == HYPERX_ALLOY_ORIGINS_CORE_ABNT2) + { + // Sets the led indexes of this variant + matrix_map[2][14] = NA; + matrix_map[3][13] = 77; // ] + matrix_map[3][14] = 78; // enter + matrix_map[4][ 1] = 34; // backslash + matrix_map[4][11] = 82; // ; + + // corrects the visual representantion + led_names[ 8].name = KEY_EN_QUOTE; + led_names[34].name = KEY_EN_ISO_BACK_SLASH; + led_names[67].name = KEY_NORD_ACUTE_GRAVE; + led_names[68].name = KEY_EN_LEFT_BRACKET; + led_names[69].name = KEY_EN_UNUSED; + led_names[75].name = KEY_FR_CEDILLA_C; + led_names[76].name = KEY_BR_TILDE; + led_names[77].name = KEY_EN_RIGHT_BRACKET; + led_names[78].name = KEY_EN_ISO_ENTER; + led_names[82].name = KEY_EN_SEMICOLON; + } + + for(unsigned int led_idx = 0; led_idx < total_leds; led_idx++) + { + led new_led; + new_led.name = led_names[led_idx].name; + new_led.value = led_names[led_idx].index; + leds.push_back(new_led); + } + + matrix_map_type * keyboard_map = new matrix_map_type; + new_zone.leds_count = total_leds; + new_zone.leds_min = new_zone.leds_count; + new_zone.leds_max = new_zone.leds_count; if(zone_types[zone_idx] == ZONE_TYPE_MATRIX) { - new_zone.matrix_map = new matrix_map_type; + new_zone.matrix_map = keyboard_map; new_zone.matrix_map->height = 6; new_zone.matrix_map->width = 19; new_zone.matrix_map->map = (unsigned int *)&matrix_map; @@ -239,19 +299,8 @@ void RGBController_HyperXAlloyOriginsCore::SetupZones() { new_zone.matrix_map = NULL; } - zones.push_back(new_zone); - - total_led_count += zone_sizes[zone_idx]; } - - for(unsigned int led_idx = 0; led_idx < total_led_count; led_idx++) - { - led new_led; - new_led.name = led_names[led_idx]; - leds.push_back(new_led); - } - SetupColors(); } diff --git a/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/RGBController_HyperXAlloyOriginsCore.h b/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/RGBController_HyperXAlloyOriginsCore.h index 826cbc40..f1341c23 100644 --- a/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/RGBController_HyperXAlloyOriginsCore.h +++ b/Controllers/HyperXKeyboardController/HyperXAlloyOriginsCoreController/RGBController_HyperXAlloyOriginsCore.h @@ -15,6 +15,9 @@ #include "RGBController.h" #include "HyperXAlloyOriginsCoreController.h" +#define HYPERX_ALLOY_ORIGINS_CORE_ANSI 0x09 +#define HYPERX_ALLOY_ORIGINS_CORE_ABNT2 0x10 + class RGBController_HyperXAlloyOriginsCore : public RGBController { public: @@ -38,4 +41,5 @@ private: std::thread* keepalive_thread; std::atomic keepalive_thread_run; std::chrono::time_point last_update_time; + unsigned int variant; }; diff --git a/RGBController/RGBControllerKeyNames.cpp b/RGBController/RGBControllerKeyNames.cpp index d3e3b6ed..a09a22e1 100644 --- a/RGBController/RGBControllerKeyNames.cpp +++ b/RGBController/RGBControllerKeyNames.cpp @@ -190,3 +190,4 @@ const char* KEY_FR_EXCLAIMATION = "Key: !"; const char* KEY_ES_OPEN_QUESTION_MARK = "Key: ¿/¡"; const char* KEY_ES_TILDE = "Key: ´/¨"; const char* KEY_ES_ENIE = "Key: Ñ"; +const char* KEY_BR_TILDE = "Key: ~"; diff --git a/RGBController/RGBControllerKeyNames.h b/RGBController/RGBControllerKeyNames.h index 4ae4cb48..99e61bdc 100644 --- a/RGBController/RGBControllerKeyNames.h +++ b/RGBController/RGBControllerKeyNames.h @@ -190,3 +190,4 @@ extern const char* KEY_FR_EXCLAIMATION; extern const char* KEY_ES_OPEN_QUESTION_MARK; extern const char* KEY_ES_TILDE; extern const char* KEY_ES_ENIE; +extern const char* KEY_BR_TILDE; diff --git a/qt/DeviceView.cpp b/qt/DeviceView.cpp index eb187910..74618d4d 100644 --- a/qt/DeviceView.cpp +++ b/qt/DeviceView.cpp @@ -228,6 +228,7 @@ static const std::map led_label_lookup = { KEY_ES_OPEN_QUESTION_MARK,{ "¿" , "¡" }}, { KEY_ES_TILDE, { "´" , "¨" }}, { KEY_ES_ENIE, { "ñ" , "Ñ" }}, + { KEY_BR_TILDE, { "~" , "~" }} }; void DeviceView::setController(RGBController * controller_ptr)