evdev 1.8.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.8.0 → evdev-1.9.1}/MANIFEST.in +2 -2
- {evdev-1.8.0/evdev.egg-info → evdev-1.9.1}/PKG-INFO +1 -1
- {evdev-1.8.0 → evdev-1.9.1}/pyproject.toml +2 -5
- {evdev-1.8.0 → evdev-1.9.1}/setup.py +13 -8
- evdev-1.9.1/src/evdev/__init__.py +39 -0
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/device.py +55 -52
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/ecodes.py +3 -3
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/ecodes_runtime.py +1 -1
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/eventio.py +6 -5
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/eventio_async.py +47 -40
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/events.py +19 -18
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/evtest.py +5 -4
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/genecodes_c.py +5 -1
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/genecodes_py.py +2 -1
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/input.c +22 -51
- evdev-1.9.1/src/evdev/py.typed +0 -0
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/uinput.c +2 -23
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/uinput.py +36 -29
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/util.py +6 -7
- {evdev-1.8.0 → evdev-1.9.1/src/evdev.egg-info}/PKG-INFO +1 -1
- evdev-1.9.1/src/evdev.egg-info/SOURCES.txt +29 -0
- {evdev-1.8.0 → evdev-1.9.1}/tests/test_ecodes.py +13 -3
- {evdev-1.8.0 → evdev-1.9.1}/tests/test_util.py +1 -1
- evdev-1.8.0/evdev/__init__.py +0 -9
- evdev-1.8.0/evdev.egg-info/SOURCES.txt +0 -28
- {evdev-1.8.0 → evdev-1.9.1}/LICENSE +0 -0
- {evdev-1.8.0 → evdev-1.9.1}/README.md +0 -0
- {evdev-1.8.0 → evdev-1.9.1}/setup.cfg +0 -0
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev/ff.py +0 -0
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev.egg-info/dependency_links.txt +0 -0
- {evdev-1.8.0 → evdev-1.9.1/src}/evdev.egg-info/top_level.txt +0 -0
- {evdev-1.8.0 → evdev-1.9.1}/tests/test_events.py +0 -0
- {evdev-1.8.0 → evdev-1.9.1}/tests/test_uinput.py +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# The _ecodes extension module source file needs to be generated against the
|
|
2
2
|
# evdev headers of the running kernel. Refer to the 'build_ecodes' distutils
|
|
3
3
|
# command in setup.py.
|
|
4
|
-
exclude evdev/ecodes.c
|
|
5
|
-
include evdev/ecodes.py
|
|
4
|
+
exclude src/evdev/ecodes.c
|
|
5
|
+
include src/evdev/ecodes.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "evdev"
|
|
7
|
-
version = "1.
|
|
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"
|
|
@@ -29,9 +29,6 @@ classifiers = [
|
|
|
29
29
|
[project.urls]
|
|
30
30
|
"Homepage" = "https://github.com/gvalkov/python-evdev"
|
|
31
31
|
|
|
32
|
-
[tool.setuptools]
|
|
33
|
-
packages = ["evdev"]
|
|
34
|
-
|
|
35
32
|
[tool.ruff]
|
|
36
33
|
line-length = 120
|
|
37
34
|
|
|
@@ -39,7 +36,7 @@ line-length = 120
|
|
|
39
36
|
ignore = ["E265", "E241", "F403", "F401", "E401", "E731"]
|
|
40
37
|
|
|
41
38
|
[tool.bumpversion]
|
|
42
|
-
current_version = "1.
|
|
39
|
+
current_version = "1.9.1"
|
|
43
40
|
commit = true
|
|
44
41
|
tag = true
|
|
45
42
|
allow_dirty = true
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import sys
|
|
3
3
|
import shutil
|
|
4
4
|
import textwrap
|
|
5
|
+
import platform
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from subprocess import run
|
|
7
8
|
|
|
@@ -10,7 +11,7 @@ from setuptools.command import build_ext as _build_ext
|
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
curdir = Path(__file__).resolve().parent
|
|
13
|
-
ecodes_c_path = curdir / "evdev/ecodes.c"
|
|
14
|
+
ecodes_c_path = curdir / "src/evdev/ecodes.c"
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def create_ecodes(headers=None):
|
|
@@ -25,7 +26,11 @@ def create_ecodes(headers=None):
|
|
|
25
26
|
include_paths.update(c_inc_path.split(":"))
|
|
26
27
|
|
|
27
28
|
include_paths.add("/usr/include")
|
|
28
|
-
|
|
29
|
+
if platform.system().lower() == "freebsd":
|
|
30
|
+
files = ["dev/evdev/input.h", "dev/evdev/input-event-codes.h", "dev/evdev/uinput.h"]
|
|
31
|
+
else:
|
|
32
|
+
files = ["linux/input.h", "linux/input-event-codes.h", "linux/uinput.h"]
|
|
33
|
+
|
|
29
34
|
headers = [os.path.join(path, file) for path in include_paths for file in files]
|
|
30
35
|
|
|
31
36
|
headers = [header for header in headers if os.path.isfile(header)]
|
|
@@ -60,7 +65,7 @@ def create_ecodes(headers=None):
|
|
|
60
65
|
|
|
61
66
|
print("writing %s (using %s)" % (ecodes_c_path, " ".join(headers)))
|
|
62
67
|
with ecodes_c_path.open("w") as fh:
|
|
63
|
-
cmd = [sys.executable, "evdev/genecodes_c.py", "--ecodes", *headers]
|
|
68
|
+
cmd = [sys.executable, "src/evdev/genecodes_c.py", "--ecodes", *headers]
|
|
64
69
|
run(cmd, check=True, stdout=fh)
|
|
65
70
|
|
|
66
71
|
|
|
@@ -93,12 +98,12 @@ class build_ext(_build_ext.build_ext):
|
|
|
93
98
|
ecodes_py = Path(self.build_lib) / "evdev/ecodes.py"
|
|
94
99
|
print(f"writing {ecodes_py}")
|
|
95
100
|
with ecodes_py.open("w") as fh:
|
|
96
|
-
cmd = [sys.executable, "-B", "evdev/genecodes_py.py"]
|
|
101
|
+
cmd = [sys.executable, "-B", "src/evdev/genecodes_py.py"]
|
|
97
102
|
res = run(cmd, env={"PYTHONPATH": self.build_lib}, stdout=fh)
|
|
98
103
|
|
|
99
104
|
if res.returncode != 0:
|
|
100
105
|
print(f"failed to generate static {ecodes_py} - will use ecodes_runtime.py")
|
|
101
|
-
shutil.copy("evdev/ecodes_runtime.py", ecodes_py)
|
|
106
|
+
shutil.copy("src/evdev/ecodes_runtime.py", ecodes_py)
|
|
102
107
|
|
|
103
108
|
def run(self):
|
|
104
109
|
for cmd_name in self.get_sub_commands():
|
|
@@ -112,9 +117,9 @@ class build_ext(_build_ext.build_ext):
|
|
|
112
117
|
cflags = ["-std=c99", "-Wno-error=declaration-after-statement"]
|
|
113
118
|
setup(
|
|
114
119
|
ext_modules=[
|
|
115
|
-
Extension("evdev._input", sources=["evdev/input.c"], extra_compile_args=cflags),
|
|
116
|
-
Extension("evdev._uinput", sources=["evdev/uinput.c"], extra_compile_args=cflags),
|
|
117
|
-
Extension("evdev._ecodes", sources=["evdev/ecodes.c"], extra_compile_args=cflags),
|
|
120
|
+
Extension("evdev._input", sources=["src/evdev/input.c"], extra_compile_args=cflags),
|
|
121
|
+
Extension("evdev._uinput", sources=["src/evdev/uinput.c"], extra_compile_args=cflags),
|
|
122
|
+
Extension("evdev._ecodes", sources=["src/evdev/ecodes.c"], extra_compile_args=cflags),
|
|
118
123
|
],
|
|
119
124
|
cmdclass={
|
|
120
125
|
"build_ext": build_ext,
|
|
@@ -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,9 +1,6 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
|
-
import collections
|
|
4
1
|
import contextlib
|
|
5
2
|
import os
|
|
6
|
-
import
|
|
3
|
+
from typing import Dict, Iterator, List, Literal, NamedTuple, Tuple, Union, overload
|
|
7
4
|
|
|
8
5
|
from . import _input, ecodes, util
|
|
9
6
|
|
|
@@ -13,18 +10,10 @@ except ImportError:
|
|
|
13
10
|
from .eventio import EvdevError, EventIO
|
|
14
11
|
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
_AbsInfo = collections.namedtuple("AbsInfo", ["value", "min", "max", "fuzz", "flat", "resolution"])
|
|
18
|
-
|
|
19
|
-
_KbdInfo = collections.namedtuple("KbdInfo", ["delay", "repeat"])
|
|
20
|
-
|
|
21
|
-
_DeviceInfo = collections.namedtuple("DeviceInfo", ["bustype", "vendor", "product", "version"])
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class AbsInfo(_AbsInfo):
|
|
13
|
+
class AbsInfo(NamedTuple):
|
|
25
14
|
"""Absolute axis information.
|
|
26
15
|
|
|
27
|
-
A ``namedtuple``
|
|
16
|
+
A ``namedtuple`` with absolute axis information -
|
|
28
17
|
corresponds to the ``input_absinfo`` struct:
|
|
29
18
|
|
|
30
19
|
Attributes
|
|
@@ -60,11 +49,18 @@ class AbsInfo(_AbsInfo):
|
|
|
60
49
|
|
|
61
50
|
"""
|
|
62
51
|
|
|
52
|
+
value: int
|
|
53
|
+
min: int
|
|
54
|
+
max: int
|
|
55
|
+
fuzz: int
|
|
56
|
+
flat: int
|
|
57
|
+
resolution: int
|
|
58
|
+
|
|
63
59
|
def __str__(self):
|
|
64
|
-
return "
|
|
60
|
+
return "value {}, min {}, max {}, fuzz {}, flat {}, res {}".format(*self) # pylint: disable=not-an-iterable
|
|
65
61
|
|
|
66
62
|
|
|
67
|
-
class KbdInfo(
|
|
63
|
+
class KbdInfo(NamedTuple):
|
|
68
64
|
"""Keyboard repeat rate.
|
|
69
65
|
|
|
70
66
|
Attributes
|
|
@@ -77,11 +73,14 @@ class KbdInfo(_KbdInfo):
|
|
|
77
73
|
Keyboard repeat rate in characters per second.
|
|
78
74
|
"""
|
|
79
75
|
|
|
76
|
+
delay: int
|
|
77
|
+
repeat: int
|
|
78
|
+
|
|
80
79
|
def __str__(self):
|
|
81
|
-
return "delay {}, repeat {}".format(
|
|
80
|
+
return "delay {}, repeat {}".format(self.delay, self.repeat)
|
|
82
81
|
|
|
83
82
|
|
|
84
|
-
class DeviceInfo(
|
|
83
|
+
class DeviceInfo(NamedTuple):
|
|
85
84
|
"""
|
|
86
85
|
Attributes
|
|
87
86
|
----------
|
|
@@ -91,9 +90,14 @@ class DeviceInfo(_DeviceInfo):
|
|
|
91
90
|
version
|
|
92
91
|
"""
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
bustype: int
|
|
94
|
+
vendor: int
|
|
95
|
+
product: int
|
|
96
|
+
version: int
|
|
97
|
+
|
|
98
|
+
def __str__(self) -> str:
|
|
95
99
|
msg = "bus: {:04x}, vendor {:04x}, product {:04x}, version {:04x}"
|
|
96
|
-
return msg.format(*self)
|
|
100
|
+
return msg.format(*self) # pylint: disable=not-an-iterable
|
|
97
101
|
|
|
98
102
|
|
|
99
103
|
class InputDevice(EventIO):
|
|
@@ -103,7 +107,7 @@ class InputDevice(EventIO):
|
|
|
103
107
|
|
|
104
108
|
__slots__ = ("path", "fd", "info", "name", "phys", "uniq", "_rawcapabilities", "version", "ff_effects_count")
|
|
105
109
|
|
|
106
|
-
def __init__(self, dev):
|
|
110
|
+
def __init__(self, dev: Union[str, bytes, os.PathLike]):
|
|
107
111
|
"""
|
|
108
112
|
Arguments
|
|
109
113
|
---------
|
|
@@ -114,15 +118,14 @@ class InputDevice(EventIO):
|
|
|
114
118
|
#: Path to input device.
|
|
115
119
|
self.path = dev if not hasattr(dev, "__fspath__") else dev.__fspath__()
|
|
116
120
|
|
|
117
|
-
# Certain operations are possible only when the device is opened in
|
|
118
|
-
# read-write mode.
|
|
121
|
+
# Certain operations are possible only when the device is opened in read-write mode.
|
|
119
122
|
try:
|
|
120
123
|
fd = os.open(dev, os.O_RDWR | os.O_NONBLOCK)
|
|
121
124
|
except OSError:
|
|
122
125
|
fd = os.open(dev, os.O_RDONLY | os.O_NONBLOCK)
|
|
123
126
|
|
|
124
127
|
#: A non-blocking file descriptor to the device file.
|
|
125
|
-
self.fd = fd
|
|
128
|
+
self.fd: int = fd
|
|
126
129
|
|
|
127
130
|
# Returns (bustype, vendor, product, version, name, phys, capabilities).
|
|
128
131
|
info_res = _input.ioctl_devinfo(self.fd)
|
|
@@ -131,16 +134,16 @@ class InputDevice(EventIO):
|
|
|
131
134
|
self.info = DeviceInfo(*info_res[:4])
|
|
132
135
|
|
|
133
136
|
#: The name of the event device.
|
|
134
|
-
self.name = info_res[4]
|
|
137
|
+
self.name: str = info_res[4]
|
|
135
138
|
|
|
136
139
|
#: The physical topology of the device.
|
|
137
|
-
self.phys = info_res[5]
|
|
140
|
+
self.phys: str = info_res[5]
|
|
138
141
|
|
|
139
142
|
#: The unique identifier of the device.
|
|
140
|
-
self.uniq = info_res[6]
|
|
143
|
+
self.uniq: str = info_res[6]
|
|
141
144
|
|
|
142
145
|
#: The evdev protocol version.
|
|
143
|
-
self.version = _input.ioctl_EVIOCGVERSION(self.fd)
|
|
146
|
+
self.version: int = _input.ioctl_EVIOCGVERSION(self.fd)
|
|
144
147
|
|
|
145
148
|
#: The raw dictionary of device capabilities - see `:func:capabilities()`.
|
|
146
149
|
self._rawcapabilities = _input.ioctl_capabilities(self.fd)
|
|
@@ -148,14 +151,14 @@ class InputDevice(EventIO):
|
|
|
148
151
|
#: The number of force feedback effects the device can keep in its memory.
|
|
149
152
|
self.ff_effects_count = _input.ioctl_EVIOCGEFFECTS(self.fd)
|
|
150
153
|
|
|
151
|
-
def __del__(self):
|
|
154
|
+
def __del__(self) -> None:
|
|
152
155
|
if hasattr(self, "fd") and self.fd is not None:
|
|
153
156
|
try:
|
|
154
157
|
self.close()
|
|
155
158
|
except (OSError, ImportError, AttributeError):
|
|
156
159
|
pass
|
|
157
160
|
|
|
158
|
-
def _capabilities(self, absinfo=True):
|
|
161
|
+
def _capabilities(self, absinfo: bool = True):
|
|
159
162
|
res = {}
|
|
160
163
|
|
|
161
164
|
for etype, _ecodes in self._rawcapabilities.items():
|
|
@@ -173,7 +176,13 @@ class InputDevice(EventIO):
|
|
|
173
176
|
|
|
174
177
|
return res
|
|
175
178
|
|
|
176
|
-
|
|
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]]]]:
|
|
177
186
|
"""
|
|
178
187
|
Return the event types that this device supports as a mapping of
|
|
179
188
|
supported event types to lists of handled event codes.
|
|
@@ -218,7 +227,7 @@ class InputDevice(EventIO):
|
|
|
218
227
|
else:
|
|
219
228
|
return self._capabilities(absinfo)
|
|
220
229
|
|
|
221
|
-
def input_props(self, verbose=False):
|
|
230
|
+
def input_props(self, verbose: bool = False):
|
|
222
231
|
"""
|
|
223
232
|
Get device properties and quirks.
|
|
224
233
|
|
|
@@ -239,7 +248,7 @@ class InputDevice(EventIO):
|
|
|
239
248
|
|
|
240
249
|
return props
|
|
241
250
|
|
|
242
|
-
def leds(self, verbose=False):
|
|
251
|
+
def leds(self, verbose: bool = False):
|
|
243
252
|
"""
|
|
244
253
|
Return currently set LED keys.
|
|
245
254
|
|
|
@@ -260,7 +269,7 @@ class InputDevice(EventIO):
|
|
|
260
269
|
|
|
261
270
|
return leds
|
|
262
271
|
|
|
263
|
-
def set_led(self, led_num, value):
|
|
272
|
+
def set_led(self, led_num: int, value: int) -> None:
|
|
264
273
|
"""
|
|
265
274
|
Set the state of the selected LED.
|
|
266
275
|
|
|
@@ -276,18 +285,18 @@ class InputDevice(EventIO):
|
|
|
276
285
|
"""
|
|
277
286
|
return isinstance(other, self.__class__) and self.info == other.info and self.path == other.path
|
|
278
287
|
|
|
279
|
-
def __str__(self):
|
|
288
|
+
def __str__(self) -> str:
|
|
280
289
|
msg = 'device {}, name "{}", phys "{}", uniq "{}"'
|
|
281
290
|
return msg.format(self.path, self.name, self.phys, self.uniq or "")
|
|
282
291
|
|
|
283
|
-
def __repr__(self):
|
|
292
|
+
def __repr__(self) -> str:
|
|
284
293
|
msg = (self.__class__.__name__, self.path)
|
|
285
294
|
return "{}({!r})".format(*msg)
|
|
286
295
|
|
|
287
296
|
def __fspath__(self):
|
|
288
297
|
return self.path
|
|
289
298
|
|
|
290
|
-
def close(self):
|
|
299
|
+
def close(self) -> None:
|
|
291
300
|
if self.fd > -1:
|
|
292
301
|
try:
|
|
293
302
|
super().close()
|
|
@@ -295,7 +304,7 @@ class InputDevice(EventIO):
|
|
|
295
304
|
finally:
|
|
296
305
|
self.fd = -1
|
|
297
306
|
|
|
298
|
-
def grab(self):
|
|
307
|
+
def grab(self) -> None:
|
|
299
308
|
"""
|
|
300
309
|
Grab input device using ``EVIOCGRAB`` - other applications will
|
|
301
310
|
be unable to receive events until the device is released. Only
|
|
@@ -308,7 +317,7 @@ class InputDevice(EventIO):
|
|
|
308
317
|
|
|
309
318
|
_input.ioctl_EVIOCGRAB(self.fd, 1)
|
|
310
319
|
|
|
311
|
-
def ungrab(self):
|
|
320
|
+
def ungrab(self) -> None:
|
|
312
321
|
"""
|
|
313
322
|
Release device if it has been already grabbed (uses `EVIOCGRAB`).
|
|
314
323
|
|
|
@@ -321,7 +330,7 @@ class InputDevice(EventIO):
|
|
|
321
330
|
_input.ioctl_EVIOCGRAB(self.fd, 0)
|
|
322
331
|
|
|
323
332
|
@contextlib.contextmanager
|
|
324
|
-
def grab_context(self):
|
|
333
|
+
def grab_context(self) -> Iterator[None]:
|
|
325
334
|
"""
|
|
326
335
|
A context manager for the duration of which only the current
|
|
327
336
|
process will be able to receive events from the device.
|
|
@@ -330,7 +339,7 @@ class InputDevice(EventIO):
|
|
|
330
339
|
yield
|
|
331
340
|
self.ungrab()
|
|
332
341
|
|
|
333
|
-
def upload_effect(self, effect):
|
|
342
|
+
def upload_effect(self, effect: "ff.Effect"):
|
|
334
343
|
"""
|
|
335
344
|
Upload a force feedback effect to a force feedback device.
|
|
336
345
|
"""
|
|
@@ -339,7 +348,7 @@ class InputDevice(EventIO):
|
|
|
339
348
|
ff_id = _input.upload_effect(self.fd, data)
|
|
340
349
|
return ff_id
|
|
341
350
|
|
|
342
|
-
def erase_effect(self, ff_id):
|
|
351
|
+
def erase_effect(self, ff_id) -> None:
|
|
343
352
|
"""
|
|
344
353
|
Erase a force effect from a force feedback device. This also
|
|
345
354
|
stops the effect.
|
|
@@ -357,10 +366,10 @@ class InputDevice(EventIO):
|
|
|
357
366
|
return KbdInfo(*_input.ioctl_EVIOCGREP(self.fd))
|
|
358
367
|
|
|
359
368
|
@repeat.setter
|
|
360
|
-
def repeat(self, value):
|
|
369
|
+
def repeat(self, value: Tuple[int, int]):
|
|
361
370
|
return _input.ioctl_EVIOCSREP(self.fd, *value)
|
|
362
371
|
|
|
363
|
-
def active_keys(self, verbose=False):
|
|
372
|
+
def active_keys(self, verbose: bool = False):
|
|
364
373
|
"""
|
|
365
374
|
Return currently active keys.
|
|
366
375
|
|
|
@@ -383,13 +392,7 @@ class InputDevice(EventIO):
|
|
|
383
392
|
|
|
384
393
|
return active_keys
|
|
385
394
|
|
|
386
|
-
|
|
387
|
-
def fn(self):
|
|
388
|
-
msg = "Please use {0}.path instead of {0}.fn".format(self.__class__.__name__)
|
|
389
|
-
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
|
390
|
-
return self.path
|
|
391
|
-
|
|
392
|
-
def absinfo(self, axis_num):
|
|
395
|
+
def absinfo(self, axis_num: int):
|
|
393
396
|
"""
|
|
394
397
|
Return current :class:`AbsInfo` for input device axis
|
|
395
398
|
|
|
@@ -405,7 +408,7 @@ class InputDevice(EventIO):
|
|
|
405
408
|
"""
|
|
406
409
|
return AbsInfo(*_input.ioctl_EVIOCGABS(self.fd, axis_num))
|
|
407
410
|
|
|
408
|
-
def set_absinfo(self, axis_num, 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:
|
|
409
412
|
"""
|
|
410
413
|
Update :class:`AbsInfo` values. Only specified values will be overwritten.
|
|
411
414
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# When installed, this module is replaced by an ecodes.py generated at
|
|
1
|
+
# When installed, this module is replaced by an ecodes.py generated at
|
|
2
2
|
# build time by genecodes_py.py (see build_ext in setup.py).
|
|
3
3
|
|
|
4
|
-
# This stub exists to make development of evdev itself more convenient.
|
|
5
|
-
from .
|
|
4
|
+
# This stub exists to make development of evdev itself more convenient.
|
|
5
|
+
from .ecodes_runtime import *
|
|
@@ -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
|
|
|
@@ -2,6 +2,7 @@ import fcntl
|
|
|
2
2
|
import functools
|
|
3
3
|
import os
|
|
4
4
|
import select
|
|
5
|
+
from typing import Iterator, Union
|
|
5
6
|
|
|
6
7
|
from . import _input, _uinput, ecodes
|
|
7
8
|
from .events import InputEvent
|
|
@@ -35,7 +36,7 @@ class EventIO:
|
|
|
35
36
|
"""
|
|
36
37
|
return self.fd
|
|
37
38
|
|
|
38
|
-
def read_loop(self):
|
|
39
|
+
def read_loop(self) -> Iterator[InputEvent]:
|
|
39
40
|
"""
|
|
40
41
|
Enter an endless :func:`select.select()` loop that yields input events.
|
|
41
42
|
"""
|
|
@@ -45,7 +46,7 @@ class EventIO:
|
|
|
45
46
|
for event in self.read():
|
|
46
47
|
yield event
|
|
47
48
|
|
|
48
|
-
def read_one(self):
|
|
49
|
+
def read_one(self) -> Union[InputEvent, None]:
|
|
49
50
|
"""
|
|
50
51
|
Read and return a single input event as an instance of
|
|
51
52
|
:class:`InputEvent <evdev.events.InputEvent>`.
|
|
@@ -59,14 +60,14 @@ class EventIO:
|
|
|
59
60
|
if event:
|
|
60
61
|
return InputEvent(*event)
|
|
61
62
|
|
|
62
|
-
def read(self):
|
|
63
|
+
def read(self) -> Iterator[InputEvent]:
|
|
63
64
|
"""
|
|
64
65
|
Read multiple input events from device. Return a generator object that
|
|
65
66
|
yields :class:`InputEvent <evdev.events.InputEvent>` instances. Raises
|
|
66
67
|
`BlockingIOError` if there are no available events at the moment.
|
|
67
68
|
"""
|
|
68
69
|
|
|
69
|
-
# events ->
|
|
70
|
+
# events -> ((sec, usec, type, code, val), ...)
|
|
70
71
|
events = _input.device_read_many(self.fd)
|
|
71
72
|
|
|
72
73
|
for event in events:
|
|
@@ -114,7 +115,7 @@ class EventIO:
|
|
|
114
115
|
self.write(event.type, event.code, event.value)
|
|
115
116
|
|
|
116
117
|
@need_write
|
|
117
|
-
def write(self, etype, code, value):
|
|
118
|
+
def write(self, etype: int, code: int, value: int):
|
|
118
119
|
"""
|
|
119
120
|
Inject an input event into the input subsystem. Events are
|
|
120
121
|
queued until a synchronization event is received.
|
|
@@ -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
|