/*-------------------------------------------------------------------*\ | RGBController_QMKOpenRGBRevD.cpp | | | | Driver for QMK keyboards using OpenRGB Protocol (Revision D) | | | | Kasper 10th Octobber 2020 | | Jath03 28th May 2021 | \*-------------------------------------------------------------------*/ #include "hsv.h" #include "LogManager.h" #include "RGBController_QMKOpenRGBRevD.h" RGBController_QMKOpenRGBRevD::RGBController_QMKOpenRGBRevD(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_FLAG_HAS_SPEED, 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_FLAG_HAS_SPEED, 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_FLAG_HAS_SPEED, 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_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_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_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_SPEED, MODE_COLORS_NONE, 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_SPEED, MODE_COLORS_NONE, 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_SPEED, MODE_COLORS_NONE, save); } if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_RAINDROPS) != enabled_modes.end()) { InitializeMode("Raindrops", current_mode, 0, MODE_COLORS_NONE, save); } if(std::find(enabled_modes.begin(), enabled_modes.end(), QMK_OPENRGB_MODE_JELLYBEAN_RAINDROPS) != enabled_modes.end()) { InitializeMode("Jellybean Raindrops", current_mode, 0, MODE_COLORS_NONE, 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_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_QMKOpenRGBRevD::~RGBController_QMKOpenRGBRevD() { 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_QMKOpenRGBRevD::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_QMKOpenRGBRevD::ResizeZone(int /*zone*/, int /*new_size*/) { /*---------------------------------------------------------*\ | This device does not support resizing zones | \*---------------------------------------------------------*/ } void RGBController_QMKOpenRGBRevD::DeviceUpdateLEDs() { controller->DirectModeSetLEDs(colors, controller->GetTotalNumberOfLEDs()); } void RGBController_QMKOpenRGBRevD::UpdateZoneLEDs(int /*zone*/) { DeviceUpdateLEDs(); } void RGBController_QMKOpenRGBRevD::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_QMKOpenRGBRevD::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_QMKOpenRGBRevD::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_QMKOpenRGBRevD::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_QMKOpenRGBRevD::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_QMKOpenRGBRevD::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_QMKOpenRGBRevD::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 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_QMKOpenRGBRevD::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_QMKOpenRGBRevD::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(int 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_QMKOpenRGBRevD::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; }