tap_dance: initial implementation
parent
a15e8011d1
commit
c9ff0e735a
|
|
@ -57,6 +57,12 @@ CMD_VIAL_QMK_SETTINGS_GET = 0x0A
|
||||||
CMD_VIAL_QMK_SETTINGS_SET = 0x0B
|
CMD_VIAL_QMK_SETTINGS_SET = 0x0B
|
||||||
CMD_VIAL_QMK_SETTINGS_RESET = 0x0C
|
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
|
# how much of a macro/keymap buffer we can read/write per packet
|
||||||
BUFFER_FETCH_CHUNK = 28
|
BUFFER_FETCH_CHUNK = 28
|
||||||
|
|
||||||
|
|
@ -207,6 +213,7 @@ class Keyboard:
|
||||||
self.reload_keymap()
|
self.reload_keymap()
|
||||||
self.reload_macros()
|
self.reload_macros()
|
||||||
self.reload_rgb()
|
self.reload_rgb()
|
||||||
|
self.reload_dynamic()
|
||||||
|
|
||||||
def reload_layers(self):
|
def reload_layers(self):
|
||||||
""" Get how many layers the keyboard has """
|
""" Get how many layers the keyboard has """
|
||||||
|
|
@ -374,6 +381,22 @@ class Keyboard:
|
||||||
self.backlight_effect = self.usb_send(
|
self.backlight_effect = self.usb_send(
|
||||||
self.dev, struct.pack(">BB", CMD_VIA_LIGHTING_GET_VALUE, QMK_BACKLIGHT_EFFECT), retries=20)[2]
|
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("<HHHHH", data[1:11]))
|
||||||
|
|
||||||
def set_key(self, layer, row, col, code):
|
def set_key(self, layer, row, col, code):
|
||||||
if code < 0:
|
if code < 0:
|
||||||
return
|
return
|
||||||
|
|
@ -670,6 +693,17 @@ class Keyboard:
|
||||||
def qmk_settings_reset(self):
|
def qmk_settings_reset(self):
|
||||||
self.usb_send(self.dev, struct.pack("BB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_QMK_SETTINGS_RESET))
|
self.usb_send(self.dev, struct.pack("BB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_QMK_SETTINGS_RESET))
|
||||||
|
|
||||||
|
def tap_dance_get(self, idx):
|
||||||
|
return self.tap_dance_entries[idx]
|
||||||
|
|
||||||
|
def tap_dance_set(self, idx, entry):
|
||||||
|
if self.tap_dance_entries[idx] == entry:
|
||||||
|
return
|
||||||
|
self.tap_dance_entries[idx] = entry
|
||||||
|
serialized = struct.pack("<HHHHH", *self.tap_dance_entries[idx])
|
||||||
|
self.usb_send(self.dev, struct.pack("BBBB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_DYNAMIC_ENTRY_OP,
|
||||||
|
DYNAMIC_VIAL_TAP_DANCE_SET, idx) + serialized, retries=20)
|
||||||
|
|
||||||
|
|
||||||
class DummyKeyboard(Keyboard):
|
class DummyKeyboard(Keyboard):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,125 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
from PyQt5.QtWidgets import QTabWidget, QWidget, QSizePolicy, QGridLayout, QVBoxLayout, QLabel, QLineEdit, QHBoxLayout, \
|
from PyQt5.QtWidgets import QTabWidget, QWidget, QSizePolicy, QGridLayout, QVBoxLayout, QLabel, QLineEdit, QHBoxLayout, \
|
||||||
QPushButton
|
QPushButton, QSpinBox
|
||||||
|
|
||||||
from util import tr
|
from util import tr
|
||||||
from vial_device import VialKeyboard
|
from vial_device import VialKeyboard
|
||||||
from basic_editor import BasicEditor
|
from basic_editor import BasicEditor
|
||||||
|
|
||||||
|
|
||||||
|
class TapDanceEntryUI:
|
||||||
|
|
||||||
|
def __init__(self, idx):
|
||||||
|
self.idx = idx
|
||||||
|
self.container = QGridLayout()
|
||||||
|
self.populate_container()
|
||||||
|
|
||||||
|
w = QWidget()
|
||||||
|
w.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
|
||||||
|
w.setLayout(self.container)
|
||||||
|
l = QVBoxLayout()
|
||||||
|
l.addStretch()
|
||||||
|
l.addSpacing(100)
|
||||||
|
l.addWidget(w)
|
||||||
|
l.setAlignment(w, QtCore.Qt.AlignHCenter)
|
||||||
|
l.addSpacing(100)
|
||||||
|
lbl = QLabel("Use <code>TD({})</code> 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):
|
class TapDance(BasicEditor):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.keyboard = None
|
self.keyboard = None
|
||||||
|
|
||||||
|
self.tap_dance_entries = []
|
||||||
|
self.tap_dance_entries_available = []
|
||||||
self.tabs = QTabWidget()
|
self.tabs = QTabWidget()
|
||||||
for x in range(32):
|
for x in range(128):
|
||||||
container = QGridLayout()
|
self.tap_dance_entries_available.append(TapDanceEntryUI(x))
|
||||||
|
|
||||||
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 <code>TD({})</code> 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)
|
self.addWidget(self.tabs)
|
||||||
buttons = QHBoxLayout()
|
buttons = QHBoxLayout()
|
||||||
buttons.addStretch()
|
buttons.addStretch()
|
||||||
btn_save = QPushButton(tr("TapDance", "Save"))
|
btn_save = QPushButton(tr("TapDance", "Save"))
|
||||||
|
btn_save.clicked.connect(self.on_save)
|
||||||
btn_revert = QPushButton(tr("TapDance", "Revert"))
|
btn_revert = QPushButton(tr("TapDance", "Revert"))
|
||||||
|
btn_revert.clicked.connect(self.on_revert)
|
||||||
buttons.addWidget(btn_save)
|
buttons.addWidget(btn_save)
|
||||||
buttons.addWidget(btn_revert)
|
buttons.addWidget(btn_revert)
|
||||||
self.addLayout(buttons)
|
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):
|
def rebuild(self, device):
|
||||||
super().rebuild(device)
|
super().rebuild(device)
|
||||||
if self.valid():
|
if self.valid():
|
||||||
self.keyboard = device.keyboard
|
self.keyboard = device.keyboard
|
||||||
|
self.rebuild_ui()
|
||||||
|
|
||||||
def valid(self):
|
def valid(self):
|
||||||
return isinstance(self.device, VialKeyboard) and \
|
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)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue