Add Fnatic STREAK and miniSTREAK support

This commit is contained in:
mikee
2025-11-27 20:15:46 +00:00
committed by Adam Honse
parent 7ef7edb1d3
commit 946383b502
5 changed files with 1277 additions and 0 deletions

View File

@@ -0,0 +1,354 @@
/*---------------------------------------------------------*\
| FnaticStreakController.cpp |
| |
| Driver for Fnatic Streak and miniStreak keyboards |
| |
| Based on leddy project by Hanna Czenczek |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "FnaticStreakController.h"
#include "StringUtils.h"
#include "LogManager.h"
FnaticStreakController::FnaticStreakController(hid_device* dev_handle, hid_device_info* dev_info, std::string dev_name, FnaticStreakType kb_type)
{
dev = dev_handle;
location = dev_info->path;
name = dev_name;
keyboard_type = kb_type;
profile = 1;
software_effect_mode = false;
memset(color_buf, 0x00, sizeof(color_buf));
/*-----------------------------------------------------*\
| Get the firmware version from the device info |
\*-----------------------------------------------------*/
char fw_version_buf[8];
memset(fw_version_buf, '\0', sizeof(fw_version_buf));
unsigned short version = dev_info->release_number;
snprintf(fw_version_buf, 8, "%.2X.%.2X", (version & 0xFF00) >> 8, version & 0x00FF);
firmware_version = fw_version_buf;
}
FnaticStreakController::~FnaticStreakController()
{
hid_close(dev);
}
std::string FnaticStreakController::GetDeviceLocation()
{
return("HID " + location);
}
std::string FnaticStreakController::GetNameString()
{
return(name);
}
std::string FnaticStreakController::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));
}
std::string FnaticStreakController::GetFirmwareVersion()
{
return(firmware_version);
}
FnaticStreakType FnaticStreakController::GetKeyboardType()
{
return(keyboard_type);
}
unsigned int FnaticStreakController::GetLEDCount()
{
if(keyboard_type == FNATIC_STREAK_TYPE_MINI)
{
return 106;
}
else
{
return 124;
}
}
void FnaticStreakController::SetProfile(unsigned char new_profile)
{
if(new_profile >= 1 && new_profile <= 4)
{
profile = new_profile;
SoftwareEffectEnd();
}
}
void FnaticStreakController::SoftwareEffectStart()
{
software_effect_mode = true;
}
void FnaticStreakController::SoftwareEffectEnd()
{
software_effect_mode = false;
RefreshProfile();
}
void FnaticStreakController::SendKeepalive()
{
/*-----------------------------------------------------*\
| Send keepalive packet (0x07 or 0xfe) to prevent |
| keyboard from reverting to profile effect during |
| direct/preview mode |
\*-----------------------------------------------------*/
unsigned char prefix[] = { 0x07 };
SendRequest(prefix, sizeof(prefix), nullptr, 0);
}
void FnaticStreakController::RefreshProfile()
{
unsigned char data[] = { profile };
unsigned char prefix[] = { 0x04 };
SendRequest(prefix, sizeof(prefix), data, sizeof(data));
}
void FnaticStreakController::SendRequest(const unsigned char* prefix, size_t prefix_len, const unsigned char* raw_data, size_t data_len)
{
size_t total_len = prefix_len + data_len;
size_t offset = 0;
unsigned char cmd = (prefix_len > 0) ? prefix[0] : raw_data[0];
while(offset < total_len)
{
unsigned char packet[65];
memset(packet, 0x00, sizeof(packet));
/*-----------------------------------------------------*\
| Packet format: |
| [0] = Report ID (0x00) |
| [1] = Command |
| [2-4] = Total length (24-bit little endian) |
| [5-7] = Offset (24-bit little endian) |
| [8-64] = Data (57 bytes max per packet) |
\*-----------------------------------------------------*/
packet[0] = 0x00;
packet[1] = cmd;
packet[2] = (unsigned char)(total_len & 0xFF);
packet[3] = (unsigned char)((total_len >> 8) & 0xFF);
packet[4] = (unsigned char)((total_len >> 16) & 0xFF);
packet[5] = (unsigned char)(offset & 0xFF);
packet[6] = (unsigned char)((offset >> 8) & 0xFF);
packet[7] = (unsigned char)((offset >> 16) & 0xFF);
for(size_t i = offset; i < offset + 57 && i < total_len; i++)
{
if(i < prefix_len)
{
packet[i - offset + 8] = prefix[i];
}
else
{
packet[i - offset + 8] = raw_data[i - prefix_len];
}
}
hid_write(dev, packet, 65);
offset += 57;
}
/*-----------------------------------------------------*\
| For command 0x05, save changes and refresh profile |
\*-----------------------------------------------------*/
if(cmd == 0x05)
{
unsigned char save_prefix[] = { 0x13 };
SendRequest(save_prefix, sizeof(save_prefix), nullptr, 0);
unsigned char profile_data[] = { profile };
unsigned char profile_prefix[] = { 0x04 };
SendRequest(profile_prefix, sizeof(profile_prefix), profile_data, sizeof(profile_data));
}
}
void FnaticStreakController::SetLEDsDirect(std::vector<led> leds, std::vector<RGBColor> colors, unsigned int brightness)
{
unsigned int total_leds = GetLEDCount();
/*-----------------------------------------------------*\
| Clear the color buffer |
\*-----------------------------------------------------*/
memset(color_buf, 0x00, sizeof(color_buf));
/*-----------------------------------------------------*\
| Transfer colors to the buffer |
| Format: sequential RGB triplets indexed by LED value |
| The LED value corresponds to the physical LED index |
| in the keyboard hardware (0-123 for full, 0-105 mini) |
| Apply brightness scaling (0-100%) |
\*-----------------------------------------------------*/
unsigned int leds_to_set = (unsigned int)std::min(colors.size(), leds.size());
for(unsigned int i = 0; i < leds_to_set; i++)
{
unsigned int led_idx = leds[i].value;
if(led_idx < total_leds)
{
if(brightness >= 100)
{
/*-----------------------------------------*\
| Full brightness - no scaling needed |
\*-----------------------------------------*/
color_buf[led_idx * 3 + 0] = RGBGetRValue(colors[i]);
color_buf[led_idx * 3 + 1] = RGBGetGValue(colors[i]);
color_buf[led_idx * 3 + 2] = RGBGetBValue(colors[i]);
}
else
{
/*-----------------------------------------*\
| Apply brightness scaling |
\*-----------------------------------------*/
color_buf[led_idx * 3 + 0] = (unsigned char)(RGBGetRValue(colors[i]) * brightness / 100);
color_buf[led_idx * 3 + 1] = (unsigned char)(RGBGetGValue(colors[i]) * brightness / 100);
color_buf[led_idx * 3 + 2] = (unsigned char)(RGBGetBValue(colors[i]) * brightness / 100);
}
}
}
}
void FnaticStreakController::SendRGBToDevice()
{
unsigned int total_leds = GetLEDCount();
unsigned int data_size = total_leds * 3;
/*-----------------------------------------------------*\
| For direct/software control, use command 0x0f |
| This bypasses the profile and allows immediate update |
| The 0x03 subcommand indicates per-key color data |
\*-----------------------------------------------------*/
unsigned char prefix[] = { 0x0f, 0x03 };
SendRequest(prefix, sizeof(prefix), color_buf, data_size);
}
void FnaticStreakController::SetPulse(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed)
{
/*-----------------------------------------------------*\
| Pulse effect - cmd 0x06 |
| Data: [mode, r, g, b, speed] |
\*-----------------------------------------------------*/
unsigned char prefix[] = { 0x05, profile, 0x02 };
unsigned char data[] = { FNATIC_STREAK_CMD_PULSE, color_mode, r, g, b, speed };
SendRequest(prefix, sizeof(prefix), data, sizeof(data));
}
void FnaticStreakController::SetWave(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed, unsigned char direction)
{
/*-----------------------------------------------------*\
| Wave effect - cmd 0x07 |
| Data: [mode, r, g, b, speed, direction] |
\*-----------------------------------------------------*/
unsigned char prefix[] = { 0x05, profile, 0x02 };
unsigned char data[] = { FNATIC_STREAK_CMD_WAVE, color_mode, r, g, b, speed, direction };
SendRequest(prefix, sizeof(prefix), data, sizeof(data));
}
void FnaticStreakController::SetReactive(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed, bool keyup)
{
/*-----------------------------------------------------*\
| Reactive effect - cmd 0x09 |
| Data: [mode, r, g, b, speed, trigger] |
| trigger: 0 = keydown, 1 = keyup |
\*-----------------------------------------------------*/
unsigned char prefix[] = { 0x05, profile, 0x02 };
unsigned char data[] = { FNATIC_STREAK_CMD_REACTIVE, color_mode, r, g, b, speed, (unsigned char)(keyup ? 0 : 1) };
SendRequest(prefix, sizeof(prefix), data, sizeof(data));
}
void FnaticStreakController::SetReactiveRipple(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed, bool keyup)
{
/*-----------------------------------------------------*\
| Reactive Ripple effect - cmd 0x0A |
| Data: [mode, r, g, b, speed, trigger] |
| trigger: 0 = keydown, 1 = keyup |
\*-----------------------------------------------------*/
unsigned char prefix[] = { 0x05, profile, 0x02 };
unsigned char data[] = { FNATIC_STREAK_CMD_REACTIVE_RIPPLE, color_mode, r, g, b, speed, (unsigned char)(keyup ? 0 : 1) };
SendRequest(prefix, sizeof(prefix), data, sizeof(data));
}
void FnaticStreakController::SetRain(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed, unsigned char direction)
{
/*-----------------------------------------------------*\
| Rain effect - cmd 0x0B |
| Data: [mode, r, g, b, speed, direction] |
| Note: Does not support rainbow mode |
\*-----------------------------------------------------*/
unsigned char prefix[] = { 0x05, profile, 0x02 };
unsigned char mode = (color_mode == FNATIC_STREAK_COLOR_MODE_RAINBOW) ? FNATIC_STREAK_COLOR_MODE_RANDOM : color_mode;
unsigned char data[] = { FNATIC_STREAK_CMD_RAIN, mode, r, g, b, speed, direction };
SendRequest(prefix, sizeof(prefix), data, sizeof(data));
}
void FnaticStreakController::SetGradient(unsigned char colors[][3], unsigned char positions[], unsigned int count)
{
/*-----------------------------------------------------*\
| Gradient effect - cmd 0x0C |
| Data: [count, {r, g, b, pos} * 10] |
| (always sends 10 color slots, unused are zeroed) |
\*-----------------------------------------------------*/
unsigned char prefix[] = { 0x05, profile, 0x02 };
unsigned char data[42];
memset(data, 0x00, sizeof(data));
data[0] = FNATIC_STREAK_CMD_GRADIENT;
data[1] = (unsigned char)count;
for(unsigned int i = 0; i < count && i < 10; i++)
{
data[2 + i * 4 + 0] = colors[i][0];
data[2 + i * 4 + 1] = colors[i][1];
data[2 + i * 4 + 2] = colors[i][2];
data[2 + i * 4 + 3] = positions[i];
}
SendRequest(prefix, sizeof(prefix), data, sizeof(data));
}
void FnaticStreakController::SetFade(unsigned char color_mode, unsigned char colors[][3], unsigned char positions[], unsigned int count, unsigned char speed)
{
/*-----------------------------------------------------*\
| Fade effect - cmd 0x0D |
| Data: [mode, count, {r, g, b, pos} * 10, speed] |
\*-----------------------------------------------------*/
unsigned char prefix[] = { 0x05, profile, 0x02 };
unsigned char data[44];
memset(data, 0x00, sizeof(data));
data[0] = FNATIC_STREAK_CMD_FADE;
data[1] = color_mode;
data[2] = (unsigned char)count;
for(unsigned int i = 0; i < count && i < 10; i++)
{
data[3 + i * 4 + 0] = colors[i][0];
data[3 + i * 4 + 1] = colors[i][1];
data[3 + i * 4 + 2] = colors[i][2];
data[3 + i * 4 + 3] = positions[i];
}
data[43] = speed;
SendRequest(prefix, sizeof(prefix), data, sizeof(data));
}

