Skip to content

Commit 08b9276

Browse files
committed
refactor uinput handling and tests
- set arbitrary device capabilities (defaults to all EV_KEY codes) - split uinput_open to uinput_open and uinput_create - add more tests - add uinput documentation - add uinput.capabilities() - add uinput.device which is an open InputDevice to the /dev/input/eventX node of the uinput device - uinput.write now has a simpler signature write(type, code, value) - the old uinput.write was renamed to uinput.write_event - uinput will set the event timestamp with gettimeofday
1 parent 67cd975 commit 08b9276

File tree

4 files changed

+288
-129
lines changed

4 files changed

+288
-129
lines changed

doc/moduledoc.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ evdev.device
1616
:special-members:
1717
:member-order: groupwise
1818

19+
evdev.uinput
20+
^^^^^^^^^^^^
21+
22+
.. automodule:: evdev.uinput
23+
:members: UInput
24+
:undoc-members:
25+
:special-members:
26+
:member-order: groupwise
27+
1928
evdev.util
2029
^^^^^^^^^^
2130

@@ -28,4 +37,3 @@ evdev.ecodes
2837

2938
.. automodule:: evdev.ecodes
3039
:members:
31-
:members:

evdev/uinput.c

Lines changed: 96 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,64 +12,80 @@
1212
#include <linux/uinput.h>
1313

1414

