From 35a827d25cb01dab44f249c5a2f875e62c0f0c60 Mon Sep 17 00:00:00 2001 From: Neneya Date: Mon, 27 Dec 2021 05:12:39 +0000 Subject: [PATCH] Implement new protocol version that adds tracking of keyboard-internal LED IDs rather than assuming they are in the same order as in OpenRGB, as well as sending the LED ID that needs to be updated on every direct update. --- .../QMKOpenRGBControllerDetect.cpp | 12 +- .../QMKOpenRGBRevDController.cpp | 525 ++++++++++++ .../QMKOpenRGBRevDController.h | 72 ++ .../RGBController_QMKOpenRGBRevD.cpp | 783 ++++++++++++++++++ .../RGBController_QMKOpenRGBRevD.h | 98 +++ OpenRGB.pro | 4 + 6 files changed, 1493 insertions(+), 1 deletion(-) create mode 100644 Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.cpp create mode 100644 Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.h create mode 100644 Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.cpp create mode 100644 Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.h diff --git a/Controllers/QMKOpenRGBController/QMKOpenRGBControllerDetect.cpp b/Controllers/QMKOpenRGBController/QMKOpenRGBControllerDetect.cpp index 9fffb0b4..78763528 100644 --- a/Controllers/QMKOpenRGBController/QMKOpenRGBControllerDetect.cpp +++ b/Controllers/QMKOpenRGBController/QMKOpenRGBControllerDetect.cpp @@ -13,9 +13,11 @@ #include "Detector.h" #include "QMKOpenRGBRev9Controller.h" #include "QMKOpenRGBRevBController.h" +#include "QMKOpenRGBRevDController.h" #include "RGBController.h" #include "RGBController_QMKOpenRGBRev9.h" #include "RGBController_QMKOpenRGBRevB.h" +#include "RGBController_QMKOpenRGBRevD.h" #include "LogManager.h" #include @@ -25,6 +27,7 @@ #define QMK_OPENRGB_PROTOCOL_VERSION_9 0x09 #define QMK_OPENRGB_PROTOCOL_VERSION_B 0x0B #define QMK_OPENRGB_PROTOCOL_VERSION_C 0x0C +#define QMK_OPENRGB_PROTOCOL_VERSION_D 0x0D /*-----------------------------------------------------*\ | Usage and Usage Page | @@ -93,6 +96,13 @@ void DetectQMKOpenRGBControllers(hid_device_info *info, const std::string&) ResourceManager::get()->RegisterRGBController(rgb_controller); } break; + case QMK_OPENRGB_PROTOCOL_VERSION_D: + { + QMKOpenRGBRevDController* controller = new QMKOpenRGBRevDController(dev, info->path); + RGBController_QMKOpenRGBRevD* rgb_controller = new RGBController_QMKOpenRGBRevD(controller, true); + ResourceManager::get()->RegisterRGBController(rgb_controller); + } + break; default: if (version == 0) { @@ -105,7 +115,7 @@ void DetectQMKOpenRGBControllers(hid_device_info *info, const std::string&) "For officaly supported QMK boards grab url \n" "For Sonix boards grab url", version); } - else if (version > QMK_OPENRGB_PROTOCOL_VERSION_C) + else if (version > QMK_OPENRGB_PROTOCOL_VERSION_D) { LOG_WARNING("[QMK OpenRGB] Detection failed - the detected keyboard is using version protocol %i which is not supported by this OpenRGB build. Please update OpenRGB!", version); } diff --git a/Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.cpp b/Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.cpp new file mode 100644 index 00000000..8cd939e7 --- /dev/null +++ b/Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.cpp @@ -0,0 +1,525 @@ +/*-------------------------------------------------------------------*\ +| QMKOpenRGBRevDController.cpp | +| | +| Driver for QMK keyboards using OpenRGB Protocol (Revision D) | +| | +| Kasper 10th Octobber 2020 | +| Jath03 28th May 2021 | +\*-------------------------------------------------------------------*/ + +#include "QMKOpenRGBRevDController.h" + +using namespace std::chrono_literals; + +static std::map QMKKeycodeToKeynameMap +{ + { 0, "" }, { 1, "Right Fn" }, { 2, "" }, { 3, "" }, + { 4, "A" }, { 5, "B" }, { 6, "C" }, { 7, "D" }, + { 8, "E" }, { 9, "F" }, { 10, "G" }, { 11, "H" }, + { 12, "I" }, { 13, "J" }, { 14, "K" }, { 15, "L" }, + { 16, "M" }, { 17, "N" }, { 18, "O" }, { 19, "P" }, + { 20, "Q" }, { 21, "R" }, { 22, "S" }, { 23, "T" }, + { 24, "U" }, { 25, "V" }, { 26, "W" }, { 27, "X" }, + { 28, "Y" }, { 29, "Z" }, { 30, "1" }, { 31, "2" }, + { 32, "3" }, { 33, "4" }, { 34, "5" }, { 35, "6" }, + { 36, "7" }, { 37, "8" }, { 38, "9" }, { 39, "0" }, + { 40, "Enter" }, { 41, "Escape" }, { 42, "Backspace" }, { 43, "Tab" }, + { 44, "Space" }, { 45, "-" }, { 46, "=" }, { 47, "[" }, + { 48, "]" }, { 49, "\\ (ANSI)" }, { 50, "" }, { 51, ";" }, + { 52, "'" }, { 53, "`" }, { 54, "," }, { 55, "." }, + { 56, "/" }, { 57, "Caps Lock" }, { 58, "F1" }, { 59, "F2" }, + { 60, "F3" }, { 61, "F4" }, { 62, "F5" }, { 63, "F6" }, + { 64, "F7" }, { 65, "F8" }, { 66, "F9" }, { 67, "F10" }, + { 68, "F11" }, { 69, "F12" }, { 70, "Print Screen" }, { 71, "Scroll Lock" }, + { 72, "Pause/Break" }, { 73, "Insert" }, { 74, "Home" }, { 75, "Page Up" }, + { 76, "Delete" }, { 77, "End" }, { 78, "Page Down" }, { 79, "Right Arrow" }, + { 80, "Left Arrow" }, { 81, "Down Arrow" }, { 82, "Up Arrow" }, { 83, "Num Lock" }, + { 84, "Number Pad /" }, { 85, "Number Pad *" }, { 86, "Number Pad -" }, { 87, "Number Pad +" }, + { 88, "Number Pad Enter" }, { 89, "Number Pad 1" }, { 90, "Number Pad 2" }, { 91, "Number Pad 3" }, + { 92, "Number Pad 4" }, { 93, "Number Pad 5" }, { 94, "Number Pad 6" }, { 95, "Number Pad 7" }, + { 96, "Number Pad 8" }, { 97, "Number Pad 9" }, { 98, "Number Pad 0" }, { 99, "Number Pad ." }, + { 100, "" }, { 101, "Menu" }, { 102, "" }, { 103, "" }, + { 104, "" }, { 105, "" }, { 106, "" }, { 107, "" }, + { 108, "" }, { 109, "" }, { 110, "" }, { 111, "" }, + { 112, "" }, { 113, "" }, { 114, "" }, { 115, "" }, + { 116, "" }, { 117, "" }, { 118, "" }, { 119, "" }, + { 120, "" }, { 121, "" }, { 122, "" }, { 123, "" }, + { 124, "" }, { 125, "" }, { 126, "" }, { 127, "" }, + { 128, "" }, { 129, "" }, { 130, "" }, { 131, "" }, + { 132, "" }, { 133, "" }, { 134, "" }, { 135, "" }, + { 136, "" }, { 137, "" }, { 138, "" }, { 139, "" }, + { 140, "" }, { 141, "" }, { 142, "" }, { 143, "" }, + { 144, "" }, { 145, "" }, { 146, "" }, { 147, "" }, + { 148, "" }, { 149, "" }, { 150, "" }, { 151, "" }, + { 152, "" }, { 153, "" }, { 154, "" }, { 155, "" }, + { 156, "" }, { 157, "" }, { 158, "" }, { 159, "" }, + { 160, "" }, { 161, "" }, { 162, "" }, { 163, "" }, { 164, "" }, + /*Space Cadet Left Shift*/ { 216, "Left Shift"}, /*Space Cadet Right Shift*/ { 217, "Right Shift"}, + { 224, "Left Control" }, { 225, "Left Shift" }, { 226, "Left Alt" }, { 227, "Left Windows" }, + { 228, "Right Control" }, { 229, "Right Shift" }, { 230, "Right Alt" }, { 231, "Right Windows" }, +}; + +QMKOpenRGBRevDController::QMKOpenRGBRevDController(hid_device *dev_handle, const char *path) +{ + /*-------------------------------------------------*\ + | Get QMKOpenRGB settings | + \*-------------------------------------------------*/ + json qmk_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("QMKOpenRGBDevices"); + if(qmk_settings.contains("leds_per_update")) + { + if(qmk_settings["leds_per_update"] > 15) + { + qmk_settings["leds_per_update"] = 15; + } + else if(qmk_settings["leds_per_update"] < 1) + { + qmk_settings["leds_per_update"] = 1; + } + SettingsManager* settings_manager = ResourceManager::get()->GetSettingsManager(); + settings_manager->SetSettings("QMKOpenRGBDevices", qmk_settings); + settings_manager->SaveSettings(); + leds_per_update = qmk_settings["leds_per_update"]; + } + else + { + leds_per_update = 15; + } + + if(qmk_settings.contains("delay")) + { + delay = (unsigned int)qmk_settings["delay"] * 1ms; + } + else + { + delay = 0ms; + } + + dev = dev_handle; + location = path; + + GetDeviceInfo(); + GetModeInfo(); +} + +QMKOpenRGBRevDController::~QMKOpenRGBRevDController() +{ + hid_close(dev); +} + +std::string QMKOpenRGBRevDController::GetLocation() +{ + return location; +} + +std::string QMKOpenRGBRevDController::GetDeviceName() +{ + return device_name; +} + +std::string QMKOpenRGBRevDController::GetDeviceVendor() +{ + return device_vendor; +} + +unsigned int QMKOpenRGBRevDController::GetTotalNumberOfLEDs() +{ + return total_number_of_leds; +} + +unsigned int QMKOpenRGBRevDController::GetTotalNumberOfLEDsWithEmptySpace() +{ + return total_number_of_leds_with_empty_space; +} + +unsigned int QMKOpenRGBRevDController::GetMode() +{ + return mode; +} + +unsigned int QMKOpenRGBRevDController::GetModeSpeed() +{ + return mode_speed; +} + +unsigned int QMKOpenRGBRevDController::GetModeColor() +{ + return mode_color; +} + +std::vector QMKOpenRGBRevDController::GetLEDPoints() +{ + return led_points; +} + +std::vector QMKOpenRGBRevDController::GetLEDFlags() +{ + return led_flags; +} + +std::vector QMKOpenRGBRevDController::GetLEDNames() +{ + return led_names; +} + +std::vector QMKOpenRGBRevDController::GetLEDColors() +{ + return led_colors; +} + +std::vector QMKOpenRGBRevDController::GetLEDValues() +{ + return led_values; +} + +unsigned int QMKOpenRGBRevDController::GetProtocolVersion() +{ + unsigned char usb_buf[QMK_OPENRGB_PACKET_SIZE]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, QMK_OPENRGB_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Set up config table request packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = 0x00; + usb_buf[0x01] = QMK_OPENRGB_GET_PROTOCOL_VERSION; + + int bytes_read = 0; + do + { + hid_write(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE); + bytes_read = hid_read_timeout(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE, QMK_OPENRGB_HID_READ_TIMEOUT); + } while(bytes_read <= 0); + + return usb_buf[1]; +} + +std::string QMKOpenRGBRevDController::GetQMKVersion() +{ + unsigned char usb_buf[QMK_OPENRGB_PACKET_SIZE]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, QMK_OPENRGB_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Set up config table request packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = 0x00; + usb_buf[0x01] = QMK_OPENRGB_GET_QMK_VERSION; + + hid_write(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE); + hid_read(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE); + + std::string qmk_version; + int i = 1; + while (usb_buf[i] != 0) + { + qmk_version.push_back(usb_buf[i]); + i++; + } + + return qmk_version; +} + +void QMKOpenRGBRevDController::GetDeviceInfo() +{ + unsigned char usb_buf[QMK_OPENRGB_PACKET_SIZE]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, QMK_OPENRGB_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Set up config table request packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = 0x00; + usb_buf[0x01] = QMK_OPENRGB_GET_DEVICE_INFO; + + int bytes_read = 0; + do + { + hid_write(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE); + bytes_read = hid_read_timeout(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE, QMK_OPENRGB_HID_READ_TIMEOUT); + } while(bytes_read <= 0); + + total_number_of_leds = usb_buf[QMK_OPENRGB_TOTAL_NUMBER_OF_LEDS_BYTE]; + total_number_of_leds_with_empty_space = usb_buf[QMK_OPENRGB_TOTAL_NUMBER_OF_LEDS_WITH_EMPTY_SPACE_BYTE]; + + int i = QMK_OPENRGB_TOTAL_NUMBER_OF_LEDS_WITH_EMPTY_SPACE_BYTE + 1; + while (usb_buf[i] != 0) + { + device_name.push_back(usb_buf[i]); + i++; + } + + i++; + while (usb_buf[i] != 0) + { + device_vendor.push_back(usb_buf[i]); + i++; + } +} + +void QMKOpenRGBRevDController::GetModeInfo() +{ + unsigned char usb_buf[QMK_OPENRGB_PACKET_SIZE]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, QMK_OPENRGB_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Set up config table request packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = 0x00; + usb_buf[0x01] = QMK_OPENRGB_GET_MODE_INFO; + + int bytes_read = 0; + do + { + hid_write(dev, usb_buf, 65); + bytes_read = hid_read_timeout(dev, usb_buf, 65, QMK_OPENRGB_HID_READ_TIMEOUT); + } while(bytes_read <= 0); + + mode = usb_buf[QMK_OPENRGB_MODE_BYTE]; + mode_speed = usb_buf[QMK_OPENRGB_SPEED_BYTE]; + + /*-----------------------------------------------------*\ + | QMK hue range is between 0-255 so hue needs to be | + | converted | + \*-----------------------------------------------------*/ + unsigned int oldRange = 255; + unsigned int newRange = 359; + unsigned int convertedHue = (usb_buf[QMK_OPENRGB_HUE_BYTE] * newRange / oldRange); + + hsv_t hsv; + hsv.hue = convertedHue; + hsv.saturation = usb_buf[QMK_OPENRGB_SATURATION_BYTE]; + hsv.value = usb_buf[QMK_OPENRGB_VALUE_BYTE]; + + mode_color = hsv2rgb(&hsv); +} + +void QMKOpenRGBRevDController::GetLEDInfo(unsigned int leds_count) +{ + unsigned int leds_sent = 0; + unsigned int leds_per_update_info = 8; + + std::vector underglow_points; + std::vector underglow_flags; + std::vector underglow_names; + std::vector underglow_colors; + std::vector underglow_values; + + while (leds_sent < leds_count) + { + if ((leds_count - leds_sent) < leds_per_update_info) + { + leds_per_update_info = leds_count - leds_sent; + } + + unsigned char usb_buf[QMK_OPENRGB_PACKET_SIZE]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, QMK_OPENRGB_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Set up config table request packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = 0x00; + usb_buf[0x01] = QMK_OPENRGB_GET_LED_INFO; + usb_buf[0x02] = leds_sent; + usb_buf[0x03] = leds_per_update_info; + + int bytes_read = 0; + do + { + hid_write(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE); + bytes_read = hid_read_timeout(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE, QMK_OPENRGB_HID_READ_TIMEOUT); + } while(bytes_read <= 0); + + for (unsigned int led_idx = 0; led_idx < leds_per_update_info; led_idx++) + { + if(usb_buf[(led_idx * 7) + QMK_OPENRGB_FLAG_BYTE] != QMK_OPENRGB_FAILURE) + { + if(usb_buf[(led_idx * 7) + QMK_OPENRGB_FLAG_BYTE] & 2) + { + underglow_points.push_back(point_t{usb_buf[(led_idx * 7) + QMK_OPENRGB_POINT_X_BYTE], usb_buf[(led_idx * 7) + QMK_OPENRGB_POINT_Y_BYTE]}); + underglow_flags.push_back(usb_buf[(led_idx * 7) + QMK_OPENRGB_FLAG_BYTE]); + underglow_colors.push_back(ToRGBColor(usb_buf[(led_idx * 7) + QMK_OPENRGB_R_COLOR_BYTE], usb_buf[(led_idx * 7) + QMK_OPENRGB_G_COLOR_BYTE], usb_buf[(led_idx * 7) + QMK_OPENRGB_B_COLOR_BYTE])); + underglow_values.push_back(underglow_values.size() + led_values.size()); + } + else + { + led_points.push_back(point_t{usb_buf[(led_idx * 7) + QMK_OPENRGB_POINT_X_BYTE], usb_buf[(led_idx * 7) + QMK_OPENRGB_POINT_Y_BYTE]}); + led_flags.push_back(usb_buf[(led_idx * 7) + QMK_OPENRGB_FLAG_BYTE]); + led_colors.push_back(ToRGBColor(usb_buf[(led_idx * 7) + QMK_OPENRGB_R_COLOR_BYTE], usb_buf[(led_idx * 7) + QMK_OPENRGB_G_COLOR_BYTE], usb_buf[(led_idx * 7) + QMK_OPENRGB_B_COLOR_BYTE])); + led_values.push_back(underglow_values.size() + led_values.size()); + } + } + + if(usb_buf[(led_idx * 7) + QMK_OPENRGB_KEYCODE_BYTE] != 0) + { + if (QMKKeycodeToKeynameMap.count(usb_buf[(led_idx * 7) + QMK_OPENRGB_KEYCODE_BYTE]) > 0) + { + led_names.push_back("Key: " + QMKKeycodeToKeynameMap[usb_buf[(led_idx * 7) + QMK_OPENRGB_KEYCODE_BYTE]]); + } + else + { + led_names.push_back("Key: "); + } + } + else if(usb_buf[(led_idx * 7) + QMK_OPENRGB_FLAG_BYTE] & 2){ + underglow_names.push_back("Underglow: " + std::to_string(underglow_names.size() + led_names.size())); + } + } + + leds_sent += leds_per_update_info; + } + + led_points.insert(led_points.end(), underglow_points.begin(), underglow_points.end()); + led_flags.insert(led_flags.end(), underglow_flags.begin(), underglow_flags.end()); + led_colors.insert(led_colors.end(), underglow_colors.begin(), underglow_colors.end()); + led_names.insert(led_names.end(), underglow_names.begin(), underglow_names.end()); + led_values.insert(led_values.end(), underglow_values.begin(), underglow_values.end()); +} + +std::vector QMKOpenRGBRevDController::GetEnabledModes() +{ + unsigned char usb_buf[QMK_OPENRGB_PACKET_SIZE]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, QMK_OPENRGB_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Set up config table request packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = 0x00; + usb_buf[0x01] = QMK_OPENRGB_GET_ENABLED_MODES; + + int bytes_read = 0; + do + { + hid_write(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE); + bytes_read = hid_read_timeout(dev, usb_buf, QMK_OPENRGB_PACKET_SIZE, QMK_OPENRGB_HID_READ_TIMEOUT); + } while(bytes_read <= 0); + + std::vector enabled_modes; + int i = 1; + while (usb_buf[i] != 0) + { + enabled_modes.push_back(usb_buf[i]); + i++; + } + return enabled_modes; +} + +void QMKOpenRGBRevDController::SetMode(hsv_t hsv_color, unsigned char mode, unsigned char speed, bool save) +{ + unsigned char usb_buf[QMK_OPENRGB_PACKET_SIZE]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, QMK_OPENRGB_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Set up config table request packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = 0x00; + usb_buf[0x01] = QMK_OPENRGB_SET_MODE; + usb_buf[0x02] = hsv_color.hue * 255 / 359; + usb_buf[0x03] = hsv_color.saturation; + usb_buf[0x04] = hsv_color.value; + usb_buf[0x05] = mode; + usb_buf[0x06] = speed; + usb_buf[0x07] = save; + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, usb_buf, 65); + hid_read_timeout(dev, usb_buf, 65, QMK_OPENRGB_HID_READ_TIMEOUT); +} + +void QMKOpenRGBRevDController::DirectModeSetSingleLED(unsigned int led, unsigned char red, unsigned char green, unsigned char blue) +{ + unsigned char usb_buf[QMK_OPENRGB_PACKET_SIZE]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, QMK_OPENRGB_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Set up config table request packet | + \*-----------------------------------------------------*/ + + usb_buf[0x00] = 0x00; + usb_buf[0x01] = QMK_OPENRGB_DIRECT_MODE_SET_SINGLE_LED; + usb_buf[0x02] = led_values[led]; + usb_buf[0x03] = red; + usb_buf[0x04] = green; + usb_buf[0x05] = blue; + + /*-----------------------------------------------------*\ + | Send packet | + \*-----------------------------------------------------*/ + hid_write(dev, usb_buf, 65); + hid_read_timeout(dev, usb_buf, 65, QMK_OPENRGB_HID_READ_TIMEOUT); +} + +void QMKOpenRGBRevDController::DirectModeSetLEDs(std::vector colors, unsigned int leds_count) +{ + unsigned int leds_sent = 0; + unsigned int tmp_leds_per_update = leds_per_update; + + while (leds_sent < leds_count) + { + if ((leds_count - leds_sent) < tmp_leds_per_update) + { + tmp_leds_per_update = leds_count - leds_sent; + } + + unsigned char usb_buf[QMK_OPENRGB_PACKET_SIZE]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, QMK_OPENRGB_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Set up config table request packet | + \*-----------------------------------------------------*/ + usb_buf[0x00] = 0x00; + usb_buf[0x01] = QMK_OPENRGB_DIRECT_MODE_SET_LEDS; + usb_buf[0x02] = tmp_leds_per_update; + + for (unsigned int led_idx = 0; led_idx < tmp_leds_per_update; led_idx++) + { + usb_buf[(led_idx * 4) + 3] = led_values[led_idx + leds_sent]; + usb_buf[(led_idx * 4) + 4] = RGBGetRValue(colors[led_idx + leds_sent]); + usb_buf[(led_idx * 4) + 5] = RGBGetGValue(colors[led_idx + leds_sent]); + usb_buf[(led_idx * 4) + 6] = RGBGetBValue(colors[led_idx + leds_sent]); + } + + hid_write(dev, usb_buf, 65); + + if(delay > 0ms) + { + std::this_thread::sleep_for(delay); + } + + leds_sent += tmp_leds_per_update; + } +} diff --git a/Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.h b/Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.h new file mode 100644 index 00000000..378cc600 --- /dev/null +++ b/Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.h @@ -0,0 +1,72 @@ +/*-------------------------------------------------------------------*\ +| QMKOpenRGBRevDController.h | +| | +| Driver for QMK keyboards using OpenRGB Protocol (Revision D) | +| | +| Kasper 10th Octobber 2020 | +| Jath03 28th May 2021 | +\*-------------------------------------------------------------------*/ + +#pragma once + +#include "QMKOpenRGBController.h" + +class QMKOpenRGBRevDController +{ +public: + QMKOpenRGBRevDController(hid_device *dev_handle, const char *path); + ~QMKOpenRGBRevDController(); + + std::string GetLocation(); + std::string GetDeviceName(); + std::string GetDeviceVendor(); + + unsigned int GetTotalNumberOfLEDs(); + unsigned int GetTotalNumberOfLEDsWithEmptySpace(); + unsigned int GetMode(); + unsigned int GetModeSpeed(); + unsigned int GetModeColor(); + + std::vector GetLEDPoints(); + std::vector GetLEDFlags(); + std::vector GetLEDNames(); + std::vector GetLEDColors(); + std::vector GetLEDValues(); + + unsigned int GetProtocolVersion(); + std::string GetQMKVersion(); + void GetDeviceInfo(); + void GetModeInfo(); + void GetLEDInfo(unsigned int leds_count); + std::vector GetEnabledModes(); + + void SetMode(hsv_t hsv_color, unsigned char mode, unsigned char speed, bool save); + void DirectModeSetSingleLED(unsigned int led, unsigned char red, unsigned char green, unsigned char blue); + void DirectModeSetLEDs(std::vector colors, unsigned int num_colors); + +protected: + hid_device *dev; + +private: + unsigned int leds_per_update; + + std::string location; + + std::string device_name; + std::string device_vendor; + + std::chrono::milliseconds delay; + + unsigned int total_number_of_leds; + unsigned int total_number_of_leds_with_empty_space; + unsigned int mode; + unsigned int mode_speed; + + RGBColor mode_color; + + std::vector led_points; + std::vector led_flags; + std::vector led_names; + std::vector led_colors; + std::vector led_values; +}; diff --git a/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.cpp b/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.cpp new file mode 100644 index 00000000..50a314d0 --- /dev/null +++ b/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.cpp @@ -0,0 +1,783 @@ +/*-------------------------------------------------------------------*\ +| 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_SPEED, MODE_COLORS_NONE, 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_SPEED, MODE_COLORS_NONE, 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(); + + /*---------------------------------------------------------*\ + | 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; + + /*---------------------------------------------------------*\ + | 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); + + 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::SetCustomMode() +{ + active_mode = 0; +} + +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(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 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; + } + else + { + while(underglow_map_xl[y][x] != NO_LED) + { + x++; + } + underglow_map_xl[y][x] = underglow_counter; + underglow_counter++; + } + } + } +} + +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(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; + + 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; +} diff --git a/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.h b/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.h new file mode 100644 index 00000000..8358f4b9 --- /dev/null +++ b/Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.h @@ -0,0 +1,98 @@ +/*-------------------------------------------------------------------*\ +| RGBController_QMKOpenRGBRevD.h | +| | +| Driver for QMK keyboards using OpenRGB Protocol (Revision D) | +| | +| Kasper 10th Octobber 2020 | +| Jath03 28th May 2021 | +\*-------------------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "QMKOpenRGBRevDController.h" +#include +#include +#include +#include + +#define NO_LED 0xFFFFFFFF + +typedef std::vector> VectorMatrix; + +class RGBController_QMKOpenRGBRevD : public RGBController +{ +public: + RGBController_QMKOpenRGBRevD(QMKOpenRGBRevDController* controller_ptr, bool save); + ~RGBController_QMKOpenRGBRevD(); + + 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 + ); +}; diff --git a/OpenRGB.pro b/OpenRGB.pro index 4cc7dc0e..d4531dd5 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -419,8 +419,10 @@ HEADERS += Controllers/QMKOpenRGBController/QMKOpenRGBController.h \ Controllers/QMKOpenRGBController/QMKOpenRGBRev9Controller.h \ Controllers/QMKOpenRGBController/QMKOpenRGBRevBController.h \ + Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.h \ Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRev9.h \ Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevB.h \ + Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.h \ Controllers/RazerController/RazerController.h \ Controllers/RazerController/RazerKrakenController.h \ Controllers/RazerController/RazerDevices.h \ @@ -839,8 +841,10 @@ SOURCES += Controllers/QMKOpenRGBController/QMKOpenRGBControllerDetect.cpp \ Controllers/QMKOpenRGBController/QMKOpenRGBRev9Controller.cpp \ Controllers/QMKOpenRGBController/QMKOpenRGBRevBController.cpp \ + Controllers/QMKOpenRGBController/QMKOpenRGBRevDController.cpp \ Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRev9.cpp \ Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevB.cpp \ + Controllers/QMKOpenRGBController/RGBController_QMKOpenRGBRevD.cpp \ Controllers/RazerController/RazerController.cpp \ Controllers/RazerController/RazerKrakenController.cpp \ Controllers/RazerController/RazerControllerDetect.cpp \