diff --git a/inputremapper/injection/injector.py b/inputremapper/injection/injector.py index 510036b10..458bf2f53 100644 --- a/inputremapper/injection/injector.py +++ b/inputremapper/injection/injector.py @@ -80,6 +80,18 @@ def get_udev_name(name: str, suffix: str) -> str: return name +def create_uinput(*args, **kwargs): + """Safely create an UInput, compatible with various versions of evdev.""" + try: + return evdev.UInput(*args, **kwargs) + except TypeError as e: + if "input_props" in str(e): + del kwargs["input_props"] + return evdev.UInput(*args, **kwargs) + + raise e + + class Injector(multiprocessing.Process): """Initializes, starts and stops injections. @@ -328,7 +340,7 @@ def run(self) -> None: # copy as much information as possible, because libinput uses the extra # information to enable certain features like "Disable touchpad while # typing" - forward_to = evdev.UInput( + forward_to = create_uinput( name=get_udev_name(source.name, "forwarded"), events=self._copy_capabilities(source), # phys=source.phys, # this leads to confusion. the appearance of an uinput with this "phys" property diff --git a/tests/unit/test_injector.py b/tests/unit/test_injector.py index 1f960cbed..93098cabd 100644 --- a/tests/unit/test_injector.py +++ b/tests/unit/test_injector.py @@ -68,6 +68,7 @@ NO_GRAB, UNKNOWN, get_udev_name, + create_uinput, ) from inputremapper.injection.numlock import is_numlock_on from inputremapper.configs.system_mapping import ( @@ -128,6 +129,27 @@ def find_joystick_to_mouse(self): if isinstance(consumer, JoystickToMouse) ][0] + def test_create_uinput(self): + # can create an uinput with an input_props argument, + # which is ignored if it fails + def patch( + events=None, + name="py-evdev-uinput", + vendor=0x1, + product=0x1, + version=0x1, + bustype=0x3, + devnode="/dev/uinput", + phys="py-evdev-uinput", + ): + # act like some outdated python-evdev version or something that doesn't + # support input_props + pass + + with mock.patch.object(evdev, "UInput", patch): + # should not raise an error + create_uinput(input_props=[]) + def test_grab(self): # path is from the fixtures path = "/dev/input/event10"