mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2026-06-24 13:48:45 -04:00
240 lines
9.4 KiB
C++
240 lines
9.4 KiB
C++
/*---------------------------------------------------------*\
|
|
| RGBController_QMKKeychron.cpp |
|
|
| |
|
|
| RGBController for Keychron QMK-based keyboards |
|
|
| |
|
|
| Amadej Kastelic 21 Jun 2026 |
|
|
| Adam Honse <calcprogrammer1@gmail.com> 22 Jun 2026 |
|
|
| |
|
|
| This file is part of the OpenRGB project |
|
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
|
\*---------------------------------------------------------*/
|
|
|
|
#include <cstring>
|
|
#include "hsv.h"
|
|
#include "RGBController_QMKKeychron.h"
|
|
#include "QMKKeycodes.h"
|
|
#include "QMKKeychronController.h"
|
|
|
|
/**------------------------------------------------------------------*\
|
|
@name QMK Keychron
|
|
@category Keyboard
|
|
@type USB
|
|
@save :white_check_mark:
|
|
@direct :white_check_mark:
|
|
@effects :white_check_mark:
|
|
@detectors DetectQMKKeychronController
|
|
@comment
|
|
\*-------------------------------------------------------------------*/
|
|
|
|
typedef struct
|
|
{
|
|
std::string name;
|
|
int value;
|
|
int flags;
|
|
} kc_effect;
|
|
|
|
static const kc_effect kc_effects[] =
|
|
{
|
|
{ "Direct", 0xFFFF, MODE_FLAG_HAS_PER_LED_COLOR },
|
|
{ "Solid Color", 1, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Breathing", 2, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Band Spiral", 3, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Cycle All", 4, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Cycle Left Right", 5, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Cycle Up Down", 6, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Rainbow Moving Chevron", 7, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Cycle Out In", 8, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Cycle Out In Dual", 9, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Cycle Pinwheel", 10, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Cycle Spiral", 11, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Dual Beacon", 12, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Rainbow Beacon", 13, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Jellybean Raindrops", 14, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Pixel Rain", 15, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Typing Heatmap", 16, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Digital Rain", 17, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Solid Reactive Simple", 18, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Solid Reactive Multiwide", 19, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Solid Reactive Multinexus", 20, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Splash", 21, MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE },
|
|
{ "Solid Splash", 22, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE },
|
|
};
|
|
|
|
RGBController_QMKKeychron::RGBController_QMKKeychron(QMKKeychronController* controller_ptr)
|
|
{
|
|
controller = controller_ptr;
|
|
|
|
name = controller->GetName();
|
|
vendor = controller->GetVendor();
|
|
type = DEVICE_TYPE_KEYBOARD;
|
|
description = "QMK Keychron Device";
|
|
location = controller->GetLocation();
|
|
serial = controller->GetSerial();
|
|
version = controller->GetVersion();
|
|
|
|
for(const kc_effect& effect : kc_effects)
|
|
{
|
|
mode m;
|
|
m.name = effect.name;
|
|
m.value = effect.value;
|
|
m.flags = effect.flags;
|
|
|
|
if(m.flags & MODE_FLAG_HAS_MODE_SPECIFIC_COLOR)
|
|
{
|
|
m.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
|
m.colors_min = 1;
|
|
m.colors_max = 1;
|
|
m.colors.resize(1);
|
|
}
|
|
else if(m.flags & MODE_FLAG_HAS_PER_LED_COLOR)
|
|
{
|
|
m.color_mode = MODE_COLORS_PER_LED;
|
|
m.colors_min = 0;
|
|
m.colors_max = 0;
|
|
m.colors.resize(0);
|
|
}
|
|
else
|
|
{
|
|
m.color_mode = MODE_COLORS_NONE;
|
|
m.colors_min = 0;
|
|
m.colors_max = 0;
|
|
m.colors.resize(0);
|
|
}
|
|
|
|
if(m.flags & MODE_FLAG_HAS_SPEED)
|
|
{
|
|
m.speed_min = KEYCHRON_QHE_MIN_SPEED;
|
|
m.speed_max = KEYCHRON_QHE_MAX_SPEED;
|
|
m.speed = KEYCHRON_QHE_MAX_SPEED / 2;
|
|
}
|
|
|
|
if(m.flags & MODE_FLAG_HAS_BRIGHTNESS)
|
|
{
|
|
m.brightness_min = KEYCHRON_QHE_MIN_BRIGHTNESS;
|
|
m.brightness_max = KEYCHRON_QHE_MAX_BRIGHTNESS;
|
|
m.brightness = KEYCHRON_QHE_MAX_BRIGHTNESS;
|
|
}
|
|
|
|
modes.push_back(m);
|
|
}
|
|
|
|
SetupZones();
|
|
}
|
|
|
|
RGBController_QMKKeychron::~RGBController_QMKKeychron()
|
|
{
|
|
delete controller;
|
|
}
|
|
|
|
void RGBController_QMKKeychron::SetupZones()
|
|
{
|
|
/*-----------------------------------------------------*\
|
|
| Build matrix map |
|
|
\*-----------------------------------------------------*/
|
|
unsigned char max_col = 0;
|
|
unsigned char max_row = 0;
|
|
|
|
for(unsigned short led_index = 0; led_index < controller->GetLEDCount(); led_index++)
|
|
{
|
|
kc_led_info info = controller->GetLEDInfo(led_index);
|
|
|
|
if(info.col > max_col)
|
|
{
|
|
max_col = info.col;
|
|
}
|
|
|
|
if(info.row > max_row)
|
|
{
|
|
max_row = info.row;
|
|
}
|
|
}
|
|
|
|
unsigned char height = max_row + 1;
|
|
unsigned char width = max_col + 1;
|
|
|
|
unsigned int* matrix_map = new unsigned int[width * height];
|
|
|
|
memset(matrix_map, 0xFF, (sizeof(unsigned int) * (width * height)));
|
|
|
|
for(unsigned short led_index = 0; led_index < controller->GetLEDCount(); led_index++)
|
|
{
|
|
kc_led_info info = controller->GetLEDInfo(led_index);
|
|
|
|
matrix_map[(width * info.row) + info.col] = (unsigned int)led_index;
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Create keyboard zone |
|
|
\*-----------------------------------------------------*/
|
|
zone keyboard;
|
|
|
|
keyboard.name = "Keyboard";
|
|
keyboard.type = ZONE_TYPE_MATRIX;
|
|
keyboard.leds_min = controller->GetLEDCount();
|
|
keyboard.leds_max = controller->GetLEDCount();
|
|
keyboard.leds_count = controller->GetLEDCount();
|
|
keyboard.matrix_map = new matrix_map_type;
|
|
keyboard.matrix_map->height = height;
|
|
keyboard.matrix_map->width = width;
|
|
keyboard.matrix_map->map = matrix_map;
|
|
|
|
zones.push_back(keyboard);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Create keyboard LEDs |
|
|
\*-----------------------------------------------------*/
|
|
for(unsigned short led_idx = 0; led_idx < controller->GetLEDCount(); led_idx++)
|
|
{
|
|
led new_led;
|
|
new_led.name = qmk_keynames[controller->GetKeycode(led_idx)];
|
|
|
|
leds.push_back(new_led);
|
|
}
|
|
|
|
SetupColors();
|
|
}
|
|
|
|
void RGBController_QMKKeychron::ResizeZone(int /*zone*/, int /*new_size*/)
|
|
{
|
|
}
|
|
|
|
void RGBController_QMKKeychron::DeviceUpdateLEDs()
|
|
{
|
|
controller->SendLEDs((unsigned short)colors.size(), colors.data());
|
|
}
|
|
|
|
void RGBController_QMKKeychron::UpdateZoneLEDs(int /*zone*/)
|
|
{
|
|
DeviceUpdateLEDs();
|
|
}
|
|
|
|
void RGBController_QMKKeychron::UpdateSingleLED(int /*led*/)
|
|
{
|
|
DeviceUpdateLEDs();
|
|
}
|
|
|
|
void RGBController_QMKKeychron::DeviceUpdateMode()
|
|
{
|
|
unsigned char hue = 0;
|
|
unsigned char sat = 255;
|
|
unsigned char val = modes[active_mode].brightness;
|
|
|
|
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC)
|
|
{
|
|
hsv_t hsv_color;
|
|
rgb2hsv(modes[active_mode].colors[0], &hsv_color);
|
|
|
|
hue = (unsigned char)((float)hsv_color.hue * (256.0f / 360.0f));
|
|
sat = hsv_color.saturation;
|
|
val = hsv_color.value;
|
|
}
|
|
|
|
controller->SetMode(modes[active_mode].value, modes[active_mode].speed, hue, sat, val);
|
|
}
|
|
|
|
void RGBController_QMKKeychron::DeviceSaveMode()
|
|
{
|
|
controller->SaveMode();
|
|
}
|