Replace file-logging with syslog
[vd_agent/hramrach.git] / src / vdagentd-uinput.c
blob685e9c922986b3746d51d9cfd979d0dd33ca941d
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;
47 struct vdagentd_uinput *vdagentd_uinput_create(const char *devname,
48 int width, int height,
49 struct vdagentd_guest_xorg_resolution *screen_info, int screen_count,
50 int debug)
52 struct vdagentd_uinput *uinput;
54 uinput = calloc(1, sizeof(*uinput));
55 if (!uinput)
56 return NULL;
58 uinput->devname = devname;
59 uinput->fd = -1; /* Gets opened by vdagentd_uinput_update_size() */
60 uinput->debug = debug;
62 vdagentd_uinput_update_size(&uinput, width, height,
63 screen_info, screen_count);
65 return uinput;
68 void vdagentd_uinput_destroy(struct vdagentd_uinput **uinputp)
70 struct vdagentd_uinput *uinput = *uinputp;
72 if (!uinput)
73 return;
75 if (uinput->fd != -1)
76 close(uinput->fd);
77 free(uinput);
78 *uinputp = NULL;
81 void vdagentd_uinput_update_size(struct vdagentd_uinput **uinputp,
82 int width, int height,
83 struct vdagentd_guest_xorg_resolution *screen_info,
84 int screen_count)
86 struct vdagentd_uinput *uinput = *uinputp;
87 struct uinput_user_dev device = {
88 .name = "spice vdagent tablet",
89 #ifdef WITH_STATIC_UINPUT
90 .absmax [ ABS_X ] = 32767,
91 .absmax [ ABS_Y ] = 32767,
92 #else
93 .absmax [ ABS_X ] = width - 1,
94 .absmax [ ABS_Y ] = height - 1,
95 #endif
97 int rc;
99 uinput->screen_info = screen_info;
100 uinput->screen_count = screen_count;
102 if (uinput->width == width && uinput->height == height)
103 return;
105 uinput->width = width;
106 uinput->height = height;
108 if (uinput->fd != -1)
109 #ifndef WITH_STATIC_UINPUT
110 close(uinput->fd);
111 #else
112 return;
113 #endif
115 uinput->fd = open(uinput->devname, O_RDWR);
116 if (uinput->fd == -1) {
117 syslog(LOG_ERR, "open %s: %m", uinput->devname);
118 vdagentd_uinput_destroy(uinputp);
119 return;
122 rc = write(uinput->fd, &device, sizeof(device));
123 if (rc != sizeof(device)) {
124 syslog(LOG_ERR, "write %s: %m", uinput->devname);
125 vdagentd_uinput_destroy(uinputp);
126 return;
129 /* buttons */
130 ioctl(uinput->fd, UI_SET_EVBIT, EV_KEY);
131 ioctl(uinput->fd, UI_SET_KEYBIT, BTN_LEFT);
132 ioctl(uinput->fd, UI_SET_KEYBIT, BTN_MIDDLE);
133 ioctl(uinput->fd, UI_SET_KEYBIT, BTN_RIGHT);
135 /* wheel */
136 ioctl(uinput->fd, UI_SET_EVBIT, EV_REL);
137 ioctl(uinput->fd, UI_SET_RELBIT, REL_WHEEL);
139 /* abs ptr */
140 ioctl(uinput->fd, UI_SET_EVBIT, EV_ABS);
141 ioctl(uinput->fd, UI_SET_ABSBIT, ABS_X);
142 ioctl(uinput->fd, UI_SET_ABSBIT, ABS_Y);
144 rc = ioctl(uinput->fd, UI_DEV_CREATE);
145 if (rc < 0) {
146 syslog(LOG_ERR, "create %s: %m", uinput->devname);
147 vdagentd_uinput_destroy(uinputp);
151 static void uinput_send_event(struct vdagentd_uinput **uinputp,
152 __u16 type, __u16 code, __s32 value)
154 struct vdagentd_uinput *uinput = *uinputp;
155 struct input_event event = {
156 .type = type,
157 .code = code,
158 .value = value,
160 int rc;
162 rc = write(uinput->fd, &event, sizeof(event));
163 if (rc != sizeof(event)) {
164 syslog(LOG_ERR, "write %s: %m", uinput->devname);
165 vdagentd_uinput_destroy(uinputp);
169 void vdagentd_uinput_do_mouse(struct vdagentd_uinput **uinputp,
170 VDAgentMouseState *mouse)
172 struct vdagentd_uinput *uinput = *uinputp;
173 struct button_s {
174 const char *name;
175 int mask;
176 int btn;
178 static const struct button_s btns[] = {
179 { .name = "left", .mask = VD_AGENT_LBUTTON_MASK, .btn = BTN_LEFT },
180 { .name = "middle", .mask = VD_AGENT_MBUTTON_MASK, .btn = BTN_MIDDLE },
181 { .name = "right", .mask = VD_AGENT_RBUTTON_MASK, .btn = BTN_RIGHT },
183 static const struct button_s wheel[] = {
184 { .name = "up", .mask = VD_AGENT_UBUTTON_MASK, .btn = 1 },
185 { .name = "down", .mask = VD_AGENT_DBUTTON_MASK, .btn = -1 },
187 int i, down;
189 if (*uinputp) {
190 if (mouse->display_id >= uinput->screen_count) {
191 syslog(LOG_WARNING, "mouse event for unknown monitor (%d >= %d)",
192 mouse->display_id, uinput->screen_count);
193 return;
195 mouse->x += uinput->screen_info[mouse->display_id].x;
196 mouse->y += uinput->screen_info[mouse->display_id].y;
197 #ifdef WITH_STATIC_UINPUT
198 mouse->x = mouse->x * 32767 / (uinput->width - 1);
199 mouse->y = mouse->y * 32767 / (uinput->height - 1);
200 #endif
203 if (*uinputp && uinput->last.x != mouse->x) {
204 if (uinput->debug)
205 syslog(LOG_DEBUG, "mouse: abs-x %d", mouse->x);
206 uinput_send_event(uinputp, EV_ABS, ABS_X, mouse->x);
208 if (*uinputp && uinput->last.y != mouse->y) {
209 if (uinput->debug)
210 syslog(LOG_DEBUG, "mouse: abs-y %d", mouse->y);
211 uinput_send_event(uinputp, EV_ABS, ABS_Y, mouse->y);
213 for (i = 0; i < sizeof(btns)/sizeof(btns[0]) && *uinputp; i++) {
214 if ((uinput->last.buttons & btns[i].mask) ==
215 (mouse->buttons & btns[i].mask))
216 continue;
217 down = !!(mouse->buttons & btns[i].mask);
218 if (uinput->debug)
219 syslog(LOG_DEBUG, "mouse: btn-%s %s",
220 btns[i].name, down ? "down" : "up");
221 uinput_send_event(uinputp, EV_KEY, btns[i].btn, down);
223 for (i = 0; i < sizeof(wheel)/sizeof(wheel[0]) && *uinputp; i++) {
224 if ((uinput->last.buttons & wheel[i].mask) ==
225 (mouse->buttons & wheel[i].mask))
226 continue;
227 if (mouse->buttons & wheel[i].mask) {
228 if (uinput->debug)
229 syslog(LOG_DEBUG, "mouse: wheel-%s", wheel[i].name);
230 uinput_send_event(uinputp, EV_REL, REL_WHEEL, wheel[i].btn);
234 if (*uinputp) {
235 if (uinput->debug)
236 syslog(LOG_DEBUG, "mouse: syn");
237 uinput_send_event(uinputp, EV_SYN, SYN_REPORT, 0);
240 if (*uinputp)
241 uinput->last = *mouse;