View File

@@ -0,0 +1,108 @@
/*---------------------------------------------------------*\
| FnaticStreakController.h |
| |
| Driver for Fnatic Streak and miniStreak keyboards |
| |
| Based on leddy project by Hanna Czenczek |
| |
| 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"
/*-----------------------------------------------------*\
| Fnatic Streak keyboard layout variants |
\*-----------------------------------------------------*/
#define FNATIC_STREAK_VARIANT_ISO 0x00
#define FNATIC_STREAK_VARIANT_ANSI 0x01
/*-----------------------------------------------------*\
| Fnatic Streak effect command bytes |
\*-----------------------------------------------------*/
#define FNATIC_STREAK_CMD_PULSE 0x06
#define FNATIC_STREAK_CMD_WAVE 0x07
#define FNATIC_STREAK_CMD_REACTIVE 0x09
#define FNATIC_STREAK_CMD_REACTIVE_RIPPLE 0x0A
#define FNATIC_STREAK_CMD_RAIN 0x0B
#define FNATIC_STREAK_CMD_GRADIENT 0x0C
#define FNATIC_STREAK_CMD_FADE 0x0D
/*-----------------------------------------------------*\
| Fnatic Streak color modes |
\*-----------------------------------------------------*/
#define FNATIC_STREAK_COLOR_MODE_SINGLE 0x00
#define FNATIC_STREAK_COLOR_MODE_RAINBOW 0x01
#define FNATIC_STREAK_COLOR_MODE_RANDOM 0x02
#define FNATIC_STREAK_COLOR_MODE_GRADIENT 0x03
/*-----------------------------------------------------*\
| Fnatic Streak directions |
\*-----------------------------------------------------*/
#define FNATIC_STREAK_DIRECTION_RIGHT 0x01
#define FNATIC_STREAK_DIRECTION_LEFT 0x02
#define FNATIC_STREAK_DIRECTION_DOWN 0x03
#define FNATIC_STREAK_DIRECTION_UP 0x04
enum FnaticStreakType
{
FNATIC_STREAK_TYPE_FULL,
FNATIC_STREAK_TYPE_MINI
};
class FnaticStreakController
{
public:
FnaticStreakController(hid_device* dev_handle, hid_device_info* dev_info, std::string dev_name, FnaticStreakType kb_type);
~FnaticStreakController();
std::string GetDeviceLocation();
std::string GetNameString();
std::string GetSerialString();
std::string GetFirmwareVersion();
FnaticStreakType GetKeyboardType();
unsigned int GetLEDCount();
void SetProfile(unsigned char profile);
void SetLEDsDirect(std::vector<led> leds, std::vector<RGBColor> colors, unsigned int brightness);
void SendRGBToDevice();
/*-----------------------------------------------------*\
| Hardware effect methods |
\*-----------------------------------------------------*/
void SetPulse(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed);
void SetWave(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed, unsigned char direction);
void SetReactive(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed, bool keyup);
void SetReactiveRipple(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed, bool keyup);
void SetRain(unsigned char color_mode, unsigned char r, unsigned char g, unsigned char b, unsigned char speed, unsigned char direction);
void SetGradient(unsigned char colors[][3], unsigned char positions[], unsigned int count);
void SetFade(unsigned char color_mode, unsigned char colors[][3], unsigned char positions[], unsigned int count, unsigned char speed);
void SoftwareEffectStart();
void SoftwareEffectEnd();
void SendKeepalive();
private:
void SendRequest(const unsigned char* prefix, size_t prefix_len, const unsigned char* raw_data, size_t data_len);
void RefreshProfile();
hid_device* dev;
std::string location;
std::string firmware_version;
std::string name;
FnaticStreakType keyboard_type;
unsigned char profile;
bool software_effect_mode;
/*-----------------------------------------------------*\
| Buffer for LED colors |
| Full: 124 LEDs * 3 (RGB) = 372 bytes |
| Mini: 106 LEDs * 3 (RGB) = 318 bytes |
| Using max size to support both |
\*-----------------------------------------------------*/
unsigned char color_buf[372];
};

