From 057f7533b1ee642961509a5ffd1032ae0813f72c Mon Sep 17 00:00:00 2001 From: Nick Price Date: Sat, 11 Jul 2026 17:42:52 -0700 Subject: [PATCH] diversion: treat evdev as an optional dependency evdev was imported unconditionally on every OS except macOS and Windows, i.e. the code assumed "not macOS and not Windows" means Linux. On any other platform the import is a hard failure at startup. evdev is also genuinely optional: setup.py only installs it when platform_system == "Linux", and packagers may make it optional. Select on whether the module imports rather than on the OS name. click_uinput() dereferenced evdev.ecodes before calling simulate_uinput(), so it raised AttributeError rather than degrading; click() has no handler, so that escaped to the caller. Bail out early there and in setup_uinput() when evdev is absent. simulate_scroll() was already safe, but only because setup_uinput()'s blanket except swallowed the AttributeError. --- lib/logitech_receiver/diversion.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/logitech_receiver/diversion.py b/lib/logitech_receiver/diversion.py index e933f5ad..b55982e5 100644 --- a/lib/logitech_receiver/diversion.py +++ b/lib/logitech_receiver/diversion.py @@ -21,7 +21,6 @@ import logging import math import numbers import os -import platform import socket import struct import subprocess @@ -39,12 +38,13 @@ import yaml from keysyms import keysymdef -# There is no evdev on macOS or Windows. Diversion will not work without -# it but other Solaar functionality is available. -if platform.system() in ("Darwin", "Windows"): - evdev = None -else: +# evdev is not available on every platform, and is an optional dependency +# elsewhere. Diversion will not work without it but other Solaar +# functionality is available. +try: import evdev +except ImportError: + evdev = None from .common import NamedInt from .hidpp20 import SupportedFeature @@ -257,6 +257,8 @@ else: def setup_uinput(): global udevice + if evdev is None: + return False if udevice is not None: return udevice try: @@ -337,6 +339,8 @@ def simulate_key(code, event): # X11 keycode but Solaar event code def click_uinput(button, count): + if evdev is None: + return False if isinstance(count, int): for _ in range(count): if not simulate_uinput(evdev.ecodes.EV_KEY, button[1], 1):