1111
1212import time
1313from micropython import const
14+ import usb_hid
1415
1516from .keycode import Keycode
1617
1718from . import find_device
1819
19- try :
20- from typing import Sequence
21- import usb_hid
22- except ImportError :
23- pass
2420
2521_MAX_KEYPRESSES = const (6 )
2622
@@ -39,7 +35,7 @@ class Keyboard:
3935
4036 # No more than _MAX_KEYPRESSES regular keys may be pressed at once.
4137
42- def __init__ (self , devices : Sequence [usb_hid .Device ]) -> None :
38+ def __init__ (self , devices : list [usb_hid .Device ]) -> None :
4339 """Create a Keyboard object that will send keyboard HID reports.
4440
4541 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:
133129 # Set bit for this modifier.
134130 self .report_modifier [0 ] |= modifier
135131 else :
132+ report_keys = self .report_keys
136133 # Don't press twice.
137- # (I'd like to use 'not in self.report_keys' here, but that's not implemented.)
138134 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
141140 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.
146143 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
149148
150149 def _remove_keycode_from_report (self , keycode : int ) -> None :
151150 """Remove a single keycode from the report."""
@@ -154,10 +153,22 @@ def _remove_keycode_from_report(self, keycode: int) -> None:
154153 # Turn off the bit for this modifier.
155154 self .report_modifier [0 ] &= ~ modifier
156155 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
158159 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
161172
162173 @property
163174 def led_status (self ) -> bytes :
0 commit comments