PYTHON-EVDEV(7)
โจ NAME โจ
okay bestie, say hi to python-evdev โ the python-evdev Documentation. This is section 7, and it's literally the whole vibe. ๐
This package provides bindings to the generic input event interface in Linux. The evdev interface serves the purpose of passing events generated in the kernel directly to userspace through character devices that are typically located in /dev/input/.
This package also comes with bindings to uinput, the userspace input subsystem. Uinput allows userspace programs to create and handle input devices that can inject events directly into the input subsystem.
In other words, python-evdev allows you to read and write input events on Linux. An event can be a key or button press, a mouse movement or a tap on a touchscreen. ๐โจ
โจ FROM AN OS PACKAGE โจ
Python-evdev has been packaged for the following distributions:
Consult the documentation of your OS package manager for installation instructions. ๐ซถ
โจ FROM SOURCE โจ
The latest stable version of python-evdev can be installed from pypi <http://pypi.python.org/pypi/evdev>, provided that you have a compiler, pip <http://pip.readthedocs.org/en/latest/installing.html> and the Python and Linux development headers installed on your system. Installing these is distribution specific and typically falls into one of the following:
On a Debian compatible OS:
$ apt install python-dev python-pip gcc
$ apt install linux-headers-$(uname -r)
On a Redhat compatible OS:
$ dnf install python-devel python-pip gcc
$ dnf install kernel-headers-$(uname -r)
On Arch Linux and derivatives:
$ pacman -S core/linux-api-headers python-pip gcc
Once all OS dependencies are available, you may install python-evdev using pip <http://pip.readthedocs.org/en/latest/installing.html>, preferably in a [virtualenv]:
# Install globally (not recommended).
$ sudo python3 -m pip install evdev
# Install for the current user.
$ python3 -m pip install --user evdev
# Install in a virtual environment.
$ python3 -m venv abc
$ source abc/bin/activate
$ python3 -m pip install evdev
โจ Specifying header locations โจ
By default, the setup script will look for the input.h and input-event-codes.h [1] header files /usr/include/linux.
You may use the --evdev-headers option to the build_ext setuptools command to the location of these header files. It accepts one or more colon-separated paths. For example:
$ python setup.py build_ext \
--evdev-headers buildroot/input.h:buildroot/input-event-codes.h \
--include-dirs buildroot/ \
install # or any other command (e.g. develop, bdist, bdist_wheel)
โจ FROM A BINARY PACKAGE โจ
You may choose to install a precompiled version of python-evdev from pypi. The evdev-binary <http://pypi.python.org/pypi/evdev-binary> package provides binary wheels that have been compiled on EL8 against the 4.18.0 kernel headers.
$ python3 -m pip install evdev-binary
While the evdev interface is stable, the precompiled version may not be fully compatible or expose all the features of your running kernel. For best results, it is recommended to use an OS package or to install from source. ๐
[1] input-event-codes.h is found only in recent kernel versions.
โจ QUICK START โจ
โจ Listing accessible event devices โจ
>>> import evdev
>>> devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
>>> for device in devices:
... print(device.path, device.name, device.phys)
/dev/input/event1 USB Keyboard usb-0000:00:12.1-2/input0
/dev/input/event0 USB Optical Mouse usb-0000:00:12.0-2/input0
Note: If you do not see any devices, ensure that your user is in the correct group (typically input) to have read/write access. ๐
โจ Reading events from a device โจ
>>> import evdev
>>> device = evdev.InputDevice('/dev/input/event1')
>>> print(device)
device /dev/input/event1, name "USB Keyboard", phys "usb-0000:00:12.1-2/input0"
>>> for event in device.read_loop():
... if event.type == evdev.ecodes.EV_KEY:
... print(evdev.categorize(event))
... # pressing 'a' and holding 'space'
key event at 1337016188.396030, 30 (KEY_A), down
key event at 1337016188.492033, 30 (KEY_A), up
key event at 1337016189.772129, 57 (KEY_SPACE), down
key event at 1337016190.275396, 57 (KEY_SPACE), hold
key event at 1337016190.284160, 57 (KEY_SPACE), up
โจ Accessing event codes โจ
The evdev.ecodes module provides reverse and forward mappings between the names and values of the event subsystem constants.
>>> from evdev import ecodes
>>> ecodes.KEY_A
... 30
>>> ecodes.ecodes['KEY_A']
... 30
>>> ecodes.KEY[30]
... 'KEY_A'
>>> ecodes.bytype[ecodes.EV_KEY][30]
... 'KEY_A'
# A single value may correspond to multiple event codes.
>>> ecodes.KEY[152]
... ['KEY_COFFEE', 'KEY_SCREENLOCK']
โจ Listing and monitoring input devices โจ
The python-evdev package also comes with a small command-line program for listing and monitoring input devices:
$ python -m evdev.evtest
โจ TUTORIAL โจ
โจ Listing accessible event devices โจ
>>> import evdev
>>> devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
>>> for device in devices:
>>> print(device.path, device.name, device.phys)
/dev/input/event1 Dell Dell USB Keyboard usb-0000:00:12.1-2/input0
/dev/input/event0 Dell USB Optical Mouse usb-0000:00:12.0-2/input0
โจ Listing device capabilities โจ
>>> import evdev
>>> device = evdev.InputDevice('/dev/input/event0')
>>> print(device)
device /dev/input/event0, name "Dell USB Optical Mouse", phys "usb-0000:00:12.0-2/input0"
>>> device.capabilities()
... { 0: [0, 1, 2], 1: [272, 273, 274, 275], 2: [0, 1, 6, 8], 4: [4] }
>>> device.capabilities(verbose=True)
... { ('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('SYN_MT_REPORT', 2)],
... ('EV_KEY', 1): [('BTN_MOUSE', 272), ('BTN_RIGHT', 273), ('BTN_MIDDLE', 274), ('BTN_SIDE', 275)], ...
โจ Listing device capabilities (devices with absolute axes) โจ
>>> import evdev
>>> device = evdev.InputDevice('/dev/input/event7')
>>> print(device)
device /dev/input/event7, name "Wacom Bamboo 2FG 4x5 Finger", phys ""
>>> device.capabilities()
... { 1: [272, 273, 277, 278, 325, 330, 333] ,
... 3: [(0, AbsInfo(min=0, max=15360, fuzz=128, flat=0)),
... (1, AbsInfo(min=0, max=10240, fuzz=128, flat=0))] }
>>> device.capabilities(verbose=True)
... { ('EV_KEY', 1): [('BTN_MOUSE', 272), ('BTN_RIGHT', 273), ...],
... ('EV_ABS', 3): [(('ABS_X', 0), AbsInfo(min=0, max=15360, fuzz=128, flat=0)),
... (('ABS_Y', 1), AbsInfo(min=0, max=10240, fuzz=128, flat=0)),] }
>>> device.capabilities(absinfo=False)
... { 1: [272, 273, 277, 278, 325, 330, 333],
... 3: [0, 1, 47, 53, 54, 57] }
โจ Getting and setting LED states โจ
>>> dev.leds(verbose=True)
... [('LED_NUML', 0), ('LED_CAPSL', 1)]
>>> dev.leds()
... [0, 1]
>>> dev.set_led(ecodes.LED_NUML, 1) # enable numlock
>>> dev.set_led(ecodes.LED_NUML, 0) # disable numlock
โจ Getting currently active keys โจ
>>> dev.active_keys(verbose=True)
... [('KEY_3', 4), ('KEY_LEFTSHIFT', 42)]
>>> dev.active_keys()
... [4, 42]
โจ Reading events โจ
Reading events from a single device in an endless loop.
>>> from evdev import InputDevice, categorize, ecodes
>>> dev = InputDevice('/dev/input/event1')
>>> print(dev)
device /dev/input/event1, name "Dell Dell USB Keyboard", phys "usb-0000:00:12.1-2/input0"
>>> for event in dev.read_loop():
... if event.type == ecodes.EV_KEY:
... print(categorize(event))
... # pressing 'a' and holding 'space'
key event at 1337016188.396030, 30 (KEY_A), down
key event at 1337016188.492033, 30 (KEY_A), up
key event at 1337016189.772129, 57 (KEY_SPACE), down
key event at 1337016190.275396, 57 (KEY_SPACE), hold
key event at 1337016190.284160, 57 (KEY_SPACE), up
โจ Reading events (using asyncio) โจ
Note: This requires Python 3.5+ for theasync/awaitkeywords.
>>> import asyncio
>>> from evdev import InputDevice
>>> dev = InputDevice('/dev/input/event1')
>>> async def main(dev):
... async for ev in dev.async_read_loop():
... print(repr(ev))
>>> asyncio.run(main(dev))
InputEvent(1527363738, 348740, 4, 4, 458792)
InputEvent(1527363738, 348740, 1, 28, 0)
InputEvent(1527363738, 348740, 0, 0, 0)
โจ Reading events from multiple devices (using select) โจ
>>> from evdev import InputDevice
>>> from select import select
# A mapping of file descriptors (integers) to InputDevice instances.
>>> devices = map(InputDevice, ('/dev/input/event1', '/dev/input/event2'))
>>> devices = {dev.fd: dev for dev in devices}
>>> for dev in devices.values(): print(dev)
device /dev/input/event1, name "Dell Dell USB Keyboard", phys "usb-0000:00:12.1-2/input0"
device /dev/input/event2, name "Logitech USB Laser Mouse", phys "usb-0000:00:12.0-2/input0"
>>> while True:
... r, w, x = select(devices, [], [])
... for fd in r:
... for event in devices[fd].read():
... print(event)
event at 1351116708.002230, code 01, type 02, val 01
event at 1351116708.002234, code 00, type 00, val 00
event at 1351116708.782231, code 04, type 04, val 458782
event at 1351116708.782237, code 02, type 01, val 01
โจ Reading events from multiple devices (using selectors) โจ
This can also be achieved using the selectors module in Python 3.4:
from evdev import InputDevice
from selectors import DefaultSelector, EVENT_READ
selector = DefaultSelector()
mouse = InputDevice('/dev/input/event1')
keybd = InputDevice('/dev/input/event2')
# This works because InputDevice has a `fileno()` method.
selector.register(mouse, EVENT_READ)
selector.register(keybd, EVENT_READ)
while True:
for key, mask in selector.select():
device = key.fileobj
for event in device.read():
print(event)
โจ Reading events from multiple devices (using asyncio) โจ
Yet another possibility is the asyncio module from Python 3.4:
import asyncio, evdev
@asyncio.coroutine
def print_events(device):
while True:
events = yield from device.async_read()
for event in events:
print(device.path, evdev.categorize(event), sep=': ')
mouse = evdev.InputDevice('/dev/input/eventX')
keybd = evdev.InputDevice('/dev/input/eventY')
for device in mouse, keybd:
asyncio.async(print_events(device))
loop = asyncio.get_event_loop()
loop.run_forever()
Okay bestie, and if you're on Python 3.5 or newer (which, like, you are, obviously ๐
) the whole async/await thing makes this even cuter. The docs live at https://docs.python.org/3/library/asyncio-task.html btw โ iykyk.
import asyncio, evdev
mouse = evdev.InputDevice('/dev/input/event4')
keybd = evdev.InputDevice('/dev/input/event5')
async def print_events(device):
async for event in device.async_read_loop():
print(device.path, evdev.categorize(event), sep=': ')
for device in mouse, keybd:
asyncio.ensure_future(print_events(device))
loop = asyncio.get_event_loop()
loop.run_forever()
๐ Accessing evdev constants ๐
All the constant vibes live in one place, bestie. Look how easy:
>>> from evdev import ecodes
>>> ecodes.KEY_A, ecodes.ecodes['KEY_A']
... (30, 30)
>>> ecodes.KEY[30]
... 'KEY_A'
>>> ecodes.bytype[ecodes.EV_KEY][30]
... 'KEY_A'
>>> ecodes.KEY[152] # a single value may correspond to multiple codes
... ['KEY_COFFEE', 'KEY_SCREENLOCK']
Not the KEY_COFFEE / KEY_SCREENLOCK plot twist ๐ญ one number, two names, it's giving polyamory.
๐ Searching event codes by regex ๐
You can literally regex-hunt for event codes. Main character behaviour fr fr.
>>> from evdev import util
>>> res = util.find_ecodes_by_regex(r'(ABS|KEY)_BR(AKE|EAK)')
>>> res
... {1: [411], 3: [10]}
>>> util.resolve_ecodes_dict(res)
... {('EV_KEY', 1): [('KEY_BREAK', 411)], ('EV_ABS', 3): [('ABS_BRAKE', 10)]}
๐ Getting exclusive access to a device ๐
>>> dev.grab() # become the sole recipient of all incoming input events
>>> dev.ungrab()
This functionality is also available as a context manager. Slay.
>>> with dev.grab_context():
... pass
๐งฌ Associating classes with event types ๐งฌ
>>> from evdev import categorize, event_factory, ecodes
>>> class SynEvent:
... def __init__(self, event):
... ...
>>> event_factory[ecodes.EV_SYN] = SynEvent
See events (anchor: #evdev.events.event_factory) for more information. ๐
๐ Injecting input ๐
>>> from evdev import UInput, ecodes as e
>>> ui = UInput()
>>> # accepts only KEY_* events by default
>>> ui.write(e.EV_KEY, e.KEY_A, 1) # KEY_A down
>>> ui.write(e.EV_KEY, e.KEY_A, 0) # KEY_A up
>>> ui.syn()
>>> ui.close()
Heads up bestie: by default it only accepts KEY_* events. Periodt.
๐ Injecting events (using a context manager) ๐
>>> ev = InputEvent(1334414993, 274296, ecodes.EV_KEY, ecodes.KEY_A, 1)
>>> with UInput() as ui:
... ui.write_event(ev)
... ui.syn()
๐๏ธ Specifying uinput device options ๐๏ธ
Note: ecodes.EV_SYN cannot be in the cap dictionary or the device will not be created.
Like, do NOT put that in there, the device simply will not spawn. No cap. ๐ซถ
>>> from evdev import UInput, AbsInfo, ecodes as e
>>> cap = {
... e.EV_KEY : [e.KEY_A, e.KEY_B],
... e.EV_ABS : [
... (e.ABS_X, AbsInfo(value=0, min=0, max=255,
... fuzz=0, flat=0, resolution=0)),
... (e.ABS_Y, AbsInfo(0, 0, 255, 0, 0, 0)),
... (e.ABS_MT_POSITION_X, (0, 128, 255, 0)) ]
... }
>>> ui = UInput(cap, name='example-device', version=0x3)
>>> print(ui)
name "example-device", bus "BUS_USB", vendor "0001", product "0001", version "0003"
event types: EV_KEY EV_ABS EV_SYN
>>> print(ui.capabilities())
{0: [0, 1, 3],
1: [30, 48],
3: [(0, AbsInfo(value=0, min=0, max=0, fuzz=255, flat=0, resolution=0)),
(1, AbsInfo(value=0, min=0, max=0, fuzz=255, flat=0, resolution=0)),
(53, AbsInfo(value=0, min=0, max=255, fuzz=128, flat=0, resolution=0))]}
>>> # move mouse cursor
>>> ui.write(e.EV_ABS, e.ABS_X, 20)
>>> ui.write(e.EV_ABS, e.ABS_Y, 20)
>>> ui.syn()
๐งฒ Create uinput device with capabilities of another device ๐งฒ
Steal the whole personality of an existing device and put it on a brand new one. It's giving clone era.
>>> from evdev import UInput, InputDevice
>>> mouse = InputDevice('/dev/input/event1')
>>> keybd = '/dev/input/event2'
>>> ui = UInput.from_device(mouse, keybd, name='keyboard-mouse-device')
>>> ui.capabilities(verbose=True).keys()
dict_keys([('EV_LED', 17), ('EV_KEY', 1), ('EV_SYN', 0), ('EV_REL', 2), ('EV_MSC', 4)])
๐ฎ Create uinput device capable of receiving FF-effects ๐ฎ
Force feedback time, bestie. Rumble mode activated. ๐
import asyncio
from evdev import UInput, categorize, ecodes
cap = {
ecodes.EV_FF: [ecodes.FF_RUMBLE ],
ecodes.EV_KEY: [ecodes.KEY_A, ecodes.KEY_B]
}
ui = UInput(cap, name='test-controller', version=0x3)
async def print_events(device):
async for event in device.async_read_loop():
print(categorize(event))
# Wait for an EV_UINPUT event that will signal us that an
# effect upload/erase operation is in progress.
if event.type != ecodes.EV_UINPUT:
continue
if event.code == ecodes.UI_FF_UPLOAD:
upload = device.begin_upload(event.value)
upload.retval = 0
print(f'[upload] effect_id: {upload.effect.id}, type: {upload.effect.type}')
device.end_upload(upload)
elif event.code == ecodes.UI_FF_ERASE:
erase = device.begin_erase(event.value)
print(f'[erase] effect_id {erase.effect_id}')
erase.retval = 0
device.end_erase(erase)
asyncio.ensure_future(print_events(ui))
loop = asyncio.get_event_loop()
loop.run_forever()
๐ฅ Injecting an FF-event into first FF-capable device found ๐ฅ
from evdev import ecodes, InputDevice, ff, list_devices
import time
# Find first EV_FF capable event device (that we have permissions to use).
for name in list_devices():
dev = InputDevice(name)
if ecodes.EV_FF in dev.capabilities():
break
rumble = ff.Rumble(strong_magnitude=0x0000, weak_magnitude=0xffff)
effect_type = ff.EffectType(ff_rumble_effect=rumble)
duration_ms = 1000
effect = ff.Effect(
ecodes.FF_RUMBLE, -1, 0,
ff.Trigger(0, 0),
ff.Replay(duration_ms, 0),
effect_type
)
repeat_count = 1
effect_id = dev.upload_effect(effect)
dev.write(ecodes.EV_FF, effect_id, repeat_count)
time.sleep(duration_ms / 1000)
dev.erase_effect(effect_id)
๐ก Forwarding force-feedback from uinput to a real device ๐ก
import evdev
from evdev import ecodes as e
# Find first EV_FF capable event device (that we have permissions to use).
for name in evdev.list_devices():
dev = evdev.InputDevice(name)
if e.EV_FF in dev.capabilities():
break
# To ensure forwarding works correctly it is important that `max_effects`
# of the uinput device is <= `dev.ff_effects_count`.
# `from_device()` will do this automatically, but in some situations you may
# want to set the `max_effects` parameter manually, such as when using `Uinput()`.
# `filtered_types` is specified as by default EV_FF events are filtered
uinput = evdev.UInput.from_device(dev, filtered_types=[e.EV_SYN])
# Keeps track of which effects have been uploaded to the device
effects = set()
for event in uinput.read_loop():
# Handle the special uinput events
if event.type == e.EV_UINPUT:
if event.code == e.UI_FF_UPLOAD:
upload = uinput.begin_upload(event.value)
# Checks if this is a new effect
if upload.effect.id not in effects:
effects.add(upload.effect.id)
# Setting id to 1 indicates that a new effect must be allocated
upload.effect.id = -1
dev.upload_effect(upload.effect)
upload.retval = 0
uinput.end_upload(upload)
elif event.code == e.UI_FF_ERASE:
erase = uinput.begin_erase(event.value)
erase.retval = 0
dev.erase_effect(erase.effect_id)
effects.remove(erase.effect_id)
uinput.end_erase(erase)
# Forward writes to actual rumble device.
elif event.type == e.EV_FF:
dev.write(event.type, event.code, event.value)
๐ API REFERENCE ๐
๐ฆ events ๐ฆ
This module provides the InputEvent class, which closely resembles the input_event struct defined in linux/input.h:
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
This module also defines several InputEvent sub-classes that know more about the different types of events (key, abs, rel etc). The event_factory dictionary maps event types to these classes.
Assuming you use the evdev.util.categorize() function to categorize events according to their type, adding or replacing a class for a specific event type becomes a matter of modifying event_factory.
All classes in this module have reasonable str() and repr() methods:
>>> print(event)
event at 1337197425.477827, code 04, type 04, val 458792
>>> print(repr(event))
InputEvent(1337197425L, 477827L, 4, 4, 458792L)
>>> print(key_event)
key event at 1337197425.477835, 28 (KEY_ENTER), up
>>> print(repr(key_event))
KeyEvent(InputEvent(1337197425L, 477835L, 1, 28, 0L))
๐ class evdev.events.InputEvent(sec, usec, type, code, value) ๐
A generic input event. The humble beginning of everything, honestly. โจ
sec: intโ Time in seconds since epoch at which event occurred.usec: intโ Microsecond portion of the timestamp.type: intโ Event type โ one ofecodes.EV_*.code: intโ Event code related to the event type.value: intโ Event value related to the event type.
And the method:
timestamp() -> floatโ Return event timestamp as a float.
๐ class evdev.events.KeyEvent(event: InputEvent <#evdev.events.InputEvent>, allow_unknown: bool = False) ๐
An event generated by a keyboard, button or other key-like devices. Your fave, probably. โจ๏ธ
key_up: Final[int] = 0key_down: Final[int] = 1key_hold: Final[int] = 2scancode: intkeystatekeycodeevent: InputEvent <#evdev.events.InputEvent>โ Reference to anInputEventinstance.
๐ธ class evdev.events.RelEvent(event: InputEvent <#evdev.events.InputEvent>) ๐ธ
A relative axis event (e.g moving the mouse 5 units to the left). Little scoot vibes. ๐ฆ
event: InputEvent <#evdev.events.InputEvent>โ Reference to anInputEventinstance.
๐ฆ class evdev.events.SynEvent(event: InputEvent <#evdev.events.InputEvent>) ๐ฆ
A synchronization event. Used as markers to separate events. Events may be separated in time or in space, such as with the multitouch protocol. It's giving "and scene". ๐ฌ
event: InputEvent <#evdev.events.InputEvent>โ Reference to anInputEventinstance.
๐ธ more evdev.events class lore
class evdev.events.AbsEvent(event: InputEvent) โ an absolute axis event, aka the exact coordinates of a tap on a touchscreen. it's giving "I know precisely where you poked me" energy ๐
event: InputEventโ a reference to anInputEventinstance.
evdev.events.event_factory โ a whole mapping, and it looks exactly like this:
{0: <class 'evdev.events.SynEvent'>, 1: <class 'evdev.events.KeyEvent'>, 2: <class 'evdev.events.RelEvent'>, 3: <class 'evdev.events.AbsEvent'>}
It maps event types to InputEvent sub-classes, and it's the thing evdev.util.categorize() uses. lowkey the matchmaker of the events world ๐ซถ
๐ฆ eventio
class evdev.eventio.EventIO โ the base class for reading and writing input events, periodt. This is the blueprint that both InputDevice and UInput are built on โจ
- On
InputDeviceit used for reading user-generated events (e.g. key presses, mouse movements) and writing feedback events (e.g. leds, beeps). - On
UInputit used for writing user-generated events (e.g. key presses, mouse movements) and reading feedback events (e.g. leds, beeps).
fileno()
Return the file descriptor to the open event device. This makes it possible to pass instances directly to select.select() and asyncore.file_dispatcher. handing out your fd like it's a friendship bracelet ๐
read_loop() -> Iterator[InputEvent]
Enter an endless select.select() loop that yields input events. endless, bestie. it does not stop. it will not stop. ๐
read_one() -> InputEvent | None
Read and return a single input event as an instance of InputEvent.
Return None if there are no pending input events. just a lil "nothing for you rn" ๐
read() -> Iterator[InputEvent]
Read multiple input events from device. Return a generator object that yields InputEvent instances. Raises BlockingIOError if there are no available events at the moment.
bestie that BlockingIOError is not a vibe killer, it just means nothing's ready yet, ok?
need_write()
Decorator that raises EvdevError if there is no write access to the input device. it checks your permission slip before you get to write anything ๐
write_event(event)
Inject an input event into the input subsystem. Events are queued until a synchronization event is received.
Parameters
- event (
InputEvent) โ anInputEventinstance or an object with aneventattribute (KeyEvent,RelEventetc).
Example
>>> ev = InputEvent(1334414993, 274296, ecodes.EV_KEY, ecodes.KEY_A, 1)
>>> ui.write_event(ev)
write(etype: int, code: int, value: int)
Inject an input event into the input subsystem. Events are queued until a synchronization event is received.
Parameters
- etype โ event type (e.g.
EV_KEY). - code โ event code (e.g.
KEY_A). - value โ event value (e.g.
012- depends on event type).
Example
>>> ui.write(e.EV_KEY, e.KEY_A, 1) # key A - down
>>> ui.write(e.EV_KEY, e.KEY_A, 0) # key A - up
syn()
Inject a SYN_REPORT event into the input subsystem. Events queued by write() will be fired. If possible, events will be merged into an 'atomic' event. it's the "ok everyone GO" moment ๐ฅ
close()
closes it. that's it. that's the whole method. ๐
dunder corner ๐ง
__annotate_func__ = None__annotations_cache__ = {}__firstlineno__ = 16__static_attributes__ = ()__weakref__โ list of weak references to the object
๐ eventio_async
class evdev.eventio_async.EventIO โ the async sibling, obviously ๐
async_read_one()
Asyncio coroutine to read and return a single input event as an instance of InputEvent.
async_read()
Asyncio coroutine to read multiple input events from device. Return a generator object that yields InputEvent instances.
async_read_loop() -> ReadIterator
Return an iterator that yields input events. This iterator is compatible with the async for syntax. yes bestie, async for โ she's flexible like that ๐
dunder corner ๐ง
__annotate_func__ = None__annotations_cache__ = {}__firstlineno__ = 56__static_attributes__ = ()
close()
also closes it. no notes. ๐ซถ
๐ device
class evdev.device.AbsInfo(value: int, min: int, max: int, fuzz: int, flat: int, resolution: int)
Absolute axis information. It's a namedtuple with absolute axis information โ corresponds to the input_absinfo struct:
valueโ Latest reported value for the axis.
Type โ int
minโ Specifies minimum value for the axis.
Type โ int
maxโ Specifies maximum value for the axis.
Type โ int
fuzzโ Specifies fuzz value that is used to filter noise from the event stream.
Type โ int
flatโ Values that are within this value will be discarded by joydev interface and reported as0instead.
Type โ int
resolutionโ Specifies resolution for the values reported for the axis. Resolution for main axes (ABS_X,ABS_Y,ABS_Z) is reported in units per millimeter (units/mm), resolution for rotational axes (ABS_RX,ABS_RY,ABS_RZ) is reported in units per radian.
Type โ int
Note: The input core does not clamp reported values to the [minimum, maximum] limits, such task is left to userspace. so likeโฆ you're on your own for clamping, bestie ๐ญ
value: intโ Alias for field number 0min: intโ Alias for field number 1max: intโ Alias for field number 2fuzz: intโ Alias for field number 3flat: intโ Alias for field number 4resolution: intโ Alias for field number 5__annotate_func__()__annotations_cache__ = {'flat': <class 'int'>, 'fuzz': <class 'int'>, 'max': <class 'int'>, 'min': <class 'int'>, 'resolution': <class 'int'>, 'value': <class 'int'>}__classdictcell__ = <cell at 0x756928317b20: dict object>__firstlineno__ = 15__getnewargs__()โ Return self as a plain tuple. Used by copy and pickle.__match_args__ = ('value', 'min', 'max', 'fuzz', 'flat', 'resolution')static __new__(_cls, value: int, min: int, max: int, fuzz: int, flat: int, resolution: int)โ Create new instance of AbsInfo(value, min, max, fuzz, flat, resolution)__orig_bases__ = (<function NamedTuple>,)__replace__(**kwds)โ Return a new AbsInfo object replacing specified fields with new values__static_attributes__ = ()
class evdev.device.KbdInfo(delay: int, repeat: int)
Keyboard repeat rate. the "how fast does this key go brrr" struct โจ๏ธ
delayโ Amount of time that a key must be depressed before it will start to repeat (in milliseconds).
Type โ int
repeatโ Keyboard repeat rate in characters per second.
Type โ int
delay: intโ Alias for field number 0repeat: intโ Alias for field number 1__annotate_func__()__annotations_cache__ = {'delay': <class 'int'>, 'repeat': <class 'int'>}__classdictcell__ = <cell at 0x756927949b70: dict object>__firstlineno__ = 65__getnewargs__()โ Return self as a plain tuple. Used by copy and pickle.__match_args__ = ('delay', 'repeat')static __new__(_cls, delay: int, repeat: int)โ Create new instance of KbdInfo(delay, repeat)__orig_bases__ = (<function NamedTuple>,)__replace__(**kwds)โ Return a new KbdInfo object replacing specified fields with new values__static_attributes__ = ()
class evdev.device.DeviceInfo(bustype: int, vendor: int, product: int, version: int)
the "who even are you" identity card of a device ๐ชช
bustype
Type โ int
vendor
Type โ int
product
Type โ int
version
Type โ int
bustype: intโ Alias for field number 0vendor: intโ Alias for field number 1product: intโ Alias for field number 2version: intโ Alias for field number 3__annotate_func__()__annotations_cache__ = {'bustype': <class 'int'>, 'product': <class 'int'>, 'vendor': <class 'int'>, 'version': <class 'int'>}__classdictcell__ = <cell at 0x756927949e70: dict object>__firstlineno__ = 85__getnewargs__()โ Return self as a plain tuple. Used by copy and pickle.__match_args__ = ('bustype', 'vendor', 'product', 'version')static __new__(_cls, bustype: int, vendor: int, product: int, version: int)โ Create new instance of DeviceInfo(bustype, vendor, product, version)__orig_bases__ = (<function NamedTuple>,)__replace__(**kwds)โ Return a new DeviceInfo object replacing specified fields with new values__static_attributes__ = ()
class evdev.device.InputDevice(dev: _AnyStr | PathLike[_AnyStr])
A linux input device from which input events can be read. the main character, honestly ๐
__init__(dev: _AnyStr | PathLike[_AnyStr])
Parameters
- dev (
str|bytes|PathLike) โ Path to input device path: _AnyStrโ Path to input device.fd: intโ A non-blocking file descriptor to the device file.infoโ ADeviceInfoinstance.name: strโ The name of the event device.phys: strโ The physical topology of the device.uniq: strโ The unique identifier of the device.version: intโ The evdev protocol version.ff_effects_countโ The number of force feedback effects the device can keep in its memory. rumble storage, basically ๐ฎcapabilities(verbose: Literal[False] = False, absinfo: bool = True) -> Dict[int, List[int]]
okay bestie we're still deep in InputDevice land, so buckle up, there's more ๐
โจ capabilities โจ
capabilities(verbose: Literal[True], absinfo: bool = True) ->
Dict[Tuple[str, int], List[Tuple[str, int]]]
Returns the event types your device supports, as a mapping of supported event types โก๏ธ lists of handled event codes. literally a vibe check for what your device can even do ๐ฆ
Example
>>> device.capabilities()
{ 1: [272, 273, 274],
2: [0, 1, 6, 8] }
If verbose is True, event codes and types get resolved to their actual names, no cap:
{ ('EV_KEY', 1): [('BTN_MOUSE', 272),
('BTN_RIGHT', 273),
('BTN_MIDDLE', 273)],
('EV_REL', 2): [('REL_X', 0),
('REL_Y', 1),
('REL_HWHEEL', 6),
('REL_WHEEL', 8)] }
Unknown codes or types get resolved to '?' (yes, the question mark is the shrug emoji of this API ๐ญ).
If absinfo is True, the capabilities list also includes absolute axis info as AbsInfo instances:
{ 3: [ (0, AbsInfo(min=0, max=255, fuzz=0, flat=0)),
(1, AbsInfo(min=0, max=255, fuzz=0, flat=0)) ]}
Combined with verbose, the above becomes:
{ ('EV_ABS', 3): [ (('ABS_X', 0), AbsInfo(min=0, max=255, fuzz=0, flat=0)),
(('ABS_Y', 1), AbsInfo(min=0, max=255, fuzz=0, flat=0)) ]}
๐ธ input_props ๐ธ
input_props(verbose: bool = False)
Get device properties and quirks, the little personality traits of your device ๐
Example
>>> device.input_props()
[0, 5]
If verbose is True, input properties get resolved to their names. Unknown codes get resolved to '?':
[('INPUT_PROP_POINTER', 0), ('INPUT_PROP_POINTING_STICK', 5)]
โจ leds โจ
leds(verbose: bool = False)
Returns the LED keys that are currently set ๐ก
Example
>>> device.leds()
[0, 1, 8, 9]
If verbose is True, event codes get resolved to their names. Unknown codes get resolved to '?':
[('LED_NUML', 0), ('LED_CAPSL', 1), ('LED_MISC', 8), ('LED_MAIL', 9)]
๐
set_led ๐
set_led(led_num: int, value: int) -> None
Set the state of the selected LED. light it up bestie โจ
Example
>>> device.set_led(ecodes.LED_NUML, 1)
๐ซถ __eq__ ๐ซถ
__eq__(other)
Two devices are equal if their info attributes are equal. it's giving "same soul, same info dict" ๐
__fspath__
__fspath__()
close
close() -> None
๐ grab ๐
grab() -> None
Grabs the input device using EVIOCGRAB โ other applications will be unable to receive events until the device is released. Only one process can hold a EVIOCGRAB on a device. main character energy fr fr, it's yours and nobody else's ๐
Warning: Grabbing an already grabbed device will raise an OSError. (the audacity ๐ญ)
๐ ungrab ๐
ungrab() -> None
Release the device if it's already been grabbed (uses EVIOCGRAB). letting it go, growth ๐
Warning: Releasing an already released device will raise an OSError('Invalid argument').
๐ฆ grab_context ๐ฆ
grab_context() -> Iterator[None]
A context manager for the duration of which only the current process will be able to receive events from the device. use it like a with block and let the vibes hold the grab for you โจ
๐ฅ upload_effect ๐ฅ
upload_effect(effect: ff.Effect)
Upload a force feedback effect to a force feedback device. shake it, rattle it ๐
erase_effect
erase_effect(ff_id) -> None
Erase a force effect from a force feedback device. This also stops the effect โ no lingering rumble, periodt ๐
โญ property repeat โญ
Get or set the keyboard repeat rate (in characters per minute) and delay (in milliseconds). typing speed unlocked โจ๏ธ
the dunder lore (they're just chillin' here) ๐
__annotate_func__ = None
__annotations_cache__ = {'fd': 'int', 'name': 'str', 'path':
'_AnyStr', 'phys': 'str', 'uniq': 'str', 'version': 'int'}
__firstlineno__ = 105
__hash__ = None
__orig_bases__ = (<class 'evdev.eventio_async.EventIO'>,
typing.Generic[~_AnyStr])
__parameters__ = (~_AnyStr,)
__static_attributes__ = ('_rawcapabilities', 'fd',
'ff_effects_count', 'info', 'name', 'path', 'phys', 'uniq',
'version')
โจ active_keys โจ
active_keys(verbose: bool = False)
Returns the keys that are currently active โ who's pressing what right now ๐น
Example
>>> device.active_keys()
[1, 42]
If verbose is True, key codes get resolved to their verbose names. Unknown codes get resolved to '?'. For example:
[('KEY_ESC', 1), ('KEY_LEFTSHIFT', 42)]
๐ absinfo ๐
absinfo(axis_num: int)
Return the current AbsInfo for an input device axis.
Parameters
axis_num(int) โEV_ABSkeycode (exampleecodes.ABS_X)
Example
>>> device.absinfo(ecodes.ABS_X)
AbsInfo(value=1501, min=-32768, max=32767, fuzz=0, flat=128, resolution=0)
๐ set_absinfo ๐
set_absinfo(axis_num: int, value=None, min=None, max=None,
fuzz=None, flat=None, resolution=None) -> None
Update AbsInfo values. Only specified values will be overwritten โ everything else stays exactly as it was, lowkey respectful ๐ซถ
Parameters
axis_num(int) โEV_ABSkeycode (exampleecodes.ABS_X)
Example
>>> device.set_absinfo(ecodes.ABS_X, min=-2000, max=2000)
You can also unpack an AbsInfo tuple, which will overwrite all values:
>>> device.set_absinfo(ecodes.ABS_Y, *AbsInfo(0, -2000, 2000, 0, 15, 0))
๐ uinput ๐
๐ class evdev.uinput.UInput ๐
class evdev.uinput.UInput(events: Dict[int, Sequence[int]] | None =
None, name: str = 'py-evdev-uinput', vendor: int = 1, product: int = 1,
version: int = 1, bustype: int = 3, devnode: str = '/dev/uinput', phys:
str = 'py-evdev-uinput', input_props=None, max_effects=96)
A userland input device that can inject input events into the linux input subsystem. you're literally the device now, iconic โจ
๐ from_device ๐
classmethod from_device(*devices: InputDevice | str | bytes | PathLike, filtered_types:
Tuple[int] = (0, 21), **kwargs)
Create a UInput device with the capabilities of one or more input devices. copy their whole vibe, respectfully ๐
Parameters
devices(InputDevice|str) โ Varargs ofInputDeviceinstances or paths to input devices.filtered_types(Tuple[event type codes]) โ Event types to exclude from the capabilities of the uinput device.**kwargsโ Keyword arguments to theUInputconstructor (i.e.name,vendoretc.).
๐ฆ __init__ ๐ฆ
__init__(events: Dict[int, Sequence[int]] | None = None, name:
str = 'py-evdev-uinput', vendor: int = 1, product: int = 1,
version: int = 1, bustype: int = 3, devnode: str = '/dev/uinput',
phys: str = 'py-evdev-uinput', input_props=None, max_effects=96)
Parameters
events(dict) โ Dictionary of event types mapping to lists of event codes. The event types and codes that the uinput device will be able to inject โ defaults to all key codes.nameโ The name of the input device.vendorโ Vendor identifier.productโ Product identifier.versionโ Version identifier.bustypeโ Bustype identifier.physโ Physical path.input_propsโ Input properties and quirks.max_effectsโ Maximum simultaneous force-feedback effects.
Note: If you do not specify any events, the uinput device will be able to inject onlyKEY_*andBTN_*event codes. that's the default, no cap ๐
attributes, the whole fit check ๐
name: strโ Uinput device name.vendor: intโ Device vendor identifier.product: intโ Device product identifier.version: intโ Device version identifier.bustype: intโ Device bustype โ e.g.BUS_USB.phys: strโ Uinput device physical path.devnode: strโ Uinput device node โ e.g./dev/uinput/.fdโ Write-only, non-blocking file descriptor to the uinput device node.device: InputDeviceโ AnInputDeviceinstance for the fake input device.Noneif the device cannot be opened for reading and writing.
โญ capabilities โญ
capabilities(verbose: bool = False, absinfo: bool = True)
See capabilities. (yes babe, same one as above, we love a callback ๐ซถ)
๐ง util ๐ง
โจ evdev.util.list_devices โจ
evdev.util.list_devices(input_device_dir: str | bytes | PathLike =
'/dev/input') -> List[str]
List readable character devices in input_device_dir. a whole roster of your devices ๐
evdev.util.is_device
evdev.util.is_device(fn: str | bytes | PathLike) -> bool
Check if fn is a readable and writable character device. both or nothing bestie ๐
๐ธ evdev.util.categorize ๐ธ
evdev.util.categorize(event: InputEvent) ->
InputEvent | KeyEvent | RelEvent | AbsEvent | SynEvent
Categorize an event according to its type. sorting the whole squad into their little groups ๐
The event_factory dictionary maps event types to sub-classes of InputEvent. If the event cannot be categorized, it is returned unmodified. no forced labels here โจ
๐ evdev.util.resolve_ecodes ๐
evdev.util.resolve_ecodes(ecode_dict, ecode_list, unknown='?')
Resolve event codes and types to their verbose names. translate the mystery numbers into actual words, slay ๐ฅ
Example
>>> resolve_ecodes(ecodes.BTN, [272, 273, 274])
[(['BTN_LEFT', 'BTN_MOUSE'], 272), ('BTN_RIGHT', 273), ('BTN_MIDDLE', 274)]
๐ evdev.util.resolve_ecodes_dict ๐
evdev.util.resolve_ecodes_dict(typecodemap, unknown='?')
Resolve event codes and types to their verbose names.
Parameters
typecodemapโ mapping of event types to lists of event codes.unknownโ symbol to which unknown types or codes will be resolved.
Example
>>> resolve_ecodes_dict({ 1: [272, 273, 274] })
{ ('EV_KEY', 1): [('BTN_MOUSE', 272),
('BTN_RIGHT', 273),
('BTN_MIDDLE', 274)] }
And if your typecodemap is carrying absolute axis info (aka instances of AbsInfo), the glow-up looks like this:
>>> resolve_ecodes_dict({ 3: [(0, AbsInfo(...))] })
{ ('EV_ABS', 3L): [(('ABS_X', 0L), AbsInfo(...))] }
๐ ecodes ๐
okay bestie, this module is literally the dictionary of every integer constant that lives in linux/input.h and linux/input-event-codes.h. It just hands them all to you. ๐
The constants it exposes:
KEY, ABS, REL, SW, MSC, LED, BTN, REP, SND, ID, EV,
BUS, SYN, FF, FF_STATUS, INPUT_PROP
And it doesn't just give you the numbers โ it gives you the reverse and forward mappings between those names and their values too, so you can go either direction. Watch:
>>> evdev.ecodes.KEY_A
30
>>> evdev.ecodes.ecodes['KEY_A']
30
>>> evdev.ecodes.KEY[30]
'KEY_A'
>>> evdev.ecodes.REL[0]
'REL_X'
>>> evdev.ecodes.EV[evdev.ecodes.EV_KEY]
'EV_KEY'
>>> evdev.ecodes.bytype[evdev.ecodes.EV_REL][0]
'REL_X'
๐ซถ heads up queen: values in the reverse mappings can point to one or more event codes, not just a single one. so don't be surprised when you get a tuple back. for example:
>>> evdev.ecodes.FF[80]
('FF_EFFECT_MIN', 'FF_RUMBLE')
>>> evdev.ecodes.FF[81]
'FF_PERIODIC'
evdev.ecodes.keysโ{0: 'KEY_RESERVED', 1: 'KEY_ESC', 2: 'KEY_1', ...}โ the keys here are a combination of all theBTNandKEYcodes. it's giving merged-and-thriving. โจevdev.ecodes.ecodesโ{'KEY_END': 107, 'FF_RUMBLE': 80, 'KEY_KPDOT': 83, 'KEY_CNT': 768, ...}'โ the mapping of names โก๏ธ values.evdev.ecodes.bytypeโ{0: {0: 'SYN_REPORT', 1: 'SYN_CONFIG', 2: 'SYN_MT_REPORT', 3: 'SYN_DROPPED'}, ...}โ the mapping of event types โก๏ธ other value/name mappings. nested dicts, very main character energy. ๐
๐ SCOPE AND STATUS ๐
so what does this thing actually do, fr fr? Python-evdev exposes most of the more common interfaces defined in the evdev subsystem. Reading events and injecting events? well supported, and it's been tested with nearly all event types. we ate. ๐
The basic functionality for reading and uploading force-feedback events is there, but ngl it has not been exercised sufficiently. ๐ญ And a major shortcoming of the uinput wrapper is that it does not support force-feedback devices at all โ see issue #23 <https://github.com/gvalkov/python-evdev/pull/23>. not iconic of it.
Some characters, like : (colon), cannot be easily injected โ see issue #7 <https://github.com/gvalkov/python-evdev/issues/7>. Translating them into UInput events would require knowing the kernel keyboard translation table, which is beyond the scope of python-evdev. So if you need more complete or convenient input injection support, bestie, go look into these projects instead:
python-uinput<https://github.com/tuomasjjrasanen/python-uinput>uinput-mapper<https://github.com/MerlijnWajer/uinput-mapper>pynput<https://github.com/moses-palmer/pynput>pygame<http://www.pygame.org/> (cross-platform)
๐ CHANGELOG ๐
1.9.3 (Feb 05, 2025)
- Fix several memory leaks in
input.c. ๐งน - Raise the minimum supported Python version to 3.9 and the setuptools version to 77.0.
1.9.2 (May 01, 2025)
- Add the
"--reproducible"build option which removes the build date and used headers from the generatedecodes.c. Example usage:
python -m build --config-setting=--build-option='build_ecodes --reproducible' -n
- Use
Genericto set precise type forInputDevice.path. โจ
1.9.1 (Feb 22, 2025)
- Fix fox missing
UI_FFconstants in generatedecodes.py. ๐ฆ - More type annotations.
1.9.0 (Feb 08, 2025)
- Fix for
CPATH/C_INCLUDE_PATHbeing ignored during build. - Slightly faster reading of events in
device.read()anddevice.read_one(). - Fix FreeBSD support. ๐ฆ
- Drop deprecated
InputDevice.fn(useInputDevice.pathinstead). - Improve type hint coverage and add a
py.typedfile to the sdist.
1.8.0 (Jan 25, 2025)
- Binary wheels are now provided by the
evdev-binary<http://pypi.python.org/pypi/evdev-binary> package. The package is compiled onmanylinux_2_28against kernel 4.18. - The
evdev.ecodesmodule is now generated at install time and contains only constants. This allows type checking and introspection of theevdev.ecodesmodule, without having to execute it first. The old module is available asevdev.ecodes_runtime. In case generation of the staticecodes.pyfails, the install process falls back to usingecodes_runtime.pyasecodes.py. - Reverse mappings in
evdev.ecodesthat point to more than one value are now tuples instead of lists. For example:
>>> ecodes.KEY[153]
('KEY_DIRECTION', 'KEY_ROTATE_DISPLAY')
- Raise the minimum supported Python version to 3.8.
- Fix keyboard delay and repeat being swapped (#227).
- Move the
syn()convenience method fromInputDevicetoEventIO(#224).
1.7.1 (May 8, 2024)
- Provide fallback value for
FF_MAX_EFFECTS, which fixes the build on EL 7 (#219). - Add
#ifdefguards aroundUI_GET_SYSNAMEto improve kernel compatibility (#218) . - Wait up to two seconds for uinput devices to appear. (#215)
1.7.0 (Feb 18, 2024)
- Respect the
CPATH/C_INCLUDE_PATHenvironment variables during install. - Add the
uniqaddress to the string representation ofInputDevice. - Improved method for finding the device node corresponding to a uinput device (#206 <https://github.com/gvalkov/python-evdev/pull/206>).
- Repository TLC (reformatted with ruff, fixed linting warnings, moved packaging metadata to
pyproject.tomletc.). ๐ง
1.6.1 (Jan 20, 2023)
- Fix generation of
ecodes.cwhen the path tosys.executablecontains spaces.
1.6.0 (Jul 17, 2022)
- Fix Python 3.11 compatibility (#174 <https://github.com/gvalkov/python-evdev/pull/174>).
1.5.0 (Mar 24, 2022)
- Fix documentation (#163 <https://github.com/gvalkov/python-evdev/pull/163>, #160 <https://github.com/gvalkov/python-evdev/pull/160>).
- Re-enable TTY echo at
evtestexit (#155 <https://github.com/gvalkov/python-evdev/pull/155>). - Fix
ImportError: sys.meta_path is None, Python is likely shutting down(#154 <https://github.com/gvalkov/python-evdev/pull/154>). - Closing the input device file descriptor in
InputDevice.close()now happens in the main thread, instead of in a new thread (reverts #146 <https://github.com/gvalkov/python-evdev/pull/146>). - Fix
util.find_ecodes_by_regexnot working across all supported Python versions (#152 <https://github.com/gvalkov/python-evdev/pull/152>).
1.4.0 (Jan 16, 2021)
- Fix
InputDevice.set_absinfoto allow setting parameters to zero. - Fix off-by-one in
ioctl_EVIOCG_bits, which causes value at the end of the list to not be reported back (#131 <https://github.com/gvalkov/python-evdev/pull/131>). - Fix
set_absinfoto allow setting parameters to zero (#128 <https://github.com/gvalkov/python-evdev/pull/128>). - Fix leak when returning
BlockingIOErrorfrom a read (#143 <https://github.com/gvalkov/python-evdev/pull/143>). - Fix
"There is no current event loop in thread"error for non asyncio code (#146 <https://github.com/gvalkov/python-evdev/pull/146>). - Prevent
InputDevicedestructor from blocking (#145 <https://github.com/gvalkov/python-evdev/pull/145>). - Add missing return codes to
os.strerror()calls and fix force feedback example in docs (#138 <https://github.com/gvalkov/python-evdev/pull/137>). - Add the
util.find_ecodes_by_regex()helper function. ๐
1.3.0 (Jan 12, 2020)
- Fix build on 32bit arches with 64bit
time_t - Add functionality to query device properties. See
InputDevice.input_propsand theinput_propsargument toUinput. KeyEventreceived anallow_unknownconstructor argument, which determines what will happen when an event code cannot be mapped to a keycode. The default and behavior so far has been to raiseKeyError. If set toTrue, the keycode will be set to the event code formatted as a hex number.- Add
InputDevice.set_absinfo()andInputDevice.absinfo(). - Instruct the asyncio event loop to stop monitoring the fd of the input device when the device is closed.
1.2.0 (Apr 7, 2019)
- Add
UInputsupport for theresolutionparameter inAbsInfo. This brings support for the new method of uinput device setup, which was introduced in Linux 4.5 <https://github.com/torvalds/linux/commit/052876f8e5aec887d22c4d06e54aa5531ffcec75> (thanks to @LinusCDE <https://github.com/gvalkov/python-evdev/pulls/LinusCDE>). - Vendor and product identifiers can be greater or equal to
0x8000(thanks @ivaradi <https://github.com/gvalkov/python-evdev/pull/104>).
1.1.2 (Sep 1, 2018)
- Fix installation on kernels
<= 4.4. - Fix uinput creation ignoring absinfo settings.
1.1.0 (Aug 27, 2018)
- Add support for handling force-feedback effect uploads (many thanks to @ndreys <https://github.com/ndreys>). ๐ฅ
- Fix typo preventing ff effects that need left coefficients from working.
1.0.0 (Jun 02, 2018)
- Prevent
Uinputdevice creation raisingObjects/longobject.c:415: bad argument to internal functionwhen a non-completeAbsInfostructure is passed. All missingAbsInfofields are set to0. - Fix
Uinputdevice creation raisingKeyErrorwhen a capability filtered by default is not present. - The
InputDevice.fnattribute was deprecated in favor ofInputDevice.path. Using the former will show aDeprecationWarning, but would otherwise continue working as before. - Fix
InputDevicecomparison raisingAttributeErrordue to a non-existantpathattribute. - Fix asyncio support in Python 3.5+.
- Uploading FF effect now works both on Python 2.7 and Python 3+.
- Remove the
asyncoreexample from the tutorial.
0.8.1 (Mar 24, 2018)
- Fix Python 2 compatibility issue in with
Uinput.from_device. - Fix minor
evdev.evtestformatting issue.
0.8.0 (Mar 22, 2018)
- Fix
InputDevicecomparison on Python 2. - The device path is now considered when comparing two devices.
- Fix
UInput.from_devicenot correctly merging the capabilities of selected devices. - The list of excluded event types in
UInput.from_deviceis now configurable. For example:
UInput.from_device(dev, filtered_types=(EV_SYN, EV_FF))
In addition, ecodes.EV_FF is now excluded by default.
- Add a context manager for grabbing access to a device โ
InputDevice.grab_context. For example:
with dev.grab_context():
pass
- Add the
InputDevice.uniqattribute, which contains the unique identifier of the device. As withphys, this attribute may be empty (i.e.''). ๐
0.7.0 (Jun 16, 2017)
InputDevicenow accepts objects that support the path protocol. For example:
pth = pathlib.Path('/dev/input/event0')
dev = evdev.InputDevice(pth)
- Support path protocol in
InputDevice. This means thatInputDeviceinstances can be passed to callers that expect anos.PathLikeobject. slay โจ - Exceptions raised during
InputDevice.async_read()(and similar) are now handled properly (i.e. an exception is set on the returned future instead of leaking that exception into the event loop) (fixes issue #67)https://github.com/gvalkov/python-evdev/issues/67. no more leaked exceptions bestie ๐
0.6.4 (Oct 07, 2016) ๐
- Excluded
ecodes.cfrom source distribution (fixes issue #63)https://github.com/gvalkov/python-evdev/issues/63. bye bye extra files ๐
0.6.3 (Oct 06, 2016) ๐ฆ
- Added the
UInput.from_deviceclass method, which allows a uinput device to be created with the capabilities of one or more existing input devices:
ui = UInput.from_device('/dev/input1', '/dev/input2', **constructor_kwargs)
- Added the
build_ecodesdistutils command, which generates theecodes.cextension module. The new way of overwriting the evdev header locations is:
python setup.py build \
build_ecodes --evdev-headers path/input.h:path/input-event-codes.h \
build_ext --include-dirs path/ \
install
The build* and install commands no longer have to be part of the same command-line (i.e. running install will reuse the outputs of the last build). lowkey convenient fr fr ๐
0.6.1 (Jun 04, 2016) ๐ธ
- Disabled tty echoing while
evtestis running. no more weird characters bestie ๐ญ - Allowed
evtestto listen to more than one device. the more the merrier ๐ - The
setup.pyscript now allows the location of the input header files to be overwritten. For example:
python setup.py build_ext \
--evdev-headers path/input.h:path/input-event-codes.h \
--include-dirs path/ \
install
0.6.0 (Feb 14, 2016) ๐
- Asyncio and async/await support (many thanks to @paulo-raca)
https://github.com/paulo-raca. it's giving modern Python โจ - Added the ability to set the
physproperty of uinput devices (thanks @paulo-raca)https://github.com/paulo-raca. - Added a generic
InputDevice.set()method (thanks @paulo-raca)https://github.com/paulo-raca. - Distribute the
evtestscript along with evdev. - Fixed issue with generating
ecodes.cin recent kernels (>= 4.4.0). - Fixed absinfo item indexes in
UInput.uinput_create()(thanks @forsenonlhaimaisentito)https://github.com/forsenonlhaimaisentito. - More robust comparison of
InputDeviceobjects (thanks @isia)https://github.com/isia.
0.5.0 (Jun 16, 2015) ๐
- Write access to the input device is no longer mandatory. Evdev will first try to open the device for reading and writing and fallback to read-only. Methods that require write access (e.g.
set_led()) will raiseEvdevErrorif the device is open only for reading. so if you're read-only, don't try to write, okay? ๐
0.4.7 (Oct 07, 2014) ๐
- Fallback to distutils if setuptools is not available.
0.4.6 (Oct 07, 2014) ๐ง
- Reworked documentation and docstrings once more.
- Fixed install on Python 3.4 (works around issue21121)
http://bugs.python.org/issue21121. - Fixed
ioctl()requested buffer size (thanks Jakub Wojciech Klama).
0.4.5 (Jul 06, 2014) ๐
- Added method for returning a list of the currently active keys -
InputDevice.active_keys()(thanks @spasche)https://github.com/spasche. - Fixed a potential buffer overflow in
ioctl_capabilities()(thanks @spasche)https://github.com/spasche.
0.4.4 (Jun 04, 2014) โญ
- Calling
InputDevice.read_one()should always returnNonewhen there is nothing to be read, even in case of aEAGAINerrno (thanks JPP).
0.4.3 (Dec 19, 2013) ๐
- Silenced
OSErrorin destructor (thanks @polyphemus)https://github.com/polyphemus. - Made
InputDevice.close()work in cases in whichstdin(fd 0) has been closed (thanks @polyphemus)https://github.com/polyphemus.
0.4.2 (Dec 13, 2013) ๐ฆ
- Reworked documentation and docstrings.
- Call
InputDevice.close()fromInputDevice.__del__().
0.4.1 (Jul 24, 2013) ๐ธ
- Fixed reference counting in
InputDevice.device_read(),InputDevice.device_read_many()andioctl_capabilities().
0.4.0 (Jul 01, 2013) ๐
- Added
FF_*andFF_STATUScodes toecodes()(thanks @bgilbert)https://github.com/bgilbert. - Reverse event code mappings (
ecodes.{KEY,FF,REL,ABS}and etc.) will now map to a list of codes, whenever a value corresponds to multiple codes:
>>> ecodes.KEY[152]
... ['KEY_COFFEE', 'KEY_SCREENLOCK']
>>> ecodes.KEY[30]
... 'KEY_A'
- Set the state of a LED through
InputDevice.set_led()(thanks @accek)https://github.com/accek. - Open
InputDevice.fdinO_RDWRmode from now on. - Fixed segfault in
InputDevice.device_read_many()(thanks @bgilbert)https://github.com/bgilbert.
0.3.3 (May 29, 2013) ๐
- Raise
IOErrorfromInputDevice.device_read()andInputDevice.device_read_many()whenInputDevice.read()fails. - Several stability and style changes (thank you debian code reviewers).
0.3.2 (Apr 05, 2013) ๐
- Fixed vendor id and product id order in
DeviceInfo()(thanks @kived)https://github.com/kived.
0.3.1 (Nov 23, 2012) ๐ง
InputDevice.read()will return an empty tuple if the device has nothing to offer (instead of segfaulting).- Exclude unnecessary package data in sdist and bdist.
0.3.0 (Nov 06, 2012) ๐
- Added ability to set/get auto-repeat settings with
EVIOC{SG}REP. - Added
InputDevice.version()- the value ofEVIOCGVERSION. - Added
InputDevice.read_loop(). - Added
InputDevice.grab()andInputDevice.ungrab()- exposesEVIOCGRAB. - Added
InputDevice.leds()- exposesEVIOCGLED. - Replaced
DeviceInfoclass with a namedtuple. - Prevented
InputDevice.read_one()from skipping events. - Renamed
AbsDatatoAbsInfo(as instruct input_absinfo).
0.2.0 (Aug 22, 2012) โญ
- Added the ability to set arbitrary device capabilities on uinput devices (defaults to all
EV_KEYecodes). - Added
UInput.devicewhich is an openInputDeviceto the input device that uinput 'spawns'. - Added
UInput.capabilities()which is just a shortcut toUInput.device.capabilities(). - Renamed
UInput.write()toUInput.write_event(). - Added a simpler
UInput.write(type, code, value)()method. - Made all
UInput()constructor arguments optional (default device name is nowpy-evdev-uinput). - Added the ability to set
absmin,absmax,absfuzzandabsflatwhen specifying the uinput device's capabilities. - Removed the
nophysargument - if a device fails theEVIOCGPHYSioctl,physwill equal the empty string. - Made
InputDevice.capabilities()perform aEVIOCGABSioctl for devices that supportEV_ABSand return that info wrapped in anAbsDatanamedtuple. - Split
ioctl_devinfointoioctl_devinfoandioctl_capabilities. - Split
UInput.uinput_open()toUInput.uinput_open()andUInput.uinput_create() - Added more uinput usage examples and documentation.
- Rewrote uinput tests.
- Removed
mouserelandmouseabsfromUInput. - Tied the sphinx version and release to the distutils version.
- Set 'methods-before-attributes' sorting in the docs.
- Removed
KEY_CNTandKEY_MAXfromecodes.keys().
0.1.1 (May 18, 2012) ๐
- Added
events.keys, which is a combination of allBTN_andKEY_event codes. ecodes.cwas not generated when installing through pip.
0.1.0 (May 17, 2012) ๐
- Initial Release
- This package is released under the terms of the Revised BSD License
https://raw.github.com/gvalkov/python-evdev/master/LICENSE.
๐ Author ๐
Georgi Valkov
๐ Copyright ๐
2012-2025, Georgi Valkov and contributors
bestie, this was PYTHON-EVDEV(7) version 1.9.3 from Mar 20, 2026. go forth and read those input events like the main character you are. periodt ๐
โจ
๐ฆ where this page comes from
- ubuntu resolute: python-evdev-doc 1.9.3-1build1 ยท BSD-3
- ubuntu stonking: python-evdev-doc 1.9.3-1build1 ยท BSD-3
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms