diff --git a/Controllers/HyperXKeyboardController/HyperXKeyboardControllerDetect.cpp b/Controllers/HyperXKeyboardController/HyperXKeyboardControllerDetect.cpp index c7fc8e743..7479e19b5 100644 --- a/Controllers/HyperXKeyboardController/HyperXKeyboardControllerDetect.cpp +++ b/Controllers/HyperXKeyboardController/HyperXKeyboardControllerDetect.cpp @@ -15,12 +15,14 @@ #include "HyperXAlloyOriginsController.h" #include "HyperXAlloyOriginsCoreController.h" #include "HyperXAlloyOrigins60and65Controller.h" +#include "HyperXOrigins2_65Controller.h" #include "RGBController_HyperXAlloyElite.h" #include "RGBController_HyperXAlloyElite2.h" #include "RGBController_HyperXAlloyFPS.h" #include "RGBController_HyperXAlloyOrigins.h" #include "RGBController_HyperXAlloyOriginsCore.h" #include "RGBController_HyperXAlloyOrigins60and65.h" +#include "RGBController_HyperXOrigins2_65.h" /*-----------------------------------------------------*\ | HyperX keyboard vendor and product IDs | @@ -44,6 +46,7 @@ #define HYPERX_ALLOY_ORIGINS_65_HP_PID 0x038F #define HYPERX_ALLOY_ORIGINS_CORE_HP_PID 0x098F #define HYPERX_ALLOY_ORIGINS_HP_PID 0x0591 +#define HYPERX_ORIGINS_2_65_HP_PID 0x0CC2 AlloyOrigins60and65MappingLayoutType GetAlloyOrigins60and65MappingLayoutType(int pid) { @@ -140,12 +143,27 @@ void DetectHyperXAlloyOrigins60and65(hid_device_info* info, const std::string& n } } +void DetectHyperXOrigins2_65(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + HyperXOrigins2_65Controller* controller = new HyperXOrigins2_65Controller(dev, info->path, name); + RGBController_HyperXOrigins2_65* rgb_controller = new RGBController_HyperXOrigins2_65(controller); + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} + REGISTER_HID_DETECTOR_IP("HyperX Alloy Elite RGB", DetectHyperXAlloyElite, HYPERX_KEYBOARD_VID, HYPERX_ALLOY_ELITE_PID, 2, 0xFF01); REGISTER_HID_DETECTOR_IP("HyperX Alloy FPS RGB", DetectHyperXAlloyFPS, HYPERX_KEYBOARD_VID, HYPERX_ALLOY_FPS_RGB_PID, 2, 0xFF01); REGISTER_HID_DETECTOR_I("HyperX Alloy Origins Core", DetectHyperXAlloyOriginsCore, HYPERX_KEYBOARD_VID, HYPERX_ALLOY_ORIGINS_CORE_PID, 2); REGISTER_HID_DETECTOR_I("HyperX Alloy Origins Core (HP)", DetectHyperXAlloyOriginsCore, HP_KEYBOARD_VID, HYPERX_ALLOY_ORIGINS_CORE_HP_PID, 2); +REGISTER_HID_DETECTOR_I("HyperX Origins 2 65 (HP)", DetectHyperXOrigins2_65, HP_KEYBOARD_VID, HYPERX_ORIGINS_2_65_HP_PID, 3); + #ifdef _WIN32 REGISTER_HID_DETECTOR_I("HyperX Alloy Origins", DetectHyperXAlloyOrigins, HYPERX_KEYBOARD_VID, HYPERX_ALLOY_ORIGINS_PID, 3); REGISTER_HID_DETECTOR_IP("HyperX Alloy Elite 2", DetectHyperXAlloyElite2, HYPERX_KEYBOARD_VID, HYPERX_ALLOY_ELITE_2_PID, 3, 0xFF90); diff --git a/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/HyperXOrigins2_65Controller.cpp b/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/HyperXOrigins2_65Controller.cpp new file mode 100644 index 000000000..bd5a9527d --- /dev/null +++ b/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/HyperXOrigins2_65Controller.cpp @@ -0,0 +1,151 @@ +/*---------------------------------------------------------*\ +| HyperXOrigins2_65Controller.cpp | +| | +| Driver for HyperX Origins 2 65 keyboard | +| | +| Ricardo Amorim 28 Mar 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include +#include "HyperXOrigins2_65Controller.h" +#include "StringUtils.h" + +HyperXOrigins2_65Controller::HyperXOrigins2_65Controller(hid_device* dev_handle, const char* path, std::string dev_name) +{ + dev = dev_handle; + location = path; + name = dev_name; +} + +HyperXOrigins2_65Controller::~HyperXOrigins2_65Controller() +{ + hid_close(dev); +} + +std::string HyperXOrigins2_65Controller::GetDeviceLocation() +{ + return("HID " + location); +} + +std::string HyperXOrigins2_65Controller::GetNameString() +{ + return(name); +} + +std::string HyperXOrigins2_65Controller::GetSerialString() +{ + wchar_t serial_string[128]; + int ret = hid_get_serial_number_string(dev, serial_string, 128); + + if(ret != 0) + { + return (""); + } + + return(StringUtils::wstring_to_string(serial_string)); +} + +void HyperXOrigins2_65Controller::SetLEDsDirect(std::vector colors) +{ + /*-----------------------------------------------------*\ + | Set up variables to track progress of color transmit | + | Do this after inserting blanks | + \*-----------------------------------------------------*/ + int colors_to_send = (int)colors.size(); + int colors_sent = 0; + + SendDirectInitialization(); + + for(int pkt_idx = 0; pkt_idx < 4; pkt_idx++) + { + if(colors_to_send > 20) + { + SendDirectColorPacket(&colors[colors_sent], 20, pkt_idx); + colors_sent += 20; + colors_to_send -= 20; + } + else if(colors_to_send > 0) + { + SendDirectColorPacket(&colors[colors_sent], colors_to_send, pkt_idx); + colors_sent += colors_to_send; + colors_to_send -= colors_to_send; + } + else + { + RGBColor temp = 0x00000000; + SendDirectColorPacket(&temp, 1, pkt_idx); + } + } +} + +void HyperXOrigins2_65Controller::SendDirectInitialization() +{ + unsigned char buf[65]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(buf, 0x00, sizeof(buf)); + + /*-----------------------------------------------------*\ + | Set up Direct Initialization packet | + \*-----------------------------------------------------*/ + buf[0x00] = 0x44; + buf[0x01] = 0x01; + buf[0x02] = 0x04; + buf[0x03] = 0x00; + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, buf, 65); +} + +void HyperXOrigins2_65Controller::SendDirectColorPacket + ( + RGBColor* color_data, + unsigned int color_count, + unsigned int seq + ) +{ + unsigned char buf[65]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(buf, 0x00, sizeof(buf)); + + /*-----------------------------------------------------*\ + | Set up Direct Initialization packet | + \*-----------------------------------------------------*/ + buf[0x00] = 0x44; + buf[0x01] = 0x02; + buf[0x02] = (unsigned char)seq; + buf[0x03] = 0x00; + + /*-----------------------------------------------------*\ + | The maximum number of colors per packet is 20 | + \*-----------------------------------------------------*/ + if(color_count > 20) + { + color_count = 20; + } + + /*-----------------------------------------------------*\ + | Copy in color data | + \*-----------------------------------------------------*/ + for(unsigned int color_idx = 0; color_idx < color_count; color_idx++) + { + buf[4 + (color_idx * 3)] = RGBGetRValue(color_data[color_idx]); + buf[4 + (color_idx * 3) + 1] = RGBGetGValue(color_data[color_idx]); + buf[4 + (color_idx * 3) + 2] = RGBGetBValue(color_data[color_idx]); + } + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, buf, 65); +} diff --git a/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/HyperXOrigins2_65Controller.h b/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/HyperXOrigins2_65Controller.h new file mode 100644 index 000000000..b760b042c --- /dev/null +++ b/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/HyperXOrigins2_65Controller.h @@ -0,0 +1,43 @@ +/*---------------------------------------------------------*\ +| HyperXOrigins2_65Controller.h | +| | +| Driver for HyperX Origins 2 65 keyboard | +| | +| Ricardo Amorim 28 Mar 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include "RGBController.h" + +class HyperXOrigins2_65Controller +{ +public: + HyperXOrigins2_65Controller(hid_device* dev_handle, const char* path, std::string dev_name); + ~HyperXOrigins2_65Controller(); + + std::string GetDeviceLocation(); + std::string GetNameString(); + std::string GetSerialString(); + + void SetLEDsDirect(std::vector colors); + +private: + hid_device* dev; + std::string location; + std::string name; + + void SendDirectInitialization(); + void SendDirectColorPacket + ( + RGBColor* color_data, + unsigned int color_count, + unsigned int seq + ); +}; + diff --git a/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/RGBController_HyperXOrigins2_65.cpp b/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/RGBController_HyperXOrigins2_65.cpp new file mode 100644 index 000000000..a4cdb1b9b --- /dev/null +++ b/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/RGBController_HyperXOrigins2_65.cpp @@ -0,0 +1,257 @@ +/*---------------------------------------------------------*\ +| RGBController_HyperXOrigins2_65.cpp | +| | +| RGBController for HyperX Origins 2 65 keyboard | +| | +| Ricardo Amorim 28 Mar 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "RGBControllerKeyNames.h" +#include "RGBController_HyperXOrigins2_65.h" + +using namespace std::chrono_literals; + +//0xFFFFFFFF indicates an unused entry in matrix +#define NA 0xFFFFFFFF + +static unsigned int matrix_map[5][15] = + { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, + { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, NA, 29 }, + { 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44 }, + { 45, 61, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59 }, + { 60, 62, 63, 65, NA, NA, 66, NA, NA, 68, 69, 70, 71, 72, 73 } }; + +static const char* zone_names[] = +{ + ZONE_EN_KEYBOARD, +}; + +static zone_type zone_types[] = +{ + ZONE_TYPE_MATRIX, +}; + +static const unsigned int zone_sizes[] = +{ + 74, +}; + +static const char *led_names[] = +{ + KEY_EN_ESCAPE, + 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_9, + KEY_EN_0, + KEY_EN_MINUS, + KEY_EN_EQUALS, + KEY_EN_BACKSPACE, + KEY_EN_DELETE, + 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_I, + KEY_EN_O, + KEY_EN_P, + KEY_EN_LEFT_BRACKET, + KEY_EN_RIGHT_BRACKET, + KEY_EN_UNUSED, + KEY_EN_HOME, + 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_K, + KEY_EN_L, + KEY_EN_SEMICOLON, + KEY_EN_QUOTE, + KEY_EN_POUND, + KEY_EN_ISO_ENTER, + KEY_EN_PAGE_UP, + KEY_EN_LEFT_SHIFT, + KEY_EN_Z, + KEY_EN_X, + KEY_EN_C, + KEY_EN_V, + KEY_EN_B, + KEY_EN_N, + KEY_EN_M, + KEY_EN_COMMA, + KEY_EN_PERIOD, + KEY_EN_FORWARD_SLASH, + KEY_EN_RIGHT_SHIFT, + KEY_EN_UP_ARROW, + KEY_EN_UNUSED, + KEY_EN_PAGE_DOWN, + KEY_EN_LEFT_CONTROL, + KEY_EN_ISO_BACK_SLASH, + KEY_EN_LEFT_WINDOWS, + KEY_EN_LEFT_ALT, + KEY_EN_UNUSED, + "Left Space", + KEY_EN_SPACE, + "Right Space", + KEY_EN_UNUSED, + KEY_EN_RIGHT_ALT, + KEY_EN_RIGHT_FUNCTION, + KEY_EN_LEFT_ARROW, + KEY_EN_DOWN_ARROW, + KEY_EN_RIGHT_ARROW +}; + +/**------------------------------------------------------------------*\ + @name HyperX Origins 2 65 + @category Keyboard + @type USB + @save :x: + @direct :white_check_mark: + @effects :x: + @detectors DetectHyperXOrigins2_65 + @comment +\*-------------------------------------------------------------------*/ + +RGBController_HyperXOrigins2_65::RGBController_HyperXOrigins2_65(HyperXOrigins2_65Controller* controller_ptr) +{ + controller = controller_ptr; + + name = controller->GetNameString(); + vendor = "HyperX"; + type = DEVICE_TYPE_KEYBOARD; + location = controller->GetDeviceLocation(); + serial = controller->GetSerialString(); + + mode Direct; + Direct.name = "Direct"; + Direct.value = 0xFFFF; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + SetupZones(); + + keepalive_thread_run = 1; + keepalive_thread = new std::thread(&RGBController_HyperXOrigins2_65::KeepaliveThread, this); +} + +RGBController_HyperXOrigins2_65::~RGBController_HyperXOrigins2_65() +{ + keepalive_thread_run = 0; + keepalive_thread->join(); + delete keepalive_thread; + + /*---------------------------------------------------------*\ + | Delete the matrix map | + \*---------------------------------------------------------*/ + for(unsigned int zone_index = 0; zone_index < zones.size(); zone_index++) + { + if(zones[zone_index].matrix_map != NULL) + { + delete zones[zone_index].matrix_map; + } + } + + delete controller; +} + +void RGBController_HyperXOrigins2_65::SetupZones() +{ + /*---------------------------------------------------------*\ + | Set up zones | + \*---------------------------------------------------------*/ + unsigned int total_led_count = 0; + 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]; + + if(zone_types[zone_idx] == ZONE_TYPE_MATRIX) + { + new_zone.matrix_map = new matrix_map_type; + new_zone.matrix_map->height = 5; + new_zone.matrix_map->width = 15; + new_zone.matrix_map->map = (unsigned int *)&matrix_map; + } + else + { + 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(); +} + +void RGBController_HyperXOrigins2_65::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_HyperXOrigins2_65::DeviceUpdateLEDs() +{ + controller->SetLEDsDirect(colors); +} + +void RGBController_HyperXOrigins2_65::UpdateZoneLEDs(int /*zone*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_HyperXOrigins2_65::UpdateSingleLED(int /*led*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_HyperXOrigins2_65::DeviceUpdateMode() +{ + +} + +void RGBController_HyperXOrigins2_65::KeepaliveThread() +{ + while(keepalive_thread_run.load()) + { + if(active_mode == 0) + { + if((std::chrono::steady_clock::now() - last_update_time) > std::chrono::milliseconds(50)) + { + UpdateLEDs(); + } + } + std::this_thread::sleep_for(10ms);; + } +} + diff --git a/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/RGBController_HyperXOrigins2_65.h b/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/RGBController_HyperXOrigins2_65.h new file mode 100644 index 000000000..a04178b32 --- /dev/null +++ b/Controllers/HyperXKeyboardController/HyperXOrigins2_65Controller/RGBController_HyperXOrigins2_65.h @@ -0,0 +1,42 @@ +/*---------------------------------------------------------*\ +| RGBController_HyperXOrigins2_65.h | +| | +| RGBController for HyperX Origins 2 65 keyboard | +| | +| Ricardo Amorim 28 Mar 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include "RGBController.h" +#include "HyperXOrigins2_65Controller.h" + +class RGBController_HyperXOrigins2_65 : public RGBController +{ +public: + RGBController_HyperXOrigins2_65(HyperXOrigins2_65Controller* controller_ptr); + ~RGBController_HyperXOrigins2_65(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + + void KeepaliveThread(); + +private: + HyperXOrigins2_65Controller* controller; + std::thread* keepalive_thread; + std::atomic keepalive_thread_run; + std::chrono::time_point last_update_time; +}; +