Initial QMK VialRGB controller

This commit is contained in:
Adam Honse
2025-09-29 18:26:52 -05:00
parent 93dd7f2122
commit 60b4810666
5 changed files with 1353 additions and 0 deletions

View File

@@ -0,0 +1,452 @@
/*---------------------------------------------------------*\
| QMKVialRGBController.cpp |
| |
| Driver for VialRGB QMK Keyboard Protocol |
| |
| Adam Honse <calcprogrammer1@gmail.com) 29 Sep 2025 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <stdio.h>
#include "hsv.h"
#include "QMKVialRGBController.h"
#include "StringUtils.h"
/*---------------------------------------------------------*\
| Portions of this controller adapted from Raspberry Pi |
| RPiKeyboardConfig utility: |
| https://github.com/raspberrypi/rpi-keyboard-config |
\*---------------------------------------------------------*/
QMKVialRGBController::QMKVialRGBController(hid_device *dev_handle, const char *path)
{
/*-----------------------------------------------------*\
| Initialize controller fields |
\*-----------------------------------------------------*/
dev = dev_handle;
location = path;
/*-----------------------------------------------------*\
| Read product string |
\*-----------------------------------------------------*/
wchar_t product_string[256];
int ret = hid_get_product_string(dev, product_string, 256);
if(ret != 0)
{
name = "";
}
else
{
name = StringUtils::wstring_to_string(product_string);
}
/*-----------------------------------------------------*\
| Read vendor string |
\*-----------------------------------------------------*/
wchar_t vendor_string[256];
ret = hid_get_manufacturer_string(dev, vendor_string, 256);
if(ret != 0)
{
vendor = "";
}
else
{
vendor = StringUtils::wstring_to_string(vendor_string);
}
/*-----------------------------------------------------*\
| Read serial string |
\*-----------------------------------------------------*/
wchar_t serial_string[256];
ret = hid_get_serial_number_string(dev, serial_string, 256);
if(ret != 0)
{
serial = "";
}
else
{
serial = StringUtils::wstring_to_string(serial_string);
}
/*-----------------------------------------------------*\
| Get VIA, Vial, and VialRGB information |
\*-----------------------------------------------------*/
CmdGetViaProtocolVersion(&via_protocol_version);
CmdGetVialInfo(&vial_protocol_version, &keyboard_uid, &vialrgb_flag);
CmdGetVialRGBInfo(&vialrgb_protocol_version, &maximum_brightness);
/*-----------------------------------------------------*\
| Get list of supported effects |
\*-----------------------------------------------------*/
CmdGetSupportedEffects();
/*-----------------------------------------------------*\
| Get count of LEDs |
\*-----------------------------------------------------*/
CmdGetNumberLEDs(&number_leds);
/*-----------------------------------------------------*\
| Get info and keycode for all LEDs |
\*-----------------------------------------------------*/
for(unsigned short led_index = 0; led_index < number_leds; led_index++)
{
led_info.push_back(CmdGetLEDInfo(led_index));
keycodes.push_back(CmdGetKeycode(0, led_info[led_index].row, led_info[led_index].col));
}
}
QMKVialRGBController::~QMKVialRGBController()
{
hid_close(dev);
}
std::string QMKVialRGBController::GetLocation()
{
return("HID: " + location);
}
std::string QMKVialRGBController::GetName()
{
return(name);
}
std::string QMKVialRGBController::GetSerial()
{
return(serial);
}
std::string QMKVialRGBController::GetVendor()
{
return(vendor);
}
std::string QMKVialRGBController::GetVersion()
{
/*-----------------------------------------------------*\
| Format UID string |
\*-----------------------------------------------------*/
char uid_buf[17];
snprintf(uid_buf, sizeof(uid_buf), "%016llX", keyboard_uid);
/*-----------------------------------------------------*\
| Format multi-line version text |
\*-----------------------------------------------------*/
return("VIA: " + std::to_string(via_protocol_version) + "\r\n"
+ "Vial: " + std::to_string(vial_protocol_version) + "\r\n"
+ "VialRGB: " + std::to_string(vialrgb_protocol_version) + "\r\n"
+ "UID: " + uid_buf);
}
unsigned short QMKVialRGBController::GetEffect(std::size_t effect_idx)
{
return(supported_effects[effect_idx]);
}
std::size_t QMKVialRGBController::GetEffectCount()
{
return(supported_effects.size());
}
unsigned short QMKVialRGBController::GetKeycode(unsigned short led_index)
{
return(keycodes[led_index]);
}
unsigned short QMKVialRGBController::GetLEDCount()
{
return(number_leds);
}
vialrgb_led_info QMKVialRGBController::GetLEDInfo(unsigned short led_index)
{
return(led_info[led_index]);
}
void QMKVialRGBController::GetMode
(
unsigned short* mode,
unsigned char* speed,
unsigned char* hue,
unsigned char* sat,
unsigned char* val
)
{
CmdGetMode(mode, speed, hue, sat, val);
}
void QMKVialRGBController::SendLEDs
(
unsigned short number_leds,
RGBColor* color_data
)
{
unsigned short led_start_index = 0;
unsigned char number_packet_leds = 9;
while(led_start_index < number_leds)
{
if((number_leds - led_start_index) < 9)
{
number_packet_leds = (number_leds - led_start_index);
}
CmdSendLEDs(led_start_index, number_packet_leds, &color_data[led_start_index]);
led_start_index += number_packet_leds;
}
}
void QMKVialRGBController::SetMode
(
unsigned short mode,
unsigned char speed,
unsigned char hue,
unsigned char sat,
unsigned char val
)
{
CmdSetMode(mode, speed, hue, sat, val);
}
unsigned short QMKVialRGBController::CmdGetKeycode
(
unsigned char layer,
unsigned char row,
unsigned char col
)
{
unsigned char data[5];
unsigned short keycode;
data[0] = row;
data[1] = col;
SendCheckCommand(CMD_VIA_DYNAMIC_KEYMAP_GET_KEYCODE, layer, data, 2, data, 5);
memcpy(&keycode, &data[3], sizeof(unsigned short));
return(keycode);
}
vialrgb_led_info QMKVialRGBController::CmdGetLEDInfo
(
unsigned short led_index
)
{
vialrgb_led_info data;
SendCheckCommand(CMD_LIGHTING_GET_VALUE, VIALRGB_GET_LED_INFO, (unsigned char*)&led_index, sizeof(led_index), (unsigned char*)&data, sizeof(data));
return(data);
}
void QMKVialRGBController::CmdGetMode
(
unsigned short* mode,
unsigned char* speed,
unsigned char* hue,
unsigned char* sat,
unsigned char* val
)
{
unsigned char data[6];
SendCheckCommand(CMD_LIGHTING_GET_VALUE, VIALRGB_GET_MODE, NULL, 0, data, 6);
memcpy(mode, &data[0], sizeof(unsigned short));
*speed = data[2];
*hue = data[3];
*sat = data[4];
*val = data[5];
}
void QMKVialRGBController::CmdGetNumberLEDs
(
unsigned short* number_leds
)
{
SendCheckCommand(CMD_LIGHTING_GET_VALUE, VIALRGB_GET_NUMBER_LEDS, NULL, 0, (unsigned char*)number_leds, sizeof(unsigned short));
}
void QMKVialRGBController::CmdGetSupportedEffects()
{
unsigned short packet_effects[15];
unsigned short max_effect = 0;
supported_effects.clear();
supported_effects.push_back(0);
while(max_effect < VIALRGB_EFFECT_SKIP)
{
SendCheckCommand(CMD_LIGHTING_GET_VALUE, VIALRGB_GET_SUPPORTED, (unsigned char*)&max_effect, sizeof(max_effect), (unsigned char*)packet_effects, sizeof(packet_effects));
for(unsigned int effect_idx = 0; effect_idx < 15; effect_idx++)
{
if(packet_effects[effect_idx] == VIALRGB_EFFECT_SKIP)
{
return;
}
supported_effects.push_back(packet_effects[effect_idx]);
max_effect = packet_effects[effect_idx];
}
}
}
void QMKVialRGBController::CmdGetVialInfo
(
unsigned int* vial_protocol,
unsigned long long* keyboard_uid,
unsigned char* vialrgb_flag
)
{
unsigned char data[sizeof(int) + sizeof(unsigned long long) + sizeof(unsigned char)];
SendCommand(CMD_VIAL_COMMAND, VIAL_GET_KEYBOARD_ID, NULL, 0, data, sizeof(data));
memcpy(vial_protocol, &data[0], sizeof(int));
memcpy(keyboard_uid, &data[sizeof(int)], sizeof(unsigned long long));
memcpy(vialrgb_flag, &data[sizeof(int) + sizeof(unsigned long long)], sizeof(unsigned char));
}
void QMKVialRGBController::CmdGetVialRGBInfo
(
unsigned short* vialrgb_protocol_version,
unsigned char* maximum_brightness
)
{
unsigned char data[sizeof(unsigned short) + sizeof(unsigned char)];
SendCommand(CMD_VIAL_COMMAND, VIAL_GET_KEYBOARD_ID, NULL, 0, data, sizeof(data));
memcpy(vialrgb_protocol_version, &data[0], sizeof(unsigned short));
memcpy(maximum_brightness, &data[sizeof(unsigned char)], sizeof(unsigned short));
}
void QMKVialRGBController::CmdGetViaProtocolVersion
(
unsigned short* via_protocol_version
)
{
SendCheckCommand(CMD_GET_PROTOCOL_VERSION, 0, NULL, 0, (unsigned char*)via_protocol_version, sizeof(unsigned int));
}
void QMKVialRGBController::CmdSendLEDs
(
unsigned short start_index,
unsigned char number_leds,
RGBColor* color_data
)
{
unsigned char data[30];
memcpy(&data[0], &start_index, sizeof(start_index));
memcpy(&data[2], &number_leds, sizeof(number_leds));
if(number_leds > 9)
{
number_leds = 9;
}
for(unsigned char led_index = 0; led_index < number_leds; led_index++)
{
/*-------------------------------------------------*\
| VialRGB sends direct packets in HSV for some |
| inexplicable reason, so do the RGB to HSV |
| conversion before sending |
\*-------------------------------------------------*/
hsv_t hsv_color;
rgb2hsv(color_data[led_index], &hsv_color);
data[3 + (led_index * 3)] = (unsigned char)((float)hsv_color.hue * (256.0f / 360.0f));
data[4 + (led_index * 3)] = hsv_color.saturation;
data[5 + (led_index * 3)] = hsv_color.value;
}
SendCheckCommand(CMD_LIGHTING_SET_VALUE, VIALRGB_DIRECT_FASTSET, data, sizeof(data), NULL, 0);
}
void QMKVialRGBController::CmdSetMode
(
unsigned short mode,
unsigned char speed,
unsigned char hue,
unsigned char sat,
unsigned char val
)
{
unsigned char data[6];
memcpy(&data[0], &mode, sizeof(unsigned short));
data[2] = speed;
data[3] = hue;
data[4] = sat;
data[5] = val;
SendCommand(CMD_LIGHTING_SET_VALUE, VIALRGB_SET_MODE, data, sizeof(data), NULL, 0);
}
int QMKVialRGBController::SendCommand
(
unsigned char cmd,
unsigned char subcmd,
unsigned char* data_in,
unsigned char data_in_size,
unsigned char* data_out,
unsigned char data_out_size
)
{
unsigned char usb_buf[MSG_LEN + 1];
memset(usb_buf, 0, sizeof(usb_buf));
usb_buf[0] = 0x00;
usb_buf[1] = cmd;
usb_buf[2] = subcmd;
memcpy(&usb_buf[3], data_in, data_in_size);
hid_write(dev, usb_buf, sizeof(usb_buf));
int bytes_received = hid_read_timeout(dev, usb_buf, sizeof(usb_buf)-1, 1000);
memcpy(data_out, &usb_buf[0], data_out_size);
return(bytes_received);
}
int QMKVialRGBController::SendCheckCommand
(
unsigned char cmd,
unsigned char subcmd,
unsigned char* data_in,
unsigned char data_in_size,
unsigned char* data_out,
unsigned char data_out_size
)
{
unsigned char usb_buf[MSG_LEN + 1];
memset(usb_buf, 0, sizeof(usb_buf));
usb_buf[0] = 0x00;
usb_buf[1] = cmd;
usb_buf[2] = subcmd;
memcpy(&usb_buf[3], data_in, data_in_size);
hid_write(dev, usb_buf, sizeof(usb_buf));
int bytes_received = hid_read_timeout(dev, usb_buf, sizeof(usb_buf)-1, 1000);
memcpy(data_out, &usb_buf[2], data_out_size);
return(bytes_received);
}

