Follow-up from PR #110 review.
UsbJoystickInput.__init__ (inputs/impl/usb_joystick.py:153) starts the evdev reader thread immediately, leaving start() as a no-op:
self._thread = threading.Thread(target=self._run, daemon=True, name="usb_joystick")
self._thread.start()
def start(self) -> None:
pass # Thread already running from __init__.
This breaks the InputProvider lifecycle contract — BasePolicy._create_input_providers() expects start() to be the point at which the input goes live. Construction should be cheap/safe (so it's usable in tests, fixtures, etc.); the device fd is opened and the reader thread is spawned during construction today.
Suggested fix: in __init__, only enumerate and select the device (or even defer device open). Move thread creation + _thread.start() into start(). Mirrors KeyboardInput semantics.
Out of scope for #110 since this isn't a regression — added now to track.
Follow-up from PR #110 review.
UsbJoystickInput.__init__(inputs/impl/usb_joystick.py:153) starts the evdev reader thread immediately, leavingstart()as a no-op:This breaks the
InputProviderlifecycle contract —BasePolicy._create_input_providers()expectsstart()to be the point at which the input goes live. Construction should be cheap/safe (so it's usable in tests, fixtures, etc.); the device fd is opened and the reader thread is spawned during construction today.Suggested fix: in
__init__, only enumerate and select the device (or even defer device open). Move thread creation +_thread.start()intostart(). MirrorsKeyboardInputsemantics.Out of scope for #110 since this isn't a regression — added now to track.