Publish LumaOps source

This commit is contained in:
LumaOps release export
2026-09-03 01:18:36 +02:00
commit 7f1c0e5f71
2363 changed files with 501543 additions and 0 deletions
@@ -0,0 +1,187 @@
/*---------------------------------------------------------*\
| RGBController_RoccatBurst.cpp |
| |
| RGBController for Roccat Burst |
| |
| Morgan Guimard (morg) 01 Jun 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_RoccatBurst.h"
/**------------------------------------------------------------------*\
@name Roccat Burst Mouse
@category Mouse
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectRoccatBurstCoreControllers,DetectRoccatBurstProControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_RoccatBurst::RGBController_RoccatBurst(RoccatBurstController* controller_ptr, unsigned int leds_count):
leds_count(leds_count)
{
controller = controller_ptr;
name = controller->GetNameString();
vendor = "Roccat";
type = DEVICE_TYPE_MOUSE;
description = "Roccat Burst Mouse Device";
location = controller->GetDeviceLocation();
serial = controller->GetSerialString();
mode Direct;
Direct.name = "Direct";
Direct.value = ROCCAT_BURST_DIRECT_MODE_VALUE;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mode Static;
Static.name = "Static";
Static.value = ROCCAT_BURST_STATIC_MODE_VALUE;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.brightness = ROCCAT_BURST_BRIGHTNESS_MAX;
Static.brightness_min = ROCCAT_BURST_BRIGHTNESS_MIN;
Static.brightness_max = ROCCAT_BURST_BRIGHTNESS_MAX;
Static.colors.resize(leds_count);
modes.push_back(Static);
mode Rainbow;
Rainbow.name = "Rainbow";
Rainbow.value = ROCCAT_BURST_WAVE_MODE_VALUE;
Rainbow.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Rainbow.color_mode = MODE_COLORS_NONE;
Rainbow.brightness = ROCCAT_BURST_BRIGHTNESS_MAX;
Rainbow.brightness_min = ROCCAT_BURST_BRIGHTNESS_MIN;
Rainbow.brightness_max = ROCCAT_BURST_BRIGHTNESS_MAX;
Rainbow.speed = ROCCAT_BURST_SPEED_MIN;
Rainbow.speed_min = ROCCAT_BURST_SPEED_MIN;
Rainbow.speed_max = ROCCAT_BURST_SPEED_MAX;
modes.push_back(Rainbow);
mode HeartBeat;
HeartBeat.name = "HeartBeat";
HeartBeat.value = ROCCAT_BURST_HEARTBEAT_MODE_VALUE;
HeartBeat.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
HeartBeat.color_mode = MODE_COLORS_MODE_SPECIFIC;
HeartBeat.brightness = ROCCAT_BURST_BRIGHTNESS_MAX;
HeartBeat.brightness_min = ROCCAT_BURST_BRIGHTNESS_MIN;
HeartBeat.brightness_max = ROCCAT_BURST_BRIGHTNESS_MAX;
HeartBeat.speed = ROCCAT_BURST_SPEED_MIN;
HeartBeat.speed_min = ROCCAT_BURST_SPEED_MIN;
HeartBeat.speed_max = ROCCAT_BURST_SPEED_MAX;
HeartBeat.colors.resize(leds_count);
modes.push_back(HeartBeat);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = ROCCAT_BURST_BREATHING_MODE_VALUE;
Breathing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.brightness = ROCCAT_BURST_BRIGHTNESS_MAX;
Breathing.brightness_min = ROCCAT_BURST_BRIGHTNESS_MIN;
Breathing.brightness_max = ROCCAT_BURST_BRIGHTNESS_MAX;
Breathing.speed = ROCCAT_BURST_SPEED_MIN;
Breathing.speed_min = ROCCAT_BURST_SPEED_MIN;
Breathing.speed_max = ROCCAT_BURST_SPEED_MAX;
Breathing.colors.resize(leds_count);
modes.push_back(Breathing);
mode Blinking;
Blinking.name = "Blinking";
Blinking.value = ROCCAT_BURST_BLINKING_MODE_VALUE;
Blinking.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Blinking.color_mode = MODE_COLORS_MODE_SPECIFIC;
Blinking.brightness = ROCCAT_BURST_BRIGHTNESS_MAX;
Blinking.brightness_min = ROCCAT_BURST_BRIGHTNESS_MIN;
Blinking.brightness_max = ROCCAT_BURST_BRIGHTNESS_MAX;
Blinking.speed = ROCCAT_BURST_SPEED_MIN;
Blinking.speed_min = ROCCAT_BURST_SPEED_MIN;
Blinking.speed_max = ROCCAT_BURST_SPEED_MAX;
Blinking.colors.resize(leds_count);
modes.push_back(Blinking);
SetupZones();
}
RGBController_RoccatBurst::~RGBController_RoccatBurst()
{
delete controller;
}
void RGBController_RoccatBurst::SetupZones()
{
zone new_zone;
new_zone.name = "Mouse";
new_zone.type = ZONE_TYPE_LINEAR;
new_zone.leds_min = leds_count;
new_zone.leds_max = leds_count;
new_zone.leds_count = leds_count;
new_zone.matrix_map = NULL;
zones.push_back(new_zone);
std::string led_names[2] =
{
"Scroll Wheel",
"Logo"
};
for(unsigned int i = 0; i < leds_count; i++)
{
led new_led;
new_led.name = led_names[i];
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_RoccatBurst::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatBurst::DeviceUpdateLEDs()
{
UpdateZoneLEDs(0);
}
void RGBController_RoccatBurst::UpdateZoneLEDs(int /*zone_idx*/)
{
const mode& active = modes[active_mode];
if(active.value == ROCCAT_BURST_DIRECT_MODE_VALUE)
{
controller->SendDirect(colors);
}
else
{
controller->SetMode(active.colors, active.value, active.speed, active.brightness, active.color_mode, active.flags);
}
}
void RGBController_RoccatBurst::UpdateSingleLED(int /*led_idx*/)
{
UpdateZoneLEDs(0);
}
void RGBController_RoccatBurst::DeviceUpdateMode()
{
if(modes[active_mode].value == ROCCAT_BURST_DIRECT_MODE_VALUE)
{
controller->SetupDirectMode();
}
else
{
DeviceUpdateLEDs();
}
}
@@ -0,0 +1,35 @@
/*---------------------------------------------------------*\
| RGBController_RoccatBurst.h |
| |
| RGBController for Roccat Burst |
| |
| Morgan Guimard (morg) 01 Jun 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatBurstController.h"
class RGBController_RoccatBurst : public RGBController
{
public:
RGBController_RoccatBurst(RoccatBurstController* controller_ptr, unsigned int leds_count);
~RGBController_RoccatBurst();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatBurstController* controller;
unsigned int leds_count;
};
@@ -0,0 +1,166 @@
/*---------------------------------------------------------*\
| RoccatBurstController.cpp |
| |
| Driver for Roccat Burst |
| |
| Morgan Guimard (morg) 24 Feb 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "RoccatBurstController.h"
#include "StringUtils.h"
RoccatBurstController::RoccatBurstController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
{
dev = dev_handle;
location = info.path;
name = dev_name;
SetupDirectMode();
}
RoccatBurstController::~RoccatBurstController()
{
hid_close(dev);
}
std::string RoccatBurstController::GetDeviceLocation()
{
return("HID: " + location);
}
std::string RoccatBurstController::GetNameString()
{
return(name);
}
std::string RoccatBurstController::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 RoccatBurstController::SetupDirectMode()
{
SwitchControl(true);
}
void RoccatBurstController::SwitchControl(bool direct)
{
unsigned char usb_buf[ROCCAT_BURST_CONTROL_MODE_PACKET_LENGTH];
usb_buf[0x00] = 0x0E;
usb_buf[0x01] = 0x06;
usb_buf[0x02] = 0x01;
usb_buf[0x03] = direct ? 0x01 : 0x00;
usb_buf[0x04] = 0x00;
usb_buf[0x05] = 0xFF;
hid_send_feature_report(dev, usb_buf, ROCCAT_BURST_CONTROL_MODE_PACKET_LENGTH);
}
void RoccatBurstController::SendDirect(std::vector<RGBColor> colors)
{
unsigned char usb_buf[ROCCAT_BURST_DIRECT_MODE_PACKET_LENGTH];
memset(usb_buf, 0x00, ROCCAT_BURST_DIRECT_MODE_PACKET_LENGTH);
usb_buf[0x00] = ROCCAT_BURST_DIRECT_MODE_REPORT_ID;
usb_buf[0x01] = ROCCAT_BURST_DIRECT_MODE_BYTE;
for(unsigned int i = 0; i < colors.size(); i++)
{
usb_buf[0x02 + 3 * i] = RGBGetRValue(colors[i]);
usb_buf[0x03 + 3 * i] = RGBGetGValue(colors[i]);
usb_buf[0x04 + 3 * i] = RGBGetBValue(colors[i]);
}
hid_send_feature_report(dev, usb_buf, ROCCAT_BURST_DIRECT_MODE_PACKET_LENGTH);
}
void RoccatBurstController::SetMode(std::vector<RGBColor> colors, unsigned char mode_value, unsigned char speed, unsigned char brightness, unsigned int color_mode, unsigned int mode_flags)
{
/*---------------------------------------------------------*\
| 1. Read from flash |
\*---------------------------------------------------------*/
unsigned char usb_buf[ROCCAT_BURST_FLASH_PACKET_LENGTH];
memset(usb_buf, 0x00, ROCCAT_BURST_FLASH_PACKET_LENGTH);
usb_buf[0x00] = 0x06;
hid_get_feature_report(dev, usb_buf, ROCCAT_BURST_FLASH_PACKET_LENGTH);
/*---------------------------------------------------------*\
| 2. Update needed bytes |
\*---------------------------------------------------------*/
usb_buf[0x01] = 0x3F;
usb_buf[0x03] = 0x06;
usb_buf[0x04] = 0x06;
usb_buf[0x05] = 0x1F;
usb_buf[30] = mode_value;
usb_buf[31] = mode_flags & MODE_FLAG_HAS_SPEED ? speed : 0xFF;
usb_buf[32] = brightness;
usb_buf[34] = 0xFF;
if(color_mode & MODE_COLORS_MODE_SPECIFIC)
{
usb_buf[36] = 0x14;
usb_buf[37] = 0xFF;
for(unsigned int i = 0; i < colors.size(); i++)
{
usb_buf[38 + 10 * i] = RGBGetRValue(colors[i]);
usb_buf[39 + 10 * i] = RGBGetGValue(colors[i]);
usb_buf[40 + 10 * i] = RGBGetBValue(colors[i]);
}
}
else if (color_mode & MODE_COLORS_NONE)
{
for(unsigned int i = 0; i < colors.size(); i++)
{
usb_buf[38 + 10 * i] = 0xF4;
usb_buf[39 + 10 * i] = 0x00;
usb_buf[40 + 10 * i] = 0x00;
}
}
unsigned int crc = CalculateCRC(&usb_buf[0]);
usb_buf[61] = (unsigned char) crc;
usb_buf[62] = crc >> 8;
/*---------------------------------------------------------*\
| 3. Send to flash |
\*---------------------------------------------------------*/
hid_send_feature_report(dev, usb_buf, ROCCAT_BURST_FLASH_PACKET_LENGTH);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
/*---------------------------------------------------------*\
| 4. Switch to built-in mode |
\*---------------------------------------------------------*/
SwitchControl(false);
}
unsigned int RoccatBurstController::CalculateCRC(unsigned char* bytes)
{
unsigned int crc = 0;
for(unsigned int i = 0; i < ROCCAT_BURST_FLASH_PACKET_LENGTH - 2; i++)
{
crc += bytes[i];
}
return crc;
}
@@ -0,0 +1,70 @@
/*---------------------------------------------------------*\
| RoccatBurstController.h |
| |
| Driver for Roccat Burst |
| |
| Morgan Guimard (morg) 01 Jun 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include <hidapi.h>
#define ROCCAT_BURST_CONTROL_MODE_PACKET_LENGTH 6
#define ROCCAT_BURST_DIRECT_MODE_PACKET_LENGTH 11
#define ROCCAT_BURST_FLASH_PACKET_LENGTH 63
#define ROCCAT_BURST_FLASH_REPORT_ID 0x06
#define ROCCAT_BURST_DIRECT_MODE_REPORT_ID 0x0D
#define ROCCAT_BURST_DIRECT_MODE_BYTE 0x0B
#define ROCCAT_BURST_CORE_NUMBER_OF_LEDS 1
#define ROCCAT_BURST_PRO_NUMBER_OF_LEDS 2
enum
{
ROCCAT_BURST_DIRECT_MODE_VALUE = 0x00,
ROCCAT_BURST_STATIC_MODE_VALUE = 0x01,
ROCCAT_BURST_WAVE_MODE_VALUE = 0x0A,
ROCCAT_BURST_HEARTBEAT_MODE_VALUE = 0x04,
ROCCAT_BURST_BREATHING_MODE_VALUE = 0x03,
ROCCAT_BURST_BLINKING_MODE_VALUE = 0x02
};
enum
{
ROCCAT_BURST_SPEED_MIN = 0x01,
ROCCAT_BURST_SPEED_MAX = 0x0B,
ROCCAT_BURST_BRIGHTNESS_MIN = 0x00,
ROCCAT_BURST_BRIGHTNESS_MAX = 0xFF
};
class RoccatBurstController
{
public:
RoccatBurstController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
~RoccatBurstController();
std::string GetDeviceLocation();
std::string GetNameString();
std::string GetSerialString();
void SetupDirectMode();
void SendDirect(std::vector<RGBColor> colors);
void SetMode(std::vector<RGBColor> colors,
unsigned char mode_value,
unsigned char speed,
unsigned char brightness,
unsigned int color_mode,
unsigned int mode_flags
);
private:
hid_device* dev;
std::string location;
std::string name;
unsigned int CalculateCRC(unsigned char* bytes);
void SwitchControl(bool direct);
};
@@ -0,0 +1,148 @@
/*---------------------------------------------------------*\
| RGBController_RoccatBurstProAir.cpp |
| |
| RGBController for Roccat Burst Pro Air |
| |
| Morgan Guimard (morg) 16 Jun 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_RoccatBurstProAir.h"
/**------------------------------------------------------------------*\
@name Roccat Burst Pro Air
@category Mouse
@type USB
@save :warning:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectRoccatBurstProAirCoreControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_RoccatBurstProAir::RGBController_RoccatBurstProAir(RoccatBurstProAirController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetNameString();
vendor = "Roccat";
type = DEVICE_TYPE_MOUSE;
description = "Roccat Burst Pro Air Mouse Device";
location = controller->GetDeviceLocation();
serial = controller->GetSerialString();
mode Direct;
Direct.name = "Direct";
Direct.value = ROCCAT_BURST_PRO_AIR_DIRECT_MODE_VALUE;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Direct.color_mode = MODE_COLORS_PER_LED;
Direct.brightness = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MAX;
Direct.brightness_min = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MIN;
Direct.brightness_max = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MAX;
modes.push_back(Direct);
mode Blink;
Blink.name = "Blink";
Blink.value = ROCCAT_BURST_PRO_AIR_BLINK_MODE_VALUE;
Blink.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Blink.color_mode = MODE_COLORS_PER_LED;
Blink.brightness = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MAX;
Blink.brightness_min = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MIN;
Blink.brightness_max = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MAX;
Blink.speed = ROCCAT_BURST_PRO_AIR_SPEED_MIN;
Blink.speed_min = ROCCAT_BURST_PRO_AIR_SPEED_MIN;
Blink.speed_max = ROCCAT_BURST_PRO_AIR_SPEED_MAX;
modes.push_back(Blink);
mode Breath;
Breath.name = "Breathing";
Breath.value = ROCCAT_BURST_PRO_AIR_BREATH_MODE_VALUE;
Breath.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Breath.color_mode = MODE_COLORS_PER_LED;
Breath.brightness = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MAX;
Breath.brightness_min = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MIN;
Breath.brightness_max = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MAX;
Breath.speed = ROCCAT_BURST_PRO_AIR_SPEED_MIN;
Breath.speed_min = ROCCAT_BURST_PRO_AIR_SPEED_MIN;
Breath.speed_max = ROCCAT_BURST_PRO_AIR_SPEED_MAX;
modes.push_back(Breath);
mode Wave;
Wave.name = "Wave";
Wave.value = ROCCAT_BURST_PRO_AIR_WAVE_MODE_VALUE;
Wave.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Wave.color_mode = MODE_COLORS_PER_LED;
Wave.brightness = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MAX;
Wave.brightness_min = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MIN;
Wave.brightness_max = ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MAX;
Wave.speed = ROCCAT_BURST_PRO_AIR_SPEED_MIN;
Wave.speed_min = ROCCAT_BURST_PRO_AIR_SPEED_MIN;
Wave.speed_max = ROCCAT_BURST_PRO_AIR_SPEED_MAX;
modes.push_back(Wave);
SetupZones();
}
RGBController_RoccatBurstProAir::~RGBController_RoccatBurstProAir()
{
delete controller;
}
void RGBController_RoccatBurstProAir::SetupZones()
{
zone new_zone;
new_zone.name = "Mouse";
new_zone.type = ZONE_TYPE_LINEAR;
new_zone.leds_min = ROCCAT_BURST_PRO_AIR_PRO_NUMBER_OF_LEDS;
new_zone.leds_max = ROCCAT_BURST_PRO_AIR_PRO_NUMBER_OF_LEDS;
new_zone.leds_count = ROCCAT_BURST_PRO_AIR_PRO_NUMBER_OF_LEDS;
new_zone.matrix_map = NULL;
zones.push_back(new_zone);
std::string led_names[ROCCAT_BURST_PRO_AIR_PRO_NUMBER_OF_LEDS] =
{
"Scroll Wheel",
"Logo",
"Left button",
"Right button"
};
for(unsigned int i = 0; i < ROCCAT_BURST_PRO_AIR_PRO_NUMBER_OF_LEDS; i++)
{
led new_led;
new_led.name = led_names[i];
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_RoccatBurstProAir::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatBurstProAir::DeviceUpdateLEDs()
{
UpdateZoneLEDs(0);
}
void RGBController_RoccatBurstProAir::UpdateZoneLEDs(int /*zone_idx*/)
{
controller->SetColors(colors);
}
void RGBController_RoccatBurstProAir::UpdateSingleLED(int /*led_idx*/)
{
UpdateZoneLEDs(0);
}
void RGBController_RoccatBurstProAir::DeviceUpdateMode()
{
const mode& active = modes[active_mode];
controller->SetModeValues(active.value, active.speed, active.brightness);
}
@@ -0,0 +1,32 @@
/*---------------------------------------------------------*\
| RGBController_RoccatBurstProAir.h |
| |
| RGBController for Roccat Burst Pro Air |
| |
| Morgan Guimard (morg) 16 Jun 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatBurstProAirController.h"
class RGBController_RoccatBurstProAir : public RGBController
{
public:
RGBController_RoccatBurstProAir(RoccatBurstProAirController* controller_ptr);
~RGBController_RoccatBurstProAir();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatBurstProAirController* controller;
};
@@ -0,0 +1,94 @@
/*---------------------------------------------------------*\
| RoccatBurstProAirController.cpp |
| |
| Driver for Roccat Burst Pro Air |
| |
| Morgan Guimard (morg) 16 Jun 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "RoccatBurstProAirController.h"
#include "StringUtils.h"
RoccatBurstProAirController::RoccatBurstProAirController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
{
dev = dev_handle;
location = info.path;
name = dev_name;
}
RoccatBurstProAirController::~RoccatBurstProAirController()
{
hid_close(dev);
}
std::string RoccatBurstProAirController::GetDeviceLocation()
{
return("HID: " + location);
}
std::string RoccatBurstProAirController::GetNameString()
{
return(name);
}
std::string RoccatBurstProAirController::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 RoccatBurstProAirController::SetColors(std::vector<RGBColor> colors)
{
unsigned char usb_buf[ROCCAT_BURST_PRO_AIR_REPORT_SIZE];
memset(usb_buf, 0x00, ROCCAT_BURST_PRO_AIR_REPORT_SIZE);
usb_buf[0] = ROCCAT_BURST_PRO_AIR_REPORT_ID;
usb_buf[1] = 0x01;
usb_buf[2] = 0x4C;
usb_buf[3] = 0x06;
usb_buf[4] = 0x14;
for(unsigned char i = 0; i < colors.size(); i++)
{
usb_buf[5 + 5 * i] = i + 1;
usb_buf[6 + 5 * i] = 0xFF;
usb_buf[7 + 5 * i] = RGBGetRValue(colors[i]);
usb_buf[8 + 5 * i] = RGBGetGValue(colors[i]);
usb_buf[9 + 5 * i] = RGBGetBValue(colors[i]);
}
hid_send_feature_report(dev, usb_buf, ROCCAT_BURST_PRO_AIR_REPORT_SIZE);
}
void RoccatBurstProAirController::SetModeValues(unsigned char mode_value, unsigned char speed, unsigned char brightness)
{
unsigned char usb_buf[ROCCAT_BURST_PRO_AIR_REPORT_SIZE];
memset(usb_buf, 0x00, ROCCAT_BURST_PRO_AIR_REPORT_SIZE);
usb_buf[0] = ROCCAT_BURST_PRO_AIR_REPORT_ID;
usb_buf[1] = 0x01;
usb_buf[2] = 0x4C;
usb_buf[3] = 0x06;
usb_buf[4] = 0x06;
usb_buf[5] = mode_value;
usb_buf[6] = speed;
usb_buf[7] = brightness;
usb_buf[8] = 0x0F;
hid_send_feature_report(dev, usb_buf, ROCCAT_BURST_PRO_AIR_REPORT_SIZE);
}
@@ -0,0 +1,54 @@
/*---------------------------------------------------------*\
| RoccatBurstProAirController.h |
| |
| Driver for Roccat Burst Pro Air |
| |
| Morgan Guimard (morg) 16 Jun 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <hidapi.h>
#include "RGBController.h"
#define ROCCAT_BURST_PRO_AIR_REPORT_ID 0x06
#define ROCCAT_BURST_PRO_AIR_REPORT_SIZE 30
#define ROCCAT_BURST_PRO_AIR_PRO_NUMBER_OF_LEDS 4
enum
{
ROCCAT_BURST_PRO_AIR_DIRECT_MODE_VALUE = 0x01,
ROCCAT_BURST_PRO_AIR_BLINK_MODE_VALUE = 0x02,
ROCCAT_BURST_PRO_AIR_BREATH_MODE_VALUE = 0x03,
ROCCAT_BURST_PRO_AIR_WAVE_MODE_VALUE = 0x04
};
enum
{
ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MIN = 0x00,
ROCCAT_BURST_PRO_AIR_BRIGHTNESS_MAX = 0xFF,
ROCCAT_BURST_PRO_AIR_SPEED_MIN = 0x00,
ROCCAT_BURST_PRO_AIR_SPEED_MAX = 0x0B
};
class RoccatBurstProAirController
{
public:
RoccatBurstProAirController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
~RoccatBurstProAirController();
std::string GetDeviceLocation();
std::string GetNameString();
std::string GetSerialString();
void SetColors(std::vector<RGBColor> colors);
void SetModeValues(unsigned char mode_value, unsigned char speed, unsigned char brightness);
private:
hid_device* dev;
std::string location;
std::string name;
};
@@ -0,0 +1,373 @@
/*---------------------------------------------------------*\
| RoccatControllerDetect.cpp |
| |
| Detector for Roccat devices |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "Detector.h"
#include "RoccatBurstController.h"
#include "RoccatBurstProAirController.h"
#include "RoccatKoneAimoController.h"
#include "RoccatKoneProController.h"
#include "RoccatKoneProAirController.h"
#include "RoccatKoneXPController.h"
#include "RoccatSenseAimoController.h"
#include "RoccatVulcanKeyboardController.h"
#include "RoccatKovaController.h"
#include "RoccatEloController.h"
#include "RGBController_RoccatBurst.h"
#include "RGBController_RoccatBurstProAir.h"
#include "RGBController_RoccatHordeAimo.h"
#include "RGBController_RoccatKoneAimo.h"
#include "RGBController_RoccatKonePro.h"
#include "RGBController_RoccatKoneProAir.h"
#include "RGBController_RoccatKoneXP.h"
#include "RGBController_RoccatSenseAimo.h"
#include "RGBController_RoccatVulcanKeyboard.h"
#include "RGBController_RoccatKova.h"
#include "RGBController_RoccatElo.h"
#include <hidapi.h>
#include <unordered_set>
#define ROCCAT_VID 0x1E7D
#define TURTLE_BEACH_VID 0x10F5
/*--------------------------------------------------------------------------------*\
| KEYBOARDS |
| RoccatVulcanKeyboardController PIDs defined in RoccatVulcanKeyboardController.h |
\*--------------------------------------------------------------------------------*/
#define ROCCAT_HORDE_AIMO_PID 0x303E
/*-----------------------------------------------------------------*\
| MICE |
\*-----------------------------------------------------------------*/
#define ROCCAT_BURST_CORE_PID 0x2DE6
#define ROCCAT_BURST_PRO_PID 0x2DE1
#define ROCCAT_BURST_PRO_AIR_PID 0x2CA6
#define ROCCAT_KONE_AIMO_PID 0x2E27
#define ROCCAT_KONE_AIMO_16K_PID 0x2E2C
#define ROCCAT_KONE_PRO_PID 0x2C88
#define ROCCAT_KONE_PRO_AIR_PID 0x2C8E
#define ROCCAT_KONE_PRO_AIR_WIRED_PID 0x2C92
#define ROCCAT_KONE_XP_PID 0x2C8B
#define ROCCAT_KOVA_PID 0x2CEE
/*-----------------------------------------------------------------*\
| MOUSEMATS |
\*-----------------------------------------------------------------*/
#define ROCCAT_SENSE_AIMO_MID_PID 0x343A
#define ROCCAT_SENSE_AIMO_XXL_PID 0x343B
/*-----------------------------------------------------------------*\
| HEADSETS |
\*-----------------------------------------------------------------*/
#define ROCCAT_ELO_PID 0x3A34
void DetectRoccatMouseControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatKoneAimoController * controller = new RoccatKoneAimoController(dev, info->path, name);
RGBController_RoccatKoneAimo * rgb_controller = new RGBController_RoccatKoneAimo(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
/*---------------------------------------------------------------------------------*\
| Tracks the paths used in DetectRoccatVulcanKeyboardControllers so multiple Roccat |
| devices can be detected without all controlling the same device. |
\*---------------------------------------------------------------------------------*/
static std::unordered_set<std::string> used_paths;
/*--------------------------------------------------------------------------------*\
| Removes all entries in used_paths so device discovery does not skip any of them. |
\*--------------------------------------------------------------------------------*/
void ResetRoccatVulcanKeyboardControllersPaths()
{
used_paths.clear();
}
void DetectRoccatVulcanKeyboardControllers(hid_device_info* info, const std::string& name)
{
/*-------------------------------------------------------------------------------------------------*\
| Create a local copy of the HID enumerations for the Roccat Vulcan Keyboard VID/PID and iterate |
| through it. This prevents detection from failing if interface 1 comes before interface 0 in the |
| main info list. |
\*-------------------------------------------------------------------------------------------------*/
hid_device* dev_ctrl = nullptr;
hid_device* dev_led = nullptr;
hid_device_info* info_full = hid_enumerate(info->vendor_id, info->product_id);
hid_device_info* info_temp = info_full;
/*--------------------------------------------------------------------------------------------*\
| Keep track of paths so they can be added to used_paths only if both interfaces can be found. |
\*--------------------------------------------------------------------------------------------*/
std::string dev_ctrl_path;
std::string dev_led_path;
int dev_led_page;
int dev_ctrl_page;
int dev_led_iface = 3;
int dev_ctrl_iface = 1;
switch(info->product_id)
{
case ROCCAT_VULCAN_PRO_PID:
case ROCCAT_VULCAN_TKL_PRO_PID:
case ROCCAT_PYRO_PID:
case ROCCAT_MAGMA_PID:
case ROCCAT_MAGMA_MINI_PID:
case ROCCAT_VULCAN_II_PID:
case ROCCAT_VULCAN_II_MAX_PID:
case TURTLE_BEACH_VULCAN_II_PID:
dev_led_page = 0xFF00;
dev_ctrl_page = 0xFF01;
dev_led_iface = 3;
dev_ctrl_iface = 1;
break;
case TURTLE_BEACH_VULCAN_II_TKL_PRO_PID:
dev_led_page = 0xFF00;
dev_ctrl_page = 0x0001;
dev_led_iface = 4;
dev_ctrl_iface = 1;
break;
default:
dev_led_page = 0x0001;
dev_ctrl_page = 0x000B;
dev_led_iface = 3;
dev_ctrl_iface = 1;
break;
}
while(info_temp)
{
/*----------------------------------------------------------------------------------------*\
| Check for paths used on an already registered Roccat Vulcan Keyboard controller to avoid |
| registering multiple controllers that refer to the same physical hardware. |
\*----------------------------------------------------------------------------------------*/
if(info_temp->vendor_id == info->vendor_id
&& info_temp->product_id == info->product_id
&& used_paths.find(info_temp->path) == used_paths.end() )
{
if(info_temp->interface_number == dev_ctrl_iface && info_temp->usage_page == dev_ctrl_page)
{
dev_ctrl = hid_open_path(info_temp->path);
dev_ctrl_path = info_temp->path;
}
else if(info_temp->interface_number == dev_led_iface && info_temp->usage_page == dev_led_page)
{
dev_led = hid_open_path(info_temp->path);
dev_led_path = info_temp->path;
}
}
if(dev_ctrl && dev_led)
{
break;
}
info_temp = info_temp->next;
}
hid_free_enumeration(info_full);
if(dev_ctrl && dev_led)
{
RoccatVulcanKeyboardController * controller = new RoccatVulcanKeyboardController(dev_ctrl, dev_led, info->path, info->product_id, name);
RGBController_RoccatVulcanKeyboard * rgb_controller = new RGBController_RoccatVulcanKeyboard(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
used_paths.insert(dev_ctrl_path);
used_paths.insert(dev_led_path);
}
else
{
// Not all of them could be opened, do some cleanup
hid_close(dev_ctrl);
hid_close(dev_led);
}
}
void DetectRoccatHordeAimoKeyboardControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatHordeAimoController * controller = new RoccatHordeAimoController(dev, *info, name);
RGBController_RoccatHordeAimo * rgb_controller = new RGBController_RoccatHordeAimo(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectRoccatBurstCoreControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatBurstController * controller = new RoccatBurstController(dev, *info, name);
RGBController_RoccatBurst * rgb_controller = new RGBController_RoccatBurst(controller, ROCCAT_BURST_CORE_NUMBER_OF_LEDS);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectRoccatBurstProControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatBurstController * controller = new RoccatBurstController(dev, *info, name);
RGBController_RoccatBurst * rgb_controller = new RGBController_RoccatBurst(controller, ROCCAT_BURST_PRO_NUMBER_OF_LEDS);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectRoccatBurstProAirControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatBurstProAirController * controller = new RoccatBurstProAirController(dev, *info, name);
RGBController_RoccatBurstProAir * rgb_controller = new RGBController_RoccatBurstProAir(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectRoccatKoneProControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatKoneProController * controller = new RoccatKoneProController(dev, *info, name);
RGBController_RoccatKonePro * rgb_controller = new RGBController_RoccatKonePro(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectRoccatKoneProAirControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatKoneProAirController * controller = new RoccatKoneProAirController(dev, *info, name);
RGBController_RoccatKoneProAir * rgb_controller = new RGBController_RoccatKoneProAir(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectRoccatKoneXPControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatKoneXPController * controller = new RoccatKoneXPController(dev, info->path, name);
RGBController_RoccatKoneXP * rgb_controller = new RGBController_RoccatKoneXP(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectRoccatKovaControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatKovaController * controller = new RoccatKovaController(dev, info->path, name);
RGBController_RoccatKova * rgb_controller = new RGBController_RoccatKova(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectRoccatEloControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatEloController * controller = new RoccatEloController(dev, *info, name);
RGBController_RoccatElo * rgb_controller = new RGBController_RoccatElo(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectRoccatSenseAimoControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatSenseAimoController * controller = new RoccatSenseAimoController(dev, info->path, name);
RGBController_RoccatSenseAimo * rgb_controller = new RGBController_RoccatSenseAimo(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
REGISTER_PRE_DETECTION_HOOK(ResetRoccatVulcanKeyboardControllersPaths);
/*-----------------------------------------------------------------*\
| KEYBOARDS |
\*-----------------------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Roccat Horde Aimo", DetectRoccatHordeAimoKeyboardControllers, ROCCAT_VID, ROCCAT_HORDE_AIMO_PID, 1, 0x0B, 0 );
REGISTER_HID_DETECTOR_IP ("Roccat Magma", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_MAGMA_PID, 1, 0xFF01);
REGISTER_HID_DETECTOR_IP ("Roccat Magma Mini", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_MAGMA_MINI_PID, 1, 0xFF01);
REGISTER_HID_DETECTOR_IP ("Roccat Pyro", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_PYRO_PID, 1, 0xFF01);
REGISTER_HID_DETECTOR_IP ("Roccat Vulcan 100 Aimo", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_VULCAN_100_AIMO_PID, 1, 11);
REGISTER_HID_DETECTOR_IP ("Roccat Vulcan 120-Series Aimo", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_VULCAN_120_AIMO_PID, 1, 11);
REGISTER_HID_DETECTOR_IP ("Roccat Vulcan TKL", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_VULCAN_TKL_PID, 1, 11);
REGISTER_HID_DETECTOR_IP ("Roccat Vulcan Pro", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_VULCAN_PRO_PID, 1, 0xFF01);
REGISTER_HID_DETECTOR_IP ("Roccat Vulcan TKL Pro", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_VULCAN_TKL_PRO_PID, 1, 0xFF01);
REGISTER_HID_DETECTOR_IP ("Roccat Vulcan II", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_VULCAN_II_PID, 1, 0xFF01);
REGISTER_HID_DETECTOR_IP ("Roccat Vulcan II Max", DetectRoccatVulcanKeyboardControllers, ROCCAT_VID, ROCCAT_VULCAN_II_MAX_PID, 1, 0xFF01);
REGISTER_HID_DETECTOR_IP ("Turtle Beach Vulcan II", DetectRoccatVulcanKeyboardControllers, TURTLE_BEACH_VID, TURTLE_BEACH_VULCAN_II_PID, 1, 0xFF01);
REGISTER_HID_DETECTOR_IP ("Turtle Beach Vulcan II TKL", DetectRoccatVulcanKeyboardControllers, TURTLE_BEACH_VID, TURTLE_BEACH_VULCAN_II_TKL_PID, 1, 11);
REGISTER_HID_DETECTOR_IP ("Turtle Beach Vulcan II TKL Pro", DetectRoccatVulcanKeyboardControllers, TURTLE_BEACH_VID, TURTLE_BEACH_VULCAN_II_TKL_PRO_PID, 1, 0x0001);
/*-----------------------------------------------------------------*\
| MICE |
\*-----------------------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Roccat Burst Core", DetectRoccatBurstCoreControllers, ROCCAT_VID, ROCCAT_BURST_CORE_PID, 3, 0xFF01, 1 );
REGISTER_HID_DETECTOR_IPU("Roccat Burst Pro", DetectRoccatBurstProControllers, ROCCAT_VID, ROCCAT_BURST_PRO_PID, 3, 0xFF01, 1 );
REGISTER_HID_DETECTOR_IPU("Roccat Burst Pro Air", DetectRoccatBurstProAirControllers, ROCCAT_VID, ROCCAT_BURST_PRO_AIR_PID, 0, 0x01, 2 );
REGISTER_HID_DETECTOR_IPU("Roccat Kone Aimo", DetectRoccatMouseControllers, ROCCAT_VID, ROCCAT_KONE_AIMO_PID, 0, 0x0B, 0 );
REGISTER_HID_DETECTOR_IPU("Roccat Kone Aimo 16K", DetectRoccatMouseControllers, ROCCAT_VID, ROCCAT_KONE_AIMO_16K_PID, 0, 0x0B, 0 );
REGISTER_HID_DETECTOR_IPU("Roccat Kone Pro", DetectRoccatKoneProControllers, ROCCAT_VID, ROCCAT_KONE_PRO_PID, 3, 0xFF01, 1 );
REGISTER_HID_DETECTOR_IPU("Roccat Kone Pro Air", DetectRoccatKoneProAirControllers, ROCCAT_VID, ROCCAT_KONE_PRO_AIR_PID, 2, 0xFF00, 1 );
REGISTER_HID_DETECTOR_IPU("Roccat Kone Pro Air (Wired)", DetectRoccatKoneProAirControllers, ROCCAT_VID, ROCCAT_KONE_PRO_AIR_WIRED_PID, 1, 0xFF13, 1 );
REGISTER_HID_DETECTOR_IPU("Roccat Kone XP", DetectRoccatKoneXPControllers, ROCCAT_VID, ROCCAT_KONE_XP_PID, 3, 0xFF01, 1 );
REGISTER_HID_DETECTOR_IPU("Roccat Kova", DetectRoccatKovaControllers, ROCCAT_VID, ROCCAT_KOVA_PID, 0, 0x0B, 0 );
/*-----------------------------------------------------------------*\
| MOUSEMATS |
\*-----------------------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Roccat Sense Aimo Mid", DetectRoccatSenseAimoControllers, ROCCAT_VID, ROCCAT_SENSE_AIMO_MID_PID, 0, 0xFF01, 1 );
REGISTER_HID_DETECTOR_IPU("Roccat Sense Aimo XXL", DetectRoccatSenseAimoControllers, ROCCAT_VID, ROCCAT_SENSE_AIMO_XXL_PID, 0, 0xFF01, 1 );
/*-----------------------------------------------------------------*\
| HEADSETS |
\*-----------------------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Roccat Elo 7.1", DetectRoccatEloControllers, ROCCAT_VID, ROCCAT_ELO_PID, 3, 0x0C, 1 );
@@ -0,0 +1,95 @@
/*---------------------------------------------------------*\
| RGBController_RoccatElo.cpp |
| |
| RGBController for Roccat Elo |
| |
| Flora Aubry 02 Jan 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <chrono>
#include <thread>
#include "RGBController_RoccatElo.h"
/**------------------------------------------------------------------*\
@name Roccat Elo 7.1
@category Headset
@type USB
@save :x:
@direct :white_check_mark:
@effects :x:
@detectors DetectRoccatEloControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_RoccatElo::RGBController_RoccatElo(RoccatEloController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetNameString();
vendor = "Roccat";
type = DEVICE_TYPE_HEADSET;
description = "Roccat Elo 7.1 Headset Device";
location = controller->GetDeviceLocation();
serial = controller->GetSerialString();
mode Direct;
Direct.name = "Direct";
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
SetupZones();
}
RGBController_RoccatElo::~RGBController_RoccatElo()
{
delete controller;
}
void RGBController_RoccatElo::SetupZones()
{
zone new_zone;
new_zone.name = "Headset";
new_zone.type = ZONE_TYPE_LINEAR;
new_zone.leds_min = ROCCAT_ELO_LEDS_COUNT;
new_zone.leds_max = ROCCAT_ELO_LEDS_COUNT;
new_zone.leds_count = ROCCAT_ELO_LEDS_COUNT;
new_zone.matrix_map = nullptr;
zones.emplace_back(new_zone);
leds.resize(new_zone.leds_count);
SetupColors();
}
void RGBController_RoccatElo::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatElo::DeviceUpdateLEDs()
{
controller->SendDirect(colors[0]);
}
void RGBController_RoccatElo::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatElo::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatElo::DeviceUpdateMode()
{
}
@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| RGBController_RoccatElo.h |
| |
| RGBController for Roccat Elo |
| |
| Flora Aubry 02 Jan 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatEloController.h"
class RGBController_RoccatElo : public RGBController
{
public:
RGBController_RoccatElo(RoccatEloController* controller_ptr);
~RGBController_RoccatElo();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatEloController* controller;
};
@@ -0,0 +1,98 @@
/*---------------------------------------------------------*\
| RoccatEloController.cpp |
| |
| Driver for Roccat Elo |
| |
| Flora Aubry 02 Jan 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cmath>
#include <string.h>
#include "RoccatEloController.h"
#include "StringUtils.h"
RoccatEloController::RoccatEloController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
{
dev = dev_handle;
location = info.path;
name = dev_name;
SendInit();
}
RoccatEloController::~RoccatEloController()
{
hid_close(dev);
}
std::string RoccatEloController::GetDeviceLocation()
{
return("HID: " + location);
}
std::string RoccatEloController::GetNameString()
{
return(name);
}
std::string RoccatEloController::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 RoccatEloController::SendInit()
{
unsigned char usb_buf[ROCCAT_ELO_REPORT_SIZE];
memset(usb_buf, 0x00, ROCCAT_ELO_REPORT_SIZE);
usb_buf[0x00] = ROCCAT_ELO_REPORT_ID;
usb_buf[0x01] = 0x01;
hid_write(dev, usb_buf, ROCCAT_ELO_REPORT_SIZE);
usb_buf[0x01] = 0x02;
hid_write(dev, usb_buf, ROCCAT_ELO_REPORT_SIZE);
usb_buf[0x01] = 0x03;
usb_buf[0x03] = 0x01;
hid_write(dev, usb_buf, ROCCAT_ELO_REPORT_SIZE);
SendDirect(0);
memset(usb_buf, 0x00, ROCCAT_ELO_REPORT_SIZE);
usb_buf[0x00] = ROCCAT_ELO_REPORT_ID;
usb_buf[0x01] = 0x01;
hid_write(dev, usb_buf, ROCCAT_ELO_REPORT_SIZE);
}
void RoccatEloController::SendDirect(RGBColor color)
{
unsigned char usb_buf[ROCCAT_ELO_REPORT_SIZE];
memset(usb_buf, 0x00, ROCCAT_ELO_REPORT_SIZE);
usb_buf[0x00] = ROCCAT_ELO_REPORT_ID;
usb_buf[0x01] = 0x04;
usb_buf[0x04] = RGBGetRValue(color);
usb_buf[0x05] = RGBGetGValue(color);
usb_buf[0x06] = RGBGetBValue(color);
hid_write(dev, usb_buf, ROCCAT_ELO_REPORT_SIZE);
}
@@ -0,0 +1,40 @@
/*---------------------------------------------------------*\
| RoccatEloController.h |
| |
| Driver for Roccat Elo |
| |
| Flora Aubry 02 Jan 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <string>
#include <hidapi.h>
#include "RGBController.h"
#define ROCCAT_ELO_REPORT_SIZE 16
#define ROCCAT_ELO_LEDS_COUNT 1
#define ROCCAT_ELO_REPORT_ID 0xFF
class RoccatEloController
{
public:
RoccatEloController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
~RoccatEloController();
std::string GetDeviceLocation();
std::string GetNameString();
std::string GetSerialString();
void SendDirect(RGBColor color);
private:
hid_device* dev;
std::string location;
std::string name;
void SendInit();
};
@@ -0,0 +1,97 @@
/*---------------------------------------------------------*\
| RGBController_RoccatHordeAimo.cpp |
| |
| RGBController for Roccat Horde Aimo |
| |
| Morgan Guimard (morg) 24 Feb 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_RoccatHordeAimo.h"
/**------------------------------------------------------------------*\
@name Roccat Horde Aimo
@category Keyboard
@type USB
@save :x:
@direct :white_check_mark:
@effects :x:
@detectors DetectRoccatHordeAimoKeyboardControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_RoccatHordeAimo::RGBController_RoccatHordeAimo(RoccatHordeAimoController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetNameString();
vendor = "Roccat";
type = DEVICE_TYPE_KEYBOARD;
description = "Roccat Horde Aimo Keyboard Device";
location = controller->GetDeviceLocation();
serial = controller->GetSerialString();
mode Direct;
Direct.name = "Direct";
Direct.value = 0;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
SetupZones();
}
RGBController_RoccatHordeAimo::~RGBController_RoccatHordeAimo()
{
delete controller;
}
void RGBController_RoccatHordeAimo::SetupZones()
{
zone new_zone;
new_zone.name = "Keyboard";
new_zone.type = ZONE_TYPE_LINEAR;
new_zone.leds_min = NUMBER_OF_LEDS;
new_zone.leds_max = NUMBER_OF_LEDS;
new_zone.leds_count = NUMBER_OF_LEDS;
new_zone.matrix_map = NULL;
zones.push_back(new_zone);
for(unsigned int i = 0; i < NUMBER_OF_LEDS; i++)
{
led new_led;
new_led.name = "LED " + std::to_string(i + 1);
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_RoccatHordeAimo::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatHordeAimo::DeviceUpdateLEDs()
{
UpdateZoneLEDs(0);
}
void RGBController_RoccatHordeAimo::UpdateZoneLEDs(int /*zone_idx*/)
{
controller->SetColors(colors);
}
void RGBController_RoccatHordeAimo::UpdateSingleLED(int /*led_idx*/)
{
UpdateZoneLEDs(0);
}
void RGBController_RoccatHordeAimo::DeviceUpdateMode()
{
}
@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| RGBController_RoccatHordeAimo.h |
| |
| RGBController for Roccat Horde Aimo |
| |
| Morgan Guimard (morg) 24 Feb 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatHordeAimoController.h"
class RGBController_RoccatHordeAimo : public RGBController
{
public:
RGBController_RoccatHordeAimo(RoccatHordeAimoController* controller_ptr);
~RGBController_RoccatHordeAimo();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatHordeAimoController* controller;
};
@@ -0,0 +1,96 @@
/*---------------------------------------------------------*\
| RoccatHordeAimoController.cpp |
| |
| Driver for Roccat Horde Aimo |
| |
| Morgan Guimard (morg) 24 Feb 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "RoccatHordeAimoController.h"
#include "StringUtils.h"
RoccatHordeAimoController::RoccatHordeAimoController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
{
dev = dev_handle;
location = info.path;
name = dev_name;
InitialPacket();
}
RoccatHordeAimoController::~RoccatHordeAimoController()
{
hid_close(dev);
}
void RoccatHordeAimoController::InitialPacket()
{
unsigned char usb_buf[8];
memset(usb_buf, 0x00,8);
usb_buf[0x00] = 0x13;
usb_buf[0x01] = 0x08;
usb_buf[0x02] = 0x01;
hid_send_feature_report(dev, usb_buf, 8);
}
std::string RoccatHordeAimoController::GetDeviceLocation()
{
return("HID: " + location);
}
std::string RoccatHordeAimoController::GetNameString()
{
return(name);
}
std::string RoccatHordeAimoController::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 RoccatHordeAimoController::SetColors(std::vector<RGBColor> colors)
{
unsigned char usb_buf[WRITE_PACKET_LENGTH];
usb_buf[0x00] = REPORT_ID;
usb_buf[0x01] = WRITE_PACKET_LENGTH;
usb_buf[0x02] = 0xFF;
usb_buf[0x03] = 0xFF;
for(unsigned int i = 0; i < 6; i++)
{
usb_buf[0x04 + (i * 3)] = RGBGetRValue(colors[i]);
usb_buf[0x05 + (i * 3)] = RGBGetGValue(colors[i]);
usb_buf[0x06 + (i * 3)] = RGBGetBValue(colors[i]);
}
int crc = 0;
for(unsigned int i = 0; i < WRITE_PACKET_LENGTH - 2; i++)
{
crc += usb_buf[i];
}
usb_buf[22] = crc;
usb_buf[23] = crc >> 8;
hid_send_feature_report(dev, usb_buf, WRITE_PACKET_LENGTH);
unsigned char usb_read_buf[READ_PACKET_LENGTH];
hid_get_feature_report(dev, usb_read_buf, READ_PACKET_LENGTH);
}
@@ -0,0 +1,40 @@
/*---------------------------------------------------------*\
| RoccatHordeAimoController.h |
| |
| Driver for Roccat Horde Aimo |
| |
| Morgan Guimard (morg) 24 Feb 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <hidapi.h>
#include "RGBController.h"
#define WRITE_PACKET_LENGTH 24
#define READ_PACKET_LENGTH 3
#define REPORT_ID 0x18
#define NUMBER_OF_LEDS 6
class RoccatHordeAimoController
{
public:
RoccatHordeAimoController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
~RoccatHordeAimoController();
std::string GetDeviceLocation();
std::string GetNameString();
std::string GetSerialString();
void SetColors(std::vector<RGBColor> colors);
private:
hid_device* dev;
std::string location;
std::string name;
void InitialPacket();
};
@@ -0,0 +1,217 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKoneAimo.cpp |
| |
| RGBController for Roccat Kone Aimo |
| |
| Thibaud M (enlight3d) 17 Nov 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_RoccatKoneAimo.h"
/**------------------------------------------------------------------*\
@name Roccat Kone Aimo
@category Mouse
@type USB
@save :x:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectRoccatMouseControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_RoccatKoneAimo::RGBController_RoccatKoneAimo(RoccatKoneAimoController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetName();
vendor = "Roccat";
type = DEVICE_TYPE_MOUSE;
description = "Roccat Kone Aimo Mouse Device";
location = controller->GetLocation();
serial = controller->GetSerial();
mode Direct;
Direct.name = "Direct";
Direct.value = 0;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.speed_min = 0;
Direct.speed_max = 0;
Direct.speed = 0;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
active_mode = 0;
SetupZones();
}
RGBController_RoccatKoneAimo::~RGBController_RoccatKoneAimo()
{
delete controller;
}
void RGBController_RoccatKoneAimo::SetupZones()
{
/*---------------------------------------------------------*\
| Set up zones and leds per zone |
\*---------------------------------------------------------*/
zone WHEEL_zone;
WHEEL_zone.name = "Scroll Wheel";
WHEEL_zone.type = ZONE_TYPE_SINGLE;
WHEEL_zone.leds_min = 1;
WHEEL_zone.leds_max = 1;
WHEEL_zone.leds_count = 1;
WHEEL_zone.matrix_map = NULL;
zones.push_back(WHEEL_zone);
zones_channel.push_back(SCROLL_WHEEL);
led WHEEL_led;
WHEEL_led.name = "Wheel LED";
WHEEL_led.value = (unsigned int)zones.size();
leds.push_back(WHEEL_led);
leds_channel.push_back(SCROLL_WHEEL);
zone STRIP_LEFT_zone;
STRIP_LEFT_zone.name = "Strip left";
STRIP_LEFT_zone.type = ZONE_TYPE_LINEAR;
STRIP_LEFT_zone.leds_min = 4;
STRIP_LEFT_zone.leds_max = 4;
STRIP_LEFT_zone.leds_count = 4;
STRIP_LEFT_zone.matrix_map = NULL;
zones.push_back(STRIP_LEFT_zone);
zones_channel.push_back(STRIP_LEFT);
for(std::size_t led_idx = 0; led_idx < STRIP_LEFT_zone.leds_max; led_idx++)
{
led STRIP_LEFT_led;
STRIP_LEFT_led.name = "Strip left LED " + std::to_string(led_idx + 1);
STRIP_LEFT_led.value = (unsigned int)zones.size();
leds.push_back(STRIP_LEFT_led);
leds_channel.push_back(STRIP_LEFT);
}
zone STRIP_RIGHT_zone;
STRIP_RIGHT_zone.name = "Strip right";
STRIP_RIGHT_zone.type = ZONE_TYPE_LINEAR;
STRIP_RIGHT_zone.leds_min = 4;
STRIP_RIGHT_zone.leds_max = 4;
STRIP_RIGHT_zone.leds_count = 4;
STRIP_RIGHT_zone.matrix_map = NULL;
zones.push_back(STRIP_RIGHT_zone);
zones_channel.push_back(STRIP_RIGHT);
for(std::size_t led_idx = 0; led_idx < STRIP_RIGHT_zone.leds_max; led_idx++)
{
led STRIP_RIGHT_led;
STRIP_RIGHT_led.name = "Strip right LED " + std::to_string(led_idx + 1);
STRIP_RIGHT_led.value = (unsigned int)zones.size();
leds.push_back(STRIP_RIGHT_led);
leds_channel.push_back(STRIP_RIGHT);
}
zone LOWER_LEFT_zone;
LOWER_LEFT_zone.name = "Lower left";
LOWER_LEFT_zone.type = ZONE_TYPE_SINGLE;
LOWER_LEFT_zone.leds_min = 1;
LOWER_LEFT_zone.leds_max = 1;
LOWER_LEFT_zone.leds_count = 1;
LOWER_LEFT_zone.matrix_map = NULL;
zones.push_back(LOWER_LEFT_zone);
zones_channel.push_back(LOWER_LEFT);
led LOWER_LEFT_led;
LOWER_LEFT_led.name = "Lower left LED";
LOWER_LEFT_led.value = (unsigned int)zones.size();
leds.push_back(LOWER_LEFT_led);
leds_channel.push_back(LOWER_LEFT);
zone LOWER_RIGHT_zone;
LOWER_RIGHT_zone.name = "Lower right";
LOWER_RIGHT_zone.type = ZONE_TYPE_SINGLE;
LOWER_RIGHT_zone.leds_min = 1;
LOWER_RIGHT_zone.leds_max = 1;
LOWER_RIGHT_zone.leds_count = 1;
LOWER_RIGHT_zone.matrix_map = NULL;
zones.push_back(LOWER_RIGHT_zone);
zones_channel.push_back(LOWER_RIGHT);
led LOWER_RIGHT_led;
LOWER_RIGHT_led.name = "Lower right LED";
LOWER_RIGHT_led.value = (unsigned int)zones.size();
leds.push_back(LOWER_RIGHT_led);
leds_channel.push_back(LOWER_RIGHT);
SetupColors();
/*---------------------------------------------------------*\
| Initialize colors for each LED |
\*---------------------------------------------------------*/
for(std::size_t led_idx = 0; led_idx < leds.size(); led_idx++)
{
unsigned char red = 0x00;
unsigned char grn = 0x00;
unsigned char blu = 0x00;
colors[led_idx] = ToRGBColor(red, grn, blu);
}
}
void RGBController_RoccatKoneAimo::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatKoneAimo::DeviceUpdateLEDs()
{
/*---------------------------------------------------------*\
| Set colors for all channel/leds |
\*---------------------------------------------------------*/
for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
controller->SetChannelColors(zones_channel[zone_idx], zones[zone_idx].colors, zones[zone_idx].leds_count);
}
/*---------------------------------------------------------*\
| Apply new colors to the mouse |
\*---------------------------------------------------------*/
controller->SendUpdate();
}
void RGBController_RoccatKoneAimo::UpdateZoneLEDs(int zone_idx)
{
/*---------------------------------------------------------*\
| Set colors for one channel of leds |
\*---------------------------------------------------------*/
controller->SetChannelColors(zones_channel[zone_idx], zones[zone_idx].colors, zones[zone_idx].leds_count);
/*---------------------------------------------------------*\
| Apply new colors to the mouse |
\*---------------------------------------------------------*/
controller->SendUpdate();
}
void RGBController_RoccatKoneAimo::UpdateSingleLED(int led_idx)
{
/*---------------------------------------------------------*\
| Get channel corresponding to led |
\*---------------------------------------------------------*/
ROCCAT_KONE_AIMO_CHANNEL channel = leds_channel[led_idx];
/*---------------------------------------------------------*\
| Update channel corresponding to led |
\*---------------------------------------------------------*/
controller->SetChannelColors(channel, zones[leds[led_idx].value].colors, zones[leds[led_idx].value].leds_count);
/*---------------------------------------------------------*\
| Apply new colors to the mouse |
\*---------------------------------------------------------*/
controller->SendUpdate();
}
void RGBController_RoccatKoneAimo::DeviceUpdateMode()
{
/*---------------------------------------------------------*\
| This device does not support changing mode |
\*---------------------------------------------------------*/
}
@@ -0,0 +1,36 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKoneAimo.h |
| |
| RGBController for Roccat Kone Aimo |
| |
| Thibaud M (enlight3d) 17 Nov 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatKoneAimoController.h"
class RGBController_RoccatKoneAimo : public RGBController
{
public:
RGBController_RoccatKoneAimo(RoccatKoneAimoController* controller_ptr);
~RGBController_RoccatKoneAimo();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatKoneAimoController* controller;
std::vector<ROCCAT_KONE_AIMO_CHANNEL> zones_channel;
std::vector<ROCCAT_KONE_AIMO_CHANNEL> leds_channel;
};
@@ -0,0 +1,112 @@
/*---------------------------------------------------------*\
| RoccatKoneAimoController.cpp |
| |
| Driver for Roccat Kone Aimo |
| |
| Thibaud M (enlight3d) 17 Nov 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "RoccatKoneAimoController.h"
#include "StringUtils.h"
RoccatKoneAimoController::RoccatKoneAimoController(hid_device* dev_handle, char *_path, std::string dev_name)
{
dev = dev_handle;
location = _path;
name = dev_name;
/*-----------------------------------------------------*\
| Init usb buffer to 0 and add first two bytes |
\*-----------------------------------------------------*/
memset(usb_colors_buf, 0x00, USB_COLOR_BUFF_LEN);
usb_colors_buf[0x00] = 0x0D;
usb_colors_buf[0x01] = 0x2E;
SendInit();
}
RoccatKoneAimoController::~RoccatKoneAimoController()
{
hid_close(dev);
}
std::string RoccatKoneAimoController::GetName()
{
return(name);
}
std::string RoccatKoneAimoController::GetSerial()
{
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));
}
std::string RoccatKoneAimoController::GetLocation()
{
return("HID: " + location);
}
void RoccatKoneAimoController::SendInit()
{
unsigned char usb_buf[6] = {00};
/*-----------------------------------------------------*\
| Read first a packet from mouse (swarm does it) |
\*-----------------------------------------------------*/
hid_get_feature_report(dev, usb_buf, 3);
/*-----------------------------------------------------*\
| Set up Init packet |
\*-----------------------------------------------------*/
usb_buf[0x00] = 0x0E;
usb_buf[0x01] = 0x06;
usb_buf[0x02] = 0x01;
usb_buf[0x03] = 0x01;
usb_buf[0x04] = 0x00;
usb_buf[0x05] = 0xFF;
/*-----------------------------------------------------*\
| Send packet |
\*-----------------------------------------------------*/
hid_send_feature_report(dev, usb_buf, 6);
}
void RoccatKoneAimoController::SetChannelColors(ROCCAT_KONE_AIMO_CHANNEL channel, RGBColor * colors, unsigned int num_colors)
{
/*---------------------------------------------------------*\
| Receiving update request for only one channel |
| and updating usb buffer to match colors |
\*---------------------------------------------------------*/
for(unsigned char i = 0; i < num_colors; i++)
{
std::size_t color = channel + i;
int usb_idx = (int)(0x02 + (color * 4));
usb_colors_buf[usb_idx + R_OFFSET] = RGBGetRValue(colors[i]);
usb_colors_buf[usb_idx + G_OFFSET] = RGBGetGValue(colors[i]);
usb_colors_buf[usb_idx + B_OFFSET] = RGBGetBValue(colors[i]);
}
}
void RoccatKoneAimoController::SendUpdate()
{
/*-----------------------------------------------------*\
| Send packet (whole buffer needs to be sent everytime) |
\*-----------------------------------------------------*/
hid_send_feature_report(dev, usb_colors_buf, 46);
/*-----------------------------------------------------*\
| Read a packet from mouse (swarm does it) |
\*-----------------------------------------------------*/
hid_get_feature_report(dev, usb_colors_buf, 3);
}
@@ -0,0 +1,59 @@
/*---------------------------------------------------------*\
| RoccatKoneAimoController.h |
| |
| Driver for Roccat Kone Aimo |
| |
| Thibaud M (enlight3d) 17 Nov 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <array>
#include <map>
#include <string>
#include <vector>
#include <hidapi.h>
#include "RGBController.h"
#define HID_MAX_STR 255
#define NUM_LEDS 11
#define R_OFFSET 0
#define G_OFFSET 1
#define B_OFFSET 2
#define USB_COLOR_BUFF_LEN 46
enum ROCCAT_KONE_AIMO_CHANNEL
{
SCROLL_WHEEL = 0,
STRIP_LEFT = 1,
STRIP_RIGHT = 5,
LOWER_LEFT = 9,
LOWER_RIGHT = 10
};
class RoccatKoneAimoController
{
public:
RoccatKoneAimoController(hid_device* dev_handle, char *_path, std::string dev_name);
~RoccatKoneAimoController();
std::string GetLocation();
std::string GetName();
std::string GetSerial();
void SetChannelColors(ROCCAT_KONE_AIMO_CHANNEL channel, RGBColor * colors, unsigned int num_colors);
void SendUpdate();
private:
std::string location;
std::string name;
hid_device* dev;
unsigned char usb_colors_buf[USB_COLOR_BUFF_LEN]; // USB buffer to be sent everytime we update mouse's LEDs
void SendInit();
};
@@ -0,0 +1,193 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKoneProAir.cpp |
| |
| RGBController for Roccat Kone Pro Air |
| |
| Plunti 10 Jun 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_RoccatKoneProAir.h"
/**------------------------------------------------------------------*\
@name Roccat Kone Pro Air Mouse
@category Mouse
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectRoccatKoneProAirControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_RoccatKoneProAir::RGBController_RoccatKoneProAir(RoccatKoneProAirController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetNameString();
vendor = "Roccat";
type = DEVICE_TYPE_MOUSE;
description = "Roccat Kone Pro Air Mouse Device";
serial = controller->GetSerialString();
location = controller->GetDeviceLocation();
mode Direct;
Direct.name = "Direct";
Direct.value = ROCCAT_KONE_PRO_AIR_DIRECT_MODE_VALUE;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mode Off;
Off.name = "Off";
Off.value = ROCCAT_KONE_PRO_AIR_OFF_MODE_VALUE;
Off.flags = MODE_FLAG_AUTOMATIC_SAVE;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
mode Static;
Static.name = "Static";
Static.value = ROCCAT_KONE_PRO_AIR_STATIC_MODE_VALUE;
Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Static.color_mode = MODE_COLORS_PER_LED;
Static.brightness = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
Static.brightness_min = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MIN;
Static.brightness_max = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
modes.push_back(Static);
mode RainbowWave;
RainbowWave.name = "Rainbow Wave";
RainbowWave.value = ROCCAT_KONE_PRO_AIR_RAINBOW_WAVE_MODE_VALUE;
RainbowWave.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
RainbowWave.color_mode = MODE_COLORS_NONE;
RainbowWave.brightness = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
RainbowWave.brightness_min = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MIN;
RainbowWave.brightness_max = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
RainbowWave.speed = ROCCAT_KONE_PRO_AIR_SPEED_MID;
RainbowWave.speed_min = ROCCAT_KONE_PRO_AIR_SPEED_MIN;
RainbowWave.speed_max = ROCCAT_KONE_PRO_AIR_SPEED_MAX;
modes.push_back(RainbowWave);
mode Heartbeat;
Heartbeat.name = "Heartbeat";
Heartbeat.value = ROCCAT_KONE_PRO_AIR_HEARTBEAT_MODE_VALUE;
Heartbeat.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Heartbeat.color_mode = MODE_COLORS_PER_LED;
Heartbeat.brightness = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
Heartbeat.brightness_min = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MIN;
Heartbeat.brightness_max = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
Heartbeat.speed = ROCCAT_KONE_PRO_AIR_SPEED_MID;
Heartbeat.speed_min = ROCCAT_KONE_PRO_AIR_SPEED_MIN;
Heartbeat.speed_max = ROCCAT_KONE_PRO_AIR_SPEED_MAX;
modes.push_back(Heartbeat);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = ROCCAT_KONE_PRO_AIR_BREATHING_MODE_VALUE;
Breathing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.brightness = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
Breathing.brightness_min = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MIN;
Breathing.brightness_max = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
Breathing.speed = ROCCAT_KONE_PRO_AIR_SPEED_MID;
Breathing.speed_min = ROCCAT_KONE_PRO_AIR_SPEED_MIN;
Breathing.speed_max = ROCCAT_KONE_PRO_AIR_SPEED_MAX;
modes.push_back(Breathing);
mode Flashing;
Flashing.name = "Flashing";
Flashing.value = ROCCAT_KONE_PRO_AIR_FLASHING_MODE_VALUE;
Flashing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Flashing.color_mode = MODE_COLORS_PER_LED;
Flashing.brightness = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
Flashing.brightness_min = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MIN;
Flashing.brightness_max = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX;
Flashing.speed = ROCCAT_KONE_PRO_AIR_SPEED_MID;
Flashing.speed_min = ROCCAT_KONE_PRO_AIR_SPEED_MIN;
Flashing.speed_max = ROCCAT_KONE_PRO_AIR_SPEED_MAX;
modes.push_back(Flashing);
mode Battery;
Battery.name = "Battery";
Battery.value = ROCCAT_KONE_PRO_AIR_BATTERY_MODE_VALUE;
Battery.flags = MODE_FLAG_AUTOMATIC_SAVE;
Battery.color_mode = MODE_COLORS_NONE;
modes.push_back(Battery);
SetupZones();
}
RGBController_RoccatKoneProAir::~RGBController_RoccatKoneProAir()
{
delete controller;
}
void RGBController_RoccatKoneProAir::SetupZones()
{
zone new_zone;
new_zone.name = "Mouse";
new_zone.type = ZONE_TYPE_LINEAR;
new_zone.leds_min = ROCCAT_KONE_PRO_AIR_LED_COUNT;
new_zone.leds_max = ROCCAT_KONE_PRO_AIR_LED_COUNT;
new_zone.leds_count = ROCCAT_KONE_PRO_AIR_LED_COUNT;
new_zone.matrix_map = NULL;
zones.push_back(new_zone);
std::string led_names[2] =
{
"Left Button",
"Right Button"
};
for(unsigned int i = 0; i < ROCCAT_KONE_PRO_AIR_LED_COUNT; i++)
{
led new_led;
new_led.name = led_names[i];
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_RoccatKoneProAir::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatKoneProAir::DeviceUpdateLEDs()
{
const mode& active = modes[active_mode];
if(active.value == ROCCAT_KONE_PRO_AIR_DIRECT_MODE_VALUE)
{
controller->SendDirect(colors);
}
else
{
controller->SetMode(colors, active.value, active.speed, active.brightness, active.flags);
}
}
void RGBController_RoccatKoneProAir::UpdateZoneLEDs(int /*zone_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatKoneProAir::UpdateSingleLED(int /*led_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatKoneProAir::DeviceUpdateMode()
{
const mode& active = modes[active_mode];
if(!(active.flags & MODE_FLAG_HAS_PER_LED_COLOR))
{
DeviceUpdateLEDs();
}
}
@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKoneProAir.h |
| |
| RGBController for Roccat Kone Pro Air |
| |
| Plunti 10 Jun 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatKoneProAirController.h"
class RGBController_RoccatKoneProAir : public RGBController
{
public:
RGBController_RoccatKoneProAir(RoccatKoneProAirController* controller_ptr);
~RGBController_RoccatKoneProAir();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatKoneProAirController* controller;
};
@@ -0,0 +1,119 @@
/*---------------------------------------------------------*\
| RoccatKoneProAirController.cpp |
| |
| Driver for Roccat Kone Pro Air |
| |
| Plunti 10 Jun 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "RoccatKoneProAirController.h"
#include "StringUtils.h"
RoccatKoneProAirController::RoccatKoneProAirController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
{
dev = dev_handle;
location = info.path;
name = dev_name;
}
RoccatKoneProAirController::~RoccatKoneProAirController()
{
hid_close(dev);
}
std::string RoccatKoneProAirController::GetDeviceLocation()
{
return("HID: " + location);
}
std::string RoccatKoneProAirController::GetNameString()
{
return(name);
}
std::string RoccatKoneProAirController::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 RoccatKoneProAirController::SendDirect(std::vector<RGBColor> colors)
{
SendRGB(true, colors, ROCCAT_KONE_PRO_AIR_DIRECT_MODE_VALUE, ROCCAT_KONE_PRO_AIR_SPEED_MAX, ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX);
}
void RoccatKoneProAirController::SetMode(std::vector<RGBColor> colors, unsigned char mode_value, unsigned char speed, unsigned char brightness, unsigned int mode_flags)
{
/*---------------------------------------------------------*\
| 1. Read settings |
\*---------------------------------------------------------*/
unsigned char active_settings[ROCCAT_KONE_PRO_AIR_SETTINGS_READ_PACKET_LENGTH];
unsigned char settings_request[] = {0x00, 0x90, 0x00, 0x04, 0x00, 0x18, 0x25, 0x51, 0x32};
hid_write(dev, settings_request, sizeof(settings_request));
do
{
hid_read(dev, active_settings, ROCCAT_KONE_PRO_AIR_SETTINGS_READ_PACKET_LENGTH);
} while( (active_settings[0] != 0x90) || (active_settings[2] != 0x26) );
/*---------------------------------------------------------*\
| 2. Send settings and select profile |
\*---------------------------------------------------------*/
unsigned char usb_buf[ROCCAT_KONE_PRO_AIR_SETTINGS_WRITE_PACKET_LENGTH];
memset(usb_buf, 0x00, ROCCAT_KONE_PRO_AIR_SETTINGS_WRITE_PACKET_LENGTH);
usb_buf[1] = 0x10;
usb_buf[2] = 0x50;
usb_buf[3] = 0x14;
memcpy(usb_buf + 5, active_settings + 10, 19);
usb_buf[24] = active_settings[41];
hid_write(dev, usb_buf, ROCCAT_KONE_PRO_AIR_SETTINGS_WRITE_PACKET_LENGTH);
/*---------------------------------------------------------*\
| 3. Send RGB |
\*---------------------------------------------------------*/
SendRGB(false,
colors,
mode_value,
(mode_flags & MODE_FLAG_HAS_SPEED ) ? speed : (unsigned char)ROCCAT_KONE_PRO_AIR_SPEED_MAX,
(mode_flags & MODE_FLAG_HAS_BRIGHTNESS) ? brightness : (unsigned char)ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX
);
}
void RoccatKoneProAirController::SendRGB(bool direct, std::vector<RGBColor> colors, unsigned char mode_value, unsigned char speed, unsigned char brightness)
{
unsigned char usb_buf[ROCCAT_KONE_PRO_AIR_RGB_PACKET_LENGTH];
memset(usb_buf, 0x00, ROCCAT_KONE_PRO_AIR_RGB_PACKET_LENGTH);
usb_buf[1] = 0x10;
usb_buf[2] = direct ? 0x10 : 0x50;
usb_buf[3] = 0x0B;
usb_buf[4] = direct ? 0x00 : 0x01;
usb_buf[5] = mode_value;
usb_buf[6] = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX; // Explicit brightness for first LED, not used by OpenRGB
usb_buf[7] = ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX; // Explicit brightness for second LED, not used by OpenRGB
usb_buf[8] = brightness;
usb_buf[9] = speed;
for(unsigned int i = 0; i < colors.size(); i++)
{
usb_buf[10 + 3 * i] = RGBGetRValue(colors[i]);
usb_buf[11 + 3 * i] = RGBGetGValue(colors[i]);
usb_buf[12 + 3 * i] = RGBGetBValue(colors[i]);
}
hid_write(dev, usb_buf, ROCCAT_KONE_PRO_AIR_RGB_PACKET_LENGTH);
}
@@ -0,0 +1,62 @@
/*---------------------------------------------------------*\
| RoccatKoneProAirController.h |
| |
| Driver for Roccat Kone Pro Air |
| |
| Plunti 10 Jun 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <hidapi.h>
#include "RGBController.h"
#define ROCCAT_KONE_PRO_AIR_RGB_PACKET_LENGTH 16
#define ROCCAT_KONE_PRO_AIR_SETTINGS_WRITE_PACKET_LENGTH 25
#define ROCCAT_KONE_PRO_AIR_SETTINGS_READ_PACKET_LENGTH 42
#define ROCCAT_KONE_PRO_AIR_LED_COUNT 2
enum
{
ROCCAT_KONE_PRO_AIR_DIRECT_MODE_VALUE = 0x09,
ROCCAT_KONE_PRO_AIR_OFF_MODE_VALUE = 0x00,
ROCCAT_KONE_PRO_AIR_STATIC_MODE_VALUE = 0x01,
ROCCAT_KONE_PRO_AIR_RAINBOW_WAVE_MODE_VALUE = 0x06,
ROCCAT_KONE_PRO_AIR_HEARTBEAT_MODE_VALUE = 0x05,
ROCCAT_KONE_PRO_AIR_BREATHING_MODE_VALUE = 0x02,
ROCCAT_KONE_PRO_AIR_FLASHING_MODE_VALUE = 0x08,
ROCCAT_KONE_PRO_AIR_BATTERY_MODE_VALUE = 0x0A
};
enum
{
ROCCAT_KONE_PRO_AIR_SPEED_MIN = 0x01,
ROCCAT_KONE_PRO_AIR_SPEED_MAX = 0x0B,
ROCCAT_KONE_PRO_AIR_SPEED_MID = (ROCCAT_KONE_PRO_AIR_SPEED_MAX - ROCCAT_KONE_PRO_AIR_SPEED_MIN) / 2,
ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MIN = 0x00,
ROCCAT_KONE_PRO_AIR_BRIGHTNESS_MAX = 0x64
};
class RoccatKoneProAirController
{
public:
RoccatKoneProAirController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
~RoccatKoneProAirController();
std::string GetDeviceLocation();
std::string GetNameString();
std::string GetSerialString();
void SendDirect(std::vector<RGBColor> colors);
void SetMode(std::vector<RGBColor> colors, unsigned char mode_value, unsigned char speed, unsigned char brightness, unsigned int mode_flags);
private:
hid_device* dev;
std::string location;
std::string name;
void SendRGB(bool direct, std::vector<RGBColor> colors, unsigned char mode_value, unsigned char speed, unsigned char brightness);
};
@@ -0,0 +1,188 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKonePro.cpp |
| |
| RGBController for Roccat Kone Pro |
| |
| Garrett Denham (GardenOfWyers) 12 Jan 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_RoccatKonePro.h"
/**------------------------------------------------------------------*\
@name Roccat Kone Pro Mouse
@category Mouse
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectRoccatKoneProControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_RoccatKonePro::RGBController_RoccatKonePro(RoccatKoneProController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetNameString();
vendor = "Roccat";
type = DEVICE_TYPE_MOUSE;
description = "Roccat Kone Pro Mouse Device";
serial = controller->GetSerialString();
location = controller->GetDeviceLocation();
// Also known as "Intelligent Lighting System" mode in Roccat Swarm
mode Direct;
Direct.name = "Direct";
Direct.value = ROCCAT_KONE_PRO_DIRECT_MODE_VALUE;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
// Also known as "Fully Lit" mode in Roccat Swarm
mode Static;
Static.name = "Static";
Static.value = ROCCAT_KONE_PRO_STATIC_MODE_VALUE;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.brightness = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Static.brightness_min = ROCCAT_KONE_PRO_BRIGHTNESS_MIN;
Static.brightness_max = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Static.colors.resize(ROCCAT_KONE_PRO_LED_COUNT);
modes.push_back(Static);
// Also known as "Wave" mode in Roccat Swarm
mode Rainbow;
Rainbow.name = "Rainbow";
Rainbow.value = ROCCAT_KONE_PRO_WAVE_MODE_VALUE;
Rainbow.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Rainbow.color_mode = MODE_COLORS_NONE;
Rainbow.brightness = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Rainbow.brightness_min = ROCCAT_KONE_PRO_BRIGHTNESS_MIN;
Rainbow.brightness_max = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Rainbow.speed = ROCCAT_KONE_PRO_SPEED_MID;
Rainbow.speed_min = ROCCAT_KONE_PRO_SPEED_MIN;
Rainbow.speed_max = ROCCAT_KONE_PRO_SPEED_MAX;
modes.push_back(Rainbow);
mode Heartbeat;
Heartbeat.name = "Heartbeat";
Heartbeat.value = ROCCAT_KONE_PRO_HEARTBEAT_MODE_VALUE;
Heartbeat.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Heartbeat.color_mode = MODE_COLORS_MODE_SPECIFIC;
Heartbeat.brightness = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Heartbeat.brightness_min = ROCCAT_KONE_PRO_BRIGHTNESS_MIN;
Heartbeat.brightness_max = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Heartbeat.speed = ROCCAT_KONE_PRO_SPEED_MID;
Heartbeat.speed_min = ROCCAT_KONE_PRO_SPEED_MIN;
Heartbeat.speed_max = ROCCAT_KONE_PRO_SPEED_MAX;
Heartbeat.colors.resize(ROCCAT_KONE_PRO_LED_COUNT);
modes.push_back(Heartbeat);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = ROCCAT_KONE_PRO_BREATHING_MODE_VALUE;
Breathing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.brightness = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Breathing.brightness_min = ROCCAT_KONE_PRO_BRIGHTNESS_MIN;
Breathing.brightness_max = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Breathing.speed = ROCCAT_KONE_PRO_SPEED_MID;
Breathing.speed_min = ROCCAT_KONE_PRO_SPEED_MIN;
Breathing.speed_max = ROCCAT_KONE_PRO_SPEED_MAX;
Breathing.colors.resize(ROCCAT_KONE_PRO_LED_COUNT);
modes.push_back(Breathing);
mode Blinking;
Blinking.name = "Blinking";
Blinking.value = ROCCAT_KONE_PRO_BLINKING_MODE_VALUE;
Blinking.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Blinking.color_mode = MODE_COLORS_MODE_SPECIFIC;
Blinking.brightness = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Blinking.brightness_min = ROCCAT_KONE_PRO_BRIGHTNESS_MIN;
Blinking.brightness_max = ROCCAT_KONE_PRO_BRIGHTNESS_MAX;
Blinking.speed = ROCCAT_KONE_PRO_SPEED_MID;
Blinking.speed_min = ROCCAT_KONE_PRO_SPEED_MIN;
Blinking.speed_max = ROCCAT_KONE_PRO_SPEED_MAX;
Blinking.colors.resize(ROCCAT_KONE_PRO_LED_COUNT);
modes.push_back(Blinking);
SetupZones();
}
RGBController_RoccatKonePro::~RGBController_RoccatKonePro()
{
delete controller;
}
void RGBController_RoccatKonePro::SetupZones()
{
zone new_zone;
new_zone.name = "Mouse";
new_zone.type = ZONE_TYPE_LINEAR;
new_zone.leds_min = ROCCAT_KONE_PRO_LED_COUNT;
new_zone.leds_max = ROCCAT_KONE_PRO_LED_COUNT;
new_zone.leds_count = ROCCAT_KONE_PRO_LED_COUNT;
new_zone.matrix_map = NULL;
zones.push_back(new_zone);
std::string led_names[2] =
{
"Left Button",
"Right Button"
};
for(unsigned int i = 0; i < ROCCAT_KONE_PRO_LED_COUNT; i++)
{
led new_led;
new_led.name = led_names[i];
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_RoccatKonePro::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatKonePro::DeviceUpdateLEDs()
{
const mode& active = modes[active_mode];
if(active.value == ROCCAT_KONE_PRO_DIRECT_MODE_VALUE)
{
controller->SendDirect(colors);
}
else
{
controller->SetMode(active.colors, active.value, active.speed, active.brightness, active.color_mode, active.flags);
}
}
void RGBController_RoccatKonePro::UpdateZoneLEDs(int /*zone_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatKonePro::UpdateSingleLED(int /*led_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatKonePro::DeviceUpdateMode()
{
if(modes[active_mode].value == ROCCAT_KONE_PRO_DIRECT_MODE_VALUE)
{
controller->SetupDirectMode();
}
else
{
DeviceUpdateLEDs();
}
}
@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKonePro.h |
| |
| RGBController for Roccat Kone Pro |
| |
| Garrett Denham (GardenOfWyers) 12 Jan 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatKoneProController.h"
class RGBController_RoccatKonePro : public RGBController
{
public:
RGBController_RoccatKonePro(RoccatKoneProController* controller_ptr);
~RGBController_RoccatKonePro();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatKoneProController* controller;
};
@@ -0,0 +1,169 @@
/*---------------------------------------------------------*\
| RoccatKoneProController.cpp |
| |
| Driver for Roccat Kone Pro |
| |
| Garrett Denham (GardenOfWyers) 12 Jan 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "RoccatKoneProController.h"
#include "StringUtils.h"
RoccatKoneProController::RoccatKoneProController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
{
dev = dev_handle;
location = info.path;
name = dev_name;
SetupDirectMode();
}
RoccatKoneProController::~RoccatKoneProController()
{
hid_close(dev);
}
std::string RoccatKoneProController::GetDeviceLocation()
{
return("HID: " + location);
}
std::string RoccatKoneProController::GetNameString()
{
return(name);
}
std::string RoccatKoneProController::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 RoccatKoneProController::SetupDirectMode()
{
SwitchControl(true);
}
void RoccatKoneProController::SwitchControl(bool direct)
{
unsigned char usb_buf[ROCCAT_KONE_PRO_CONTROL_MODE_PACKET_LENGTH];
usb_buf[0x00] = 0x0E;
usb_buf[0x01] = 0x06;
usb_buf[0x02] = 0x01;
usb_buf[0x03] = direct ? 0x01 : 0x00;
usb_buf[0x04] = 0x00;
usb_buf[0x05] = 0xFF;
hid_send_feature_report(dev, usb_buf, ROCCAT_KONE_PRO_CONTROL_MODE_PACKET_LENGTH);
}
void RoccatKoneProController::SendDirect(std::vector<RGBColor> colors)
{
unsigned char usb_buf[ROCCAT_KONE_PRO_DIRECT_MODE_PACKET_LENGTH];
memset(usb_buf, 0x00, ROCCAT_KONE_PRO_DIRECT_MODE_PACKET_LENGTH);
usb_buf[0x00] = ROCCAT_KONE_PRO_DIRECT_MODE_REPORT_ID;
usb_buf[0x01] = ROCCAT_KONE_PRO_DIRECT_MODE_BYTE;
for(unsigned int i = 0; i < colors.size(); i++)
{
usb_buf[0x02 + 3 * i] = RGBGetRValue(colors[i]);
usb_buf[0x03 + 3 * i] = RGBGetGValue(colors[i]);
usb_buf[0x04 + 3 * i] = RGBGetBValue(colors[i]);
}
hid_send_feature_report(dev, usb_buf, ROCCAT_KONE_PRO_DIRECT_MODE_PACKET_LENGTH);
}
void RoccatKoneProController::SetMode(std::vector<RGBColor> colors, unsigned char mode_value, unsigned char speed, unsigned char brightness, unsigned int color_mode, unsigned int mode_flags)
{
/*---------------------------------------------------------*\
| 1. Read from flash |
\*---------------------------------------------------------*/
unsigned char usb_buf[ROCCAT_KONE_PRO_FLASH_PACKET_LENGTH];
memset(usb_buf, 0x00, ROCCAT_KONE_PRO_FLASH_PACKET_LENGTH);
hid_get_feature_report(dev, usb_buf, ROCCAT_KONE_PRO_FLASH_PACKET_LENGTH);
/*---------------------------------------------------------*\
| 2. Update needed bytes |
\*---------------------------------------------------------*/
usb_buf[0x00] = 0x06;
usb_buf[0x01] = 0x45;
usb_buf[0x03] = 0x06;
usb_buf[0x04] = 0x06;
usb_buf[0x05] = 0x1F;
usb_buf[0x1E] = mode_value;
usb_buf[0x1F] = mode_flags & MODE_FLAG_HAS_SPEED ? speed : 0xFF;
usb_buf[0x20] = brightness;
if(color_mode & MODE_COLORS_MODE_SPECIFIC)
{
for(unsigned int i = 0; i < colors.size(); i++)
{
usb_buf[0x24 + 5 * i] = 0x14;
usb_buf[0x25 + 5 * i] = 0xFF;
usb_buf[0x26 + 5 * i] = RGBGetRValue(colors[i]);
usb_buf[0x27 + 5 * i] = RGBGetGValue(colors[i]);
usb_buf[0x28 + 5 * i] = RGBGetBValue(colors[i]);
}
}
else if(color_mode & MODE_COLORS_NONE)
{
for(unsigned int i = 0; i < colors.size(); i++)
{
usb_buf[0x24 + 5 * i] = 0x14;
usb_buf[0x25 + 5 * i] = 0x00;
usb_buf[0x26 + 5 * i] = 0x00;
usb_buf[0x27 + 5 * i] = 0x00;
usb_buf[0x28 + 5 * i] = 0x00;
}
}
usb_buf[0x2E] = 0x14;
usb_buf[0x2F] = 0xFF;
unsigned int crc = CalculateCRC(&usb_buf[0x00]);
usb_buf[0x43] = (unsigned char) crc;
usb_buf[0x44] = crc >> 8;
/*---------------------------------------------------------*\
| 3. Send to flash |
\*---------------------------------------------------------*/
hid_send_feature_report(dev, usb_buf, ROCCAT_KONE_PRO_FLASH_PACKET_LENGTH);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
/*---------------------------------------------------------*\
| 4. Switch to built-in mode |
\*---------------------------------------------------------*/
SwitchControl(false);
}
unsigned int RoccatKoneProController::CalculateCRC(unsigned char* bytes)
{
unsigned int crc = 0;
for(unsigned int i = 0; i < ROCCAT_KONE_PRO_FLASH_PACKET_LENGTH - 2; i++)
{
crc += bytes[i];
}
return crc;
}
@@ -0,0 +1,70 @@
/*---------------------------------------------------------*\
| RoccatKoneProController.h |
| |
| Driver for Roccat Kone Pro |
| |
| Garrett Denham (GardenOfWyers) 12 Jan 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <hidapi.h>
#include "RGBController.h"
#define ROCCAT_KONE_PRO_CONTROL_MODE_PACKET_LENGTH 6
#define ROCCAT_KONE_PRO_DIRECT_MODE_PACKET_LENGTH 11
#define ROCCAT_KONE_PRO_FLASH_PACKET_LENGTH 69
#define ROCCAT_KONE_PRO_FLASH_REPORT_ID 0x06
#define ROCCAT_KONE_PRO_DIRECT_MODE_REPORT_ID 0x0D
#define ROCCAT_KONE_PRO_DIRECT_MODE_BYTE 0x0B
#define ROCCAT_KONE_PRO_LED_COUNT 2
enum
{
ROCCAT_KONE_PRO_DIRECT_MODE_VALUE = 0x00,
ROCCAT_KONE_PRO_STATIC_MODE_VALUE = 0x01,
ROCCAT_KONE_PRO_WAVE_MODE_VALUE = 0x0A,
ROCCAT_KONE_PRO_HEARTBEAT_MODE_VALUE = 0x04,
ROCCAT_KONE_PRO_BREATHING_MODE_VALUE = 0x03,
ROCCAT_KONE_PRO_BLINKING_MODE_VALUE = 0x02
};
enum
{
ROCCAT_KONE_PRO_SPEED_MIN = 0x01,
ROCCAT_KONE_PRO_SPEED_MAX = 0x0B,
ROCCAT_KONE_PRO_SPEED_MID = (ROCCAT_KONE_PRO_SPEED_MAX - ROCCAT_KONE_PRO_SPEED_MIN) / 2,
ROCCAT_KONE_PRO_BRIGHTNESS_MIN = 0x00,
ROCCAT_KONE_PRO_BRIGHTNESS_MAX = 0xFF
};
class RoccatKoneProController
{
public:
RoccatKoneProController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
~RoccatKoneProController();
std::string GetDeviceLocation();
std::string GetNameString();
std::string GetSerialString();
void SetupDirectMode();
void SendDirect(std::vector<RGBColor> colors);
void SetMode(std::vector<RGBColor> colors,
unsigned char mode_value,
unsigned char speed,
unsigned char brightness,
unsigned int color_mode,
unsigned int mode_flags
);
private:
hid_device* dev;
std::string location;
std::string name;
unsigned int CalculateCRC(unsigned char* bytes);
void SwitchControl(bool direct);
};
@@ -0,0 +1,285 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKoneXP.cpp |
| |
| RGBController for Roccat Kone XP |
| |
| Mola19 12 Jun 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_RoccatKoneXP.h"
/**------------------------------------------------------------------*\
@name Roccat Kone XP Mouse
@category Mouse
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectRoccatKoneXPControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_RoccatKoneXP::RGBController_RoccatKoneXP(RoccatKoneXPController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetName();
vendor = "Roccat";
type = DEVICE_TYPE_MOUSE;
description = "Roccat Kone XP Mouse Device";
version = controller->GetVersion();
location = controller->GetLocation();
serial = controller->GetSerial();
mode Direct;
Direct.name = "Direct";
Direct.value = ROCCAT_KONE_XP_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mode Off;
Off.name = "Off";
Off.value = ROCCAT_KONE_XP_MODE_OFF;
Off.flags = MODE_FLAG_AUTOMATIC_SAVE;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
mode Static;
Static.name = "Static";
Static.value = ROCCAT_KONE_XP_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Static.color_mode = MODE_COLORS_PER_LED;
Static.brightness = ROCCAT_KONE_XP_BRIGHTNESS_DEFAULT;
Static.brightness_min = ROCCAT_KONE_XP_BRIGHTNESS_MIN;
Static.brightness_max = ROCCAT_KONE_XP_BRIGHTNESS_MAX;
modes.push_back(Static);
mode Rainbow;
Rainbow.name = "Rainbow";
Rainbow.value = ROCCAT_KONE_XP_MODE_WAVE;
Rainbow.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Rainbow.color_mode = MODE_COLORS_NONE;
Rainbow.brightness = ROCCAT_KONE_XP_BRIGHTNESS_DEFAULT;
Rainbow.brightness_min = ROCCAT_KONE_XP_BRIGHTNESS_MIN;
Rainbow.brightness_max = ROCCAT_KONE_XP_BRIGHTNESS_MAX;
Rainbow.speed = ROCCAT_KONE_XP_SPEED_DEFAULT;
Rainbow.speed_min = ROCCAT_KONE_XP_SPEED_MIN;
Rainbow.speed_max = ROCCAT_KONE_XP_SPEED_MAX;
modes.push_back(Rainbow);
mode Blinking;
Blinking.name = "Blinking";
Blinking.value = ROCCAT_KONE_XP_MODE_BLINKING;
Blinking.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Blinking.color_mode = MODE_COLORS_PER_LED;
Blinking.brightness = ROCCAT_KONE_XP_BRIGHTNESS_DEFAULT;
Blinking.brightness_min = ROCCAT_KONE_XP_BRIGHTNESS_MIN;
Blinking.brightness_max = ROCCAT_KONE_XP_BRIGHTNESS_MAX;
Blinking.speed = ROCCAT_KONE_XP_SPEED_DEFAULT;
Blinking.speed_min = ROCCAT_KONE_XP_SPEED_MIN;
Blinking.speed_max = ROCCAT_KONE_XP_SPEED_MAX;
modes.push_back(Blinking);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = ROCCAT_KONE_XP_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.brightness = ROCCAT_KONE_XP_BRIGHTNESS_DEFAULT;
Breathing.brightness_min = ROCCAT_KONE_XP_BRIGHTNESS_MIN;
Breathing.brightness_max = ROCCAT_KONE_XP_BRIGHTNESS_MAX;
Breathing.speed = ROCCAT_KONE_XP_SPEED_DEFAULT;
Breathing.speed_min = ROCCAT_KONE_XP_SPEED_MIN;
Breathing.speed_max = ROCCAT_KONE_XP_SPEED_MAX;
modes.push_back(Breathing);
mode Heartbeat;
Heartbeat.name = "Heartbeat";
Heartbeat.value = ROCCAT_KONE_XP_MODE_HEARTBEAT;
Heartbeat.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Heartbeat.color_mode = MODE_COLORS_PER_LED;
Heartbeat.brightness = ROCCAT_KONE_XP_BRIGHTNESS_DEFAULT;
Heartbeat.brightness_min = ROCCAT_KONE_XP_BRIGHTNESS_MIN;
Heartbeat.brightness_max = ROCCAT_KONE_XP_BRIGHTNESS_MAX;
Heartbeat.speed = ROCCAT_KONE_XP_SPEED_DEFAULT;
Heartbeat.speed_min = ROCCAT_KONE_XP_SPEED_MIN;
Heartbeat.speed_max = ROCCAT_KONE_XP_SPEED_MAX;
modes.push_back(Heartbeat);
mode Photon;
Photon.name = "Photon FX";
Photon.value = ROCCAT_KONE_XP_MODE_PHOTON_FX;
Photon.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Photon.color_mode = MODE_COLORS_NONE;
Photon.brightness = ROCCAT_KONE_XP_BRIGHTNESS_DEFAULT;
Photon.brightness_min = ROCCAT_KONE_XP_BRIGHTNESS_MIN;
Photon.brightness_max = ROCCAT_KONE_XP_BRIGHTNESS_MAX;
modes.push_back(Photon);
/*---------------------------------------------------------------------*\
| This is the default mode for software modes, while swarm isn't active |
\*---------------------------------------------------------------------*/
mode Default;
Default.name = "Default";
Default.value = ROCCAT_KONE_XP_MODE_DEFAULT;
Default.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Default.color_mode = MODE_COLORS_NONE;
Default.brightness = ROCCAT_KONE_XP_BRIGHTNESS_DEFAULT;
Default.brightness_min = ROCCAT_KONE_XP_BRIGHTNESS_MIN;
Default.brightness_max = ROCCAT_KONE_XP_BRIGHTNESS_MAX;
modes.push_back(Default);
SetupZones();
uint8_t active_profile = controller->GetActiveProfile();
controller->SetReadProfile(active_profile);
controller->WaitUntilReady();
roccat_kone_xp_mode_struct active = controller->GetMode();
for(uint32_t i = 0; i < modes.size(); i++)
{
if(modes[i].value == active.mode)
{
active_mode = i;
break;
}
/*----------------------------------------------*\
| If no mode was found, select 0th mode (direct) |
\*----------------------------------------------*/
if(i == modes.size() - 1)
{
active_mode = 0;
}
}
modes[active_mode].speed = active.speed;
modes[active_mode].brightness = active.brightness;
for(uint8_t i = 0; i < 20; i++)
{
colors[i] = active.colors[i].color;
}
}
RGBController_RoccatKoneXP::~RGBController_RoccatKoneXP()
{
delete controller;
}
void RGBController_RoccatKoneXP::SetupZones()
{
zone left;
left.name = "Left";
left.type = ZONE_TYPE_LINEAR;
left.leds_min = 9;
left.leds_max = 9;
left.leds_count = 9;
left.matrix_map = NULL;
zones.push_back(left);
for (uint8_t i = 1; i <= 9; i++) {
led left_led;
left_led.name = "Left LED " + std::to_string(i);
leds.push_back(left_led);
}
zone right;
right.name = "Right";
right.type = ZONE_TYPE_LINEAR;
right.leds_min = 9;
right.leds_max = 9;
right.leds_count = 9;
right.matrix_map = NULL;
zones.push_back(right);
for (uint8_t i = 1; i <= 9; i++) {
led left_led;
left_led.name = "Right LED " + std::to_string(i);
leds.push_back(left_led);
}
zone wheel;
wheel.name = "Scrollwheel";
wheel.type = ZONE_TYPE_SINGLE;
wheel.leds_min = 1;
wheel.leds_max = 1;
wheel.leds_count = 1;
wheel.matrix_map = NULL;
zones.push_back(wheel);
led wheel_led;
wheel_led.name = "Scrollwheel LED";
leds.push_back(wheel_led);
zone dpi;
dpi.name = "DPI button";
dpi.type = ZONE_TYPE_SINGLE;
dpi.leds_min = 1;
dpi.leds_max = 1;
dpi.leds_count = 1;
dpi.matrix_map = NULL;
zones.push_back(dpi);
led dpi_led;
dpi_led.name = "DPI button LED";
leds.push_back(dpi_led);
SetupColors();
}
void RGBController_RoccatKoneXP::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatKoneXP::DeviceUpdateLEDs()
{
if(modes[active_mode].value == ROCCAT_KONE_XP_MODE_DIRECT)
{
controller->SendDirect(colors);
}
else
{
DeviceUpdateMode();
}
}
void RGBController_RoccatKoneXP::UpdateZoneLEDs(int /*zone_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatKoneXP::UpdateSingleLED(int /*led_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatKoneXP::DeviceUpdateMode()
{
mode selected = modes[active_mode];
roccat_kone_xp_mode_struct active = controller->GetMode();
active.mode = selected.value;
active.speed = selected.speed;
active.brightness = (modes[active_mode].value == ROCCAT_KONE_XP_MODE_DIRECT) ? 0xFF : selected.brightness;
for(uint8_t i = 0; i < 20; i++)
{
active.colors[i].color = colors[i];
}
controller->SetMode(active);
controller->WaitUntilReady();
controller->EnableDirect(selected.value == ROCCAT_KONE_XP_MODE_DIRECT);
controller->WaitUntilReady();
}
@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKoneXP.h |
| |
| RGBController for Roccat Kone XP |
| |
| Mola19 12 Jun 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatKoneXPController.h"
class RGBController_RoccatKoneXP : public RGBController
{
public:
RGBController_RoccatKoneXP(RoccatKoneXPController* controller_ptr);
~RGBController_RoccatKoneXP();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatKoneXPController* controller;
};
@@ -0,0 +1,308 @@
/*---------------------------------------------------------*\
| RoccatKoneXPController.cpp |
| |
| Driver for Roccat Kone XP |
| |
| Mola19 12 Jun 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <chrono>
#include <cstring>
#include <thread>
#include "LogManager.h"
#include "RoccatKoneXPController.h"
#include "StringUtils.h"
RoccatKoneXPController::RoccatKoneXPController(hid_device* dev_handle, char *path, std::string dev_name)
{
dev = dev_handle;
location = path;
name = dev_name;
}
RoccatKoneXPController::~RoccatKoneXPController()
{
hid_close(dev);
}
std::string RoccatKoneXPController::GetLocation()
{
return("HID: " + location);
}
std::string RoccatKoneXPController::GetName()
{
return(name);
}
std::string RoccatKoneXPController::GetSerial()
{
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));
}
std::string RoccatKoneXPController::GetVersion()
{
uint8_t buf[9] = { 0x09 };
int return_length = hid_get_feature_report(dev, buf, 9);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Kone XP]: Could not fetch version. HIDAPI Error: %ls", hid_error(dev));
return std::string("Unknown");
}
char version[5];
snprintf(version, 5, "%d.%02d", buf[2] / 100, buf[2] % 100);
return std::string(version);
}
uint8_t RoccatKoneXPController::GetActiveProfile()
{
uint8_t buf[4] = { 0x05 };
int return_length = hid_get_feature_report(dev, buf, 4);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Kone XP]: Could not fetch active profile. HIDAPI Error: %ls", hid_error(dev));
return 0;
}
return buf[2];
}
#include <iostream>
roccat_kone_xp_mode_struct RoccatKoneXPController::GetMode()
{
uint8_t buf[0xAE] = { 0x06 };
int return_length = hid_get_feature_report(dev, buf, 0xAE);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Kone XP]: Could not fetch mode. HIDAPI Error: %ls", hid_error(dev));
roccat_kone_xp_mode_struct default_mode;
return default_mode;
}
roccat_kone_xp_mode_struct active_mode;
active_mode.profile = buf[2];
active_mode.byte_3 = buf[3];
active_mode.byte_4 = buf[4];
active_mode.dpi_flag = buf[5];
active_mode.byte_6 = buf[6];
for(uint8_t i = 0; i < 10; i++)
{
active_mode.dpi[i] = (buf[8 + i * 2] << 8) + buf[7 + i * 2];
}
active_mode.angle_snapping = (bool) buf[27];
active_mode.byte_28 = buf[28];
active_mode.polling_rate = buf[29];
active_mode.mode = buf[30];
active_mode.speed = buf[31];
active_mode.brightness = buf[32];
active_mode.time_until_idle = buf[33];
active_mode.idle_mode = buf[34];
active_mode.byte_35 = buf[35];
for(uint8_t i = 0; i < 20; i++)
{
active_mode.colors[i].brightness = buf[37 + i * 6];
active_mode.colors[i].color = ToRGBColor(
buf[38 + i * 6],
buf[39 + i * 6],
buf[40 + i * 6]
);
}
active_mode.byte_156 = buf[156];
active_mode.byte_157 = buf[157];
active_mode.profile_color_brightness = buf[158];
active_mode.profile_color_red = buf[159];
active_mode.profile_color_green = buf[160];
active_mode.profile_color_blue = buf[161];
active_mode.byte_162 = buf[162];
active_mode.theme = buf[163];
active_mode.auto_dpi_flag = buf[164];
active_mode.end_bytes[0] = buf[165];
active_mode.end_bytes[1] = buf[166];
active_mode.end_bytes[2] = buf[167];
active_mode.end_bytes[3] = buf[168];
active_mode.end_bytes[4] = buf[169];
active_mode.end_bytes[5] = buf[170];
active_mode.end_bytes[6] = buf[171];
return active_mode;
}
void RoccatKoneXPController::EnableDirect(bool on_off_switch)
{
unsigned char usb_buf[6];
usb_buf[0x00] = 0x0E;
usb_buf[0x01] = 0x06;
usb_buf[0x02] = 0x01;
usb_buf[0x03] = on_off_switch;
usb_buf[0x04] = 0x00;
usb_buf[0x05] = 0xFF;
int return_length = hid_send_feature_report(dev, usb_buf, 6);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Kone XP]: Could not send mode. HIDAPI Error: %ls", hid_error(dev));
}
}
void RoccatKoneXPController::SetReadProfile(uint8_t profile)
{
unsigned char usb_buf[4];
usb_buf[0x00] = 0x04;
usb_buf[0x01] = profile;
usb_buf[0x02] = 0x80;
usb_buf[0x03] = 0xFF;
int return_length = hid_send_feature_report(dev, usb_buf, 4);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Kone XP]: Could not set profile to read. HIDAPI Error: %ls", hid_error(dev));
}
}
void RoccatKoneXPController::SetMode(roccat_kone_xp_mode_struct mode)
{
uint8_t buf[0xAE];
memset(buf, 0x00, 0xAE);
buf[0x00] = 0x06;
buf[0x01] = 0xAE;
buf[0x02] = mode.profile;
buf[0x03] = mode.byte_3;
buf[0x04] = mode.byte_4;
buf[0x05] = mode.dpi_flag;
buf[0x06] = mode.byte_6;
for(uint8_t i = 0; i < 10; i++)
{
buf[0x07 + i * 2] = mode.dpi[i] & 0xFF;
buf[0x08 + i * 2] = mode.dpi[i] >> 8;
}
buf[0x1B] = mode.angle_snapping;
buf[0x1C] = mode.byte_28;
buf[0x1D] = mode.polling_rate;
buf[0x1E] = mode.mode;
buf[0x1F] = mode.speed;
buf[0x20] = mode.brightness;
buf[0x21] = mode.time_until_idle;
buf[0x22] = mode.idle_mode;
buf[0x23] = mode.byte_35;
for(uint8_t i = 0; i < 20; i++)
{
buf[0x24 + i * 6] = mode.colors[i].byte_0;
buf[0x25 + i * 6] = 0xFF;
buf[0x26 + i * 6] = RGBGetRValue(mode.colors[i].color);
buf[0x27 + i * 6] = RGBGetGValue(mode.colors[i].color);
buf[0x28 + i * 6] = RGBGetBValue(mode.colors[i].color);
buf[0x29 + i * 6] = mode.colors[i].byte_5;
}
buf[0x9C] = mode.byte_156;
buf[0x9D] = mode.byte_157;
buf[0x9E] = mode.profile_color_brightness;
buf[0x9F] = mode.profile_color_red;
buf[0xA0] = mode.profile_color_green;
buf[0xA1] = mode.profile_color_blue;
buf[0xA2] = mode.byte_162;
buf[0xA3] = mode.theme & ~0x80; // this stores the swarm intern selected theme (biggest bit is a flag for custom theme)
buf[0xA4] = mode.auto_dpi_flag;
for(uint8_t i = 0; i < 7; i++)
{
buf[0xA5 + i] = mode.end_bytes[i];
}
unsigned short total = 0;
for(int i = 0; i < 0xAE - 2; i++) total += buf[i];
buf[0xAE - 2] = total & 0xFF;
buf[0xAE - 1] = total >> 8;
int return_length = hid_send_feature_report(dev, buf, 0xAE);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Kone XP]: Could not send mode. HIDAPI Error: %ls", hid_error(dev));
}
}
void RoccatKoneXPController::SendDirect(std::vector<RGBColor> colors)
{
uint8_t buf[0x7A];
memset(buf, 0x00, 0x7A);
buf[0x00] = 0x0D;
buf[0x01] = 0x7A;
for(uint8_t i = 0; i < colors.size() && i < 20; i++)
{
/*-----------------------------------------------------------*\
| This device uses rgbrgb which means that e.g. the red value |
| is calculated by multiplying both given red values. |
| Maybe it is some sort of brightness? |
| For OpenRGBs purpose these aren't usefull, |
| so the second part is always 0xff. |
\*-----------------------------------------------------------*/
buf[0x02 + i * 6] = RGBGetRValue(colors[i]);
buf[0x03 + i * 6] = RGBGetGValue(colors[i]);
buf[0x04 + i * 6] = RGBGetBValue(colors[i]);
buf[0x05 + i * 6] = 0xFF;
buf[0x06 + i * 6] = 0xFF;
buf[0x07 + i * 6] = 0xFF;
}
int return_length = hid_send_feature_report(dev, buf, 0x7A);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Kone XP]: Could not send direct. HIDAPI Error: %ls", hid_error(dev));
}
}
void RoccatKoneXPController::WaitUntilReady()
{
uint8_t buf[4];
memset(buf, 0x00, 4);
buf[0] = 0x04;
for(unsigned char i = 0; buf[1] != 1 && i < 100; i++)
{
if(i != 0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
hid_get_feature_report(dev, buf, 4);
}
}
@@ -0,0 +1,103 @@
/*---------------------------------------------------------*\
| RoccatKoneXPController.h |
| |
| Driver for Roccat Kone XP |
| |
| Mola19 12 Jun 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <hidapi.h>
#include "RGBController.h"
enum
{
ROCCAT_KONE_XP_MODE_DIRECT = 0x0B,
ROCCAT_KONE_XP_MODE_OFF = 0x00,
ROCCAT_KONE_XP_MODE_STATIC = 0x01,
ROCCAT_KONE_XP_MODE_BLINKING = 0x02,
ROCCAT_KONE_XP_MODE_BREATHING = 0x03,
ROCCAT_KONE_XP_MODE_HEARTBEAT = 0x04,
ROCCAT_KONE_XP_MODE_PHOTON_FX = 0x05,
ROCCAT_KONE_XP_MODE_DEFAULT = 0x09,
ROCCAT_KONE_XP_MODE_WAVE = 0x0A
};
enum
{
ROCCAT_KONE_XP_SPEED_MIN = 0x0B,
ROCCAT_KONE_XP_SPEED_MAX = 0x01,
ROCCAT_KONE_XP_SPEED_DEFAULT = 0x06,
ROCCAT_KONE_XP_BRIGHTNESS_MIN = 0x00,
ROCCAT_KONE_XP_BRIGHTNESS_MAX = 0xFF,
ROCCAT_KONE_XP_BRIGHTNESS_DEFAULT = 0xFF
};
struct roccat_kone_xp_color_struct
{
uint8_t byte_0 = 0x14;
uint8_t brightness = 0xFF;
RGBColor color = 0;
uint8_t byte_5 = 0x64;
};
struct roccat_kone_xp_mode_struct
{
uint8_t profile = 0;
uint8_t byte_3 = 0x06;
uint8_t byte_4 = 0x06;
uint8_t dpi_flag = 0x1F;
uint8_t byte_6 = 0x01;
uint16_t dpi[10] = { 0x08, 0x10, 0x18, 0x20, 0x40, 0x08, 0x10, 0x18, 0x20, 0x40 };
bool angle_snapping = false;
uint8_t byte_28 = 0x00;
uint8_t polling_rate = 0x03;
uint8_t mode = ROCCAT_KONE_XP_MODE_STATIC;
uint8_t speed = 0x00;
uint8_t brightness = 0xFF;
uint8_t time_until_idle = 0x0F;
uint8_t idle_mode = 0x00;
uint8_t byte_35 = 0x00;
roccat_kone_xp_color_struct colors[20];
uint8_t byte_156 = 0x01;
uint8_t byte_157 = 0x64;
uint8_t profile_color_brightness = 0xFF;
uint8_t profile_color_red = 0xFF;
uint8_t profile_color_green = 0x00;
uint8_t profile_color_blue = 0x00;
uint8_t byte_162 = 0x00;
uint8_t theme = 0x80;
uint8_t auto_dpi_flag = 0x00;
uint8_t end_bytes[7] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
};
class RoccatKoneXPController
{
public:
RoccatKoneXPController(hid_device* dev_handle, char *path, std::string dev_name);
~RoccatKoneXPController();
std::string GetLocation();
std::string GetName();
std::string GetSerial();
std::string GetVersion();
uint8_t GetActiveProfile();
roccat_kone_xp_mode_struct GetMode();
void EnableDirect(bool on_off_switch);
void SetReadProfile(uint8_t profile);
void SendDirect(std::vector<RGBColor> colors);
void SetMode(roccat_kone_xp_mode_struct mode);
void WaitUntilReady();
private:
hid_device* dev;
std::string location;
std::string name;
};
@@ -0,0 +1,147 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKova.cpp |
| |
| RGBController for Roccat Kova |
| |
| Gustash 01 Dec 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_RoccatKova.h"
/**------------------------------------------------------------------*\
@name Roccat Kova
@category Mouse
@type USB
@save :robot:
@direct :x:
@effects :white_check_mark:
@detectors RoccatControllerDetect
@comment Color Flow mode is only supported starting at the first
preset color in the mouse's memory, and color offsets for each LED
are not supported. You'd need to use Swarm if you intend to use that
specific feature.
\*-------------------------------------------------------------------*/
RGBController_RoccatKova::RGBController_RoccatKova(RoccatKovaController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetName();
vendor = "Roccat";
type = DEVICE_TYPE_MOUSE;
description = "Roccat Kova Mouse Device";
serial = controller->GetSerial();
location = controller->GetLocation();
version = controller->GetVersion();
mode Static;
Static.name = "Static";
Static.value = ROCCAT_KOVA_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE;
Static.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Static);
mode ColorFlow;
ColorFlow.name = "Color Flow";
ColorFlow.value = ROCCAT_KOVA_MODE_COLOR_FLOW;
ColorFlow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
ColorFlow.color_mode = MODE_COLORS_RANDOM;
ColorFlow.speed_min = ROCCAT_KOVA_SPEED_MIN;
ColorFlow.speed_max = ROCCAT_KOVA_SPEED_MAX;
modes.push_back(ColorFlow);
mode Flashing;
Flashing.name = "Flashing";
Flashing.value = ROCCAT_KOVA_MODE_FLASHING;
Flashing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Flashing.color_mode = MODE_COLORS_PER_LED;
Flashing.speed_min = ROCCAT_KOVA_SPEED_MIN;
Flashing.speed_max = ROCCAT_KOVA_SPEED_MAX;
modes.push_back(Flashing);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = ROCCAT_KOVA_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.speed_min = ROCCAT_KOVA_SPEED_MIN;
Breathing.speed_max = ROCCAT_KOVA_SPEED_MAX;
modes.push_back(Breathing);
mode Off;
Off.name = "Off";
Off.value = 0x00;
Off.flags = MODE_FLAG_AUTOMATIC_SAVE;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
SetupZones();
}
RGBController_RoccatKova::~RGBController_RoccatKova()
{
delete controller;
}
void RGBController_RoccatKova::SetupZones()
{
zone Mouse;
Mouse.name = "Mouse";
Mouse.type = ZONE_TYPE_LINEAR;
Mouse.leds_count = ROCCAT_KOVA_LED_COUNT;
Mouse.leds_min = ROCCAT_KOVA_LED_COUNT;
Mouse.leds_max = ROCCAT_KOVA_LED_COUNT;
Mouse.matrix_map = NULL;
zones.push_back(Mouse);
led WheelLED;
WheelLED.name = "Wheel LED";
WheelLED.value = ROCCAT_KOVA_WHEEL_IDX;
leds.push_back(WheelLED);
led StripeLED;
StripeLED.name = "Stripe LED";
StripeLED.value = ROCCAT_KOVA_PIPE_IDX;
leds.push_back(StripeLED);
SetupColors();
}
void RGBController_RoccatKova::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatKova::DeviceUpdateLEDs()
{
DeviceUpdateMode();
}
void RGBController_RoccatKova::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateMode();
}
void RGBController_RoccatKova::UpdateSingleLED(int /*led*/)
{
DeviceUpdateMode();
}
void RGBController_RoccatKova::DeviceUpdateMode()
{
mode &active = modes[active_mode];
int mode = active.value;
bool is_color_flow = active.color_mode == MODE_COLORS_RANDOM;
if(active.value == ROCCAT_KOVA_MODE_COLOR_FLOW)
{
mode = ROCCAT_KOVA_MODE_STATIC;
is_color_flow = true;
}
controller->SetColor(colors[0], colors[1], mode, active.speed, is_color_flow);
}
@@ -0,0 +1,35 @@
/*---------------------------------------------------------*\
| RGBController_RoccatKova.h |
| |
| RGBController for Roccat Kova |
| |
| Gustash 01 Dec 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatKovaController.h"
class RGBController_RoccatKova : public RGBController
{
public:
RGBController_RoccatKova(RoccatKovaController *controller_ptr);
~RGBController_RoccatKova();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatKovaController *controller;
};
@@ -0,0 +1,147 @@
/*---------------------------------------------------------*\
| RoccatKovaController.cpp |
| |
| Driver for Roccat Kova |
| |
| Gustash 01 Dec 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <hidapi.h>
#include "LogManager.h"
#include "RoccatKovaController.h"
#include "StringUtils.h"
RoccatKovaController::RoccatKovaController(hid_device* dev_handle, char *path, std::string dev_name)
{
dev = dev_handle;
location = path;
name = dev_name;
SendInitialPacket();
FetchFirmwareVersion();
}
RoccatKovaController::~RoccatKovaController()
{
hid_close(dev);
}
std::string RoccatKovaController::GetLocation()
{
return("HID: " + location);
}
std::string RoccatKovaController::GetName()
{
return(name);
}
std::string RoccatKovaController::GetSerial()
{
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));
}
std::string RoccatKovaController::GetVersion()
{
return(version);
}
void RoccatKovaController::SetColor(RGBColor color_wheel,
RGBColor color_stripe,
uint8_t mode,
uint8_t speed,
bool color_flow)
{
bool is_off = mode == ROCCAT_KOVA_MODE_OFF;
uint8_t report_buf[ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE] {00};
FetchProfileData(report_buf);
report_buf[0x0] = ROCCAT_KOVA_PROFILE_REPORT_ID;
report_buf[0x1] = ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE;
report_buf[ROCCAT_KOVA_FLAGS_IDX] |= ROCCAT_KOVA_USE_CUSTOM_COLORS_MASK;
if(is_off)
{
report_buf[ROCCAT_KOVA_FLAGS_IDX] &= ~ROCCAT_KOVA_LIGHTS_ON_MASK;
}
else
{
report_buf[ROCCAT_KOVA_FLAGS_IDX] |= ROCCAT_KOVA_LIGHTS_ON_MASK;
}
/*-------------------------------------------------*\
| Set colors for each LED and reset the selected |
| preset color to ensure consistency |
\*-------------------------------------------------*/
report_buf[ROCCAT_KOVA_WHEEL_IDX] = 0x0;
report_buf[ROCCAT_KOVA_WHEEL_IDX + ROCCAT_KOVA_R_OFFSET] = RGBGetRValue(color_wheel);
report_buf[ROCCAT_KOVA_WHEEL_IDX + ROCCAT_KOVA_G_OFFSET] = RGBGetGValue(color_wheel);
report_buf[ROCCAT_KOVA_WHEEL_IDX + ROCCAT_KOVA_B_OFFSET] = RGBGetBValue(color_wheel);
report_buf[ROCCAT_KOVA_PIPE_IDX] = 0x0;
report_buf[ROCCAT_KOVA_PIPE_IDX + ROCCAT_KOVA_R_OFFSET] = RGBGetRValue(color_stripe);
report_buf[ROCCAT_KOVA_PIPE_IDX + ROCCAT_KOVA_G_OFFSET] = RGBGetGValue(color_stripe);
report_buf[ROCCAT_KOVA_PIPE_IDX + ROCCAT_KOVA_B_OFFSET] = RGBGetBValue(color_stripe);
report_buf[ROCCAT_KOVA_COLOR_FLOW_IDX] = color_flow;
if(!is_off)
{
report_buf[ROCCAT_KOVA_MODE_IDX] = mode;
}
report_buf[ROCCAT_KOVA_EFFECT_SPEED_IDX] = speed;
uint16_t checksum = GenerateChecksum(report_buf, sizeof(report_buf) - 2);
report_buf[ROCCAT_KOVA_CHECKSUM_IDX] = checksum & 0xFF;
report_buf[ROCCAT_KOVA_CHECKSUM_IDX + 1] = checksum >> 8;
hid_send_feature_report(dev, report_buf, ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE);
}
void RoccatKovaController::SendInitialPacket()
{
uint8_t buf[ROCCAT_KOVA_INIT_WRITE_PACKET_SIZE] {00};
buf[0x00] = ROCCAT_KOVA_INIT_REPORT_ID;
buf[0x01] = 0x00;
buf[0x02] = 0x80;
hid_send_feature_report(dev, buf, ROCCAT_KOVA_INIT_WRITE_PACKET_SIZE);
}
void RoccatKovaController::FetchFirmwareVersion()
{
uint8_t buf[ROCCAT_KOVA_VERSION_READ_PACKET_SIZE] {00};
buf[0x0] = ROCCAT_KOVA_VERSION_REPORT_ID;
hid_get_feature_report(dev, buf, ROCCAT_KOVA_VERSION_READ_PACKET_SIZE);
uint8_t fw_version = buf[ROCCAT_KOVA_FIRMWARE_VERSION_IDX];
char version_str[5] {00};
snprintf(version_str, 5, "%.2f", fw_version / 100.);
version = version_str;
}
void RoccatKovaController::FetchProfileData(uint8_t *buf)
{
buf[0x00] = ROCCAT_KOVA_PROFILE_REPORT_ID;
hid_get_feature_report(dev, buf, ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE);
}
uint16_t RoccatKovaController::GenerateChecksum(uint8_t *buf, size_t length)
{
uint16_t checksum = 0x0;
for (uint8_t idx = 0; idx < length; idx++)
{
checksum += buf[idx];
}
return checksum;
}
@@ -0,0 +1,93 @@
/*---------------------------------------------------------*\
| RoccatKovaController.h |
| |
| Driver for Roccat Kova |
| |
| Gustash 01 Dec 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <hidapi.h>
#include "RGBController.h"
#define ROCCAT_KOVA_HID_MAX_STR 255
#define ROCCAT_KOVA_LED_COUNT 2
#define ROCCAT_KOVA_SPEED_MIN 1
#define ROCCAT_KOVA_SPEED_MAX 3
#define ROCCAT_KOVA_INIT_REPORT_ID 4
#define ROCCAT_KOVA_INIT_WRITE_PACKET_SIZE 3
#define ROCCAT_KOVA_PROFILE_REPORT_ID 6
#define ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE 28
#define ROCCAT_KOVA_VERSION_REPORT_ID 9
#define ROCCAT_KOVA_VERSION_READ_PACKET_SIZE 8
/*#define NUM_OF_DPI_SWITCHES 5*/
enum
{
ROCCAT_KOVA_FIRMWARE_VERSION_IDX = 2,
/*ROCCAT_KOVA_SELECTED_PROFILE_IDX = 2,*/
/*ROCCAT_KOVA_UNKNOWN_3_IDX = 3,*/
/*ROCCAT_KOVA_UNKNOWN_4_IDX = 4,*/
/*ROCCAT_KOVA_ORIENTATION_IDX = 5,*/
/*ROCCAT_KOVA_DPI_SWITCHER_IDX = 6,*/
/*ROCCAT_KOVA_DPI_SPEED_IDX = 7,*/
/*ROCCAT_KOVA_SELECTED_DPI_IDX = 12,*/
/*ROCCAT_KOVA_POLLING_RATE_IDX = 13,*/
ROCCAT_KOVA_FLAGS_IDX = 14,
ROCCAT_KOVA_COLOR_FLOW_IDX = 15,
ROCCAT_KOVA_MODE_IDX = 16,
ROCCAT_KOVA_EFFECT_SPEED_IDX = 17,
ROCCAT_KOVA_PIPE_IDX = 18,
ROCCAT_KOVA_WHEEL_IDX = 22,
ROCCAT_KOVA_CHECKSUM_IDX = 26,
};
#define ROCCAT_KOVA_R_OFFSET 1
#define ROCCAT_KOVA_G_OFFSET 2
#define ROCCAT_KOVA_B_OFFSET 3
#define ROCCAT_KOVA_USE_CUSTOM_COLORS_MASK 0b00110000
#define ROCCAT_KOVA_LIGHTS_ON_MASK 0b00000011
enum
{
ROCCAT_KOVA_MODE_OFF = 0x00,
ROCCAT_KOVA_MODE_STATIC = 0x01,
ROCCAT_KOVA_MODE_FLASHING = 0x02,
ROCCAT_KOVA_MODE_BREATHING = 0x03,
ROCCAT_KOVA_MODE_COLOR_FLOW = 0xFF,
};
class RoccatKovaController
{
public:
RoccatKovaController(hid_device* dev_handle, char *path, std::string dev_name);
~RoccatKovaController();
std::string GetLocation();
std::string GetName();
std::string GetSerial();
std::string GetVersion();
void SetColor(RGBColor color_wheel,
RGBColor color_stripe,
uint8_t mode,
uint8_t speed,
bool color_flow);
private:
hid_device* dev;
std::string location;
std::string name;
std::string version;
void SendInitialPacket();
void FetchProfileData(uint8_t *buf);
void FetchFirmwareVersion();
uint16_t GenerateChecksum(uint8_t *buf, size_t length);
};
@@ -0,0 +1,196 @@
/*---------------------------------------------------------*\
| RGBController_RoccatSenseAimo.cpp |
| |
| RGBController for Roccat Sense Aimo |
| |
| Mola19 09 Aug 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_RoccatSenseAimo.h"
/**------------------------------------------------------------------*\
@name Roccat Sense Aimo Mousepad
@category Mousemat
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectRoccatSenseAimoControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_RoccatSenseAimo::RGBController_RoccatSenseAimo(RoccatSenseAimoController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetName();
vendor = "Roccat";
type = DEVICE_TYPE_MOUSEMAT;
description = "Roccat Sense Aimo Mousepad Device";
version = controller->GetVersion();
location = controller->GetLocation();
serial = controller->GetSerial();
mode Direct;
Direct.name = "Direct";
Direct.value = ROCCAT_SENSE_AIMO_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mode Static;
Static.name = "Static";
Static.value = ROCCAT_SENSE_AIMO_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Static.color_mode = MODE_COLORS_PER_LED;
Static.brightness = ROCCAT_SENSE_AIMO_BRIGHTNESS_DEFAULT;
Static.brightness_min = ROCCAT_SENSE_AIMO_BRIGHTNESS_MIN;
Static.brightness_max = ROCCAT_SENSE_AIMO_BRIGHTNESS_MAX;
modes.push_back(Static);
mode Rainbow;
Rainbow.name = "Rainbow";
Rainbow.value = ROCCAT_SENSE_AIMO_MODE_WAVE;
Rainbow.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Rainbow.color_mode = MODE_COLORS_NONE;
Rainbow.brightness = ROCCAT_SENSE_AIMO_BRIGHTNESS_DEFAULT;
Rainbow.brightness_min = ROCCAT_SENSE_AIMO_BRIGHTNESS_MIN;
Rainbow.brightness_max = ROCCAT_SENSE_AIMO_BRIGHTNESS_MAX;
Rainbow.speed = ROCCAT_SENSE_AIMO_SPEED_DEFAULT;
Rainbow.speed_min = ROCCAT_SENSE_AIMO_SPEED_MIN;
Rainbow.speed_max = ROCCAT_SENSE_AIMO_SPEED_MAX;
modes.push_back(Rainbow);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = ROCCAT_SENSE_AIMO_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.brightness = ROCCAT_SENSE_AIMO_BRIGHTNESS_DEFAULT;
Breathing.brightness_min = ROCCAT_SENSE_AIMO_BRIGHTNESS_MIN;
Breathing.brightness_max = ROCCAT_SENSE_AIMO_BRIGHTNESS_MAX;
Breathing.speed = ROCCAT_SENSE_AIMO_SPEED_DEFAULT;
Breathing.speed_min = ROCCAT_SENSE_AIMO_SPEED_MIN;
Breathing.speed_max = ROCCAT_SENSE_AIMO_SPEED_MAX;
modes.push_back(Breathing);
mode Heartbeat;
Heartbeat.name = "Heartbeat";
Heartbeat.value = ROCCAT_SENSE_AIMO_MODE_HEARTBEAT;
Heartbeat.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
Heartbeat.color_mode = MODE_COLORS_PER_LED;
Heartbeat.brightness = ROCCAT_SENSE_AIMO_BRIGHTNESS_DEFAULT;
Heartbeat.brightness_min = ROCCAT_SENSE_AIMO_BRIGHTNESS_MIN;
Heartbeat.brightness_max = ROCCAT_SENSE_AIMO_BRIGHTNESS_MAX;
Heartbeat.speed = ROCCAT_SENSE_AIMO_SPEED_DEFAULT;
Heartbeat.speed_min = ROCCAT_SENSE_AIMO_SPEED_MIN;
Heartbeat.speed_max = ROCCAT_SENSE_AIMO_SPEED_MAX;
modes.push_back(Heartbeat);
/*---------------------------------------------------------------------*\
| This is the default mode for software modes, while swarm isn't active |
\*---------------------------------------------------------------------*/
mode Default;
Default.name = "Default";
Default.value = ROCCAT_SENSE_AIMO_MODE_DEFAULT;
Default.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Default.color_mode = MODE_COLORS_NONE;
Default.brightness = ROCCAT_SENSE_AIMO_BRIGHTNESS_DEFAULT;
Default.brightness_min = ROCCAT_SENSE_AIMO_BRIGHTNESS_MIN;
Default.brightness_max = ROCCAT_SENSE_AIMO_BRIGHTNESS_MAX;
modes.push_back(Default);
SetupZones();
mode_struct active = controller->GetMode();
for(uint32_t i = 0; i < modes.size(); i++)
{
if(modes[i].value == active.mode)
{
active_mode = i;
break;
}
/*----------------------------------------------*\
| If no mode was found, select 0th mode (direct) |
\*----------------------------------------------*/
if(i == modes.size() - 1)
{
active_mode = 0;
}
}
modes[active_mode].speed = active.speed;
modes[active_mode].brightness = active.brightness;
colors[0] = active.left;
colors[1] = active.right;
}
RGBController_RoccatSenseAimo::~RGBController_RoccatSenseAimo()
{
delete controller;
}
void RGBController_RoccatSenseAimo::SetupZones()
{
zone pad;
pad.name = "Mousepad";
pad.type = ZONE_TYPE_LINEAR;
pad.leds_min = 2;
pad.leds_max = 2;
pad.leds_count = 2;
pad.matrix_map = NULL;
zones.push_back(pad);
led left_led;
left_led.name = "Mousepad left led";
leds.push_back(left_led);
led right_led;
right_led.name = "Mousepad right led";
leds.push_back(right_led);
SetupColors();
}
void RGBController_RoccatSenseAimo::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatSenseAimo::DeviceUpdateLEDs()
{
if(modes[active_mode].value == ROCCAT_SENSE_AIMO_MODE_DIRECT)
{
controller->SendDirect(colors);
}
else
{
DeviceUpdateMode();
}
}
void RGBController_RoccatSenseAimo::UpdateZoneLEDs(int /*zone_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatSenseAimo::UpdateSingleLED(int /*led_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatSenseAimo::DeviceUpdateMode()
{
mode selected = modes[active_mode];
mode_struct active = controller->GetMode();
controller->SetMode(active.profile, selected.value, selected.speed, selected.brightness, colors);
}
@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| RGBController_RoccatSenseAimo.h |
| |
| RGBController for Roccat Sense Aimo |
| |
| Mola19 09 Aug 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatSenseAimoController.h"
class RGBController_RoccatSenseAimo : public RGBController
{
public:
RGBController_RoccatSenseAimo(RoccatSenseAimoController* controller_ptr);
~RGBController_RoccatSenseAimo();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatSenseAimoController* controller;
};
@@ -0,0 +1,152 @@
/*---------------------------------------------------------*\
| RoccatSenseAimoController.cpp |
| |
| Driver for Roccat Sense Aimo |
| |
| Mola19 09 Aug 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "LogManager.h"
#include "RoccatSenseAimoController.h"
#include "StringUtils.h"
RoccatSenseAimoController::RoccatSenseAimoController(hid_device* dev_handle, char *path, std::string dev_name)
{
dev = dev_handle;
location = path;
name = dev_name;
}
RoccatSenseAimoController::~RoccatSenseAimoController()
{
hid_close(dev);
}
std::string RoccatSenseAimoController::GetLocation()
{
return("HID: " + location);
}
std::string RoccatSenseAimoController::GetName()
{
return(name);
}
std::string RoccatSenseAimoController::GetSerial()
{
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));
}
std::string RoccatSenseAimoController::GetVersion()
{
uint8_t buf[8] = { 0x01 };
int return_length = hid_get_feature_report(dev, buf, 5);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Sense Aimo]: Could not fetch mode. HIDAPI Error: %ls", hid_error(dev));
return std::string("Unknown");
}
char version[6];
snprintf(version, 6, "%2X.%02X", buf[1], buf[2]);
return std::string(version);
}
mode_struct RoccatSenseAimoController::GetMode()
{
uint8_t buf[19] = { 0x02 };
int return_length = hid_get_feature_report(dev, buf, 19);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Sense Aimo]: Could not fetch mode. HIDAPI Error: %ls", hid_error(dev));
mode_struct default_mode;
default_mode.profile = 0;
default_mode.mode = ROCCAT_SENSE_AIMO_MODE_STATIC;
default_mode.speed = 0;
default_mode.brightness = ROCCAT_SENSE_AIMO_BRIGHTNESS_DEFAULT;
default_mode.left = ToRGBColor(0, 0, 0);
default_mode.right = ToRGBColor(0, 0, 0);
return default_mode;
}
mode_struct active_mode;
active_mode.profile = buf[1];
active_mode.mode = buf[2];
active_mode.speed = buf[3];
active_mode.brightness = buf[4];
active_mode.left = ToRGBColor(buf[6], buf[7], buf[8]);
active_mode.right = ToRGBColor(buf[14], buf[15], buf[16]);
return active_mode;
}
void RoccatSenseAimoController::SetMode(uint8_t profile, uint8_t mode, uint8_t speed, uint8_t brightness, std::vector<RGBColor> colors)
{
uint8_t buf[19];
memset(buf, 0x00, 19);
buf[0x00] = 0x02;
buf[0x01] = profile;
for(uint8_t i = 0; i < 2; i++)
{
buf[0x02 + i * 8] = mode; // this device has per led modes
buf[0x03 + i * 8] = speed;
buf[0x04 + i * 8] = brightness;
buf[0x05 + i * 8] = 0x00;
buf[0x06 + i * 8] = RGBGetRValue(colors[i]);
buf[0x07 + i * 8] = RGBGetGValue(colors[i]);
buf[0x08 + i * 8] = RGBGetBValue(colors[i]);
buf[0x09 + i * 8] = 0xFF; // this device uses RGBA, but OpenRGB doesn't allow it, so it is always max
}
buf[0x12] = 0x00; // this stores the swarm theme and first bit is a flag if custom is active in swarm. No usage outside Swarm
int return_length = hid_send_feature_report(dev, buf, 19);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Sense Aimo]: Could not send mode. HIDAPI Error: %ls", hid_error(dev));
}
}
void RoccatSenseAimoController::SendDirect(std::vector<RGBColor> colors)
{
uint8_t buf[9];
memset(buf, 0x00, 9);
buf[0x00] = 0x03;
for(uint8_t i = 0; i < 2; i++)
{
buf[0x01 + i * 4] = RGBGetRValue(colors[i]);
buf[0x02 + i * 4] = RGBGetGValue(colors[i]);
buf[0x03 + i * 4] = RGBGetBValue(colors[i]);
buf[0x04 + i * 4] = 0xFF; // this device uses RGBA, but OpenRGB doesn't allow it, so it is always max
}
int return_length = hid_send_feature_report(dev, buf, 9);
if(return_length == -1)
{
LOG_DEBUG("[Roccat Sense Aimo]: Could not send direct. HIDAPI Error: %ls", hid_error(dev));
}
}
@@ -0,0 +1,67 @@
/*---------------------------------------------------------*\
| RoccatSenseAimoController.h |
| |
| Driver for Roccat Sense Aimo |
| |
| Mola19 09 Aug 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <hidapi.h>
#include "RGBController.h"
enum
{
ROCCAT_SENSE_AIMO_MODE_DIRECT = 0x0B,
ROCCAT_SENSE_AIMO_MODE_STATIC = 0x01,
ROCCAT_SENSE_AIMO_MODE_BREATHING = 0x03,
ROCCAT_SENSE_AIMO_MODE_HEARTBEAT = 0x04,
ROCCAT_SENSE_AIMO_MODE_DEFAULT = 0x09,
ROCCAT_SENSE_AIMO_MODE_WAVE = 0x0A
};
enum
{
ROCCAT_SENSE_AIMO_SPEED_MIN = 0xFF,
ROCCAT_SENSE_AIMO_SPEED_MAX = 0x00,
ROCCAT_SENSE_AIMO_SPEED_DEFAULT = 0x07,
ROCCAT_SENSE_AIMO_BRIGHTNESS_MIN = 0x00,
ROCCAT_SENSE_AIMO_BRIGHTNESS_MAX = 0xFF,
ROCCAT_SENSE_AIMO_BRIGHTNESS_DEFAULT = 0xFF
};
struct mode_struct
{
uint8_t profile;
uint8_t mode;
uint8_t speed;
uint8_t brightness;
RGBColor left;
RGBColor right;
};
class RoccatSenseAimoController
{
public:
RoccatSenseAimoController(hid_device* dev_handle, char *path, std::string dev_name);
~RoccatSenseAimoController();
std::string GetLocation();
std::string GetName();
std::string GetSerial();
std::string GetVersion();
mode_struct GetMode();
void SendDirect(std::vector<RGBColor> colors);
void SetMode(uint8_t profile, uint8_t mode, uint8_t speed, uint8_t brightness, std::vector<RGBColor> colors);
private:
hid_device* dev;
std::string location;
std::string name;
};
@@ -0,0 +1,319 @@
/*---------------------------------------------------------*\
| RGBController_RoccatVulcanKeyboard.cpp |
| |
| RGBController for Roccat Vulcan keyboard |
| |
| Mola19 17 Dec 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <vector>
#include "RGBControllerKeyNames.h"
#include "RGBController_RoccatVulcanKeyboard.h"
#define NA 0xFFFFFFFF
/**------------------------------------------------------------------*\
@name Roccat Vulcan Keyboard
@category Keyboard
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectRoccatVulcanKeyboardControllers
@comment The mode "Default" differs from device to device and
and sometimes also based on which profile you are on.
Often it is very close to the rainbow mode.
\*-------------------------------------------------------------------*/
RGBController_RoccatVulcanKeyboard::RGBController_RoccatVulcanKeyboard(RoccatVulcanKeyboardController* controller_ptr)
{
controller = controller_ptr;
pid = controller->device_pid;
controller->InitDeviceInfo();
name = controller->GetName();
vendor = "Roccat";
type = DEVICE_TYPE_KEYBOARD;
description = "Roccat Vulcan Keyboard Device";
version = controller->GetDeviceInfo().version;
location = controller->GetLocation();
serial = controller->GetSerial();
mode Direct;
Direct.name = "Direct";
Direct.value = ROCCAT_VULCAN_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
if(pid != ROCCAT_VULCAN_120_AIMO_PID && pid != ROCCAT_VULCAN_100_AIMO_PID)
{
Direct.flags |= MODE_FLAG_HAS_BRIGHTNESS;
Direct.brightness_min = ROCCAT_VULCAN_BRIGHTNESS_MIN;
Direct.brightness_max = ROCCAT_VULCAN_BRIGHTNESS_MAX;
Direct.brightness = ROCCAT_VULCAN_BRIGHTNESS_DEFAULT;
}
modes.push_back(Direct);
mode Static;
Static.name = "Static";
Static.value = ROCCAT_VULCAN_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE;
Static.brightness_min = ROCCAT_VULCAN_BRIGHTNESS_MIN;
Static.brightness_max = ROCCAT_VULCAN_BRIGHTNESS_MAX;
Static.brightness = ROCCAT_VULCAN_BRIGHTNESS_DEFAULT;
Static.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Static);
mode Wave;
Wave.name = "Rainbow Wave";
Wave.value = ROCCAT_VULCAN_MODE_WAVE;
Wave.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE;
Wave.speed_min = ROCCAT_VULCAN_SPEED_MIN;
Wave.speed_max = ROCCAT_VULCAN_SPEED_MAX;
Wave.speed = ROCCAT_VULCAN_SPEED_DEFAULT;
Wave.brightness_min = ROCCAT_VULCAN_BRIGHTNESS_MIN;
Wave.brightness_max = ROCCAT_VULCAN_BRIGHTNESS_MAX;
Wave.brightness = ROCCAT_VULCAN_BRIGHTNESS_DEFAULT;
Wave.color_mode = MODE_COLORS_NONE;
modes.push_back(Wave);
mode Default;
Default.name = "Default";
Default.value = ROCCAT_VULCAN_MODE_DEFAULT;
Default.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE;
Default.brightness_min = ROCCAT_VULCAN_BRIGHTNESS_MIN;
Default.brightness_max = ROCCAT_VULCAN_BRIGHTNESS_MAX;
Default.brightness = ROCCAT_VULCAN_BRIGHTNESS_DEFAULT;
Default.color_mode = MODE_COLORS_NONE;
modes.push_back(Default);
SetupZones();
}
RGBController_RoccatVulcanKeyboard::~RGBController_RoccatVulcanKeyboard()
{
delete controller;
}
void RGBController_RoccatVulcanKeyboard::SetupZones()
{
std::map<int,layout_info> * keyboard_ptr;
switch(pid)
{
case ROCCAT_VULCAN_100_AIMO_PID:
case ROCCAT_VULCAN_120_AIMO_PID:
keyboard_ptr = &RoccatVulcan120AimoLayouts;
break;
case ROCCAT_VULCAN_TKL_PID:
case ROCCAT_VULCAN_TKL_PRO_PID:
case TURTLE_BEACH_VULCAN_II_TKL_PID:
keyboard_ptr = &RoccatVulcanTKLLayouts;
break;
case TURTLE_BEACH_VULCAN_II_TKL_PRO_PID:
keyboard_ptr = &TurtleBeachVulcanIITKLProLayouts;
break;
case ROCCAT_VULCAN_PRO_PID:
case ROCCAT_PYRO_PID:
keyboard_ptr = &RoccatPyroLayouts;
break;
case ROCCAT_VULCAN_II_PID:
case TURTLE_BEACH_VULCAN_II_PID:
keyboard_ptr = &RoccatVulcanIILayouts;
break;
case ROCCAT_VULCAN_II_MAX_PID:
keyboard_ptr = &RoccatVulcanIIMaxLayouts;
break;
case ROCCAT_MAGMA_PID:
case ROCCAT_MAGMA_MINI_PID:
keyboard_ptr = &RoccatMagmaLayouts;
break;
default:
keyboard_ptr = &RoccatVulcan120AimoLayouts;
}
std::map<int,layout_info> & keyboard = *keyboard_ptr;
unsigned char layout;
switch(controller->GetDeviceInfo().layout_type)
{
case ROCCAT_VULCAN_LAYOUT_DE:
case ROCCAT_VULCAN_LAYOUT_UK:
case ROCCAT_VULCAN_LAYOUT_FR:
layout = ROCCAT_VULCAN_LAYOUT_UK;
break;
case ROCCAT_VULCAN_LAYOUT_US:
default:
layout = ROCCAT_VULCAN_LAYOUT_US;
}
/*---------------------------------------------------------*\
| Determine zone sizes |
| Vulcan II MAX has 108 keyboard keys + 24 secondary LEDs |
| (physically under parent keys) + 16 palm rest LEDs. |
| Secondary LEDs are split into labeled linear zones. |
\*---------------------------------------------------------*/
int keyboard_size = keyboard[layout].size;
if(pid == ROCCAT_VULCAN_II_MAX_PID)
{
keyboard_size = 108;
}
zone keyboard_zone;
keyboard_zone.name = "Keyboard";
keyboard_zone.type = ZONE_TYPE_MATRIX;
keyboard_zone.leds_min = keyboard_size;
keyboard_zone.leds_max = keyboard_size;
keyboard_zone.leds_count = keyboard_size;
keyboard_zone.matrix_map = new matrix_map_type;
keyboard_zone.matrix_map->height = keyboard[layout].rows;
keyboard_zone.matrix_map->width = keyboard[layout].cols;
keyboard_zone.matrix_map->map = keyboard[layout].matrix_map;
zones.push_back(keyboard_zone);
if(pid == ROCCAT_VULCAN_II_MAX_PID)
{
zone fkey_ind_zone;
fkey_ind_zone.name = "F-Key Indicators";
fkey_ind_zone.type = ZONE_TYPE_LINEAR;
fkey_ind_zone.leds_min = 15;
fkey_ind_zone.leds_max = 15;
fkey_ind_zone.leds_count = 15;
fkey_ind_zone.matrix_map = NULL;
zones.push_back(fkey_ind_zone);
zone nav1_zone;
nav1_zone.name = "Nav Cluster Indicators";
nav1_zone.type = ZONE_TYPE_LINEAR;
nav1_zone.leds_min = 3;
nav1_zone.leds_max = 3;
nav1_zone.leds_count = 3;
nav1_zone.matrix_map = NULL;
zones.push_back(nav1_zone);
zone numlock_zone;
numlock_zone.name = "Num Lock Indicator";
numlock_zone.type = ZONE_TYPE_LINEAR;
numlock_zone.leds_min = 1;
numlock_zone.leds_max = 1;
numlock_zone.leds_count = 1;
numlock_zone.matrix_map = NULL;
zones.push_back(numlock_zone);
zone nav2_zone;
nav2_zone.name = "Nav Cluster Indicators 2";
nav2_zone.type = ZONE_TYPE_LINEAR;
nav2_zone.leds_min = 3;
nav2_zone.leds_max = 3;
nav2_zone.leds_count = 3;
nav2_zone.matrix_map = NULL;
zones.push_back(nav2_zone);
zone caps_zone;
caps_zone.name = "Caps Lock Indicator";
caps_zone.type = ZONE_TYPE_LINEAR;
caps_zone.leds_min = 1;
caps_zone.leds_max = 1;
caps_zone.leds_count = 1;
caps_zone.matrix_map = NULL;
zones.push_back(caps_zone);
zone win_zone;
win_zone.name = "Win Key Indicator";
win_zone.type = ZONE_TYPE_LINEAR;
win_zone.leds_min = 1;
win_zone.leds_max = 1;
win_zone.leds_count = 1;
win_zone.matrix_map = NULL;
zones.push_back(win_zone);
zone palmrest_zone;
palmrest_zone.name = "Palm Rest";
palmrest_zone.type = ZONE_TYPE_LINEAR;
palmrest_zone.leds_min = 16;
palmrest_zone.leds_max = 16;
palmrest_zone.leds_count = 16;
palmrest_zone.matrix_map = NULL;
zones.push_back(palmrest_zone);
}
for(int led_id = 0; led_id < keyboard[layout].size; led_id++)
{
led new_led;
new_led.name = keyboard[layout].led_names[led_id].name;
new_led.value = keyboard[layout].led_names[led_id].id;
leds.push_back(new_led);
}
SetupColors();
/*---------------------------------------------------------*\
| sends the init packet for the default mode (direct) |
\*---------------------------------------------------------*/
DeviceUpdateMode();
DeviceUpdateLEDs();
}
void RGBController_RoccatVulcanKeyboard::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatVulcanKeyboard::DeviceUpdateLEDs()
{
if(modes[active_mode].value == ROCCAT_VULCAN_MODE_DIRECT)
{
std::vector<led_color> led_color_list = {};
for(unsigned int i = 0; i < colors.size(); i++)
{
led_color_list.push_back({ leds[i].value, colors[i] });
}
controller->SendColors(led_color_list);
}
else
{
DeviceUpdateMode();
}
}
void RGBController_RoccatVulcanKeyboard::UpdateZoneLEDs(int /*zone_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatVulcanKeyboard::UpdateSingleLED(int /*led_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_RoccatVulcanKeyboard::DeviceUpdateMode()
{
std::vector<led_color> led_color_list = {};
if(modes[active_mode].value == ROCCAT_VULCAN_MODE_STATIC)
{
for(unsigned int i = 0; i < colors.size(); i++)
{
led_color_list.push_back({ leds[i].value, colors[i] });
}
}
controller->SendMode(modes[active_mode].value, modes[active_mode].speed, modes[active_mode].brightness, led_color_list);
controller->WaitUntilReady();
controller->EnableDirect(modes[active_mode].value == ROCCAT_VULCAN_MODE_DIRECT);
controller->WaitUntilReady();
}
@@ -0,0 +1,35 @@
/*---------------------------------------------------------*\
| RGBController_RoccatVulcanKeyboard.h |
| |
| RGBController for Roccat Vulcan keyboard |
| |
| Mola19 17 Dec 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatVulcanKeyboardController.h"
class RGBController_RoccatVulcanKeyboard : public RGBController
{
public:
RGBController_RoccatVulcanKeyboard(RoccatVulcanKeyboardController* controller_ptr);
~RGBController_RoccatVulcanKeyboard();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatVulcanKeyboardController* controller;
uint16_t pid;
};
@@ -0,0 +1,540 @@
/*---------------------------------------------------------*\
| RoccatVulcanKeyboardController.cpp |
| |
| Driver for Roccat Vulcan keyboard |
| |
| Mola19 17 Dec 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <chrono>
#include <cstring>
#include <math.h>
#include <thread>
#include <vector>
#include "LogManager.h"
#include "RoccatVulcanKeyboardController.h"
#include "StringUtils.h"
RoccatVulcanKeyboardController::RoccatVulcanKeyboardController(hid_device* dev_ctrl_handle, hid_device* dev_led_handle, char *path, uint16_t pid, std::string dev_name)
{
dev_ctrl = dev_ctrl_handle;
dev_led = dev_led_handle;
location = path;
name = dev_name;
device_pid = pid;
}
RoccatVulcanKeyboardController::~RoccatVulcanKeyboardController()
{
hid_close(dev_ctrl);
hid_close(dev_led);
}
std::string RoccatVulcanKeyboardController::GetLocation()
{
return("HID: " + location);
}
std::string RoccatVulcanKeyboardController::GetName()
{
return(name);
}
std::string RoccatVulcanKeyboardController::GetSerial()
{
wchar_t serial_string[128];
int ret = hid_get_serial_number_string(dev_ctrl, serial_string, 128);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
device_info RoccatVulcanKeyboardController::InitDeviceInfo()
{
uint8_t packet_length;
uint8_t report_id;
switch(device_pid)
{
case ROCCAT_PYRO_PID:
case ROCCAT_MAGMA_PID:
case ROCCAT_MAGMA_MINI_PID:
case ROCCAT_VULCAN_PRO_PID:
case ROCCAT_VULCAN_TKL_PRO_PID:
case ROCCAT_VULCAN_II_PID:
case ROCCAT_VULCAN_II_MAX_PID:
case TURTLE_BEACH_VULCAN_II_PID:
case TURTLE_BEACH_VULCAN_II_TKL_PRO_PID:
packet_length = 9;
report_id = 0x09;
break;
default:
packet_length = 8;
report_id = 0x0F;
}
uint8_t* buf = new uint8_t[packet_length];
memset(buf, 0x00, packet_length);
buf[0] = report_id;
hid_get_feature_report(dev_ctrl, buf, packet_length);
/*-------------------------------------------------------------*\
| buf[2] is version e.g. 103 means v1.03 |
\*-------------------------------------------------------------*/
dev_info.version_major = buf[2] / 100;
dev_info.version_minor = buf[2] % 100;
char version[5];
snprintf(version, 5, "%d.%02d", dev_info.version_major, dev_info.version_minor);
dev_info.version = version;
if(device_pid == ROCCAT_MAGMA_PID || device_pid == ROCCAT_MAGMA_MINI_PID)
{
/*---------------------------------------------------------*\
| This device doesn't need a layout, |
| because it doesn't have per-led lighting. |
| Taking us layout as placeholder instead |
\*---------------------------------------------------------*/
dev_info.layout_type = ROCCAT_VULCAN_LAYOUT_US;
}
else
{
dev_info.layout_type = buf[6];
}
LOG_DEBUG("[Roccat Vulcan Keyboard]: Detected layout '0x%02X'", buf[6]);
delete[] buf;
return dev_info;
}
device_info RoccatVulcanKeyboardController::GetDeviceInfo()
{
return dev_info;
}
bool RoccatVulcanKeyboardController::IsBigEndianDirectMode()
{
return (dev_info.version_major >= 1 && dev_info.version_minor >= 16);
}
void RoccatVulcanKeyboardController::EnableDirect(bool on_off_switch)
{
uint8_t* buf;
switch(device_pid)
{
case ROCCAT_PYRO_PID:
case ROCCAT_MAGMA_PID:
case ROCCAT_MAGMA_MINI_PID:
case ROCCAT_VULCAN_PRO_PID:
case ROCCAT_VULCAN_TKL_PRO_PID:
case ROCCAT_VULCAN_II_PID:
case ROCCAT_VULCAN_II_MAX_PID:
case TURTLE_BEACH_VULCAN_II_PID:
case TURTLE_BEACH_VULCAN_II_TKL_PRO_PID:
buf = new uint8_t[5] { 0x0E, 0x05, on_off_switch, 0x00, 0x00 };
hid_send_feature_report(dev_ctrl, buf, 5);
break;
default:
buf = new uint8_t[3] { 0x15, 0x00, on_off_switch };
hid_send_feature_report(dev_ctrl, buf, 3);
}
delete[] buf;
}
void RoccatVulcanKeyboardController::SendColors(std::vector<led_color> colors)
{
unsigned short packet_length;
unsigned char column_length;
unsigned char protocol_version;
switch(device_pid)
{
case ROCCAT_MAGMA_PID:
case ROCCAT_MAGMA_MINI_PID:
packet_length = 64;
column_length = 5;
protocol_version = 2;
break;
case ROCCAT_PYRO_PID:
packet_length = 378;
column_length = 1;
protocol_version = 2;
break;
case ROCCAT_VULCAN_PRO_PID:
case ROCCAT_VULCAN_TKL_PRO_PID:
packet_length = 384;
column_length = 12;
protocol_version = 2;
break;
case ROCCAT_VULCAN_II_PID:
case TURTLE_BEACH_VULCAN_II_PID:
packet_length = 396;
column_length = 1;
protocol_version = 2;
break;
case ROCCAT_VULCAN_II_MAX_PID:
packet_length = 567;
column_length = 1;
protocol_version = 2;
break;
case TURTLE_BEACH_VULCAN_II_TKL_PRO_PID:
packet_length = 320;
column_length = 1;
protocol_version = 2;
break;
default:
packet_length = 436;
column_length = 12;
protocol_version = 1;
}
unsigned char packet_num = (unsigned char)(ceil((float)packet_length / 64));
std::vector<std::vector<uint8_t>> bufs(packet_num);
for(int p = 0; p < packet_num; p++)
{
bufs[p].resize(65);
memset(&bufs[p][0], 0x00, sizeof(bufs[p][0]) * bufs[p].size());
}
if(protocol_version > 1)
{
for(unsigned int i = 0; i < packet_num; i++)
{
bufs[i][1] = 0xA1;
bufs[i][2] = i + 1;
}
}
else
{
bufs[0][1] = 0xA1;
bufs[0][2] = 0x01;
}
unsigned char header_length_first = (packet_length > 255) ? 4 : 3;
if(header_length_first == 3)
{
bufs[0][3] = (uint8_t)packet_length;
}
else
{
if(IsBigEndianDirectMode())
{
bufs[0][3] = (packet_length >> 8) & 0xFF;
bufs[0][4] = packet_length & 0xFF;
}
else
{
bufs[0][3] = packet_length & 0xFF;
bufs[0][4] = (packet_length >> 8) & 0xFF;
}
}
unsigned int data_length_packet = 64 - header_length_first;
unsigned int hw_leds = 0;
if(device_pid == TURTLE_BEACH_VULCAN_II_TKL_PRO_PID)
{
for(unsigned int i = 0; i < colors.size(); i++)
{
if(colors[i].value > hw_leds)
{
hw_leds = colors[i].value;
}
}
hw_leds += 1;
}
for(unsigned int i = 0; i < colors.size(); i++)
{
if(device_pid == TURTLE_BEACH_VULCAN_II_TKL_PRO_PID)
{
const unsigned int CHANNEL_OFFSET = hw_leds;
unsigned int led_index = colors[i].value;
if(led_index >= hw_leds)
{
continue;
}
unsigned int logical_pos_r = led_index;
unsigned int p_idx_r = logical_pos_r / data_length_packet;
unsigned int b_idx_r = logical_pos_r % data_length_packet;
if(p_idx_r < bufs.size())
{
bufs[p_idx_r][b_idx_r + header_length_first + 1] = RGBGetRValue(colors[i].color);
}
unsigned int logical_pos_g = led_index + CHANNEL_OFFSET;
unsigned int p_idx_g = logical_pos_g / data_length_packet;
unsigned int b_idx_g = logical_pos_g % data_length_packet;
if(p_idx_g < bufs.size())
{
bufs[p_idx_g][b_idx_g + header_length_first + 1] = RGBGetGValue(colors[i].color);
}
unsigned int logical_pos_b = led_index + 2 * CHANNEL_OFFSET;
unsigned int p_idx_b = logical_pos_b / data_length_packet;
unsigned int b_idx_b = logical_pos_b % data_length_packet;
if(p_idx_b < bufs.size())
{
bufs[p_idx_b][b_idx_b + header_length_first + 1] = RGBGetBValue(colors[i].color);
}
}
else
{
int column = (int)(floor(colors[i].value / column_length));
int row = colors[i].value % column_length;
if(protocol_version == 1)
{
int offset = column * 3 * column_length + row + header_length_first;
bufs[offset / 64][offset % 64 + 1] = RGBGetRValue(colors[i].color);
offset += column_length;
bufs[offset / 64][offset % 64 + 1] = RGBGetGValue(colors[i].color);
offset += column_length;
bufs[offset / 64][offset % 64 + 1] = RGBGetBValue(colors[i].color);
}
else
{
int offset = column * 3 * column_length + row;
bufs[offset / data_length_packet][offset % data_length_packet + header_length_first + 1] = RGBGetRValue(colors[i].color);
offset += column_length;
bufs[offset / data_length_packet][offset % data_length_packet + header_length_first + 1] = RGBGetGValue(colors[i].color);
offset += column_length;
bufs[offset / data_length_packet][offset % data_length_packet + header_length_first + 1] = RGBGetBValue(colors[i].color);
}
}
}
for(int p = 0; p < packet_num; p++)
{
hid_write(dev_led, &bufs[p][0], 65);
}
ClearResponses();
AwaitResponse(20);
}
void RoccatVulcanKeyboardController::SendMode(unsigned int mode, unsigned int speed, unsigned int brightness, std::vector<led_color> colors)
{
if(speed == 0) speed = ROCCAT_VULCAN_SPEED_DEFAULT;
if(brightness == 0) brightness = ROCCAT_VULCAN_BRIGHTNESS_DEFAULT;
unsigned short packet_length;
unsigned char protocol_version;
unsigned char column_length;
switch(device_pid)
{
case ROCCAT_PYRO_PID:
protocol_version = 2;
packet_length = 365;
column_length = 1;
break;
case ROCCAT_MAGMA_PID:
case ROCCAT_MAGMA_MINI_PID:
protocol_version = 2;
packet_length = 26;
column_length = 5;
break;
case ROCCAT_VULCAN_PRO_PID:
case ROCCAT_VULCAN_TKL_PRO_PID:
protocol_version = 2;
packet_length = 371;
column_length = 12;
break;
case ROCCAT_VULCAN_II_PID:
case TURTLE_BEACH_VULCAN_II_PID:
protocol_version = 2;
packet_length = 377;
column_length = 1;
break;
case ROCCAT_VULCAN_II_MAX_PID:
protocol_version = 2;
packet_length = 542;
column_length = 1;
break;
case TURTLE_BEACH_VULCAN_II_TKL_PRO_PID:
packet_length = 284;
column_length = 1;
protocol_version = 2;
break;
default:
protocol_version = 1;
packet_length = 443;
column_length = 12;
}
uint8_t* buf = new uint8_t[packet_length];
memset(buf, 0x00, packet_length);
unsigned char header_length = (packet_length > 255) ? 2 : 1;
buf[0] = (protocol_version == 1) ? 0x0D : 0x11;
if(header_length == 1)
{
buf[1] = (uint8_t)packet_length;
}
else
{
buf[1] = packet_length % 256;
buf[2] = packet_length / 256;
}
unsigned char offset = header_length + 1;
buf[0 + offset] = 0x00;
buf[1 + offset] = mode;
buf[2 + offset] = speed;
if(protocol_version == 1)
{
buf[3 + offset] = 0x00;
buf[4 + offset] = brightness;
buf[5 + offset] = 0x00;
}
else
{
buf[3 + offset] = brightness;
buf[4 + offset] = 0x00;
buf[5 + offset] = 0x00;
}
if(device_pid == TURTLE_BEACH_VULCAN_II_TKL_PRO_PID)
{
buf[0 + offset] = 0x03;
buf[4 + offset] = 0x0B;
buf[5 + offset] = 0x01;
}
unsigned int hw_leds = 0;
if(device_pid == TURTLE_BEACH_VULCAN_II_TKL_PRO_PID)
{
for(unsigned int i = 0; i < colors.size(); i++)
{
if(colors[i].value > hw_leds)
{
hw_leds = colors[i].value;
}
}
hw_leds += 1;
}
for(unsigned int i = 0; i < colors.size(); i++)
{
if(device_pid == TURTLE_BEACH_VULCAN_II_TKL_PRO_PID)
{
const int HEADER_OFFSET = 9;
const unsigned int CHANNEL_OFFSET = hw_leds;
unsigned int led_index = colors[i].value;
if(led_index >= hw_leds) continue;
int pos_r = HEADER_OFFSET + led_index;
int pos_g = HEADER_OFFSET + led_index + CHANNEL_OFFSET;
int pos_b = HEADER_OFFSET + led_index + (2 * CHANNEL_OFFSET);
if (pos_b < packet_length - 2)
{
buf[pos_r] = RGBGetRValue(colors[i].color);
buf[pos_g] = RGBGetGValue(colors[i].color);
buf[pos_b] = RGBGetBValue(colors[i].color);
}
}
else
{
int column = (int)(floor(colors[i].value / column_length));
int row = colors[i].value % column_length;
int pos = column * 3 * column_length + row + 9;
if(pos + (2 * column_length) < packet_length - 2)
{
buf[pos] = RGBGetRValue(colors[i].color);
pos += column_length;
buf[pos] = RGBGetGValue(colors[i].color);
pos += column_length;
buf[pos] = RGBGetBValue(colors[i].color);
}
}
}
unsigned short total = 0;
for(int i = 0; i < packet_length - 2; i++) total += buf[i];
buf[packet_length - 2] = total & 0xFF;
buf[packet_length - 1] = total >> 8;
hid_send_feature_report(dev_ctrl, buf, packet_length);
delete[] buf;
}
void RoccatVulcanKeyboardController::WaitUntilReady()
{
unsigned short packet_length;
switch(device_pid)
{
case ROCCAT_PYRO_PID:
case ROCCAT_MAGMA_PID:
case ROCCAT_MAGMA_MINI_PID:
case ROCCAT_VULCAN_PRO_PID:
case ROCCAT_VULCAN_TKL_PRO_PID:
packet_length = 4;
break;
default:
packet_length = 3;
}
uint8_t* buf = new uint8_t[packet_length];
buf[0] = 0x04;
for(unsigned char i = 0; buf[1] != 1 && i < 100; i++)
{
if(i != 0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(25));
}
hid_get_feature_report(dev_ctrl, buf, packet_length);
}
delete[] buf;
}
void RoccatVulcanKeyboardController::AwaitResponse(int ms)
{
unsigned char usb_buf_out[65];
hid_read_timeout(dev_led, usb_buf_out, 65, ms);
}
void RoccatVulcanKeyboardController::ClearResponses()
{
int result = 1;
unsigned char usb_buf_flush[65];
while(result > 0)
{
result = hid_read_timeout(dev_led, usb_buf_flush, 65, 0);
}
}
@@ -0,0 +1,105 @@
/*---------------------------------------------------------*\
| RoccatVulcanKeyboardController.h |
| |
| Driver for Roccat Vulcan keyboard |
| |
| Mola19 17 Dec 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <string>
#include <hidapi.h>
#include "RGBController.h"
#include "RoccatVulcanKeyboardLayouts.h"
/*--------------------------------------------------------------------------------*\
| KEYBOARDS |
| This section was used to be enum. |
\*--------------------------------------------------------------------------------*/
#define ROCCAT_VULCAN_100_AIMO_PID 0x307A
#define ROCCAT_VULCAN_120_AIMO_PID 0x3098
#define ROCCAT_VULCAN_TKL_PID 0x2FEE
#define ROCCAT_VULCAN_PRO_PID 0x30F7
#define ROCCAT_VULCAN_TKL_PRO_PID 0x311A
#define ROCCAT_VULCAN_II_PID 0x2F4E
#define ROCCAT_VULCAN_II_MAX_PID 0x2EE2
#define ROCCAT_PYRO_PID 0x314C
#define ROCCAT_MAGMA_PID 0x3124
#define ROCCAT_MAGMA_MINI_PID 0x69A0
#define TURTLE_BEACH_VULCAN_II_PID 0x501B
#define TURTLE_BEACH_VULCAN_II_TKL_PID 0x5023
#define TURTLE_BEACH_VULCAN_II_TKL_PRO_PID 0x5001
enum
{
ROCCAT_VULCAN_MODE_DIRECT = 0x0B,
ROCCAT_VULCAN_MODE_STATIC = 0x01,
ROCCAT_VULCAN_MODE_WAVE = 0x0A,
/*-------------------------------------------------------------------*\
| This mode is not a real mode, it's just the default mode when |
| a mode is software generated, but Swarm is inactive, hence it has |
| no id. Unfortunately 0 is refused by some keyboards, so 2 seems |
| like a good choice as it is not used anywhere else |
\*-------------------------------------------------------------------*/
ROCCAT_VULCAN_MODE_DEFAULT = 0x02,
};
enum
{
ROCCAT_VULCAN_SPEED_MIN = 0x01,
ROCCAT_VULCAN_SPEED_MAX = 0x0B,
ROCCAT_VULCAN_SPEED_DEFAULT = 0x06,
ROCCAT_VULCAN_BRIGHTNESS_MIN = 0x01,
ROCCAT_VULCAN_BRIGHTNESS_MAX = 0x45,
ROCCAT_VULCAN_BRIGHTNESS_DEFAULT = 0x45,
};
struct device_info
{
std::string version;
int version_major;
int version_minor;
int layout_type;
};
struct led_color
{
unsigned int value;
RGBColor color;
};
class RoccatVulcanKeyboardController
{
public:
RoccatVulcanKeyboardController(hid_device* dev_ctrl_handle, hid_device* dev_led_handle, char *path, uint16_t pid, std::string dev_name);
~RoccatVulcanKeyboardController();
std::string GetSerial();
std::string GetLocation();
std::string GetName();
device_info InitDeviceInfo();
device_info GetDeviceInfo();
void EnableDirect(bool on_off_switch);
void SendColors(std::vector<led_color> colors);
void SendMode(unsigned int mode, unsigned int speed, unsigned int brightness, std::vector<led_color> colors);
void WaitUntilReady();
void AwaitResponse(int ms);
void ClearResponses();
uint16_t device_pid;
private:
hid_device* dev_ctrl;
hid_device* dev_led;
device_info dev_info;
std::string location;
std::string name;
bool IsBigEndianDirectMode();
};