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
;
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
,
52 struct vdagentd_uinput
*uinput
;
54 uinput
= calloc(1, sizeof(*uinput
));
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
);
68 void vdagentd_uinput_destroy(struct vdagentd_uinput
**uinputp
)
70 struct vdagentd_uinput
*uinput
= *uinputp
;
81 void vdagentd_uinput_update_size(struct vdagentd_uinput
**uinputp
,
82 int width
, int height
,
83 struct vdagentd_guest_xorg_resolution
*screen_info
,
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,
93 .absmax
[ ABS_X
] = width
- 1,
94 .absmax
[ ABS_Y
] = height
- 1,
99 uinput
->screen_info
= screen_info
;
100 uinput
->screen_count
= screen_count
;
102 if (uinput
->width
== width
&& uinput
->height
== height
)
105 uinput
->width
= width
;
106 uinput
->height
= height
;
108 if (uinput
->fd
!= -1)
109 #ifndef WITH_STATIC_UINPUT
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
);
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
);
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
);
136 ioctl(uinput
->fd
, UI_SET_EVBIT
, EV_REL
);
137 ioctl(uinput
->fd
, UI_SET_RELBIT
, REL_WHEEL
);
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
);
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
= {
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
;
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 },
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
);
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);
203 if (*uinputp
&& uinput
->last
.x
!= mouse
->x
) {
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
) {
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
))
217 down
= !!(mouse
->buttons
& btns
[i
].mask
);
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
))
227 if (mouse
->buttons
& wheel
[i
].mask
) {
229 syslog(LOG_DEBUG
, "mouse: wheel-%s", wheel
[i
].name
);
230 uinput_send_event(uinputp
, EV_REL
, REL_WHEEL
, wheel
[i
].btn
);
236 syslog(LOG_DEBUG
, "mouse: syn");
237 uinput_send_event(uinputp
, EV_SYN
, SYN_REPORT
, 0);
241 uinput
->last
= *mouse
;