layout_editor: implement loading and parsing of layout options
parent
d6e9a14202
commit
6add0a8d70
|
|
@ -9,11 +9,15 @@ from kle_serial import Serial as KleSerial
|
|||
from util import MSG_LEN, hid_send
|
||||
|
||||
|
||||
CMD_VIA_GET_KEYBOARD_VALUE = 0x02
|
||||
CMD_VIA_SET_KEYBOARD_VALUE = 0x03
|
||||
CMD_VIA_GET_KEYCODE = 0x04
|
||||
CMD_VIA_SET_KEYCODE = 0x05
|
||||
CMD_VIA_GET_LAYER_COUNT = 0x11
|
||||
CMD_VIA_VIAL_PREFIX = 0xFE
|
||||
|
||||
VIA_LAYOUT_OPTIONS = 0x02
|
||||
|
||||
CMD_VIAL_GET_KEYBOARD_ID = 0x00
|
||||
CMD_VIAL_GET_SIZE = 0x01
|
||||
CMD_VIAL_GET_DEFINITION = 0x02
|
||||
|
|
@ -34,6 +38,8 @@ class Keyboard:
|
|||
self.layout = dict()
|
||||
self.encoder_layout = dict()
|
||||
self.rows = self.cols = self.layers = 0
|
||||
self.layouts = None
|
||||
self.layout_options = 0
|
||||
self.keys = []
|
||||
self.encoders = []
|
||||
|
||||
|
|
@ -83,6 +89,8 @@ class Keyboard:
|
|||
|
||||
payload = json.loads(lzma.decompress(payload))
|
||||
|
||||
self.layouts = payload.get("layouts")
|
||||
|
||||
self.rows = payload["matrix"]["rows"]
|
||||
self.cols = payload["matrix"]["cols"]
|
||||
|
||||
|
|
@ -125,6 +133,10 @@ class Keyboard:
|
|||
self.encoder_layout[(layer, idx, 0)] = struct.unpack(">H", data[0:2])[0]
|
||||
self.encoder_layout[(layer, idx, 1)] = struct.unpack(">H", data[2:4])[0]
|
||||
|
||||
if self.layouts:
|
||||
data = self.usb_send(self.dev, struct.pack("BB", CMD_VIA_GET_KEYBOARD_VALUE, VIA_LAYOUT_OPTIONS))
|
||||
self.layout_options = struct.unpack(">I", data[2:6])[0]
|
||||
|
||||
def set_key(self, layer, row, col, code):
|
||||
key = (layer, row, col)
|
||||
if self.layout[key] != code:
|
||||
|
|
@ -138,6 +150,11 @@ class Keyboard:
|
|||
layer, index, direction, code))
|
||||
self.encoder_layout[key] = code
|
||||
|
||||
def set_layout_options(self, options):
|
||||
if self.layout_options != options:
|
||||
self.layout_options = options
|
||||
self.usb_send(self.dev, struct.pack(">BBI", CMD_VIA_SET_KEYBOARD_VALUE, VIA_LAYOUT_OPTIONS, options))
|
||||
|
||||
def save_layout(self):
|
||||
""" Serializes current layout to a binary """
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,113 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
from PyQt5.QtWidgets import QLabel, QCheckBox, QComboBox, QGridLayout
|
||||
|
||||
from basic_editor import BasicEditor
|
||||
from vial_device import VialKeyboard
|
||||
|
||||
|
||||
class BooleanChoice:
|
||||
|
||||
def __init__(self, container, label):
|
||||
self.choice = 0
|
||||
|
||||
self.widget_label = QLabel(label)
|
||||
self.widget_checkbox = QCheckBox()
|
||||
|
||||
row = container.rowCount()
|
||||
container.addWidget(self.widget_label, row, 0)
|
||||
container.addWidget(self.widget_checkbox, row, 1)
|
||||
|
||||
def delete(self):
|
||||
self.widget_label.deleteLater()
|
||||
self.widget_checkbox.deleteLater()
|
||||
|
||||
def pack(self):
|
||||
return str(self.choice)
|
||||
|
||||
def unpack(self, value):
|
||||
self.change(int(value))
|
||||
|
||||
def change(self, value):
|
||||
self.widget_checkbox.setChecked(bool(value))
|
||||
|
||||
|
||||
class SelectChoice:
|
||||
|
||||
def __init__(self, container, label, options):
|
||||
self.choice = 0
|
||||
self.options = options
|
||||
|
||||
self.widget_label = QLabel(label)
|
||||
self.widget_options = QComboBox()
|
||||
self.widget_options.addItems(options)
|
||||
|
||||
row = container.rowCount()
|
||||
container.addWidget(self.widget_label, row, 0)
|
||||
container.addWidget(self.widget_options, row, 1)
|
||||
|
||||
def delete(self):
|
||||
self.widget_label.deleteLater()
|
||||
self.widget_options.deleteLater()
|
||||
|
||||
def pack(self):
|
||||
val = bin(self.choice)[2:]
|
||||
val = "0" * ((len(self.options) - 1).bit_length() - len(val)) + val
|
||||
return val
|
||||
|
||||
def unpack(self, value):
|
||||
self.change(int(value, 2))
|
||||
|
||||
def change(self, value):
|
||||
self.choice = value
|
||||
self.widget_options.setCurrentIndex(self.choice)
|
||||
|
||||
|
||||
class LayoutEditor(BasicEditor):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.device = None
|
||||
|
||||
self.choices = []
|
||||
|
||||
self.widgets = []
|
||||
|
||||
self.container = QGridLayout()
|
||||
self.addLayout(self.container)
|
||||
|
||||
def rebuild(self, device):
|
||||
super().rebuild(device)
|
||||
|
||||
if not self.valid:
|
||||
return
|
||||
|
||||
for choice in self.choices:
|
||||
choice.delete()
|
||||
self.choices = []
|
||||
|
||||
for item in device.keyboard.layouts["labels"]:
|
||||
if isinstance(item, str):
|
||||
self.choices.append(BooleanChoice(self.container, item))
|
||||
else:
|
||||
self.choices.append(SelectChoice(self.container, item[0], item[1:]))
|
||||
|
||||
self.unpack(self.device.keyboard.layout_options)
|
||||
|
||||
def valid(self):
|
||||
return isinstance(self.device, VialKeyboard)
|
||||
return isinstance(self.device, VialKeyboard) and self.device.keyboard.layouts
|
||||
|
||||
def pack(self):
|
||||
val = ""
|
||||
for choice in self.choices[::-1]:
|
||||
val += choice.pack()
|
||||
return int(val, 2)
|
||||
|
||||
def unpack(self, value):
|
||||
# we operate on bit strings
|
||||
value = "0" * 100 + bin(value)[2:]
|
||||
|
||||
# VIA stores option choices backwards, we need to parse the input in reverse
|
||||
for choice in self.choices[::-1]:
|
||||
sz = len(choice.pack())
|
||||
choice.unpack(value[-sz:])
|
||||
value = value[:-sz]
|
||||
|
|
|
|||
Loading…
Reference in New Issue