From a15e8011d1e44091fb8eb762684d261c20f2e661 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 12:20:54 -0400 Subject: [PATCH 01/11] tap_dance: initial UI --- src/main/python/main_window.py | 7 ++-- src/main/python/tap_dance.py | 62 ++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/main/python/tap_dance.py diff --git a/src/main/python/main_window.py b/src/main/python/main_window.py index 8c32fe8..b879efb 100644 --- a/src/main/python/main_window.py +++ b/src/main/python/main_window.py @@ -18,6 +18,7 @@ from layout_editor import LayoutEditor from macro_recorder import MacroRecorder from qmk_settings import QmkSettings from rgb_configurator import RGBConfigurator +from tap_dance import TapDance from unlocker import Unlocker from util import tr, find_vial_devices, EXAMPLE_KEYBOARDS from vial_device import VialKeyboard @@ -58,12 +59,14 @@ class MainWindow(QMainWindow): self.keymap_editor = KeymapEditor(self.layout_editor) self.firmware_flasher = FirmwareFlasher(self) self.macro_recorder = MacroRecorder() + self.tap_dance = TapDance() self.qmk_settings = QmkSettings(self.appctx) 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.rgb_configurator, "Lighting"), (self.qmk_settings, "QMK Settings"), + (self.rgb_configurator, "Lighting"), (self.tap_dance, "Tap Dance"), + (self.qmk_settings, "QMK Settings"), (self.matrix_tester, "Matrix tester"), (self.firmware_flasher, "Firmware updater")] Unlocker.global_layout_editor = self.layout_editor @@ -257,7 +260,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.qmk_settings, self.matrix_tester, self.rgb_configurator]: + self.tap_dance, self.qmk_settings, self.matrix_tester, self.rgb_configurator]: e.rebuild(self.current_device) def refresh_tabs(self): diff --git a/src/main/python/tap_dance.py b/src/main/python/tap_dance.py new file mode 100644 index 0000000..7d920a3 --- /dev/null +++ b/src/main/python/tap_dance.py @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +from PyQt5 import QtCore +from PyQt5.QtWidgets import QTabWidget, QWidget, QSizePolicy, QGridLayout, QVBoxLayout, QLabel, QLineEdit, QHBoxLayout, \ + QPushButton + +from util import tr +from vial_device import VialKeyboard +from basic_editor import BasicEditor + + +class TapDance(BasicEditor): + + def __init__(self): + super().__init__() + self.keyboard = None + + self.tabs = QTabWidget() + for x in range(32): + container = QGridLayout() + + container.addWidget(QLabel("On tap"), 0, 0) + container.addWidget(QLineEdit(), 0, 1) + container.addWidget(QLabel("On hold"), 1, 0) + container.addWidget(QLineEdit(), 1, 1) + container.addWidget(QLabel("On double tap"), 2, 0) + container.addWidget(QLineEdit(), 2, 1) + container.addWidget(QLabel("On tap + hold"), 3, 0) + container.addWidget(QLineEdit(), 3, 1) + + w = QWidget() + w.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) + w.setLayout(container) + l = QVBoxLayout() + l.addStretch() + l.addWidget(w) + l.setAlignment(w, QtCore.Qt.AlignHCenter) + l.addSpacing(100) + lbl = QLabel("Use TD({}) to set up this action in the keymap.".format(x)) + l.addWidget(lbl) + l.setAlignment(lbl, QtCore.Qt.AlignHCenter) + l.addStretch() + w2 = QWidget() + w2.setLayout(l) + self.tabs.addTab(w2, str(x)) + + self.addWidget(self.tabs) + buttons = QHBoxLayout() + buttons.addStretch() + btn_save = QPushButton(tr("TapDance", "Save")) + btn_revert = QPushButton(tr("TapDance", "Revert")) + buttons.addWidget(btn_save) + buttons.addWidget(btn_revert) + self.addLayout(buttons) + + def rebuild(self, device): + super().rebuild(device) + if self.valid(): + self.keyboard = device.keyboard + + def valid(self): + return isinstance(self.device, VialKeyboard) and \ + (self.device.keyboard and self.device.keyboard.vial_protocol >= 4) From c9ff0e735a1283c3337fb01a89ff90b986cd1fb9 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 13:31:07 -0400 Subject: [PATCH 02/11] tap_dance: initial implementation --- src/main/python/keyboard_comm.py | 34 +++++++++ src/main/python/tap_dance.py | 121 +++++++++++++++++++++++-------- 2 files changed, 126 insertions(+), 29 deletions(-) diff --git a/src/main/python/keyboard_comm.py b/src/main/python/keyboard_comm.py index fdaa5d3..a104814 100644 --- a/src/main/python/keyboard_comm.py +++ b/src/main/python/keyboard_comm.py @@ -57,6 +57,12 @@ CMD_VIAL_QMK_SETTINGS_GET = 0x0A CMD_VIAL_QMK_SETTINGS_SET = 0x0B CMD_VIAL_QMK_SETTINGS_RESET = 0x0C +CMD_VIAL_DYNAMIC_ENTRY_OP = 0x0D + +DYNAMIC_VIAL_GET_NUMBER_OF_ENTRIES = 0x00 +DYNAMIC_VIAL_TAP_DANCE_GET = 0x01 +DYNAMIC_VIAL_TAP_DANCE_SET = 0x02 + # how much of a macro/keymap buffer we can read/write per packet BUFFER_FETCH_CHUNK = 28 @@ -207,6 +213,7 @@ class Keyboard: self.reload_keymap() self.reload_macros() self.reload_rgb() + self.reload_dynamic() def reload_layers(self): """ Get how many layers the keyboard has """ @@ -374,6 +381,22 @@ class Keyboard: self.backlight_effect = self.usb_send( self.dev, struct.pack(">BB", CMD_VIA_LIGHTING_GET_VALUE, QMK_BACKLIGHT_EFFECT), retries=20)[2] + def reload_dynamic(self): + if self.vial_protocol < 4: + self.tap_dance_count = 0 + self.tap_dance_entries = [] + return + data = self.usb_send(self.dev, struct.pack("BBB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_DYNAMIC_ENTRY_OP, + DYNAMIC_VIAL_GET_NUMBER_OF_ENTRIES), retries=20) + self.tap_dance_count = data[0] + self.tap_dance_entries = [] + for x in range(self.tap_dance_count): + data = self.usb_send(self.dev, struct.pack("BBBB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_DYNAMIC_ENTRY_OP, + DYNAMIC_VIAL_TAP_DANCE_GET, x), retries=20) + if data[0] != 0: + raise RuntimeError("failed retrieving tapdance entry {} from the device".format(x)) + self.tap_dance_entries.append(struct.unpack("TD({}) to set up this action in the keymap.".format(self.idx)) + l.addWidget(lbl) + l.setAlignment(lbl, QtCore.Qt.AlignHCenter) + l.addStretch() + self.w2 = QWidget() + self.w2.setLayout(l) + + def populate_container(self): + self.container.addWidget(QLabel("On tap"), 0, 0) + self.txt_on_tap = QLineEdit() + self.container.addWidget(self.txt_on_tap, 0, 1) + self.container.addWidget(QLabel("On hold"), 1, 0) + self.txt_on_hold = QLineEdit() + self.container.addWidget(self.txt_on_hold, 1, 1) + self.container.addWidget(QLabel("On double tap"), 2, 0) + self.txt_on_double_tap = QLineEdit() + self.container.addWidget(self.txt_on_double_tap, 2, 1) + self.container.addWidget(QLabel("On tap + hold"), 3, 0) + self.txt_on_tap_hold = QLineEdit() + self.container.addWidget(self.txt_on_tap_hold, 3, 1) + self.container.addWidget(QLabel("Tapping term (ms)"), 4, 0) + self.txt_tapping_term = QSpinBox() + self.txt_tapping_term.setMinimum(0) + self.txt_tapping_term.setMaximum(10000) + self.container.addWidget(self.txt_tapping_term, 4, 1) + + def widget(self): + return self.w2 + + def load(self, data): + self.txt_on_tap.setText(str(data[0])) + self.txt_on_hold.setText(str(data[1])) + self.txt_on_double_tap.setText(str(data[2])) + self.txt_on_tap_hold.setText(str(data[3])) + self.txt_tapping_term.setValue(data[4]) + + def save(self): + return ( + int(self.txt_on_tap.text()), + int(self.txt_on_hold.text()), + int(self.txt_on_double_tap.text()), + int(self.txt_on_tap_hold.text()), + self.txt_tapping_term.value() + ) + + class TapDance(BasicEditor): def __init__(self): super().__init__() self.keyboard = None + self.tap_dance_entries = [] + self.tap_dance_entries_available = [] self.tabs = QTabWidget() - for x in range(32): - container = QGridLayout() - - container.addWidget(QLabel("On tap"), 0, 0) - container.addWidget(QLineEdit(), 0, 1) - container.addWidget(QLabel("On hold"), 1, 0) - container.addWidget(QLineEdit(), 1, 1) - container.addWidget(QLabel("On double tap"), 2, 0) - container.addWidget(QLineEdit(), 2, 1) - container.addWidget(QLabel("On tap + hold"), 3, 0) - container.addWidget(QLineEdit(), 3, 1) - - w = QWidget() - w.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) - w.setLayout(container) - l = QVBoxLayout() - l.addStretch() - l.addWidget(w) - l.setAlignment(w, QtCore.Qt.AlignHCenter) - l.addSpacing(100) - lbl = QLabel("Use TD({}) to set up this action in the keymap.".format(x)) - l.addWidget(lbl) - l.setAlignment(lbl, QtCore.Qt.AlignHCenter) - l.addStretch() - w2 = QWidget() - w2.setLayout(l) - self.tabs.addTab(w2, str(x)) + for x in range(128): + self.tap_dance_entries_available.append(TapDanceEntryUI(x)) self.addWidget(self.tabs) buttons = QHBoxLayout() buttons.addStretch() btn_save = QPushButton(tr("TapDance", "Save")) + btn_save.clicked.connect(self.on_save) btn_revert = QPushButton(tr("TapDance", "Revert")) + btn_revert.clicked.connect(self.on_revert) buttons.addWidget(btn_save) buttons.addWidget(btn_revert) self.addLayout(buttons) + def rebuild_ui(self): + while self.tabs.count() > 0: + self.tabs.removeTab(0) + self.tap_dance_entries = self.tap_dance_entries_available[:self.keyboard.tap_dance_count] + for x, e in enumerate(self.tap_dance_entries): + self.tabs.addTab(e.widget(), str(x)) + self.reload_ui() + + def reload_ui(self): + for x, e in enumerate(self.tap_dance_entries): + e.load(self.keyboard.tap_dance_get(x)) + + def on_save(self): + for x, e in enumerate(self.tap_dance_entries): + self.keyboard.tap_dance_set(x, self.tap_dance_entries[x].save()) + + def on_revert(self): + self.keyboard.reload_dynamic() + self.reload_ui() + def rebuild(self, device): super().rebuild(device) if self.valid(): self.keyboard = device.keyboard + self.rebuild_ui() def valid(self): return isinstance(self.device, VialKeyboard) and \ - (self.device.keyboard and self.device.keyboard.vial_protocol >= 4) + (self.device.keyboard and self.device.keyboard.vial_protocol >= 4 + and self.device.keyboard.tap_dance_count > 0) From cc031a5c01adfe7e9ef92def17c9484687de0670 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 13:50:34 -0400 Subject: [PATCH 03/11] keyboard_comm: save/restore tapdance --- src/main/python/keyboard_comm.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/python/keyboard_comm.py b/src/main/python/keyboard_comm.py index a104814..33eb7bf 100644 --- a/src/main/python/keyboard_comm.py +++ b/src/main/python/keyboard_comm.py @@ -500,6 +500,7 @@ class Keyboard: data["macro"] = self.save_macro() data["vial_protocol"] = self.vial_protocol data["via_protocol"] = self.via_protocol + data["tap_dance"] = self.tap_dance_entries return json.dumps(data).encode("utf-8") @@ -531,6 +532,10 @@ class Keyboard: self.set_layout_options(data["layout_options"]) self.restore_macros(data.get("macro")) + for x, e in enumerate(data.get("tap_dance", [])): + if x < self.tap_dance_count: + self.tap_dance_set(x, e) + def restore_macros(self, macros): if not isinstance(macros, list): return From ec3df5bdd072d9bbb8e4790d1ee7466e2be89655 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 14:37:45 -0400 Subject: [PATCH 04/11] tap_dance: initial implementation of key selection tray --- src/main/python/key_widget.py | 25 +++++++++++++++++++++++++ src/main/python/keyboard_widget.py | 12 +++++++----- src/main/python/main_window.py | 6 ++++++ src/main/python/tabbed_keycodes.py | 18 ++++++++++++++++++ src/main/python/tap_dance.py | 14 ++++++++------ 5 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 src/main/python/key_widget.py diff --git a/src/main/python/key_widget.py b/src/main/python/key_widget.py new file mode 100644 index 0000000..0e018fe --- /dev/null +++ b/src/main/python/key_widget.py @@ -0,0 +1,25 @@ +from keyboard_widget import KeyboardWidget +from kle_serial import Key +from tabbed_keycodes import TabbedKeycodes + + +class KeyWidget(KeyboardWidget): + + def __init__(self): + super().__init__(None) + + self.padding = 1 + + self.keycode = 0 + + key = Key() + key.row = key.col = 0 + key.layout_index = key.layout_option = -1 + self.set_keys([key], []) + + def mousePressEvent(self, ev): + super().mousePressEvent(ev) + if self.active_key is not None: + TabbedKeycodes.open_tray(self) + else: + TabbedKeycodes.close_tray() diff --git a/src/main/python/keyboard_widget.py b/src/main/python/keyboard_widget.py index e4493a8..5eb9450 100644 --- a/src/main/python/keyboard_widget.py +++ b/src/main/python/keyboard_widget.py @@ -4,7 +4,8 @@ from PyQt5.QtGui import QPainter, QColor, QPainterPath, QTransform, QBrush, QPol from PyQt5.QtWidgets import QWidget, QToolTip, QApplication from PyQt5.QtCore import Qt, QSize, QRect, QPointF, pyqtSignal, QEvent, QRectF -from constants import KEY_SIZE_RATIO, KEY_SPACING_RATIO, KEYBOARD_WIDGET_PADDING, KEYBOARD_WIDGET_MASK_PADDING, KEYBOARD_WIDGET_MASK_HEIGHT, KEY_ROUNDNESS +from constants import KEY_SIZE_RATIO, KEY_SPACING_RATIO, KEYBOARD_WIDGET_PADDING, KEYBOARD_WIDGET_MASK_PADDING,\ + KEYBOARD_WIDGET_MASK_HEIGHT, KEY_ROUNDNESS class KeyWidget: @@ -166,6 +167,7 @@ class KeyboardWidget(QWidget): self.enabled = True self.scale = 1 + self.padding = KEYBOARD_WIDGET_PADDING self.setMouseTracking(True) @@ -215,7 +217,7 @@ class KeyboardWidget(QWidget): # place common widgets, that is, ones which are always displayed and require no extra transforms for widget in self.common_widgets: - widget.update_position(scale_factor, -top_x + KEYBOARD_WIDGET_PADDING, -top_y + KEYBOARD_WIDGET_PADDING) + widget.update_position(scale_factor, -top_x + self.padding, -top_y + self.padding) self.widgets.append(widget) # top-left position for specific layout @@ -236,7 +238,7 @@ class KeyboardWidget(QWidget): if opt == self.layout_editor.get_choice(idx): shift_x = layout_x[idx][opt] - layout_x[idx][0] shift_y = layout_y[idx][opt] - layout_y[idx][0] - widget.update_position(scale_factor, -shift_x - top_x + KEYBOARD_WIDGET_PADDING, -shift_y - top_y + KEYBOARD_WIDGET_PADDING) + widget.update_position(scale_factor, -shift_x - top_x + self.padding, -shift_y - top_y + self.padding) self.widgets.append(widget) def update_layout(self): @@ -255,8 +257,8 @@ class KeyboardWidget(QWidget): max_w = max(max_w, p.x() * self.scale) max_h = max(max_h, p.y() * self.scale) - self.width = max_w + 2 * KEYBOARD_WIDGET_PADDING - self.height = max_h + 2 * KEYBOARD_WIDGET_PADDING + self.width = max_w + 2 * self.padding + self.height = max_h + 2 * self.padding self.update() self.updateGeometry() diff --git a/src/main/python/main_window.py b/src/main/python/main_window.py index b879efb..a30b4e3 100644 --- a/src/main/python/main_window.py +++ b/src/main/python/main_window.py @@ -18,6 +18,7 @@ from layout_editor import LayoutEditor from macro_recorder import MacroRecorder from qmk_settings import QmkSettings from rgb_configurator import RGBConfigurator +from tabbed_keycodes import TabbedKeycodes from tap_dance import TapDance from unlocker import Unlocker from util import tr, find_vial_devices, EXAMPLE_KEYBOARDS @@ -91,6 +92,10 @@ class MainWindow(QMainWindow): layout.addWidget(self.tabs) layout.addWidget(self.lbl_no_devices) layout.setAlignment(self.lbl_no_devices, Qt.AlignHCenter) + self.popup_keycodes = TabbedKeycodes() + TabbedKeycodes.set_tray(self.popup_keycodes) + layout.addWidget(self.popup_keycodes) + self.popup_keycodes.hide() w = QWidget() w.setLayout(layout) self.setCentralWidget(w) @@ -343,6 +348,7 @@ class MainWindow(QMainWindow): msg.exec_() def on_tab_changed(self, index): + TabbedKeycodes.close_tray() old_tab = self.current_tab new_tab = None if index >= 0: diff --git a/src/main/python/tabbed_keycodes.py b/src/main/python/tabbed_keycodes.py index 9c2d5c4..edb2471 100644 --- a/src/main/python/tabbed_keycodes.py +++ b/src/main/python/tabbed_keycodes.py @@ -22,6 +22,7 @@ class TabbedKeycodes(QTabWidget): super().__init__(parent) self.keymap_override = None + self.target = None self.tab_basic = QScrollArea() self.tab_iso = QScrollArea() @@ -116,3 +117,20 @@ class TabbedKeycodes(QTabWidget): label = widget.keycode.label widget.setStyleSheet("QPushButton {}") widget.setText(label.replace("&", "&&")) + + @classmethod + def set_tray(cls, tray): + cls.tray = tray + + @classmethod + def open_tray(cls, target): + cls.tray.show() + if cls.tray.target is not None and cls.tray.target != target: + cls.tray.target.deselect() + cls.tray.target = target + + @classmethod + def close_tray(cls): + if cls.tray.target is not None: + cls.tray.target.deselect() + cls.tray.hide() diff --git a/src/main/python/tap_dance.py b/src/main/python/tap_dance.py index ff33ec7..8f8088d 100644 --- a/src/main/python/tap_dance.py +++ b/src/main/python/tap_dance.py @@ -3,6 +3,7 @@ from PyQt5 import QtCore from PyQt5.QtWidgets import QTabWidget, QWidget, QSizePolicy, QGridLayout, QVBoxLayout, QLabel, QLineEdit, QHBoxLayout, \ QPushButton, QSpinBox +from key_widget import KeyWidget from util import tr from vial_device import VialKeyboard from basic_editor import BasicEditor @@ -20,10 +21,10 @@ class TapDanceEntryUI: w.setLayout(self.container) l = QVBoxLayout() l.addStretch() - l.addSpacing(100) + l.addSpacing(10) l.addWidget(w) l.setAlignment(w, QtCore.Qt.AlignHCenter) - l.addSpacing(100) + l.addSpacing(10) lbl = QLabel("Use TD({}) to set up this action in the keymap.".format(self.idx)) l.addWidget(lbl) l.setAlignment(lbl, QtCore.Qt.AlignHCenter) @@ -34,16 +35,17 @@ class TapDanceEntryUI: def populate_container(self): self.container.addWidget(QLabel("On tap"), 0, 0) self.txt_on_tap = QLineEdit() - self.container.addWidget(self.txt_on_tap, 0, 1) + # self.container.addWidget(self.txt_on_tap, 0, 1) + self.container.addWidget(KeyWidget(), 0, 1) self.container.addWidget(QLabel("On hold"), 1, 0) self.txt_on_hold = QLineEdit() - self.container.addWidget(self.txt_on_hold, 1, 1) + self.container.addWidget(KeyWidget(), 1, 1) self.container.addWidget(QLabel("On double tap"), 2, 0) self.txt_on_double_tap = QLineEdit() - self.container.addWidget(self.txt_on_double_tap, 2, 1) + self.container.addWidget(KeyWidget(), 2, 1) self.container.addWidget(QLabel("On tap + hold"), 3, 0) self.txt_on_tap_hold = QLineEdit() - self.container.addWidget(self.txt_on_tap_hold, 3, 1) + self.container.addWidget(KeyWidget(), 3, 1) self.container.addWidget(QLabel("Tapping term (ms)"), 4, 0) self.txt_tapping_term = QSpinBox() self.txt_tapping_term.setMinimum(0) From fea0dcaa9b8403d4d6c6ea8c77780337aaa0ac7d Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 14:56:41 -0400 Subject: [PATCH 05/11] move keymap override handling into global util --- src/main/python/key_widget.py | 4 +++ src/main/python/keymap_editor.py | 42 ++++-------------------- src/main/python/main_window.py | 12 +++---- src/main/python/tabbed_keycodes.py | 29 ++++++++++++----- src/main/python/util.py | 52 +++++++++++++++++++++++++++++- 5 files changed, 89 insertions(+), 50 deletions(-) diff --git a/src/main/python/key_widget.py b/src/main/python/key_widget.py index 0e018fe..b686816 100644 --- a/src/main/python/key_widget.py +++ b/src/main/python/key_widget.py @@ -23,3 +23,7 @@ class KeyWidget(KeyboardWidget): TabbedKeycodes.open_tray(self) else: TabbedKeycodes.close_tray() + + def on_keycode_changed(self, kc): + """ Unlike set_keycode, this handles setting masked keycode inside the mask """ + print(kc) diff --git a/src/main/python/keymap_editor.py b/src/main/python/keymap_editor.py index 85139a9..8f9c543 100644 --- a/src/main/python/keymap_editor.py +++ b/src/main/python/keymap_editor.py @@ -1,8 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later import json -from PyQt5.QtGui import QPalette -from PyQt5.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout, QMessageBox, QApplication +from PyQt5.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout, QMessageBox from PyQt5.QtCore import Qt from any_keycode_dialog import AnyKeycodeDialog @@ -12,7 +11,7 @@ from keycodes import recreate_keyboard_keycodes, Keycode from keymaps import KEYMAPS from square_button import SquareButton from tabbed_keycodes import TabbedKeycodes -from util import tr +from util import tr, KeycodeDisplay from vial_device import VialKeyboard @@ -48,8 +47,6 @@ class KeymapEditor(BasicEditor): layout_editor.changed.connect(self.on_layout_changed) - self.keymap_override = KEYMAPS[0][1] - self.container.anykey.connect(self.on_any_keycode) self.tabbed_keycodes = TabbedKeycodes() @@ -60,6 +57,7 @@ class KeymapEditor(BasicEditor): self.addWidget(self.tabbed_keycodes) self.device = None + KeycodeDisplay.notify_keymap_override(self) def on_container_clicked(self): """ Called when a mouse click event is bubbled up to the editor's container """ @@ -135,11 +133,6 @@ class KeymapEditor(BasicEditor): self.keyboard.restore_layout(data) self.refresh_layer_display() - def set_keymap_override(self, override): - self.keymap_override = override - self.refresh_layer_display() - self.tabbed_keycodes.set_keymap_override(override) - def on_any_keycode(self): if self.container.active_key is None: return @@ -148,17 +141,6 @@ class KeymapEditor(BasicEditor): if dlg.exec_() and dlg.value >= 0: self.on_keycode_changed(dlg.value) - def code_is_overriden(self, code): - """ Check whether a country-specific keymap overrides a code """ - key = Keycode.find_outer_keycode(code) - return key is not None and key.qmk_id in self.keymap_override - - def get_label(self, code): - """ Get label for a specific keycode """ - if self.code_is_overriden(code): - return self.keymap_override[Keycode.find_outer_keycode(code).qmk_id] - return Keycode.label(code) - def code_for_widget(self, widget): if widget.desc.row is not None: return self.keyboard.layout[(self.current_layer, widget.desc.row, widget.desc.col)] @@ -177,20 +159,7 @@ class KeymapEditor(BasicEditor): for widget in self.container.widgets: code = self.code_for_widget(widget) - text = self.get_label(code) - tooltip = Keycode.tooltip(code) - mask = Keycode.is_mask(code) - mask_text = self.get_label(code & 0xFF) - if mask: - text = text.split("\n")[0] - widget.masked = mask - widget.setText(text) - widget.setMaskText(mask_text) - widget.setToolTip(tooltip) - if self.code_is_overriden(code): - widget.setColor(QApplication.palette().color(QPalette.Link)) - else: - widget.setColor(None) + KeycodeDisplay.display_keycode(widget, code) self.container.update() self.container.updateGeometry() @@ -245,3 +214,6 @@ class KeymapEditor(BasicEditor): self.refresh_layer_display() self.keyboard.set_layout_options(self.layout_editor.pack()) + + def on_keymap_override(self): + self.refresh_layer_display() diff --git a/src/main/python/main_window.py b/src/main/python/main_window.py index a30b4e3..43011e6 100644 --- a/src/main/python/main_window.py +++ b/src/main/python/main_window.py @@ -21,7 +21,7 @@ from rgb_configurator import RGBConfigurator from tabbed_keycodes import TabbedKeycodes from tap_dance import TapDance from unlocker import Unlocker -from util import tr, find_vial_devices, EXAMPLE_KEYBOARDS +from util import tr, find_vial_devices, EXAMPLE_KEYBOARDS, KeycodeDisplay from vial_device import VialKeyboard from matrix_test import MatrixTest @@ -92,10 +92,10 @@ class MainWindow(QMainWindow): layout.addWidget(self.tabs) layout.addWidget(self.lbl_no_devices) layout.setAlignment(self.lbl_no_devices, Qt.AlignHCenter) - self.popup_keycodes = TabbedKeycodes() - TabbedKeycodes.set_tray(self.popup_keycodes) - layout.addWidget(self.popup_keycodes) - self.popup_keycodes.hide() + self.tray_keycodes = TabbedKeycodes() + self.tray_keycodes.make_tray() + layout.addWidget(self.tray_keycodes) + self.tray_keycodes.hide() w = QWidget() w.setLayout(layout) self.setCentralWidget(w) @@ -335,7 +335,7 @@ class MainWindow(QMainWindow): def change_keyboard_layout(self, index): self.settings.setValue("keymap", KEYMAPS[index][0]) - self.keymap_editor.set_keymap_override(KEYMAPS[index][1]) + KeycodeDisplay.set_keymap_override(KEYMAPS[index][1]) def get_theme(self): return self.settings.value("theme", "Dark") diff --git a/src/main/python/tabbed_keycodes.py b/src/main/python/tabbed_keycodes.py index edb2471..b59eff4 100644 --- a/src/main/python/tabbed_keycodes.py +++ b/src/main/python/tabbed_keycodes.py @@ -8,9 +8,8 @@ from constants import KEYCODE_BTN_RATIO from flowlayout import FlowLayout from keycodes import KEYCODES_BASIC, KEYCODES_ISO, KEYCODES_MACRO, KEYCODES_LAYERS, KEYCODES_QUANTUM, \ KEYCODES_BACKLIGHT, KEYCODES_MEDIA, KEYCODES_SPECIAL, KEYCODES_SHIFTED, KEYCODES_USER, Keycode -from keymaps import KEYMAPS from square_button import SquareButton -from util import tr +from util import tr, KeycodeDisplay class TabbedKeycodes(QTabWidget): @@ -21,8 +20,8 @@ class TabbedKeycodes(QTabWidget): def __init__(self, parent=None): super().__init__(parent) - self.keymap_override = None self.target = None + self.is_tray = False self.tab_basic = QScrollArea() self.tab_iso = QScrollArea() @@ -74,7 +73,7 @@ class TabbedKeycodes(QTabWidget): self.layer_keycode_buttons = [] self.macro_keycode_buttons = [] self.user_keycode_buttons = [] - self.set_keymap_override(KEYMAPS[0][1]) + KeycodeDisplay.notify_keymap_override(self) def create_buttons(self, layout, keycodes, wordWrap = False): buttons = [] @@ -102,15 +101,14 @@ class TabbedKeycodes(QTabWidget): self.widgets += self.layer_keycode_buttons + self.macro_keycode_buttons + self.user_keycode_buttons self.relabel_buttons() - def set_keymap_override(self, override): - self.keymap_override = override + def on_keymap_override(self): self.relabel_buttons() def relabel_buttons(self): for widget in self.widgets: qmk_id = widget.keycode.qmk_id - if qmk_id in self.keymap_override: - label = self.keymap_override[qmk_id] + if qmk_id in KeycodeDisplay.keymap_override: + label = KeycodeDisplay.keymap_override[qmk_id] highlight_color = QApplication.palette().color(QPalette.Link).getRgb() widget.setStyleSheet("QPushButton {color: rgb"+str(highlight_color)+";}") else: @@ -133,4 +131,19 @@ class TabbedKeycodes(QTabWidget): def close_tray(cls): if cls.tray.target is not None: cls.tray.target.deselect() + cls.tray.target = None cls.tray.hide() + + def make_tray(self): + self.is_tray = True + TabbedKeycodes.set_tray(self) + + self.keycode_changed.connect(self.on_tray_keycode_changed) + self.anykey.connect(self.on_tray_anykey) + + def on_tray_keycode_changed(self, kc): + if self.target is not None: + self.target.on_keycode_changed(kc) + + def on_tray_anykey(self): + pass diff --git a/src/main/python/util.py b/src/main/python/util.py index 1c020ae..2740431 100644 --- a/src/main/python/util.py +++ b/src/main/python/util.py @@ -5,9 +5,12 @@ import time from logging.handlers import RotatingFileHandler from PyQt5.QtCore import QCoreApplication, QStandardPaths +from PyQt5.QtGui import QPalette +from PyQt5.QtWidgets import QApplication from hidproxy import hid - +from keycodes import Keycode +from keymaps import KEYMAPS tr = QCoreApplication.translate @@ -147,3 +150,50 @@ def init_logger(): handler = RotatingFileHandler(path, maxBytes=5 * 1024 * 1024, backupCount=5) handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s")) logging.getLogger().addHandler(handler) + + +class KeycodeDisplay: + + keymap_override = KEYMAPS[0][1] + clients = [] + + @classmethod + def get_label(cls, code): + """ Get label for a specific keycode """ + if cls.code_is_overriden(code): + return cls.keymap_override[Keycode.find_outer_keycode(code).qmk_id] + return Keycode.label(code) + + @classmethod + def code_is_overriden(cls, code): + """ Check whether a country-specific keymap overrides a code """ + key = Keycode.find_outer_keycode(code) + return key is not None and key.qmk_id in cls.keymap_override + + @classmethod + def display_keycode(cls, widget, code): + text = cls.get_label(code) + tooltip = Keycode.tooltip(code) + mask = Keycode.is_mask(code) + mask_text = cls.get_label(code & 0xFF) + if mask: + text = text.split("\n")[0] + widget.masked = mask + widget.setText(text) + widget.setMaskText(mask_text) + widget.setToolTip(tooltip) + if cls.code_is_overriden(code): + widget.setColor(QApplication.palette().color(QPalette.Link)) + else: + widget.setColor(None) + + @classmethod + def set_keymap_override(cls, override): + cls.keymap_override = override + for client in cls.clients: + client.on_keymap_override() + + @classmethod + def notify_keymap_override(cls, client): + cls.clients.append(client) + client.on_keymap_override() From af311b51c3fc8b8724b6eaf25fe197d26b59b0c7 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 16:16:07 -0400 Subject: [PATCH 06/11] key_widget: support changing keycodes --- src/main/python/key_widget.py | 25 +++++++++++++++++++++++-- src/main/python/tabbed_keycodes.py | 3 ++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/python/key_widget.py b/src/main/python/key_widget.py index b686816..86f37fd 100644 --- a/src/main/python/key_widget.py +++ b/src/main/python/key_widget.py @@ -1,6 +1,8 @@ +from any_keycode_dialog import AnyKeycodeDialog from keyboard_widget import KeyboardWidget from kle_serial import Key from tabbed_keycodes import TabbedKeycodes +from util import KeycodeDisplay class KeyWidget(KeyboardWidget): @@ -17,6 +19,8 @@ class KeyWidget(KeyboardWidget): key.layout_index = key.layout_option = -1 self.set_keys([key], []) + self.anykey.connect(self.on_anykey) + def mousePressEvent(self, ev): super().mousePressEvent(ev) if self.active_key is not None: @@ -24,6 +28,23 @@ class KeyWidget(KeyboardWidget): else: TabbedKeycodes.close_tray() - def on_keycode_changed(self, kc): + def on_keycode_changed(self, keycode): """ Unlike set_keycode, this handles setting masked keycode inside the mask """ - print(kc) + + if self.active_mask: + if keycode > 0xFF: + return + keycode = (self.keycode & 0xFF00) | keycode + self.set_keycode(keycode) + + def on_anykey(self): + if self.active_key is None: + return + dlg = AnyKeycodeDialog(self.keycode) + if dlg.exec_() and dlg.value >= 0: + self.set_keycode(dlg.value) + + def set_keycode(self, kc): + self.keycode = kc + KeycodeDisplay.display_keycode(self.widgets[0], self.keycode) + self.update() diff --git a/src/main/python/tabbed_keycodes.py b/src/main/python/tabbed_keycodes.py index b59eff4..266bec3 100644 --- a/src/main/python/tabbed_keycodes.py +++ b/src/main/python/tabbed_keycodes.py @@ -146,4 +146,5 @@ class TabbedKeycodes(QTabWidget): self.target.on_keycode_changed(kc) def on_tray_anykey(self): - pass + if self.target is not None: + self.target.on_anykey() From 028655f418b3a84ee09a952382e849f801c90995 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 16:27:22 -0400 Subject: [PATCH 07/11] tap_dance: switch to new key widgets --- src/main/python/tap_dance.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/main/python/tap_dance.py b/src/main/python/tap_dance.py index 8f8088d..3e9d4ac 100644 --- a/src/main/python/tap_dance.py +++ b/src/main/python/tap_dance.py @@ -34,18 +34,17 @@ class TapDanceEntryUI: def populate_container(self): self.container.addWidget(QLabel("On tap"), 0, 0) - self.txt_on_tap = QLineEdit() - # self.container.addWidget(self.txt_on_tap, 0, 1) - self.container.addWidget(KeyWidget(), 0, 1) + self.kc_on_tap = KeyWidget() + self.container.addWidget(self.kc_on_tap, 0, 1) self.container.addWidget(QLabel("On hold"), 1, 0) - self.txt_on_hold = QLineEdit() - self.container.addWidget(KeyWidget(), 1, 1) + self.kc_on_hold = KeyWidget() + self.container.addWidget(self.kc_on_hold, 1, 1) self.container.addWidget(QLabel("On double tap"), 2, 0) - self.txt_on_double_tap = QLineEdit() - self.container.addWidget(KeyWidget(), 2, 1) + self.kc_on_double_tap = KeyWidget() + self.container.addWidget(self.kc_on_double_tap, 2, 1) self.container.addWidget(QLabel("On tap + hold"), 3, 0) - self.txt_on_tap_hold = QLineEdit() - self.container.addWidget(KeyWidget(), 3, 1) + self.kc_on_tap_hold = KeyWidget() + self.container.addWidget(self.kc_on_tap_hold, 3, 1) self.container.addWidget(QLabel("Tapping term (ms)"), 4, 0) self.txt_tapping_term = QSpinBox() self.txt_tapping_term.setMinimum(0) @@ -56,18 +55,18 @@ class TapDanceEntryUI: return self.w2 def load(self, data): - self.txt_on_tap.setText(str(data[0])) - self.txt_on_hold.setText(str(data[1])) - self.txt_on_double_tap.setText(str(data[2])) - self.txt_on_tap_hold.setText(str(data[3])) + self.kc_on_tap.set_keycode(data[0]) + self.kc_on_hold.set_keycode(data[1]) + self.kc_on_double_tap.set_keycode(data[2]) + self.kc_on_tap_hold.set_keycode(data[3]) self.txt_tapping_term.setValue(data[4]) def save(self): return ( - int(self.txt_on_tap.text()), - int(self.txt_on_hold.text()), - int(self.txt_on_double_tap.text()), - int(self.txt_on_tap_hold.text()), + self.kc_on_tap.keycode, + self.kc_on_hold.keycode, + self.kc_on_double_tap.keycode, + self.kc_on_tap_hold.keycode, self.txt_tapping_term.value() ) From 8f4734ab4056870703296775bfe49f00e8aa8de3 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 16:53:24 -0400 Subject: [PATCH 08/11] tap_dance: track state of tab change --- src/main/python/key_widget.py | 8 +++++ src/main/python/tap_dance.py | 56 +++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/main/python/key_widget.py b/src/main/python/key_widget.py index 86f37fd..bf7fd6b 100644 --- a/src/main/python/key_widget.py +++ b/src/main/python/key_widget.py @@ -1,3 +1,5 @@ +from PyQt5.QtCore import pyqtSignal + from any_keycode_dialog import AnyKeycodeDialog from keyboard_widget import KeyboardWidget from kle_serial import Key @@ -7,6 +9,8 @@ from util import KeycodeDisplay class KeyWidget(KeyboardWidget): + changed = pyqtSignal() + def __init__(self): super().__init__(None) @@ -45,6 +49,10 @@ class KeyWidget(KeyboardWidget): self.set_keycode(dlg.value) def set_keycode(self, kc): + if kc == self.keycode: + return self.keycode = kc KeycodeDisplay.display_keycode(self.widgets[0], self.keycode) self.update() + + self.changed.emit() diff --git a/src/main/python/tap_dance.py b/src/main/python/tap_dance.py index 3e9d4ac..cf950b3 100644 --- a/src/main/python/tap_dance.py +++ b/src/main/python/tap_dance.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later from PyQt5 import QtCore +from PyQt5.QtCore import pyqtSignal, QObject from PyQt5.QtWidgets import QTabWidget, QWidget, QSizePolicy, QGridLayout, QVBoxLayout, QLabel, QLineEdit, QHBoxLayout, \ QPushButton, QSpinBox @@ -9,9 +10,14 @@ from vial_device import VialKeyboard from basic_editor import BasicEditor -class TapDanceEntryUI: +class TapDanceEntryUI(QObject): + + key_changed = pyqtSignal() + timing_changed = pyqtSignal() def __init__(self, idx): + super().__init__() + self.idx = idx self.container = QGridLayout() self.populate_container() @@ -35,18 +41,23 @@ class TapDanceEntryUI: def populate_container(self): self.container.addWidget(QLabel("On tap"), 0, 0) self.kc_on_tap = KeyWidget() + self.kc_on_tap.changed.connect(self.on_key_changed) self.container.addWidget(self.kc_on_tap, 0, 1) self.container.addWidget(QLabel("On hold"), 1, 0) self.kc_on_hold = KeyWidget() + self.kc_on_hold.changed.connect(self.on_key_changed) self.container.addWidget(self.kc_on_hold, 1, 1) self.container.addWidget(QLabel("On double tap"), 2, 0) self.kc_on_double_tap = KeyWidget() + self.kc_on_double_tap.changed.connect(self.on_key_changed) self.container.addWidget(self.kc_on_double_tap, 2, 1) self.container.addWidget(QLabel("On tap + hold"), 3, 0) self.kc_on_tap_hold = KeyWidget() + self.kc_on_tap_hold.changed.connect(self.on_key_changed) self.container.addWidget(self.kc_on_tap_hold, 3, 1) self.container.addWidget(QLabel("Tapping term (ms)"), 4, 0) self.txt_tapping_term = QSpinBox() + self.txt_tapping_term.valueChanged.connect(self.on_timing_changed) self.txt_tapping_term.setMinimum(0) self.txt_tapping_term.setMaximum(10000) self.container.addWidget(self.txt_tapping_term, 4, 1) @@ -55,12 +66,19 @@ class TapDanceEntryUI: return self.w2 def load(self, data): + objs = [self.kc_on_tap, self.kc_on_hold, self.kc_on_double_tap, self.kc_on_tap_hold, self.txt_tapping_term] + for o in objs: + o.blockSignals(True) + self.kc_on_tap.set_keycode(data[0]) self.kc_on_hold.set_keycode(data[1]) self.kc_on_double_tap.set_keycode(data[2]) self.kc_on_tap_hold.set_keycode(data[3]) self.txt_tapping_term.setValue(data[4]) + for o in objs: + o.blockSignals(False) + def save(self): return ( self.kc_on_tap.keycode, @@ -70,6 +88,12 @@ class TapDanceEntryUI: self.txt_tapping_term.value() ) + def on_key_changed(self): + self.key_changed.emit() + + def on_timing_changed(self): + self.timing_changed.emit() + class TapDance(BasicEditor): @@ -81,16 +105,19 @@ class TapDance(BasicEditor): self.tap_dance_entries_available = [] self.tabs = QTabWidget() for x in range(128): - self.tap_dance_entries_available.append(TapDanceEntryUI(x)) + entry = TapDanceEntryUI(x) + entry.key_changed.connect(self.on_key_changed) + entry.timing_changed.connect(self.on_timing_changed) + self.tap_dance_entries_available.append(entry) self.addWidget(self.tabs) buttons = QHBoxLayout() buttons.addStretch() - btn_save = QPushButton(tr("TapDance", "Save")) - btn_save.clicked.connect(self.on_save) + self.btn_save = QPushButton(tr("TapDance", "Save")) + self.btn_save.clicked.connect(self.on_save) btn_revert = QPushButton(tr("TapDance", "Revert")) btn_revert.clicked.connect(self.on_revert) - buttons.addWidget(btn_save) + buttons.addWidget(self.btn_save) buttons.addWidget(btn_revert) self.addLayout(buttons) @@ -105,10 +132,12 @@ class TapDance(BasicEditor): def reload_ui(self): for x, e in enumerate(self.tap_dance_entries): e.load(self.keyboard.tap_dance_get(x)) + self.update_modified_state() def on_save(self): for x, e in enumerate(self.tap_dance_entries): self.keyboard.tap_dance_set(x, self.tap_dance_entries[x].save()) + self.update_modified_state() def on_revert(self): self.keyboard.reload_dynamic() @@ -124,3 +153,20 @@ class TapDance(BasicEditor): return isinstance(self.device, VialKeyboard) and \ (self.device.keyboard and self.device.keyboard.vial_protocol >= 4 and self.device.keyboard.tap_dance_count > 0) + + def on_key_changed(self): + self.on_save() + + def update_modified_state(self): + """ Update indication of which tabs are modified, and keep Save button enabled only if it's needed """ + has_changes = False + for x, e in enumerate(self.tap_dance_entries): + if self.tap_dance_entries[x].save() != self.keyboard.tap_dance_get(x): + has_changes = True + self.tabs.setTabText(x, "{}*".format(x)) + else: + self.tabs.setTabText(x, str(x)) + self.btn_save.setEnabled(has_changes) + + def on_timing_changed(self): + self.update_modified_state() From 838182494802f897b2d8c192b7ff6404a602ae55 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 20:06:26 -0400 Subject: [PATCH 09/11] tap_dance: hide keycode tray when empty space is clicked --- src/main/python/key_widget.py | 3 +++ src/main/python/tap_dance.py | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/python/key_widget.py b/src/main/python/key_widget.py index bf7fd6b..607fdcf 100644 --- a/src/main/python/key_widget.py +++ b/src/main/python/key_widget.py @@ -32,6 +32,9 @@ class KeyWidget(KeyboardWidget): else: TabbedKeycodes.close_tray() + def mouseReleaseEvent(self, ev): + ev.accept() + def on_keycode_changed(self, keycode): """ Unlike set_keycode, this handles setting masked keycode inside the mask """ diff --git a/src/main/python/tap_dance.py b/src/main/python/tap_dance.py index cf950b3..5afb982 100644 --- a/src/main/python/tap_dance.py +++ b/src/main/python/tap_dance.py @@ -5,6 +5,7 @@ from PyQt5.QtWidgets import QTabWidget, QWidget, QSizePolicy, QGridLayout, QVBox QPushButton, QSpinBox from key_widget import KeyWidget +from tabbed_keycodes import TabbedKeycodes from util import tr from vial_device import VialKeyboard from basic_editor import BasicEditor @@ -95,6 +96,12 @@ class TapDanceEntryUI(QObject): self.timing_changed.emit() +class CustomTabWidget(QTabWidget): + + def mouseReleaseEvent(self, ev): + TabbedKeycodes.close_tray() + + class TapDance(BasicEditor): def __init__(self): @@ -103,7 +110,7 @@ class TapDance(BasicEditor): self.tap_dance_entries = [] self.tap_dance_entries_available = [] - self.tabs = QTabWidget() + self.tabs = CustomTabWidget() for x in range(128): entry = TapDanceEntryUI(x) entry.key_changed.connect(self.on_key_changed) From 5bb644615597b4e0ec3d370fb74755d31ef458ab Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 22:25:45 -0400 Subject: [PATCH 10/11] tabbed_keycodes: show tap dance in the UI --- src/main/python/keycodes.py | 10 ++++++++-- src/main/python/tabbed_keycodes.py | 20 ++++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/main/python/keycodes.py b/src/main/python/keycodes.py index f0d550f..d965bec 100644 --- a/src/main/python/keycodes.py +++ b/src/main/python/keycodes.py @@ -524,6 +524,8 @@ KEYCODES_MEDIA = [ K(132, "KC_LSCR", "Locking\nScroll", "Locking Scroll Lock", alias=["KC_LOCKING_SCROLL"]), ] +KEYCODES_TAP_DANCE = [] + KEYCODES_USER = [] KEYCODES_MACRO = [] @@ -544,8 +546,8 @@ def recreate_keycodes(): KEYCODES.clear() KEYCODES.extend(KEYCODES_SPECIAL + KEYCODES_BASIC + KEYCODES_SHIFTED + KEYCODES_ISO + KEYCODES_LAYERS + - KEYCODES_QUANTUM + KEYCODES_BACKLIGHT + KEYCODES_MEDIA + KEYCODES_MACRO + KEYCODES_USER + - KEYCODES_HIDDEN) + KEYCODES_QUANTUM + KEYCODES_BACKLIGHT + KEYCODES_MEDIA + KEYCODES_TAP_DANCE + KEYCODES_MACRO + + KEYCODES_USER + KEYCODES_HIDDEN) def create_user_keycodes(): @@ -608,6 +610,10 @@ def recreate_keyboard_keycodes(keyboard): lbl = "M{}".format(x) KEYCODES_MACRO.append(Keycode(0x5F12 + x, lbl, lbl)) + for x in range(keyboard.tap_dance_count): + lbl = "TD({})".format(x) + KEYCODES_TAP_DANCE.append(Keycode(QK_TAP_DANCE | x, lbl, lbl)) + # Check if custom keycodes are defined in keyboard, and if so add them to user keycodes if keyboard.custom_keycodes is not None and len(keyboard.custom_keycodes) > 0: create_custom_user_keycodes(keyboard.custom_keycodes) diff --git a/src/main/python/tabbed_keycodes.py b/src/main/python/tabbed_keycodes.py index 266bec3..da9e9ff 100644 --- a/src/main/python/tabbed_keycodes.py +++ b/src/main/python/tabbed_keycodes.py @@ -7,7 +7,7 @@ from PyQt5.QtGui import QPalette from constants import KEYCODE_BTN_RATIO from flowlayout import FlowLayout from keycodes import KEYCODES_BASIC, KEYCODES_ISO, KEYCODES_MACRO, KEYCODES_LAYERS, KEYCODES_QUANTUM, \ - KEYCODES_BACKLIGHT, KEYCODES_MEDIA, KEYCODES_SPECIAL, KEYCODES_SHIFTED, KEYCODES_USER, Keycode + KEYCODES_BACKLIGHT, KEYCODES_MEDIA, KEYCODES_SPECIAL, KEYCODES_SHIFTED, KEYCODES_USER, Keycode, KEYCODES_TAP_DANCE from square_button import SquareButton from util import tr, KeycodeDisplay @@ -29,6 +29,7 @@ class TabbedKeycodes(QTabWidget): self.tab_quantum = QScrollArea() self.tab_backlight = QScrollArea() self.tab_media = QScrollArea() + self.tab_tap_dance = QScrollArea() self.tab_user = QScrollArea() self.tab_macro = QScrollArea() @@ -41,12 +42,15 @@ class TabbedKeycodes(QTabWidget): (self.tab_quantum, "Quantum", KEYCODES_QUANTUM), (self.tab_backlight, "Backlight", KEYCODES_BACKLIGHT), (self.tab_media, "App, Media and Mouse", KEYCODES_MEDIA), + (self.tab_tap_dance, "Tap Dance", KEYCODES_TAP_DANCE), (self.tab_user, "User", KEYCODES_USER), (self.tab_macro, "Macro", KEYCODES_MACRO), ]: layout = FlowLayout() if tab == self.tab_layers: self.layout_layers = layout + elif tab == self.tab_tap_dance: + self.layout_tap_dance = layout elif tab == self.tab_macro: self.layout_macro = layout elif tab == self.tab_user: @@ -71,16 +75,17 @@ class TabbedKeycodes(QTabWidget): self.addTab(tab, tr("TabbedKeycodes", label)) self.layer_keycode_buttons = [] + self.tap_dance_keycode_buttons = [] self.macro_keycode_buttons = [] self.user_keycode_buttons = [] KeycodeDisplay.notify_keymap_override(self) - def create_buttons(self, layout, keycodes, wordWrap = False): + def create_buttons(self, layout, keycodes, word_wrap=False): buttons = [] for keycode in keycodes: btn = SquareButton() - btn.setWordWrap(wordWrap) + btn.setWordWrap(word_wrap) btn.setRelSize(KEYCODE_BTN_RATIO) btn.setToolTip(Keycode.tooltip(keycode.code)) btn.clicked.connect(lambda st, k=keycode: self.keycode_changed.emit(k.code)) @@ -91,14 +96,17 @@ class TabbedKeycodes(QTabWidget): return buttons def recreate_keycode_buttons(self): - for btn in self.layer_keycode_buttons + self.macro_keycode_buttons + self.user_keycode_buttons: + for btn in self.layer_keycode_buttons + self.tap_dance_keycode_buttons + self.macro_keycode_buttons \ + + self.user_keycode_buttons: self.widgets.remove(btn) btn.hide() btn.deleteLater() self.layer_keycode_buttons = self.create_buttons(self.layout_layers, KEYCODES_LAYERS) + self.tap_dance_keycode_buttons = self.create_buttons(self.layout_tap_dance, KEYCODES_TAP_DANCE) self.macro_keycode_buttons = self.create_buttons(self.layout_macro, KEYCODES_MACRO) - self.user_keycode_buttons = self.create_buttons(self.layout_user, KEYCODES_USER, wordWrap=True) - self.widgets += self.layer_keycode_buttons + self.macro_keycode_buttons + self.user_keycode_buttons + self.user_keycode_buttons = self.create_buttons(self.layout_user, KEYCODES_USER, word_wrap=True) + self.widgets += self.layer_keycode_buttons + self.tap_dance_keycode_buttons + \ + self.macro_keycode_buttons + self.user_keycode_buttons self.relabel_buttons() def on_keymap_override(self): From 57386d41dc3940154647b41045009ee0a4972aa3 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Sat, 3 Jul 2021 22:28:05 -0400 Subject: [PATCH 11/11] keymap_editor: also recreate keycodes in the tray TabbedKeycodes --- src/main/python/keymap_editor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/python/keymap_editor.py b/src/main/python/keymap_editor.py index 8f9c543..f075e46 100644 --- a/src/main/python/keymap_editor.py +++ b/src/main/python/keymap_editor.py @@ -113,6 +113,7 @@ class KeymapEditor(BasicEditor): recreate_keyboard_keycodes(self.keyboard) self.tabbed_keycodes.recreate_keycode_buttons() + TabbedKeycodes.tray.recreate_keycode_buttons() self.refresh_layer_display() self.container.setEnabled(self.valid())