Skip to content

Commit

Permalink
Asking for a python-evdev upgrade if outdated (sezanzeb#346)
Browse files Browse the repository at this point in the history
  • Loading branch information
sezanzeb authored Mar 18, 2022
1 parent f4de4d9 commit b6f26e1
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 61 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ input-remapper is now part of [Debian Unstable](https://packages.debian.org/sid/

##### pip

Dependencies from your distros repo: `python3-evdev`, `gtksourceview4`, `python3-devel`, `python3-pydantic`
Dependencies: `python3-evdev` ≥1.3.0, `gtksourceview4`, `python3-devel`, `python3-pydantic`

```bash
sudo pip install evdev -U # If newest version not in distros repo
sudo pip uninstall key-mapper
sudo pip install --no-binary :all: git+https://github.com/sezanzeb/input-remapper.git
sudo pip install --no-binary :all: git+https://github.com/sezanzeb/input-remapper.git # no --user
sudo systemctl enable input-remapper
sudo systemctl restart input-remapper
```
Expand Down
10 changes: 9 additions & 1 deletion inputremapper/gui/user_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
from inputremapper.event_combination import EventCombination
from inputremapper.gui.reader import reader
from inputremapper.gui.helper import is_helper_running
from inputremapper.injection.injector import RUNNING, FAILED, NO_GRAB
from inputremapper.injection.injector import RUNNING, FAILED, NO_GRAB, UPGRADE_EVDEV
from inputremapper.daemon import Daemon
from inputremapper.configs.global_config import global_config
from inputremapper.injection.macros.parse import is_this_a_macro, parse
Expand Down Expand Up @@ -629,6 +629,14 @@ def show_injection_result(self):
)
return False

if state == UPGRADE_EVDEV:
self.show_status(
CTX_ERROR,
"Upgrade python-evdev",
"Your python-evdev version is too old.",
)
return False

# keep the timeout running until a relevant state is found
return True

Expand Down
70 changes: 34 additions & 36 deletions inputremapper/injection/injector.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"""Keeps injecting keycodes in the background based on the preset."""

import os
import sys
import asyncio
import time
import multiprocessing
Expand All @@ -47,7 +48,7 @@

# messages
CLOSE = 0
OK = 1
UPGRADE_EVDEV = 7

# states
UNKNOWN = -1
Expand Down Expand Up @@ -80,18 +81,6 @@ 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.
Expand Down Expand Up @@ -139,27 +128,26 @@ def get_state(self) -> int:
Can be safely called from the main process.
"""
# slowly figure out what is going on
# figure out what is going on step by step
alive = self.is_alive()

if self._state == UNKNOWN and not alive:
# didn't start yet
# `self.start()` has not been called yet
return self._state

# if it is alive, it is definitely at least starting up
if self._state == UNKNOWN and alive:
# if it is alive, it is definitely at least starting up.
self._state = STARTING

# if there is a message available, it might have finished starting up
if self._state == STARTING and self._msg_pipe[1].poll():
# if there is a message available, it might have finished starting up
# and the injector has the real status for us
msg = self._msg_pipe[1].recv()
if msg == OK:
self._state = RUNNING

if msg == NO_GRAB:
self._state = NO_GRAB
self._state = msg

if self._state in [STARTING, RUNNING] and not alive:
# we thought it is running (maybe it was when get_state was previously),
# but the process is not alive. It probably crashed
self._state = FAILED
logger.error("Injector was unexpectedly found stopped")

Expand Down Expand Up @@ -340,19 +328,29 @@ 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 = 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
# causes the udev rule to autoload for the original device, overwriting our previous attempts at
# starting an injection.
vendor=source.info.vendor,
product=source.info.product,
version=source.info.version,
bustype=source.info.bustype,
# input_props has been missing in one case
input_props=getattr(source, "input_props", lambda: None)(),
)
try:
forward_to = evdev.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 causes the udev rule to
# autoload for the original device, overwriting our previous
# attempts at starting an injection.
vendor=source.info.vendor,
product=source.info.product,
version=source.info.version,
bustype=source.info.bustype,
input_props=source.input_props(),
)
except TypeError as e:
if "input_props" in str(e):
# UInput constructor doesn't support input_props and
# source.input_props doesn't exist with old python-evdev versions.
logger.error("Please upgrade your python-evdev version. Exiting")
self._msg_pipe[0].send(UPGRADE_EVDEV)
sys.exit(12)

raise e

# actually doing things
consumer_control = ConsumerControl(self.context, source, forward_to)
Expand All @@ -365,7 +363,7 @@ def run(self) -> None:
# grabbing devices screws this up
set_numlock(numlock_state)

self._msg_pipe[0].send(OK)
self._msg_pipe[0].send(RUNNING)

try:
loop.run_until_complete(asyncio.gather(*coroutines))
Expand Down
22 changes: 0 additions & 22 deletions tests/unit/test_injector.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
NO_GRAB,
UNKNOWN,
get_udev_name,
create_uinput,
)
from inputremapper.injection.numlock import is_numlock_on
from inputremapper.configs.system_mapping import (
Expand Down Expand Up @@ -129,27 +128,6 @@ 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"
Expand Down

0 comments on commit b6f26e1

Please sign in to comment.