1 /* vdagentd-uinput.c vdagentd uinput handling code
3 Copyright 2010 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/>.
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
{
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
));
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
);
62 void vdagentd_uinput_destroy(struct vdagentd_uinput
**uinputp
)
64 struct vdagentd_uinput
*uinput
= *uinputp
;
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
,
86 if (uinput
->width
== width
&& uinput
->height
== height
)
89 uinput
->width
= width
;
90 uinput
->height
= height
;
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
);
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
);
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
);
118 ioctl(uinput
->fd
, UI_SET_EVBIT
, EV_REL
);
119 ioctl(uinput
->fd
, UI_SET_RELBIT
, REL_WHEEL
);
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
);
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
= {
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
;
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 },
173 if (*uinputp
&& uinput
->last
.x
!= mouse
->x
) {
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
) {
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
))
187 down
= !!(mouse
->buttons
& btns
[i
].mask
);
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
))
197 if (mouse
->buttons
& wheel
[i
].mask
) {
199 fprintf(uinput
->errfile
, "mouse: wheel-%s\n", wheel
[i
].name
);
200 uinput_send_event(uinputp
, EV_REL
, REL_WHEEL
, wheel
[i
].btn
);
206 fprintf(uinput
->errfile
, "mouse: syn\n");
207 uinput_send_event(uinputp
, EV_SYN
, SYN_REPORT
, 0);
211 uinput
->last
= *mouse
;