-
Notifications
You must be signed in to change notification settings - Fork 2
/
uinput.c
155 lines (130 loc) · 2.9 KB
/
uinput.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <fcntl.h>
#include <linux/uinput.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "utils.h"
#include "uinput.h"
int uinput_init(struct wvnc_uinput *uinput)
{
uinput->fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (uinput->fd < 0) {
return uinput->fd;
}
uint32_t keys[] = {
BTN_LEFT, BTN_RIGHT, BTN_MIDDLE,
};
ioctl(uinput->fd, UI_SET_EVBIT, EV_KEY);
for (size_t i = 0; i < ARRAY_SIZE(keys); i++) {
ioctl(uinput->fd, UI_SET_KEYBIT, keys[i]);
}
ioctl(uinput->fd, UI_SET_EVBIT, EV_ABS);
ioctl(uinput->fd, UI_SET_ABSBIT, ABS_X);
ioctl(uinput->fd, UI_SET_ABSBIT, ABS_Y);
ioctl(uinput->fd, UI_SET_EVBIT, EV_REL);
ioctl(uinput->fd, UI_SET_RELBIT, REL_WHEEL);
struct uinput_abs_setup abs;
memset(&abs, 0, sizeof(abs));
abs.absinfo.maximum = UINPUT_ABS_MAX;
abs.absinfo.minimum = 0;
abs.code = ABS_X;
ioctl(uinput->fd, UI_ABS_SETUP, &abs);
abs.code = ABS_Y;
ioctl(uinput->fd, UI_ABS_SETUP, &abs);
struct uinput_setup set;
memset(&set, 0, sizeof(set));
set.id.bustype = BUS_VIRTUAL;
set.id.vendor = 0x0;
set.id.product = 0x0;
set.id.version = 1;
strncpy(set.name, "wvnc-device", sizeof(set.name));
ioctl(uinput->fd, UI_DEV_SETUP, &set);
ioctl(uinput->fd, UI_DEV_CREATE, 0);
// Not sleeping here causes userspace to just ignore the device,
// go figure.
// I don't think we necessarily need this, but still
usleep(500000);
uinput->initialized = true;
return 0;
}
static int dispatch_events(struct wvnc_uinput *uinput,
struct input_event *evs, size_t count)
{
for (size_t i = 0; i < count; i++) {
ssize_t ret = write(uinput->fd, &evs[i], sizeof(evs[i]));
if (ret < 0) {
return ret;
}
}
return 0;
}
int uinput_move_abs(struct wvnc_uinput *uinput, int32_t x, int32_t y)
{
struct input_event evs[] = {
{
.type = EV_ABS,
.code = ABS_X,
.value = x,
},
{
.type = EV_ABS,
.code = ABS_Y,
.value = y,
},
{
.type = EV_SYN,
.code = 0,
.value = SYN_REPORT,
},
};
return dispatch_events(uinput, evs, ARRAY_SIZE(evs));
}
int uinput_set_buttons(struct wvnc_uinput *uinput, bool left, bool middle, bool right)
{
struct input_event evs[] = {
{
.type = EV_KEY,
.code = BTN_LEFT,
.value = left
},
{
.type = EV_KEY,
.code = BTN_MIDDLE,
.value = middle
},
{
.type = EV_KEY,
.code = BTN_RIGHT,
.value = right
},
{
.type = EV_SYN,
.code = 0,
.value = SYN_REPORT,
},
};
return dispatch_events(uinput, evs, ARRAY_SIZE(evs));
}
int uinput_wheel(struct wvnc_uinput *uinput, bool up)
{
struct input_event evs[] = {
{
.type = EV_REL,
.code = REL_WHEEL,
.value = up ? 1 : -1
},
{
.type = EV_SYN,
.code = 0,
.value = SYN_REPORT,
},
};
return dispatch_events(uinput, evs, ARRAY_SIZE(evs));
}
void uinput_destroy(struct wvnc_uinput *uinput)
{
ioctl(uinput->fd, UI_DEV_DESTROY, 0);
close(uinput->fd);
uinput->initialized = false;
}