From 8aa8e0dab3fa23ea1df5b34f1230868ff5d9917b Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Apr 2021 19:47:29 -0400 Subject: [PATCH] rgb_configurator: initial implementation --- src/main/python/keyboard_comm.py | 54 +++++++++++ src/main/python/main_window.py | 8 +- src/main/python/rgb_configurator.py | 142 ++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 src/main/python/rgb_configurator.py diff --git a/src/main/python/keyboard_comm.py b/src/main/python/keyboard_comm.py index f2830ad..eee805a 100644 --- a/src/main/python/keyboard_comm.py +++ b/src/main/python/keyboard_comm.py @@ -17,6 +17,9 @@ CMD_VIA_GET_KEYBOARD_VALUE = 0x02 CMD_VIA_SET_KEYBOARD_VALUE = 0x03 CMD_VIA_GET_KEYCODE = 0x04 CMD_VIA_SET_KEYCODE = 0x05 +CMD_VIA_LIGHTING_SET_VALUE = 0x07 +CMD_VIA_LIGHTING_GET_VALUE = 0x08 +CMD_VIA_LIGHTING_SAVE = 0x09 CMD_VIA_MACRO_GET_COUNT = 0x0C CMD_VIA_MACRO_GET_BUFFER_SIZE = 0x0D CMD_VIA_MACRO_GET_BUFFER = 0x0E @@ -28,6 +31,14 @@ CMD_VIA_VIAL_PREFIX = 0xFE VIA_LAYOUT_OPTIONS = 0x02 VIA_SWITCH_MATRIX_STATE = 0x03 +QMK_BACKLIGHT_BRIGHTNESS = 0x09 +QMK_BACKLIGHT_EFFECT = 0x0A + +QMK_RGBLIGHT_BRIGHTNESS = 0x80 +QMK_RGBLIGHT_EFFECT = 0x81 +QMK_RGBLIGHT_EFFECT_SPEED = 0x82 +QMK_RGBLIGHT_COLOR = 0x83 + CMD_VIAL_GET_KEYBOARD_ID = 0x00 CMD_VIAL_GET_SIZE = 0x01 CMD_VIAL_GET_DEFINITION = 0x02 @@ -145,6 +156,7 @@ class Keyboard: def __init__(self, dev, usb_send=hid_send): self.dev = dev self.usb_send = usb_send + self.definition = None # n.b. using OrderedDict here to make order of layout requests consistent for tests self.rowcol = OrderedDict() @@ -163,6 +175,10 @@ class Keyboard: self.vibl = False self.custom_keycodes = None + self.lighting_qmk_rgblight = self.lighting_qmk_backlight = False + self.underglow_brightness = self.underglow_effect = self.underglow_effect_speed = -1 + self.underglow_color = (0, 0) + self.via_protocol = self.vial_protocol = self.keyboard_id = -1 def reload(self, sideload_json=None): @@ -177,6 +193,7 @@ class Keyboard: self.reload_layers() self.reload_keymap() self.reload_macros() + self.reload_rgb() def reload_layers(self): """ Get how many layers the keyboard has """ @@ -217,6 +234,8 @@ class Keyboard: payload = json.loads(lzma.decompress(payload)) + self.definition = payload + if "vial" in payload: vial = payload["vial"] self.vibl = vial.get("vibl", False) @@ -313,6 +332,23 @@ class Keyboard: macros = self.macro.split(b"\x00") + [b""] * self.macro_count self.macro = b"\x00".join(macros[:self.macro_count]) + b"\x00" + def reload_rgb(self): + if "lighting" in self.definition: + self.lighting_qmk_rgblight = self.definition["lighting"] in ["qmk_rgblight", "qmk_backlight_rgblight"] + self.lighting_qmk_backlight = self.definition["lighting"] in ["qmk_backlight", "qmk_backlight_rgblight"] + + if self.lighting_qmk_rgblight: + self.underglow_brightness = self.usb_send( + self.dev, struct.pack(">BB", CMD_VIA_LIGHTING_GET_VALUE, QMK_RGBLIGHT_BRIGHTNESS), retries=20)[2] + self.underglow_effect = self.usb_send( + self.dev, struct.pack(">BB", CMD_VIA_LIGHTING_GET_VALUE, QMK_RGBLIGHT_EFFECT), retries=20)[2] + self.underglow_effect_speed = self.usb_send( + self.dev, struct.pack(">BB", CMD_VIA_LIGHTING_GET_VALUE, QMK_RGBLIGHT_EFFECT_SPEED), retries=20)[2] + color = self.usb_send( + self.dev, struct.pack(">BB", CMD_VIA_LIGHTING_GET_VALUE, QMK_RGBLIGHT_COLOR), retries=20)[2:4] + # hue, sat + self.underglow_color = (color[0], color[1]) + def set_key(self, layer, row, col, code): if code < 0: return @@ -354,6 +390,24 @@ class Keyboard: retries=20) self.macro = data + def set_qmk_rgblight_brightness(self, value): + self.underglow_brightness = value + self.usb_send(self.dev, struct.pack(">BBB", CMD_VIA_LIGHTING_SET_VALUE, QMK_RGBLIGHT_BRIGHTNESS, value), + retries=20) + + def set_qmk_rgblight_effect(self, index): + self.underglow_effect = index + self.usb_send(self.dev, struct.pack(">BBB", CMD_VIA_LIGHTING_SET_VALUE, QMK_RGBLIGHT_EFFECT, index), + retries=20) + + def set_qmk_rgblight_effect_speed(self, value): + self.underglow_effect_speed = value + self.usb_send(self.dev, struct.pack(">BBB", CMD_VIA_LIGHTING_SET_VALUE, QMK_RGBLIGHT_EFFECT_SPEED, value), + retries=20) + + def save_rgb(self): + self.usb_send(self.dev, struct.pack(">B", CMD_VIA_LIGHTING_SAVE), retries=20) + def save_layout(self): """ Serializes current layout to a binary """ diff --git a/src/main/python/main_window.py b/src/main/python/main_window.py index 334641a..57b409f 100644 --- a/src/main/python/main_window.py +++ b/src/main/python/main_window.py @@ -14,6 +14,7 @@ from keymap_editor import KeymapEditor from keymaps import KEYMAPS from layout_editor import LayoutEditor from macro_recorder import MacroRecorder +from rgb_configurator import RGBConfigurator from unlocker import Unlocker from util import tr, find_vial_devices, EXAMPLE_KEYBOARDS from vial_device import VialKeyboard @@ -54,9 +55,12 @@ class MainWindow(QMainWindow): self.firmware_flasher = FirmwareFlasher(self) self.macro_recorder = MacroRecorder() self.matrix_tester = MatrixTest(self.layout_editor) + self.rgb_configurator = RGBConfigurator() self.editors = [(self.keymap_editor, "Keymap"), (self.layout_editor, "Layout"), (self.macro_recorder, "Macros"), - (self.matrix_tester, "Matrix tester"), (self.firmware_flasher, "Firmware updater")] + (self.matrix_tester, "Matrix tester"), (self.rgb_configurator, "Lighting"), + (self.firmware_flasher, "Firmware updater")] + Unlocker.global_layout_editor = self.layout_editor self.tabs = QTabWidget() @@ -238,7 +242,7 @@ class MainWindow(QMainWindow): self.current_device.keyboard.reload() for e in [self.layout_editor, self.keymap_editor, self.firmware_flasher, self.macro_recorder, - self.matrix_tester]: + self.matrix_tester, self.rgb_configurator]: e.rebuild(self.current_device) def refresh_tabs(self): diff --git a/src/main/python/rgb_configurator.py b/src/main/python/rgb_configurator.py new file mode 100644 index 0000000..efbcc90 --- /dev/null +++ b/src/main/python/rgb_configurator.py @@ -0,0 +1,142 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +from PyQt5 import QtCore +from PyQt5.QtWidgets import QVBoxLayout, QWidget, QPushButton, QHBoxLayout, QSizePolicy, QGridLayout, QLabel, QSlider, \ + QComboBox + +from basic_editor import BasicEditor +from util import tr +from vial_device import VialKeyboard + + +class QmkRgblightEffect: + + def __init__(self, idx, name, color_picker): + self.idx = idx + self.name = name + self.color_picker = color_picker + + +QMK_RGBLIGHT_EFFECTS = [ + QmkRgblightEffect(0, "All Off", False), + QmkRgblightEffect(1, "Solid Color", True), + QmkRgblightEffect(2, "Breathing 1", True), + QmkRgblightEffect(3, "Breathing 2", True), + QmkRgblightEffect(4, "Breathing 3", True), + QmkRgblightEffect(5, "Breathing 4", True), + QmkRgblightEffect(6, "Rainbow Mood 1", False), + QmkRgblightEffect(7, "Rainbow Mood 2", False), + QmkRgblightEffect(8, "Rainbow Mood 3", False), + QmkRgblightEffect(9, "Rainbow Swirl 1", False), + QmkRgblightEffect(10, "Rainbow Swirl 2", False), + QmkRgblightEffect(11, "Rainbow Swirl 3", False), + QmkRgblightEffect(12, "Rainbow Swirl 4", False), + QmkRgblightEffect(13, "Rainbow Swirl 5", False), + QmkRgblightEffect(14, "Rainbow Swirl 6", False), + QmkRgblightEffect(15, "Snake 1", True), + QmkRgblightEffect(16, "Snake 2", True), + QmkRgblightEffect(17, "Snake 3", True), + QmkRgblightEffect(18, "Snake 4", True), + QmkRgblightEffect(19, "Snake 5", True), + QmkRgblightEffect(20, "Snake 6", True), + QmkRgblightEffect(21, "Knight 1", True), + QmkRgblightEffect(22, "Knight 2", True), + QmkRgblightEffect(23, "Knight 3", True), + QmkRgblightEffect(24, "Christmas", True), + QmkRgblightEffect(25, "Gradient 1", True), + QmkRgblightEffect(26, "Gradient 2", True), + QmkRgblightEffect(27, "Gradient 3", True), + QmkRgblightEffect(28, "Gradient 4", True), + QmkRgblightEffect(29, "Gradient 5", True), + QmkRgblightEffect(30, "Gradient 6", True), + QmkRgblightEffect(31, "Gradient 7", True), + QmkRgblightEffect(32, "Gradient 8", True), + QmkRgblightEffect(33, "Gradient 9", True), + QmkRgblightEffect(34, "Gradient 10", True), + QmkRgblightEffect(35, "RGB Test", True), + QmkRgblightEffect(36, "Alternating", True), +] + + +class RGBConfigurator(BasicEditor): + + def __init__(self): + super().__init__() + + self.addStretch() + + w = QWidget() + w.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) + self.container = QGridLayout() + w.setLayout(self.container) + self.addWidget(w) + self.setAlignment(w, QtCore.Qt.AlignHCenter) + + self.container.addWidget(QLabel(tr("RGBConfigurator", "Underglow Effect")), 0, 0) + self.underglow_effect = QComboBox() + for ef in QMK_RGBLIGHT_EFFECTS: + self.underglow_effect.addItem(ef.name) + self.container.addWidget(self.underglow_effect, 0, 1) + + self.container.addWidget(QLabel(tr("RGBConfigurator", "Underglow Brightness")), 1, 0) + self.underglow_brightness = QSlider(QtCore.Qt.Horizontal) + self.underglow_brightness.setMinimum(0) + self.underglow_brightness.setMaximum(255) + self.underglow_brightness.valueChanged.connect(self.on_underglow_brightness_changed) + self.container.addWidget(self.underglow_brightness, 1, 1) + + # XXX: qmk speed setting does nothing + # self.container.addWidget(QLabel(tr("RGBConfigurator", "Underglow Effect Speed")), 2, 0) + # self.underglow_effect_speed = QSlider(QtCore.Qt.Horizontal) + # self.underglow_effect_speed.setMinimum(0) + # self.underglow_effect_speed.setMaximum(3) + # self.underglow_effect_speed.valueChanged.connect(self.on_underglow_effect_speed_changed) + # self.container.addWidget(self.underglow_effect_speed, 2, 1) + + self.lbl_underglow_color = QLabel(tr("RGBConfigurator", "Underglow Color")) + self.container.addWidget(self.lbl_underglow_color, 3, 0) + self.underglow_color = QLabel("x") + self.container.addWidget(self.underglow_color, 3, 1) + + self.underglow_effect.currentIndexChanged.connect(self.on_underglow_effect_changed) + + self.addStretch() + buttons = QHBoxLayout() + buttons.addStretch() + save_btn = QPushButton(tr("RGBConfigurator", "Save")) + buttons.addWidget(save_btn) + save_btn.clicked.connect(self.on_save) + self.addLayout(buttons) + + def on_underglow_brightness_changed(self, value): + self.device.keyboard.set_qmk_rgblight_brightness(value) + + def on_underglow_effect_changed(self, index): + self.lbl_underglow_color.setVisible(QMK_RGBLIGHT_EFFECTS[index].color_picker) + self.underglow_color.setVisible(QMK_RGBLIGHT_EFFECTS[index].color_picker) + + self.device.keyboard.set_qmk_rgblight_effect(index) + + def on_underglow_effect_speed_changed(self, value): + self.device.keyboard.set_qmk_rgblight_effect_speed(value) + + def on_save(self): + self.device.keyboard.save_rgb() + + def valid(self): + return isinstance(self.device, VialKeyboard) and self.device.keyboard.lighting_qmk_rgblight + + def rebuild(self, device): + super().rebuild(device) + + if not self.valid(): + return + + # TODO: this should block signals from the actual combobox/etc sending them + # self.blockSignals(True) + + self.underglow_brightness.setValue(device.keyboard.underglow_brightness) + self.underglow_effect.setCurrentIndex(device.keyboard.underglow_effect) + # self.underglow_effect_speed.setValue(device.keyboard.underglow_effect_speed) + + # TODO: as above + # self.blockSignals(False)