evdev-binary 1.9.3__cp314-cp314-musllinux_1_2_x86_64.whl

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/__init__.py ADDED
@@ -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
+ )
evdev/device.py ADDED
@@ -0,0 +1,440 @@
1
+ import contextlib
2
+ import os
3
+ from typing import Dict, Generic, Iterator, List, Literal, NamedTuple, Tuple, TypeVar, Union, overload
4
+
5
+ from . import _input, ecodes, util
6
+
7
+ try:
8
+ from .eventio_async import EvdevError, EventIO
9
+ except ImportError:
10
+ from .eventio import EvdevError, EventIO
11
+
12
+ _AnyStr = TypeVar("_AnyStr", str, bytes)
13
+
14
+
15
+ class AbsInfo(NamedTuple):
16
+ """Absolute axis information.
17
+
18
+ A ``namedtuple`` with absolute axis information -
19
+ corresponds to the ``input_absinfo`` struct:
20
+
21
+ Attributes
22
+ ---------
23
+ value
24
+ Latest reported value for the axis.
25
+
26
+ min
27
+ Specifies minimum value for the axis.
28
+
29
+ max
30
+ Specifies maximum value for the axis.
31
+
32
+ fuzz
33
+ Specifies fuzz value that is used to filter noise from the
34
+ event stream.
35
+
36
+ flat
37
+ Values that are within this value will be discarded by joydev
38
+ interface and reported as 0 instead.
39
+
40
+ resolution
41
+ Specifies resolution for the values reported for the axis.
42
+ Resolution for main axes (``ABS_X, ABS_Y, ABS_Z``) is reported
43
+ in units per millimeter (units/mm), resolution for rotational
44
+ axes (``ABS_RX, ABS_RY, ABS_RZ``) is reported in units per
45
+ radian.
46
+
47
+ Note
48
+ ----
49
+ The input core does not clamp reported values to the ``[minimum,
50
+ maximum]`` limits, such task is left to userspace.
51
+
52
+ """
53
+
54
+ value: int
55
+ min: int
56
+ max: int
57
+ fuzz: int
58
+ flat: int
59
+ resolution: int
60
+
61
+ def __str__(self):
62
+ return "value {}, min {}, max {}, fuzz {}, flat {}, res {}".format(*self) # pylint: disable=not-an-iterable
63
+
64
+
65
+ class KbdInfo(NamedTuple):
66
+ """Keyboard repeat rate.
67
+
68
+ Attributes
69
+ ----------
70
+ delay
71
+ Amount of time that a key must be depressed before it will start
72
+ to repeat (in milliseconds).
73
+
74
+ repeat
75
+ Keyboard repeat rate in characters per second.
76
+ """
77
+
78
+ delay: int
79
+ repeat: int
80
+
81
+ def __str__(self):
82
+ return "delay {}, repeat {}".format(self.delay, self.repeat)
83
+
84
+
85
+ class DeviceInfo(NamedTuple):
86
+ """
87
+ Attributes
88
+ ----------
89
+ bustype
90
+ vendor
91
+ product
92
+ version
93
+ """
94
+
95
+ bustype: int
96
+ vendor: int
97
+ product: int
98
+ version: int
99
+
100
+ def __str__(self) -> str:
101
+ msg = "bus: {:04x}, vendor {:04x}, product {:04x}, version {:04x}"
102
+ return msg.format(*self) # pylint: disable=not-an-iterable
103
+
104
+
105
+ class InputDevice(EventIO, Generic[_AnyStr]):
106
+ """
107
+ A linux input device from which input events can be read.
108
+ """
109
+
110
+ __slots__ = ("path", "fd", "info", "name", "phys", "uniq", "_rawcapabilities", "version", "ff_effects_count")
111
+
112
+ def __init__(self, dev: Union[_AnyStr, "os.PathLike[_AnyStr]"]):
113
+ """
114
+ Arguments
115
+ ---------
116
+ dev : str|bytes|PathLike
117
+ Path to input device
118
+ """
119
+
120
+ #: Path to input device.
121
+ self.path: _AnyStr = dev if not hasattr(dev, "__fspath__") else dev.__fspath__()
122
+
123
+ # Certain operations are possible only when the device is opened in read-write mode.
124
+ try:
125
+ fd = os.open(dev, os.O_RDWR | os.O_NONBLOCK)
126
+ except OSError:
127
+ fd = os.open(dev, os.O_RDONLY | os.O_NONBLOCK)
128
+
129
+ #: A non-blocking file descriptor to the device file.
130
+ self.fd: int = fd
131
+
132
+ # Returns (bustype, vendor, product, version, name, phys, capabilities).
133
+ info_res = _input.ioctl_devinfo(self.fd)
134
+
135
+ #: A :class:`DeviceInfo <evdev.device.DeviceInfo>` instance.
136
+ self.info = DeviceInfo(*info_res[:4])
137
+
138
+ #: The name of the event device.
139
+ self.name: str = info_res[4]
140
+
141
+ #: The physical topology of the device.
142
+ self.phys: str = info_res[5]
143
+
144
+ #: The unique identifier of the device.
145
+ self.uniq: str = info_res[6]
146
+
147
+ #: The evdev protocol version.
148
+ self.version: int = _input.ioctl_EVIOCGVERSION(self.fd)
149
+
150
+ #: The raw dictionary of device capabilities - see `:func:capabilities()`.
151
+ self._rawcapabilities = _input.ioctl_capabilities(self.fd)
152
+
153
+ #: The number of force feedback effects the device can keep in its memory.
154
+ self.ff_effects_count = _input.ioctl_EVIOCGEFFECTS(self.fd)
155
+
156
+ def __del__(self) -> None:
157
+ if hasattr(self, "fd") and self.fd is not None:
158
+ try:
159
+ self.close()
160
+ except (OSError, ImportError, AttributeError):
161
+ pass
162
+
163
+ def _capabilities(self, absinfo: bool = True):
164
+ res = {}
165
+
166
+ for etype, _ecodes in self._rawcapabilities.items():
167
+ for code in _ecodes:
168
+ l = res.setdefault(etype, [])
169
+ if isinstance(code, tuple):
170
+ if absinfo:
171
+ a = code[1] # (0, 0, 0, 255, 0, 0)
172
+ i = AbsInfo(*a)
173
+ l.append((code[0], i))
174
+ else:
175
+ l.append(code[0])
176
+ else:
177
+ l.append(code)
178
+
179
+ return res
180
+
181
+ @overload
182
+ def capabilities(self, verbose: Literal[False] = ..., absinfo: bool = ...) -> Dict[int, List[int]]:
183
+ ...
184
+ @overload
185
+ def capabilities(self, verbose: Literal[True], absinfo: bool = ...) -> Dict[Tuple[str, int], List[Tuple[str, int]]]:
186
+ ...
187
+ def capabilities(self, verbose: bool = False, absinfo: bool = True) -> Union[Dict[int, List[int]], Dict[Tuple[str, int], List[Tuple[str, int]]]]:
188
+ """
189
+ Return the event types that this device supports as a mapping of
190
+ supported event types to lists of handled event codes.
191
+
192
+ Example
193
+ --------
194
+ >>> device.capabilities()
195
+ { 1: [272, 273, 274],
196
+ 2: [0, 1, 6, 8] }
197
+
198
+ If ``verbose`` is ``True``, event codes and types will be resolved
199
+ to their names.
200
+
201
+ ::
202
+
203
+ { ('EV_KEY', 1): [('BTN_MOUSE', 272),
204
+ ('BTN_RIGHT', 273),
205
+ ('BTN_MIDDLE', 273)],
206
+ ('EV_REL', 2): [('REL_X', 0),
207
+ ('REL_Y', 1),
208
+ ('REL_HWHEEL', 6),
209
+ ('REL_WHEEL', 8)] }
210
+
211
+ Unknown codes or types will be resolved to ``'?'``.
212
+
213
+ If ``absinfo`` is ``True``, the list of capabilities will also
214
+ include absolute axis information in the form of
215
+ :class:`AbsInfo` instances::
216
+
217
+ { 3: [ (0, AbsInfo(min=0, max=255, fuzz=0, flat=0)),
218
+ (1, AbsInfo(min=0, max=255, fuzz=0, flat=0)) ]}
219
+
220
+ Combined with ``verbose`` the above becomes::
221
+
222
+ { ('EV_ABS', 3): [ (('ABS_X', 0), AbsInfo(min=0, max=255, fuzz=0, flat=0)),
223
+ (('ABS_Y', 1), AbsInfo(min=0, max=255, fuzz=0, flat=0)) ]}
224
+
225
+ """
226
+
227
+ if verbose:
228
+ return dict(util.resolve_ecodes_dict(self._capabilities(absinfo)))
229
+ else:
230
+ return self._capabilities(absinfo)
231
+
232
+ def input_props(self, verbose: bool = False):
233
+ """
234
+ Get device properties and quirks.
235
+
236
+ Example
237
+ -------
238
+ >>> device.input_props()
239
+ [0, 5]
240
+
241
+ If ``verbose`` is ``True``, input properties are resolved to their
242
+ names. Unknown codes are resolved to ``'?'``::
243
+
244
+ [('INPUT_PROP_POINTER', 0), ('INPUT_PROP_POINTING_STICK', 5)]
245
+
246
+ """
247
+ props = _input.ioctl_EVIOCGPROP(self.fd)
248
+ if verbose:
249
+ return util.resolve_ecodes(ecodes.INPUT_PROP, props)
250
+
251
+ return props
252
+
253
+ def leds(self, verbose: bool = False):
254
+ """
255
+ Return currently set LED keys.
256
+
257
+ Example
258
+ -------
259
+ >>> device.leds()
260
+ [0, 1, 8, 9]
261
+
262
+ If ``verbose`` is ``True``, event codes are resolved to their
263
+ names. Unknown codes are resolved to ``'?'``::
264
+
265
+ [('LED_NUML', 0), ('LED_CAPSL', 1), ('LED_MISC', 8), ('LED_MAIL', 9)]
266
+
267
+ """
268
+ leds = _input.ioctl_EVIOCG_bits(self.fd, ecodes.EV_LED)
269
+ if verbose:
270
+ return util.resolve_ecodes(ecodes.LED, leds)
271
+
272
+ return leds
273
+
274
+ def set_led(self, led_num: int, value: int) -> None:
275
+ """
276
+ Set the state of the selected LED.
277
+
278
+ Example
279
+ -------
280
+ >>> device.set_led(ecodes.LED_NUML, 1)
281
+ """
282
+ self.write(ecodes.EV_LED, led_num, value)
283
+
284
+ def __eq__(self, other):
285
+ """
286
+ Two devices are equal if their :data:`info` attributes are equal.
287
+ """
288
+ return isinstance(other, self.__class__) and self.info == other.info and self.path == other.path
289
+
290
+ def __str__(self) -> str:
291
+ msg = 'device {}, name "{}", phys "{}", uniq "{}"'
292
+ return msg.format(self.path, self.name, self.phys, self.uniq or "")
293
+
294
+ def __repr__(self) -> str:
295
+ msg = (self.__class__.__name__, self.path)
296
+ return "{}({!r})".format(*msg)
297
+
298
+ def __fspath__(self):
299
+ return self.path
300
+
301
+ def close(self) -> None:
302
+ if self.fd > -1:
303
+ try:
304
+ super().close()
305
+ os.close(self.fd)
306
+ finally:
307
+ self.fd = -1
308
+
309
+ def grab(self) -> None:
310
+ """
311
+ Grab input device using ``EVIOCGRAB`` - other applications will
312
+ be unable to receive events until the device is released. Only
313
+ one process can hold a ``EVIOCGRAB`` on a device.
314
+
315
+ Warning
316
+ -------
317
+ Grabbing an already grabbed device will raise an ``OSError``.
318
+ """
319
+
320
+ _input.ioctl_EVIOCGRAB(self.fd, 1)
321
+
322
+ def ungrab(self) -> None:
323
+ """
324
+ Release device if it has been already grabbed (uses `EVIOCGRAB`).
325
+
326
+ Warning
327
+ -------
328
+ Releasing an already released device will raise an
329
+ ``OSError('Invalid argument')``.
330
+ """
331
+
332
+ _input.ioctl_EVIOCGRAB(self.fd, 0)
333
+
334
+ @contextlib.contextmanager
335
+ def grab_context(self) -> Iterator[None]:
336
+ """
337
+ A context manager for the duration of which only the current
338
+ process will be able to receive events from the device.
339
+ """
340
+ self.grab()
341
+ yield
342
+ self.ungrab()
343
+
344
+ def upload_effect(self, effect: "ff.Effect"):
345
+ """
346
+ Upload a force feedback effect to a force feedback device.
347
+ """
348
+
349
+ data = memoryview(effect).tobytes()
350
+ ff_id = _input.upload_effect(self.fd, data)
351
+ return ff_id
352
+
353
+ def erase_effect(self, ff_id) -> None:
354
+ """
355
+ Erase a force effect from a force feedback device. This also
356
+ stops the effect.
357
+ """
358
+
359
+ _input.erase_effect(self.fd, ff_id)
360
+
361
+ @property
362
+ def repeat(self):
363
+ """
364
+ Get or set the keyboard repeat rate (in characters per
365
+ minute) and delay (in milliseconds).
366
+ """
367
+
368
+ return KbdInfo(*_input.ioctl_EVIOCGREP(self.fd))
369
+
370
+ @repeat.setter
371
+ def repeat(self, value: Tuple[int, int]):
372
+ return _input.ioctl_EVIOCSREP(self.fd, *value)
373
+
374
+ def active_keys(self, verbose: bool = False):
375
+ """
376
+ Return currently active keys.
377
+
378
+ Example
379
+ -------
380
+
381
+ >>> device.active_keys()
382
+ [1, 42]
383
+
384
+ If ``verbose`` is ``True``, key codes are resolved to their
385
+ verbose names. Unknown codes are resolved to ``'?'``. For
386
+ example::
387
+
388
+ [('KEY_ESC', 1), ('KEY_LEFTSHIFT', 42)]
389
+
390
+ """
391
+ active_keys = _input.ioctl_EVIOCG_bits(self.fd, ecodes.EV_KEY)
392
+ if verbose:
393
+ return util.resolve_ecodes(ecodes.KEY, active_keys)
394
+
395
+ return active_keys
396
+
397
+ def absinfo(self, axis_num: int):
398
+ """
399
+ Return current :class:`AbsInfo` for input device axis
400
+
401
+ Arguments
402
+ ---------
403
+ axis_num : int
404
+ EV_ABS keycode (example :attr:`ecodes.ABS_X`)
405
+
406
+ Example
407
+ -------
408
+ >>> device.absinfo(ecodes.ABS_X)
409
+ AbsInfo(value=1501, min=-32768, max=32767, fuzz=0, flat=128, resolution=0)
410
+ """
411
+ return AbsInfo(*_input.ioctl_EVIOCGABS(self.fd, axis_num))
412
+
413
+ def set_absinfo(self, axis_num: int, value=None, min=None, max=None, fuzz=None, flat=None, resolution=None) -> None:
414
+ """
415
+ Update :class:`AbsInfo` values. Only specified values will be overwritten.
416
+
417
+ Arguments
418
+ ---------
419
+ axis_num : int
420
+ EV_ABS keycode (example :attr:`ecodes.ABS_X`)
421
+
422
+ Example
423
+ -------
424
+ >>> device.set_absinfo(ecodes.ABS_X, min=-2000, max=2000)
425
+
426
+ You can also unpack AbsInfo tuple that will overwrite all values
427
+
428
+ >>> device.set_absinfo(ecodes.ABS_Y, *AbsInfo(0, -2000, 2000, 0, 15, 0))
429
+ """
430
+
431
+ cur_absinfo = self.absinfo(axis_num)
432
+ new_absinfo = AbsInfo(
433
+ value if value is not None else cur_absinfo.value,
434
+ min if min is not None else cur_absinfo.min,
435
+ max if max is not None else cur_absinfo.max,
436
+ fuzz if fuzz is not None else cur_absinfo.fuzz,
437
+ flat if flat is not None else cur_absinfo.flat,
438
+ resolution if resolution is not None else cur_absinfo.resolution,
439
+ )
440
+ _input.ioctl_EVIOCSABS(self.fd, axis_num, new_absinfo)