implement VIA json sideload
parent
11e8c50ac4
commit
78f06cd3f3
|
|
@ -31,13 +31,13 @@ class Keyboard:
|
||||||
self.rows = self.cols = self.layers = 0
|
self.rows = self.cols = self.layers = 0
|
||||||
self.keys = []
|
self.keys = []
|
||||||
|
|
||||||
def reload(self):
|
def reload(self, sideload_json=None):
|
||||||
""" Load information about the keyboard: number of layers, physical key layout """
|
""" Load information about the keyboard: number of layers, physical key layout """
|
||||||
|
|
||||||
self.rowcol = OrderedDict()
|
self.rowcol = OrderedDict()
|
||||||
self.layout = dict()
|
self.layout = dict()
|
||||||
|
|
||||||
self.reload_layout()
|
self.reload_layout(sideload_json)
|
||||||
self.reload_layers()
|
self.reload_layers()
|
||||||
self.reload_keymap()
|
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]
|
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 """
|
""" Requests layout data from the current device """
|
||||||
|
|
||||||
# get the size
|
if sideload_json is not None:
|
||||||
data = self.usb_send(self.dev, struct.pack("BB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_GET_SIZE))
|
payload = sideload_json
|
||||||
sz = struct.unpack("<I", data[0:4])[0]
|
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
|
# get the payload
|
||||||
payload = b""
|
payload = b""
|
||||||
block = 0
|
block = 0
|
||||||
while sz > 0:
|
while sz > 0:
|
||||||
data = self.usb_send(self.dev, struct.pack("<BBI", CMD_VIA_VIAL_PREFIX, CMD_VIAL_GET_DEFINITION, block))
|
data = self.usb_send(self.dev, struct.pack("<BBI", CMD_VIA_VIAL_PREFIX, CMD_VIAL_GET_DEFINITION, block))
|
||||||
if sz < MSG_LEN:
|
if sz < MSG_LEN:
|
||||||
data = data[:sz]
|
data = data[:sz]
|
||||||
payload += data
|
payload += data
|
||||||
block += 1
|
block += 1
|
||||||
sz -= MSG_LEN
|
sz -= MSG_LEN
|
||||||
|
|
||||||
payload = json.loads(lzma.decompress(payload))
|
payload = json.loads(lzma.decompress(payload))
|
||||||
|
|
||||||
self.rows = payload["matrix"]["rows"]
|
self.rows = payload["matrix"]["rows"]
|
||||||
self.cols = payload["matrix"]["cols"]
|
self.cols = payload["matrix"]["cols"]
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtWidgets import QWidget, QComboBox, QToolButton, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, qApp, \
|
from PyQt5.QtWidgets import QWidget, QComboBox, QToolButton, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, qApp, \
|
||||||
QFileDialog, QDialog
|
QFileDialog, QDialog
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
from keyboard import Keyboard
|
from keyboard import Keyboard
|
||||||
from keyboard_container import KeyboardContainer
|
from keyboard_container import KeyboardContainer
|
||||||
from keycodes import recreate_layer_keycodes
|
from keycodes import recreate_layer_keycodes
|
||||||
|
|
@ -15,8 +17,10 @@ class MainWindow(QMainWindow):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.device = None
|
self.keyboard = None
|
||||||
self.devices = []
|
self.devices = []
|
||||||
|
self.sideload_json = None
|
||||||
|
self.sideload_vid = self.sideload_pid = -1
|
||||||
|
|
||||||
self.keyboard_container = KeyboardContainer()
|
self.keyboard_container = KeyboardContainer()
|
||||||
self.keyboard_container.number_layers_changed.connect(self.on_number_layers_changed)
|
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.setShortcut("Ctrl+S")
|
||||||
layout_save_act.triggered.connect(self.on_layout_save)
|
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 = QAction(tr("MenuFile", "Exit"), self)
|
||||||
exit_act.setShortcut("Ctrl+Q")
|
exit_act.setShortcut("Ctrl+Q")
|
||||||
exit_act.triggered.connect(qApp.exit)
|
exit_act.triggered.connect(qApp.exit)
|
||||||
|
|
@ -67,6 +74,8 @@ class MainWindow(QMainWindow):
|
||||||
file_menu.addAction(layout_load_act)
|
file_menu.addAction(layout_load_act)
|
||||||
file_menu.addAction(layout_save_act)
|
file_menu.addAction(layout_save_act)
|
||||||
file_menu.addSeparator()
|
file_menu.addSeparator()
|
||||||
|
file_menu.addAction(sideload_json_act)
|
||||||
|
file_menu.addSeparator()
|
||||||
file_menu.addAction(exit_act)
|
file_menu.addAction(exit_act)
|
||||||
|
|
||||||
def on_layout_load(self):
|
def on_layout_load(self):
|
||||||
|
|
@ -89,19 +98,27 @@ class MainWindow(QMainWindow):
|
||||||
outf.write(self.keyboard_container.save_layout())
|
outf.write(self.keyboard_container.save_layout())
|
||||||
|
|
||||||
def on_click_refresh(self):
|
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()
|
self.combobox_devices.clear()
|
||||||
|
|
||||||
for dev in self.devices:
|
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):
|
def on_device_selected(self):
|
||||||
self.device = None
|
if self.keyboard is not None:
|
||||||
|
self.keyboard.dev.close()
|
||||||
idx = self.combobox_devices.currentIndex()
|
idx = self.combobox_devices.currentIndex()
|
||||||
if idx >= 0:
|
if idx >= 0:
|
||||||
keyboard = Keyboard(open_device(self.devices[idx]))
|
dev = self.devices[idx]
|
||||||
keyboard.reload()
|
self.keyboard = Keyboard(open_device(dev))
|
||||||
self.keyboard_container.rebuild(keyboard)
|
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):
|
def on_number_layers_changed(self):
|
||||||
recreate_layer_keycodes(self.keyboard_container.keyboard.layers)
|
recreate_layer_keycodes(self.keyboard_container.keyboard.layers)
|
||||||
|
|
@ -109,3 +126,16 @@ class MainWindow(QMainWindow):
|
||||||
|
|
||||||
def on_keycode_changed(self, code):
|
def on_keycode_changed(self, code):
|
||||||
self.keyboard_container.set_key(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()
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,13 @@ def is_rawhid(dev):
|
||||||
return dev["interface_number"] == 1
|
return dev["interface_number"] == 1
|
||||||
|
|
||||||
|
|
||||||
def find_vial_keyboards():
|
def find_vial_keyboards(sideload_vid, sideload_pid):
|
||||||
filtered = []
|
filtered = []
|
||||||
for dev in hid.enumerate():
|
for dev in hid.enumerate():
|
||||||
if VIAL_SERIAL_NUMBER_MAGIC in dev["serial_number"] and is_rawhid(dev):
|
if VIAL_SERIAL_NUMBER_MAGIC in dev["serial_number"] and is_rawhid(dev):
|
||||||
filtered.append(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
|
return filtered
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue