uploaded spice-vdagent
[platform/adaptation/emulator/spice-vdagent.git] / src / vdagentd-uinput.c
1 /*  vdagentd-uinput.c vdagentd uinput handling code
2
3     Copyright 2010-2012 Red Hat, Inc.
4
5     Red Hat Authors:
6     Hans de Goede <hdegoede@redhat.com>
7     Gerd Hoffmann <kraxel@redhat.com>
8
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.
13
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.
18
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/>.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
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"
35
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;
46 };
47
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)
52 {
53     struct vdagentd_uinput *uinput;
54
55     uinput = calloc(1, sizeof(*uinput));
56     if (!uinput)
57         return NULL;
58
59     uinput->devname = devname;
60     uinput->fd      = -1; /* Gets opened by vdagentd_uinput_update_size() */
61     uinput->debug   = debug;
62     uinput->fake    = fake;
63
64     vdagentd_uinput_update_size(&uinput, width, height,
65                                 screen_info, screen_count);
66
67     return uinput;
68 }
69
70 void vdagentd_uinput_destroy(struct vdagentd_uinput **uinputp)
71 {
72     struct vdagentd_uinput *uinput = *uinputp;
73
74     if (!uinput)
75         return;
76
77     if (uinput->fd != -1)
78         close(uinput->fd);
79     free(uinput);
80     *uinputp = NULL;
81 }
82
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)
87 {
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
98     };
99     int i, rc;
100
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);
106     }
107
108     uinput->screen_info  = screen_info;
109     uinput->screen_count = screen_count;
110
111     if (uinput->width == width && uinput->height == height)
112         return;
113
114     uinput->width  = width;
115     uinput->height = height;
116
117     if (uinput->fd != -1)
118 #ifndef WITH_STATIC_UINPUT
119         close(uinput->fd);
120 #else
121         return;
122 #endif
123
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;
129     }
130
131     if (uinput->fake) {
132         /* fake device doesn't understand any ioctls and only writes events */
133         return;
134     }
135
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;
141     }
142
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);
148
149     /* wheel */
150     ioctl(uinput->fd, UI_SET_EVBIT, EV_REL);
151     ioctl(uinput->fd, UI_SET_RELBIT, REL_WHEEL);
152
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);
157
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);
162     }
163 }
164
165 static void uinput_send_event(struct vdagentd_uinput **uinputp,
166     __u16 type, __u16 code, __s32 value)
167 {
168     struct vdagentd_uinput *uinput = *uinputp;
169     struct input_event event = {
170         .type  = type,
171         .code  = code,
172         .value = value,
173     };
174     int rc;
175
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);
180     }
181 }
182
183 void vdagentd_uinput_do_mouse(struct vdagentd_uinput **uinputp,
184         VDAgentMouseState *mouse)
185 {
186     struct vdagentd_uinput *uinput = *uinputp;
187     struct button_s {
188         const char *name;
189         int mask;
190         int btn;
191     };
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     },
196     };
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 },
200     };
201     int i, down;
202
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;
208         }
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
218     }
219
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);
224     }
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);
229     }
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);
239     }
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);
248         }
249     }
250
251     if (*uinputp) {
252         if (uinput->debug)
253             syslog(LOG_DEBUG, "mouse: syn");
254         uinput_send_event(uinputp, EV_SYN, SYN_REPORT, 0);
255     }
256
257     if (*uinputp)
258         uinput->last = *mouse;
259 }