Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
include:
- os: ubuntu-latest
python-version: "3.9"
python-version: "3.10"

steps:
- uses: actions/checkout@v6
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:

- name: Check for pylint errors
run: |
python -m pip install pylint setuptools
python -m pip install pylint setuptools ruff
python setup.py build
python -m pylint --verbose -E build/lib*/evdev
python -m ruff check build/lib*/evdev
4 changes: 2 additions & 2 deletions examples/udev-example.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@
# should adapt this to your needs
if "py-evdev-uinput" in name:
if udev.action == "add":
print("Device added: %s" % udev)
print(f"Device added: {udev}")
fds[dev.fd] = InputDevice(udev.device_node)
break
if udev.action == "remove":
print("Device removed: %s" % udev)
print(f"Device removed: {udev}")

def helper():
global fds
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ description = "Bindings to the Linux input handling subsystem"
keywords = ["evdev", "input", "uinput"]
readme = "README.md"
license = "BSD-3-Clause"
requires-python = ">=3.9"
requires-python = ">=3.10"
authors = [
{ name="Georgi Valkov", email="georgi.t.valkov@gmail.com" },
]
Expand All @@ -32,6 +32,7 @@ classifiers = [
line-length = 120

[tool.ruff.lint]
select = ["UP", "TC"]
ignore = ["E265", "E241", "F403", "F401", "E401", "E731"]

[tool.bumpversion]
Expand Down
22 changes: 13 additions & 9 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
from setuptools import setup, Extension, Command
from setuptools.command import build_ext as _build_ext

from evdev import genecodes_c


curdir = Path(__file__).resolve().parent
ecodes_c_path = curdir / "src/evdev/ecodes.c"
ecodes_pyi_path = curdir / "src/evdev/_ecodes.pyi"


def create_ecodes(headers=None, reproducible=False):
Expand Down Expand Up @@ -63,13 +66,14 @@ def create_ecodes(headers=None, reproducible=False):
sys.stderr.write(textwrap.dedent(msg))
sys.exit(1)

print("writing %s (using %s)" % (ecodes_c_path, " ".join(headers)))
with ecodes_c_path.open("w") as fh:
cmd = [sys.executable, "src/evdev/genecodes_c.py"]
if reproducible:
cmd.append("--reproducible")
cmd.extend(["--ecodes", *headers])
run(cmd, check=True, stdout=fh)
for path, arg in [(ecodes_c_path, "--ecodes"), (ecodes_pyi_path, "--stubs")]:
print("writing %s (using %s)" % (path, " ".join(headers)))
with path.open("w") as fh:
cmd = [sys.executable, "src/evdev/genecodes_c.py"]
if reproducible:
cmd.append("--reproducible")
cmd.extend([arg, *headers])
run(cmd, check=True, stdout=fh)


class build_ecodes(Command):
Expand All @@ -96,8 +100,8 @@ def run(self):

class build_ext(_build_ext.build_ext):
def has_ecodes(self):
if ecodes_c_path.exists():
print("ecodes.c already exists ... skipping build_ecodes")
if ecodes_c_path.exists() and ecodes_pyi_path.exists():
print("ecodes.c and _ecodes.pyi already exist ... skipping build_ecodes")
return False
return True

Expand Down
7 changes: 5 additions & 2 deletions src/evdev/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
# Gather everything into a single, convenient namespace.
# --------------------------------------------------------------------------

# The superfluous "import name as name" syntax is here to satisfy mypy's attrs-defined rule.
# Alternatively all exported objects can be listed in __all__.
# The "import name as name" syntax is here to satisfy Python's type system
# import conventions:
# https://typing.python.org/en/latest/spec/distributing.html#import-conventions

from __future__ import annotations

from . import (
ecodes as ecodes,
Expand Down
42 changes: 42 additions & 0 deletions src/evdev/_input.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Python bindings to certain linux input subsystem functions"""

def ioctl_devinfo(fd: int, /) -> tuple[int, int, int, int, str, str, str]:
"""fetch input device info"""

def ioctl_capabilities(
fd: int, /
) -> dict[int, list[int | tuple[int, tuple[int, int, int, int, int, int]]]]:
"""fetch input device capabilities"""

def ioctl_EVIOCGABS(fd: int, ev_code: int, /) -> tuple[int, int, int, int, int, int]:
"""get input device absinfo"""

def ioctl_EVIOCSABS(
fd: int,
ev_code: int,
absinfo: tuple[int, int, int, int, int, int],
/,
) -> None:
"""set input device absinfo"""

def ioctl_EVIOCGREP(fd: int, /) -> tuple[int, int]: ...
def ioctl_EVIOCSREP(fd: int, delay: int, period: int, /) -> int: ...
def ioctl_EVIOCGVERSION(fd: int, /) -> int: ...
def ioctl_EVIOCGRAB(fd: int, flag: int, /) -> None: ...
def ioctl_EVIOCGEFFECTS(fd: int, /) -> int:
"""fetch the number of effects the device can keep in its memory."""

def ioctl_EVIOCG_bits(fd: int, evtype: int, /) -> list[int]:
"""get state of KEY|LED|SND|SW"""

def ioctl_EVIOCGPROP(fd: int, /) -> list[int]:
"""get device properties"""

def device_read(fd: int, /) -> tuple[int, int, int, int, int] | None:
"""read an input event from a device"""

def device_read_many(fd: int, /) -> tuple[tuple[int, int, int, int, int], ...]:
"""read all available input events from a device"""

def upload_effect(fd: int, effect_data: bytes, /) -> int: ...
def erase_effect(fd: int, ff_id: int, /) -> None: ...
42 changes: 42 additions & 0 deletions src/evdev/_uinput.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Python bindings for parts of linux/uinput.c."""

from typing import Final

maxnamelen: Final[int]

def open(devnode: str, /) -> int:
"""Open uinput device node."""

def setup(
fd: int,
name: str,
vendor: int,
product: int,
version: int,
bustype: int,
absinfo: list[list[int]],
max_effects: int,
/,
) -> None:
"""Set an uinput device up."""

def create(fd: int, /) -> None:
"""Create an uinput device."""

def close(fd: int, /) -> None:
"""Destroy uinput device."""

def write(fd: int, type: int, code: int, value: int, /) -> None:
"""Write event to uinput device."""

def enable(fd: int, type: int, code: int, /) -> None:
"""Enable a type of event."""

def set_phys(fd: int, phys: str, /) -> None:
"""Set physical path"""

def get_sysname(fd: int, /) -> str:
"""Obtain the sysname of the uinput device."""

def set_prop(fd: int, prop: int, /) -> None:
"""Set device input property"""
Loading