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/evtest.py ADDED
@@ -0,0 +1,181 @@
1
+ """
2
+ Usage: evtest [options] [<device>, ...]
3
+
4
+ Input device enumerator and event monitor.
5
+
6
+ Running evtest without any arguments will let you select
7
+ from a list of all readable input devices.
8
+
9
+ Options:
10
+ -h, --help Show this help message and exit.
11
+ -c, --capabilities List device capabilities and exit.
12
+ -g, --grab Other applications will not receive events from
13
+ the selected devices while evtest is running.
14
+
15
+ Examples:
16
+ evtest /dev/input/event0 /dev/input/event1
17
+ """
18
+
19
+ import atexit
20
+ import optparse
21
+ import re
22
+ import select
23
+ import sys
24
+ import termios
25
+
26
+ from . import AbsInfo, InputDevice, ecodes, list_devices
27
+
28
+
29
+ def parseopt():
30
+ parser = optparse.OptionParser(add_help_option=False)
31
+ parser.add_option("-h", "--help", action="store_true")
32
+ parser.add_option("-g", "--grab", action="store_true")
33
+ parser.add_option("-c", "--capabilities", action="store_true")
34
+ return parser.parse_args()
35
+
36
+
37
+ def main():
38
+ opts, devices = parseopt()
39
+ if opts.help:
40
+ print(__doc__.strip())
41
+ return 0
42
+
43
+ if not devices:
44
+ devices = select_devices()
45
+ else:
46
+ devices = [InputDevice(path) for path in devices]
47
+
48
+ if opts.capabilities:
49
+ for device in devices:
50
+ print_capabilities(device)
51
+ return 0
52
+
53
+ if opts.grab:
54
+ for device in devices:
55
+ device.grab()
56
+
57
+ # Disable tty echoing if stdin is a tty.
58
+ if sys.stdin.isatty():
59
+ toggle_tty_echo(sys.stdin, enable=False)
60
+ atexit.register(toggle_tty_echo, sys.stdin, enable=True)
61
+
62
+ print("Listening for events (press ctrl-c to exit) ...")
63
+ fd_to_device = {dev.fd: dev for dev in devices}
64
+ while True:
65
+ r, w, e = select.select(fd_to_device, [], [])
66
+
67
+ for fd in r:
68
+ for event in fd_to_device[fd].read():
69
+ print_event(event)
70
+
71
+
72
+ def select_devices(device_dir="/dev/input"):
73
+ """
74
+ Select one or more devices from a list of accessible input devices.
75
+ """
76
+
77
+ def devicenum(device_path):
78
+ digits = re.findall(r"\d+$", device_path)
79
+ return [int(i) for i in digits]
80
+
81
+ devices = sorted(list_devices(device_dir), key=devicenum)
82
+ devices = [InputDevice(path) for path in devices]
83
+ if not devices:
84
+ msg = "error: no input devices found (do you have rw permission on %s/*?)"
85
+ print(msg % device_dir, file=sys.stderr)
86
+ sys.exit(1)
87
+
88
+ dev_format = "{0:<3} {1.path:<20} {1.name:<35} {1.phys:<35} {1.uniq:<4}"
89
+ dev_lines = [dev_format.format(num, dev) for num, dev in enumerate(devices)]
90
+
91
+ print("ID {:<20} {:<35} {:<35} {}".format("Device", "Name", "Phys", "Uniq"))
92
+ print("-" * len(max(dev_lines, key=len)))
93
+ print("\n".join(dev_lines))
94
+ print()
95
+
96
+ choices = input("Select devices [0-%s]: " % (len(dev_lines) - 1))
97
+
98
+ try:
99
+ choices = choices.split()
100
+ choices = [devices[int(num)] for num in choices]
101
+ except ValueError:
102
+ choices = None
103
+
104
+ if not choices:
105
+ msg = "error: invalid input - please enter one or more numbers separated by spaces"
106
+ print(msg, file=sys.stderr)
107
+ sys.exit(1)
108
+
109
+ return choices
110
+
111
+
112
+ def print_capabilities(device):
113
+ capabilities = device.capabilities(verbose=True)
114
+ input_props = device.input_props(verbose=True)
115
+
116
+ print("Device name: {.name}".format(device))
117
+ print("Device info: {.info}".format(device))
118
+ print("Repeat settings: {}\n".format(device.repeat))
119
+
120
+ if ("EV_LED", ecodes.EV_LED) in capabilities:
121
+ leds = ",".join(i[0] for i in device.leds(True))
122
+ print("Active LEDs: %s" % leds)
123
+
124
+ active_keys = ",".join(k[0] for k in device.active_keys(True))
125
+ print("Active keys: %s\n" % active_keys)
126
+
127
+ if input_props:
128
+ print("Input properties:")
129
+ for type, code in input_props:
130
+ print(" %s %s" % (type, code))
131
+ print()
132
+
133
+ print("Device capabilities:")
134
+ for type, codes in capabilities.items():
135
+ print(" Type {} {}:".format(*type))
136
+ for code in codes:
137
+ # code <- ('BTN_RIGHT', 273) or (['BTN_LEFT', 'BTN_MOUSE'], 272)
138
+ if isinstance(code[1], AbsInfo):
139
+ print(" Code {:<4} {}:".format(*code[0]))
140
+ print(" {}".format(code[1]))
141
+ else:
142
+ # Multiple names may resolve to one value.
143
+ s = ", ".join(code[0]) if isinstance(code[0], list) else code[0]
144
+ print(" Code {:<4} {}".format(s, code[1]))
145
+ print("")
146
+
147
+
148
+ def print_event(e):
149
+ if e.type == ecodes.EV_SYN:
150
+ if e.code == ecodes.SYN_MT_REPORT:
151
+ msg = "time {:<17} +++++++++++++ {} +++++++++++++"
152
+ elif e.code == ecodes.SYN_DROPPED:
153
+ msg = "time {:<17} !!!!!!!!!!!!! {} !!!!!!!!!!!!!"
154
+ else:
155
+ msg = "time {:<17} ------------- {} -------------"
156
+ print(msg.format(e.timestamp(), ecodes.SYN[e.code]))
157
+ else:
158
+ if e.type in ecodes.bytype:
159
+ codename = ecodes.bytype[e.type][e.code]
160
+ else:
161
+ codename = "?"
162
+
163
+ evfmt = "time {:<17} type {} ({}), code {:<4} ({}), value {}"
164
+ print(evfmt.format(e.timestamp(), e.type, ecodes.EV[e.type], e.code, codename, e.value))
165
+
166
+
167
+ def toggle_tty_echo(fh, enable=True):
168
+ flags = termios.tcgetattr(fh.fileno())
169
+ if enable:
170
+ flags[3] |= termios.ECHO
171
+ else:
172
+ flags[3] &= ~termios.ECHO
173
+ termios.tcsetattr(fh.fileno(), termios.TCSANOW, flags)
174
+
175
+
176
+ if __name__ == "__main__":
177
+ try:
178
+ ret = main()
179
+ except (KeyboardInterrupt, EOFError):
180
+ ret = 0
181
+ sys.exit(ret)
evdev/ff.py ADDED
@@ -0,0 +1,198 @@
1
+ import ctypes
2
+
3
+ from . import ecodes
4
+
5
+ _u8 = ctypes.c_uint8
6
+ _u16 = ctypes.c_uint16
7
+ _u32 = ctypes.c_uint32
8
+ _s16 = ctypes.c_int16
9
+ _s32 = ctypes.c_int32
10
+
11
+
12
+ class Replay(ctypes.Structure):
13
+ """
14
+ Defines scheduling of the force-feedback effect
15
+ @length: duration of the effect
16
+ @delay: delay before effect should start playing
17
+ """
18
+
19
+ _fields_ = [
20
+ ("length", _u16),
21
+ ("delay", _u16),
22
+ ]
23
+
24
+
25
+ class Trigger(ctypes.Structure):
26
+ """
27
+ Defines what triggers the force-feedback effect
28
+ @button: number of the button triggering the effect
29
+ @interval: controls how soon the effect can be re-triggered
30
+ """
31
+
32
+ _fields_ = [
33
+ ("button", _u16),
34
+ ("interval", _u16),
35
+ ]
36
+
37
+
38
+ class Envelope(ctypes.Structure):
39
+ """
40
+ Generic force-feedback effect envelope
41
+ @attack_length: duration of the attack (ms)
42
+ @attack_level: level at the beginning of the attack
43
+ @fade_length: duration of fade (ms)
44
+ @fade_level: level at the end of fade
45
+
46
+ The @attack_level and @fade_level are absolute values; when applying
47
+ envelope force-feedback core will convert to positive/negative
48
+ value based on polarity of the default level of the effect.
49
+ Valid range for the attack and fade levels is 0x0000 - 0x7fff
50
+ """
51
+
52
+ _fields_ = [
53
+ ("attack_length", _u16),
54
+ ("attack_level", _u16),
55
+ ("fade_length", _u16),
56
+ ("fade_level", _u16),
57
+ ]
58
+
59
+
60
+ class Constant(ctypes.Structure):
61
+ """
62
+ Defines parameters of a constant force-feedback effect
63
+ @level: strength of the effect; may be negative
64
+ @envelope: envelope data
65
+ """
66
+
67
+ _fields_ = [
68
+ ("level", _s16),
69
+ ("ff_envelope", Envelope),
70
+ ]
71
+
72
+
73
+ class Ramp(ctypes.Structure):
74
+ """
75
+ Defines parameters of a ramp force-feedback effect
76
+ @start_level: beginning strength of the effect; may be negative
77
+ @end_level: final strength of the effect; may be negative
78
+ @envelope: envelope data
79
+ """
80
+
81
+ _fields_ = [
82
+ ("start_level", _s16),
83
+ ("end_level", _s16),
84
+ ("ff_envelope", Envelope),
85
+ ]
86
+
87
+
88
+ class Condition(ctypes.Structure):
89
+ """
90
+ Defines a spring or friction force-feedback effect
91
+ @right_saturation: maximum level when joystick moved all way to the right
92
+ @left_saturation: same for the left side
93
+ @right_coeff: controls how fast the force grows when the joystick moves to the right
94
+ @left_coeff: same for the left side
95
+ @deadband: size of the dead zone, where no force is produced
96
+ @center: position of the dead zone
97
+ """
98
+
99
+ _fields_ = [
100
+ ("right_saturation", _u16),
101
+ ("left_saturation", _u16),
102
+ ("right_coeff", _s16),
103
+ ("left_coeff", _s16),
104
+ ("deadband", _u16),
105
+ ("center", _s16),
106
+ ]
107
+
108
+
109
+ class Periodic(ctypes.Structure):
110
+ """
111
+ Defines parameters of a periodic force-feedback effect
112
+ @waveform: kind of the effect (wave)
113
+ @period: period of the wave (ms)
114
+ @magnitude: peak value
115
+ @offset: mean value of the wave (roughly)
116
+ @phase: 'horizontal' shift
117
+ @envelope: envelope data
118
+ @custom_len: number of samples (FF_CUSTOM only)
119
+ @custom_data: buffer of samples (FF_CUSTOM only)
120
+ """
121
+
122
+ _fields_ = [
123
+ ("waveform", _u16),
124
+ ("period", _u16),
125
+ ("magnitude", _s16),
126
+ ("offset", _s16),
127
+ ("phase", _u16),
128
+ ("envelope", Envelope),
129
+ ("custom_len", _u32),
130
+ ("custom_data", ctypes.POINTER(_s16)),
131
+ ]
132
+
133
+
134
+ class Rumble(ctypes.Structure):
135
+ """
136
+ Defines parameters of a periodic force-feedback effect
137
+ @strong_magnitude: magnitude of the heavy motor
138
+ @weak_magnitude: magnitude of the light one
139
+
140
+ Some rumble pads have two motors of different weight. Strong_magnitude
141
+ represents the magnitude of the vibration generated by the heavy one.
142
+ """
143
+
144
+ _fields_ = [
145
+ ("strong_magnitude", _u16),
146
+ ("weak_magnitude", _u16),
147
+ ]
148
+
149
+
150
+ class EffectType(ctypes.Union):
151
+ _fields_ = [
152
+ ("ff_constant_effect", Constant),
153
+ ("ff_ramp_effect", Ramp),
154
+ ("ff_periodic_effect", Periodic),
155
+ ("ff_condition_effect", Condition * 2), # one for each axis
156
+ ("ff_rumble_effect", Rumble),
157
+ ]
158
+
159
+
160
+ class Effect(ctypes.Structure):
161
+ _fields_ = [
162
+ ("type", _u16),
163
+ ("id", _s16),
164
+ ("direction", _u16),
165
+ ("ff_trigger", Trigger),
166
+ ("ff_replay", Replay),
167
+ ("u", EffectType),
168
+ ]
169
+
170
+
171
+ class UInputUpload(ctypes.Structure):
172
+ _fields_ = [
173
+ ("request_id", _u32),
174
+ ("retval", _s32),
175
+ ("effect", Effect),
176
+ ("old", Effect),
177
+ ]
178
+
179
+
180
+ class UInputErase(ctypes.Structure):
181
+ _fields_ = [
182
+ ("request_id", _u32),
183
+ ("retval", _s32),
184
+ ("effect_id", _u32),
185
+ ]
186
+
187
+
188
+ # ff_types = {
189
+ # ecodes.FF_CONSTANT,
190
+ # ecodes.FF_PERIODIC,
191
+ # ecodes.FF_RAMP,
192
+ # ecodes.FF_SPRING,
193
+ # ecodes.FF_FRICTION,
194
+ # ecodes.FF_DAMPER,
195
+ # ecodes.FF_RUMBLE,
196
+ # ecodes.FF_INERTIA,
197
+ # ecodes.FF_CUSTOM,
198
+ # }
evdev/genecodes_c.py ADDED
@@ -0,0 +1,147 @@
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", "reproducible"])
19
+ if not opts:
20
+ print("usage: genecodes.py [--ecodes|--stubs] [--reproducible] <headers>")
21
+ exit(2)
22
+
23
+ if args:
24
+ headers = args
25
+
26
+ reproducible = ("--reproducible", "") in opts
27
+
28
+
29
+ # -----------------------------------------------------------------------------
30
+ macro_regex = r"#define\s+((?:KEY|ABS|REL|SW|MSC|LED|BTN|REP|SND|ID|EV|BUS|SYN|FF|UI_FF|INPUT_PROP)_\w+)"
31
+ macro_regex = re.compile(macro_regex)
32
+
33
+ if reproducible:
34
+ uname = "hidden for reproducibility"
35
+ else:
36
+ # Uname without hostname.
37
+ uname = list(os.uname())
38
+ uname = " ".join((uname[0], *uname[2:]))
39
+
40
+
41
+ # -----------------------------------------------------------------------------
42
+ template_ecodes = r"""
43
+ #include <Python.h>
44
+ #ifdef __FreeBSD__
45
+ #include <dev/evdev/input.h>
46
+ #include <dev/evdev/uinput.h>
47
+ #else
48
+ #include <linux/input.h>
49
+ #include <linux/uinput.h>
50
+ #endif
51
+
52
+ /* Automatically generated by evdev.genecodes */
53
+ /* Generated on %s */
54
+ /* Generated from %s */
55
+
56
+ #define MODULE_NAME "_ecodes"
57
+ #define MODULE_HELP "linux/input.h macros"
58
+
59
+ static PyMethodDef MethodTable[] = {
60
+ { NULL, NULL, 0, NULL}
61
+ };
62
+
63
+ static struct PyModuleDef moduledef = {
64
+ PyModuleDef_HEAD_INIT,
65
+ MODULE_NAME,
66
+ MODULE_HELP,
67
+ -1, /* m_size */
68
+ MethodTable, /* m_methods */
69
+ NULL, /* m_reload */
70
+ NULL, /* m_traverse */
71
+ NULL, /* m_clear */
72
+ NULL, /* m_free */
73
+ };
74
+
75
+ PyMODINIT_FUNC
76
+ PyInit__ecodes(void)
77
+ {
78
+ PyObject* m = PyModule_Create(&moduledef);
79
+ if (m == NULL) return NULL;
80
+
81
+ %s
82
+
83
+ return m;
84
+ }
85
+ """
86
+
87
+
88
+ template_stubs = r"""
89
+ # Automatically generated by evdev.genecodes
90
+ # Generated on %s
91
+ # Generated from %s
92
+
93
+ # pylint: skip-file
94
+
95
+ ecodes: dict[str, int]
96
+ keys: dict[int, str|list[str]]
97
+ bytype: dict[int, dict[int, str|list[str]]]
98
+
99
+ KEY: dict[int, str|list[str]]
100
+ ABS: dict[int, str|list[str]]
101
+ REL: dict[int, str|list[str]]
102
+ SW: dict[int, str|list[str]]
103
+ MSC: dict[int, str|list[str]]
104
+ LED: dict[int, str|list[str]]
105
+ BTN: dict[int, str|list[str]]
106
+ REP: dict[int, str|list[str]]
107
+ SND: dict[int, str|list[str]]
108
+ ID: dict[int, str|list[str]]
109
+ EV: dict[int, str|list[str]]
110
+ BUS: dict[int, str|list[str]]
111
+ SYN: dict[int, str|list[str]]
112
+ FF_STATUS: dict[int, str|list[str]]
113
+ FF_INPUT_PROP: dict[int, str|list[str]]
114
+
115
+ %s
116
+ """
117
+
118
+
119
+ def parse_headers(headers=headers):
120
+ for header in headers:
121
+ try:
122
+ fh = open(header)
123
+ except (IOError, OSError):
124
+ continue
125
+
126
+ for line in fh:
127
+ macro = macro_regex.search(line)
128
+ if macro:
129
+ yield macro.group(1)
130
+
131
+
132
+ all_macros = list(parse_headers())
133
+ if not all_macros:
134
+ print("no input macros found in: %s" % " ".join(headers), file=sys.stderr)
135
+ sys.exit(1)
136
+
137
+ # pylint: disable=possibly-used-before-assignment, used-before-assignment
138
+ if ("--ecodes", "") in opts:
139
+ body = (" PyModule_AddIntMacro(m, %s);" % macro for macro in all_macros)
140
+ template = template_ecodes
141
+ elif ("--stubs", "") in opts:
142
+ body = ("%s: int" % macro for macro in all_macros)
143
+ template = template_stubs
144
+
145
+ body = os.linesep.join(body)
146
+ text = template % (uname, headers if not reproducible else ["hidden for reproducibility"], body)
147
+ print(text.strip())
evdev/genecodes_py.py ADDED
@@ -0,0 +1,54 @@
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
+ ("UI_FF", "Dict[int, Union[str, Tuple[str]]]", None),
44
+ ("FF_STATUS", "Dict[int, Union[str, Tuple[str]]]", None),
45
+ ("INPUT_PROP", "Dict[int, Union[str, Tuple[str]]]", None)
46
+ ]
47
+
48
+ for key, annotation, doc in entries:
49
+ if doc:
50
+ print(doc)
51
+
52
+ print(f"{key}: {annotation} = ", end="")
53
+ pprint(getattr(ecodes, key))
54
+ print()