evdev-binary 1.9.3__cp314-cp314t-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/input.c ADDED
@@ -0,0 +1,580 @@
1
+
2
+ /*
3
+ * Python bindings to certain linux input subsystem functions.
4
+ *
5
+ * While everything here can be implemented in pure Python with struct and
6
+ * fcntl.ioctl, imho, it is much more straightforward to do so in C.
7
+ *
8
+ */
9
+
10
+ #include <Python.h>
11
+
12
+ #include <stdio.h>
13
+ #include <stdint.h>
14
+ #include <string.h>
15
+ #include <errno.h>
16
+ #include <sys/types.h>
17
+ #include <sys/stat.h>
18
+ #include <fcntl.h>
19
+ #include <unistd.h>
20
+
21
+ #ifdef __FreeBSD__
22
+ #include <dev/evdev/input.h>
23
+ #else
24
+ #include <linux/input.h>
25
+ #endif
26
+
27
+ #ifndef input_event_sec
28
+ #define input_event_sec time.tv_sec
29
+ #define input_event_usec time.tv_usec
30
+ #endif
31
+
32
+ #define MAX_NAME_SIZE 256
33
+
34
+ extern char* EV_NAME[EV_CNT];
35
+ extern int EV_TYPE_MAX[EV_CNT];
36
+ extern char** EV_TYPE_NAME[EV_CNT];
37
+ extern char* BUS_NAME[];
38
+
39
+
40
+ int test_bit(const char* bitmask, int bit) {
41
+ return bitmask[bit/8] & (1 << (bit % 8));
42
+ }
43
+
44
+
45
+ // Read input event from a device and return a tuple that mimics input_event
46
+ static PyObject *
47
+ device_read(PyObject *self, PyObject *args)
48
+ {
49
+ struct input_event event;
50
+
51
+ // get device file descriptor (O_RDONLY|O_NONBLOCK)
52
+ int fd = (int)PyLong_AsLong(PyTuple_GET_ITEM(args, 0));
53
+
54
+ int n = read(fd, &event, sizeof(event));
55
+
56
+ if (n < 0) {
57
+ if (errno == EAGAIN) {
58
+ Py_INCREF(Py_None);
59
+ return Py_None;
60
+ }
61
+
62
+ PyErr_SetFromErrno(PyExc_OSError);
63
+ return NULL;
64
+ }
65
+
66
+ PyObject *py_input_event = PyTuple_New(5);
67
+ PyTuple_SET_ITEM(py_input_event, 0, PyLong_FromLong(event.input_event_sec));
68
+ PyTuple_SET_ITEM(py_input_event, 1, PyLong_FromLong(event.input_event_usec));
69
+ PyTuple_SET_ITEM(py_input_event, 2, PyLong_FromLong(event.type));
70
+ PyTuple_SET_ITEM(py_input_event, 3, PyLong_FromLong(event.code));
71
+ PyTuple_SET_ITEM(py_input_event, 4, PyLong_FromLong(event.value));
72
+
73
+ return py_input_event;
74
+ }
75
+
76
+
77
+ // Read multiple input events from a device and return a list of tuples
78
+ static PyObject *
79
+ device_read_many(PyObject *self, PyObject *args)
80
+ {
81
+ // get device file descriptor (O_RDONLY|O_NONBLOCK)
82
+ int fd = (int)PyLong_AsLong(PyTuple_GET_ITEM(args, 0));
83
+
84
+ struct input_event event[64];
85
+
86
+ size_t event_size = sizeof(struct input_event);
87
+ ssize_t nread = read(fd, event, event_size*64);
88
+
89
+ if (nread < 0) {
90
+ PyErr_SetFromErrno(PyExc_OSError);
91
+ return NULL;
92
+ }
93
+
94
+ // Construct a tuple of event tuples. Each tuple is the arguments to InputEvent.
95
+ size_t num_events = nread / event_size;
96
+
97
+ PyObject* events = PyTuple_New(num_events);
98
+ for (size_t i = 0 ; i < num_events; i++) {
99
+ PyObject *py_input_event = PyTuple_New(5);
100
+ PyTuple_SET_ITEM(py_input_event, 0, PyLong_FromLong(event[i].input_event_sec));
101
+ PyTuple_SET_ITEM(py_input_event, 1, PyLong_FromLong(event[i].input_event_usec));
102
+ PyTuple_SET_ITEM(py_input_event, 2, PyLong_FromLong(event[i].type));
103
+ PyTuple_SET_ITEM(py_input_event, 3, PyLong_FromLong(event[i].code));
104
+ PyTuple_SET_ITEM(py_input_event, 4, PyLong_FromLong(event[i].value));
105
+ PyTuple_SET_ITEM(events, i, py_input_event);
106
+ }
107
+
108
+ return events;
109
+ }
110
+
111
+
112
+ // Get the event types and event codes that the input device supports
113
+ static PyObject *
114
+ ioctl_capabilities(PyObject *self, PyObject *args)
115
+ {
116
+ int fd, ev_type, ev_code;
117
+ char ev_bits[EV_MAX/8 + 1], code_bits[KEY_MAX/8 + 1];
118
+ struct input_absinfo absinfo;
119
+
120
+ int ret = PyArg_ParseTuple(args, "i", &fd);
121
+ if (!ret) return NULL;
122
+
123
+ // @todo: figure out why fd gets zeroed on an ioctl after the
124
+ // refactoring and get rid of this workaround
125
+ const int _fd = fd;
126
+
127
+ // Capabilities is a mapping of supported event types to lists of handled
128
+ // events e.g: {1: [272, 273, 274, 275], 2: [0, 1, 6, 8]}
129
+ PyObject* capabilities = PyDict_New();
130
+ PyObject* eventcodes = NULL;
131
+ PyObject* evlong = NULL;
132
+ PyObject* capability = NULL;
133
+ PyObject* py_absinfo = NULL;
134
+ PyObject* absitem = NULL;
135
+
136
+ memset(&ev_bits, 0, sizeof(ev_bits));
137
+
138
+ if (ioctl(_fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0)
139
+ goto on_err;
140
+
141
+ // Build a dictionary of the device's capabilities
142
+ for (ev_type=0 ; ev_type<EV_MAX ; ev_type++) {
143
+ if (test_bit(ev_bits, ev_type)) {
144
+
145
+ capability = PyLong_FromLong(ev_type);
146
+ eventcodes = PyList_New(0);
147
+
148
+ memset(&code_bits, 0, sizeof(code_bits));
149
+ ioctl(_fd, EVIOCGBIT(ev_type, sizeof(code_bits)), code_bits);
150
+
151
+ for (ev_code = 0; ev_code < KEY_MAX; ev_code++) {
152
+ if (test_bit(code_bits, ev_code)) {
153
+ // Get abs{min,max,fuzz,flat} values for ABS_* event codes
154
+ if (ev_type == EV_ABS) {
155
+ memset(&absinfo, 0, sizeof(absinfo));
156
+ ioctl(_fd, EVIOCGABS(ev_code), &absinfo);
157
+
158
+ py_absinfo = Py_BuildValue("(iiiiii)",
159
+ absinfo.value,
160
+ absinfo.minimum,
161
+ absinfo.maximum,
162
+ absinfo.fuzz,
163
+ absinfo.flat,
164
+ absinfo.resolution);
165
+
166
+ evlong = PyLong_FromLong(ev_code);
167
+ absitem = Py_BuildValue("(OO)", evlong, py_absinfo);
168
+
169
+ // absitem -> tuple(ABS_X, (0, 255, 0, 0))
170
+ PyList_Append(eventcodes, absitem);
171
+
172
+ Py_DECREF(absitem);
173
+ Py_DECREF(py_absinfo);
174
+ }
175
+ else {
176
+ evlong = PyLong_FromLong(ev_code);
177
+ PyList_Append(eventcodes, evlong);
178
+ }
179
+
180
+ Py_DECREF(evlong);
181
+ }
182
+ }
183
+ // capabilities[EV_KEY] = [KEY_A, KEY_B, KEY_C, ...]
184
+ // capabilities[EV_ABS] = [(ABS_X, (0, 255, 0, 0)), ...]
185
+ PyDict_SetItem(capabilities, capability, eventcodes);
186
+
187
+ Py_DECREF(capability);
188
+ Py_DECREF(eventcodes);
189
+ }
190
+ }
191
+
192
+ return capabilities;
193
+
194
+ on_err:
195
+ Py_XDECREF(capabilities);
196
+ Py_XDECREF(eventcodes);
197
+ Py_XDECREF(capability);
198
+ Py_XDECREF(py_absinfo);
199
+ Py_XDECREF(absitem);
200
+ PyErr_SetFromErrno(PyExc_OSError);
201
+ return NULL;
202
+ }
203
+
204
+
205
+ // An all-in-one function for describing an input device
206
+ static PyObject *
207
+ ioctl_devinfo(PyObject *self, PyObject *args)
208
+ {
209
+ int fd;
210
+
211
+ struct input_id iid;
212
+ char name[MAX_NAME_SIZE];
213
+ char phys[MAX_NAME_SIZE] = {0};
214
+ char uniq[MAX_NAME_SIZE] = {0};
215
+
216
+ int ret = PyArg_ParseTuple(args, "i", &fd);
217
+ if (!ret) return NULL;
218
+
219
+ memset(&iid, 0, sizeof(iid));
220
+
221
+ if (ioctl(fd, EVIOCGID, &iid) < 0) goto on_err;
222
+ if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) goto on_err;
223
+
224
+ // Some devices do not have a physical topology associated with them
225
+ ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys);
226
+
227
+ // Some kernels have started reporting bluetooth controller MACs as phys.
228
+ // This lets us get the real physical address. As with phys, it may be blank.
229
+ ioctl(fd, EVIOCGUNIQ(sizeof(uniq)), uniq);
230
+
231
+ return Py_BuildValue("hhhhsss", iid.bustype, iid.vendor, iid.product, iid.version,
232
+ name, phys, uniq);
233
+
234
+ on_err:
235
+ PyErr_SetFromErrno(PyExc_OSError);
236
+ return NULL;
237
+ }
238
+
239
+
240
+ static PyObject *
241
+ ioctl_EVIOCGABS(PyObject *self, PyObject *args)
242
+ {
243
+ int fd, ev_code;
244
+ struct input_absinfo absinfo;
245
+ PyObject* py_absinfo = NULL;
246
+
247
+ int ret = PyArg_ParseTuple(args, "ii", &fd, &ev_code);
248
+ if (!ret) return NULL;
249
+
250
+ memset(&absinfo, 0, sizeof(absinfo));
251
+ ret = ioctl(fd, EVIOCGABS(ev_code), &absinfo);
252
+ if (ret == -1) {
253
+ PyErr_SetFromErrno(PyExc_OSError);
254
+ return NULL;
255
+ }
256
+
257
+ py_absinfo = Py_BuildValue("(iiiiii)",
258
+ absinfo.value,
259
+ absinfo.minimum,
260
+ absinfo.maximum,
261
+ absinfo.fuzz,
262
+ absinfo.flat,
263
+ absinfo.resolution);
264
+ return py_absinfo;
265
+ }
266
+
267
+
268
+ static PyObject *
269
+ ioctl_EVIOCSABS(PyObject *self, PyObject *args)
270
+ {
271
+ int fd, ev_code;
272
+ struct input_absinfo absinfo;
273
+
274
+ int ret = PyArg_ParseTuple(args,
275
+ "ii(iiiiii)",
276
+ &fd,
277
+ &ev_code,
278
+ &absinfo.value,
279
+ &absinfo.minimum,
280
+ &absinfo.maximum,
281
+ &absinfo.fuzz,
282
+ &absinfo.flat,
283
+ &absinfo.resolution);
284
+ if (!ret) return NULL;
285
+
286
+ ret = ioctl(fd, EVIOCSABS(ev_code), &absinfo);
287
+ if (ret == -1) {
288
+ PyErr_SetFromErrno(PyExc_OSError);
289
+ return NULL;
290
+ }
291
+
292
+ Py_INCREF(Py_None);
293
+ return Py_None;
294
+ }
295
+
296
+
297
+ static PyObject *
298
+ ioctl_EVIOCGREP(PyObject *self, PyObject *args)
299
+ {
300
+ int fd, ret;
301
+ unsigned int rep[REP_CNT] = {0};
302
+ ret = PyArg_ParseTuple(args, "i", &fd);
303
+ if (!ret) return NULL;
304
+
305
+ ret = ioctl(fd, EVIOCGREP, &rep);
306
+ if (ret == -1)
307
+ return NULL;
308
+
309
+ return Py_BuildValue("(ii)", rep[REP_DELAY], rep[REP_PERIOD]);
310
+ }
311
+
312
+
313
+ static PyObject *
314
+ ioctl_EVIOCSREP(PyObject *self, PyObject *args)
315
+ {
316
+ int fd, ret;
317
+ unsigned int rep[REP_CNT] = {0};
318
+
319
+ ret = PyArg_ParseTuple(args, "iii", &fd, &rep[0], &rep[1]);
320
+ if (!ret) return NULL;
321
+
322
+ ret = ioctl(fd, EVIOCSREP, &rep);
323
+ if (ret == -1)
324
+ return NULL;
325
+
326
+ return Py_BuildValue("i", ret);
327
+ }
328
+
329
+
330
+ static PyObject *
331
+ ioctl_EVIOCGVERSION(PyObject *self, PyObject *args)
332
+ {
333
+ int fd, ret, res;
334
+ ret = PyArg_ParseTuple(args, "i", &fd);
335
+ if (!ret) return NULL;
336
+
337
+ ret = ioctl(fd, EVIOCGVERSION, &res);
338
+ if (ret == -1)
339
+ return NULL;
340
+
341
+ return Py_BuildValue("i", res);
342
+ }
343
+
344
+
345
+ static PyObject *
346
+ ioctl_EVIOCGRAB(PyObject *self, PyObject *args)
347
+ {
348
+ int fd, ret, flag;
349
+ ret = PyArg_ParseTuple(args, "ii", &fd, &flag);
350
+ if (!ret) return NULL;
351
+
352
+ ret = ioctl(fd, EVIOCGRAB, (intptr_t)flag);
353
+ if (ret != 0) {
354
+ PyErr_SetFromErrno(PyExc_OSError);
355
+ return NULL;
356
+ }
357
+
358
+ Py_INCREF(Py_None);
359
+ return Py_None;
360
+ }
361
+
362
+
363
+ static PyObject *
364
+ ioctl_EVIOCG_bits(PyObject *self, PyObject *args)
365
+ {
366
+ int max, fd, evtype, ret;
367
+
368
+ ret = PyArg_ParseTuple(args, "ii", &fd, &evtype);
369
+ if (!ret) return NULL;
370
+
371
+ switch (evtype) {
372
+ case EV_LED:
373
+ max = LED_MAX; break;
374
+ case EV_SND:
375
+ max = SND_MAX; break;
376
+ case EV_KEY:
377
+ max = KEY_MAX; break;
378
+ case EV_SW:
379
+ max = SW_MAX; break;
380
+ default:
381
+ return NULL;
382
+ }
383
+
384
+ char bytes[(max+7)/8];
385
+ memset(bytes, 0, sizeof bytes);
386
+
387
+ switch (evtype) {
388
+ case EV_LED:
389
+ ret = ioctl(fd, EVIOCGLED(sizeof(bytes)), &bytes);
390
+ break;
391
+ case EV_SND:
392
+ ret = ioctl(fd, EVIOCGSND(sizeof(bytes)), &bytes);
393
+ break;
394
+ case EV_KEY:
395
+ ret = ioctl(fd, EVIOCGKEY(sizeof(bytes)), &bytes);
396
+ break;
397
+ case EV_SW:
398
+ ret = ioctl(fd, EVIOCGSW(sizeof(bytes)), &bytes);
399
+ break;
400
+ }
401
+
402
+ if (ret == -1)
403
+ return NULL;
404
+
405
+ PyObject* res = PyList_New(0);
406
+ for (int i=0; i<=max; i++) {
407
+ if (test_bit(bytes, i)) {
408
+ PyObject *val = PyLong_FromLong(i);
409
+ PyList_Append(res, val);
410
+ Py_DECREF(val);
411
+ }
412
+ }
413
+
414
+ return res;
415
+ }
416
+
417
+
418
+ static PyObject *
419
+ ioctl_EVIOCGEFFECTS(PyObject *self, PyObject *args)
420
+ {
421
+ int fd, ret, res;
422
+ ret = PyArg_ParseTuple(args, "i", &fd);
423
+ if (!ret) return NULL;
424
+
425
+ ret = ioctl(fd, EVIOCGEFFECTS, &res);
426
+ if (ret == -1)
427
+ return NULL;
428
+
429
+ return Py_BuildValue("i", res);
430
+ }
431
+
432
+ void print_ff_effect(struct ff_effect* effect) {
433
+ fprintf(stderr,
434
+ "ff_effect:\n"
435
+ " type: %d \n"
436
+ " id: %d \n"
437
+ " direction: %d\n"
438
+ " trigger: (%d, %d)\n"
439
+ " replay: (%d, %d)\n",
440
+ effect->type, effect->id, effect->direction,
441
+ effect->trigger.button, effect->trigger.interval,
442
+ effect->replay.length, effect->replay.delay
443
+ );
444
+
445
+
446
+ switch (effect->type) {
447
+ case FF_CONSTANT:
448
+ fprintf(stderr, " constant: (%d, (%d, %d, %d, %d))\n", effect->u.constant.level,
449
+ effect->u.constant.envelope.attack_length,
450
+ effect->u.constant.envelope.attack_level,
451
+ effect->u.constant.envelope.fade_length,
452
+ effect->u.constant.envelope.fade_level);
453
+ break;
454
+ case FF_RUMBLE:
455
+ fprintf(stderr, " rumble: (%d, %d)\n",
456
+ effect->u.rumble.strong_magnitude,
457
+ effect->u.rumble.weak_magnitude);
458
+ break;
459
+ }
460
+ }
461
+
462
+
463
+ static PyObject *
464
+ upload_effect(PyObject *self, PyObject *args)
465
+ {
466
+ int fd, ret;
467
+ PyObject* effect_data;
468
+ ret = PyArg_ParseTuple(args, "iO", &fd, &effect_data);
469
+ if (!ret) return NULL;
470
+
471
+ void* data = PyBytes_AsString(effect_data);
472
+ struct ff_effect effect = {};
473
+ memmove(&effect, data, sizeof(struct ff_effect));
474
+
475
+ // print_ff_effect(&effect);
476
+
477
+ ret = ioctl(fd, EVIOCSFF, &effect);
478
+ if (ret != 0) {
479
+ PyErr_SetFromErrno(PyExc_OSError);
480
+ return NULL;
481
+ }
482
+
483
+ return Py_BuildValue("i", effect.id);
484
+ }
485
+
486
+
487
+ static PyObject *
488
+ erase_effect(PyObject *self, PyObject *args)
489
+ {
490
+ int fd, ret;
491
+ PyObject* ff_id_obj;
492
+ ret = PyArg_ParseTuple(args, "iO", &fd, &ff_id_obj);
493
+ if (!ret) return NULL;
494
+
495
+ long ff_id = PyLong_AsLong(ff_id_obj);
496
+ ret = ioctl(fd, EVIOCRMFF, ff_id);
497
+ if (ret != 0) {
498
+ PyErr_SetFromErrno(PyExc_OSError);
499
+ return NULL;
500
+ }
501
+
502
+ Py_INCREF(Py_None);
503
+ return Py_None;
504
+ }
505
+
506
+ static PyObject *
507
+ ioctl_EVIOCGPROP(PyObject *self, PyObject *args)
508
+ {
509
+ int fd, ret;
510
+
511
+ ret = PyArg_ParseTuple(args, "i", &fd);
512
+ if (!ret) return NULL;
513
+
514
+ char bytes[(INPUT_PROP_MAX+7)/8];
515
+ memset(bytes, 0, sizeof bytes);
516
+
517
+ ret = ioctl(fd, EVIOCGPROP(sizeof(bytes)), &bytes);
518
+
519
+ if (ret == -1)
520
+ return NULL;
521
+
522
+ PyObject* res = PyList_New(0);
523
+ for (int i=0; i<INPUT_PROP_MAX; i++) {
524
+ if (test_bit(bytes, i)) {
525
+ PyObject *val = PyLong_FromLong(i);
526
+ PyList_Append(res, val);
527
+ Py_DECREF(val);
528
+ }
529
+ }
530
+
531
+ return res;
532
+ }
533
+
534
+
535
+ static PyMethodDef MethodTable[] = {
536
+ { "ioctl_devinfo", ioctl_devinfo, METH_VARARGS, "fetch input device info" },
537
+ { "ioctl_capabilities", ioctl_capabilities, METH_VARARGS, "fetch input device capabilities" },
538
+ { "ioctl_EVIOCGABS", ioctl_EVIOCGABS, METH_VARARGS, "get input device absinfo"},
539
+ { "ioctl_EVIOCSABS", ioctl_EVIOCSABS, METH_VARARGS, "set input device absinfo"},
540
+ { "ioctl_EVIOCGREP", ioctl_EVIOCGREP, METH_VARARGS},
541
+ { "ioctl_EVIOCSREP", ioctl_EVIOCSREP, METH_VARARGS},
542
+ { "ioctl_EVIOCGVERSION", ioctl_EVIOCGVERSION, METH_VARARGS},
543
+ { "ioctl_EVIOCGRAB", ioctl_EVIOCGRAB, METH_VARARGS},
544
+ { "ioctl_EVIOCGEFFECTS", ioctl_EVIOCGEFFECTS, METH_VARARGS, "fetch the number of effects the device can keep in its memory." },
545
+ { "ioctl_EVIOCG_bits", ioctl_EVIOCG_bits, METH_VARARGS, "get state of KEY|LED|SND|SW"},
546
+ { "ioctl_EVIOCGPROP", ioctl_EVIOCGPROP, METH_VARARGS, "get device properties"},
547
+ { "device_read", device_read, METH_VARARGS, "read an input event from a device" },
548
+ { "device_read_many", device_read_many, METH_VARARGS, "read all available input events from a device" },
549
+ { "upload_effect", upload_effect, METH_VARARGS, "" },
550
+ { "erase_effect", erase_effect, METH_VARARGS, "" },
551
+
552
+ { NULL, NULL, 0, NULL}
553
+ };
554
+
555
+
556
+ static struct PyModuleDef moduledef = {
557
+ PyModuleDef_HEAD_INIT,
558
+ "_input",
559
+ "Python bindings to certain linux input subsystem functions",
560
+ -1, /* m_size */
561
+ MethodTable, /* m_methods */
562
+ NULL, /* m_reload */
563
+ NULL, /* m_traverse */
564
+ NULL, /* m_clear */
565
+ NULL, /* m_free */
566
+ };
567
+
568
+ static PyObject *
569
+ moduleinit(void)
570
+ {
571
+ PyObject* m = PyModule_Create(&moduledef);
572
+ if (m == NULL) return NULL;
573
+ return m;
574
+ }
575
+
576
+ PyMODINIT_FUNC
577
+ PyInit__input(void)
578
+ {
579
+ return moduleinit();
580
+ }
evdev/py.typed ADDED
File without changes