layout_editor: implement loading and parsing of layout options

main
Ilya Zhuravlev 2020-12-20 21:04:26 -05:00
parent d6e9a14202
commit 6add0a8d70
2 changed files with 114 additions and 1 deletions

View File

@ -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 """

View File

@ -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]