11
11
12
12
import time
13
13
from micropython import const
14
+ import usb_hid
14
15
15
16
from .keycode import Keycode
16
17
17
18
from . import find_device
18
19
19
- try :
20
- from typing import Sequence
21
- import usb_hid
22
- except ImportError :
23
- pass
24
20
25
21
_MAX_KEYPRESSES = const (6 )
26
22
@@ -39,7 +35,7 @@ class Keyboard:
39
35
40
36
# No more than _MAX_KEYPRESSES regular keys may be pressed at once.
41
37
42
- def __init__ (self , devices : Sequence [usb_hid .Device ]) -> None :
38
+ def __init__ (self , devices : list [usb_hid .Device ]) -> None :
43
39
"""Create a Keyboard object that will send keyboard HID reports.
44
40
45
41
Devices can be a sequence of devices that includes a keyboard device or a keyboard device
@@ -133,19 +129,22 @@ def _add_keycode_to_report(self, keycode: int) -> None:
133
129
# Set bit for this modifier.
134
130
self .report_modifier [0 ] |= modifier
135
131
else :
132
+ report_keys = self .report_keys
136
133
# Don't press twice.
137
- # (I'd like to use 'not in self.report_keys' here, but that's not implemented.)
138
134
for i in range (_MAX_KEYPRESSES ):
139
- if self .report_keys [i ] == keycode :
140
- # Already pressed.
135
+ report_key = report_keys [i ]
136
+ if report_key == 0 :
137
+ # Put keycode in first empty slot. Since the report_keys
138
+ # are compact and unique, this is not a repeated key
139
+ report_keys [i ] = keycode
141
140
return
142
- # Put keycode in first empty slot.
143
- for i in range (_MAX_KEYPRESSES ):
144
- if self .report_keys [i ] == 0 :
145
- self .report_keys [i ] = keycode
141
+ if report_key == keycode :
142
+ # Already pressed.
146
143
return
147
- # All slots are filled.
148
- raise ValueError ("Trying to press more than six keys at once." )
144
+ # All slots are filled. Shuffle down and reuse last slot
145
+ for i in range (_MAX_KEYPRESSES - 1 ):
146
+ report_keys [i ] = report_keys [i + 1 ]
147
+ report_keys [- 1 ] = keycode
149
148
150
149
def _remove_keycode_from_report (self , keycode : int ) -> None :
151
150
"""Remove a single keycode from the report."""
@@ -154,10 +153,22 @@ def _remove_keycode_from_report(self, keycode: int) -> None:
154
153
# Turn off the bit for this modifier.
155
154
self .report_modifier [0 ] &= ~ modifier
156
155
else :
157
- # Check all the slots, just in case there's a duplicate. (There should not be.)
156
+ report_keys = self .report_keys
157
+ # Clear the at most one matching slot and move remaining keys down
158
+ j = 0
158
159
for i in range (_MAX_KEYPRESSES ):
159
- if self .report_keys [i ] == keycode :
160
- self .report_keys [i ] = 0
160
+ pressed = report_keys [i ]
161
+ if not pressed :
162
+ break # Handled all used report slots
163
+ if pressed == keycode :
164
+ continue # Remove this entry
165
+ if i != j :
166
+ report_keys [j ] = report_keys [i ]
167
+ j += 1
168
+ # Clear any remaining slots
169
+ while j < _MAX_KEYPRESSES and report_keys [j ]:
170
+ report_keys [j ] = 0
171
+ j += 1
161
172
162
173
@property
163
174
def led_status (self ) -> bytes :
0 commit comments