2 * Copyright (C) 2010 Red Hat, Inc.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 or
7 * (at your option) version 3 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #include <spice/enums.h>
26 #include "qemu-common.h"
27 #include "qemu-spice.h"
32 typedef struct QemuSpiceKbd
{
37 static void kbd_push_key(SpiceKbdInstance
*sin
, uint8_t frag
);
38 static uint8_t kbd_get_leds(SpiceKbdInstance
*sin
);
39 static void kbd_leds(void *opaque
, int l
);
41 static const SpiceKbdInterface kbd_interface
= {
42 .base
.type
= SPICE_INTERFACE_KEYBOARD
,
43 .base
.description
= "qemu keyboard",
44 .base
.major_version
= SPICE_INTERFACE_KEYBOARD_MAJOR
,
45 .base
.minor_version
= SPICE_INTERFACE_KEYBOARD_MINOR
,
46 .push_scan_freg
= kbd_push_key
,
47 .get_leds
= kbd_get_leds
,
50 static void kbd_push_key(SpiceKbdInstance
*sin
, uint8_t frag
)
52 kbd_put_keycode(frag
);
55 static uint8_t kbd_get_leds(SpiceKbdInstance
*sin
)
57 QemuSpiceKbd
*kbd
= container_of(sin
, QemuSpiceKbd
, sin
);
61 static void kbd_leds(void *opaque
, int ledstate
)
63 QemuSpiceKbd
*kbd
= opaque
;
66 if (ledstate
& QEMU_SCROLL_LOCK_LED
) {
67 kbd
->ledstate
|= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK
;
69 if (ledstate
& QEMU_NUM_LOCK_LED
) {
70 kbd
->ledstate
|= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK
;
72 if (ledstate
& QEMU_CAPS_LOCK_LED
) {
73 kbd
->ledstate
|= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK
;
75 spice_server_kbd_leds(&kbd
->sin
, ledstate
);
80 typedef struct QemuSpicePointer
{
81 SpiceMouseInstance mouse
;
82 SpiceTabletInstance tablet
;
83 int width
, height
, x
, y
;
88 static int map_buttons(int spice_buttons
)
93 * Note: SPICE_MOUSE_BUTTON_* specifies the wire protocol but this
94 * isn't what we get passed in via interface callbacks for the
95 * middle and right button ...
97 if (spice_buttons
& SPICE_MOUSE_BUTTON_MASK_LEFT
) {
98 qemu_buttons
|= MOUSE_EVENT_LBUTTON
;
100 if (spice_buttons
& 0x04 /* SPICE_MOUSE_BUTTON_MASK_MIDDLE */) {
101 qemu_buttons
|= MOUSE_EVENT_MBUTTON
;
103 if (spice_buttons
& 0x02 /* SPICE_MOUSE_BUTTON_MASK_RIGHT */) {
104 qemu_buttons
|= MOUSE_EVENT_RBUTTON
;
109 static void mouse_motion(SpiceMouseInstance
*sin
, int dx
, int dy
, int dz
,
110 uint32_t buttons_state
)
112 kbd_mouse_event(dx
, dy
, dz
, map_buttons(buttons_state
));
115 static void mouse_buttons(SpiceMouseInstance
*sin
, uint32_t buttons_state
)
117 kbd_mouse_event(0, 0, 0, map_buttons(buttons_state
));
120 static const SpiceMouseInterface mouse_interface
= {
121 .base
.type
= SPICE_INTERFACE_MOUSE
,
122 .base
.description
= "mouse",
123 .base
.major_version
= SPICE_INTERFACE_MOUSE_MAJOR
,
124 .base
.minor_version
= SPICE_INTERFACE_MOUSE_MINOR
,
125 .motion
= mouse_motion
,
126 .buttons
= mouse_buttons
,
129 static void tablet_set_logical_size(SpiceTabletInstance
* sin
, int width
, int height
)
131 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, tablet
);
139 pointer
->width
= width
;
140 pointer
->height
= height
;
143 static void tablet_position(SpiceTabletInstance
* sin
, int x
, int y
,
144 uint32_t buttons_state
)
146 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, tablet
);
148 pointer
->x
= x
* 0x7FFF / (pointer
->width
- 1);
149 pointer
->y
= y
* 0x7FFF / (pointer
->height
- 1);
150 kbd_mouse_event(pointer
->x
, pointer
->y
, 0, map_buttons(buttons_state
));
154 static void tablet_wheel(SpiceTabletInstance
* sin
, int wheel
,
155 uint32_t buttons_state
)
157 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, tablet
);
159 kbd_mouse_event(pointer
->x
, pointer
->y
, wheel
, map_buttons(buttons_state
));
162 static void tablet_buttons(SpiceTabletInstance
*sin
,
163 uint32_t buttons_state
)
165 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, tablet
);
167 kbd_mouse_event(pointer
->x
, pointer
->y
, 0, map_buttons(buttons_state
));
170 static const SpiceTabletInterface tablet_interface
= {
171 .base
.type
= SPICE_INTERFACE_TABLET
,
172 .base
.description
= "tablet",
173 .base
.major_version
= SPICE_INTERFACE_TABLET_MAJOR
,
174 .base
.minor_version
= SPICE_INTERFACE_TABLET_MINOR
,
175 .set_logical_size
= tablet_set_logical_size
,
176 .position
= tablet_position
,
177 .wheel
= tablet_wheel
,
178 .buttons
= tablet_buttons
,
181 static void mouse_mode_notifier(Notifier
*notifier
)
183 QemuSpicePointer
*pointer
= container_of(notifier
, QemuSpicePointer
, mouse_mode
);
184 bool is_absolute
= kbd_mouse_is_absolute();
186 if (pointer
->absolute
== is_absolute
) {
191 qemu_spice_add_interface(&pointer
->tablet
.base
);
193 spice_server_remove_interface(&pointer
->tablet
.base
);
195 pointer
->absolute
= is_absolute
;
198 void qemu_spice_input_init(void)
201 QemuSpicePointer
*pointer
;
203 kbd
= qemu_mallocz(sizeof(*kbd
));
204 kbd
->sin
.base
.sif
= &kbd_interface
.base
;
205 qemu_spice_add_interface(&kbd
->sin
.base
);
206 qemu_add_led_event_handler(kbd_leds
, kbd
);
208 pointer
= qemu_mallocz(sizeof(*pointer
));
209 pointer
->mouse
.base
.sif
= &mouse_interface
.base
;
210 pointer
->tablet
.base
.sif
= &tablet_interface
.base
;
211 qemu_spice_add_interface(&pointer
->mouse
.base
);
213 pointer
->absolute
= false;
214 pointer
->mouse_mode
.notify
= mouse_mode_notifier
;
215 qemu_add_mouse_mode_change_notifier(&pointer
->mouse_mode
);
216 mouse_mode_notifier(&pointer
->mouse_mode
);