fix(evdev): remove disconnected devices to prevent CPU spin (#242)

When an input device is disconnected, select() reports the fd as
readable but read() fails with ENODEV. Previously, the code caught
the error but kept the dead fd in the list, causing an infinite
busy loop that consumed 100% CPU.

Now disconnected devices are removed from both self.devices and
self.device_fds when read() fails, preventing the busy loop.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: AntoineMontane <monnet.antoine@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Antoine Monnet
2026-02-22 19:59:49 -08:00
committed by GitHub
co-authored by AntoineMontane Claude Opus 4.5
parent 0c5e641060
commit 068240e7be
@@ -315,8 +315,16 @@ class EvdevKeyboardBackend(KeyboardBackend):
if event.type == ecodes.EV_KEY:
self._handle_key_event(event, device)
except (OSError, IOError):
# Device was likely disconnected
except (OSError, IOError) as e:
# Device was disconnected - remove it to avoid busy loop
logger.debug(f"Device disconnected (fd={fd}): {e}")
if device is not None:
try:
self.devices.remove(device)
except ValueError:
pass
if fd in self.device_fds:
self.device_fds.remove(fd)
continue
except (OSError, ValueError) as e: