1 /* vdagentd-uinput.c vdagentd uinput handling code
3 Copyright 2010-2012 Red Hat, Inc.
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/>.
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
{
42 struct vdagentd_guest_xorg_resolution
*screen_info
;
44 VDAgentMouseState last
;
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
,
53 struct vdagentd_uinput
*uinput
;
55 uinput
= calloc(1, sizeof(*uinput
));
59 uinput
->devname
= devname
;
60 uinput
->fd
= -1; /* Gets opened by vdagentd_uinput_update_size() */
61 uinput
->debug
= debug
;
64 vdagentd_uinput_update_size(&uinput
, width
, height
,
65 screen_info
, screen_count
);
70 void vdagentd_uinput_destroy(struct vdagentd_uinput
**uinputp
)
72 struct vdagentd_uinput
*uinput
= *uinputp
;
83 void vdagentd_uinput_update_size(struct vdagentd_uinput
**uinputp
,
84 int width
, int height
,
85 struct vdagentd_guest_xorg_resolution
*screen_info
,
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,
95 .absmax
[ ABS_X
] = width
- 1,
96 .absmax
[ ABS_Y
] = height
- 1,
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
,
108 uinput
->screen_info
= screen_info
;
109 uinput
->screen_count
= screen_count
;
111 if (uinput
->width
== width
&& uinput
->height
== height
)
114 uinput
->width
= width
;
115 uinput
->height
= height
;
117 if (uinput
->fd
!= -1)
118 #ifndef WITH_STATIC_UINPUT
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
);
132 /* fake device doesn't understand any ioctls and only writes events */
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
);
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
);
150 ioctl(uinput
->fd
, UI_SET_EVBIT
, EV_REL
);
151 ioctl(uinput
->fd
, UI_SET_RELBIT
, REL_WHEEL
);
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
);
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
= {
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
;
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 },
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
);
210 syslog(LOG_DEBUG
, "mouse-event: mon %d %dx%d", mouse
->display_id
,
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);
220 if (*uinputp
&& uinput
->last
.x
!= mouse
->x
) {
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
) {
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
))
234 down
= !!(mouse
->buttons
& btns
[i
].mask
);
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
))
244 if (mouse
->buttons
& wheel
[i
].mask
) {
246 syslog(LOG_DEBUG
, "mouse: wheel-%s", wheel
[i
].name
);
247 uinput_send_event(uinputp
, EV_REL
, REL_WHEEL
, wheel
[i
].btn
);
253 syslog(LOG_DEBUG
, "mouse: syn");
254 uinput_send_event(uinputp
, EV_SYN
, SYN_REPORT
, 0);
258 uinput
->last
= *mouse
;