66from adafruit_hid .consumer_control import ConsumerControl
77from adafruit_hid .keyboard import Keyboard
88from adafruit_hid .mouse import Mouse
9- from evdev import (
10- InputDevice ,
11- InputEvent ,
12- KeyEvent ,
13- RelEvent ,
14- categorize ,
15- list_devices ,
16- )
9+ from evdev import InputDevice , InputEvent , KeyEvent , RelEvent , categorize , list_devices
1710import usb_hid
1811from usb_hid import Device
1912
2720
2821
2922_logger = get_logger ()
23+ _keyboard_gadget : Keyboard = None
24+ _mouse_gadget : Mouse = None
25+ _consumer_gadget : ConsumerControl = None
3026
3127PATH = "path"
3228MAC = "MAC"
3329NAME = "name"
3430
3531
32+ def list_readable_devices () -> list [InputDevice ]:
33+ return [InputDevice (path ) for path in list_devices ()]
34+
35+
36+ def init_usb_devices () -> None :
37+ usb_hid .enable (
38+ [
39+ Device .MOUSE ,
40+ Device .KEYBOARD ,
41+ Device .CONSUMER_CONTROL ,
42+ ]
43+ )
44+ _logger .debug (f"Available USB devices: { usb_hid .devices } " )
45+ global _keyboard_gadget , _mouse_gadget , _consumer_gadget
46+ _keyboard_gadget = Keyboard (usb_hid .devices )
47+ _mouse_gadget = Mouse (usb_hid .devices )
48+ _consumer_gadget = ConsumerControl (usb_hid .devices )
49+
50+
3651class DeviceIdentifier :
3752 def __init__ (self , device_identifier : str ) -> None :
3853 self ._value = device_identifier
@@ -86,9 +101,6 @@ def matches(self, device: InputDevice) -> bool:
86101class DeviceRelay :
87102 def __init__ (self , input_device : InputDevice ):
88103 self ._input_device = input_device
89- self ._keyboard_gadget = Keyboard (usb_hid .devices )
90- self ._mouse_gadget = Mouse (usb_hid .devices )
91- self ._consumer_gadget = ConsumerControl (usb_hid .devices )
92104
93105 @property
94106 def input_device (self ) -> InputDevice :
@@ -107,45 +119,48 @@ async def async_relay_events_loop(self) -> NoReturn:
107119 async def _async_relay_event (self , input_event : InputEvent ) -> None :
108120 event = categorize (input_event )
109121 _logger .debug (f"Received { event } from { self .input_device .name } " )
110- method = None
122+ func = None
111123 if isinstance (event , RelEvent ):
112- method = self . _move_mouse
124+ func = _move_mouse
113125 elif isinstance (event , KeyEvent ):
114- method = self . _send_key
115- if method :
126+ func = _send_key
127+ if func :
116128 loop = asyncio .get_running_loop ()
117- await loop .run_in_executor (None , method , event )
118-
119- def _send_key (self , event : KeyEvent ) -> None :
120- key_id , key_name = evdev_to_usb_hid (event )
121- if key_id is None :
122- return
123- device_out = self ._get_output_device (event )
124- try :
125- if event .keystate == KeyEvent .key_down :
126- _logger .debug (f"Pressing { key_name } (0x{ key_id :02X} ) on { device_out } " )
127- device_out .press (key_id )
128- elif event .keystate == KeyEvent .key_up :
129- _logger .debug (f"Releasing { key_name } (0x{ key_id :02X} ) on { device_out } " )
130- device_out .release (key_id )
131- except Exception :
132- _logger .exception (f"Failed sending 0x{ key_id :02X} to { device_out } " )
133-
134- def _get_output_device (self , event : KeyEvent ) -> ConsumerControl | Keyboard | Mouse :
135- if is_consumer_key (event ):
136- return self ._consumer_gadget
137- elif is_mouse_button (event ):
138- return self ._mouse_gadget
139- return self ._keyboard_gadget
140-
141- def _move_mouse (self , event : RelEvent ) -> None :
142- x , y , mwheel = get_mouse_movement (event )
143- coordinates = f"(x={ x } , y={ y } , mwheel={ mwheel } )"
144- try :
145- _logger .debug (f"Moving mouse { self ._mouse_gadget } { coordinates } " )
146- self ._mouse_gadget .move (x , y , mwheel )
147- except Exception :
148- _logger .exception (f"Failed moving mouse { self ._mouse_gadget } { coordinates } " )
129+ await loop .run_in_executor (None , func , event )
130+
131+
132+ def _move_mouse (event : RelEvent ) -> None :
133+ x , y , mwheel = get_mouse_movement (event )
134+ coordinates = f"(x={ x } , y={ y } , mwheel={ mwheel } )"
135+ try :
136+ _logger .debug (f"Moving mouse { _mouse_gadget } { coordinates } " )
137+ _mouse_gadget .move (x , y , mwheel )
138+ except Exception :
139+ _logger .exception (f"Failed moving mouse { _mouse_gadget } { coordinates } " )
140+
141+
142+ def _send_key (event : KeyEvent ) -> None :
143+ key_id , key_name = evdev_to_usb_hid (event )
144+ if key_id is None :
145+ return
146+ device_out = _get_output_device (event )
147+ try :
148+ if event .keystate == KeyEvent .key_down :
149+ _logger .debug (f"Pressing { key_name } (0x{ key_id :02X} ) on { device_out } " )
150+ device_out .press (key_id )
151+ elif event .keystate == KeyEvent .key_up :
152+ _logger .debug (f"Releasing { key_name } (0x{ key_id :02X} ) on { device_out } " )
153+ device_out .release (key_id )
154+ except Exception :
155+ _logger .exception (f"Failed sending 0x{ key_id :02X} to { device_out } " )
156+
157+
158+ def _get_output_device (event : KeyEvent ) -> ConsumerControl | Keyboard | Mouse :
159+ if is_consumer_key (event ):
160+ return _consumer_gadget
161+ elif is_mouse_button (event ):
162+ return _mouse_gadget
163+ return _keyboard_gadget
149164
150165
151166class RelayController :
@@ -156,12 +171,13 @@ class RelayController:
156171 def __init__ (
157172 self , device_identifiers : list [str ] = None , auto_discover : bool = False
158173 ) -> None :
159- _enable_usb_devices ()
174+ init_usb_devices ()
160175 if not device_identifiers :
161176 device_identifiers = []
162177 self ._device_ids = [DeviceIdentifier (id ) for id in device_identifiers ]
163178 self ._auto_discover = auto_discover
164179 self ._cancelled = False
180+ self ._device_relay_paths : list [str ] = []
165181
166182 async def async_relay_devices (self ) -> NoReturn :
167183 try :
@@ -187,13 +203,13 @@ async def _async_discover_devices_loop(self) -> AsyncGenerator[InputDevice, None
187203 for device in list_readable_devices ():
188204 if self ._should_relay (device ):
189205 yield device
190- await asyncio .sleep (1 )
206+ await asyncio .sleep (0. 1 )
191207
192208 def _should_relay (self , device : InputDevice ) -> bool :
193- return not self ._has_task (device ) and self ._matches_criteria (device )
209+ return not self ._has_relay (device ) and self ._matches_criteria (device )
194210
195- def _has_task (self , device : InputDevice ) -> bool :
196- return device .path in [ task . get_name () for task in asyncio . all_tasks ()]
211+ def _has_relay (self , device : InputDevice ) -> bool :
212+ return device .path in self . _device_relay_paths
197213
198214 def _matches_criteria (self , device : InputDevice ) -> bool :
199215 return self ._auto_discover or self ._matches_any_identifier (device )
@@ -207,6 +223,7 @@ def _create_task(self, device: InputDevice, task_group: TaskGroup) -> None:
207223 async def _async_relay_events (self , device : InputDevice ) -> NoReturn :
208224 try :
209225 relay = DeviceRelay (device )
226+ self ._device_relay_paths .append (device .path )
210227 _logger .info (f"Activated { repr (relay )} " )
211228 await relay .async_relay_events_loop ()
212229 except CancelledError :
@@ -216,19 +233,6 @@ async def _async_relay_events(self, device: InputDevice) -> NoReturn:
216233 _logger .critical (f"Connection to { device .name } lost [{ repr (ex )} ]" )
217234 except Exception :
218235 _logger .exception (f"{ device .name } failed!" )
219- await asyncio .sleep (2 )
220-
221-
222- def list_readable_devices () -> list [InputDevice ]:
223- return [InputDevice (path ) for path in list_devices ()]
224-
225-
226- def _enable_usb_devices ():
227- usb_hid .enable (
228- [
229- Device .MOUSE ,
230- Device .KEYBOARD ,
231- Device .CONSUMER_CONTROL ,
232- ]
233- )
234- _logger .debug (f"Available USB devices: { usb_hid .devices } " )
236+ await asyncio .sleep (1 )
237+ finally :
238+ self ._device_relay_paths .remove (device .path )
0 commit comments