implement VIA json sideload

main
Ilya Zhuravlev 2020-10-18 00:58:01 -04:00
parent 11e8c50ac4
commit 78f06cd3f3
3 changed files with 60 additions and 25 deletions

View File

@ -31,13 +31,13 @@ class Keyboard:
self.rows = self.cols = self.layers = 0
self.keys = []
def reload(self):
def reload(self, sideload_json=None):
""" Load information about the keyboard: number of layers, physical key layout """
self.rowcol = OrderedDict()
self.layout = dict()
self.reload_layout()
self.reload_layout(sideload_json)
self.reload_layers()
self.reload_keymap()
@ -46,25 +46,28 @@ class Keyboard:
self.layers = self.usb_send(self.dev, struct.pack("B", CMD_VIA_GET_LAYER_COUNT))[1]
def reload_layout(self):
def reload_layout(self, sideload_json=None):
""" Requests layout data from the current device """
# get the size
data = self.usb_send(self.dev, struct.pack("BB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_GET_SIZE))
sz = struct.unpack("<I", data[0:4])[0]
if sideload_json is not None:
payload = sideload_json
else:
# get the size
data = self.usb_send(self.dev, struct.pack("BB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_GET_SIZE))
sz = struct.unpack("<I", data[0:4])[0]
# get the payload
payload = b""
block = 0
while sz > 0:
data = self.usb_send(self.dev, struct.pack("<BBI", CMD_VIA_VIAL_PREFIX, CMD_VIAL_GET_DEFINITION, block))
if sz < MSG_LEN:
data = data[:sz]
payload += data
block += 1
sz -= MSG_LEN
# get the payload
payload = b""
block = 0
while sz > 0:
data = self.usb_send(self.dev, struct.pack("<BBI", CMD_VIA_VIAL_PREFIX, CMD_VIAL_GET_DEFINITION, block))
if sz < MSG_LEN:
data = data[:sz]
payload += data
block += 1
sz -= MSG_LEN
payload = json.loads(lzma.decompress(payload))
payload = json.loads(lzma.decompress(payload))
self.rows = payload["matrix"]["rows"]
self.cols = payload["matrix"]["cols"]

View File

@ -4,6 +4,8 @@ from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QComboBox, QToolButton, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, qApp, \
QFileDialog, QDialog
import json
from keyboard import Keyboard
from keyboard_container import KeyboardContainer
from keycodes import recreate_layer_keycodes
@ -15,8 +17,10 @@ class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.device = None
self.keyboard = None
self.devices = []
self.sideload_json = None
self.sideload_vid = self.sideload_pid = -1
self.keyboard_container = KeyboardContainer()
self.keyboard_container.number_layers_changed.connect(self.on_number_layers_changed)
@ -58,6 +62,9 @@ class MainWindow(QMainWindow):
layout_save_act.setShortcut("Ctrl+S")
layout_save_act.triggered.connect(self.on_layout_save)
sideload_json_act = QAction(tr("MenuFile", "Sideload VIA JSON"), self)
sideload_json_act.triggered.connect(self.on_sideload_json)
exit_act = QAction(tr("MenuFile", "Exit"), self)
exit_act.setShortcut("Ctrl+Q")
exit_act.triggered.connect(qApp.exit)
@ -67,6 +74,8 @@ class MainWindow(QMainWindow):
file_menu.addAction(layout_load_act)
file_menu.addAction(layout_save_act)
file_menu.addSeparator()
file_menu.addAction(sideload_json_act)
file_menu.addSeparator()
file_menu.addAction(exit_act)
def on_layout_load(self):
@ -89,19 +98,27 @@ class MainWindow(QMainWindow):
outf.write(self.keyboard_container.save_layout())
def on_click_refresh(self):
self.devices = find_vial_keyboards()
self.devices = find_vial_keyboards(self.sideload_vid, self.sideload_pid)
self.combobox_devices.clear()
for dev in self.devices:
self.combobox_devices.addItem("{} {}".format(dev["manufacturer_string"], dev["product_string"]))
title = "{} {}".format(dev["manufacturer_string"], dev["product_string"])
if dev["vendor_id"] == self.sideload_vid and dev["product_id"] == self.sideload_pid:
title += " [sideload]"
self.combobox_devices.addItem(title)
def on_device_selected(self):
self.device = None
if self.keyboard is not None:
self.keyboard.dev.close()
idx = self.combobox_devices.currentIndex()
if idx >= 0:
keyboard = Keyboard(open_device(self.devices[idx]))
keyboard.reload()
self.keyboard_container.rebuild(keyboard)
dev = self.devices[idx]
self.keyboard = Keyboard(open_device(dev))
if dev["vendor_id"] == self.sideload_vid and dev["product_id"] == self.sideload_pid:
self.keyboard.reload(self.sideload_json)
else:
self.keyboard.reload()
self.keyboard_container.rebuild(self.keyboard)
def on_number_layers_changed(self):
recreate_layer_keycodes(self.keyboard_container.keyboard.layers)
@ -109,3 +126,16 @@ class MainWindow(QMainWindow):
def on_keycode_changed(self, code):
self.keyboard_container.set_key(code)
def on_sideload_json(self):
dialog = QFileDialog()
dialog.setDefaultSuffix("json")
dialog.setAcceptMode(QFileDialog.AcceptOpen)
dialog.setNameFilters(["VIA layout JSON (*.json)"])
if dialog.exec_() == QDialog.Accepted:
with open(dialog.selectedFiles()[0], "rb") as inf:
data = inf.read()
self.sideload_json = json.loads(data)
self.sideload_vid = int(self.sideload_json["vendorId"], 16)
self.sideload_pid = int(self.sideload_json["productId"], 16)
self.on_click_refresh()

View File

@ -33,11 +33,13 @@ def is_rawhid(dev):
return dev["interface_number"] == 1
def find_vial_keyboards():
def find_vial_keyboards(sideload_vid, sideload_pid):
filtered = []
for dev in hid.enumerate():
if VIAL_SERIAL_NUMBER_MAGIC in dev["serial_number"] and is_rawhid(dev):
filtered.append(dev)
elif dev["vendor_id"] == sideload_vid and dev["product_id"] == sideload_pid and is_rawhid(dev):
filtered.append(dev)
return filtered