15-
static int uinput_fd = -1;
15+
int _uinput_close(int fd)
16+
{
17+
if (ioctl(fd, UI_DEV_DESTROY) < 0) {
18+
int oerrno = errno;
19+
close(fd);
20+
errno = oerrno;
21+
return -1;
22+
}
1623

17-
static void _uinput_close(void) {
18-
if (uinput_fd >= 0) {
19-
close(uinput_fd);
20-
uinput_fd = -1;
21-
}
24+
return close(fd);
2225
}
2326

2427

2528
static PyObject *
2629
uinput_open(PyObject *self, PyObject *args)
2730
{
28-
struct uinput_user_dev uidev;
31+
const char* devnode;
2932

30-
__u16 vendor, product, version;
31-
const char* name;
32-
const char* uinputdev_fn;
33-
34-
int ret = PyArg_ParseTuple(args, "shhhs", &name, &vendor, &product, &version, &uinputdev_fn);
33+
int ret = PyArg_ParseTuple(args, "s", &devnode);
3534
if (!ret) return NULL;
3635

37-
uinput_fd = open(uinputdev_fn, O_WRONLY | O_NONBLOCK);
38-
if (uinput_fd < 0) {
36+
int fd = open(devnode, O_WRONLY | O_NONBLOCK);
37+
if (fd < 0) {
3938
PyErr_SetString(PyExc_IOError, "could not open uinput device in write mode");
4039
return NULL;
4140
}
4241

42+
return Py_BuildValue("i", fd);
43+
}
44+
45+
46+
static PyObject *
47+
uinput_create(PyObject *self, PyObject *args) {
48+
int fd;
49+
__u16 vendor, product, version, bustype;
50+
51+
struct uinput_user_dev uidev;
52+
const char* name;
53+
54+
int ret = PyArg_ParseTuple(args, "ishhhh", &fd, &name, &vendor,
55+
&product, &version, &bustype);
56+
if (!ret) return NULL;
57+
4358
memset(&uidev, 0, sizeof(uidev));
4459
strncpy(uidev.name, name, UINPUT_MAX_NAME_SIZE);
45-
uidev.id.bustype = BUS_USB;
4660
uidev.id.vendor = vendor;
4761
uidev.id.product = product;
4862
uidev.id.version = version;
63+
uidev.id.bustype = bustype;
4964

50-
if (write(uinput_fd, &uidev, sizeof(uidev)) != sizeof(uidev))
51-
goto on_err;
52-
53-
if (ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY) < 0)
65+
if (write(fd, &uidev, sizeof(uidev)) != sizeof(uidev))
5466
goto on_err;
5567

56-
int i;
57-
for (i=0; i<KEY_MAX && uinput_fd; i++) {
58-
if (ioctl(uinput_fd, UI_SET_KEYBIT, i) < 0)
59-
goto on_err;
60-
}
68+
/* if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) */
69+
/* goto on_err; */
70+
/* int i; */
71+
/* for (i=0; i<KEY_MAX && fd; i++) { */
72+
/* if (ioctl(fd, UI_SET_KEYBIT, i) < 0) */
73+
/* goto on_err; */
74+
/* } */
6175

62-
if (ioctl(uinput_fd, UI_DEV_CREATE) < 0)
76+
if (ioctl(fd, UI_DEV_CREATE) < 0)
6377
goto on_err;
6478

65-
return Py_BuildValue("i", uinput_fd);
79+
80+
return Py_BuildValue("i", 1);
6681

6782
on_err:
68-
_uinput_close();
83+
_uinput_close(fd);
6984
PyErr_SetFromErrno(PyExc_IOError);
7085
return NULL;
7186
}
7287

88+
7389
static PyObject *
7490
uinput_close(PyObject *self, PyObject *args)
7591
{
@@ -78,15 +94,15 @@ uinput_close(PyObject *self, PyObject *args)
7894
int ret = PyArg_ParseTuple(args, "i", &fd);
7995
if (!ret) return NULL;
8096

81-
ret = ioctl(fd, UI_DEV_DESTROY);
82-
if (ret < 0) {
97+
if (_uinput_close(fd) < 0) {
8398
PyErr_SetFromErrno(PyExc_IOError);
8499
return NULL;
85100
}
86101

87102
return Py_BuildValue("i", 1);
88103
}
89104

105+
90106
static PyObject *
91107
uinput_write(PyObject *self, PyObject *args)
92108
{
@@ -97,31 +113,79 @@ uinput_write(PyObject *self, PyObject *args)
97113

98114
struct input_event event;
99115
memset(&event, 0, sizeof(event));
116+
gettimeofday(&event.time, 0);
100117
event.type = type;
101118
event.code = code;
102119
event.value = value;
103120

104121
if (write(fd, &event, sizeof(event)) != sizeof(event)) {
105-
PyErr_SetString(PyExc_IOError, "error writing event to uinput device"); // @todo: elaborate
122+
// @todo: elaborate
123+
PyErr_SetString(PyExc_IOError, "error writing event to uinput device");
106124
return NULL;
107-
}
125+
}
108126

109127
return Py_BuildValue("i", 1);
110128
}
111129

130+
131+
static PyObject *
132+
uinput_enable_event(PyObject *self, PyObject *args)
133+
{
134+
int fd;
135+
__u16 type, code;
136+
unsigned long req;
137+
138+
int ret = PyArg_ParseTuple(args, "ihh", &fd, &type, &code);
139+
if (!ret) return NULL;
140+
141+
switch (type) {
142+
case EV_KEY: req = UI_SET_KEYBIT; break;
143+
case EV_ABS: req = UI_SET_ABSBIT; break;
144+
case EV_REL: req = UI_SET_RELBIT; break;
145+
case EV_MSC: req = UI_SET_MSCBIT; break;
146+
case EV_SW: req = UI_SET_SWBIT; break;
147+
case EV_LED: req = UI_SET_LEDBIT; break;
148+
case EV_FF: req = UI_SET_FFBIT; break;
149+
case EV_SND: req = UI_SET_SNDBIT; break;
150+
default:
151+
errno = EINVAL;
152+
goto on_err;
153+
}
154+
155+
if (ioctl(fd, UI_SET_EVBIT, type) < 0)
156+
goto on_err;
157+
158+
if (ioctl(fd, req, code) < 0)
159+
goto on_err;
160+
161+
return Py_BuildValue("i", 1);
162+
163+
on_err:
164+
_uinput_close(fd);
165+
PyErr_SetFromErrno(PyExc_IOError);
166+
return NULL;
167+
}
168+
169+
112170
#define MODULE_NAME "_uinput"
113171
#define MODULE_HELP "Python bindings for parts of linux/uinput.c"
114172

115173
static PyMethodDef MethodTable[] = {
116174
{ "open", uinput_open, METH_VARARGS,
117-
"Create uinput device."},
175+
"Open uinput device node."},
176+
177+
{ "create", uinput_create, METH_VARARGS,
178+
"Create an uinput device."},
118179

119180
{ "close", uinput_close, METH_VARARGS,
120181
"Destroy uinput device."},
121182

122183
{ "write", uinput_write, METH_VARARGS,
123184
"Write event to uinput device."},
124185

186+
{ "enable", uinput_enable_event, METH_VARARGS,
187+
"Enable a type of event."},
188+
125189
{ NULL, NULL, 0, NULL}
126190
};
127191

0 commit comments

Comments
 (0)