View File

@@ -0,0 +1,55 @@
/*---------------------------------------------------------*\
| FnaticStreakControllerDetect.cpp |
| |
| Detector for Fnatic Streak and miniStreak keyboards |
| |
| Based on leddy project by Hanna Czenczek |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <hidapi.h>
#include "Detector.h"
#include "FnaticStreakController.h"
#include "RGBController_FnaticStreak.h"
/*-----------------------------------------------------*\
| Fnatic keyboard vendor and product IDs |
| Based on leddy project keyboard.rs |
| VID: 0x2f0e |
| PID: 0x0101 (Streak full) |
| PID: 0x0102 (miniStreak) |
| Interface: 1 |
\*-----------------------------------------------------*/
#define FNATIC_VID 0x2F0E
#define FNATIC_STREAK_PID 0x0101
#define FNATIC_MINISTREAK_PID 0x0102
void DetectFnaticStreakKeyboard(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
FnaticStreakType kb_type;
if(info->product_id == FNATIC_MINISTREAK_PID)
{
kb_type = FNATIC_STREAK_TYPE_MINI;
}
else
{
kb_type = FNATIC_STREAK_TYPE_FULL;
}
FnaticStreakController* controller = new FnaticStreakController(dev, info, name, kb_type);
RGBController_FnaticStreak* rgb_controller = new RGBController_FnaticStreak(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
REGISTER_HID_DETECTOR_I("Fnatic Streak", DetectFnaticStreakKeyboard, FNATIC_VID, FNATIC_STREAK_PID, 1);
REGISTER_HID_DETECTOR_I("Fnatic miniStreak", DetectFnaticStreakKeyboard, FNATIC_VID, FNATIC_MINISTREAK_PID, 1);

View File

@@ -0,0 +1,719 @@
/*---------------------------------------------------------*\
| RGBController_FnaticStreak.cpp |
| |
| RGBController for Fnatic Streak and miniStreak keyboard |
| |
| Based on leddy project by Hanna Czenczek |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_FnaticStreak.h"
#include "RGBControllerKeyNames.h"
using namespace std::chrono_literals;
/*---------------------------------------------------------------------*\
| 0xFFFFFFFF indicates an unused entry in matrix |
\*---------------------------------------------------------------------*/
#define NA 0xFFFFFFFF
/*---------------------------------------------------------------------*\
| Fnatic Streak Full Size Matrix Map (6 rows x 22 columns) |
| Based on leddy project keyboard.rs ledmap |
| Values are LED indices that map to the physical LED positions |
\*---------------------------------------------------------------------*/
static unsigned int matrix_map_full[6][22] =
{
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 */
/* ESC FNLK F1 F2 F3 F4 F5 F6 F7 F8 SIG F9 F10 F11 F12 PRSC SCLK PAUS MMIC GAME MSPK VOL */
{ 1, 0, 7, 13, 19, 25, 31, 37, 43, 49, 120, 55, 67, 73, 79, 90, 93, 98, 91, 97, 92, 118 },
/* BKT 1 2 3 4 5 6 7 8 9 0 - = NA BSP INS HOME PGUP NLCK NP/ NP* NP- */
{ 2, 8, 14, 20, 26, 32, 38, 44, 50, 56, 61, 62, 68, NA, 80, 89, 94, 99, 100, 108, 109, 116 },
/* TAB Q W E R T Y U I O P [ ] NA BS DEL END PGDN NP7 NP8 NP9 NP+ */
{ 3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, NA, 81, 88, 95, 96, 101, 107, 110, 115 },
/* CAPS NA A S D F G H J K L ; ' # ENT NA NA NA NP4 NP5 NP6 NA */
{ 4, NA, 10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70, 76, 82, NA, NA, NA, 102, 106, 111, NA },
/* LSFT ISO\ Z X C V B N M , . / NA RSFT NA NA UP NA NP1 NP2 NP3 NPEN */
{ 5, 11, 17, 23, 29, 35, 41, 47, 53, 59, 65, 66, NA, 77, NA, NA, 87, NA, 103, 105, 112, 114 },
/* LCTL LWIN LALT NA NA NA SPC NA NA NA RALT FN NA MENU RCTL LEFT DOWN RGHT NP0 NA NP. NA */
{ 6, 12, 18, NA, NA, NA, 36, NA, NA, NA, 60, 72, NA, 78, 83, 84, 85, 86, 104, NA, 113, NA }
};
/*---------------------------------------------------------------------*\
| Fnatic miniStreak TKL Matrix Map (6 rows x 18 columns) |
| Based on leddy project keyboard.rs ledmap |
\*---------------------------------------------------------------------*/
static unsigned int matrix_map_mini[6][18] =
{
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 */
/* ESC FNLK F1 F2 F3 F4 F5 F6 F7 F8 SIG F9 F10 F11 F12 PRSC SCLK PAUS */
{ 1, 0, 7, 13, 19, 25, 31, 37, 43, 49, 103, 55, 67, 73, 79, 90, 93, 98 },
/* BKT 1 2 3 4 5 6 7 8 9 0 - = NA BSP INS HOME PGUP */
{ 2, 8, 14, 20, 26, 32, 38, 44, 50, 56, 61, 62, 68, NA, 80, 89, 94, 99 },
/* TAB Q W E R T Y U I O P [ ] NA BS DEL END PGDN */
{ 3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, NA, 81, 88, 95, 96 },
/* CAPS NA A S D F G H J K L ; ' # ENT NA NA NA */
{ 4, NA, 10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70, 76, 82, NA, NA, NA },
/* LSFT ISO\ Z X C V B N M , . / NA RSFT NA NA UP NA */
{ 5, 11, 17, 23, 29, 35, 41, 47, 53, 59, 65, 66, NA, 77, NA, NA, 87, NA },
/* LCTL LWIN LALT NA NA NA SPC NA NA NA RALT FN NA MENU RCTL LEFT DOWN RGHT */
{ 6, 12, 18, NA, NA, NA, 36, NA, NA, NA, 60, 72, NA, 78, 83, 84, 85, 86 }
};
/*---------------------------------------------------------------------*\
| LED Names - Full keyboard (124 LEDs, indices 0-123) |
| Names are in LED index order based on leddy keyboard.rs constants |
\*---------------------------------------------------------------------*/
static const char* led_names_full[] =
{
/* 0 */ "Key: Fn Lock",
/* 1 */ KEY_EN_ESCAPE,
/* 2 */ KEY_EN_BACK_TICK,
/* 3 */ KEY_EN_TAB,
/* 4 */ KEY_EN_CAPS_LOCK,
/* 5 */ KEY_EN_LEFT_SHIFT,
/* 6 */ KEY_EN_LEFT_CONTROL,
/* 7 */ KEY_EN_F1,
/* 8 */ KEY_EN_1,
/* 9 */ KEY_EN_Q,
/* 10 */ KEY_EN_A,
/* 11 */ KEY_EN_ISO_BACK_SLASH,
/* 12 */ KEY_EN_LEFT_WINDOWS,
/* 13 */ KEY_EN_F2,
/* 14 */ KEY_EN_2,
/* 15 */ KEY_EN_W,
/* 16 */ KEY_EN_S,
/* 17 */ KEY_EN_Z,
/* 18 */ KEY_EN_LEFT_ALT,
/* 19 */ KEY_EN_F3,
/* 20 */ KEY_EN_3,
/* 21 */ KEY_EN_E,
/* 22 */ KEY_EN_D,
/* 23 */ KEY_EN_X,
/* 24 */ KEY_EN_UNUSED,
/* 25 */ KEY_EN_F4,
/* 26 */ KEY_EN_4,
/* 27 */ KEY_EN_R,
/* 28 */ KEY_EN_F,
/* 29 */ KEY_EN_C,
/* 30 */ KEY_EN_UNUSED,
/* 31 */ KEY_EN_F5,
/* 32 */ KEY_EN_5,
/* 33 */ KEY_EN_T,
/* 34 */ KEY_EN_G,
/* 35 */ KEY_EN_V,
/* 36 */ KEY_EN_SPACE,
/* 37 */ KEY_EN_F6,
/* 38 */ KEY_EN_6,
/* 39 */ KEY_EN_Y,
/* 40 */ KEY_EN_H,
/* 41 */ KEY_EN_B,
/* 42 */ KEY_EN_UNUSED,
/* 43 */ KEY_EN_F7,
/* 44 */ KEY_EN_7,
/* 45 */ KEY_EN_U,
/* 46 */ KEY_EN_J,
/* 47 */ KEY_EN_N,
/* 48 */ KEY_EN_UNUSED,
/* 49 */ KEY_EN_F8,
/* 50 */ KEY_EN_8,
/* 51 */ KEY_EN_I,
/* 52 */ KEY_EN_K,
/* 53 */ KEY_EN_M,
/* 54 */ KEY_EN_UNUSED,
/* 55 */ KEY_EN_F9,
/* 56 */ KEY_EN_9,
/* 57 */ KEY_EN_O,
/* 58 */ KEY_EN_L,
/* 59 */ KEY_EN_COMMA,
/* 60 */ KEY_EN_RIGHT_ALT,
/* 61 */ KEY_EN_0,
/* 62 */ KEY_EN_MINUS,
/* 63 */ KEY_EN_P,
/* 64 */ KEY_EN_SEMICOLON,
/* 65 */ KEY_EN_PERIOD,
/* 66 */ KEY_EN_FORWARD_SLASH,
/* 67 */ KEY_EN_F10,
/* 68 */ KEY_EN_EQUALS,
/* 69 */ KEY_EN_LEFT_BRACKET,
/* 70 */ KEY_EN_QUOTE,
/* 71 */ KEY_EN_UNUSED,
/* 72 */ KEY_EN_RIGHT_FUNCTION,
/* 73 */ KEY_EN_F11,
/* 74 */ KEY_EN_UNUSED,
/* 75 */ KEY_EN_RIGHT_BRACKET,
/* 76 */ KEY_EN_POUND,
/* 77 */ KEY_EN_RIGHT_SHIFT,
/* 78 */ KEY_EN_MENU,
/* 79 */ KEY_EN_F12,
/* 80 */ KEY_EN_BACKSPACE,
/* 81 */ KEY_EN_ANSI_BACK_SLASH,
/* 82 */ KEY_EN_ANSI_ENTER,
/* 83 */ KEY_EN_RIGHT_CONTROL,
/* 84 */ KEY_EN_LEFT_ARROW,
/* 85 */ KEY_EN_DOWN_ARROW,
/* 86 */ KEY_EN_RIGHT_ARROW,
/* 87 */ KEY_EN_UP_ARROW,
/* 88 */ KEY_EN_DELETE,
/* 89 */ KEY_EN_INSERT,
/* 90 */ KEY_EN_PRINT_SCREEN,
/* 91 */ "Key: Mute Mic",
/* 92 */ "Key: Mute Speaker",
/* 93 */ KEY_EN_SCROLL_LOCK,
/* 94 */ KEY_EN_HOME,
/* 95 */ KEY_EN_END,
/* 96 */ KEY_EN_PAGE_DOWN,
/* 97 */ "Key: Gaming Mode",
/* 98 */ KEY_EN_PAUSE_BREAK,
/* 99 */ KEY_EN_PAGE_UP,
/* 100 */ KEY_EN_NUMPAD_LOCK,
/* 101 */ KEY_EN_NUMPAD_7,
/* 102 */ KEY_EN_NUMPAD_4,
/* 103 */ KEY_EN_NUMPAD_1,
/* 104 */ KEY_EN_NUMPAD_0,
/* 105 */ KEY_EN_NUMPAD_2,
/* 106 */ KEY_EN_NUMPAD_5,
/* 107 */ KEY_EN_NUMPAD_8,
/* 108 */ KEY_EN_NUMPAD_DIVIDE,
/* 109 */ KEY_EN_NUMPAD_TIMES,
/* 110 */ KEY_EN_NUMPAD_9,
/* 111 */ KEY_EN_NUMPAD_6,
/* 112 */ KEY_EN_NUMPAD_3,
/* 113 */ KEY_EN_NUMPAD_PERIOD,
/* 114 */ KEY_EN_NUMPAD_ENTER,
/* 115 */ KEY_EN_NUMPAD_PLUS,
/* 116 */ KEY_EN_NUMPAD_MINUS,
/* 117 */ KEY_EN_UNUSED,
/* 118 */ "Key: Volume Knob",
/* 119 */ KEY_EN_UNUSED,
/* 120 */ "Key: Signature Plate",
/* 121 */ KEY_EN_UNUSED,
/* 122 */ KEY_EN_UNUSED,
/* 123 */ KEY_EN_UNUSED,
};
/*---------------------------------------------------------------------*\
| LED Names - Mini keyboard (106 LEDs, indices 0-105) |
| Same as full but with different signature plate location |
\*---------------------------------------------------------------------*/
static const char* led_names_mini[] =
{
/* 0 */ "Key: Fn Lock",
/* 1 */ KEY_EN_ESCAPE,
/* 2 */ KEY_EN_BACK_TICK,
/* 3 */ KEY_EN_TAB,
/* 4 */ KEY_EN_CAPS_LOCK,
/* 5 */ KEY_EN_LEFT_SHIFT,
/* 6 */ KEY_EN_LEFT_CONTROL,
/* 7 */ KEY_EN_F1,
/* 8 */ KEY_EN_1,
/* 9 */ KEY_EN_Q,
/* 10 */ KEY_EN_A,
/* 11 */ KEY_EN_ISO_BACK_SLASH,
/* 12 */ KEY_EN_LEFT_WINDOWS,
/* 13 */ KEY_EN_F2,
/* 14 */ KEY_EN_2,
/* 15 */ KEY_EN_W,
/* 16 */ KEY_EN_S,
/* 17 */ KEY_EN_Z,
/* 18 */ KEY_EN_LEFT_ALT,
/* 19 */ KEY_EN_F3,
/* 20 */ KEY_EN_3,
/* 21 */ KEY_EN_E,
/* 22 */ KEY_EN_D,
/* 23 */ KEY_EN_X,
/* 24 */ KEY_EN_UNUSED,
/* 25 */ KEY_EN_F4,
/* 26 */ KEY_EN_4,
/* 27 */ KEY_EN_R,
/* 28 */ KEY_EN_F,
/* 29 */ KEY_EN_C,
/* 30 */ KEY_EN_UNUSED,
/* 31 */ KEY_EN_F5,
/* 32 */ KEY_EN_5,
/* 33 */ KEY_EN_T,
/* 34 */ KEY_EN_G,
/* 35 */ KEY_EN_V,
/* 36 */ KEY_EN_SPACE,
/* 37 */ KEY_EN_F6,
/* 38 */ KEY_EN_6,
/* 39 */ KEY_EN_Y,
/* 40 */ KEY_EN_H,
/* 41 */ KEY_EN_B,
/* 42 */ KEY_EN_UNUSED,
/* 43 */ KEY_EN_F7,
/* 44 */ KEY_EN_7,
/* 45 */ KEY_EN_U,
/* 46 */ KEY_EN_J,
/* 47 */ KEY_EN_N,
/* 48 */ KEY_EN_UNUSED,
/* 49 */ KEY_EN_F8,
/* 50 */ KEY_EN_8,
/* 51 */ KEY_EN_I,
/* 52 */ KEY_EN_K,
/* 53 */ KEY_EN_M,
/* 54 */ KEY_EN_UNUSED,
/* 55 */ KEY_EN_F9,
/* 56 */ KEY_EN_9,
/* 57 */ KEY_EN_O,
/* 58 */ KEY_EN_L,
/* 59 */ KEY_EN_COMMA,
/* 60 */ KEY_EN_RIGHT_ALT,
/* 61 */ KEY_EN_0,
/* 62 */ KEY_EN_MINUS,
/* 63 */ KEY_EN_P,
/* 64 */ KEY_EN_SEMICOLON,
/* 65 */ KEY_EN_PERIOD,
/* 66 */ KEY_EN_FORWARD_SLASH,
/* 67 */ KEY_EN_F10,
/* 68 */ KEY_EN_EQUALS,
/* 69 */ KEY_EN_LEFT_BRACKET,
/* 70 */ KEY_EN_QUOTE,
/* 71 */ KEY_EN_UNUSED,
/* 72 */ KEY_EN_RIGHT_FUNCTION,
/* 73 */ KEY_EN_F11,
/* 74 */ KEY_EN_UNUSED,
/* 75 */ KEY_EN_RIGHT_BRACKET,
/* 76 */ KEY_EN_POUND,
/* 77 */ KEY_EN_RIGHT_SHIFT,
/* 78 */ KEY_EN_MENU,
/* 79 */ KEY_EN_F12,
/* 80 */ KEY_EN_BACKSPACE,
/* 81 */ KEY_EN_ANSI_BACK_SLASH,
/* 82 */ KEY_EN_ANSI_ENTER,
/* 83 */ KEY_EN_RIGHT_CONTROL,
/* 84 */ KEY_EN_LEFT_ARROW,
/* 85 */ KEY_EN_DOWN_ARROW,
/* 86 */ KEY_EN_RIGHT_ARROW,
/* 87 */ KEY_EN_UP_ARROW,
/* 88 */ KEY_EN_DELETE,
/* 89 */ KEY_EN_INSERT,
/* 90 */ KEY_EN_PRINT_SCREEN,
/* 91 */ KEY_EN_UNUSED,
/* 92 */ KEY_EN_UNUSED,
/* 93 */ KEY_EN_SCROLL_LOCK,
/* 94 */ KEY_EN_HOME,
/* 95 */ KEY_EN_END,
/* 96 */ KEY_EN_PAGE_DOWN,
/* 97 */ KEY_EN_UNUSED,
/* 98 */ KEY_EN_PAUSE_BREAK,
/* 99 */ KEY_EN_PAGE_UP,
/* 100 */ KEY_EN_UNUSED,
/* 101 */ KEY_EN_UNUSED,
/* 102 */ KEY_EN_UNUSED,
/* 103 */ "Key: Signature Plate",
/* 104 */ KEY_EN_UNUSED,
/* 105 */ KEY_EN_UNUSED,
};
/**------------------------------------------------------------------*\
@name Fnatic Streak
@category Keyboard
@type USB
@save :white_check_mark:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectFnaticStreakKeyboard
@comment The Fnatic Streak and miniStreak are gaming keyboards
with per-key RGB lighting. Supports hardware effects like Wave,
Pulse, Reactive, Rain, Gradient, and Fade.
\*-------------------------------------------------------------------*/
RGBController_FnaticStreak::RGBController_FnaticStreak(FnaticStreakController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetNameString();
vendor = "Fnatic";
type = DEVICE_TYPE_KEYBOARD;
description = "Fnatic Streak Keyboard";
location = controller->GetDeviceLocation();
serial = controller->GetSerialString();
version = controller->GetFirmwareVersion();
/*-----------------------------------------------------*\
| Direct mode - per-key color control |
\*-----------------------------------------------------*/
mode Direct;
Direct.name = "Direct";
Direct.value = 0xFFFF;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Direct.color_mode = MODE_COLORS_PER_LED;
Direct.brightness_min = 0;
Direct.brightness_max = 100;
Direct.brightness = 100;
modes.push_back(Direct);
/*-----------------------------------------------------*\
| Pulse mode - breathing/pulsing effect |
\*-----------------------------------------------------*/
mode Pulse;
Pulse.name = "Pulse";
Pulse.value = FNATIC_STREAK_CMD_PULSE;
Pulse.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Pulse.color_mode = MODE_COLORS_MODE_SPECIFIC;
Pulse.speed_min = 0;
Pulse.speed_max = 100;
Pulse.speed = 50;
Pulse.brightness_min = 0;
Pulse.brightness_max = 100;
Pulse.brightness = 100;
Pulse.colors_min = 1;
Pulse.colors_max = 1;
Pulse.colors.resize(1);
modes.push_back(Pulse);
/*-----------------------------------------------------*\
| Wave mode - wave rolling across keyboard |
\*-----------------------------------------------------*/
mode Wave;
Wave.name = "Wave";
Wave.value = FNATIC_STREAK_CMD_WAVE;
Wave.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_DIRECTION_LR | MODE_FLAG_HAS_DIRECTION_UD | MODE_FLAG_HAS_BRIGHTNESS;
Wave.color_mode = MODE_COLORS_MODE_SPECIFIC;
Wave.speed_min = 0;
Wave.speed_max = 100;
Wave.speed = 50;
Wave.brightness_min = 0;
Wave.brightness_max = 100;
Wave.brightness = 100;
Wave.direction = MODE_DIRECTION_RIGHT;
Wave.colors_min = 1;
Wave.colors_max = 1;
Wave.colors.resize(1);
modes.push_back(Wave);
/*-----------------------------------------------------*\
| Reactive mode - LED lights on keypress |
\*-----------------------------------------------------*/
mode Reactive;
Reactive.name = "Reactive";
Reactive.value = FNATIC_STREAK_CMD_REACTIVE;
Reactive.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Reactive.color_mode = MODE_COLORS_MODE_SPECIFIC;
Reactive.speed_min = 0;
Reactive.speed_max = 100;
Reactive.speed = 50;
Reactive.brightness_min = 0;
Reactive.brightness_max = 100;
Reactive.brightness = 100;
Reactive.colors_min = 1;
Reactive.colors_max = 1;
Reactive.colors.resize(1);
modes.push_back(Reactive);
/*-----------------------------------------------------*\
| Reactive Ripple mode - ripple effect on keypress |
\*-----------------------------------------------------*/
mode ReactiveRipple;
ReactiveRipple.name = "Reactive Ripple";
ReactiveRipple.value = FNATIC_STREAK_CMD_REACTIVE_RIPPLE;
ReactiveRipple.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
ReactiveRipple.color_mode = MODE_COLORS_MODE_SPECIFIC;
ReactiveRipple.speed_min = 0;
ReactiveRipple.speed_max = 100;
ReactiveRipple.speed = 50;
ReactiveRipple.brightness_min = 0;
ReactiveRipple.brightness_max = 100;
ReactiveRipple.brightness = 100;
ReactiveRipple.colors_min = 1;
ReactiveRipple.colors_max = 1;
ReactiveRipple.colors.resize(1);
modes.push_back(ReactiveRipple);
/*-----------------------------------------------------*\
| Rain mode - raindrop effect |
\*-----------------------------------------------------*/
mode Rain;
Rain.name = "Rain";
Rain.value = FNATIC_STREAK_CMD_RAIN;
Rain.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_DIRECTION_LR | MODE_FLAG_HAS_DIRECTION_UD | MODE_FLAG_HAS_BRIGHTNESS;
Rain.color_mode = MODE_COLORS_MODE_SPECIFIC;
Rain.speed_min = 0;
Rain.speed_max = 100;
Rain.speed = 50;
Rain.brightness_min = 0;
Rain.brightness_max = 100;
Rain.brightness = 100;
Rain.direction = MODE_DIRECTION_DOWN;
Rain.colors_min = 1;
Rain.colors_max = 1;
Rain.colors.resize(1);
modes.push_back(Rain);
/*-----------------------------------------------------*\
| Spectrum Cycle (Fade) mode - fade through colors |
\*-----------------------------------------------------*/
mode SpectrumCycle;
SpectrumCycle.name = "Spectrum Cycle";
SpectrumCycle.value = FNATIC_STREAK_CMD_FADE;
SpectrumCycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
SpectrumCycle.color_mode = MODE_COLORS_RANDOM;
SpectrumCycle.speed_min = 0;
SpectrumCycle.speed_max = 100;
SpectrumCycle.speed = 50;
SpectrumCycle.brightness_min = 0;
SpectrumCycle.brightness_max = 100;
SpectrumCycle.brightness = 100;
modes.push_back(SpectrumCycle);
/*-----------------------------------------------------*\
| Rainbow Gradient mode - static rainbow gradient |
\*-----------------------------------------------------*/
mode RainbowGradient;
RainbowGradient.name = "Rainbow Gradient";
RainbowGradient.value = FNATIC_STREAK_CMD_GRADIENT;
RainbowGradient.flags = MODE_FLAG_HAS_BRIGHTNESS;
RainbowGradient.color_mode = MODE_COLORS_NONE;
RainbowGradient.brightness_min = 0;
RainbowGradient.brightness_max = 100;
RainbowGradient.brightness = 100;
modes.push_back(RainbowGradient);
SetupZones();
/*-----------------------------------------------------*\
| Initialize last_update_time to now |
\*-----------------------------------------------------*/
last_update_time = std::chrono::steady_clock::now();
/*-----------------------------------------------------*\
| The Fnatic Streak requires periodic packets to |
| maintain direct control. Start a keepalive thread. |
\*-----------------------------------------------------*/
keepalive_thread_run = true;
keepalive_thread = new std::thread(&RGBController_FnaticStreak::KeepaliveThread, this);
}
RGBController_FnaticStreak::~RGBController_FnaticStreak()
{
keepalive_thread_run = false;
keepalive_thread->join();
delete keepalive_thread;
/*---------------------------------------------------------*\
| Delete the matrix map |
\*---------------------------------------------------------*/
for(unsigned int zone_index = 0; zone_index < zones.size(); zone_index++)
{
if(zones[zone_index].matrix_map != NULL)
{
delete zones[zone_index].matrix_map;
}
}
delete controller;
}
void RGBController_FnaticStreak::SetupZones()
{
bool is_mini = (controller->GetKeyboardType() == FNATIC_STREAK_TYPE_MINI);
unsigned int total_led_count = is_mini ? 106 : 124;
unsigned int matrix_cols = is_mini ? 18 : 22;
unsigned int* matrix_map_ptr = is_mini ? (unsigned int*)matrix_map_mini : (unsigned int*)matrix_map_full;
const char** led_name_ptr = is_mini ? led_names_mini : led_names_full;
/*---------------------------------------------------------*\
| Set up zone |
\*---------------------------------------------------------*/
zone new_zone;
new_zone.name = ZONE_EN_KEYBOARD;
new_zone.type = ZONE_TYPE_MATRIX;
new_zone.leds_min = total_led_count;
new_zone.leds_max = total_led_count;
new_zone.leds_count = total_led_count;
new_zone.matrix_map = new matrix_map_type;
new_zone.matrix_map->height = 6;
new_zone.matrix_map->width = matrix_cols;
new_zone.matrix_map->map = matrix_map_ptr;
zones.push_back(new_zone);
/*---------------------------------------------------------*\
| Set up LEDs |
\*---------------------------------------------------------*/
for(unsigned int led_idx = 0; led_idx < total_led_count; led_idx++)
{
led new_led;
new_led.name = led_name_ptr[led_idx];
new_led.value = led_idx;
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_FnaticStreak::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_FnaticStreak::DeviceUpdateLEDs()
{
last_update_time = std::chrono::steady_clock::now();
controller->SoftwareEffectStart();
/*-----------------------------------------------------*\
| Apply brightness scaling to colors |
\*-----------------------------------------------------*/
unsigned int brightness = modes[active_mode].brightness;
controller->SetLEDsDirect(leds, colors, brightness);
controller->SendRGBToDevice();
}
void RGBController_FnaticStreak::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_FnaticStreak::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_FnaticStreak::DeviceUpdateMode()
{
unsigned char r = 0;
unsigned char g = 0;
unsigned char b = 0;
unsigned char color_mode = FNATIC_STREAK_COLOR_MODE_RAINBOW;
unsigned char speed = (unsigned char)modes[active_mode].speed;
unsigned char direction = FNATIC_STREAK_DIRECTION_RIGHT;
unsigned int brightness = modes[active_mode].brightness;
/*-----------------------------------------------------*\
| Get color from mode if available and apply brightness |
\*-----------------------------------------------------*/
if(modes[active_mode].colors.size() > 0)
{
r = (unsigned char)(RGBGetRValue(modes[active_mode].colors[0]) * brightness / 100);
g = (unsigned char)(RGBGetGValue(modes[active_mode].colors[0]) * brightness / 100);
b = (unsigned char)(RGBGetBValue(modes[active_mode].colors[0]) * brightness / 100);
color_mode = FNATIC_STREAK_COLOR_MODE_SINGLE;
}
/*-----------------------------------------------------*\
| Check for random color mode |
\*-----------------------------------------------------*/
if(modes[active_mode].color_mode == MODE_COLORS_RANDOM)
{
color_mode = FNATIC_STREAK_COLOR_MODE_RAINBOW;
}
/*-----------------------------------------------------*\
| Convert OpenRGB direction to Fnatic direction |
\*-----------------------------------------------------*/
switch(modes[active_mode].direction)
{
case MODE_DIRECTION_RIGHT:
direction = FNATIC_STREAK_DIRECTION_RIGHT;
break;
case MODE_DIRECTION_LEFT:
direction = FNATIC_STREAK_DIRECTION_LEFT;
break;
case MODE_DIRECTION_DOWN:
direction = FNATIC_STREAK_DIRECTION_DOWN;
break;
case MODE_DIRECTION_UP:
direction = FNATIC_STREAK_DIRECTION_UP;
break;
default:
direction = FNATIC_STREAK_DIRECTION_RIGHT;
break;
}
/*-----------------------------------------------------*\
| Send hardware effect command based on mode |
\*-----------------------------------------------------*/
switch(modes[active_mode].value)
{
case 0xFFFF:
/*-------------------------------------------------*\
| Direct mode - handled by DeviceUpdateLEDs |
\*-------------------------------------------------*/
break;
case FNATIC_STREAK_CMD_PULSE:
controller->SetPulse(color_mode, r, g, b, speed);
break;
case FNATIC_STREAK_CMD_WAVE:
controller->SetWave(color_mode, r, g, b, speed, direction);
break;
case FNATIC_STREAK_CMD_REACTIVE:
controller->SetReactive(color_mode, r, g, b, speed, false);
break;
case FNATIC_STREAK_CMD_REACTIVE_RIPPLE:
controller->SetReactiveRipple(color_mode, r, g, b, speed, false);
break;
case FNATIC_STREAK_CMD_RAIN:
controller->SetRain(color_mode, r, g, b, speed, direction);
break;
case FNATIC_STREAK_CMD_GRADIENT:
{
/*---------------------------------------------*\
| Send rainbow gradient with brightness scaling |
\*---------------------------------------------*/
unsigned char gradient_colors[6][3] =
{
{ (unsigned char)(0xFF * brightness / 100), 0x00, 0x00 },
{ (unsigned char)(0xFF * brightness / 100), (unsigned char)(0xFF * brightness / 100), 0x00 },
{ 0x00, (unsigned char)(0xFF * brightness / 100), 0x00 },
{ 0x00, (unsigned char)(0xFF * brightness / 100), (unsigned char)(0xFF * brightness / 100) },
{ 0x00, 0x00, (unsigned char)(0xFF * brightness / 100) },
{ (unsigned char)(0xFF * brightness / 100), 0x00, (unsigned char)(0xFF * brightness / 100) },
};
unsigned char gradient_positions[6] = { 0, 20, 40, 60, 80, 100 };
controller->SetGradient(gradient_colors, gradient_positions, 6);
}
break;
case FNATIC_STREAK_CMD_FADE:
{
/*---------------------------------------------*\
| Send rainbow fade with brightness scaling |
\*---------------------------------------------*/
unsigned char fade_colors[6][3] =
{
{ (unsigned char)(0xFF * brightness / 100), 0x00, 0x00 },
{ (unsigned char)(0xFF * brightness / 100), (unsigned char)(0xFF * brightness / 100), 0x00 },
{ 0x00, (unsigned char)(0xFF * brightness / 100), 0x00 },
{ 0x00, (unsigned char)(0xFF * brightness / 100), (unsigned char)(0xFF * brightness / 100) },
{ 0x00, 0x00, (unsigned char)(0xFF * brightness / 100) },
{ (unsigned char)(0xFF * brightness / 100), 0x00, (unsigned char)(0xFF * brightness / 100) },
};
unsigned char fade_positions[6] = { 0, 20, 40, 60, 80, 100 };
controller->SetFade(FNATIC_STREAK_COLOR_MODE_RAINBOW, fade_colors, fade_positions, 6, speed);
}
break;
default:
break;
}
}
void RGBController_FnaticStreak::KeepaliveThread()
{
while(keepalive_thread_run.load())
{
if(active_mode == 0)
{
/*-------------------------------------------------*\
| In Direct mode, send keepalive to prevent |
| keyboard from reverting to profile effect |
\*-------------------------------------------------*/
if((std::chrono::steady_clock::now() - last_update_time) > std::chrono::milliseconds(500))
{
controller->SendKeepalive();
}
}
std::this_thread::sleep_for(100ms);
}
}

View File

@@ -0,0 +1,41 @@
/*---------------------------------------------------------*\
| RGBController_FnaticStreak.h |
| |
| RGBController for Fnatic Streak and miniStreak keyboard |
| |
| Based on leddy project by Hanna Czenczek |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <chrono>
#include "RGBController.h"
#include "FnaticStreakController.h"
class RGBController_FnaticStreak : public RGBController
{
public:
RGBController_FnaticStreak(FnaticStreakController* controller_ptr);
~RGBController_FnaticStreak();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
void KeepaliveThread();
private:
FnaticStreakController* controller;
std::thread* keepalive_thread;
std::atomic<bool> keepalive_thread_run;
std::chrono::time_point<std::chrono::steady_clock> last_update_time;
};