build-sys: get rid of noinst_HEADERS
[vd_agent.git] / src / vdagentd-uinput.c
blob5a70530f59f8d408772c73489e1f0f1905bfd200
1 /* vdagentd-uinput.c vdagentd uinput handling code
3 Copyright 2010-2012 Red Hat, Inc.
5 Red Hat Authors:
6 Hans de Goede <hdegoede@redhat.com>
7 Gerd Hoffmann <kraxel@redhat.com>
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <stdlib.h>
27 #include <syslog.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <linux/input.h>
32 #include <linux/uinput.h>
33 #include <spice/vd_agent.h>
34 #include "vdagentd-uinput.h"
36 struct vdagentd_uinput {
37 const char *devname;
38 int fd;
39 int debug;
40 int width;
41 int height;
42 struct vdagentd_guest_xorg_resolution *screen_info;
43 int screen_count;
44 VDAgentMouseState last;
45 int fake;
48 struct vdagentd_uinput *vdagentd_uinput_create(const char *devname,
49 int width, int height,
50 struct vdagentd_guest_xorg_resolution *screen_info, int screen_count,
51 int debug, int fake)
53 struct vdagentd_uinput *uinput;
55 uinput = calloc(1, sizeof(*uinput));
56 if (!uinput)
57 return NULL;
59 uinput->devname = devname;
60 uinput->fd = -1; /* Gets opened by vdagentd_uinput_update_size() */
61 uinput->debug = debug;
62 uinput->fake = fake;
64 vdagentd_uinput_update_size(&uinput, width, height,
65 screen_info, screen_count);
67 return uinput;
70 void vdagentd_uinput_destroy(struct vdagentd_uinput **uinputp)
72 struct vdagentd_uinput *uinput = *uinputp;
74 if (!uinput)
75 return;
77 if (uinput->fd != -1)
78 close(uinput->fd);
79 free(uinput);
80 *uinputp = NULL;
83 void vdagentd_uinput_update_size(struct vdagentd_uinput **uinputp,
84 int width, int height,
85 struct vdagentd_guest_xorg_resolution *screen_info,
86 int screen_count)
88 struct vdagentd_uinput *uinput = *uinputp;
89 struct uinput_user_dev device = {
90 .name = "spice vdagent tablet",
91 #ifdef WITH_STATIC_UINPUT
92 .absmax [ ABS_X ] = 32767,
93 .absmax [ ABS_Y ] = 32767,
94 #else
95 .absmax [ ABS_X ] = width - 1,
96 .absmax [ ABS_Y ] = height - 1,
97 #endif
99 int i, rc;
101 if (uinput->debug) {
102 syslog(LOG_DEBUG, "uinput-update-size: %dx%d", width, height);
103 for (i = 0; i < screen_count; i++)
104 syslog(LOG_DEBUG, "screen %d: +%d+%d", i, screen_info[i].x,
105 screen_info[i].y);
108 uinput->screen_info = screen_info;
109 uinput->screen_count = screen_count;
111 if (uinput->width == width && uinput->height == height)
112 return;
114 uinput->width = width;
115 uinput->height = height;
117 if (uinput->fd != -1)
118 #ifndef WITH_STATIC_UINPUT
119 close(uinput->fd);
120 #else
121 return;
122 #endif
124 uinput->fd = open(uinput->devname, uinput->fake ? O_WRONLY : O_RDWR);
125 if (uinput->fd == -1) {
126 syslog(LOG_ERR, "open %s: %m", uinput->devname);
127 vdagentd_uinput_destroy(uinputp);
128 return;
131 if (uinput->fake) {
132 /* fake device doesn't understand any ioctls and only writes events */
133 return;
136 rc = write(uinput->fd, &device, sizeof(device));
137 if (rc != sizeof(device)) {
138 syslog(LOG_ERR, "write %s: %m", uinput->devname);
139 vdagentd_uinput_destroy(uinputp);
140 return;
143 /* buttons */
144 ioctl(uinput->fd, UI_SET_EVBIT, EV_KEY);
145 ioctl(uinput->fd, UI_SET_KEYBIT, BTN_LEFT);
146 ioctl(uinput->fd, UI_SET_KEYBIT, BTN_MIDDLE);
147 ioctl(uinput->fd, UI_SET_KEYBIT, BTN_RIGHT);
149 /* wheel */
150 ioctl(uinput->fd, UI_SET_EVBIT, EV_REL);
151 ioctl(uinput->fd, UI_SET_RELBIT, REL_WHEEL);
153 /* abs ptr */
154 ioctl(uinput->fd, UI_SET_EVBIT, EV_ABS);
155 ioctl(uinput->fd, UI_SET_ABSBIT, ABS_X);
156 ioctl(uinput->fd, UI_SET_ABSBIT, ABS_Y);
158 rc = ioctl(uinput->fd, UI_DEV_CREATE);
159 if (rc < 0) {
160 syslog(LOG_ERR, "create %s: %m", uinput->devname);
161 vdagentd_uinput_destroy(uinputp);
165 static void uinput_send_event(struct vdagentd_uinput **uinputp,
166 __u16 type, __u16 code, __s32 value)
168 struct vdagentd_uinput *uinput = *uinputp;
169 struct input_event event = {
170 .type = type,
171 .code = code,
172 .value = value,
174 int rc;
176 rc = write(uinput->fd, &event, sizeof(event));
177 if (rc != sizeof(event)) {
178 syslog(LOG_ERR, "write %s: %m", uinput->devname);
179 vdagentd_uinput_destroy(uinputp);
183 void vdagentd_uinput_do_mouse(struct vdagentd_uinput **uinputp,
184 VDAgentMouseState *mouse)
186 struct vdagentd_uinput *uinput = *uinputp;
187 struct button_s {
188 const char *name;
189 int mask;
190 int btn;
192 static const struct button_s btns[] = {
193 { .name = "left", .mask = VD_AGENT_LBUTTON_MASK, .btn = BTN_LEFT },
194 { .name = "middle", .mask = VD_AGENT_MBUTTON_MASK, .btn = BTN_MIDDLE },
195 { .name = "right", .mask = VD_AGENT_RBUTTON_MASK, .btn = BTN_RIGHT },
197 static const struct button_s wheel[] = {
198 { .name = "up", .mask = VD_AGENT_UBUTTON_MASK, .btn = 1 },
199 { .name = "down", .mask = VD_AGENT_DBUTTON_MASK, .btn = -1 },
201 int i, down;
203 if (*uinputp) {
204 if (mouse->display_id >= uinput->screen_count) {
205 syslog(LOG_WARNING, "mouse event for unknown monitor (%d >= %d)",
206 mouse->display_id, uinput->screen_count);
207 return;
209 if (uinput->debug)
210 syslog(LOG_DEBUG, "mouse-event: mon %d %dx%d", mouse->display_id,
211 mouse->x, mouse->y);
212 mouse->x += uinput->screen_info[mouse->display_id].x;
213 mouse->y += uinput->screen_info[mouse->display_id].y;
214 #ifdef WITH_STATIC_UINPUT
215 mouse->x = mouse->x * 32767 / (uinput->width - 1);
216 mouse->y = mouse->y * 32767 / (uinput->height - 1);
217 #endif
220 if (*uinputp && uinput->last.x != mouse->x) {
221 if (uinput->debug)
222 syslog(LOG_DEBUG, "mouse: abs-x %d", mouse->x);
223 uinput_send_event(uinputp, EV_ABS, ABS_X, mouse->x);
225 if (*uinputp && uinput->last.y != mouse->y) {
226 if (uinput->debug)
227 syslog(LOG_DEBUG, "mouse: abs-y %d", mouse->y);
228 uinput_send_event(uinputp, EV_ABS, ABS_Y, mouse->y);
230 for (i = 0; i < sizeof(btns)/sizeof(btns[0]) && *uinputp; i++) {
231 if ((uinput->last.buttons & btns[i].mask) ==
232 (mouse->buttons & btns[i].mask))
233 continue;
234 down = !!(mouse->buttons & btns[i].mask);
235 if (uinput->debug)
236 syslog(LOG_DEBUG, "mouse: btn-%s %s",
237 btns[i].name, down ? "down" : "up");
238 uinput_send_event(uinputp, EV_KEY, btns[i].btn, down);
240 for (i = 0; i < sizeof(wheel)/sizeof(wheel[0]) && *uinputp; i++) {
241 if ((uinput->last.buttons & wheel[i].mask) ==
242 (mouse->buttons & wheel[i].mask))
243 continue;
244 if (mouse->buttons & wheel[i].mask) {
245 if (uinput->debug)
246 syslog(LOG_DEBUG, "mouse: wheel-%s", wheel[i].name);
247 uinput_send_event(uinputp, EV_REL, REL_WHEEL, wheel[i].btn);
251 if (*uinputp) {
252 if (uinput->debug)
253 syslog(LOG_DEBUG, "mouse: syn");
254 uinput_send_event(uinputp, EV_SYN, SYN_REPORT, 0);
257 if (*uinputp)
258 uinput->last = *mouse;