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/uinput.py ADDED
@@ -0,0 +1,375 @@
1
+ import ctypes
2
+ import os
3
+ import platform
4
+ import re
5
+ import stat
6
+ import time
7
+ from collections import defaultdict
8
+ from typing import Union, Tuple, Dict, Sequence, Optional
9
+
10
+ from . import _uinput, ecodes, ff, util
11
+ from .device import InputDevice, AbsInfo
12
+ from .events import InputEvent
13
+
14
+ try:
15
+ from evdev.eventio_async import EventIO
16
+ except ImportError:
17
+ from evdev.eventio import EventIO
18
+
19
+
20
+ class UInputError(Exception):
21
+ pass
22
+
23
+
24
+ class UInput(EventIO):
25
+ """
26
+ A userland input device and that can inject input events into the
27
+ linux input subsystem.
28
+ """
29
+
30
+ __slots__ = (
31
+ "name",
32
+ "vendor",
33
+ "product",
34
+ "version",
35
+ "bustype",
36
+ "events",
37
+ "devnode",
38
+ "fd",
39
+ "device",
40
+ )
41
+
42
+ @classmethod
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
+ ):
49
+ """
50
+ Create an UInput device with the capabilities of one or more input
51
+ devices.
52
+
53
+ Arguments
54
+ ---------
55
+ devices : InputDevice|str
56
+ Varargs of InputDevice instances or paths to input devices.
57
+
58
+ filtered_types : Tuple[event type codes]
59
+ Event types to exclude from the capabilities of the uinput device.
60
+
61
+ **kwargs
62
+ Keyword arguments to UInput constructor (i.e. name, vendor etc.).
63
+ """
64
+
65
+ device_instances = []
66
+ for dev in devices:
67
+ if not isinstance(dev, InputDevice):
68
+ dev = InputDevice(str(dev))
69
+ device_instances.append(dev)
70
+
71
+ all_capabilities = defaultdict(set)
72
+
73
+ if "max_effects" not in kwargs:
74
+ kwargs["max_effects"] = min([dev.ff_effects_count for dev in device_instances])
75
+
76
+ # Merge the capabilities of all devices into one dictionary.
77
+ for dev in device_instances:
78
+ for ev_type, ev_codes in dev.capabilities().items():
79
+ all_capabilities[ev_type].update(ev_codes)
80
+
81
+ for evtype in filtered_types:
82
+ if evtype in all_capabilities:
83
+ del all_capabilities[evtype]
84
+
85
+ return cls(events=all_capabilities, **kwargs)
86
+
87
+ def __init__(
88
+ self,
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",
97
+ input_props=None,
98
+ # CentOS 7 has sufficiently old headers that FF_MAX_EFFECTS is not defined there,
99
+ # which causes the whole module to fail loading. Fallback on a hardcoded value of
100
+ # FF_MAX_EFFECTS if it is not defined in the ecodes.
101
+ max_effects=ecodes.ecodes.get("FF_MAX_EFFECTS", 96),
102
+ ):
103
+ """
104
+ Arguments
105
+ ---------
106
+ events : dict
107
+ Dictionary of event types mapping to lists of event codes. The
108
+ event types and codes that the uinput device will be able to
109
+ inject - defaults to all key codes.
110
+
111
+ name
112
+ The name of the input device.
113
+
114
+ vendor
115
+ Vendor identifier.
116
+
117
+ product
118
+ Product identifier.
119
+
120
+ version
121
+ Version identifier.
122
+
123
+ bustype
124
+ Bustype identifier.
125
+
126
+ phys
127
+ Physical path.
128
+
129
+ input_props
130
+ Input properties and quirks.
131
+
132
+ max_effects
133
+ Maximum simultaneous force-feedback effects.
134
+
135
+ Note
136
+ ----
137
+ If you do not specify any events, the uinput device will be able
138
+ to inject only ``KEY_*`` and ``BTN_*`` event codes.
139
+ """
140
+
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/``.
148
+
149
+ if not events:
150
+ events = {ecodes.EV_KEY: ecodes.keys.keys()}
151
+
152
+ self._verify()
153
+
154
+ #: Write-only, non-blocking file descriptor to the uinput device node.
155
+ self.fd = _uinput.open(devnode)
156
+
157
+ # Prepare the list of events for passing to _uinput.enable and _uinput.setup.
158
+ absinfo, prepared_events = self._prepare_events(events)
159
+
160
+ # Set phys name
161
+ _uinput.set_phys(self.fd, phys)
162
+
163
+ # Set properties
164
+ input_props = input_props or []
165
+ for prop in input_props:
166
+ _uinput.set_prop(self.fd, prop)
167
+
168
+ for etype, code in prepared_events:
169
+ _uinput.enable(self.fd, etype, code)
170
+
171
+ _uinput.setup(self.fd, name, vendor, product, version, bustype, absinfo, max_effects)
172
+
173
+ # Create the uinput device.
174
+ _uinput.create(self.fd)
175
+
176
+ self.dll = ctypes.CDLL(_uinput.__file__)
177
+ self.dll._uinput_begin_upload.restype = ctypes.c_int
178
+ self.dll._uinput_end_upload.restype = ctypes.c_int
179
+
180
+ #: An :class:`InputDevice <evdev.device.InputDevice>` instance
181
+ #: for the fake input device. ``None`` if the device cannot be
182
+ #: opened for reading and writing.
183
+ self.device: InputDevice = self._find_device(self.fd)
184
+
185
+ def _prepare_events(self, events):
186
+ """Prepare events for passing to _uinput.enable and _uinput.setup"""
187
+ absinfo, prepared_events = [], []
188
+ for etype, codes in events.items():
189
+ for code in codes:
190
+ # Handle max, min, fuzz, flat.
191
+ if isinstance(code, (tuple, list, AbsInfo)):
192
+ # Flatten (ABS_Y, (0, 255, 0, 0, 0, 0)) to (ABS_Y, 0, 255, 0, 0, 0, 0).
193
+ f = [code[0]]
194
+ f.extend(code[1])
195
+ # Ensure the tuple is always 6 ints long, since uinput.c:uinput_create
196
+ # does little in the way of checking the length.
197
+ f.extend([0] * (6 - len(code[1])))
198
+ absinfo.append(f)
199
+ code = code[0]
200
+ prepared_events.append((etype, code))
201
+ return absinfo, prepared_events
202
+
203
+ def __enter__(self):
204
+ return self
205
+
206
+ def __exit__(self, type, value, tb):
207
+ if hasattr(self, "fd"):
208
+ self.close()
209
+
210
+ def __repr__(self):
211
+ # TODO:
212
+ v = (repr(getattr(self, i)) for i in ("name", "bustype", "vendor", "product", "version", "phys"))
213
+ return "{}({})".format(self.__class__.__name__, ", ".join(v))
214
+
215
+ def __str__(self):
216
+ msg = 'name "{}", bus "{}", vendor "{:04x}", product "{:04x}", version "{:04x}", phys "{}"\nevent types: {}'
217
+
218
+ evtypes = [i[0] for i in self.capabilities(True).keys()]
219
+ msg = msg.format(
220
+ self.name, ecodes.BUS[self.bustype], self.vendor, self.product, self.version, self.phys, " ".join(evtypes)
221
+ )
222
+
223
+ return msg
224
+
225
+ def close(self):
226
+ # Close the associated InputDevice, if it was previously opened.
227
+ if self.device is not None:
228
+ self.device.close()
229
+
230
+ # Destroy the uinput device.
231
+ if self.fd > -1:
232
+ _uinput.close(self.fd)
233
+ self.fd = -1
234
+
235
+ def capabilities(self, verbose: bool = False, absinfo: bool = True):
236
+ """See :func:`capabilities <evdev.device.InputDevice.capabilities>`."""
237
+ if self.device is None:
238
+ raise UInputError("input device not opened - cannot read capabilities")
239
+
240
+ return self.device.capabilities(verbose, absinfo)
241
+
242
+ def begin_upload(self, effect_id):
243
+ upload = ff.UInputUpload()
244
+ upload.effect_id = effect_id
245
+
246
+ ret = self.dll._uinput_begin_upload(self.fd, ctypes.byref(upload))
247
+ if ret:
248
+ raise UInputError("Failed to begin uinput upload: " + os.strerror(ret))
249
+
250
+ return upload
251
+
252
+ def end_upload(self, upload):
253
+ ret = self.dll._uinput_end_upload(self.fd, ctypes.byref(upload))
254
+ if ret:
255
+ raise UInputError("Failed to end uinput upload: " + os.strerror(ret))
256
+
257
+ def begin_erase(self, effect_id):
258
+ erase = ff.UInputErase()
259
+ erase.effect_id = effect_id
260
+
261
+ ret = self.dll._uinput_begin_erase(self.fd, ctypes.byref(erase))
262
+ if ret:
263
+ raise UInputError("Failed to begin uinput erase: " + os.strerror(ret))
264
+ return erase
265
+
266
+ def end_erase(self, erase):
267
+ ret = self.dll._uinput_end_erase(self.fd, ctypes.byref(erase))
268
+ if ret:
269
+ raise UInputError("Failed to end uinput erase: " + os.strerror(ret))
270
+
271
+ def _verify(self):
272
+ """
273
+ Verify that an uinput device exists and is readable and writable
274
+ by the current process.
275
+ """
276
+ try:
277
+ m = os.stat(self.devnode)[stat.ST_MODE]
278
+ assert stat.S_ISCHR(m)
279
+ except (IndexError, OSError, AssertionError):
280
+ msg = '"{}" does not exist or is not a character device file - verify that the uinput module is loaded'
281
+ raise UInputError(msg.format(self.devnode))
282
+
283
+ if not os.access(self.devnode, os.W_OK):
284
+ msg = '"{}" cannot be opened for writing'
285
+ raise UInputError(msg.format(self.devnode))
286
+
287
+ if len(self.name) > _uinput.maxnamelen:
288
+ msg = "uinput device name must not be longer than {} characters"
289
+ raise UInputError(msg.format(_uinput.maxnamelen))
290
+
291
+ def _find_device(self, fd: int) -> InputDevice:
292
+ """
293
+ Tries to find the device node. Will delegate this task to one of
294
+ several platform-specific functions.
295
+ """
296
+ if platform.system() == "Linux":
297
+ try:
298
+ sysname = _uinput.get_sysname(fd)
299
+ return self._find_device_linux(sysname)
300
+ except OSError:
301
+ # UI_GET_SYSNAME returned an error code. We're likely dealing with
302
+ # an old kernel. Guess the device based on the filesystem.
303
+ pass
304
+
305
+ # If we're not running or Linux or the above method fails for any reason,
306
+ # use the generic fallback method.
307
+ return self._find_device_fallback()
308
+
309
+ def _find_device_linux(self, sysname: str) -> InputDevice:
310
+ """
311
+ Tries to find the device node when running on Linux.
312
+ """
313
+
314
+ syspath = f"/sys/devices/virtual/input/{sysname}"
315
+
316
+ # The sysfs entry for event devices should contain exactly one folder
317
+ # whose name matches the format "event[0-9]+". It is then assumed that
318
+ # the device node in /dev/input uses the same name.
319
+ regex = re.compile("event[0-9]+")
320
+ for entry in os.listdir(syspath):
321
+ if regex.fullmatch(entry):
322
+ device_path = f"/dev/input/{entry}"
323
+ break
324
+ else: # no break
325
+ raise FileNotFoundError()
326
+
327
+ # It is possible that there is some delay before /dev/input/event* shows
328
+ # up on old systems that do not use devtmpfs, so if the device cannot be
329
+ # found, wait for a short amount and then try again once.
330
+ #
331
+ # Furthermore, even if devtmpfs is in use, it is possible that the device
332
+ # does show up immediately, but without the correct permissions that
333
+ # still need to be set by udev. Wait for up to two seconds for either the
334
+ # device to show up or the permissions to be set.
335
+ for attempt in range(19):
336
+ try:
337
+ return InputDevice(device_path)
338
+ except (FileNotFoundError, PermissionError):
339
+ time.sleep(0.1)
340
+
341
+ # Last attempt. If this fails, whatever exception the last attempt raises
342
+ # shall be the exception that this function raises.
343
+ return InputDevice(device_path)
344
+
345
+ def _find_device_fallback(self) -> Union[InputDevice, None]:
346
+ """
347
+ Tries to find the device node when UI_GET_SYSNAME is not available or
348
+ we're running on a system sufficiently exotic that we do not know how
349
+ to interpret its return value.
350
+ """
351
+ #:bug: the device node might not be immediately available
352
+ time.sleep(0.1)
353
+
354
+ # There could also be another device with the same name already present,
355
+ # make sure to select the newest one.
356
+ # Strictly speaking, we cannot be certain that everything returned by list_devices()
357
+ # ends at event[0-9]+: it might return something like "/dev/input/events_all". Find
358
+ # the devices that have the expected structure and extract their device number.
359
+ path_number_pairs = []
360
+ regex = re.compile("/dev/input/event([0-9]+)")
361
+ for path in util.list_devices("/dev/input/"):
362
+ regex_match = regex.fullmatch(path)
363
+ if not regex_match:
364
+ continue
365
+ device_number = int(regex_match[1])
366
+ path_number_pairs.append((path, device_number))
367
+
368
+ # The modification date of the devnode is not reliable unfortunately, so we
369
+ # are sorting by the number in the name
370
+ path_number_pairs.sort(key=lambda pair: pair[1], reverse=True)
371
+
372
+ for path, _ in path_number_pairs:
373
+ d = InputDevice(path)
374
+ if d.name == self.name:
375
+ return d
evdev/util.py ADDED
@@ -0,0 +1,146 @@
1
+ import collections
2
+ import glob
3
+ import os
4
+ import re
5
+ import stat
6
+ from typing import Union, List
7
+
8
+ from . import ecodes
9
+ from .events import InputEvent, event_factory, KeyEvent, RelEvent, AbsEvent, SynEvent
10
+
11
+
12
+ def list_devices(input_device_dir: Union[str, bytes, os.PathLike] = "/dev/input") -> List[str]:
13
+ """List readable character devices in ``input_device_dir``."""
14
+
15
+ fns = glob.glob("{}/event*".format(input_device_dir))
16
+ return list(filter(is_device, fns))
17
+
18
+
19
+ def is_device(fn: Union[str, bytes, os.PathLike]) -> bool:
20
+ """Check if ``fn`` is a readable and writable character device."""
21
+
22
+ if not os.path.exists(fn):
23
+ return False
24
+
25
+ m = os.stat(fn)[stat.ST_MODE]
26
+ if not stat.S_ISCHR(m):
27
+ return False
28
+
29
+ if not os.access(fn, os.R_OK | os.W_OK):
30
+ return False
31
+
32
+ return True
33
+
34
+
35
+ def categorize(event: InputEvent) -> Union[InputEvent, KeyEvent, RelEvent, AbsEvent, SynEvent]:
36
+ """
37
+ Categorize an event according to its type.
38
+
39
+ The :data:`event_factory <evdev.events.event_factory>` dictionary
40
+ maps event types to sub-classes of :class:`InputEvent
41
+ <evdev.events.InputEvent>`. If the event cannot be categorized, it
42
+ is returned unmodified."""
43
+
44
+ if event.type in event_factory:
45
+ return event_factory[event.type](event)
46
+ else:
47
+ return event
48
+
49
+
50
+ def resolve_ecodes_dict(typecodemap, unknown="?"):
51
+ """
52
+ Resolve event codes and types to their verbose names.
53
+
54
+ :param typecodemap: mapping of event types to lists of event codes.
55
+ :param unknown: symbol to which unknown types or codes will be resolved.
56
+
57
+ Example
58
+ -------
59
+ >>> resolve_ecodes_dict({ 1: [272, 273, 274] })
60
+ { ('EV_KEY', 1): [('BTN_MOUSE', 272),
61
+ ('BTN_RIGHT', 273),
62
+ ('BTN_MIDDLE', 274)] }
63
+
64
+ If ``typecodemap`` contains absolute axis info (instances of
65
+ :class:`AbsInfo <evdev.device.AbsInfo>` ) the result would look
66
+ like:
67
+
68
+ >>> resolve_ecodes_dict({ 3: [(0, AbsInfo(...))] })
69
+ { ('EV_ABS', 3L): [(('ABS_X', 0L), AbsInfo(...))] }
70
+ """
71
+
72
+ for etype, codes in typecodemap.items():
73
+ type_name = ecodes.EV[etype]
74
+
75
+ # ecodes.keys are a combination of KEY_ and BTN_ codes
76
+ if etype == ecodes.EV_KEY:
77
+ ecode_dict = ecodes.keys
78
+ else:
79
+ ecode_dict = getattr(ecodes, type_name.split("_")[-1])
80
+
81
+ resolved = resolve_ecodes(ecode_dict, codes, unknown)
82
+ yield (type_name, etype), resolved
83
+
84
+
85
+ def resolve_ecodes(ecode_dict, ecode_list, unknown="?"):
86
+ """
87
+ Resolve event codes and types to their verbose names.
88
+
89
+ Example
90
+ -------
91
+ >>> resolve_ecodes(ecodes.BTN, [272, 273, 274])
92
+ [(['BTN_LEFT', 'BTN_MOUSE'], 272), ('BTN_RIGHT', 273), ('BTN_MIDDLE', 274)]
93
+ """
94
+ res = []
95
+ for ecode in ecode_list:
96
+ # elements with AbsInfo(), eg { 3 : [(0, AbsInfo(...)), (1, AbsInfo(...))] }
97
+ if isinstance(ecode, tuple):
98
+ if ecode[0] in ecode_dict:
99
+ l = ((ecode_dict[ecode[0]], ecode[0]), ecode[1])
100
+ else:
101
+ l = ((unknown, ecode[0]), ecode[1])
102
+
103
+ # just ecodes, e.g: { 0 : [0, 1, 3], 1 : [30, 48] }
104
+ else:
105
+ if ecode in ecode_dict:
106
+ l = (ecode_dict[ecode], ecode)
107
+ else:
108
+ l = (unknown, ecode)
109
+ res.append(l)
110
+
111
+ return res
112
+
113
+
114
+ def find_ecodes_by_regex(regex):
115
+ """
116
+ Find ecodes matching a regex and return a mapping of event type to event codes.
117
+
118
+ regex can be a pattern string or a compiled regular expression object.
119
+
120
+ Example
121
+ -------
122
+ >>> find_ecodes_by_regex(r'(ABS|KEY)_BR(AKE|EAK)')
123
+ {1: [411], 3: [10]}
124
+ >>> res = find_ecodes_by_regex(r'(ABS|KEY)_BR(AKE|EAK)')
125
+ >>> resolve_ecodes_dict(res)
126
+ {
127
+ ('EV_KEY', 1): [('KEY_BREAK', 411)],
128
+ ('EV_ABS', 3): [('ABS_BRAKE', 10)]
129
+ }
130
+ """
131
+
132
+ regex = re.compile(regex) # re.compile is idempotent
133
+ result = collections.defaultdict(list)
134
+
135
+ for type_code, codes in ecodes.bytype.items():
136
+ for code, names in codes.items():
137
+ names = (names,) if isinstance(names, str) else names
138
+ for name in names:
139
+ if regex.match(name):
140
+ result[type_code].append(code)
141
+ break
142
+
143
+ return dict(result)
144
+
145
+
146
+ __all__ = ("list_devices", "is_device", "categorize", "resolve_ecodes", "resolve_ecodes_dict", "find_ecodes_by_regex")
@@ -0,0 +1,48 @@
1
+ Metadata-Version: 2.4
2
+ Name: evdev-binary
3
+ Version: 1.9.3
4
+ Summary: Bindings to the Linux input handling subsystem
5
+ Author-email: Georgi Valkov <georgi.t.valkov@gmail.com>
6
+ Maintainer-email: Tobi <proxima@sezanzeb.de>
7
+ License-Expression: BSD-3-Clause
8
+ Project-URL: Homepage, https://github.com/gvalkov/python-evdev
9
+ Keywords: evdev,input,uinput
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Operating System :: POSIX :: Linux
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Topic :: Software Development :: Libraries
15
+ Classifier: Programming Language :: Python :: Implementation :: CPython
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Dynamic: license-file
20
+
21
+ # evdev
22
+
23
+ <p>
24
+ <a href="https://pypi.python.org/pypi/evdev"><img alt="pypi version" src="https://img.shields.io/pypi/v/evdev.svg"></a>
25
+ <a href="https://github.com/gvalkov/python-evdev/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/evdev"></a>
26
+ <a href="https://repology.org/project/python:evdev/versions"><img alt="Packaging status" src="https://repology.org/badge/tiny-repos/python:evdev.svg"></a>
27
+ </p>
28
+
29
+ This package provides bindings to the generic input event interface in Linux.
30
+ The *evdev* interface serves the purpose of passing events generated in the
31
+ kernel directly to userspace through character devices that are typically
32
+ located in `/dev/input/`.
33
+
34
+ This package also comes with bindings to *uinput*, the userspace input
35
+ subsystem. *Uinput* allows userspace programs to create and handle input devices
36
+ that can inject events directly into the input subsystem.
37
+
38
+ ***Documentation:***
39
+ https://python-evdev.readthedocs.io/en/latest/
40
+
41
+ ***Development:***
42
+ https://github.com/gvalkov/python-evdev
43
+
44
+ ***Package:***
45
+ https://pypi.python.org/pypi/evdev
46
+
47
+ ***Changelog:***
48
+ https://python-evdev.readthedocs.io/en/latest/changelog.html
@@ -0,0 +1,24 @@
1
+ evdev/__init__.py,sha256=cu0Qu3CK4loreHKefFqudMmHQP-P-rkXSjrzjxHUCbw,1011
2
+ evdev/_ecodes.cpython-314-x86_64-linux-musl.so,sha256=fINhj1cMccNnQk2fN76xPdB9wh3nNgH1xmn4qpI8Sko,86800
3
+ evdev/_input.cpython-314-x86_64-linux-musl.so,sha256=PqZTiWeavzAIZtuqz_cEu_k7qEmbYK0RTJ7VW-Ugt8s,50232
4
+ evdev/_uinput.cpython-314-x86_64-linux-musl.so,sha256=fGGNoGqLKvAYdxM5v6wCWRcvi9WaQNIJEBMIQoH25ZI,35840
5
+ evdev/device.py,sha256=8sKHGmZh3DF1lJpsIy0pF1R9L5qGzazFGretaysu1Os,12959
6
+ evdev/ecodes.py,sha256=_AVTtsN9w5f4M74FQgbxwAQPOedmCqVts0TCX4AE6Yw,98110
7
+ evdev/ecodes_runtime.py,sha256=_QR3aSjX3pbwrk0f1dA-tXjiECKtV_uPpUtXpWP_cTI,2838
8
+ evdev/eventio.py,sha256=4SnIINjPJadQChUEy_1lbTzuTORsydDC7zL2qkegTIY,4422
9
+ evdev/eventio_async.py,sha256=B1qaEKYoiiop8YpG0AFf0lu2Im3CvW50dRPLug40xWA,3078
10
+ evdev/events.py,sha256=_0vXzjv8yFtJR9drfwhmBZl9w4ZmfwQhgCo3WcrWi-Q,5905
11
+ evdev/evtest.py,sha256=u0umJIV_HQUDlbBhLvXEKZ87UZqNIhk0XJRcm5VYIzg,5543
12
+ evdev/ff.py,sha256=1B1VJ8TJ_CpJ01Qi4tUym1p8qZK_HKQSZvvhA8ROoJY,4961
13
+ evdev/genecodes_c.py,sha256=_AhMK1iOQlkykOSzkbCbCJfZTk_dDU-jLsL_7FhYUqM,3618
14
+ evdev/genecodes_py.py,sha256=-FuU-qy4-C_q7xkSwJICwMbCmAxyvezwSU4L2SRqwAs,1996
15
+ evdev/input.c,sha256=wINgUFPAcFAsjnXaQja3Pr_4h-u4RsX2cEb_IfyvOdk,16346
16
+ evdev/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ evdev/uinput.c,sha256=9CkdJwL57R-qxaBS3T6vCJq9rC2KrRQK7BTHforK4XI,10188
18
+ evdev/uinput.py,sha256=vJb5E0ThptDo6HeB0mc74zFXkh3_oW7a5amn-jhWo9U,13363
19
+ evdev/util.py,sha256=WzgxwgjBuCE25n6UNPk91Bg2_j6weGUv1VO3vfyX8xU,4409
20
+ evdev_binary-1.9.3.dist-info/METADATA,sha256=83J31v0SCp-axino0tX-Nm5UR8CPjqWsIoxLhiIJ46s,1940
21
+ evdev_binary-1.9.3.dist-info/WHEEL,sha256=NmqaxmnfrP7aluxNMb6qEOEbyuTWfFfbybJv9PXNQu4,113
22
+ evdev_binary-1.9.3.dist-info/top_level.txt,sha256=tgRM-peDJTah3Is39Micsqkx31ek4FTHG4usyN23Xsk,6
23
+ evdev_binary-1.9.3.dist-info/RECORD,,
24
+ evdev_binary-1.9.3.dist-info/licenses/LICENSE,sha256=1FVJYNZJYVDIjB_QLXlzEhqaV7lh6lj-NJ-_ito4FrI,1507
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: false
4
+ Tag: cp314-cp314-musllinux_1_2_x86_64
5
+
@@ -0,0 +1,29 @@
1
+ Copyright (c) 2012-2025 Georgi Valkov. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are
5
+ met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in
12
+ the documentation and/or other materials provided with the
13
+ distribution.
14
+
15
+ 3. Neither the name of author nor the names of its contributors may
16
+ be used to endorse or promote products derived from this software
17
+ without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
23
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ evdev