1 #include <Python.h>
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10
11 #include <linux/input.h>
12 #include <linux/uinput.h>
13
14 #ifndef input_event_sec
15 #define input_event_sec time.tv_sec
16 #define input_event_usec time.tv_usec
17 #endif
18
19 // Workaround for installing on kernels newer than 4.4.
20 #ifndef FF_MAX_EFFECTS
21 #define FF_MAX_EFFECTS FF_GAIN;
22 #endif
23
_uinput_close(int fd)24 int _uinput_close(int fd)
25 {
26 if (ioctl(fd, UI_DEV_DESTROY) < 0) {
27 int oerrno = errno;
28 close(fd);
29 errno = oerrno;
30 return -1;
31 }
32
33 return close(fd);
34 }
35
36
37 static PyObject *
uinput_open(PyObject * self,PyObject * args)38 uinput_open(PyObject *self, PyObject *args)
39 {
40 const char* devnode;
41
42 int ret = PyArg_ParseTuple(args, "s", &devnode);
43 if (!ret) return NULL;
44
45 int fd = open(devnode, O_RDWR | O_NONBLOCK);
46 if (fd < 0) {
47 PyErr_SetString(PyExc_IOError, "could not open uinput device in write mode");
48 return NULL;
49 }
50
51 return Py_BuildValue("i", fd);
52 }
53
54
55 static PyObject *
uinput_set_phys(PyObject * self,PyObject * args)56 uinput_set_phys(PyObject *self, PyObject *args)
57 {
58 int fd;
59 const char* phys;
60
61 int ret = PyArg_ParseTuple(args, "is", &fd, &phys);
62 if (!ret) return NULL;
63
64 if (ioctl(fd, UI_SET_PHYS, phys) < 0)
65 goto on_err;
66
67 Py_RETURN_NONE;
68
69 on_err:
70 _uinput_close(fd);
71 PyErr_SetFromErrno(PyExc_IOError);
72 return NULL;
73 }
74
75 static PyObject *
uinput_set_prop(PyObject * self,PyObject * args)76 uinput_set_prop(PyObject *self, PyObject *args)
77 {
78 int fd;
79 uint16_t prop;
80
81 int ret = PyArg_ParseTuple(args, "ih", &fd, &prop);
82 if (!ret) return NULL;
83
84 if (ioctl(fd, UI_SET_PROPBIT, prop) < 0)
85 goto on_err;
86
87 Py_RETURN_NONE;
88
89 on_err:
90 _uinput_close(fd);
91 PyErr_SetFromErrno(PyExc_IOError);
92 return NULL;
93 }
94
95
96 // Different kernel versions have different device setup methods. You can read
97 // more about it here:
98 // https://github.com/torvalds/linux/commit/052876f8e5aec887d22c4d06e54aa5531ffcec75
99
100 // Setup function for kernel >= v4.5
101 #if defined(UI_DEV_SETUP) && defined(UI_ABS_SETUP)
102 static PyObject *
uinput_setup(PyObject * self,PyObject * args)103 uinput_setup(PyObject *self, PyObject *args) {
104 int fd, len, i;
105 uint16_t vendor, product, version, bustype;
106
107 PyObject *absinfo = NULL, *item = NULL;
108
109 struct uinput_abs_setup abs_setup;
110
111 const char* name;
112 int ret = PyArg_ParseTuple(args, "isHHHHO", &fd, &name, &vendor,
113 &product, &version, &bustype, &absinfo);
114 if (!ret) return NULL;
115
116 // Setup absinfo:
117 len = PyList_Size(absinfo);
118 for (i=0; i<len; i++) {
119
120 // item -> (ABS_X, 0, 255, 0, 0, 0, 0)
121 item = PyList_GetItem(absinfo, i);
122
123 memset(&abs_setup, 0, sizeof(abs_setup)); // Clear struct
124 abs_setup.code = PyLong_AsLong(PyList_GetItem(item, 0));
125 abs_setup.absinfo.value = PyLong_AsLong(PyList_GetItem(item, 1));
126 abs_setup.absinfo.minimum = PyLong_AsLong(PyList_GetItem(item, 2));
127 abs_setup.absinfo.maximum = PyLong_AsLong(PyList_GetItem(item, 3));
128 abs_setup.absinfo.fuzz = PyLong_AsLong(PyList_GetItem(item, 4));
129 abs_setup.absinfo.flat = PyLong_AsLong(PyList_GetItem(item, 5));
130 abs_setup.absinfo.resolution = PyLong_AsLong(PyList_GetItem(item, 6));
131
132 if(ioctl(fd, UI_ABS_SETUP, &abs_setup) < 0)
133 goto on_err;
134 }
135
136 // Setup evdev:
137 struct uinput_setup usetup;
138
139 memset(&usetup, 0, sizeof(usetup));
140 strncpy(usetup.name, name, sizeof(usetup.name) - 1);
141 usetup.id.vendor = vendor;
142 usetup.id.product = product;
143 usetup.id.version = version;
144 usetup.id.bustype = bustype;
145 usetup.ff_effects_max = FF_MAX_EFFECTS;
146
147 if(ioctl(fd, UI_DEV_SETUP, &usetup) < 0)
148 goto on_err;
149
150 Py_RETURN_NONE;
151
152 on_err:
153 _uinput_close(fd);
154 PyErr_SetFromErrno(PyExc_IOError);
155 return NULL;
156 }
157
158 // Fallback setup function (Linux <= 4.5 and FreeBSD).
159 #else
160 static PyObject *
uinput_setup(PyObject * self,PyObject * args)161 uinput_setup(PyObject *self, PyObject *args) {
162 int fd, len, i, abscode;
163 uint16_t vendor, product, version, bustype;
164
165 PyObject *absinfo = NULL, *item = NULL;
166
167 struct uinput_user_dev uidev;
168 const char* name;
169
170 int ret = PyArg_ParseTuple(args, "isHHHHO", &fd, &name, &vendor,
171 &product, &version, &bustype, &absinfo);
172 if (!ret) return NULL;
173
174 memset(&uidev, 0, sizeof(uidev));
175 strncpy(uidev.name, name, sizeof(uidev.name) - 1);
176 uidev.id.vendor = vendor;
177 uidev.id.product = product;
178 uidev.id.version = version;
179 uidev.id.bustype = bustype;
180 uidev.ff_effects_max = FF_MAX_EFFECTS;
181
182 len = PyList_Size(absinfo);
183 for (i=0; i<len; i++) {
184 // item -> (ABS_X, 0, 255, 0, 0, 0, 0)
185 item = PyList_GetItem(absinfo, i);
186 abscode = (int)PyLong_AsLong(PyList_GetItem(item, 0));
187
188 /* min/max/fuzz/flat start from index 2 because index 1 is value */
189 uidev.absmin[abscode] = PyLong_AsLong(PyList_GetItem(item, 2));
190 uidev.absmax[abscode] = PyLong_AsLong(PyList_GetItem(item, 3));
191 uidev.absfuzz[abscode] = PyLong_AsLong(PyList_GetItem(item, 4));
192 uidev.absflat[abscode] = PyLong_AsLong(PyList_GetItem(item, 5));
193 }
194
195 if (write(fd, &uidev, sizeof(uidev)) != sizeof(uidev))
196 goto on_err;
197
198 Py_RETURN_NONE;
199
200 on_err:
201 _uinput_close(fd);
202 PyErr_SetFromErrno(PyExc_IOError);
203 return NULL;
204 }
205 #endif
206
207
208 static PyObject *
uinput_create(PyObject * self,PyObject * args)209 uinput_create(PyObject *self, PyObject *args)
210 {
211 int fd;
212
213 int ret = PyArg_ParseTuple(args, "i", &fd);
214 if (!ret) return NULL;
215
216 if (ioctl(fd, UI_DEV_CREATE) < 0)
217 goto on_err;
218
219 Py_RETURN_NONE;
220
221 on_err:
222 _uinput_close(fd);
223 PyErr_SetFromErrno(PyExc_IOError);
224 return NULL;
225 }
226
227
228 static PyObject *
uinput_close(PyObject * self,PyObject * args)229 uinput_close(PyObject *self, PyObject *args)
230 {
231 int fd;
232
233 int ret = PyArg_ParseTuple(args, "i", &fd);
234 if (!ret) return NULL;
235
236 if (_uinput_close(fd) < 0) {
237 PyErr_SetFromErrno(PyExc_IOError);
238 return NULL;
239 }
240
241 Py_RETURN_NONE;
242 }
243
244
245 static PyObject *
uinput_write(PyObject * self,PyObject * args)246 uinput_write(PyObject *self, PyObject *args)
247 {
248 int fd, type, code, value;
249
250 int ret = PyArg_ParseTuple(args, "iiii", &fd, &type, &code, &value);
251 if (!ret) return NULL;
252
253 struct input_event event;
254 struct timeval tval;
255 memset(&event, 0, sizeof(event));
256 gettimeofday(&tval, 0);
257 event.input_event_usec = tval.tv_usec;
258 event.input_event_sec = tval.tv_sec;
259 event.type = type;
260 event.code = code;
261 event.value = value;
262
263 if (write(fd, &event, sizeof(event)) != sizeof(event)) {
264 // @todo: elaborate
265 // PyErr_SetString(PyExc_IOError, "error writing event to uinput device");
266 PyErr_SetFromErrno(PyExc_IOError);
267 return NULL;
268 }
269
270 Py_RETURN_NONE;
271 }
272
273
274 static PyObject *
uinput_enable_event(PyObject * self,PyObject * args)275 uinput_enable_event(PyObject *self, PyObject *args)
276 {
277 int fd;
278 uint16_t type, code;
279 unsigned long req;
280
281 int ret = PyArg_ParseTuple(args, "ihh", &fd, &type, &code);
282 if (!ret) return NULL;
283
284 switch (type) {
285 case EV_KEY: req = UI_SET_KEYBIT; break;
286 case EV_ABS: req = UI_SET_ABSBIT; break;
287 case EV_REL: req = UI_SET_RELBIT; break;
288 case EV_MSC: req = UI_SET_MSCBIT; break;
289 case EV_SW: req = UI_SET_SWBIT; break;
290 case EV_LED: req = UI_SET_LEDBIT; break;
291 case EV_FF: req = UI_SET_FFBIT; break;
292 case EV_SND: req = UI_SET_SNDBIT; break;
293 default:
294 errno = EINVAL;
295 goto on_err;
296 }
297
298 if (ioctl(fd, UI_SET_EVBIT, type) < 0)
299 goto on_err;
300
301 if (ioctl(fd, req, code) < 0)
302 goto on_err;
303
304 Py_RETURN_NONE;
305
306 on_err:
307 _uinput_close(fd);
308 PyErr_SetFromErrno(PyExc_IOError);
309 return NULL;
310 }
311
_uinput_begin_upload(int fd,struct uinput_ff_upload * upload)312 int _uinput_begin_upload(int fd, struct uinput_ff_upload *upload)
313 {
314 return ioctl(fd, UI_BEGIN_FF_UPLOAD, upload);
315 }
316
_uinput_end_upload(int fd,struct uinput_ff_upload * upload)317 int _uinput_end_upload(int fd, struct uinput_ff_upload *upload)
318 {
319 return ioctl(fd, UI_END_FF_UPLOAD, upload);
320 }
321
_uinput_begin_erase(int fd,struct uinput_ff_erase * upload)322 int _uinput_begin_erase(int fd, struct uinput_ff_erase *upload)
323 {
324 return ioctl(fd, UI_BEGIN_FF_ERASE, upload);
325 }
326
_uinput_end_erase(int fd,struct uinput_ff_erase * upload)327 int _uinput_end_erase(int fd, struct uinput_ff_erase *upload)
328 {
329 return ioctl(fd, UI_END_FF_ERASE, upload);
330 }
331
332 #define MODULE_NAME "_uinput"
333 #define MODULE_HELP "Python bindings for parts of linux/uinput.c"
334
335 static PyMethodDef MethodTable[] = {
336 { "open", uinput_open, METH_VARARGS,
337 "Open uinput device node."},
338
339 { "setup", uinput_setup, METH_VARARGS,
340 "Set an uinput device up."},
341
342 { "create", uinput_create, METH_VARARGS,
343 "Create an uinput device."},
344
345 { "close", uinput_close, METH_VARARGS,
346 "Destroy uinput device."},
347
348 { "write", uinput_write, METH_VARARGS,
349 "Write event to uinput device."},
350
351 { "enable", uinput_enable_event, METH_VARARGS,
352 "Enable a type of event."},
353
354 { "set_phys", uinput_set_phys, METH_VARARGS,
355 "Set physical path"},
356
357 { "set_prop", uinput_set_prop, METH_VARARGS,
358 "Set device input property"},
359
360 { NULL, NULL, 0, NULL}
361 };
362
363 #if PY_MAJOR_VERSION >= 3
364 static struct PyModuleDef moduledef = {
365 PyModuleDef_HEAD_INIT,
366 MODULE_NAME,
367 MODULE_HELP,
368 -1, /* m_size */
369 MethodTable, /* m_methods */
370 NULL, /* m_reload */
371 NULL, /* m_traverse */
372 NULL, /* m_clear */
373 NULL, /* m_free */
374 };
375
376 static PyObject *
moduleinit(void)377 moduleinit(void)
378 {
379 PyObject* m = PyModule_Create(&moduledef);
380 if (m == NULL) return NULL;
381
382 PyModule_AddIntConstant(m, "maxnamelen", UINPUT_MAX_NAME_SIZE);
383 return m;
384 }
385
386 PyMODINIT_FUNC
PyInit__uinput(void)387 PyInit__uinput(void)
388 {
389 return moduleinit();
390 }
391
392 #else
393 static PyObject *
moduleinit(void)394 moduleinit(void)
395 {
396 PyObject* m = Py_InitModule3(MODULE_NAME, MethodTable, MODULE_HELP);
397 if (m == NULL) return NULL;
398
399 PyModule_AddIntConstant(m, "maxnamelen", UINPUT_MAX_NAME_SIZE);
400 return m;
401 }
402
403 PyMODINIT_FUNC
init_uinput(void)404 init_uinput(void)
405 {
406 moduleinit();
407 }
408 #endif
409