View File

@@ -0,0 +1,250 @@
/*---------------------------------------------------------*\
| QMKVialRGBController.h |
| |
| Driver for VialRGB QMK Keyboard Protocol |
| |
| Adam Honse <calcprogrammer1@gmail.com) 29 Sep 2025 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <hidapi.h>
#include "ResourceManager.h"
#include "RGBController.h"
#define MSG_LEN 32
enum
{
CMD_GET_PROTOCOL_VERSION = 0x01,
CMD_GET_KEYBOARD_VALUE = 0x02,
CMD_SET_KEYBOARD_VALUE = 0x03,
CMD_VIA_DYNAMIC_KEYMAP_GET_KEYCODE = 0x04,
CMD_VIA_DYNAMIC_KEYMAP_SET_KEYCODE = 0x05,
CMD_VIA_DYNAMIC_KEYMAP_RESET = 0x06,
CMD_LIGHTING_SET_VALUE = 0x07,
CMD_LIGHTING_GET_VALUE = 0x08,
CMD_VIAL_COMMAND = 0xFE,
};
enum
{
VIAL_GET_KEYBOARD_ID = 0x00,
VIAL_GET_SIZE = 0x01,
VIAL_GET_DEFINITION = 0x02,
VIAL_GET_UNLOCK_STATUS = 0x05,
VIAL_UNLOCK_START = 0x06,
VIAL_UNLOCK_POLL = 0x07,
VIAL_LOCK = 0x08,
VIALRGB_GET_INFO = 0x40,
VIALRGB_GET_MODE = 0x41,
VIALRGB_GET_SUPPORTED = 0x42,
VIALRGB_GET_NUMBER_LEDS = 0x43,
VIALRGB_GET_LED_INFO = 0x44,
VIALRGB_SET_MODE = 0x41,
VIALRGB_DIRECT_FASTSET = 0x42,
};
enum
{
VIALRGB_EFFECT_OFF,
VIALRGB_EFFECT_DIRECT,
VIALRGB_EFFECT_SOLID_COLOR,
VIALRGB_EFFECT_ALPHAS_MODS,
VIALRGB_EFFECT_GRADIENT_UP_DOWN,
VIALRGB_EFFECT_GRADIENT_LEFT_RIGHT,
VIALRGB_EFFECT_BREATHING,
VIALRGB_EFFECT_BAND_SAT,
VIALRGB_EFFECT_BAND_VAL,
VIALRGB_EFFECT_BAND_PINWHEEL_SAT,
VIALRGB_EFFECT_BAND_PINWHEEL_VAL,
VIALRGB_EFFECT_BAND_SPIRAL_SAT,
VIALRGB_EFFECT_BAND_SPIRAL_VAL,
VIALRGB_EFFECT_CYCLE_ALL,
VIALRGB_EFFECT_CYCLE_LEFT_RIGHT,
VIALRGB_EFFECT_CYCLE_UP_DOWN,
VIALRGB_EFFECT_RAINBOW_MOVING_CHEVRON,
VIALRGB_EFFECT_CYCLE_OUT_IN,
VIALRGB_EFFECT_CYCLE_OUT_IN_DUAL,
VIALRGB_EFFECT_CYCLE_PINWHEEL,
VIALRGB_EFFECT_CYCLE_SPIRAL,
VIALRGB_EFFECT_DUAL_BEACON,
VIALRGB_EFFECT_RAINBOW_BEACON,
VIALRGB_EFFECT_RAINBOW_PINWHEELS,
VIALRGB_EFFECT_RAINDROPS,
VIALRGB_EFFECT_JELLYBEAN_RAINDROPS,
VIALRGB_EFFECT_HUE_BREATHING,
VIALRGB_EFFECT_HUE_PENDULUM,
VIALRGB_EFFECT_HUE_WAVE,
VIALRGB_EFFECT_TYPING_HEATMAP,
VIALRGB_EFFECT_DIGITAL_RAIN,
VIALRGB_EFFECT_SOLID_REACTIVE_SIMPLE,
VIALRGB_EFFECT_SOLID_REACTIVE,
VIALRGB_EFFECT_SOLID_REACTIVE_WIDE,
VIALRGB_EFFECT_SOLID_REACTIVE_MULTIWIDE,
VIALRGB_EFFECT_SOLID_REACTIVE_CROSS,
VIALRGB_EFFECT_SOLID_REACTIVE_MULTICROSS,
VIALRGB_EFFECT_SOLID_REACTIVE_NEXUS,
VIALRGB_EFFECT_SOLID_REACTIVE_MULTINEXUS,
VIALRGB_EFFECT_SPLASH,
VIALRGB_EFFECT_MULTISPLASH,
VIALRGB_EFFECT_SOLID_SPLASH,
VIALRGB_EFFECT_SOLID_MULTISPLASH,
VIALRGB_EFFECT_PIXEL_RAIN,
VIALRGB_EFFECT_PIXEL_FRACTAL,
VIALRGB_EFFECT_SKIP = 0xFFFF
};
typedef struct
{
unsigned char x;
unsigned char y;
unsigned char flags;
unsigned char row;
unsigned char col;
} vialrgb_led_info;
class QMKVialRGBController
{
public:
QMKVialRGBController(hid_device *dev_handle, const char *path);
~QMKVialRGBController();
std::string GetLocation();
std::string GetName();
std::string GetSerial();
std::string GetVendor();
std::string GetVersion();
unsigned short GetEffect(std::size_t effect_idx);
std::size_t GetEffectCount();
unsigned short GetKeycode(unsigned short led_index);
unsigned short GetLEDCount();
vialrgb_led_info GetLEDInfo(unsigned short led_index);
void GetMode
(
unsigned short* mode,
unsigned char* speed,
unsigned char* hue,
unsigned char* sat,
unsigned char* val
);
void SendLEDs
(
unsigned short number_leds,
RGBColor* color_data
);
void SetMode
(
unsigned short mode,
unsigned char speed,
unsigned char hue,
unsigned char sat,
unsigned char val
);
private:
hid_device* dev;
unsigned long long keyboard_uid;
std::vector<unsigned short> keycodes;
std::vector<vialrgb_led_info> led_info;
std::string location;
unsigned char maximum_brightness;
std::string name;
unsigned short number_leds;
std::string serial;
std::vector<unsigned short> supported_effects;
std::string vendor;
unsigned short via_protocol_version;
unsigned int vial_protocol_version;
unsigned short vialrgb_protocol_version;
unsigned char vialrgb_flag;
unsigned short CmdGetKeycode
(
unsigned char layer,
unsigned char row,
unsigned char col
);
vialrgb_led_info CmdGetLEDInfo
(
unsigned short led_index
);
void CmdGetMode
(
unsigned short* mode,
unsigned char* speed,
unsigned char* hue,
unsigned char* sat,
unsigned char* val
);
void CmdGetNumberLEDs
(
unsigned short* number_leds
);
void CmdGetSupportedEffects();
void CmdGetVialInfo
(
unsigned int* vial_protocol_version,
unsigned long long* keyboard_uid,
unsigned char* vialrgb_flag
);
void CmdGetVialRGBInfo
(
unsigned short* vialrgb_protocol_version,
unsigned char* maximum_brightness
);
void CmdGetViaProtocolVersion
(
unsigned short* via_protocol_version
);
void CmdSendLEDs
(
unsigned short start_index,
unsigned char number_leds,
RGBColor* color_data
);
void CmdSetMode
(
unsigned short mode,
unsigned char speed,
unsigned char hue,
unsigned char sat,
unsigned char val
);
int SendCommand
(
unsigned char cmd,
unsigned char subcmd,
unsigned char* data_in,
unsigned char data_in_size,
unsigned char* data_out,
unsigned char data_out_size
);
int SendCheckCommand
(
unsigned char cmd,
unsigned char subcmd,
unsigned char* data_in,
unsigned char data_in_size,
unsigned char* data_out,
unsigned char data_out_size
);
};

View File

@@ -0,0 +1,42 @@
/*---------------------------------------------------------*\
| QMKVialRGBControllerDetect.cpp |
| |
| Detector for VialRGB QMK Keyboard Protocol |
| |
| Adam Honse <calcprogrammer1@gmail.com> 29 Sep 2025 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <string>
#include <hidapi.h>
#include "Detector.h"
#include "QMKVialRGBController.h"
#include "RGBController_QMKVialRGB.h"
/*-----------------------------------------------------*\
| USB IDs |
\*-----------------------------------------------------*/
#define RASPBERRY_PI_VID 0x2E8A
#define RASPBERRY_PI_500_PLUS_PID 0x0011
/*-----------------------------------------------------*\
| Usage and Usage Page |
\*-----------------------------------------------------*/
#define QMK_USAGE_PAGE 0xFF60
#define QMK_USAGE 0x61
void DetectQMKVialRGBControllers(hid_device_info *info, const std::string&)
{
hid_device *dev = hid_open_path(info->path);
if(dev)
{
QMKVialRGBController* controller = new QMKVialRGBController(dev, info->path);
RGBController_QMKVialRGB* rgb_controller = new RGBController_QMKVialRGB(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
REGISTER_HID_DETECTOR_PU( "Raspberry Pi 500+", DetectQMKVialRGBControllers, RASPBERRY_PI_VID, RASPBERRY_PI_500_PLUS_PID, QMK_USAGE_PAGE, QMK_USAGE );

View File

@@ -0,0 +1,575 @@
/*---------------------------------------------------------*\
| RGBController_QMKVialRGB.cpp |
| |
| RGBController for VialRGB QMK Keyboard Protocol |
| |
| Adam Honse <calcprogrammer1@gmail.com) 29 Sep 2025 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <map>
#include "hsv.h"
#include "RGBController_QMKVialRGB.h"
#include "RGBControllerKeyNames.h"
typedef struct
{
unsigned short value;
std::string name;
bool has_speed;
} vialrgb_mode;
static const vialrgb_mode vialrgb_modes[] =
{
{ VIALRGB_EFFECT_OFF, "Off", false },
{ VIALRGB_EFFECT_DIRECT, "Direct", false },
{ VIALRGB_EFFECT_SOLID_COLOR, "Static", false },
{ VIALRGB_EFFECT_ALPHAS_MODS, "Alphas Mods", true },
{ VIALRGB_EFFECT_GRADIENT_UP_DOWN, "Gradient Up Down", true },
{ VIALRGB_EFFECT_GRADIENT_LEFT_RIGHT, "Gradient Left Right", true },
{ VIALRGB_EFFECT_BREATHING, "Breathing", true },
{ VIALRGB_EFFECT_BAND_SAT, "Band Sat", true },
{ VIALRGB_EFFECT_BAND_VAL, "Band Val", true },
{ VIALRGB_EFFECT_BAND_PINWHEEL_SAT, "Band Pinwheel Sat", true },
{ VIALRGB_EFFECT_BAND_PINWHEEL_VAL, "Band Pinwheel Val", true },
{ VIALRGB_EFFECT_BAND_SPIRAL_SAT, "Band Spiral Sat", true },
{ VIALRGB_EFFECT_BAND_SPIRAL_VAL, "Band Spiral Val", true },
{ VIALRGB_EFFECT_CYCLE_ALL, "Cycle All", true },
{ VIALRGB_EFFECT_CYCLE_LEFT_RIGHT, "Cycle Left Right", true },
{ VIALRGB_EFFECT_CYCLE_UP_DOWN, "Cycle Up Down", true },
{ VIALRGB_EFFECT_RAINBOW_MOVING_CHEVRON, "Rainbow Moving Chevron", true },
{ VIALRGB_EFFECT_CYCLE_OUT_IN, "Cycle Out In", true },
{ VIALRGB_EFFECT_CYCLE_OUT_IN_DUAL, "Cycle Out In Dual", true },
{ VIALRGB_EFFECT_CYCLE_PINWHEEL, "Cycle Pinwheel", true },
{ VIALRGB_EFFECT_CYCLE_SPIRAL, "Cycle Spiral", true },
{ VIALRGB_EFFECT_DUAL_BEACON, "Dual Beacon", true },
{ VIALRGB_EFFECT_RAINBOW_BEACON, "Rainbow Beacon", true },
{ VIALRGB_EFFECT_RAINBOW_PINWHEELS, "Rainbow Pinwheels", true },
{ VIALRGB_EFFECT_RAINDROPS, "Raindrops", true },
{ VIALRGB_EFFECT_JELLYBEAN_RAINDROPS, "Jellybean Raindrops", true },
{ VIALRGB_EFFECT_HUE_BREATHING, "Hue Breathing", true },
{ VIALRGB_EFFECT_HUE_PENDULUM, "Hue Pendulum", true },
{ VIALRGB_EFFECT_HUE_WAVE, "Hue Wave", true },
{ VIALRGB_EFFECT_TYPING_HEATMAP, "Typing Heatmap", true },
{ VIALRGB_EFFECT_DIGITAL_RAIN, "Digital Rain", true },
{ VIALRGB_EFFECT_SOLID_REACTIVE_SIMPLE, "Solid Reactive Simple", true },
{ VIALRGB_EFFECT_SOLID_REACTIVE, "Solid Reactive", true },
{ VIALRGB_EFFECT_SOLID_REACTIVE_WIDE, "Solid Reactive Wide", true },
{ VIALRGB_EFFECT_SOLID_REACTIVE_MULTIWIDE, "Solid Reactive Multiwide", true },
{ VIALRGB_EFFECT_SOLID_REACTIVE_CROSS, "Solid Reactive Cross", true },
{ VIALRGB_EFFECT_SOLID_REACTIVE_MULTICROSS, "Solid Reactive Multicross", true },
{ VIALRGB_EFFECT_SOLID_REACTIVE_NEXUS, "Solid Reactive Nexus", true },
{ VIALRGB_EFFECT_SOLID_REACTIVE_MULTINEXUS, "Solid Reactive Multinexus", true },
{ VIALRGB_EFFECT_SPLASH, "Splash", true },
{ VIALRGB_EFFECT_MULTISPLASH, "Multisplash", true },
{ VIALRGB_EFFECT_SOLID_SPLASH, "Solid Splash", true },
{ VIALRGB_EFFECT_SOLID_MULTISPLASH, "Solid Multisplash", true },
{ VIALRGB_EFFECT_PIXEL_RAIN, "Pixel Rain", true },
{ VIALRGB_EFFECT_PIXEL_FRACTAL, "Pixel Fractal", true },
};
enum
{
KC_NO = 0x0000,
KC_TRANSPARENT = 0x0001,
KC_A = 0x0004,
KC_B = 0x0005,
KC_C = 0x0006,
KC_D = 0x0007,
KC_E = 0x0008,
KC_F = 0x0009,
KC_G = 0x000A,
KC_H = 0x000B,
KC_I = 0x000C,
KC_J = 0x000D,
KC_K = 0x000E,
KC_L = 0x000F,
KC_M = 0x0010,
KC_N = 0x0011,
KC_O = 0x0012,
KC_P = 0x0013,
KC_Q = 0x0014,
KC_R = 0x0015,
KC_S = 0x0016,
KC_T = 0x0017,
KC_U = 0x0018,
KC_V = 0x0019,
KC_W = 0x001A,
KC_X = 0x001B,
KC_Y = 0x001C,
KC_Z = 0x001D,
KC_1 = 0x001E,
KC_2 = 0x001F,
KC_3 = 0x0020,
KC_4 = 0x0021,
KC_5 = 0x0022,
KC_6 = 0x0023,
KC_7 = 0x0024,
KC_8 = 0x0025,
KC_9 = 0x0026,
KC_0 = 0x0027,
KC_ENTER = 0x0028,
KC_ESCAPE = 0x0029,
KC_BACKSPACE = 0x002A,
KC_TAB = 0x002B,
KC_SPACE = 0x002C,
KC_MINUS = 0x002D,
KC_EQUAL = 0x002E,
KC_LEFT_BRACKET = 0x002F,
KC_RIGHT_BRACKET = 0x0030,
KC_BACKSLASH = 0x0031,
KC_NONUS_HASH = 0x0032,
KC_SEMICOLON = 0x0033,
KC_QUOTE = 0x0034,
KC_GRAVE = 0x0035,
KC_COMMA = 0x0036,
KC_DOT = 0x0037,
KC_SLASH = 0x0038,
KC_CAPS_LOCK = 0x0039,
KC_F1 = 0x003A,
KC_F2 = 0x003B,
KC_F3 = 0x003C,
KC_F4 = 0x003D,
KC_F5 = 0x003E,
KC_F6 = 0x003F,
KC_F7 = 0x0040,
KC_F8 = 0x0041,
KC_F9 = 0x0042,
KC_F10 = 0x0043,
KC_F11 = 0x0044,
KC_F12 = 0x0045,
KC_PRINT_SCREEN = 0x0046,
KC_SCROLL_LOCK = 0x0047,
KC_PAUSE = 0x0048,
KC_INSERT = 0x0049,
KC_HOME = 0x004A,
KC_PAGE_UP = 0x004B,
KC_DELETE = 0x004C,
KC_END = 0x004D,
KC_PAGE_DOWN = 0x004E,
KC_RIGHT = 0x004F,
KC_LEFT = 0x0050,
KC_DOWN = 0x0051,
KC_UP = 0x0052,
KC_NUM_LOCK = 0x0053,
KC_KP_SLASH = 0x0054,
KC_KP_ASTERISK = 0x0055,
KC_KP_MINUS = 0x0056,
KC_KP_PLUS = 0x0057,
KC_KP_ENTER = 0x0058,
KC_KP_1 = 0x0059,
KC_KP_2 = 0x005A,
KC_KP_3 = 0x005B,
KC_KP_4 = 0x005C,
KC_KP_5 = 0x005D,
KC_KP_6 = 0x005E,
KC_KP_7 = 0x005F,
KC_KP_8 = 0x0060,
KC_KP_9 = 0x0061,
KC_KP_0 = 0x0062,
KC_KP_DOT = 0x0063,
KC_NONUS_BACKSLASH = 0x0064,
KC_APPLICATION = 0x0065,
KC_KB_POWER = 0x0066,
KC_KP_EQUAL = 0x0067,
KC_F13 = 0x0068,
KC_F14 = 0x0069,
KC_F15 = 0x006A,
KC_F16 = 0x006B,
KC_F17 = 0x006C,
KC_F18 = 0x006D,
KC_F19 = 0x006E,
KC_F20 = 0x006F,
KC_F21 = 0x0070,
KC_F22 = 0x0071,
KC_F23 = 0x0072,
KC_F24 = 0x0073,
KC_EXECUTE = 0x0074,
KC_HELP = 0x0075,
KC_MENU = 0x0076,
KC_SELECT = 0x0077,
KC_STOP = 0x0078,
KC_AGAIN = 0x0079,
KC_UNDO = 0x007A,
KC_CUT = 0x007B,
KC_COPY = 0x007C,
KC_PASTE = 0x007D,
KC_FIND = 0x007E,
KC_KB_MUTE = 0x007F,
KC_KB_VOLUME_UP = 0x0080,
KC_KB_VOLUME_DOWN = 0x0081,
KC_LOCKING_CAPS_LOCK = 0x0082,
KC_LOCKING_NUM_LOCK = 0x0083,
KC_LOCKING_SCROLL_LOCK = 0x0084,
KC_KP_COMMA = 0x0085,
KC_KP_EQUAL_AS400 = 0x0086,
KC_INTERNATIONAL_1 = 0x0087,
KC_INTERNATIONAL_2 = 0x0088,
KC_INTERNATIONAL_3 = 0x0089,
KC_INTERNATIONAL_4 = 0x008A,
KC_INTERNATIONAL_5 = 0x008B,
KC_INTERNATIONAL_6 = 0x008C,
KC_INTERNATIONAL_7 = 0x008D,
KC_INTERNATIONAL_8 = 0x008E,
KC_INTERNATIONAL_9 = 0x008F,
KC_LANGUAGE_1 = 0x0090,
KC_LANGUAGE_2 = 0x0091,
KC_LANGUAGE_3 = 0x0092,
KC_LANGUAGE_4 = 0x0093,
KC_LANGUAGE_5 = 0x0094,
KC_LANGUAGE_6 = 0x0095,
KC_LANGUAGE_7 = 0x0096,
KC_LANGUAGE_8 = 0x0097,
KC_LANGUAGE_9 = 0x0098,
KC_ALTERNATE_ERASE = 0x0099,
KC_SYSTEM_REQUEST = 0x009A,
KC_CANCEL = 0x009B,
KC_CLEAR = 0x009C,
KC_PRIOR = 0x009D,
KC_RETURN = 0x009E,
KC_SEPARATOR = 0x009F,
KC_OUT = 0x00A0,
KC_OPER = 0x00A1,
KC_CLEAR_AGAIN = 0x00A2,
KC_CRSEL = 0x00A3,
KC_EXSEL = 0x00A4,
KC_SYSTEM_POWER = 0x00A5,
KC_SYSTEM_SLEEP = 0x00A6,
KC_SYSTEM_WAKE = 0x00A7,
KC_AUDIO_MUTE = 0x00A8,
KC_AUDIO_VOL_UP = 0x00A9,
KC_AUDIO_VOL_DOWN = 0x00AA,
KC_MEDIA_NEXT_TRACK = 0x00AB,
KC_MEDIA_PREV_TRACK = 0x00AC,
KC_MEDIA_STOP = 0x00AD,
KC_MEDIA_PLAY_PAUSE = 0x00AE,
KC_MEDIA_SELECT = 0x00AF,
KC_MEDIA_EJECT = 0x00B0,
KC_MAIL = 0x00B1,
KC_CALCULATOR = 0x00B2,
KC_MY_COMPUTER = 0x00B3,
KC_WWW_SEARCH = 0x00B4,
KC_WWW_HOME = 0x00B5,
KC_WWW_BACK = 0x00B6,
KC_WWW_FORWARD = 0x00B7,
KC_WWW_STOP = 0x00B8,
KC_WWW_REFRESH = 0x00B9,
KC_WWW_FAVORITES = 0x00BA,
KC_MEDIA_FAST_FORWARD = 0x00BB,
KC_MEDIA_REWIND = 0x00BC,
KC_BRIGHTNESS_UP = 0x00BD,
KC_BRIGHTNESS_DOWN = 0x00BE,
KC_CONTROL_PANEL = 0x00BF,
KC_ASSISTANT = 0x00C0,
KC_MISSION_CONTROL = 0x00C1,
KC_LAUNCHPAD = 0x00C2,
KC_LEFT_CTRL = 0x00E0,
KC_LEFT_SHIFT = 0x00E1,
KC_LEFT_ALT = 0x00E2,
KC_LEFT_GUI = 0x00E3,
KC_RIGHT_CTRL = 0x00E4,
KC_RIGHT_SHIFT = 0x00E5,
KC_RIGHT_ALT = 0x00E6,
KC_RIGHT_GUI = 0x00E7,
};
static std::map<unsigned short, std::string> vialrgb_keynames =
{
{ KC_NO, "" },
{ KC_TRANSPARENT, "" },
{ KC_A, KEY_EN_A },
{ KC_B, KEY_EN_B },
{ KC_C, KEY_EN_C },
{ KC_D, KEY_EN_D },
{ KC_E, KEY_EN_E },
{ KC_F, KEY_EN_F },
{ KC_G, KEY_EN_G },
{ KC_H, KEY_EN_H },
{ KC_I, KEY_EN_I },
{ KC_J, KEY_EN_J },
{ KC_K, KEY_EN_K },
{ KC_L, KEY_EN_L },
{ KC_M, KEY_EN_M },
{ KC_N, KEY_EN_N },
{ KC_O, KEY_EN_O },
{ KC_P, KEY_EN_P },
{ KC_Q, KEY_EN_Q },
{ KC_R, KEY_EN_R },
{ KC_S, KEY_EN_S },
{ KC_T, KEY_EN_T },
{ KC_U, KEY_EN_U },
{ KC_V, KEY_EN_V },
{ KC_W, KEY_EN_W },
{ KC_X, KEY_EN_X },
{ KC_Y, KEY_EN_Y },
{ KC_Z, KEY_EN_Z },
{ KC_1, KEY_EN_1 },
{ KC_2, KEY_EN_2 },
{ KC_3, KEY_EN_3 },
{ KC_4, KEY_EN_4 },
{ KC_5, KEY_EN_5 },
{ KC_6, KEY_EN_6 },
{ KC_7, KEY_EN_7 },
{ KC_8, KEY_EN_8 },
{ KC_9, KEY_EN_9 },
{ KC_0, KEY_EN_0 },
{ KC_ENTER, KEY_EN_ANSI_ENTER },
{ KC_ESCAPE, KEY_EN_ESCAPE },
{ KC_BACKSPACE, KEY_EN_BACKSPACE },
{ KC_TAB, KEY_EN_TAB },
{ KC_SPACE, KEY_EN_SPACE },
{ KC_MINUS, KEY_EN_MINUS },
{ KC_EQUAL, KEY_EN_EQUALS },
{ KC_LEFT_BRACKET, KEY_EN_LEFT_BRACKET },
{ KC_RIGHT_BRACKET, KEY_EN_RIGHT_BRACKET },
{ KC_BACKSLASH, KEY_EN_BACK_SLASH },
{ KC_NONUS_HASH, KEY_EN_POUND },
{ KC_SEMICOLON, KEY_EN_SEMICOLON },
{ KC_QUOTE, KEY_EN_QUOTE },
{ KC_GRAVE, KEY_EN_BACK_TICK },
{ KC_COMMA, KEY_EN_COMMA },
{ KC_DOT, KEY_EN_PERIOD },
{ KC_SLASH, KEY_EN_FORWARD_SLASH },
{ KC_CAPS_LOCK, KEY_EN_CAPS_LOCK },
{ KC_F1, KEY_EN_F1 },
{ KC_F2, KEY_EN_F2 },
{ KC_F3, KEY_EN_F3 },
{ KC_F4, KEY_EN_F4 },
{ KC_F5, KEY_EN_F5 },
{ KC_F6, KEY_EN_F6 },
{ KC_F7, KEY_EN_F7 },
{ KC_F8, KEY_EN_F8 },
{ KC_F9, KEY_EN_F9 },
{ KC_F10, KEY_EN_F10 },
{ KC_F11, KEY_EN_F11 },
{ KC_F12, KEY_EN_F12 },
{ KC_PRINT_SCREEN, KEY_EN_PRINT_SCREEN },
{ KC_SCROLL_LOCK, KEY_EN_SCROLL_LOCK },
{ KC_PAUSE, KEY_EN_PAUSE_BREAK },
{ KC_INSERT, KEY_EN_INSERT },
{ KC_HOME, KEY_EN_HOME },
{ KC_PAGE_UP, KEY_EN_PAGE_UP },
{ KC_DELETE, KEY_EN_DELETE },
{ KC_END, KEY_EN_END },
{ KC_PAGE_DOWN, KEY_EN_PAGE_DOWN },
{ KC_RIGHT, KEY_EN_RIGHT_ARROW },
{ KC_LEFT, KEY_EN_LEFT_ARROW },
{ KC_DOWN, KEY_EN_DOWN_ARROW },
{ KC_UP, KEY_EN_UP_ARROW },
{ KC_NUM_LOCK, KEY_EN_NUMPAD_LOCK },
{ KC_KP_SLASH, KEY_EN_NUMPAD_DIVIDE },
{ KC_KP_ASTERISK, KEY_EN_NUMPAD_TIMES },
{ KC_KP_MINUS, KEY_EN_NUMPAD_MINUS },
{ KC_KP_PLUS, KEY_EN_NUMPAD_PLUS },
{ KC_KP_ENTER, KEY_EN_NUMPAD_ENTER },
{ KC_KP_1, KEY_EN_NUMPAD_1 },
{ KC_KP_2, KEY_EN_NUMPAD_2 },
{ KC_KP_3, KEY_EN_NUMPAD_3 },
{ KC_KP_4, KEY_EN_NUMPAD_4 },
{ KC_KP_5, KEY_EN_NUMPAD_5 },
{ KC_KP_6, KEY_EN_NUMPAD_6 },
{ KC_KP_7, KEY_EN_NUMPAD_7 },
{ KC_KP_8, KEY_EN_NUMPAD_8 },
{ KC_KP_9, KEY_EN_NUMPAD_9 },
{ KC_KP_0, KEY_EN_NUMPAD_0 },
{ KC_KP_DOT, KEY_EN_NUMPAD_PERIOD },
{ KC_LEFT_CTRL, KEY_EN_LEFT_CONTROL },
{ KC_LEFT_SHIFT, KEY_EN_LEFT_SHIFT },
{ KC_LEFT_ALT, KEY_EN_LEFT_ALT },
{ KC_LEFT_GUI, KEY_EN_LEFT_WINDOWS },
{ KC_RIGHT_CTRL, KEY_EN_RIGHT_CONTROL },
{ KC_RIGHT_SHIFT, KEY_EN_RIGHT_SHIFT },
{ KC_RIGHT_ALT, KEY_EN_RIGHT_ALT },
{ KC_RIGHT_GUI, KEY_EN_RIGHT_WINDOWS },
};
RGBController_QMKVialRGB::RGBController_QMKVialRGB(QMKVialRGBController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetName();
description = "QMK VialRGB Device";
vendor = controller->GetVendor();
location = controller->GetLocation();
serial = controller->GetSerial();
version = controller->GetVersion();
type = DEVICE_TYPE_KEYBOARD;
/*-----------------------------------------------------*\
| Read mode list |
\*-----------------------------------------------------*/
for(std::size_t effect_idx = 0; effect_idx < controller->GetEffectCount(); effect_idx++)
{
mode new_mode;
new_mode.name = vialrgb_modes[controller->GetEffect(effect_idx)].name;
new_mode.value = vialrgb_modes[controller->GetEffect(effect_idx)].value;
if(new_mode.value == VIALRGB_EFFECT_DIRECT)
{
new_mode.flags = MODE_FLAG_HAS_PER_LED_COLOR;
new_mode.color_mode = MODE_COLORS_PER_LED;
}
if(new_mode.value >= VIALRGB_EFFECT_SOLID_COLOR)
{
new_mode.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
new_mode.color_mode = MODE_COLORS_MODE_SPECIFIC;
new_mode.colors_min = 1;
new_mode.colors_max = 1;
new_mode.colors.resize(1);
}
if(vialrgb_modes[controller->GetEffect(effect_idx)].has_speed)
{
new_mode.flags |= MODE_FLAG_HAS_SPEED;
new_mode.speed_min = 0;
new_mode.speed_max = 255;
new_mode.speed = 128;
}
modes.push_back(new_mode);
}
/*-----------------------------------------------------*\
| Read current mode |
\*-----------------------------------------------------*/
unsigned short cur_mode;
unsigned char cur_speed;
unsigned char cur_hue;
unsigned char cur_sat;
unsigned char cur_val;
controller->GetMode(&cur_mode, &cur_speed, &cur_hue, &cur_sat, &cur_val);
active_mode = cur_mode;
if(modes[active_mode].flags & MODE_FLAG_HAS_SPEED)
{
modes[active_mode].speed = cur_speed;
}
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC)
{
hsv_t hsv_color;
hsv_color.hue = ((float)cur_hue * (360.0f / 256.0f));
hsv_color.saturation = cur_sat;
hsv_color.value = cur_val;
RGBColor rgb_color = hsv2rgb(&hsv_color);
modes[active_mode].colors[0] = rgb_color;
}
SetupZones();
}
RGBController_QMKVialRGB::~RGBController_QMKVialRGB()
{
delete controller;
}
void RGBController_QMKVialRGB::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++)
{
vialrgb_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++)
{
vialrgb_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 = vialrgb_keynames[controller->GetKeycode(led_idx)];
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_QMKVialRGB::ResizeZone(int zone, int new_size)
{
}
void RGBController_QMKVialRGB::DeviceUpdateLEDs()
{
controller->SendLEDs(colors.size(), colors.data());
}
void RGBController_QMKVialRGB::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_QMKVialRGB::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_QMKVialRGB::DeviceUpdateMode()
{
unsigned char hue = 0;
unsigned char sat = 0;
unsigned char val = 0;
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);
}

View File

@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| RGBController_QMKVialRGB.h |
| |
| RGBController for VialRGB QMK Keyboard Protocol |
| |
| Adam Honse <calcprogrammer1@gmail.com) 29 Sep 2025 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "QMKVialRGBController.h"
#include "RGBController.h"
class RGBController_QMKVialRGB : public RGBController
{
public:
RGBController_QMKVialRGB(QMKVialRGBController* controller_ptr);
~RGBController_QMKVialRGB();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
QMKVialRGBController* controller;
};