diff --git a/Controllers/QMKOpenRGBController/QMKOpenRGBController.h b/Controllers/QMKOpenRGBController/QMKOpenRGBController.h index f54a8ec9..d0c4c0fb 100644 --- a/Controllers/QMKOpenRGBController/QMKOpenRGBController.h +++ b/Controllers/QMKOpenRGBController/QMKOpenRGBController.h @@ -78,6 +78,9 @@ enum Modes QMK_OPENRGB_MODE_MULTISPLASH, QMK_OPENRGB_MODE_SOLID_SPLASH, QMK_OPENRGB_MODE_SOLID_MULTISPLASH, + QMK_OPENRGB_MODE_PIXEL_RAIN, + QMK_OPENRGB_MODE_PIXEL_FLOW, + QMK_OPENRGB_MODE_PIXEL_FRACTAL, }; enum SpeedCommands diff --git a/Controllers/QMKOpenRGBController/QMKOpenRGBControllerDetect.cpp b/Controllers/QMKOpenRGBController/QMKOpenRGBControllerDetect.cpp index 78763528..8d997241 100644 --- a/Controllers/QMKOpenRGBController/QMKOpenRGBControllerDetect.cpp +++ b/Controllers/QMKOpenRGBController/QMKOpenRGBControllerDetect.cpp @@ -18,6 +18,7 @@ #include "RGBController_QMKOpenRGBRev9.h" #include "RGBController_QMKOpenRGBRevB.h" #include "RGBController_QMKOpenRGBRevD.h" +#include "RGBController_QMKOpenRGBRevE.h" #include "LogManager.h" #include @@ -28,6 +29,7 @@ #define QMK_OPENRGB_PROTOCOL_VERSION_B 0x0B #define QMK_OPENRGB_PROTOCOL_VERSION_C 0x0C #define QMK_OPENRGB_PROTOCOL_VERSION_D 0x0D +#define QMK_OPENRGB_PROTOCOL_VERSION_E 0x0E /*-----------------------------------------------------*\ | Usage and Usage Page | diff --git a/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevE.cpp b/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevE.cpp new file mode 100644 index 00000000..8ce811dd --- /dev/null +++ b/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevE.cpp @@ -0,0 +1,807 @@ +/*-------------------------------------------------------------------*\ +| RGBController_QMKOpenRGBRevE.cpp | +| | +| Driver for QMK keyboards using OpenRGB Protocol (Revision E) | +| | +| Kasper 10th Octobber 2020 | +| Jath03 28th May 2021 | +| HorrorTroll 11th July 2022 | +\*-------------------------------------------------------------------*/ + +#include "hsv.h" +#include "LogManager.h" +#include "RGBController_QMKOpenRGBRevE.h" + +RGBController_QMKOpenRGBRevE::RGBController_QMKOpenRGBRevE(QMKOpenRGBRevDController* controller_ptr, bool save) +{ + controller = controller_ptr; + + name = controller->GetDeviceName(); + vendor = controller->GetDeviceVendor(); + description = "QMK OpenRGB Device (Protocol Version " + std::to_string(controller->GetProtocolVersion()) + ")"; + type = DEVICE_TYPE_KEYBOARD; + location = controller->GetLocation(); + version = controller->GetQMKVersion(); + + unsigned int current_mode = 1; + std::vector enabled_modes = controller->GetEnabledModes(); + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_COLOR) != enabled_modes.end()) + { + InitializeMode("Static", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_ALPHA_MOD) != enabled_modes.end()) + { + InitializeMode("Alpha Mod", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_GRADIENT_UP_DOWN) != enabled_modes.end()) + { + InitializeMode("Gradient Up Down", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_GRADIENT_LEFT_RIGHT) != enabled_modes.end()) + { + InitializeMode("Gradient Left Right", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_BREATHING) != enabled_modes.end()) + { + InitializeMode("Breathing", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_BAND_SAT) != enabled_modes.end()) + { + InitializeMode("Band Saturation", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_BAND_VAL) != enabled_modes.end()) + { + InitializeMode("Band Value", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_BAND_PINWHEEL_SAT) != enabled_modes.end()) + { + InitializeMode("Band Pinwheel Saturation", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_BAND_PINWHEEL_VAL) != enabled_modes.end()) + { + InitializeMode("Band Pinwheel Value", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_BAND_SPIRAL_SAT) != enabled_modes.end()) + { + InitializeMode("Band Spiral Saturation", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_BAND_SPIRAL_VAL) != enabled_modes.end()) + { + InitializeMode("Band Spiral Value", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_CYCLE_ALL) != enabled_modes.end()) + { + InitializeMode("Cycle All", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_CYCLE_LEFT_RIGHT) != enabled_modes.end()) + { + InitializeMode("Cycle Left Right", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_CYCLE_UP_DOWN) != enabled_modes.end()) + { + InitializeMode("Cycle Up Down", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_RAINBOW_MOVING_CHEVRON) != enabled_modes.end()) + { + InitializeMode("Rainbow Moving Chevron", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_CYCLE_OUT_IN) != enabled_modes.end()) + { + InitializeMode("Cycle Out In", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_CYCLE_OUT_IN_DUAL) != enabled_modes.end()) + { + InitializeMode("Cycle Out In Dual", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_CYCLE_PINWHEEL) != enabled_modes.end()) + { + InitializeMode("Cycle Pinwheel", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_CYCLE_SPIRAL) != enabled_modes.end()) + { + InitializeMode("Cycle Spiral", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_DUAL_BEACON) != enabled_modes.end()) + { + InitializeMode("Dual Beacon", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_RAINBOW_BEACON) != enabled_modes.end()) + { + InitializeMode("Rainbow Beacon", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_RAINBOW_PINWHEELS) != enabled_modes.end()) + { + InitializeMode("Rainbow Pinwheels", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_RAINDROPS) != enabled_modes.end()) + { + InitializeMode("Raindrops", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_JELLYBEAN_RAINDROPS) != enabled_modes.end()) + { + InitializeMode("Jellybean Raindrops", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_HUE_BREATHING) != enabled_modes.end()) + { + InitializeMode("Hue Breathing", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_HUE_PENDULUM) != enabled_modes.end()) + { + InitializeMode("Hue Pendulum", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_HUE_WAVE) != enabled_modes.end()) + { + InitializeMode("Hue Wave", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_PIXEL_RAIN) != enabled_modes.end()) + { + InitializeMode("Pixel Rain", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_PIXEL_FLOW) != enabled_modes.end()) + { + InitializeMode("Pixel Flow", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_PIXEL_FRACTAL) != enabled_modes.end()) + { + InitializeMode("Pixel Fractal", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_TYPING_HEATMAP) != enabled_modes.end()) + { + InitializeMode("Typing Heatmap", current_mode, 0, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_DIGITAL_RAIN) != enabled_modes.end()) + { + InitializeMode("Digital Rain", current_mode, 0, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_REACTIVE_SIMPLE) != enabled_modes.end()) + { + InitializeMode("Solid Reactive Simple", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_REACTIVE) != enabled_modes.end()) + { + InitializeMode("Solid Reactive", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_REACTIVE_WIDE) != enabled_modes.end()) + { + InitializeMode("Solid Reactive Wide", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_REACTIVE_MULTIWIDE) != enabled_modes.end()) + { + InitializeMode("Solid Reactive Multi Wide", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_REACTIVE_CROSS) != enabled_modes.end()) + { + InitializeMode("Solid Reactive Cross", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_REACTIVE_MULTICROSS) != enabled_modes.end()) + { + InitializeMode("Solid Reactive Multi Cross", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_REACTIVE_NEXUS) != enabled_modes.end()) + { + InitializeMode("Solid Reactive Nexus", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_REACTIVE_MULTINEXUS) != enabled_modes.end()) + { + InitializeMode("Solid Reactive Multi Nexus", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SPLASH) != enabled_modes.end()) + { + InitializeMode("Rainbow Reactive Splash", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_MULTISPLASH) != enabled_modes.end()) + { + InitializeMode("Rainbow Reactive Multi Splash", current_mode, MODE_FLAG_HAS_SPEED, MODE_COLORS_NONE, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_SPLASH) != enabled_modes.end()) + { + InitializeMode("Solid Reactive Splash", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_SOLID_MULTISPLASH) != enabled_modes.end()) + { + InitializeMode("Solid Reactive Multi Splash", current_mode, MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED, MODE_COLORS_MODE_SPECIFIC, save); + } + + if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_OPENRGB_DIRECT) != enabled_modes.end()) + { + InitializeMode("Direct", current_mode, MODE_FLAG_HAS_PER_LED_COLOR, MODE_COLORS_PER_LED, save); + } + + /*-----------------------------------------------------*\ + | As we are insertting direct mode at index 0 | + | for it to be the first mode in the UI there will | + | be a mismatch between the values. QMK has direct | + | mode last in order, while in OpenRGB it's first. | + \*-----------------------------------------------------*/ + if(controller->GetMode() == (current_mode - 1)) + { + active_mode = 0; + } + else + { + active_mode = controller->GetMode(); + } + + SetupZones(); +} + +RGBController_QMKOpenRGBRevE::~RGBController_QMKOpenRGBRevE() +{ + 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; + } + } +} + +void RGBController_QMKOpenRGBRevE::SetupZones() +{ + /*---------------------------------------------------------*\ + | Get the number of LEDs from the device | + \*---------------------------------------------------------*/ + const unsigned int total_number_of_leds = controller->GetTotalNumberOfLEDs(); + const unsigned int total_number_of_leds_with_empty_space = controller->GetTotalNumberOfLEDsWithEmptySpace(); + + LOG_INFO("[%s] Keyboard has %u LEDs total", name.c_str(), total_number_of_leds); + + /*---------------------------------------------------------*\ + | Get information for each LED | + \*---------------------------------------------------------*/ + controller->GetLEDInfo(std::max(total_number_of_leds, total_number_of_leds_with_empty_space)); + + /*---------------------------------------------------------*\ + | Get LED vectors from controller | + \*---------------------------------------------------------*/ + std::vector led_points = controller->GetLEDPoints(); + std::vector led_flags = controller->GetLEDFlags(); + std::vector led_names = controller->GetLEDNames(); + std::vector led_values = controller->GetLEDValues(); + + /*---------------------------------------------------------*\ + | Count key LEDs and underglow LEDs | + \*---------------------------------------------------------*/ + unsigned int number_of_key_leds; + unsigned int number_of_underglow_leds; + + CountKeyTypes(led_flags, total_number_of_leds, number_of_key_leds, number_of_underglow_leds); + + /*---------------------------------------------------------*\ + | Count total LEDs and check if underglow exists | + \*---------------------------------------------------------*/ + unsigned int number_of_leds = number_of_key_leds + number_of_underglow_leds; + bool has_underglow = number_of_underglow_leds > 0; + LOG_INFO("[%s] Keyboard has %u underglow LEDs", name.c_str(), number_of_underglow_leds); + + /*---------------------------------------------------------*\ + | Create sets for row and column position values | + \*---------------------------------------------------------*/ + std::set rows, columns; + for (unsigned int i = 0; i < number_of_leds; i++) + { + rows.insert(led_points[i].y); + columns.insert(led_points[i].x); + } + + /*---------------------------------------------------------*\ + | Calculate matrix map from QMK positions | + \*---------------------------------------------------------*/ + unsigned int divisor = CalculateDivisor(led_points, rows, columns); + LOG_DEBUG("[%s] Distance between standard keys calculated to be %u", name.c_str(), divisor); + + VectorMatrix matrix_map; + VectorMatrix underglow_map; + + PlaceLEDsInMaps(rows, columns, divisor, led_points, led_flags, matrix_map, underglow_map); + CleanMatrixMaps(matrix_map, underglow_map, rows.size(), has_underglow); + + /*---------------------------------------------------------*\ + | These vectors are class members because if they go out of | + | scope, the underlying array (used by each zones' | + | matrix_map) is unallocated. | + \*---------------------------------------------------------*/ + flat_matrix_map = FlattenMatrixMap(matrix_map); + flat_underglow_map = FlattenMatrixMap(underglow_map); + + /*---------------------------------------------------------*\ + | Create Keyboard zone | + \*---------------------------------------------------------*/ + zone keys_zone; + keys_zone.name = "Keyboard"; + keys_zone.type = ZONE_TYPE_MATRIX; + keys_zone.leds_min = number_of_key_leds; + keys_zone.leds_max = keys_zone.leds_min; + keys_zone.leds_count = keys_zone.leds_min; + keys_zone.matrix_map = new matrix_map_type; + keys_zone.matrix_map->width = matrix_map[0].size(); + keys_zone.matrix_map->height = matrix_map.size(); + keys_zone.matrix_map->map = flat_matrix_map.data(); + zones.push_back(keys_zone); + + /*---------------------------------------------------------*\ + | Create Underglow zone if it exists | + \*---------------------------------------------------------*/ + if(has_underglow) + { + zone underglow_zone; + underglow_zone.name = "Underglow"; + underglow_zone.type = ZONE_TYPE_MATRIX; + underglow_zone.leds_min = number_of_underglow_leds; + underglow_zone.leds_max = underglow_zone.leds_min; + underglow_zone.leds_count = underglow_zone.leds_min; + underglow_zone.matrix_map = new matrix_map_type; + underglow_zone.matrix_map->width = underglow_map[0].size(); + underglow_zone.matrix_map->height = underglow_map.size(); + underglow_zone.matrix_map->map = flat_underglow_map.data(); + zones.push_back(underglow_zone); + } + + /*---------------------------------------------------------*\ + | Create LEDs | + \*---------------------------------------------------------*/ + for(unsigned int led_idx = 0; led_idx < number_of_leds; led_idx++) + { + led keyboard_led; + + if(led_idx < led_names.size()) + { + keyboard_led.name = led_names[led_idx]; + } + if(led_idx < led_values.size()){ + keyboard_led.value = led_values[led_idx]; + } + else + { + keyboard_led.value = led_idx; + } + + leds.push_back(keyboard_led); + } + + /*---------------------------------------------------------*\ + | Setup Colors | + \*---------------------------------------------------------*/ + SetupColors(); + + /*---------------------------------------------------------*\ + | Initialize colors from device values | + \*---------------------------------------------------------*/ + for(unsigned int i = 0; i < leds.size(); i++) + { + colors[i] = controller->GetLEDColors()[i]; + } +} + +void RGBController_QMKOpenRGBRevE::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_QMKOpenRGBRevE::DeviceUpdateLEDs() +{ + controller->DirectModeSetLEDs(colors, controller->GetTotalNumberOfLEDs()); +} + +void RGBController_QMKOpenRGBRevE::UpdateZoneLEDs(int /*zone*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_QMKOpenRGBRevE::UpdateSingleLED(int led) +{ + RGBColor color = colors[led]; + unsigned char red = RGBGetRValue(color); + unsigned char grn = RGBGetGValue(color); + unsigned char blu = RGBGetBValue(color); + + controller->DirectModeSetSingleLED(led, red, grn, blu); +} + +void RGBController_QMKOpenRGBRevE::SetCustomMode() +{ + active_mode = 0; +} + +void RGBController_QMKOpenRGBRevE::DeviceUpdateMode() +{ + if(modes[active_mode].color_mode == MODE_COLORS_PER_LED) + { + controller->SetMode({ 0, 255, 255 }, modes[active_mode].value, 127, false); + } + else if(modes[active_mode].color_mode == MODE_COLORS_NONE) + { + controller->SetMode({ 0, 255, 255 }, modes[active_mode].value, modes[active_mode].speed, false); + } + else if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC) + { + RGBColor rgb_color = modes[active_mode].colors[0]; + hsv_t hsv_color; + rgb2hsv(rgb_color, &hsv_color); + + if(modes[active_mode].flags & MODE_FLAG_HAS_SPEED) + { + controller->SetMode(hsv_color, modes[active_mode].value, modes[active_mode].speed, false); + } + else + { + controller->SetMode(hsv_color, modes[active_mode].value, 127, false); + } + } +} + +void RGBController_QMKOpenRGBRevE::DeviceSaveMode() +{ + if(modes[active_mode].color_mode == MODE_COLORS_NONE) + { + controller->SetMode({ 0, 255, 255 }, modes[active_mode].value, modes[active_mode].speed, true); + } + else if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC) + { + RGBColor rgb_color = modes[active_mode].colors[0]; + hsv_t hsv_color; + rgb2hsv(rgb_color, &hsv_color); + + if(modes[active_mode].flags & MODE_FLAG_HAS_SPEED) + { + controller->SetMode(hsv_color, modes[active_mode].value, modes[active_mode].speed, true); + } + else + { + controller->SetMode(hsv_color, modes[active_mode].value, 127, true); + } + } +} + +void RGBController_QMKOpenRGBRevE::InitializeMode + ( + std::string name, + unsigned int ¤t_mode, + unsigned int flags, + unsigned int color_mode, + bool save + ) +{ + mode qmk_mode; + qmk_mode.name = name; + qmk_mode.value = current_mode++; + qmk_mode.flags = flags; + qmk_mode.color_mode = color_mode; + + if(flags & MODE_FLAG_HAS_SPEED) + { + qmk_mode.speed_min = QMK_OPENRGB_SPEED_SLOWEST; + qmk_mode.speed_max = QMK_OPENRGB_SPEED_FASTEST; + qmk_mode.speed = QMK_OPENRGB_SPEED_NORMAL; + } + if(flags & MODE_FLAG_HAS_MODE_SPECIFIC_COLOR) + { + qmk_mode.colors_min = 1; + qmk_mode.colors_max = 1; + qmk_mode.colors.resize(1); + qmk_mode.colors[0] = controller->GetModeColor(); + } + + /*-----------------------------------------------------*\ + | Direct mode it the last mode on the QMK firmware | + | but we still want it to appear first on the UI | + \*-----------------------------------------------------*/ + if(flags & MODE_FLAG_HAS_PER_LED_COLOR) + { + modes.insert(modes.begin(), qmk_mode); + } + else + { + /*-----------------------------------------------------*\ + | Every mode apart from direct is save-able | + \*-----------------------------------------------------*/ + if(save == true) + { + qmk_mode.flags = flags | MODE_FLAG_MANUAL_SAVE; + } + modes.push_back(qmk_mode); + } +} + +unsigned int RGBController_QMKOpenRGBRevE::CalculateDivisor + ( + std::vector led_points, + std::set rows, + std::set columns + ) +{ + std::vector< std::vector > row_points(rows.size()); + for(const point_t &pt : led_points) + { + for(const int &i : rows) + { + if(pt.y == i) + { + row_points[std::distance(rows.begin(), rows.find(i))].push_back(pt); + } + } + } + + int last_pos; + std::vector distances; + for(const std::vector &row : row_points) + { + last_pos = 0; + std::for_each(row.begin(), row.end(), [&distances, &last_pos](const point_t &pt) + { + distances.push_back(std::abs(pt.x - last_pos)); + last_pos = pt.x; + }); + } + std::map counts; + for(const int &i : distances) + { + counts[i]++; + } + + unsigned int divisor = distances[0]; + for(const std::pair &i : counts) + { + if(counts[divisor] < i.second) + { + divisor = i.first; + } + } + return divisor; +} + +void RGBController_QMKOpenRGBRevE::CountKeyTypes + ( + std::vector led_flags, + unsigned int total_led_count, + unsigned int& key_leds, + unsigned int& underglow_leds + ) +{ + underglow_leds = 0; + key_leds = 0; + + for(unsigned int i = 0; i < total_led_count; i++) + { + if(led_flags[i] & 2) + { + underglow_leds++; + } + else if(led_flags[i] != 0) + { + key_leds++; + } + } +} + +void RGBController_QMKOpenRGBRevE::PlaceLEDsInMaps + ( + std::set unique_rows, + std::set unique_cols, + unsigned int divisor, + std::vector led_points, + std::vector led_flags, + VectorMatrix& matrix_map_xl, + VectorMatrix& underglow_map_xl + ) +{ + matrix_map_xl = MakeEmptyMatrixMap(unique_rows.size(), std::round(255/divisor) + 10); + underglow_map_xl = MakeEmptyMatrixMap(unique_rows.size(), std::round(255/divisor) + 10); + + unsigned int x = 0; + unsigned int y = 0; + unsigned int openrgb_idx = 0; + unsigned int underglow_counter = 0; + + for(unsigned int i = 0; i < controller->GetTotalNumberOfLEDs(); i++) + { + if(led_points[i].x != 255 && led_points[i].y != 255) + { + bool underglow = led_flags[i] & 2; + + x = std::round(led_points[i].x/divisor); + y = std::distance(unique_rows.begin(), unique_rows.find(led_points[i].y)); + + if(!underglow) + { + while(matrix_map_xl[y][x] != NO_LED) + { + x++; + } + matrix_map_xl[y][x] = i; + LOG_DEBUG("[%s] Key Matrix LED %u, (%u, %u) being placed into (%u, %u)", name.c_str(), i, led_points[i].x, led_points[i].y, x, y); + } + else + { + while(underglow_map_xl[y][x] != NO_LED) + { + x++; + } + underglow_map_xl[y][x] = underglow_counter; + underglow_counter++; + LOG_DEBUG("[%s] Underglow LED %u, (%u, %u) being placed into (%u, %u)", name.c_str(), i, led_points[i].x, led_points[i].y, x, y); + } + } + } +} + +VectorMatrix RGBController_QMKOpenRGBRevE::MakeEmptyMatrixMap + ( + unsigned int height, + unsigned int width + ) +{ + std::vector > matrix_map(height); + for (unsigned int i = 0; i < height; i++) + { + for (unsigned int j = 0; j < width; j++) + { + matrix_map[i].push_back(NO_LED); + } + } + return matrix_map; +} + +void RGBController_QMKOpenRGBRevE::CleanMatrixMaps + ( + VectorMatrix& matrix_map, + VectorMatrix& underglow_map, + unsigned int height, + bool has_underglow + ) +{ + bool empty_col = true; + bool empty_col_udg = true; + bool empty_row = true; + int width = 0; + int width_udg = 0; + + std::vector empty_rows; + + bool can_break; + bool can_break_udg; + + for(unsigned int i = 0; i < height; i++) + { + empty_row = true; + can_break = false; + can_break_udg = false; + + for(std::size_t j = matrix_map[i].size() - 1; j --> 0; ) + { + if(matrix_map[i][j] != NO_LED && width < (j + 1) && !can_break) + { + width = (j + 1); + can_break = true; + empty_row = false; + } + else if(matrix_map[i][j] != NO_LED) + { + empty_row = false; + } + if(underglow_map[i][j] != NO_LED && width_udg < (j + 1) && !can_break_udg) + { + width_udg = (j + 1); + can_break_udg = true; + } + if (can_break && can_break_udg) break; + } + + if(matrix_map[i][0] != NO_LED) + { + empty_col = false; + } + + if(underglow_map[i][0] != NO_LED) + { + empty_col_udg = false; + } + + if(empty_row) + { + empty_rows.push_back(i); + } + } + + unsigned int new_height = height - empty_rows.size(); + width = empty_col ? width - 1 : width; + width_udg = empty_col_udg && empty_col ? width_udg - 1 : width_udg; + LOG_DEBUG("[%s] Key LED Matrix: %ux%u", name.c_str(), width, new_height); + LOG_DEBUG("[%s] Underglow LED Matrix: %ux%u", name.c_str(), width_udg, new_height); + + for(unsigned int i = empty_rows.size(); i --> 0; ) + { + matrix_map.erase(matrix_map.begin()+empty_rows[i]); + } + + for(unsigned int i = 0; i < new_height; i++) + { + if(empty_col) + { + matrix_map[i].erase(matrix_map[i].begin(), matrix_map[i].begin() + 1); + } + + if(empty_col_udg && empty_col) + { + underglow_map[i].erase(underglow_map[i].begin(), underglow_map[i].begin() + 1); + } + + matrix_map[i].erase(matrix_map[i].begin()+width, matrix_map[i].end()); + + if(has_underglow) + { + underglow_map[i].erase(underglow_map[i].begin()+width_udg, underglow_map[i].end()); + } + } + + if(has_underglow) + { + for(unsigned int i = new_height; i < height; i++) + { + underglow_map[i].erase(underglow_map[i].begin()+width_udg, underglow_map[i].end()); + } + } +} + +std::vector RGBController_QMKOpenRGBRevE::FlattenMatrixMap + ( + VectorMatrix matrix_map + ) +{ + std::vector flat_map; + + for(const std::vector &row : matrix_map) + { + for(const unsigned int &item : row) + { + flat_map.push_back(item); + } + } + return flat_map; +} diff --git a/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevE.h b/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevE.h new file mode 100644 index 00000000..a4b4aabb --- /dev/null +++ b/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevE.h @@ -0,0 +1,99 @@ +/*-------------------------------------------------------------------*\ +| RGBController_QMKOpenRGBRevE.h | +| | +| Driver for QMK keyboards using OpenRGB Protocol (Revision E) | +| | +| Kasper 10th Octobber 2020 | +| Jath03 28th May 2021 | +| HorrorTroll 11th July 2022 | +\*-------------------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "QMKOpenRGBRevDController.h" +#include +#include +#include +#include + +#define NO_LED 0xFFFFFFFF + +typedef std::vector> VectorMatrix; + +class RGBController_QMKOpenRGBRevE : public RGBController +{ +public: + RGBController_QMKOpenRGBRevE(QMKOpenRGBRevDController* controller_ptr, bool save); + ~RGBController_QMKOpenRGBRevE(); + + void SetupZones(); + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void SetCustomMode(); + void DeviceUpdateMode(); + void DeviceSaveMode(); + +private: + QMKOpenRGBRevDController* controller; + std::vector flat_matrix_map; + std::vector flat_underglow_map; + + void InitializeMode + ( + std::string name, + unsigned int ¤t_mode, + unsigned int flags, + unsigned int color_mode, + bool save + ); + + unsigned int CalculateDivisor + ( + std::vector led_points, + std::set rows, + std::set columns + ); + + void CountKeyTypes + ( + std::vector led_flags, + unsigned int total_led_count, + unsigned int& key_leds, + unsigned int& underglow_leds + ); + + void PlaceLEDsInMaps + ( + std::set unique_rows, + std::set unique_cols, + unsigned int divisor, + std::vector led_points, + std::vector led_flags, + VectorMatrix& matrix_map_xl, + VectorMatrix& underglow_map_xl + ); + + VectorMatrix MakeEmptyMatrixMap + ( + unsigned int height, + unsigned int width + ); + + void CleanMatrixMaps + ( + VectorMatrix& matrix_map, + VectorMatrix& underglow_map, + unsigned int height, + bool has_underglow + ); + + std::vector FlattenMatrixMap + ( + VectorMatrix matrix_map + ); +};