evdev 1.9.0__tar.gz → 1.9.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {evdev-1.9.0/src/evdev.egg-info → evdev-1.9.1}/PKG-INFO +2 -2
- {evdev-1.9.0 → evdev-1.9.1}/pyproject.toml +2 -2
- evdev-1.9.1/src/evdev/__init__.py +39 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/device.py +19 -13
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/ecodes_runtime.py +1 -1
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/eventio_async.py +47 -40
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/genecodes_py.py +2 -1
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/util.py +2 -2
- {evdev-1.9.0 → evdev-1.9.1/src/evdev.egg-info}/PKG-INFO +2 -2
- {evdev-1.9.0 → evdev-1.9.1}/tests/test_ecodes.py +13 -3
- evdev-1.9.0/src/evdev/__init__.py +0 -9
- {evdev-1.9.0 → evdev-1.9.1}/LICENSE +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/MANIFEST.in +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/README.md +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/setup.cfg +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/setup.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/ecodes.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/eventio.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/events.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/evtest.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/ff.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/genecodes_c.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/input.c +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/py.typed +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/uinput.c +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev/uinput.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev.egg-info/SOURCES.txt +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev.egg-info/dependency_links.txt +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/src/evdev.egg-info/top_level.txt +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/tests/test_events.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/tests/test_uinput.py +0 -0
- {evdev-1.9.0 → evdev-1.9.1}/tests/test_util.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "evdev"
|
|
7
|
-
version = "1.9.
|
|
7
|
+
version = "1.9.1"
|
|
8
8
|
description = "Bindings to the Linux input handling subsystem"
|
|
9
9
|
keywords = ["evdev", "input", "uinput"]
|
|
10
10
|
readme = "README.md"
|
|
@@ -36,7 +36,7 @@ line-length = 120
|
|
|
36
36
|
ignore = ["E265", "E241", "F403", "F401", "E401", "E731"]
|
|
37
37
|
|
|
38
38
|
[tool.bumpversion]
|
|
39
|
-
current_version = "1.9.
|
|
39
|
+
current_version = "1.9.1"
|
|
40
40
|
commit = true
|
|
41
41
|
tag = true
|
|
42
42
|
allow_dirty = true
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# --------------------------------------------------------------------------
|
|
2
|
+
# Gather everything into a single, convenient namespace.
|
|
3
|
+
# --------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
# The superfluous "import name as name" syntax is here to satisfy mypy's attrs-defined rule.
|
|
6
|
+
# Alternatively all exported objects can be listed in __all__.
|
|
7
|
+
|
|
8
|
+
from . import (
|
|
9
|
+
ecodes as ecodes,
|
|
10
|
+
ff as ff,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from .device import (
|
|
14
|
+
AbsInfo as AbsInfo,
|
|
15
|
+
DeviceInfo as DeviceInfo,
|
|
16
|
+
EvdevError as EvdevError,
|
|
17
|
+
InputDevice as InputDevice,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from .events import (
|
|
21
|
+
AbsEvent as AbsEvent,
|
|
22
|
+
InputEvent as InputEvent,
|
|
23
|
+
KeyEvent as KeyEvent,
|
|
24
|
+
RelEvent as RelEvent,
|
|
25
|
+
SynEvent as SynEvent,
|
|
26
|
+
event_factory as event_factory,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
from .uinput import (
|
|
30
|
+
UInput as UInput,
|
|
31
|
+
UInputError as UInputError,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
from .util import (
|
|
35
|
+
categorize as categorize,
|
|
36
|
+
list_devices as list_devices,
|
|
37
|
+
resolve_ecodes as resolve_ecodes,
|
|
38
|
+
resolve_ecodes_dict as resolve_ecodes_dict,
|
|
39
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import contextlib
|
|
2
2
|
import os
|
|
3
|
-
from typing import NamedTuple, Tuple, Union
|
|
3
|
+
from typing import Dict, Iterator, List, Literal, NamedTuple, Tuple, Union, overload
|
|
4
4
|
|
|
5
5
|
from . import _input, ecodes, util
|
|
6
6
|
|
|
@@ -95,7 +95,7 @@ class DeviceInfo(NamedTuple):
|
|
|
95
95
|
product: int
|
|
96
96
|
version: int
|
|
97
97
|
|
|
98
|
-
def __str__(self):
|
|
98
|
+
def __str__(self) -> str:
|
|
99
99
|
msg = "bus: {:04x}, vendor {:04x}, product {:04x}, version {:04x}"
|
|
100
100
|
return msg.format(*self) # pylint: disable=not-an-iterable
|
|
101
101
|
|
|
@@ -151,7 +151,7 @@ class InputDevice(EventIO):
|
|
|
151
151
|
#: The number of force feedback effects the device can keep in its memory.
|
|
152
152
|
self.ff_effects_count = _input.ioctl_EVIOCGEFFECTS(self.fd)
|
|
153
153
|
|
|
154
|
-
def __del__(self):
|
|
154
|
+
def __del__(self) -> None:
|
|
155
155
|
if hasattr(self, "fd") and self.fd is not None:
|
|
156
156
|
try:
|
|
157
157
|
self.close()
|
|
@@ -176,7 +176,13 @@ class InputDevice(EventIO):
|
|
|
176
176
|
|
|
177
177
|
return res
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
@overload
|
|
180
|
+
def capabilities(self, verbose: Literal[False] = ..., absinfo: bool = ...) -> Dict[int, List[int]]:
|
|
181
|
+
...
|
|
182
|
+
@overload
|
|
183
|
+
def capabilities(self, verbose: Literal[True], absinfo: bool = ...) -> Dict[Tuple[str, int], List[Tuple[str, int]]]:
|
|
184
|
+
...
|
|
185
|
+
def capabilities(self, verbose: bool = False, absinfo: bool = True) -> Union[Dict[int, List[int]], Dict[Tuple[str, int], List[Tuple[str, int]]]]:
|
|
180
186
|
"""
|
|
181
187
|
Return the event types that this device supports as a mapping of
|
|
182
188
|
supported event types to lists of handled event codes.
|
|
@@ -263,7 +269,7 @@ class InputDevice(EventIO):
|
|
|
263
269
|
|
|
264
270
|
return leds
|
|
265
271
|
|
|
266
|
-
def set_led(self, led_num: int, value: int):
|
|
272
|
+
def set_led(self, led_num: int, value: int) -> None:
|
|
267
273
|
"""
|
|
268
274
|
Set the state of the selected LED.
|
|
269
275
|
|
|
@@ -279,18 +285,18 @@ class InputDevice(EventIO):
|
|
|
279
285
|
"""
|
|
280
286
|
return isinstance(other, self.__class__) and self.info == other.info and self.path == other.path
|
|
281
287
|
|
|
282
|
-
def __str__(self):
|
|
288
|
+
def __str__(self) -> str:
|
|
283
289
|
msg = 'device {}, name "{}", phys "{}", uniq "{}"'
|
|
284
290
|
return msg.format(self.path, self.name, self.phys, self.uniq or "")
|
|
285
291
|
|
|
286
|
-
def __repr__(self):
|
|
292
|
+
def __repr__(self) -> str:
|
|
287
293
|
msg = (self.__class__.__name__, self.path)
|
|
288
294
|
return "{}({!r})".format(*msg)
|
|
289
295
|
|
|
290
296
|
def __fspath__(self):
|
|
291
297
|
return self.path
|
|
292
298
|
|
|
293
|
-
def close(self):
|
|
299
|
+
def close(self) -> None:
|
|
294
300
|
if self.fd > -1:
|
|
295
301
|
try:
|
|
296
302
|
super().close()
|
|
@@ -298,7 +304,7 @@ class InputDevice(EventIO):
|
|
|
298
304
|
finally:
|
|
299
305
|
self.fd = -1
|
|
300
306
|
|
|
301
|
-
def grab(self):
|
|
307
|
+
def grab(self) -> None:
|
|
302
308
|
"""
|
|
303
309
|
Grab input device using ``EVIOCGRAB`` - other applications will
|
|
304
310
|
be unable to receive events until the device is released. Only
|
|
@@ -311,7 +317,7 @@ class InputDevice(EventIO):
|
|
|
311
317
|
|
|
312
318
|
_input.ioctl_EVIOCGRAB(self.fd, 1)
|
|
313
319
|
|
|
314
|
-
def ungrab(self):
|
|
320
|
+
def ungrab(self) -> None:
|
|
315
321
|
"""
|
|
316
322
|
Release device if it has been already grabbed (uses `EVIOCGRAB`).
|
|
317
323
|
|
|
@@ -324,7 +330,7 @@ class InputDevice(EventIO):
|
|
|
324
330
|
_input.ioctl_EVIOCGRAB(self.fd, 0)
|
|
325
331
|
|
|
326
332
|
@contextlib.contextmanager
|
|
327
|
-
def grab_context(self):
|
|
333
|
+
def grab_context(self) -> Iterator[None]:
|
|
328
334
|
"""
|
|
329
335
|
A context manager for the duration of which only the current
|
|
330
336
|
process will be able to receive events from the device.
|
|
@@ -342,7 +348,7 @@ class InputDevice(EventIO):
|
|
|
342
348
|
ff_id = _input.upload_effect(self.fd, data)
|
|
343
349
|
return ff_id
|
|
344
350
|
|
|
345
|
-
def erase_effect(self, ff_id):
|
|
351
|
+
def erase_effect(self, ff_id) -> None:
|
|
346
352
|
"""
|
|
347
353
|
Erase a force effect from a force feedback device. This also
|
|
348
354
|
stops the effect.
|
|
@@ -402,7 +408,7 @@ class InputDevice(EventIO):
|
|
|
402
408
|
"""
|
|
403
409
|
return AbsInfo(*_input.ioctl_EVIOCGABS(self.fd, axis_num))
|
|
404
410
|
|
|
405
|
-
def set_absinfo(self, axis_num: int, value=None, min=None, max=None, fuzz=None, flat=None, resolution=None):
|
|
411
|
+
def set_absinfo(self, axis_num: int, value=None, min=None, max=None, fuzz=None, flat=None, resolution=None) -> None:
|
|
406
412
|
"""
|
|
407
413
|
Update :class:`AbsInfo` values. Only specified values will be overwritten.
|
|
408
414
|
|
|
@@ -46,7 +46,7 @@ from . import _ecodes
|
|
|
46
46
|
#: Mapping of names to values.
|
|
47
47
|
ecodes = {}
|
|
48
48
|
|
|
49
|
-
prefixes = "KEY ABS REL SW MSC LED BTN REP SND ID EV BUS SYN FF_STATUS FF INPUT_PROP".split()
|
|
49
|
+
prefixes = "KEY ABS REL SW MSC LED BTN REP SND ID EV BUS SYN FF_STATUS FF INPUT_PROP UI_FF".split()
|
|
50
50
|
prev_prefix = ""
|
|
51
51
|
g = globals()
|
|
52
52
|
|
|
@@ -1,11 +1,57 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import select
|
|
3
|
+
import sys
|
|
3
4
|
|
|
4
5
|
from . import eventio
|
|
6
|
+
from .events import InputEvent
|
|
5
7
|
|
|
6
8
|
# needed for compatibility
|
|
7
9
|
from .eventio import EvdevError
|
|
8
10
|
|
|
11
|
+
if sys.version_info >= (3, 11):
|
|
12
|
+
from typing import Self
|
|
13
|
+
else:
|
|
14
|
+
from typing import Any as Self
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ReadIterator:
|
|
18
|
+
def __init__(self, device):
|
|
19
|
+
self.current_batch = iter(())
|
|
20
|
+
self.device = device
|
|
21
|
+
|
|
22
|
+
# Standard iterator protocol.
|
|
23
|
+
def __iter__(self) -> Self:
|
|
24
|
+
return self
|
|
25
|
+
|
|
26
|
+
def __next__(self) -> InputEvent:
|
|
27
|
+
try:
|
|
28
|
+
# Read from the previous batch of events.
|
|
29
|
+
return next(self.current_batch)
|
|
30
|
+
except StopIteration:
|
|
31
|
+
r, w, x = select.select([self.device.fd], [], [])
|
|
32
|
+
self.current_batch = self.device.read()
|
|
33
|
+
return next(self.current_batch)
|
|
34
|
+
|
|
35
|
+
def __aiter__(self) -> Self:
|
|
36
|
+
return self
|
|
37
|
+
|
|
38
|
+
def __anext__(self) -> "asyncio.Future[InputEvent]":
|
|
39
|
+
future = asyncio.Future()
|
|
40
|
+
try:
|
|
41
|
+
# Read from the previous batch of events.
|
|
42
|
+
future.set_result(next(self.current_batch))
|
|
43
|
+
except StopIteration:
|
|
44
|
+
|
|
45
|
+
def next_batch_ready(batch):
|
|
46
|
+
try:
|
|
47
|
+
self.current_batch = batch.result()
|
|
48
|
+
future.set_result(next(self.current_batch))
|
|
49
|
+
except Exception as e:
|
|
50
|
+
future.set_exception(e)
|
|
51
|
+
|
|
52
|
+
self.device.async_read().add_done_callback(next_batch_ready)
|
|
53
|
+
return future
|
|
54
|
+
|
|
9
55
|
|
|
10
56
|
class EventIO(eventio.EventIO):
|
|
11
57
|
def _do_when_readable(self, callback):
|
|
@@ -42,7 +88,7 @@ class EventIO(eventio.EventIO):
|
|
|
42
88
|
self._do_when_readable(lambda: self._set_result(future, self.read))
|
|
43
89
|
return future
|
|
44
90
|
|
|
45
|
-
def async_read_loop(self):
|
|
91
|
+
def async_read_loop(self) -> ReadIterator:
|
|
46
92
|
"""
|
|
47
93
|
Return an iterator that yields input events. This iterator is
|
|
48
94
|
compatible with the ``async for`` syntax.
|
|
@@ -58,42 +104,3 @@ class EventIO(eventio.EventIO):
|
|
|
58
104
|
# no event loop present, so there is nothing to
|
|
59
105
|
# remove the reader from. Ignore
|
|
60
106
|
pass
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class ReadIterator:
|
|
64
|
-
def __init__(self, device):
|
|
65
|
-
self.current_batch = iter(())
|
|
66
|
-
self.device = device
|
|
67
|
-
|
|
68
|
-
# Standard iterator protocol.
|
|
69
|
-
def __iter__(self):
|
|
70
|
-
return self
|
|
71
|
-
|
|
72
|
-
def __next__(self):
|
|
73
|
-
try:
|
|
74
|
-
# Read from the previous batch of events.
|
|
75
|
-
return next(self.current_batch)
|
|
76
|
-
except StopIteration:
|
|
77
|
-
r, w, x = select.select([self.device.fd], [], [])
|
|
78
|
-
self.current_batch = self.device.read()
|
|
79
|
-
return next(self.current_batch)
|
|
80
|
-
|
|
81
|
-
def __aiter__(self):
|
|
82
|
-
return self
|
|
83
|
-
|
|
84
|
-
def __anext__(self):
|
|
85
|
-
future = asyncio.Future()
|
|
86
|
-
try:
|
|
87
|
-
# Read from the previous batch of events.
|
|
88
|
-
future.set_result(next(self.current_batch))
|
|
89
|
-
except StopIteration:
|
|
90
|
-
|
|
91
|
-
def next_batch_ready(batch):
|
|
92
|
-
try:
|
|
93
|
-
self.current_batch = batch.result()
|
|
94
|
-
future.set_result(next(self.current_batch))
|
|
95
|
-
except Exception as e:
|
|
96
|
-
future.set_exception(e)
|
|
97
|
-
|
|
98
|
-
self.device.async_read().add_done_callback(next_batch_ready)
|
|
99
|
-
return future
|
|
@@ -40,6 +40,7 @@ entries = [
|
|
|
40
40
|
("BUS", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
41
41
|
("SYN", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
42
42
|
("FF", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
43
|
+
("UI_FF", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
43
44
|
("FF_STATUS", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
44
45
|
("INPUT_PROP", "Dict[int, Union[str, Tuple[str]]]", None)
|
|
45
46
|
]
|
|
@@ -50,4 +51,4 @@ for key, annotation, doc in entries:
|
|
|
50
51
|
|
|
51
52
|
print(f"{key}: {annotation} = ", end="")
|
|
52
53
|
pprint(getattr(ecodes, key))
|
|
53
|
-
print()
|
|
54
|
+
print()
|
|
@@ -6,7 +6,7 @@ import stat
|
|
|
6
6
|
from typing import Union, List
|
|
7
7
|
|
|
8
8
|
from . import ecodes
|
|
9
|
-
from .events import event_factory
|
|
9
|
+
from .events import InputEvent, event_factory
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def list_devices(input_device_dir: Union[str, bytes, os.PathLike] = "/dev/input") -> List[str]:
|
|
@@ -32,7 +32,7 @@ def is_device(fn: Union[str, bytes, os.PathLike]) -> bool:
|
|
|
32
32
|
return True
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def categorize(event):
|
|
35
|
+
def categorize(event: InputEvent) -> InputEvent:
|
|
36
36
|
"""
|
|
37
37
|
Categorize an event according to its type.
|
|
38
38
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
1
|
from evdev import ecodes
|
|
2
|
+
from evdev import ecodes_runtime
|
|
4
3
|
|
|
5
4
|
|
|
6
|
-
prefixes = "KEY ABS REL SW MSC LED BTN REP SND ID EV BUS SYN FF_STATUS FF"
|
|
5
|
+
prefixes = "KEY ABS REL SW MSC LED BTN REP SND ID EV BUS SYN FF_STATUS FF UI_FF"
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
def to_tuples(val):
|
|
@@ -29,3 +28,14 @@ def test_overlap():
|
|
|
29
28
|
vals_ff = set(to_tuples(ecodes.FF.values()))
|
|
30
29
|
vals_ff_status = set(to_tuples(ecodes.FF_STATUS.values()))
|
|
31
30
|
assert bool(vals_ff & vals_ff_status) is False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_generated():
|
|
34
|
+
e_run = vars(ecodes_runtime)
|
|
35
|
+
e_gen = vars(ecodes)
|
|
36
|
+
|
|
37
|
+
def keys(v):
|
|
38
|
+
res = {k for k in v.keys() if not k.startswith("_") and not k[1].islower()}
|
|
39
|
+
return res
|
|
40
|
+
|
|
41
|
+
assert keys(e_run) == keys(e_gen)
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# --------------------------------------------------------------------------
|
|
2
|
-
# Gather everything into a single, convenient namespace.
|
|
3
|
-
# --------------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
from . import ecodes, ff
|
|
6
|
-
from .device import AbsInfo, DeviceInfo, EvdevError, InputDevice
|
|
7
|
-
from .events import AbsEvent, InputEvent, KeyEvent, RelEvent, SynEvent, event_factory
|
|
8
|
-
from .uinput import UInput, UInputError
|
|
9
|
-
from .util import categorize, list_devices, resolve_ecodes, resolve_ecodes_dict
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|