evdev 1.7.0__tar.gz → 1.8.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.7.0 → evdev-1.8.0}/LICENSE +1 -1
- {evdev-1.7.0 → evdev-1.8.0}/MANIFEST.in +1 -0
- {evdev-1.7.0/evdev.egg-info → evdev-1.8.0}/PKG-INFO +26 -22
- evdev-1.8.0/README.md +28 -0
- evdev-1.8.0/evdev/__init__.py +9 -0
- {evdev-1.7.0 → evdev-1.8.0}/evdev/device.py +10 -11
- evdev-1.8.0/evdev/ecodes.py +5 -0
- evdev-1.7.0/evdev/ecodes.py → evdev-1.8.0/evdev/ecodes_runtime.py +15 -5
- {evdev-1.7.0 → evdev-1.8.0}/evdev/eventio.py +15 -4
- {evdev-1.7.0 → evdev-1.8.0}/evdev/eventio_async.py +2 -2
- {evdev-1.7.0 → evdev-1.8.0}/evdev/events.py +14 -13
- {evdev-1.7.0 → evdev-1.8.0}/evdev/evtest.py +4 -10
- {evdev-1.7.0 → evdev-1.8.0}/evdev/ff.py +1 -1
- evdev-1.8.0/evdev/genecodes_c.py +138 -0
- evdev-1.8.0/evdev/genecodes_py.py +53 -0
- {evdev-1.7.0 → evdev-1.8.0}/evdev/uinput.c +2 -0
- {evdev-1.7.0 → evdev-1.8.0}/evdev/uinput.py +24 -25
- {evdev-1.7.0 → evdev-1.8.0}/evdev/util.py +5 -5
- {evdev-1.7.0 → evdev-1.8.0/evdev.egg-info}/PKG-INFO +26 -22
- {evdev-1.7.0 → evdev-1.8.0}/evdev.egg-info/SOURCES.txt +4 -2
- {evdev-1.7.0 → evdev-1.8.0}/pyproject.toml +14 -5
- {evdev-1.7.0 → evdev-1.8.0}/setup.py +25 -8
- {evdev-1.7.0 → evdev-1.8.0}/tests/test_uinput.py +27 -6
- evdev-1.7.0/README.rst +0 -24
- evdev-1.7.0/evdev/__init__.py +0 -10
- evdev-1.7.0/evdev/genecodes.py +0 -96
- {evdev-1.7.0 → evdev-1.8.0}/evdev/input.c +0 -0
- {evdev-1.7.0 → evdev-1.8.0}/evdev.egg-info/dependency_links.txt +0 -0
- {evdev-1.7.0 → evdev-1.8.0}/evdev.egg-info/top_level.txt +0 -0
- {evdev-1.7.0 → evdev-1.8.0}/setup.cfg +0 -0
- {evdev-1.7.0 → evdev-1.8.0}/tests/test_ecodes.py +0 -0
- {evdev-1.7.0 → evdev-1.8.0}/tests/test_events.py +0 -0
- {evdev-1.7.0 → evdev-1.8.0}/tests/test_util.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: evdev
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: Bindings to the Linux input handling subsystem
|
|
5
5
|
Author-email: Georgi Valkov <georgi.t.valkov@gmail.com>
|
|
6
6
|
Maintainer-email: Tobi <proxima@sezanzeb.de>
|
|
7
|
-
License: Copyright (c) 2012-
|
|
7
|
+
License: Copyright (c) 2012-2025 Georgi Valkov. All rights reserved.
|
|
8
8
|
|
|
9
9
|
Redistribution and use in source and binary forms, with or without
|
|
10
10
|
modification, are permitted provided that the following conditions are
|
|
@@ -43,31 +43,35 @@ Classifier: Intended Audience :: Developers
|
|
|
43
43
|
Classifier: Topic :: Software Development :: Libraries
|
|
44
44
|
Classifier: License :: OSI Approved :: BSD License
|
|
45
45
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
46
|
-
Requires-Python: >=3.
|
|
47
|
-
Description-Content-Type: text/
|
|
46
|
+
Requires-Python: >=3.8
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
48
|
License-File: LICENSE
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
-------
|
|
50
|
+
# evdev
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
<p>
|
|
53
|
+
<a href="https://pypi.python.org/pypi/evdev"><img alt="pypi version" src="https://img.shields.io/pypi/v/evdev.svg"></a>
|
|
54
|
+
<a href="https://github.com/gvalkov/python-evdev/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/evdev"></a>
|
|
55
|
+
<a href="https://repology.org/project/python:evdev/versions"><img alt="Packaging status" src="https://repology.org/badge/tiny-repos/python:evdev.svg"></a>
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
This package provides bindings to the generic input event interface in Linux.
|
|
59
|
+
The *evdev* interface serves the purpose of passing events generated in the
|
|
60
|
+
kernel directly to userspace through character devices that are typically
|
|
61
|
+
located in `/dev/input/`.
|
|
57
62
|
|
|
58
63
|
This package also comes with bindings to *uinput*, the userspace input
|
|
59
|
-
subsystem. *Uinput* allows userspace programs to create and handle
|
|
60
|
-
|
|
61
|
-
subsystem.
|
|
64
|
+
subsystem. *Uinput* allows userspace programs to create and handle input devices
|
|
65
|
+
that can inject events directly into the input subsystem.
|
|
62
66
|
|
|
63
|
-
Documentation
|
|
64
|
-
|
|
67
|
+
***Documentation:***
|
|
68
|
+
https://python-evdev.readthedocs.io/en/latest/
|
|
65
69
|
|
|
66
|
-
Development
|
|
67
|
-
|
|
70
|
+
***Development:***
|
|
71
|
+
https://github.com/gvalkov/python-evdev
|
|
68
72
|
|
|
69
|
-
Package
|
|
70
|
-
|
|
73
|
+
***Package:***
|
|
74
|
+
https://pypi.python.org/pypi/evdev
|
|
71
75
|
|
|
72
|
-
Changelog
|
|
73
|
-
|
|
76
|
+
***Changelog:***
|
|
77
|
+
https://python-evdev.readthedocs.io/en/latest/changelog.html
|
evdev-1.8.0/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# evdev
|
|
2
|
+
|
|
3
|
+
<p>
|
|
4
|
+
<a href="https://pypi.python.org/pypi/evdev"><img alt="pypi version" src="https://img.shields.io/pypi/v/evdev.svg"></a>
|
|
5
|
+
<a href="https://github.com/gvalkov/python-evdev/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/evdev"></a>
|
|
6
|
+
<a href="https://repology.org/project/python:evdev/versions"><img alt="Packaging status" src="https://repology.org/badge/tiny-repos/python:evdev.svg"></a>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
This package provides bindings to the generic input event interface in Linux.
|
|
10
|
+
The *evdev* interface serves the purpose of passing events generated in the
|
|
11
|
+
kernel directly to userspace through character devices that are typically
|
|
12
|
+
located in `/dev/input/`.
|
|
13
|
+
|
|
14
|
+
This package also comes with bindings to *uinput*, the userspace input
|
|
15
|
+
subsystem. *Uinput* allows userspace programs to create and handle input devices
|
|
16
|
+
that can inject events directly into the input subsystem.
|
|
17
|
+
|
|
18
|
+
***Documentation:***
|
|
19
|
+
https://python-evdev.readthedocs.io/en/latest/
|
|
20
|
+
|
|
21
|
+
***Development:***
|
|
22
|
+
https://github.com/gvalkov/python-evdev
|
|
23
|
+
|
|
24
|
+
***Package:***
|
|
25
|
+
https://pypi.python.org/pypi/evdev
|
|
26
|
+
|
|
27
|
+
***Changelog:***
|
|
28
|
+
https://python-evdev.readthedocs.io/en/latest/changelog.html
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# --------------------------------------------------------------------------
|
|
2
|
+
# Gather everything into a single, convenient namespace.
|
|
3
|
+
# --------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
from . import ecodes, ff
|
|
6
|
+
from .device import AbsInfo, DeviceInfo, EvdevError, InputDevice
|
|
7
|
+
from .events import AbsEvent, InputEvent, KeyEvent, RelEvent, SynEvent, event_factory
|
|
8
|
+
from .uinput import UInput, UInputError
|
|
9
|
+
from .util import categorize, list_devices, resolve_ecodes, resolve_ecodes_dict
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
|
+
import collections
|
|
4
|
+
import contextlib
|
|
3
5
|
import os
|
|
4
6
|
import warnings
|
|
5
|
-
import contextlib
|
|
6
|
-
import collections
|
|
7
7
|
|
|
8
|
-
from
|
|
9
|
-
from evdev.events import InputEvent
|
|
8
|
+
from . import _input, ecodes, util
|
|
10
9
|
|
|
11
10
|
try:
|
|
12
|
-
from
|
|
11
|
+
from .eventio_async import EvdevError, EventIO
|
|
13
12
|
except ImportError:
|
|
14
|
-
from
|
|
13
|
+
from .eventio import EvdevError, EventIO
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
# --------------------------------------------------------------------------
|
|
18
17
|
_AbsInfo = collections.namedtuple("AbsInfo", ["value", "min", "max", "fuzz", "flat", "resolution"])
|
|
19
18
|
|
|
20
|
-
_KbdInfo = collections.namedtuple("KbdInfo", ["
|
|
19
|
+
_KbdInfo = collections.namedtuple("KbdInfo", ["delay", "repeat"])
|
|
21
20
|
|
|
22
21
|
_DeviceInfo = collections.namedtuple("DeviceInfo", ["bustype", "vendor", "product", "version"])
|
|
23
22
|
|
|
@@ -70,16 +69,16 @@ class KbdInfo(_KbdInfo):
|
|
|
70
69
|
|
|
71
70
|
Attributes
|
|
72
71
|
----------
|
|
73
|
-
repeat
|
|
74
|
-
Keyboard repeat rate in characters per second.
|
|
75
|
-
|
|
76
72
|
delay
|
|
77
73
|
Amount of time that a key must be depressed before it will start
|
|
78
74
|
to repeat (in milliseconds).
|
|
75
|
+
|
|
76
|
+
repeat
|
|
77
|
+
Keyboard repeat rate in characters per second.
|
|
79
78
|
"""
|
|
80
79
|
|
|
81
80
|
def __str__(self):
|
|
82
|
-
return "
|
|
81
|
+
return "delay {}, repeat {}".format(*self)
|
|
83
82
|
|
|
84
83
|
|
|
85
84
|
class DeviceInfo(_DeviceInfo):
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=undefined-variable
|
|
1
2
|
"""
|
|
2
3
|
This modules exposes the integer constants defined in ``linux/input.h`` and
|
|
3
4
|
``linux/input-event-codes.h``.
|
|
@@ -32,26 +33,26 @@ Keep in mind that values in reverse mappings may point to one or more event
|
|
|
32
33
|
codes. For example::
|
|
33
34
|
|
|
34
35
|
>>> evdev.ecodes.FF[80]
|
|
35
|
-
|
|
36
|
+
('FF_EFFECT_MIN', 'FF_RUMBLE')
|
|
36
37
|
|
|
37
38
|
>>> evdev.ecodes.FF[81]
|
|
38
39
|
'FF_PERIODIC'
|
|
39
40
|
"""
|
|
40
41
|
|
|
41
42
|
from inspect import getmembers
|
|
42
|
-
from evdev import _ecodes
|
|
43
43
|
|
|
44
|
+
from . import _ecodes
|
|
44
45
|
|
|
45
46
|
#: Mapping of names to values.
|
|
46
47
|
ecodes = {}
|
|
47
48
|
|
|
48
|
-
prefixes = "KEY ABS REL SW MSC LED BTN REP SND ID EV BUS SYN FF_STATUS FF INPUT_PROP"
|
|
49
|
+
prefixes = "KEY ABS REL SW MSC LED BTN REP SND ID EV BUS SYN FF_STATUS FF INPUT_PROP".split()
|
|
49
50
|
prev_prefix = ""
|
|
50
51
|
g = globals()
|
|
51
52
|
|
|
52
53
|
# eg. code: 'REL_Z', val: 2
|
|
53
54
|
for code, val in getmembers(_ecodes):
|
|
54
|
-
for prefix in prefixes
|
|
55
|
+
for prefix in prefixes: # eg. 'REL'
|
|
55
56
|
if code.startswith(prefix):
|
|
56
57
|
ecodes[code] = val
|
|
57
58
|
# FF_STATUS codes should not appear in the FF reverse mapping
|
|
@@ -70,6 +71,15 @@ for code, val in getmembers(_ecodes):
|
|
|
70
71
|
|
|
71
72
|
prev_prefix = prefix
|
|
72
73
|
|
|
74
|
+
|
|
75
|
+
# Convert lists to tuples.
|
|
76
|
+
k, v = None, None
|
|
77
|
+
for prefix in prefixes:
|
|
78
|
+
for k, v in g[prefix].items():
|
|
79
|
+
if isinstance(v, list):
|
|
80
|
+
g[prefix][k] = tuple(v)
|
|
81
|
+
|
|
82
|
+
|
|
73
83
|
#: Keys are a combination of all BTN and KEY codes.
|
|
74
84
|
keys = {}
|
|
75
85
|
keys.update(BTN)
|
|
@@ -98,4 +108,4 @@ bytype = {
|
|
|
98
108
|
from evdev._ecodes import *
|
|
99
109
|
|
|
100
110
|
# cheaper than whitelisting in an __all__
|
|
101
|
-
del code, val, prefix, getmembers, g, d, prefixes, prev_prefix
|
|
111
|
+
del code, val, prefix, getmembers, g, d, k, v, prefixes, prev_prefix
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import fcntl
|
|
3
|
-
import select
|
|
4
2
|
import functools
|
|
3
|
+
import os
|
|
4
|
+
import select
|
|
5
5
|
|
|
6
|
-
from
|
|
7
|
-
from
|
|
6
|
+
from . import _input, _uinput, ecodes
|
|
7
|
+
from .events import InputEvent
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
# --------------------------------------------------------------------------
|
|
@@ -72,6 +72,7 @@ class EventIO:
|
|
|
72
72
|
for event in events:
|
|
73
73
|
yield InputEvent(*event)
|
|
74
74
|
|
|
75
|
+
# pylint: disable=no-self-argument
|
|
75
76
|
def need_write(func):
|
|
76
77
|
"""
|
|
77
78
|
Decorator that raises :class:`EvdevError` if there is no write access to the
|
|
@@ -82,6 +83,7 @@ class EventIO:
|
|
|
82
83
|
def wrapper(*args):
|
|
83
84
|
fd = args[0].fd
|
|
84
85
|
if fcntl.fcntl(fd, fcntl.F_GETFL) & os.O_RDWR:
|
|
86
|
+
# pylint: disable=not-callable
|
|
85
87
|
return func(*args)
|
|
86
88
|
msg = 'no write access to device "%s"' % args[0].path
|
|
87
89
|
raise EvdevError(msg)
|
|
@@ -136,5 +138,14 @@ class EventIO:
|
|
|
136
138
|
|
|
137
139
|
_uinput.write(self.fd, etype, code, value)
|
|
138
140
|
|
|
141
|
+
def syn(self):
|
|
142
|
+
"""
|
|
143
|
+
Inject a ``SYN_REPORT`` event into the input subsystem. Events
|
|
144
|
+
queued by :func:`write()` will be fired. If possible, events
|
|
145
|
+
will be merged into an 'atomic' event.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
self.write(ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
|
|
149
|
+
|
|
139
150
|
def close(self):
|
|
140
151
|
pass
|
|
@@ -37,7 +37,8 @@ methods::
|
|
|
37
37
|
# event type descriptions have been taken mot-a-mot from:
|
|
38
38
|
# http://www.kernel.org/doc/Documentation/input/event-codes.txt
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
# pylint: disable=no-name-in-module
|
|
41
|
+
from .ecodes import ABS, EV_ABS, EV_KEY, EV_REL, EV_SYN, KEY, REL, SYN, keys
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
class InputEvent:
|
|
@@ -65,13 +66,13 @@ class InputEvent:
|
|
|
65
66
|
"""Return event timestamp as a float."""
|
|
66
67
|
return self.sec + (self.usec / 1000000.0)
|
|
67
68
|
|
|
68
|
-
def __str__(
|
|
69
|
+
def __str__(self):
|
|
69
70
|
msg = "event at {:f}, code {:02d}, type {:02d}, val {:02d}"
|
|
70
|
-
return msg.format(
|
|
71
|
+
return msg.format(self.timestamp(), self.code, self.type, self.value)
|
|
71
72
|
|
|
72
|
-
def __repr__(
|
|
73
|
+
def __repr__(self):
|
|
73
74
|
msg = "{}({!r}, {!r}, {!r}, {!r}, {!r})"
|
|
74
|
-
return msg.format(
|
|
75
|
+
return msg.format(self.__class__.__name__, self.sec, self.usec, self.type, self.code, self.value)
|
|
75
76
|
|
|
76
77
|
|
|
77
78
|
class KeyEvent:
|
|
@@ -119,8 +120,8 @@ class KeyEvent:
|
|
|
119
120
|
msg = "key event at {:f}, {} ({}), {}"
|
|
120
121
|
return msg.format(self.event.timestamp(), self.scancode, self.keycode, ks)
|
|
121
122
|
|
|
122
|
-
def __repr__(
|
|
123
|
-
return "{}({!r})".format(
|
|
123
|
+
def __repr__(self):
|
|
124
|
+
return "{}({!r})".format(self.__class__.__name__, self.event)
|
|
124
125
|
|
|
125
126
|
|
|
126
127
|
class RelEvent:
|
|
@@ -136,8 +137,8 @@ class RelEvent:
|
|
|
136
137
|
msg = "relative axis event at {:f}, {}"
|
|
137
138
|
return msg.format(self.event.timestamp(), REL[self.event.code])
|
|
138
139
|
|
|
139
|
-
def __repr__(
|
|
140
|
-
return "{}({!r})".format(
|
|
140
|
+
def __repr__(self):
|
|
141
|
+
return "{}({!r})".format(self.__class__.__name__, self.event)
|
|
141
142
|
|
|
142
143
|
|
|
143
144
|
class AbsEvent:
|
|
@@ -153,8 +154,8 @@ class AbsEvent:
|
|
|
153
154
|
msg = "absolute axis event at {:f}, {}"
|
|
154
155
|
return msg.format(self.event.timestamp(), ABS[self.event.code])
|
|
155
156
|
|
|
156
|
-
def __repr__(
|
|
157
|
-
return "{}({!r})".format(
|
|
157
|
+
def __repr__(self):
|
|
158
|
+
return "{}({!r})".format(self.__class__.__name__, self.event)
|
|
158
159
|
|
|
159
160
|
|
|
160
161
|
class SynEvent:
|
|
@@ -173,8 +174,8 @@ class SynEvent:
|
|
|
173
174
|
msg = "synchronization event at {:f}, {}"
|
|
174
175
|
return msg.format(self.event.timestamp(), SYN[self.event.code])
|
|
175
176
|
|
|
176
|
-
def __repr__(
|
|
177
|
-
return "{}({!r})".format(
|
|
177
|
+
def __repr__(self):
|
|
178
|
+
return "{}({!r})".format(self.__class__.__name__, self.event)
|
|
178
179
|
|
|
179
180
|
|
|
180
181
|
#: A mapping of event types to :class:`InputEvent` sub-classes. Used
|
|
@@ -16,21 +16,15 @@ Examples:
|
|
|
16
16
|
evtest /dev/input/event0 /dev/input/event1
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
from __future__ import print_function
|
|
20
19
|
|
|
20
|
+
import atexit
|
|
21
|
+
import optparse
|
|
21
22
|
import re
|
|
22
|
-
import sys
|
|
23
23
|
import select
|
|
24
|
-
import
|
|
24
|
+
import sys
|
|
25
25
|
import termios
|
|
26
|
-
import optparse
|
|
27
|
-
|
|
28
|
-
try:
|
|
29
|
-
input = raw_input
|
|
30
|
-
except NameError:
|
|
31
|
-
pass
|
|
32
26
|
|
|
33
|
-
from
|
|
27
|
+
from . import AbsInfo, InputDevice, ecodes, list_devices
|
|
34
28
|
|
|
35
29
|
|
|
36
30
|
def parseopt():
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generate a Python extension module with the constants defined in linux/input.h.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import getopt
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
# -----------------------------------------------------------------------------
|
|
11
|
+
# The default header file locations to try.
|
|
12
|
+
headers = [
|
|
13
|
+
"/usr/include/linux/input.h",
|
|
14
|
+
"/usr/include/linux/input-event-codes.h",
|
|
15
|
+
"/usr/include/linux/uinput.h",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
opts, args = getopt.getopt(sys.argv[1:], "", ["ecodes", "stubs"])
|
|
19
|
+
if not opts:
|
|
20
|
+
print("usage: genecodes.py [--ecodes|--stubs] <headers>")
|
|
21
|
+
exit(2)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# -----------------------------------------------------------------------------
|
|
25
|
+
macro_regex = r"#define +((?:KEY|ABS|REL|SW|MSC|LED|BTN|REP|SND|ID|EV|BUS|SYN|FF|UI_FF|INPUT_PROP)_\w+)"
|
|
26
|
+
macro_regex = re.compile(macro_regex)
|
|
27
|
+
|
|
28
|
+
# Uname without hostname.
|
|
29
|
+
uname = list(os.uname())
|
|
30
|
+
uname = " ".join((uname[0], *uname[2:]))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# -----------------------------------------------------------------------------
|
|
34
|
+
template_ecodes = r"""
|
|
35
|
+
#include <Python.h>
|
|
36
|
+
#ifdef __FreeBSD__
|
|
37
|
+
#include <dev/evdev/input.h>
|
|
38
|
+
#else
|
|
39
|
+
#include <linux/input.h>
|
|
40
|
+
#include <linux/uinput.h>
|
|
41
|
+
#endif
|
|
42
|
+
|
|
43
|
+
/* Automatically generated by evdev.genecodes */
|
|
44
|
+
/* Generated on %s */
|
|
45
|
+
/* Generated from %s */
|
|
46
|
+
|
|
47
|
+
#define MODULE_NAME "_ecodes"
|
|
48
|
+
#define MODULE_HELP "linux/input.h macros"
|
|
49
|
+
|
|
50
|
+
static PyMethodDef MethodTable[] = {
|
|
51
|
+
{ NULL, NULL, 0, NULL}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
static struct PyModuleDef moduledef = {
|
|
55
|
+
PyModuleDef_HEAD_INIT,
|
|
56
|
+
MODULE_NAME,
|
|
57
|
+
MODULE_HELP,
|
|
58
|
+
-1, /* m_size */
|
|
59
|
+
MethodTable, /* m_methods */
|
|
60
|
+
NULL, /* m_reload */
|
|
61
|
+
NULL, /* m_traverse */
|
|
62
|
+
NULL, /* m_clear */
|
|
63
|
+
NULL, /* m_free */
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
PyMODINIT_FUNC
|
|
67
|
+
PyInit__ecodes(void)
|
|
68
|
+
{
|
|
69
|
+
PyObject* m = PyModule_Create(&moduledef);
|
|
70
|
+
if (m == NULL) return NULL;
|
|
71
|
+
|
|
72
|
+
%s
|
|
73
|
+
|
|
74
|
+
return m;
|
|
75
|
+
}
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
template_stubs = r"""
|
|
80
|
+
# Automatically generated by evdev.genecodes
|
|
81
|
+
# Generated on %s
|
|
82
|
+
# Generated from %s
|
|
83
|
+
|
|
84
|
+
# pylint: skip-file
|
|
85
|
+
|
|
86
|
+
ecodes: dict[str, int]
|
|
87
|
+
keys: dict[int, str|list[str]]
|
|
88
|
+
bytype: dict[int, dict[int, str|list[str]]]
|
|
89
|
+
|
|
90
|
+
KEY: dict[int, str|list[str]]
|
|
91
|
+
ABS: dict[int, str|list[str]]
|
|
92
|
+
REL: dict[int, str|list[str]]
|
|
93
|
+
SW: dict[int, str|list[str]]
|
|
94
|
+
MSC: dict[int, str|list[str]]
|
|
95
|
+
LED: dict[int, str|list[str]]
|
|
96
|
+
BTN: dict[int, str|list[str]]
|
|
97
|
+
REP: dict[int, str|list[str]]
|
|
98
|
+
SND: dict[int, str|list[str]]
|
|
99
|
+
ID: dict[int, str|list[str]]
|
|
100
|
+
EV: dict[int, str|list[str]]
|
|
101
|
+
BUS: dict[int, str|list[str]]
|
|
102
|
+
SYN: dict[int, str|list[str]]
|
|
103
|
+
FF_STATUS: dict[int, str|list[str]]
|
|
104
|
+
FF_INPUT_PROP: dict[int, str|list[str]]
|
|
105
|
+
|
|
106
|
+
%s
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def parse_headers(headers=headers):
|
|
111
|
+
for header in headers:
|
|
112
|
+
try:
|
|
113
|
+
fh = open(header)
|
|
114
|
+
except (IOError, OSError):
|
|
115
|
+
continue
|
|
116
|
+
|
|
117
|
+
for line in fh:
|
|
118
|
+
macro = macro_regex.search(line)
|
|
119
|
+
if macro:
|
|
120
|
+
yield macro.group(1)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
all_macros = list(parse_headers())
|
|
124
|
+
if not all_macros:
|
|
125
|
+
print("no input macros found in: %s" % " ".join(headers), file=sys.stderr)
|
|
126
|
+
sys.exit(1)
|
|
127
|
+
|
|
128
|
+
# pylint: disable=possibly-used-before-assignment, used-before-assignment
|
|
129
|
+
if ("--ecodes", "") in opts:
|
|
130
|
+
body = (" PyModule_AddIntMacro(m, %s);" % macro for macro in all_macros)
|
|
131
|
+
template = template_ecodes
|
|
132
|
+
elif ("--stubs", "") in opts:
|
|
133
|
+
body = ("%s: int" % macro for macro in all_macros)
|
|
134
|
+
template = template_stubs
|
|
135
|
+
|
|
136
|
+
body = os.linesep.join(body)
|
|
137
|
+
text = template % (uname, headers, body)
|
|
138
|
+
print(text.strip())
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from unittest import mock
|
|
3
|
+
from pprint import PrettyPrinter
|
|
4
|
+
|
|
5
|
+
sys.modules["evdev.ecodes"] = mock.Mock()
|
|
6
|
+
from evdev import ecodes_runtime as ecodes
|
|
7
|
+
|
|
8
|
+
pprint = PrettyPrinter(indent=2, sort_dicts=True, width=120).pprint
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
print("# Automatically generated by evdev.genecodes_py")
|
|
12
|
+
print()
|
|
13
|
+
print('"""')
|
|
14
|
+
print(ecodes.__doc__.strip())
|
|
15
|
+
print('"""')
|
|
16
|
+
|
|
17
|
+
print()
|
|
18
|
+
print("from typing import Final, Dict, Tuple, Union")
|
|
19
|
+
print()
|
|
20
|
+
|
|
21
|
+
for name, value in ecodes.ecodes.items():
|
|
22
|
+
print(f"{name}: Final[int] = {value}")
|
|
23
|
+
print()
|
|
24
|
+
|
|
25
|
+
entries = [
|
|
26
|
+
("ecodes", "Dict[str, int]", "#: Mapping of names to values."),
|
|
27
|
+
("bytype", "Dict[int, Dict[int, Union[str, Tuple[str]]]]", "#: Mapping of event types to other value/name mappings."),
|
|
28
|
+
("keys", "Dict[int, Union[str, Tuple[str]]]", "#: Keys are a combination of all BTN and KEY codes."),
|
|
29
|
+
("KEY", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
30
|
+
("ABS", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
31
|
+
("REL", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
32
|
+
("SW", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
33
|
+
("MSC", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
34
|
+
("LED", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
35
|
+
("BTN", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
36
|
+
("REP", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
37
|
+
("SND", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
38
|
+
("ID", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
39
|
+
("EV", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
40
|
+
("BUS", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
41
|
+
("SYN", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
42
|
+
("FF", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
43
|
+
("FF_STATUS", "Dict[int, Union[str, Tuple[str]]]", None),
|
|
44
|
+
("INPUT_PROP", "Dict[int, Union[str, Tuple[str]]]", None)
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
for key, annotation, doc in entries:
|
|
48
|
+
if doc:
|
|
49
|
+
print(doc)
|
|
50
|
+
|
|
51
|
+
print(f"{key}: {annotation} = ", end="")
|
|
52
|
+
pprint(getattr(ecodes, key))
|
|
53
|
+
print()
|
|
@@ -106,10 +106,12 @@ uinput_get_sysname(PyObject *self, PyObject *args)
|
|
|
106
106
|
int ret = PyArg_ParseTuple(args, "i", &fd);
|
|
107
107
|
if (!ret) return NULL;
|
|
108
108
|
|
|
109
|
+
#ifdef UI_GET_SYSNAME
|
|
109
110
|
if (ioctl(fd, UI_GET_SYSNAME(sizeof(sysname)), &sysname) < 0)
|
|
110
111
|
goto on_err;
|
|
111
112
|
|
|
112
113
|
return Py_BuildValue("s", &sysname);
|
|
114
|
+
#endif
|
|
113
115
|
|
|
114
116
|
on_err:
|
|
115
117
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import ctypes
|
|
1
2
|
import os
|
|
2
3
|
import platform
|
|
3
4
|
import re
|
|
@@ -5,11 +6,8 @@ import stat
|
|
|
5
6
|
import time
|
|
6
7
|
from collections import defaultdict
|
|
7
8
|
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from evdev.events import InputEvent
|
|
11
|
-
import evdev.ff as ff
|
|
12
|
-
import ctypes
|
|
9
|
+
from . import _uinput, device, ecodes, ff, util
|
|
10
|
+
from .events import InputEvent
|
|
13
11
|
|
|
14
12
|
try:
|
|
15
13
|
from evdev.eventio_async import EventIO
|
|
@@ -90,7 +88,10 @@ class UInput(EventIO):
|
|
|
90
88
|
devnode="/dev/uinput",
|
|
91
89
|
phys="py-evdev-uinput",
|
|
92
90
|
input_props=None,
|
|
93
|
-
|
|
91
|
+
# CentOS 7 has sufficiently old headers that FF_MAX_EFFECTS is not defined there,
|
|
92
|
+
# which causes the whole module to fail loading. Fallback on a hardcoded value of
|
|
93
|
+
# FF_MAX_EFFECTS if it is not defined in the ecodes.
|
|
94
|
+
max_effects=ecodes.ecodes.get("FF_MAX_EFFECTS", 96),
|
|
94
95
|
):
|
|
95
96
|
"""
|
|
96
97
|
Arguments
|
|
@@ -224,15 +225,6 @@ class UInput(EventIO):
|
|
|
224
225
|
_uinput.close(self.fd)
|
|
225
226
|
self.fd = -1
|
|
226
227
|
|
|
227
|
-
def syn(self):
|
|
228
|
-
"""
|
|
229
|
-
Inject a ``SYN_REPORT`` event into the input subsystem. Events
|
|
230
|
-
queued by :func:`write()` will be fired. If possible, events
|
|
231
|
-
will be merged into an 'atomic' event.
|
|
232
|
-
"""
|
|
233
|
-
|
|
234
|
-
_uinput.write(self.fd, ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
|
|
235
|
-
|
|
236
228
|
def capabilities(self, verbose=False, absinfo=True):
|
|
237
229
|
"""See :func:`capabilities <evdev.device.InputDevice.capabilities>`."""
|
|
238
230
|
if self.device is None:
|
|
@@ -274,13 +266,11 @@ class UInput(EventIO):
|
|
|
274
266
|
Verify that an uinput device exists and is readable and writable
|
|
275
267
|
by the current process.
|
|
276
268
|
"""
|
|
277
|
-
|
|
278
269
|
try:
|
|
279
270
|
m = os.stat(self.devnode)[stat.ST_MODE]
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
msg = '"{}" does not exist or is not a character device file ' "- verify that the uinput module is loaded"
|
|
271
|
+
assert stat.S_ISCHR(m)
|
|
272
|
+
except (IndexError, OSError, AssertionError):
|
|
273
|
+
msg = '"{}" does not exist or is not a character device file - verify that the uinput module is loaded'
|
|
284
274
|
raise UInputError(msg.format(self.devnode))
|
|
285
275
|
|
|
286
276
|
if not os.access(self.devnode, os.W_OK):
|
|
@@ -330,11 +320,20 @@ class UInput(EventIO):
|
|
|
330
320
|
# It is possible that there is some delay before /dev/input/event* shows
|
|
331
321
|
# up on old systems that do not use devtmpfs, so if the device cannot be
|
|
332
322
|
# found, wait for a short amount and then try again once.
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
323
|
+
#
|
|
324
|
+
# Furthermore, even if devtmpfs is in use, it is possible that the device
|
|
325
|
+
# does show up immediately, but without the correct permissions that
|
|
326
|
+
# still need to be set by udev. Wait for up to two seconds for either the
|
|
327
|
+
# device to show up or the permissions to be set.
|
|
328
|
+
for attempt in range(19):
|
|
329
|
+
try:
|
|
330
|
+
return device.InputDevice(device_path)
|
|
331
|
+
except (FileNotFoundError, PermissionError):
|
|
332
|
+
time.sleep(0.1)
|
|
333
|
+
|
|
334
|
+
# Last attempt. If this fails, whatever exception the last attempt raises
|
|
335
|
+
# shall be the exception that this function raises.
|
|
336
|
+
return device.InputDevice(device_path)
|
|
338
337
|
|
|
339
338
|
def _find_device_fallback(self):
|
|
340
339
|
"""
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import collections
|
|
2
|
+
import glob
|
|
2
3
|
import os
|
|
4
|
+
import re
|
|
3
5
|
import stat
|
|
4
|
-
import glob
|
|
5
|
-
import collections
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
from
|
|
7
|
+
from . import ecodes
|
|
8
|
+
from .events import event_factory
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def list_devices(input_device_dir="/dev/input"):
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: evdev
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: Bindings to the Linux input handling subsystem
|
|
5
5
|
Author-email: Georgi Valkov <georgi.t.valkov@gmail.com>
|
|
6
6
|
Maintainer-email: Tobi <proxima@sezanzeb.de>
|
|
7
|
-
License: Copyright (c) 2012-
|
|
7
|
+
License: Copyright (c) 2012-2025 Georgi Valkov. All rights reserved.
|
|
8
8
|
|
|
9
9
|
Redistribution and use in source and binary forms, with or without
|
|
10
10
|
modification, are permitted provided that the following conditions are
|
|
@@ -43,31 +43,35 @@ Classifier: Intended Audience :: Developers
|
|
|
43
43
|
Classifier: Topic :: Software Development :: Libraries
|
|
44
44
|
Classifier: License :: OSI Approved :: BSD License
|
|
45
45
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
46
|
-
Requires-Python: >=3.
|
|
47
|
-
Description-Content-Type: text/
|
|
46
|
+
Requires-Python: >=3.8
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
48
|
License-File: LICENSE
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
-------
|
|
50
|
+
# evdev
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
<p>
|
|
53
|
+
<a href="https://pypi.python.org/pypi/evdev"><img alt="pypi version" src="https://img.shields.io/pypi/v/evdev.svg"></a>
|
|
54
|
+
<a href="https://github.com/gvalkov/python-evdev/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/evdev"></a>
|
|
55
|
+
<a href="https://repology.org/project/python:evdev/versions"><img alt="Packaging status" src="https://repology.org/badge/tiny-repos/python:evdev.svg"></a>
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
This package provides bindings to the generic input event interface in Linux.
|
|
59
|
+
The *evdev* interface serves the purpose of passing events generated in the
|
|
60
|
+
kernel directly to userspace through character devices that are typically
|
|
61
|
+
located in `/dev/input/`.
|
|
57
62
|
|
|
58
63
|
This package also comes with bindings to *uinput*, the userspace input
|
|
59
|
-
subsystem. *Uinput* allows userspace programs to create and handle
|
|
60
|
-
|
|
61
|
-
subsystem.
|
|
64
|
+
subsystem. *Uinput* allows userspace programs to create and handle input devices
|
|
65
|
+
that can inject events directly into the input subsystem.
|
|
62
66
|
|
|
63
|
-
Documentation
|
|
64
|
-
|
|
67
|
+
***Documentation:***
|
|
68
|
+
https://python-evdev.readthedocs.io/en/latest/
|
|
65
69
|
|
|
66
|
-
Development
|
|
67
|
-
|
|
70
|
+
***Development:***
|
|
71
|
+
https://github.com/gvalkov/python-evdev
|
|
68
72
|
|
|
69
|
-
Package
|
|
70
|
-
|
|
73
|
+
***Package:***
|
|
74
|
+
https://pypi.python.org/pypi/evdev
|
|
71
75
|
|
|
72
|
-
Changelog
|
|
73
|
-
|
|
76
|
+
***Changelog:***
|
|
77
|
+
https://python-evdev.readthedocs.io/en/latest/changelog.html
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
LICENSE
|
|
2
2
|
MANIFEST.in
|
|
3
|
-
README.
|
|
3
|
+
README.md
|
|
4
4
|
pyproject.toml
|
|
5
5
|
setup.py
|
|
6
6
|
evdev/__init__.py
|
|
7
7
|
evdev/device.py
|
|
8
8
|
evdev/ecodes.py
|
|
9
|
+
evdev/ecodes_runtime.py
|
|
9
10
|
evdev/eventio.py
|
|
10
11
|
evdev/eventio_async.py
|
|
11
12
|
evdev/events.py
|
|
12
13
|
evdev/evtest.py
|
|
13
14
|
evdev/ff.py
|
|
14
|
-
evdev/
|
|
15
|
+
evdev/genecodes_c.py
|
|
16
|
+
evdev/genecodes_py.py
|
|
15
17
|
evdev/input.c
|
|
16
18
|
evdev/uinput.c
|
|
17
19
|
evdev/uinput.py
|
|
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "evdev"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.8.0"
|
|
8
8
|
description = "Bindings to the Linux input handling subsystem"
|
|
9
9
|
keywords = ["evdev", "input", "uinput"]
|
|
10
|
-
readme = "README.
|
|
10
|
+
readme = "README.md"
|
|
11
11
|
license = {file = "LICENSE"}
|
|
12
|
-
requires-python = ">=3.
|
|
12
|
+
requires-python = ">=3.8"
|
|
13
13
|
authors = [
|
|
14
14
|
{ name="Georgi Valkov", email="georgi.t.valkov@gmail.com" },
|
|
15
15
|
]
|
|
@@ -39,7 +39,7 @@ line-length = 120
|
|
|
39
39
|
ignore = ["E265", "E241", "F403", "F401", "E401", "E731"]
|
|
40
40
|
|
|
41
41
|
[tool.bumpversion]
|
|
42
|
-
current_version = "1.
|
|
42
|
+
current_version = "1.8.0"
|
|
43
43
|
commit = true
|
|
44
44
|
tag = true
|
|
45
45
|
allow_dirty = true
|
|
@@ -48,4 +48,13 @@ allow_dirty = true
|
|
|
48
48
|
filename = "pyproject.toml"
|
|
49
49
|
|
|
50
50
|
[[tool.bumpversion.files]]
|
|
51
|
-
filename = "docs/conf.py"
|
|
51
|
+
filename = "docs/conf.py"
|
|
52
|
+
|
|
53
|
+
[tool.pylint.'MESSAGES CONTROL']
|
|
54
|
+
disable = """
|
|
55
|
+
no-member,
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
[tool.pylint.typecheck]
|
|
59
|
+
generated-members = ["evdev.ecodes.*"]
|
|
60
|
+
ignored-modules= ["evdev._*"]
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
|
+
import shutil
|
|
3
4
|
import textwrap
|
|
4
5
|
from pathlib import Path
|
|
6
|
+
from subprocess import run
|
|
5
7
|
|
|
6
8
|
from setuptools import setup, Extension, Command
|
|
7
9
|
from setuptools.command import build_ext as _build_ext
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
curdir = Path(__file__).resolve().parent
|
|
11
|
-
|
|
13
|
+
ecodes_c_path = curdir / "evdev/ecodes.c"
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
def create_ecodes(headers=None):
|
|
@@ -47,16 +49,18 @@ def create_ecodes(headers=None):
|
|
|
47
49
|
build_ecodes --evdev-headers path/input.h:path/input-event-codes.h \\
|
|
48
50
|
build_ext --include-dirs path/ \\
|
|
49
51
|
install
|
|
52
|
+
|
|
53
|
+
If you want to avoid building this package from source, then please consider
|
|
54
|
+
installing the `evdev-binary` package instead. Keep in mind that it may not be
|
|
55
|
+
fully compatible with, or support all the features of your current kernel.
|
|
50
56
|
"""
|
|
51
57
|
|
|
52
58
|
sys.stderr.write(textwrap.dedent(msg))
|
|
53
59
|
sys.exit(1)
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
with ecodes_path.open("w") as fh:
|
|
59
|
-
cmd = [sys.executable, "evdev/genecodes.py", *headers]
|
|
61
|
+
print("writing %s (using %s)" % (ecodes_c_path, " ".join(headers)))
|
|
62
|
+
with ecodes_c_path.open("w") as fh:
|
|
63
|
+
cmd = [sys.executable, "evdev/genecodes_c.py", "--ecodes", *headers]
|
|
60
64
|
run(cmd, check=True, stdout=fh)
|
|
61
65
|
|
|
62
66
|
|
|
@@ -80,14 +84,27 @@ class build_ecodes(Command):
|
|
|
80
84
|
|
|
81
85
|
class build_ext(_build_ext.build_ext):
|
|
82
86
|
def has_ecodes(self):
|
|
83
|
-
if
|
|
87
|
+
if ecodes_c_path.exists():
|
|
84
88
|
print("ecodes.c already exists ... skipping build_ecodes")
|
|
85
|
-
|
|
89
|
+
return False
|
|
90
|
+
return True
|
|
91
|
+
|
|
92
|
+
def generate_ecodes_py(self):
|
|
93
|
+
ecodes_py = Path(self.build_lib) / "evdev/ecodes.py"
|
|
94
|
+
print(f"writing {ecodes_py}")
|
|
95
|
+
with ecodes_py.open("w") as fh:
|
|
96
|
+
cmd = [sys.executable, "-B", "evdev/genecodes_py.py"]
|
|
97
|
+
res = run(cmd, env={"PYTHONPATH": self.build_lib}, stdout=fh)
|
|
98
|
+
|
|
99
|
+
if res.returncode != 0:
|
|
100
|
+
print(f"failed to generate static {ecodes_py} - will use ecodes_runtime.py")
|
|
101
|
+
shutil.copy("evdev/ecodes_runtime.py", ecodes_py)
|
|
86
102
|
|
|
87
103
|
def run(self):
|
|
88
104
|
for cmd_name in self.get_sub_commands():
|
|
89
105
|
self.run_command(cmd_name)
|
|
90
106
|
_build_ext.build_ext.run(self)
|
|
107
|
+
self.generate_ecodes_py()
|
|
91
108
|
|
|
92
109
|
sub_commands = [("build_ecodes", has_ecodes)] + _build_ext.build_ext.sub_commands
|
|
93
110
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
-
|
|
2
|
+
import os
|
|
3
|
+
import stat
|
|
3
4
|
from select import select
|
|
4
|
-
from
|
|
5
|
+
from unittest.mock import patch
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
import pytest
|
|
8
|
+
from pytest import raises, fixture
|
|
7
9
|
|
|
10
|
+
from evdev import uinput, ecodes, device, UInputError
|
|
8
11
|
|
|
9
12
|
# -----------------------------------------------------------------------------
|
|
10
13
|
uinput_options = {
|
|
@@ -66,12 +69,12 @@ def test_enable_events(c):
|
|
|
66
69
|
|
|
67
70
|
def test_abs_values(c):
|
|
68
71
|
e = ecodes
|
|
69
|
-
c
|
|
72
|
+
c = {
|
|
70
73
|
e.EV_KEY: [e.KEY_A, e.KEY_B],
|
|
71
|
-
e.EV_ABS: [(e.ABS_X, (0, 255, 0, 0)), (e.ABS_Y, device.AbsInfo(0, 255, 5, 10, 0
|
|
74
|
+
e.EV_ABS: [(e.ABS_X, (0, 0, 255, 0, 0)), (e.ABS_Y, device.AbsInfo(0, 0, 255, 5, 10, 0))],
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
with uinput.UInput(
|
|
77
|
+
with uinput.UInput(events=c) as ui:
|
|
75
78
|
c = ui.capabilities()
|
|
76
79
|
abs = device.AbsInfo(value=0, min=0, max=255, fuzz=0, flat=0, resolution=0)
|
|
77
80
|
assert c[e.EV_ABS][0] == (0, abs)
|
|
@@ -114,3 +117,21 @@ def test_write(c):
|
|
|
114
117
|
assert evs[3].code == ecodes.KEY_A and evs[3].value == 2
|
|
115
118
|
assert evs[4].code == ecodes.KEY_A and evs[4].value == 0
|
|
116
119
|
break
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@patch.object(stat, 'S_ISCHR', return_value=False)
|
|
123
|
+
def test_not_a_character_device(ischr_mock, c):
|
|
124
|
+
with pytest.raises(UInputError, match='not a character device file'):
|
|
125
|
+
uinput.UInput(**c)
|
|
126
|
+
|
|
127
|
+
@patch.object(stat, 'S_ISCHR', return_value=True)
|
|
128
|
+
@patch.object(os, 'stat', side_effect=OSError())
|
|
129
|
+
def test_not_a_character_device_2(stat_mock, ischr_mock, c):
|
|
130
|
+
with pytest.raises(UInputError, match='not a character device file'):
|
|
131
|
+
uinput.UInput(**c)
|
|
132
|
+
|
|
133
|
+
@patch.object(stat, 'S_ISCHR', return_value=True)
|
|
134
|
+
@patch.object(os, 'stat', return_value=[])
|
|
135
|
+
def test_not_a_character_device_3(stat_mock, ischr_mock, c):
|
|
136
|
+
with pytest.raises(UInputError, match='not a character device file'):
|
|
137
|
+
uinput.UInput(**c)
|
evdev-1.7.0/README.rst
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
*evdev*
|
|
2
|
-
-------
|
|
3
|
-
|
|
4
|
-
This package provides bindings to the generic input event interface in
|
|
5
|
-
Linux. The *evdev* interface serves the purpose of passing events
|
|
6
|
-
generated in the kernel directly to userspace through character
|
|
7
|
-
devices that are typically located in ``/dev/input/``.
|
|
8
|
-
|
|
9
|
-
This package also comes with bindings to *uinput*, the userspace input
|
|
10
|
-
subsystem. *Uinput* allows userspace programs to create and handle
|
|
11
|
-
input devices that can inject events directly into the input
|
|
12
|
-
subsystem.
|
|
13
|
-
|
|
14
|
-
Documentation:
|
|
15
|
-
https://python-evdev.readthedocs.io/en/latest/
|
|
16
|
-
|
|
17
|
-
Development:
|
|
18
|
-
https://github.com/gvalkov/python-evdev
|
|
19
|
-
|
|
20
|
-
Package:
|
|
21
|
-
https://pypi.python.org/pypi/evdev
|
|
22
|
-
|
|
23
|
-
Changelog:
|
|
24
|
-
https://python-evdev.readthedocs.io/en/latest/changelog.html
|
evdev-1.7.0/evdev/__init__.py
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
# --------------------------------------------------------------------------
|
|
2
|
-
# Gather everything into a single, convenient namespace.
|
|
3
|
-
# --------------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
from evdev.device import DeviceInfo, InputDevice, AbsInfo, EvdevError
|
|
6
|
-
from evdev.events import InputEvent, KeyEvent, RelEvent, SynEvent, AbsEvent, event_factory
|
|
7
|
-
from evdev.uinput import UInput, UInputError
|
|
8
|
-
from evdev.util import list_devices, categorize, resolve_ecodes, resolve_ecodes_dict
|
|
9
|
-
from evdev import ecodes
|
|
10
|
-
from evdev import ff
|
evdev-1.7.0/evdev/genecodes.py
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Generate a Python extension module with the constants defined in linux/input.h.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import print_function
|
|
6
|
-
import os, sys, re
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# -----------------------------------------------------------------------------
|
|
10
|
-
# The default header file locations to try.
|
|
11
|
-
headers = [
|
|
12
|
-
"/usr/include/linux/input.h",
|
|
13
|
-
"/usr/include/linux/input-event-codes.h",
|
|
14
|
-
"/usr/include/linux/uinput.h",
|
|
15
|
-
]
|
|
16
|
-
|
|
17
|
-
if sys.argv[1:]:
|
|
18
|
-
headers = sys.argv[1:]
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
# -----------------------------------------------------------------------------
|
|
22
|
-
macro_regex = r"#define +((?:KEY|ABS|REL|SW|MSC|LED|BTN|REP|SND|ID|EV|BUS|SYN|FF|UI_FF|INPUT_PROP)_\w+)"
|
|
23
|
-
macro_regex = re.compile(macro_regex)
|
|
24
|
-
|
|
25
|
-
uname = list(os.uname())
|
|
26
|
-
del uname[1]
|
|
27
|
-
uname = " ".join(uname)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# -----------------------------------------------------------------------------
|
|
31
|
-
template = r"""
|
|
32
|
-
#include <Python.h>
|
|
33
|
-
#ifdef __FreeBSD__
|
|
34
|
-
#include <dev/evdev/input.h>
|
|
35
|
-
#else
|
|
36
|
-
#include <linux/input.h>
|
|
37
|
-
#include <linux/uinput.h>
|
|
38
|
-
#endif
|
|
39
|
-
|
|
40
|
-
/* Automatically generated by evdev.genecodes */
|
|
41
|
-
/* Generated on %s */
|
|
42
|
-
|
|
43
|
-
#define MODULE_NAME "_ecodes"
|
|
44
|
-
#define MODULE_HELP "linux/input.h macros"
|
|
45
|
-
|
|
46
|
-
static PyMethodDef MethodTable[] = {
|
|
47
|
-
{ NULL, NULL, 0, NULL}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
static struct PyModuleDef moduledef = {
|
|
51
|
-
PyModuleDef_HEAD_INIT,
|
|
52
|
-
MODULE_NAME,
|
|
53
|
-
MODULE_HELP,
|
|
54
|
-
-1, /* m_size */
|
|
55
|
-
MethodTable, /* m_methods */
|
|
56
|
-
NULL, /* m_reload */
|
|
57
|
-
NULL, /* m_traverse */
|
|
58
|
-
NULL, /* m_clear */
|
|
59
|
-
NULL, /* m_free */
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
PyMODINIT_FUNC
|
|
63
|
-
PyInit__ecodes(void)
|
|
64
|
-
{
|
|
65
|
-
PyObject* m = PyModule_Create(&moduledef);
|
|
66
|
-
if (m == NULL) return NULL;
|
|
67
|
-
|
|
68
|
-
%s
|
|
69
|
-
|
|
70
|
-
return m;
|
|
71
|
-
}
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def parse_header(header):
|
|
76
|
-
for line in open(header):
|
|
77
|
-
macro = macro_regex.search(line)
|
|
78
|
-
if macro:
|
|
79
|
-
yield " PyModule_AddIntMacro(m, %s);" % macro.group(1)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
all_macros = []
|
|
83
|
-
for header in headers:
|
|
84
|
-
try:
|
|
85
|
-
fh = open(header)
|
|
86
|
-
except (IOError, OSError):
|
|
87
|
-
continue
|
|
88
|
-
all_macros += parse_header(header)
|
|
89
|
-
|
|
90
|
-
if not all_macros:
|
|
91
|
-
print("no input macros found in: %s" % " ".join(headers), file=sys.stderr)
|
|
92
|
-
sys.exit(1)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
macros = os.linesep.join(all_macros)
|
|
96
|
-
print(template % (uname, macros))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|