Skip to content

Commit 2321573

Browse files
committed
Listen to all HID devices
1 parent 1d1dd3b commit 2321573

File tree

1 file changed

+34
-16
lines changed

1 file changed

+34
-16
lines changed

plover/machine/plover_hid.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class PloverHid(ThreadedStenotypeBase):
8080
def __init__(self, params):
8181
super().__init__()
8282
self._params = params
83-
self._hid = None
83+
self._hids = []
8484

8585
def _parse(self, report):
8686
# The first byte is the report id, and due to idiosyncrasies
@@ -102,7 +102,7 @@ def send(self, key_state):
102102
def run(self):
103103
self._ready()
104104

105-
if not self._hid:
105+
if not self._hids:
106106
log.error("no HID available")
107107
self._error()
108108
return
@@ -114,12 +114,24 @@ def run(self):
114114
sent_first_up = False
115115
while not self.finished.wait(0):
116116
interval_ms = self._params["repeat_interval_ms"]
117-
try:
118-
report = self._hid.read(65536, interval_ms)
119-
except Exception as e:
120-
log.error(f"exception during run: {e}")
121-
self._error()
122-
return
117+
118+
report = None
119+
# Poll all devices: block on the first, then non-blocking on the rest
120+
for idx, dev in enumerate(list(self._hids)):
121+
try:
122+
r = dev.read(65536, interval_ms if idx == 0 else 0)
123+
except Exception as e:
124+
log.debug(f"exception during run: {e}")
125+
try:
126+
dev.close()
127+
except Exception:
128+
pass
129+
self._hids.remove(dev)
130+
continue
131+
if r:
132+
report = r
133+
break
134+
123135
if not report:
124136
# The set of keys pressed down hasn't changed. Figure out if we need to be sending repeats:
125137
if (
@@ -131,7 +143,12 @@ def run(self):
131143
self.send(current)
132144
# Avoid sending an extra chord when the repeated chord is released.
133145
sent_first_up = True
146+
# If all devices are gone, stop.
147+
if not self._hids:
148+
self._error()
149+
return
134150
continue
151+
135152
try:
136153
current = self._parse(report)
137154
except InvalidReport:
@@ -174,10 +191,7 @@ def start_capture(self):
174191
log.info("no device found")
175192
return
176193

177-
# FIXME: if multiple compatible devices are found we should either
178-
# let the end user configure which one they want, or support reading
179-
# from all connected plover hid devices at the same time.
180-
self._hid = hid.Device(path=devices[0])
194+
self._hids = [hid.Device(path=path) for path in devices]
181195
except Exception as e:
182196
self._error()
183197
log.error(f"error during start of capture: {e}")
@@ -186,15 +200,19 @@ def start_capture(self):
186200

187201
def stop_capture(self):
188202
super().stop_capture()
189-
if self._hid:
190-
self._hid.close()
191-
self._hid = None
203+
for dev in self._hids:
204+
try:
205+
dev.close()
206+
except Exception as e:
207+
log.debug(f"error while closing device: {e}")
208+
pass
209+
self._hids = []
192210

193211
@classmethod
194212
def get_option_info(cls):
195213
return {
196214
"first_up_chord_send": (False, boolean),
197215
"double_tap_repeat": (False, boolean),
198216
"repeat_delay_ms": (200, int),
199-
"repeat_interval_ms": (50, int),
217+
"repeat_interval_ms": (30, int),
200218
}

0 commit comments

Comments
 (0)