evdev 1.8.0__tar.gz → 1.9.0__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.0}/MANIFEST.in +2 -2
- {evdev-1.8.0/evdev.egg-info → evdev-1.9.0}/PKG-INFO +2 -2
- {evdev-1.8.0 → evdev-1.9.0}/pyproject.toml +2 -5
- {evdev-1.8.0 → evdev-1.9.0}/setup.py +13 -8
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/device.py +40 -43
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/ecodes.py +3 -3
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/eventio.py +6 -5
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/events.py +19 -18
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/evtest.py +5 -4
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/genecodes_c.py +5 -1
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/input.c +22 -51
- evdev-1.9.0/src/evdev/py.typed +0 -0
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/uinput.c +2 -23
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/uinput.py +36 -29
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/util.py +4 -5
- {evdev-1.8.0 → evdev-1.9.0/src/evdev.egg-info}/PKG-INFO +2 -2
- evdev-1.9.0/src/evdev.egg-info/SOURCES.txt +29 -0
- {evdev-1.8.0 → evdev-1.9.0}/tests/test_util.py +1 -1
- evdev-1.8.0/evdev.egg-info/SOURCES.txt +0 -28
- {evdev-1.8.0 → evdev-1.9.0}/LICENSE +0 -0
- {evdev-1.8.0 → evdev-1.9.0}/README.md +0 -0
- {evdev-1.8.0 → evdev-1.9.0}/setup.cfg +0 -0
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/__init__.py +0 -0
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/ecodes_runtime.py +0 -0
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/eventio_async.py +0 -0
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/ff.py +0 -0
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev/genecodes_py.py +0 -0
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev.egg-info/dependency_links.txt +0 -0
- {evdev-1.8.0 → evdev-1.9.0/src}/evdev.egg-info/top_level.txt +0 -0
- {evdev-1.8.0 → evdev-1.9.0}/tests/test_ecodes.py +0 -0
- {evdev-1.8.0 → evdev-1.9.0}/tests/test_events.py +0 -0
- {evdev-1.8.0 → evdev-1.9.0}/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.0"
|
|
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.0"
|
|
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,
|
|
@@ -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 NamedTuple, Tuple, Union
|
|
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
|
|
|
93
|
+
bustype: int
|
|
94
|
+
vendor: int
|
|
95
|
+
product: int
|
|
96
|
+
version: int
|
|
97
|
+
|
|
94
98
|
def __str__(self):
|
|
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)
|
|
@@ -155,7 +158,7 @@ class InputDevice(EventIO):
|
|
|
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,7 @@ class InputDevice(EventIO):
|
|
|
173
176
|
|
|
174
177
|
return res
|
|
175
178
|
|
|
176
|
-
def capabilities(self, verbose=False, absinfo=True):
|
|
179
|
+
def capabilities(self, verbose: bool = False, absinfo: bool = True):
|
|
177
180
|
"""
|
|
178
181
|
Return the event types that this device supports as a mapping of
|
|
179
182
|
supported event types to lists of handled event codes.
|
|
@@ -218,7 +221,7 @@ class InputDevice(EventIO):
|
|
|
218
221
|
else:
|
|
219
222
|
return self._capabilities(absinfo)
|
|
220
223
|
|
|
221
|
-
def input_props(self, verbose=False):
|
|
224
|
+
def input_props(self, verbose: bool = False):
|
|
222
225
|
"""
|
|
223
226
|
Get device properties and quirks.
|
|
224
227
|
|
|
@@ -239,7 +242,7 @@ class InputDevice(EventIO):
|
|
|
239
242
|
|
|
240
243
|
return props
|
|
241
244
|
|
|
242
|
-
def leds(self, verbose=False):
|
|
245
|
+
def leds(self, verbose: bool = False):
|
|
243
246
|
"""
|
|
244
247
|
Return currently set LED keys.
|
|
245
248
|
|
|
@@ -260,7 +263,7 @@ class InputDevice(EventIO):
|
|
|
260
263
|
|
|
261
264
|
return leds
|
|
262
265
|
|
|
263
|
-
def set_led(self, led_num, value):
|
|
266
|
+
def set_led(self, led_num: int, value: int):
|
|
264
267
|
"""
|
|
265
268
|
Set the state of the selected LED.
|
|
266
269
|
|
|
@@ -330,7 +333,7 @@ class InputDevice(EventIO):
|
|
|
330
333
|
yield
|
|
331
334
|
self.ungrab()
|
|
332
335
|
|
|
333
|
-
def upload_effect(self, effect):
|
|
336
|
+
def upload_effect(self, effect: "ff.Effect"):
|
|
334
337
|
"""
|
|
335
338
|
Upload a force feedback effect to a force feedback device.
|
|
336
339
|
"""
|
|
@@ -357,10 +360,10 @@ class InputDevice(EventIO):
|
|
|
357
360
|
return KbdInfo(*_input.ioctl_EVIOCGREP(self.fd))
|
|
358
361
|
|
|
359
362
|
@repeat.setter
|
|
360
|
-
def repeat(self, value):
|
|
363
|
+
def repeat(self, value: Tuple[int, int]):
|
|
361
364
|
return _input.ioctl_EVIOCSREP(self.fd, *value)
|
|
362
365
|
|
|
363
|
-
def active_keys(self, verbose=False):
|
|
366
|
+
def active_keys(self, verbose: bool = False):
|
|
364
367
|
"""
|
|
365
368
|
Return currently active keys.
|
|
366
369
|
|
|
@@ -383,13 +386,7 @@ class InputDevice(EventIO):
|
|
|
383
386
|
|
|
384
387
|
return active_keys
|
|
385
388
|
|
|
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):
|
|
389
|
+
def absinfo(self, axis_num: int):
|
|
393
390
|
"""
|
|
394
391
|
Return current :class:`AbsInfo` for input device axis
|
|
395
392
|
|
|
@@ -405,7 +402,7 @@ class InputDevice(EventIO):
|
|
|
405
402
|
"""
|
|
406
403
|
return AbsInfo(*_input.ioctl_EVIOCGABS(self.fd, axis_num))
|
|
407
404
|
|
|
408
|
-
def set_absinfo(self, axis_num, value=None, min=None, max=None, fuzz=None, flat=None, resolution=None):
|
|
405
|
+
def set_absinfo(self, axis_num: int, value=None, min=None, max=None, fuzz=None, flat=None, resolution=None):
|
|
409
406
|
"""
|
|
410
407
|
Update :class:`AbsInfo` values. Only specified values will be overwritten.
|
|
411
408
|
|
|
@@ -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 *
|
|
@@ -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.
|
|
@@ -38,6 +38,7 @@ methods::
|
|
|
38
38
|
# http://www.kernel.org/doc/Documentation/input/event-codes.txt
|
|
39
39
|
|
|
40
40
|
# pylint: disable=no-name-in-module
|
|
41
|
+
from typing import Final
|
|
41
42
|
from .ecodes import ABS, EV_ABS, EV_KEY, EV_REL, EV_SYN, KEY, REL, SYN, keys
|
|
42
43
|
|
|
43
44
|
|
|
@@ -48,21 +49,21 @@ class InputEvent:
|
|
|
48
49
|
|
|
49
50
|
def __init__(self, sec, usec, type, code, value):
|
|
50
51
|
#: Time in seconds since epoch at which event occurred.
|
|
51
|
-
self.sec = sec
|
|
52
|
+
self.sec: int = sec
|
|
52
53
|
|
|
53
54
|
#: Microsecond portion of the timestamp.
|
|
54
|
-
self.usec = usec
|
|
55
|
+
self.usec: int = usec
|
|
55
56
|
|
|
56
57
|
#: Event type - one of ``ecodes.EV_*``.
|
|
57
|
-
self.type = type
|
|
58
|
+
self.type: int = type
|
|
58
59
|
|
|
59
60
|
#: Event code related to the event type.
|
|
60
|
-
self.code = code
|
|
61
|
+
self.code: int = code
|
|
61
62
|
|
|
62
63
|
#: Event value related to the event type.
|
|
63
|
-
self.value = value
|
|
64
|
+
self.value: int = value
|
|
64
65
|
|
|
65
|
-
def timestamp(self):
|
|
66
|
+
def timestamp(self) -> float:
|
|
66
67
|
"""Return event timestamp as a float."""
|
|
67
68
|
return self.sec + (self.usec / 1000000.0)
|
|
68
69
|
|
|
@@ -78,20 +79,20 @@ class InputEvent:
|
|
|
78
79
|
class KeyEvent:
|
|
79
80
|
"""An event generated by a keyboard, button or other key-like devices."""
|
|
80
81
|
|
|
81
|
-
key_up = 0x0
|
|
82
|
-
key_down = 0x1
|
|
83
|
-
key_hold = 0x2
|
|
82
|
+
key_up: Final[int] = 0x0
|
|
83
|
+
key_down: Final[int] = 0x1
|
|
84
|
+
key_hold: Final[int] = 0x2
|
|
84
85
|
|
|
85
86
|
__slots__ = "scancode", "keycode", "keystate", "event"
|
|
86
87
|
|
|
87
|
-
def __init__(self, event, allow_unknown=False):
|
|
88
|
+
def __init__(self, event: InputEvent, allow_unknown: bool = False):
|
|
88
89
|
"""
|
|
89
90
|
The ``allow_unknown`` argument determines what to do in the event of an event code
|
|
90
91
|
for which a key code cannot be found. If ``False`` a ``KeyError`` will be raised.
|
|
91
92
|
If ``True`` the keycode will be set to the hex value of the event code.
|
|
92
93
|
"""
|
|
93
94
|
|
|
94
|
-
self.scancode = event.code
|
|
95
|
+
self.scancode: int = event.code
|
|
95
96
|
|
|
96
97
|
if event.value == 0:
|
|
97
98
|
self.keystate = KeyEvent.key_up
|
|
@@ -109,7 +110,7 @@ class KeyEvent:
|
|
|
109
110
|
raise
|
|
110
111
|
|
|
111
112
|
#: Reference to an :class:`InputEvent` instance.
|
|
112
|
-
self.event = event
|
|
113
|
+
self.event: InputEvent = event
|
|
113
114
|
|
|
114
115
|
def __str__(self):
|
|
115
116
|
try:
|
|
@@ -129,9 +130,9 @@ class RelEvent:
|
|
|
129
130
|
|
|
130
131
|
__slots__ = "event"
|
|
131
132
|
|
|
132
|
-
def __init__(self, event):
|
|
133
|
+
def __init__(self, event: InputEvent):
|
|
133
134
|
#: Reference to an :class:`InputEvent` instance.
|
|
134
|
-
self.event = event
|
|
135
|
+
self.event: InputEvent = event
|
|
135
136
|
|
|
136
137
|
def __str__(self):
|
|
137
138
|
msg = "relative axis event at {:f}, {}"
|
|
@@ -146,9 +147,9 @@ class AbsEvent:
|
|
|
146
147
|
|
|
147
148
|
__slots__ = "event"
|
|
148
149
|
|
|
149
|
-
def __init__(self, event):
|
|
150
|
+
def __init__(self, event: InputEvent):
|
|
150
151
|
#: Reference to an :class:`InputEvent` instance.
|
|
151
|
-
self.event = event
|
|
152
|
+
self.event: InputEvent = event
|
|
152
153
|
|
|
153
154
|
def __str__(self):
|
|
154
155
|
msg = "absolute axis event at {:f}, {}"
|
|
@@ -166,9 +167,9 @@ class SynEvent:
|
|
|
166
167
|
|
|
167
168
|
__slots__ = "event"
|
|
168
169
|
|
|
169
|
-
def __init__(self, event):
|
|
170
|
+
def __init__(self, event: InputEvent):
|
|
170
171
|
#: Reference to an :class:`InputEvent` instance.
|
|
171
|
-
self.event = event
|
|
172
|
+
self.event: InputEvent = event
|
|
172
173
|
|
|
173
174
|
def __str__(self):
|
|
174
175
|
msg = "synchronization event at {:f}, {}"
|
|
@@ -16,7 +16,6 @@ Examples:
|
|
|
16
16
|
evtest /dev/input/event0 /dev/input/event1
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
|
|
20
19
|
import atexit
|
|
21
20
|
import optparse
|
|
22
21
|
import re
|
|
@@ -149,9 +148,11 @@ def print_capabilities(device):
|
|
|
149
148
|
def print_event(e):
|
|
150
149
|
if e.type == ecodes.EV_SYN:
|
|
151
150
|
if e.code == ecodes.SYN_MT_REPORT:
|
|
152
|
-
msg = "time {:<
|
|
151
|
+
msg = "time {:<17} +++++++++++++ {} +++++++++++++"
|
|
152
|
+
elif e.code == ecodes.SYN_DROPPED:
|
|
153
|
+
msg = "time {:<17} !!!!!!!!!!!!! {} !!!!!!!!!!!!!"
|
|
153
154
|
else:
|
|
154
|
-
msg = "time {:<
|
|
155
|
+
msg = "time {:<17} ------------- {} -------------"
|
|
155
156
|
print(msg.format(e.timestamp(), ecodes.SYN[e.code]))
|
|
156
157
|
else:
|
|
157
158
|
if e.type in ecodes.bytype:
|
|
@@ -159,7 +160,7 @@ def print_event(e):
|
|
|
159
160
|
else:
|
|
160
161
|
codename = "?"
|
|
161
162
|
|
|
162
|
-
evfmt = "time {:<
|
|
163
|
+
evfmt = "time {:<17} type {} ({}), code {:<4} ({}), value {}"
|
|
163
164
|
print(evfmt.format(e.timestamp(), e.type, ecodes.EV[e.type], e.code, codename, e.value))
|
|
164
165
|
|
|
165
166
|
|
|
@@ -20,9 +20,12 @@ if not opts:
|
|
|
20
20
|
print("usage: genecodes.py [--ecodes|--stubs] <headers>")
|
|
21
21
|
exit(2)
|
|
22
22
|
|
|
23
|
+
if args:
|
|
24
|
+
headers = args
|
|
25
|
+
|
|
23
26
|
|
|
24
27
|
# -----------------------------------------------------------------------------
|
|
25
|
-
macro_regex = r"#define
|
|
28
|
+
macro_regex = r"#define\s+((?:KEY|ABS|REL|SW|MSC|LED|BTN|REP|SND|ID|EV|BUS|SYN|FF|UI_FF|INPUT_PROP)_\w+)"
|
|
26
29
|
macro_regex = re.compile(macro_regex)
|
|
27
30
|
|
|
28
31
|
# Uname without hostname.
|
|
@@ -35,6 +38,7 @@ template_ecodes = r"""
|
|
|
35
38
|
#include <Python.h>
|
|
36
39
|
#ifdef __FreeBSD__
|
|
37
40
|
#include <dev/evdev/input.h>
|
|
41
|
+
#include <dev/evdev/uinput.h>
|
|
38
42
|
#else
|
|
39
43
|
#include <linux/input.h>
|
|
40
44
|
#include <linux/uinput.h>
|
|
@@ -46,12 +46,10 @@ int test_bit(const char* bitmask, int bit) {
|
|
|
46
46
|
static PyObject *
|
|
47
47
|
device_read(PyObject *self, PyObject *args)
|
|
48
48
|
{
|
|
49
|
-
int fd;
|
|
50
49
|
struct input_event event;
|
|
51
50
|
|
|
52
51
|
// get device file descriptor (O_RDONLY|O_NONBLOCK)
|
|
53
|
-
|
|
54
|
-
return NULL;
|
|
52
|
+
int fd = (int)PyLong_AsLong(PyTuple_GET_ITEM(args, 0));
|
|
55
53
|
|
|
56
54
|
int n = read(fd, &event, sizeof(event));
|
|
57
55
|
|
|
@@ -68,12 +66,9 @@ device_read(PyObject *self, PyObject *args)
|
|
|
68
66
|
PyObject* sec = PyLong_FromLong(event.input_event_sec);
|
|
69
67
|
PyObject* usec = PyLong_FromLong(event.input_event_usec);
|
|
70
68
|
PyObject* val = PyLong_FromLong(event.value);
|
|
71
|
-
PyObject*
|
|
72
|
-
|
|
73
|
-
py_input_event =
|
|
74
|
-
Py_DECREF(sec);
|
|
75
|
-
Py_DECREF(usec);
|
|
76
|
-
Py_DECREF(val);
|
|
69
|
+
PyObject* type = PyLong_FromLong(event.type);
|
|
70
|
+
PyObject* code = PyLong_FromLong(event.code);
|
|
71
|
+
PyObject* py_input_event = PyTuple_Pack(5, sec, usec, type, code, val);
|
|
77
72
|
|
|
78
73
|
return py_input_event;
|
|
79
74
|
}
|
|
@@ -83,17 +78,16 @@ device_read(PyObject *self, PyObject *args)
|
|
|
83
78
|
static PyObject *
|
|
84
79
|
device_read_many(PyObject *self, PyObject *args)
|
|
85
80
|
{
|
|
86
|
-
int fd;
|
|
87
|
-
|
|
88
81
|
// get device file descriptor (O_RDONLY|O_NONBLOCK)
|
|
89
|
-
int
|
|
90
|
-
if (!ret) return NULL;
|
|
82
|
+
int fd = (int)PyLong_AsLong(PyTuple_GET_ITEM(args, 0));
|
|
91
83
|
|
|
92
|
-
PyObject* event_list = PyList_New(0);
|
|
93
84
|
PyObject* py_input_event = NULL;
|
|
85
|
+
PyObject* events = NULL;
|
|
94
86
|
PyObject* sec = NULL;
|
|
95
87
|
PyObject* usec = NULL;
|
|
96
88
|
PyObject* val = NULL;
|
|
89
|
+
PyObject* type = NULL;
|
|
90
|
+
PyObject* code = NULL;
|
|
97
91
|
|
|
98
92
|
struct input_event event[64];
|
|
99
93
|
|
|
@@ -102,26 +96,24 @@ device_read_many(PyObject *self, PyObject *args)
|
|
|
102
96
|
|
|
103
97
|
if (nread < 0) {
|
|
104
98
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
105
|
-
Py_DECREF(event_list);
|
|
106
99
|
return NULL;
|
|
107
100
|
}
|
|
108
101
|
|
|
109
|
-
// Construct a
|
|
110
|
-
|
|
102
|
+
// Construct a tuple of event tuples. Each tuple is the arguments to InputEvent.
|
|
103
|
+
size_t num_events = nread / event_size;
|
|
104
|
+
events = PyTuple_New(num_events);
|
|
105
|
+
for (size_t i = 0 ; i < num_events; i++) {
|
|
111
106
|
sec = PyLong_FromLong(event[i].input_event_sec);
|
|
112
107
|
usec = PyLong_FromLong(event[i].input_event_usec);
|
|
113
108
|
val = PyLong_FromLong(event[i].value);
|
|
109
|
+
type = PyLong_FromLong(event[i].type);
|
|
110
|
+
code = PyLong_FromLong(event[i].code);
|
|
114
111
|
|
|
115
|
-
py_input_event =
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
Py_DECREF(py_input_event);
|
|
119
|
-
Py_DECREF(sec);
|
|
120
|
-
Py_DECREF(usec);
|
|
121
|
-
Py_DECREF(val);
|
|
112
|
+
py_input_event = PyTuple_Pack(5, sec, usec, type, code, val);
|
|
113
|
+
PyTuple_SET_ITEM(events, i, py_input_event);
|
|
122
114
|
}
|
|
123
115
|
|
|
124
|
-
return
|
|
116
|
+
return events;
|
|
125
117
|
}
|
|
126
118
|
|
|
127
119
|
|
|
@@ -309,7 +301,7 @@ static PyObject *
|
|
|
309
301
|
ioctl_EVIOCGREP(PyObject *self, PyObject *args)
|
|
310
302
|
{
|
|
311
303
|
int fd, ret;
|
|
312
|
-
unsigned int rep[
|
|
304
|
+
unsigned int rep[REP_CNT] = {0};
|
|
313
305
|
ret = PyArg_ParseTuple(args, "i", &fd);
|
|
314
306
|
if (!ret) return NULL;
|
|
315
307
|
|
|
@@ -317,7 +309,7 @@ ioctl_EVIOCGREP(PyObject *self, PyObject *args)
|
|
|
317
309
|
if (ret == -1)
|
|
318
310
|
return NULL;
|
|
319
311
|
|
|
320
|
-
return Py_BuildValue("(ii)", rep[
|
|
312
|
+
return Py_BuildValue("(ii)", rep[REP_DELAY], rep[REP_PERIOD]);
|
|
321
313
|
}
|
|
322
314
|
|
|
323
315
|
|
|
@@ -325,7 +317,7 @@ static PyObject *
|
|
|
325
317
|
ioctl_EVIOCSREP(PyObject *self, PyObject *args)
|
|
326
318
|
{
|
|
327
319
|
int fd, ret;
|
|
328
|
-
unsigned int rep[
|
|
320
|
+
unsigned int rep[REP_CNT] = {0};
|
|
329
321
|
|
|
330
322
|
ret = PyArg_ParseTuple(args, "iii", &fd, &rep[0], &rep[1]);
|
|
331
323
|
if (!ret) return NULL;
|
|
@@ -539,7 +531,6 @@ ioctl_EVIOCGPROP(PyObject *self, PyObject *args)
|
|
|
539
531
|
}
|
|
540
532
|
|
|
541
533
|
|
|
542
|
-
|
|
543
534
|
static PyMethodDef MethodTable[] = {
|
|
544
535
|
{ "ioctl_devinfo", ioctl_devinfo, METH_VARARGS, "fetch input device info" },
|
|
545
536
|
{ "ioctl_capabilities", ioctl_capabilities, METH_VARARGS, "fetch input device capabilities" },
|
|
@@ -561,14 +552,10 @@ static PyMethodDef MethodTable[] = {
|
|
|
561
552
|
};
|
|
562
553
|
|
|
563
554
|
|
|
564
|
-
#define MODULE_NAME "_input"
|
|
565
|
-
#define MODULE_HELP "Python bindings to certain linux input subsystem functions"
|
|
566
|
-
|
|
567
|
-
#if PY_MAJOR_VERSION >= 3
|
|
568
555
|
static struct PyModuleDef moduledef = {
|
|
569
556
|
PyModuleDef_HEAD_INIT,
|
|
570
|
-
|
|
571
|
-
|
|
557
|
+
"_input",
|
|
558
|
+
"Python bindings to certain linux input subsystem functions",
|
|
572
559
|
-1, /* m_size */
|
|
573
560
|
MethodTable, /* m_methods */
|
|
574
561
|
NULL, /* m_reload */
|
|
@@ -590,19 +577,3 @@ PyInit__input(void)
|
|
|
590
577
|
{
|
|
591
578
|
return moduleinit();
|
|
592
579
|
}
|
|
593
|
-
|
|
594
|
-
#else
|
|
595
|
-
static PyObject *
|
|
596
|
-
moduleinit(void)
|
|
597
|
-
{
|
|
598
|
-
PyObject* m = Py_InitModule3(MODULE_NAME, MethodTable, MODULE_HELP);
|
|
599
|
-
if (m == NULL) return NULL;
|
|
600
|
-
return m;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
PyMODINIT_FUNC
|
|
604
|
-
init_input(void)
|
|
605
|
-
{
|
|
606
|
-
moduleinit();
|
|
607
|
-
}
|
|
608
|
-
#endif
|
|
File without changes
|
|
@@ -356,8 +356,6 @@ int _uinput_end_erase(int fd, struct uinput_ff_erase *upload)
|
|
|
356
356
|
return ioctl(fd, UI_END_FF_ERASE, upload);
|
|
357
357
|
}
|
|
358
358
|
|
|
359
|
-
#define MODULE_NAME "_uinput"
|
|
360
|
-
#define MODULE_HELP "Python bindings for parts of linux/uinput.c"
|
|
361
359
|
|
|
362
360
|
static PyMethodDef MethodTable[] = {
|
|
363
361
|
{ "open", uinput_open, METH_VARARGS,
|
|
@@ -390,11 +388,10 @@ static PyMethodDef MethodTable[] = {
|
|
|
390
388
|
{ NULL, NULL, 0, NULL}
|
|
391
389
|
};
|
|
392
390
|
|
|
393
|
-
#if PY_MAJOR_VERSION >= 3
|
|
394
391
|
static struct PyModuleDef moduledef = {
|
|
395
392
|
PyModuleDef_HEAD_INIT,
|
|
396
|
-
|
|
397
|
-
|
|
393
|
+
"_uinput",
|
|
394
|
+
"Python bindings for parts of linux/uinput.c",
|
|
398
395
|
-1, /* m_size */
|
|
399
396
|
MethodTable, /* m_methods */
|
|
400
397
|
NULL, /* m_reload */
|
|
@@ -418,21 +415,3 @@ PyInit__uinput(void)
|
|
|
418
415
|
{
|
|
419
416
|
return moduleinit();
|
|
420
417
|
}
|
|
421
|
-
|
|
422
|
-
#else
|
|
423
|
-
static PyObject *
|
|
424
|
-
moduleinit(void)
|
|
425
|
-
{
|
|
426
|
-
PyObject* m = Py_InitModule3(MODULE_NAME, MethodTable, MODULE_HELP);
|
|
427
|
-
if (m == NULL) return NULL;
|
|
428
|
-
|
|
429
|
-
PyModule_AddIntConstant(m, "maxnamelen", UINPUT_MAX_NAME_SIZE);
|
|
430
|
-
return m;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
PyMODINIT_FUNC
|
|
434
|
-
init_uinput(void)
|
|
435
|
-
{
|
|
436
|
-
moduleinit();
|
|
437
|
-
}
|
|
438
|
-
#endif
|
|
@@ -5,8 +5,10 @@ import re
|
|
|
5
5
|
import stat
|
|
6
6
|
import time
|
|
7
7
|
from collections import defaultdict
|
|
8
|
+
from typing import Union, Tuple, Dict, Sequence, Optional
|
|
8
9
|
|
|
9
|
-
from . import _uinput,
|
|
10
|
+
from . import _uinput, ecodes, ff, util
|
|
11
|
+
from .device import InputDevice, AbsInfo
|
|
10
12
|
from .events import InputEvent
|
|
11
13
|
|
|
12
14
|
try:
|
|
@@ -38,7 +40,12 @@ class UInput(EventIO):
|
|
|
38
40
|
)
|
|
39
41
|
|
|
40
42
|
@classmethod
|
|
41
|
-
def from_device(
|
|
43
|
+
def from_device(
|
|
44
|
+
cls,
|
|
45
|
+
*devices: Union[InputDevice, Union[str, bytes, os.PathLike]],
|
|
46
|
+
filtered_types: Tuple[int] = (ecodes.EV_SYN, ecodes.EV_FF),
|
|
47
|
+
**kwargs,
|
|
48
|
+
):
|
|
42
49
|
"""
|
|
43
50
|
Create an UInput device with the capabilities of one or more input
|
|
44
51
|
devices.
|
|
@@ -57,8 +64,8 @@ class UInput(EventIO):
|
|
|
57
64
|
|
|
58
65
|
device_instances = []
|
|
59
66
|
for dev in devices:
|
|
60
|
-
if not isinstance(dev,
|
|
61
|
-
dev =
|
|
67
|
+
if not isinstance(dev, InputDevice):
|
|
68
|
+
dev = InputDevice(str(dev))
|
|
62
69
|
device_instances.append(dev)
|
|
63
70
|
|
|
64
71
|
all_capabilities = defaultdict(set)
|
|
@@ -79,14 +86,14 @@ class UInput(EventIO):
|
|
|
79
86
|
|
|
80
87
|
def __init__(
|
|
81
88
|
self,
|
|
82
|
-
events=None,
|
|
83
|
-
name="py-evdev-uinput",
|
|
84
|
-
vendor=0x1,
|
|
85
|
-
product=0x1,
|
|
86
|
-
version=0x1,
|
|
87
|
-
bustype=0x3,
|
|
88
|
-
devnode="/dev/uinput",
|
|
89
|
-
phys="py-evdev-uinput",
|
|
89
|
+
events: Optional[Dict[int, Sequence[int]]] = None,
|
|
90
|
+
name: str = "py-evdev-uinput",
|
|
91
|
+
vendor: int = 0x1,
|
|
92
|
+
product: int = 0x1,
|
|
93
|
+
version: int = 0x1,
|
|
94
|
+
bustype: int = 0x3,
|
|
95
|
+
devnode: str = "/dev/uinput",
|
|
96
|
+
phys: str = "py-evdev-uinput",
|
|
90
97
|
input_props=None,
|
|
91
98
|
# CentOS 7 has sufficiently old headers that FF_MAX_EFFECTS is not defined there,
|
|
92
99
|
# which causes the whole module to fail loading. Fallback on a hardcoded value of
|
|
@@ -131,13 +138,13 @@ class UInput(EventIO):
|
|
|
131
138
|
to inject only ``KEY_*`` and ``BTN_*`` event codes.
|
|
132
139
|
"""
|
|
133
140
|
|
|
134
|
-
self.name = name #: Uinput device name.
|
|
135
|
-
self.vendor = vendor #: Device vendor identifier.
|
|
136
|
-
self.product = product #: Device product identifier.
|
|
137
|
-
self.version = version #: Device version identifier.
|
|
138
|
-
self.bustype = bustype #: Device bustype - e.g. ``BUS_USB``.
|
|
139
|
-
self.phys = phys #: Uinput device physical path.
|
|
140
|
-
self.devnode = devnode #: Uinput device node - e.g. ``/dev/uinput/``.
|
|
141
|
+
self.name: str = name #: Uinput device name.
|
|
142
|
+
self.vendor: int = vendor #: Device vendor identifier.
|
|
143
|
+
self.product: int = product #: Device product identifier.
|
|
144
|
+
self.version: int = version #: Device version identifier.
|
|
145
|
+
self.bustype: int = bustype #: Device bustype - e.g. ``BUS_USB``.
|
|
146
|
+
self.phys: str = phys #: Uinput device physical path.
|
|
147
|
+
self.devnode: str = devnode #: Uinput device node - e.g. ``/dev/uinput/``.
|
|
141
148
|
|
|
142
149
|
if not events:
|
|
143
150
|
events = {ecodes.EV_KEY: ecodes.keys.keys()}
|
|
@@ -173,7 +180,7 @@ class UInput(EventIO):
|
|
|
173
180
|
#: An :class:`InputDevice <evdev.device.InputDevice>` instance
|
|
174
181
|
#: for the fake input device. ``None`` if the device cannot be
|
|
175
182
|
#: opened for reading and writing.
|
|
176
|
-
self.device = self._find_device(self.fd)
|
|
183
|
+
self.device: InputDevice = self._find_device(self.fd)
|
|
177
184
|
|
|
178
185
|
def _prepare_events(self, events):
|
|
179
186
|
"""Prepare events for passing to _uinput.enable and _uinput.setup"""
|
|
@@ -181,7 +188,7 @@ class UInput(EventIO):
|
|
|
181
188
|
for etype, codes in events.items():
|
|
182
189
|
for code in codes:
|
|
183
190
|
# Handle max, min, fuzz, flat.
|
|
184
|
-
if isinstance(code, (tuple, list,
|
|
191
|
+
if isinstance(code, (tuple, list, AbsInfo)):
|
|
185
192
|
# Flatten (ABS_Y, (0, 255, 0, 0, 0, 0)) to (ABS_Y, 0, 255, 0, 0, 0, 0).
|
|
186
193
|
f = [code[0]]
|
|
187
194
|
f.extend(code[1])
|
|
@@ -206,7 +213,7 @@ class UInput(EventIO):
|
|
|
206
213
|
return "{}({})".format(self.__class__.__name__, ", ".join(v))
|
|
207
214
|
|
|
208
215
|
def __str__(self):
|
|
209
|
-
msg = 'name "{}", bus "{}", vendor "{:04x}", product "{:04x}", version "{:04x}", phys "{}"\
|
|
216
|
+
msg = 'name "{}", bus "{}", vendor "{:04x}", product "{:04x}", version "{:04x}", phys "{}"\nevent types: {}'
|
|
210
217
|
|
|
211
218
|
evtypes = [i[0] for i in self.capabilities(True).keys()]
|
|
212
219
|
msg = msg.format(
|
|
@@ -225,7 +232,7 @@ class UInput(EventIO):
|
|
|
225
232
|
_uinput.close(self.fd)
|
|
226
233
|
self.fd = -1
|
|
227
234
|
|
|
228
|
-
def capabilities(self, verbose=False, absinfo=True):
|
|
235
|
+
def capabilities(self, verbose: bool = False, absinfo: bool = True):
|
|
229
236
|
"""See :func:`capabilities <evdev.device.InputDevice.capabilities>`."""
|
|
230
237
|
if self.device is None:
|
|
231
238
|
raise UInputError("input device not opened - cannot read capabilities")
|
|
@@ -281,7 +288,7 @@ class UInput(EventIO):
|
|
|
281
288
|
msg = "uinput device name must not be longer than {} characters"
|
|
282
289
|
raise UInputError(msg.format(_uinput.maxnamelen))
|
|
283
290
|
|
|
284
|
-
def _find_device(self, fd):
|
|
291
|
+
def _find_device(self, fd: int) -> InputDevice:
|
|
285
292
|
"""
|
|
286
293
|
Tries to find the device node. Will delegate this task to one of
|
|
287
294
|
several platform-specific functions.
|
|
@@ -299,7 +306,7 @@ class UInput(EventIO):
|
|
|
299
306
|
# use the generic fallback method.
|
|
300
307
|
return self._find_device_fallback()
|
|
301
308
|
|
|
302
|
-
def _find_device_linux(self, sysname):
|
|
309
|
+
def _find_device_linux(self, sysname: str) -> InputDevice:
|
|
303
310
|
"""
|
|
304
311
|
Tries to find the device node when running on Linux.
|
|
305
312
|
"""
|
|
@@ -327,15 +334,15 @@ class UInput(EventIO):
|
|
|
327
334
|
# device to show up or the permissions to be set.
|
|
328
335
|
for attempt in range(19):
|
|
329
336
|
try:
|
|
330
|
-
return
|
|
337
|
+
return InputDevice(device_path)
|
|
331
338
|
except (FileNotFoundError, PermissionError):
|
|
332
339
|
time.sleep(0.1)
|
|
333
340
|
|
|
334
341
|
# Last attempt. If this fails, whatever exception the last attempt raises
|
|
335
342
|
# shall be the exception that this function raises.
|
|
336
|
-
return
|
|
343
|
+
return InputDevice(device_path)
|
|
337
344
|
|
|
338
|
-
def _find_device_fallback(self):
|
|
345
|
+
def _find_device_fallback(self) -> Union[InputDevice, None]:
|
|
339
346
|
"""
|
|
340
347
|
Tries to find the device node when UI_GET_SYSNAME is not available or
|
|
341
348
|
we're running on a system sufficiently exotic that we do not know how
|
|
@@ -363,6 +370,6 @@ class UInput(EventIO):
|
|
|
363
370
|
path_number_pairs.sort(key=lambda pair: pair[1], reverse=True)
|
|
364
371
|
|
|
365
372
|
for path, _ in path_number_pairs:
|
|
366
|
-
d =
|
|
373
|
+
d = InputDevice(path)
|
|
367
374
|
if d.name == self.name:
|
|
368
375
|
return d
|
|
@@ -3,21 +3,20 @@ import glob
|
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
5
|
import stat
|
|
6
|
+
from typing import Union, List
|
|
6
7
|
|
|
7
8
|
from . import ecodes
|
|
8
9
|
from .events import event_factory
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
def list_devices(input_device_dir="/dev/input"):
|
|
12
|
+
def list_devices(input_device_dir: Union[str, bytes, os.PathLike] = "/dev/input") -> List[str]:
|
|
12
13
|
"""List readable character devices in ``input_device_dir``."""
|
|
13
14
|
|
|
14
15
|
fns = glob.glob("{}/event*".format(input_device_dir))
|
|
15
|
-
|
|
16
|
+
return list(filter(is_device, fns))
|
|
16
17
|
|
|
17
|
-
return fns
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
def is_device(fn):
|
|
19
|
+
def is_device(fn: Union[str, bytes, os.PathLike]) -> bool:
|
|
21
20
|
"""Check if ``fn`` is a readable and writable character device."""
|
|
22
21
|
|
|
23
22
|
if not os.path.exists(fn):
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
src/evdev/__init__.py
|
|
7
|
+
src/evdev/device.py
|
|
8
|
+
src/evdev/ecodes.py
|
|
9
|
+
src/evdev/ecodes_runtime.py
|
|
10
|
+
src/evdev/eventio.py
|
|
11
|
+
src/evdev/eventio_async.py
|
|
12
|
+
src/evdev/events.py
|
|
13
|
+
src/evdev/evtest.py
|
|
14
|
+
src/evdev/ff.py
|
|
15
|
+
src/evdev/genecodes_c.py
|
|
16
|
+
src/evdev/genecodes_py.py
|
|
17
|
+
src/evdev/input.c
|
|
18
|
+
src/evdev/py.typed
|
|
19
|
+
src/evdev/uinput.c
|
|
20
|
+
src/evdev/uinput.py
|
|
21
|
+
src/evdev/util.py
|
|
22
|
+
src/evdev.egg-info/PKG-INFO
|
|
23
|
+
src/evdev.egg-info/SOURCES.txt
|
|
24
|
+
src/evdev.egg-info/dependency_links.txt
|
|
25
|
+
src/evdev.egg-info/top_level.txt
|
|
26
|
+
tests/test_ecodes.py
|
|
27
|
+
tests/test_events.py
|
|
28
|
+
tests/test_uinput.py
|
|
29
|
+
tests/test_util.py
|
|
@@ -6,7 +6,7 @@ def test_match_ecodes_a():
|
|
|
6
6
|
assert res == {1: [372, 418, 419, 420]}
|
|
7
7
|
assert dict(util.resolve_ecodes_dict(res)) == {
|
|
8
8
|
("EV_KEY", 1): [
|
|
9
|
-
(
|
|
9
|
+
(("KEY_FULL_SCREEN", "KEY_ZOOM"), 372),
|
|
10
10
|
("KEY_ZOOMIN", 418),
|
|
11
11
|
("KEY_ZOOMOUT", 419),
|
|
12
12
|
("KEY_ZOOMRESET", 420),
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
LICENSE
|
|
2
|
-
MANIFEST.in
|
|
3
|
-
README.md
|
|
4
|
-
pyproject.toml
|
|
5
|
-
setup.py
|
|
6
|
-
evdev/__init__.py
|
|
7
|
-
evdev/device.py
|
|
8
|
-
evdev/ecodes.py
|
|
9
|
-
evdev/ecodes_runtime.py
|
|
10
|
-
evdev/eventio.py
|
|
11
|
-
evdev/eventio_async.py
|
|
12
|
-
evdev/events.py
|
|
13
|
-
evdev/evtest.py
|
|
14
|
-
evdev/ff.py
|
|
15
|
-
evdev/genecodes_c.py
|
|
16
|
-
evdev/genecodes_py.py
|
|
17
|
-
evdev/input.c
|
|
18
|
-
evdev/uinput.c
|
|
19
|
-
evdev/uinput.py
|
|
20
|
-
evdev/util.py
|
|
21
|
-
evdev.egg-info/PKG-INFO
|
|
22
|
-
evdev.egg-info/SOURCES.txt
|
|
23
|
-
evdev.egg-info/dependency_links.txt
|
|
24
|
-
evdev.egg-info/top_level.txt
|
|
25
|
-
tests/test_ecodes.py
|
|
26
|
-
tests/test_events.py
|
|
27
|
-
tests/test_uinput.py
|
|
28
|
-
tests/test_util.py
|
|
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
|