Initial communication with keyboard
parent
8f1123ee77
commit
ed4673dfb8
130
g60.json
130
g60.json
|
|
@ -1,130 +0,0 @@
|
||||||
{
|
|
||||||
"name": "g60",
|
|
||||||
"vendorId": "0xFEED",
|
|
||||||
"productId": "0x6464",
|
|
||||||
"lighting": "none",
|
|
||||||
"matrix": {
|
|
||||||
"rows": 5,
|
|
||||||
"cols": 15
|
|
||||||
},
|
|
||||||
"layouts": {
|
|
||||||
"keymap": [
|
|
||||||
[
|
|
||||||
"0,0",
|
|
||||||
"0,1",
|
|
||||||
"0,2",
|
|
||||||
"0,3",
|
|
||||||
"0,4",
|
|
||||||
"0,5",
|
|
||||||
"0,6",
|
|
||||||
"0,7",
|
|
||||||
"0,8",
|
|
||||||
"0,9",
|
|
||||||
"0,10",
|
|
||||||
"0,11",
|
|
||||||
"0,12",
|
|
||||||
"0,13",
|
|
||||||
"0,14"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"1,0",
|
|
||||||
"1,2",
|
|
||||||
"1,3",
|
|
||||||
"1,4",
|
|
||||||
"1,5",
|
|
||||||
"1,6",
|
|
||||||
"1,7",
|
|
||||||
"1,8",
|
|
||||||
"1,9",
|
|
||||||
"1,10",
|
|
||||||
"1,11",
|
|
||||||
"1,12",
|
|
||||||
"1,13",
|
|
||||||
{
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"1,14"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"w": 1.75
|
|
||||||
},
|
|
||||||
"2,0",
|
|
||||||
"2,2",
|
|
||||||
"2,3",
|
|
||||||
"2,4",
|
|
||||||
"2,5",
|
|
||||||
"2,6",
|
|
||||||
"2,7",
|
|
||||||
"2,8",
|
|
||||||
"2,9",
|
|
||||||
"2,10",
|
|
||||||
"2,11",
|
|
||||||
"2,12",
|
|
||||||
{
|
|
||||||
"w": 2.25
|
|
||||||
},
|
|
||||||
"2,13"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"3,0",
|
|
||||||
"3,1",
|
|
||||||
"3,2",
|
|
||||||
"3,3",
|
|
||||||
"3,4",
|
|
||||||
"3,5",
|
|
||||||
"3,6",
|
|
||||||
"3,7",
|
|
||||||
"3,8",
|
|
||||||
"3,9",
|
|
||||||
"3,10",
|
|
||||||
"3,11",
|
|
||||||
{
|
|
||||||
"w": 1.75
|
|
||||||
},
|
|
||||||
"3,13",
|
|
||||||
"3,14"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,0",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,1",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,3",
|
|
||||||
{
|
|
||||||
"w": 6.25
|
|
||||||
},
|
|
||||||
"4,6",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,10",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,11",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,13",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,14"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
301
plain60.json
301
plain60.json
|
|
@ -1,301 +0,0 @@
|
||||||
{
|
|
||||||
"name": "plain60",
|
|
||||||
"vendorId": "0x4705",
|
|
||||||
"productId": "0x0160",
|
|
||||||
"lighting": "none",
|
|
||||||
"matrix": {
|
|
||||||
"rows": 5,
|
|
||||||
"cols": 15
|
|
||||||
},
|
|
||||||
"layouts": {
|
|
||||||
"labels": [
|
|
||||||
[
|
|
||||||
"Enter Key",
|
|
||||||
"ANSI",
|
|
||||||
"ISO"
|
|
||||||
],
|
|
||||||
"Split Left Shift",
|
|
||||||
"Split Right Shift",
|
|
||||||
"Split Backspace",
|
|
||||||
[
|
|
||||||
"Bottom row",
|
|
||||||
"Default",
|
|
||||||
"Tsangan",
|
|
||||||
"WKL",
|
|
||||||
"HHKB"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"keymap": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"x": 2.75,
|
|
||||||
"c": "#777777"
|
|
||||||
},
|
|
||||||
"0,0",
|
|
||||||
{
|
|
||||||
"c": "#cccccc"
|
|
||||||
},
|
|
||||||
"0,1",
|
|
||||||
"0,2",
|
|
||||||
"0,3",
|
|
||||||
"0,4",
|
|
||||||
"0,5",
|
|
||||||
"0,6",
|
|
||||||
"0,7",
|
|
||||||
"0,8",
|
|
||||||
"0,9",
|
|
||||||
"0,10",
|
|
||||||
"0,11",
|
|
||||||
"0,12",
|
|
||||||
{
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 2
|
|
||||||
},
|
|
||||||
"0,14\n\n\n3,0",
|
|
||||||
{
|
|
||||||
"x": 0.5,
|
|
||||||
"c": "#cccccc"
|
|
||||||
},
|
|
||||||
"0,13\n\n\n3,1",
|
|
||||||
"0,14\n\n\n3,1"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"x": 2.75,
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"1,0",
|
|
||||||
{
|
|
||||||
"c": "#cccccc"
|
|
||||||
},
|
|
||||||
"1,1",
|
|
||||||
"1,2",
|
|
||||||
"1,3",
|
|
||||||
"1,4",
|
|
||||||
"1,5",
|
|
||||||
"1,6",
|
|
||||||
"1,7",
|
|
||||||
"1,8",
|
|
||||||
"1,9",
|
|
||||||
"1,10",
|
|
||||||
"1,11",
|
|
||||||
"1,12",
|
|
||||||
{
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"1,13\n\n\n0,0",
|
|
||||||
{
|
|
||||||
"x": 1.5,
|
|
||||||
"c": "#777777",
|
|
||||||
"w": 1.25,
|
|
||||||
"h": 2,
|
|
||||||
"w2": 1.5,
|
|
||||||
"h2": 1,
|
|
||||||
"x2": -0.25
|
|
||||||
},
|
|
||||||
"2,13\n\n\n0,1"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"x": 2.75,
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 1.75
|
|
||||||
},
|
|
||||||
"2,0",
|
|
||||||
{
|
|
||||||
"c": "#cccccc"
|
|
||||||
},
|
|
||||||
"2,1",
|
|
||||||
"2,2",
|
|
||||||
"2,3",
|
|
||||||
"2,4",
|
|
||||||
"2,5",
|
|
||||||
"2,6",
|
|
||||||
"2,7",
|
|
||||||
"2,8",
|
|
||||||
"2,09",
|
|
||||||
"2,10",
|
|
||||||
"2,11",
|
|
||||||
{
|
|
||||||
"c": "#777777",
|
|
||||||
"w": 2.25
|
|
||||||
},
|
|
||||||
"2,13\n\n\n0,0",
|
|
||||||
{
|
|
||||||
"x": 0.5,
|
|
||||||
"c": "#cccccc"
|
|
||||||
},
|
|
||||||
"2,12\n\n\n0,1"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"3,0\n\n\n1,1",
|
|
||||||
{
|
|
||||||
"c": "#cccccc"
|
|
||||||
},
|
|
||||||
"3,1\n\n\n1,1",
|
|
||||||
{
|
|
||||||
"x": 0.5,
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 2.25
|
|
||||||
},
|
|
||||||
"3,0\n\n\n1,0",
|
|
||||||
{
|
|
||||||
"c": "#cccccc"
|
|
||||||
},
|
|
||||||
"3,2",
|
|
||||||
"3,3",
|
|
||||||
"3,4",
|
|
||||||
"3,5",
|
|
||||||
"3,6",
|
|
||||||
"3,7",
|
|
||||||
"3,8",
|
|
||||||
"3,9",
|
|
||||||
"3,10",
|
|
||||||
"3,11",
|
|
||||||
{
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 2.75
|
|
||||||
},
|
|
||||||
"3,12\n\n\n2,0",
|
|
||||||
{
|
|
||||||
"x": 0.5,
|
|
||||||
"w": 1.75
|
|
||||||
},
|
|
||||||
"3,12\n\n\n2,1",
|
|
||||||
"3,13\n\n\n2,1"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"x": 2.75,
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,0\n\n\n4,0",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,1\n\n\n4,0",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,2\n\n\n4,0",
|
|
||||||
{
|
|
||||||
"c": "#cccccc",
|
|
||||||
"w": 6.25
|
|
||||||
},
|
|
||||||
"4,6\n\n\n4,0",
|
|
||||||
{
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,10\n\n\n4,0",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,11\n\n\n4,0",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,12\n\n\n4,0",
|
|
||||||
{
|
|
||||||
"w": 1.25
|
|
||||||
},
|
|
||||||
"4,13\n\n\n4,0"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"y": 0.25,
|
|
||||||
"x": 2.75,
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,0\n\n\n4,1",
|
|
||||||
"4,1\n\n\n4,1",
|
|
||||||
{
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,2\n\n\n4,1",
|
|
||||||
{
|
|
||||||
"c": "#cccccc",
|
|
||||||
"w": 7
|
|
||||||
},
|
|
||||||
"4,6\n\n\n4,1",
|
|
||||||
{
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,11\n\n\n4,1",
|
|
||||||
"4,12\n\n\n4,1",
|
|
||||||
{
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,13\n\n\n4,1"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"x": 2.75,
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,0\n\n\n4,2",
|
|
||||||
{
|
|
||||||
"d": true
|
|
||||||
},
|
|
||||||
"\n\n\n4,2",
|
|
||||||
{
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,2\n\n\n4,2",
|
|
||||||
{
|
|
||||||
"c": "#cccccc",
|
|
||||||
"w": 7
|
|
||||||
},
|
|
||||||
"4,6\n\n\n4,2",
|
|
||||||
{
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,11\n\n\n4,2",
|
|
||||||
{
|
|
||||||
"d": true
|
|
||||||
},
|
|
||||||
"\n\n\n4,2",
|
|
||||||
{
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,13\n\n\n4,2"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"x": 2.75,
|
|
||||||
"w": 1.5,
|
|
||||||
"d": true
|
|
||||||
},
|
|
||||||
"\n\n\n4,3",
|
|
||||||
"4,1\n\n\n4,3",
|
|
||||||
{
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,2\n\n\n4,3",
|
|
||||||
{
|
|
||||||
"c": "#cccccc",
|
|
||||||
"w": 7
|
|
||||||
},
|
|
||||||
"4,6\n\n\n4,3",
|
|
||||||
{
|
|
||||||
"c": "#aaaaaa",
|
|
||||||
"w": 1.5
|
|
||||||
},
|
|
||||||
"4,11\n\n\n4,3",
|
|
||||||
"4,12\n\n\n4,3",
|
|
||||||
{
|
|
||||||
"w": 1.5,
|
|
||||||
"d": true
|
|
||||||
},
|
|
||||||
"\n\n\n4,3"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import hid
|
|
||||||
|
|
||||||
VIAL_SERIAL_NUMBER_MAGIC = "vial:f64c2b3c"
|
|
||||||
|
|
||||||
def find_vial_keyboards():
|
|
||||||
for dev in hid.enumerate():
|
|
||||||
print(dev)
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
REPORT_LEN = 32
|
|
||||||
|
|
||||||
def hid_send(dev, msg):
|
|
||||||
if len(report) > REPORT_LEN:
|
|
||||||
raise RuntimeError("report must be less than 64 bytes")
|
|
||||||
msg += b"\x00" * (REPORT_LEN - len(msg))
|
|
||||||
|
|
||||||
# add 00 at start for hidapi report id
|
|
||||||
dev.write(b"\x00" + report)
|
|
||||||
|
|
||||||
return dev.read(REPORT_LEN)
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
from fbs_runtime.application_context.PyQt5 import ApplicationContext
|
from fbs_runtime.application_context.PyQt5 import ApplicationContext
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtWidgets import QWidget, QTabWidget, QVBoxLayout, QPushButton, QLabel
|
from PyQt5.QtWidgets import QWidget, QTabWidget, QVBoxLayout, QPushButton, QLabel, QComboBox, QToolButton, QHBoxLayout
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
|
import struct
|
||||||
|
import lzma
|
||||||
|
|
||||||
from flowlayout import FlowLayout
|
from flowlayout import FlowLayout
|
||||||
from util import tr
|
from util import tr, find_vial_keyboards, open_device, hid_send, MSG_LEN
|
||||||
from kle_serial import Serial as KleSerial
|
from kle_serial import Serial as KleSerial
|
||||||
|
|
||||||
class TabbedKeycodes(QTabWidget):
|
class TabbedKeycodes(QTabWidget):
|
||||||
|
|
@ -40,9 +42,14 @@ class KeyboardContainer(QWidget):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self.keys = []
|
||||||
|
|
||||||
|
def rebuild(self, data):
|
||||||
|
for key in self.keys:
|
||||||
|
key.deleteLater()
|
||||||
|
self.keys = []
|
||||||
|
|
||||||
serial = KleSerial()
|
serial = KleSerial()
|
||||||
data = open("g60.json", "r").read()
|
|
||||||
data = json.loads(data)
|
|
||||||
kb = serial.deserialize(data["layouts"]["keymap"])
|
kb = serial.deserialize(data["layouts"]["keymap"])
|
||||||
|
|
||||||
max_w = max_h = 0
|
max_w = max_h = 0
|
||||||
|
|
@ -60,11 +67,14 @@ class KeyboardContainer(QWidget):
|
||||||
|
|
||||||
widget.setFixedSize(w, h)
|
widget.setFixedSize(w, h)
|
||||||
widget.move(x, y)
|
widget.move(x, y)
|
||||||
print("{} {}x{}+{}x{}".format(key.labels, key.x, key.y, key.width, key.height))
|
widget.show()
|
||||||
|
# print("{} {}x{}+{}x{}".format(key.labels, key.x, key.y, key.width, key.height))
|
||||||
|
|
||||||
max_w = max(max_w, x + w)
|
max_w = max(max_w, x + w)
|
||||||
max_h = max(max_h, y + h)
|
max_h = max(max_h, y + h)
|
||||||
|
|
||||||
|
self.keys.append(widget)
|
||||||
|
|
||||||
self.setFixedSize(max_w, max_h)
|
self.setFixedSize(max_w, max_h)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -72,17 +82,71 @@ class MainWindow(QWidget):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self.device = None
|
||||||
|
self.devices = []
|
||||||
|
|
||||||
self.keyboard_container = KeyboardContainer()
|
self.keyboard_container = KeyboardContainer()
|
||||||
|
|
||||||
self.tabbed_keycodes = TabbedKeycodes()
|
self.tabbed_keycodes = TabbedKeycodes()
|
||||||
|
|
||||||
|
self.combobox_devices = QComboBox()
|
||||||
|
self.combobox_devices.currentIndexChanged.connect(self.on_device_selected)
|
||||||
|
|
||||||
|
btn_refresh_devices = QToolButton()
|
||||||
|
btn_refresh_devices.setToolButtonStyle(Qt.ToolButtonTextOnly)
|
||||||
|
btn_refresh_devices.setText(tr("MainWindow", "Refresh"))
|
||||||
|
btn_refresh_devices.clicked.connect(self.on_click_refresh)
|
||||||
|
|
||||||
|
layout_combobox = QHBoxLayout()
|
||||||
|
layout_combobox.addWidget(self.combobox_devices)
|
||||||
|
layout_combobox.addWidget(btn_refresh_devices)
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
|
layout.addLayout(layout_combobox)
|
||||||
layout.addWidget(self.keyboard_container)
|
layout.addWidget(self.keyboard_container)
|
||||||
layout.setAlignment(self.keyboard_container, Qt.AlignHCenter)
|
layout.setAlignment(self.keyboard_container, Qt.AlignHCenter)
|
||||||
layout.addWidget(self.tabbed_keycodes)
|
layout.addWidget(self.tabbed_keycodes)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
# make sure initial state is valid
|
||||||
|
self.on_click_refresh()
|
||||||
|
self.on_device_selected()
|
||||||
|
|
||||||
|
def on_click_refresh(self):
|
||||||
|
self.devices = find_vial_keyboards()
|
||||||
|
self.combobox_devices.clear()
|
||||||
|
|
||||||
|
for dev in self.devices:
|
||||||
|
self.combobox_devices.addItem("{} {}".format(dev["manufacturer_string"], dev["product_string"]))
|
||||||
|
|
||||||
|
def on_device_selected(self):
|
||||||
|
self.device = None
|
||||||
|
idx = self.combobox_devices.currentIndex()
|
||||||
|
if idx >= 0:
|
||||||
|
self.device = open_device(self.devices[idx])
|
||||||
|
self.reload_layout()
|
||||||
|
|
||||||
|
def reload_layout(self):
|
||||||
|
""" Requests layout data from the current device """
|
||||||
|
|
||||||
|
# get the size
|
||||||
|
data = hid_send(self.device, b"\xFE\x01")
|
||||||
|
sz = struct.unpack("<I", data[0:4])[0]
|
||||||
|
|
||||||
|
# get the payload
|
||||||
|
payload = b""
|
||||||
|
block = 0
|
||||||
|
while sz > 0:
|
||||||
|
data = hid_send(self.device, b"\xFE\x02" + struct.pack("<I", block))
|
||||||
|
if sz < MSG_LEN:
|
||||||
|
data = data[:sz]
|
||||||
|
payload += data
|
||||||
|
block += 1
|
||||||
|
sz -= MSG_LEN
|
||||||
|
|
||||||
|
payload = json.loads(lzma.decompress(payload))
|
||||||
|
self.keyboard_container.rebuild(payload)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
appctxt = ApplicationContext() # 1. Instantiate ApplicationContext
|
appctxt = ApplicationContext() # 1. Instantiate ApplicationContext
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,42 @@
|
||||||
from PyQt5.QtCore import QCoreApplication
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.platform.startswith("linux"):
|
||||||
|
import hidraw as hid
|
||||||
|
else:
|
||||||
|
import hid
|
||||||
|
|
||||||
|
|
||||||
tr = QCoreApplication.translate
|
tr = QCoreApplication.translate
|
||||||
|
|
||||||
|
VIAL_SERIAL_NUMBER_MAGIC = "vial:f64c2b3c"
|
||||||
|
|
||||||
|
MSG_LEN = 32
|
||||||
|
|
||||||
|
def hid_send(dev, msg):
|
||||||
|
if len(msg) > MSG_LEN:
|
||||||
|
raise RuntimeError("message must be less than 32 bytes")
|
||||||
|
msg += b"\x00" * (MSG_LEN - len(msg))
|
||||||
|
|
||||||
|
# add 00 at start for hidapi report id
|
||||||
|
dev.write(b"\x00" + msg)
|
||||||
|
|
||||||
|
return bytes(dev.read(MSG_LEN))
|
||||||
|
|
||||||
|
def is_rawhid(dev):
|
||||||
|
# TODO: this is only broken on linux, other platforms should be able to check usage_page
|
||||||
|
return dev["interface_number"] == 1
|
||||||
|
|
||||||
|
def find_vial_keyboards():
|
||||||
|
filtered = []
|
||||||
|
for dev in hid.enumerate():
|
||||||
|
if VIAL_SERIAL_NUMBER_MAGIC in dev["serial_number"] and is_rawhid(dev):
|
||||||
|
filtered.append(dev)
|
||||||
|
return filtered
|
||||||
|
|
||||||
|
def open_device(desc):
|
||||||
|
# TODO: error handling here
|
||||||
|
dev = hid.device()
|
||||||
|
dev.open_path(desc["path"])
|
||||||
|
return dev
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue