vdagent-x11: move freeing of incr data sending buffers out of next_selection_request
[vd_agent/hramrach.git] / vdagentd-uinput.c
blob54cccb075bfb8979e0a70ad966db5a63643e7d7f
1 /* vdagentd-uinput.c vdagentd uinput handling code
3 Copyright 2010 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/>.
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <linux/input.h>
29 #include <linux/uinput.h>
30 #include <spice/vd_agent.h>
31 #include "vdagentd-uinput.h"
33 struct vdagentd_uinput {
34 const char *devname;
35 int fd;
36 int width;
37 int height;
38 int verbose;
39 FILE *errfile;
40 VDAgentMouseState last;
43 struct vdagentd_uinput *vdagentd_uinput_create(const char *devname,
44 int width, int height, FILE *errfile, int verbose)
46 struct vdagentd_uinput *uinput;
48 uinput = calloc(1, sizeof(*uinput));
49 if (!uinput)
50 return NULL;
52 uinput->devname = devname;
53 uinput->fd = -1; /* Gets opened by vdagentd_uinput_update_size() */
54 uinput->verbose = verbose;
55 uinput->errfile = errfile;
57 vdagentd_uinput_update_size(&uinput, width, height);
59 return uinput;
62 void vdagentd_uinput_destroy(struct vdagentd_uinput **uinputp)
64 struct vdagentd_uinput *uinput = *uinputp;
66 if (!uinput)
67 return;
69 if (uinput->fd != -1)
70 close(uinput->fd);
71 free(uinput);
72 *uinputp = NULL;
75 void vdagentd_uinput_update_size(struct vdagentd_uinput **uinputp,
76 int width, int height)
78 struct vdagentd_uinput *uinput = *uinputp;
79 struct uinput_user_dev device = {
80 .name = "spice vdagent tablet",
81 .absmax [ ABS_X ] = width,
82 .absmax [ ABS_Y ] = height,
84 int rc;
86 if (uinput->width == width && uinput->height == height)
87 return;
89 uinput->width = width;
90 uinput->height = height;
92 if (uinput->fd != -1)
93 close(uinput->fd);
95 uinput->fd = open(uinput->devname, O_RDWR);
96 if (uinput->fd == -1) {
97 fprintf(uinput->errfile, "open %s: %s\n",
98 uinput->devname, strerror(errno));
99 vdagentd_uinput_destroy(uinputp);
100 return;
103 rc = write(uinput->fd, &device, sizeof(device));
104 if (rc != sizeof(device)) {
105 fprintf(uinput->errfile, "write %s: %s\n",
106 uinput->devname, strerror(errno));
107 vdagentd_uinput_destroy(uinputp);
108 return;
111 /* buttons */
112 ioctl(uinput->fd, UI_SET_EVBIT, EV_KEY);
113 ioctl(uinput->fd, UI_SET_KEYBIT, BTN_LEFT);
114 ioctl(uinput->fd, UI_SET_KEYBIT, BTN_MIDDLE);
115 ioctl(uinput->fd, UI_SET_KEYBIT, BTN_RIGHT);
117 /* wheel */
118 ioctl(uinput->fd, UI_SET_EVBIT, EV_REL);
119 ioctl(uinput->fd, UI_SET_RELBIT, REL_WHEEL);
121 /* abs ptr */
122 ioctl(uinput->fd, UI_SET_EVBIT, EV_ABS);
123 ioctl(uinput->fd, UI_SET_ABSBIT, ABS_X);
124 ioctl(uinput->fd, UI_SET_ABSBIT, ABS_Y);
126 rc = ioctl(uinput->fd, UI_DEV_CREATE);
127 if (rc < 0) {
128 fprintf(uinput->errfile, "create %s: %s\n",
129 uinput->devname, strerror(errno));
130 vdagentd_uinput_destroy(uinputp);
134 static void uinput_send_event(struct vdagentd_uinput **uinputp,
135 __u16 type, __u16 code, __s32 value)
137 struct vdagentd_uinput *uinput = *uinputp;
138 struct input_event event = {
139 .type = type,
140 .code = code,
141 .value = value,
143 int rc;
145 rc = write(uinput->fd, &event, sizeof(event));
146 if (rc != sizeof(event)) {
147 fprintf(uinput->errfile, "write %s: %s\n",
148 uinput->devname, strerror(errno));
149 vdagentd_uinput_destroy(uinputp);
153 void vdagentd_uinput_do_mouse(struct vdagentd_uinput **uinputp,
154 VDAgentMouseState *mouse)
156 struct vdagentd_uinput *uinput = *uinputp;
157 struct button_s {
158 const char *name;
159 int mask;
160 int btn;
162 static const struct button_s btns[] = {
163 { .name = "left", .mask = VD_AGENT_LBUTTON_MASK, .btn = BTN_LEFT },
164 { .name = "middle", .mask = VD_AGENT_MBUTTON_MASK, .btn = BTN_MIDDLE },
165 { .name = "right", .mask = VD_AGENT_RBUTTON_MASK, .btn = BTN_RIGHT },
167 static const struct button_s wheel[] = {
168 { .name = "up", .mask = VD_AGENT_UBUTTON_MASK, .btn = 1 },
169 { .name = "down", .mask = VD_AGENT_DBUTTON_MASK, .btn = -1 },
171 int i, down;
173 if (*uinputp && uinput->last.x != mouse->x) {
174 if (uinput->verbose)
175 fprintf(uinput->errfile, "mouse: abs-x %d\n", mouse->x);
176 uinput_send_event(uinputp, EV_ABS, ABS_X, mouse->x);
178 if (*uinputp && uinput->last.y != mouse->y) {
179 if (uinput->verbose)
180 fprintf(uinput->errfile, "mouse: abs-y %d\n", mouse->y);
181 uinput_send_event(uinputp, EV_ABS, ABS_Y, mouse->y);
183 for (i = 0; i < sizeof(btns)/sizeof(btns[0]) && *uinputp; i++) {
184 if ((uinput->last.buttons & btns[i].mask) ==
185 (mouse->buttons & btns[i].mask))
186 continue;
187 down = !!(mouse->buttons & btns[i].mask);
188 if (uinput->verbose)
189 fprintf(uinput->errfile, "mouse: btn-%s %s\n",
190 btns[i].name, down ? "down" : "up");
191 uinput_send_event(uinputp, EV_KEY, btns[i].btn, down);
193 for (i = 0; i < sizeof(wheel)/sizeof(wheel[0]) && *uinputp; i++) {
194 if ((uinput->last.buttons & wheel[i].mask) ==
195 (mouse->buttons & wheel[i].mask))
196 continue;
197 if (mouse->buttons & wheel[i].mask) {
198 if (uinput->verbose)
199 fprintf(uinput->errfile, "mouse: wheel-%s\n", wheel[i].name);
200 uinput_send_event(uinputp, EV_REL, REL_WHEEL, wheel[i].btn);
204 if (*uinputp) {
205 if (uinput->verbose)
206 fprintf(uinput->errfile, "mouse: syn\n");
207 uinput_send_event(uinputp, EV_SYN, SYN_REPORT, 0);
210 if (*uinputp)
211 uinput->last = *mouse;