Python bindings to the Linux input handling subsystem for reading input events and creating virtual input devices
npx @tessl/cli install tessl/pypi-evdev@1.9.0Python bindings to the Linux input handling subsystem, providing access to input events from devices like keyboards, mice, joysticks, and touchscreens. The package enables both reading input events from existing devices and creating virtual input devices to inject events into the Linux input subsystem.
pip install evdevimport evdevCommon patterns:
import os
from evdev import InputDevice, UInput, categorize, ecodesFor specific functionality:
from evdev import list_devices, resolve_ecodes, resolve_ecodes_dict
from evdev.ff import Effect, Rumble, Constant, Periodic, Conditionfrom evdev import InputDevice, categorize, ecodes
# Open an input device
device = InputDevice('/dev/input/event0')
# Read events continuously
for event in device.read_loop():
if event.type == ecodes.EV_KEY:
key_event = categorize(event)
print(f'Key {key_event.keycode} {key_event.keystate}')from evdev import UInput, ecodes
# Create a virtual input device
ui = UInput()
# Send a key press
ui.write(ecodes.EV_KEY, ecodes.KEY_A, 1) # Press
ui.write(ecodes.EV_KEY, ecodes.KEY_A, 0) # Release
ui.syn()
ui.close()from evdev import list_devices, InputDevice
# List all available input devices
devices = list_devices()
for device_path in devices:
device = InputDevice(device_path)
print(f'{device.path}: {device.name}')The evdev package is built around several core components:
The design closely mirrors the Linux kernel's input subsystem, providing a Pythonic interface to evdev character devices while maintaining full access to low-level capabilities.
Core functionality for opening, reading from, and controlling input devices. Includes device discovery, capability querying, event reading, and exclusive device access.
class InputDevice:
def __init__(self, dev: Union[str, bytes, os.PathLike]) -> None: ...
def capabilities(self, verbose: bool = False, absinfo: bool = True) -> Dict: ...
def read_loop(self) -> Iterator[InputEvent]: ...
def read_one(self) -> Union[InputEvent, None]: ...
def grab(self) -> None: ...
def close(self) -> None: ...
def list_devices(input_device_dir: Union[str, bytes, os.PathLike] = "/dev/input") -> List[str]: ...Event classes and utilities for handling, categorizing, and interpreting input events from devices. Includes typed event classes and event processing utilities.
class InputEvent:
def __init__(self, sec: int, usec: int, type: int, code: int, value: int) -> None: ...
def timestamp(self) -> float: ...
class KeyEvent:
def __init__(self, event: InputEvent, allow_unknown: bool = False) -> None: ...
def categorize(event: InputEvent) -> Union[InputEvent, KeyEvent, RelEvent, AbsEvent, SynEvent]: ...Creating and managing virtual input devices using UInput to inject events into the Linux input subsystem. Supports creating devices with custom capabilities and sending events programmatically.
class UInput:
def __init__(
self,
events: Optional[Dict[int, Sequence[int]]] = None,
name: str = "py-evdev-uinput",
vendor: int = 0x1,
product: int = 0x1,
version: int = 0x1,
bustype: int = 0x3,
devnode: str = "/dev/uinput",
phys: str = "py-evdev-uinput",
input_props=None,
max_effects: int = 96
) -> None: ...
def write(self, etype: int, code: int, value: int) -> None: ...
def syn(self) -> None: ...
def close(self) -> None: ...Comprehensive mapping of Linux input subsystem constants and utilities for resolving event codes to human-readable names. Includes all event types, key codes, and constant mappings.
# Event type constants
EV_KEY: int
EV_REL: int
EV_ABS: int
EV_SYN: int
# Key code dictionaries
KEY: Dict[int, str]
BTN: Dict[int, str]
ABS: Dict[int, str]
REL: Dict[int, str]
def resolve_ecodes(ecode_dict, ecode_list, unknown: str = "?") -> List: ...
def resolve_ecodes_dict(typecodemap, unknown: str = "?") -> Iterator: ...
def find_ecodes_by_regex(regex) -> Dict[int, List[int]]: ...Support for force feedback effects on compatible devices. Includes effect structures, uploading effects, and controlling haptic feedback.
class Effect(ctypes.Structure): ...
class Rumble(ctypes.Structure): ...
class Constant(ctypes.Structure): ...
class Periodic(ctypes.Structure): ...The evdev package provides async support for non-blocking event reading through the eventio_async module (when available):
class ReadIterator:
"""Async iterator for reading input events"""
def __aiter__(self) -> ReadIterator: ...
def __anext__(self) -> Awaitable[InputEvent]: ...Async usage:
import asyncio
from evdev import InputDevice
async def read_events():
device = InputDevice('/dev/input/event0')
# Async event reading
async for event in device.async_read_loop():
print(f'Event: {event.type} {event.code} {event.value}')
# Single async read
event = await device.async_read_one()
if event:
print(f'Single event: {event}')The package defines specific exceptions for different error conditions:
class EvdevError(Exception):
"""Base exception for evdev-related errors"""
class UInputError(Exception):
"""Exception for UInput-specific errors"""Common error scenarios include device access permissions, invalid device paths, and UInput device creation failures.
class AbsInfo(NamedTuple):
"""Absolute axis information"""
value: int
min: int
max: int
fuzz: int
flat: int
resolution: int
class DeviceInfo(NamedTuple):
"""Device identification information"""
bustype: int
vendor: int
product: int
version: int
class KbdInfo(NamedTuple):
"""Keyboard repeat rate information"""
delay: int
repeat: intUsage examples:
# Get current repeat settings
device = InputDevice('/dev/input/event0')
kbd_info = device.repeat
print(f"Delay: {kbd_info.delay}ms, Rate: {kbd_info.repeat} chars/sec")
# Set new repeat settings
device.repeat = KbdInfo(500, 30) # 500ms delay, 30 chars/sec