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/>.
18 #include "qemu/osdep.h"
21 #include <spice/enums.h>
23 #include "ui/qemu-spice.h"
24 #include "ui/console.h"
30 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 scancode
)
52 static const uint8_t pauseseq
[] = { 0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5 };
53 QemuSpiceKbd
*kbd
= container_of(sin
, QemuSpiceKbd
, sin
);
57 if (scancode
== SCANCODE_EMUL0
) {
62 if (scancode
== pauseseq
[kbd
->pauseseq
]) {
64 if (kbd
->pauseseq
== G_N_ELEMENTS(pauseseq
)) {
65 qemu_input_event_send_key_qcode(NULL
, Q_KEY_CODE_PAUSE
, true);
73 keycode
= scancode
& ~SCANCODE_UP
;
74 up
= scancode
& SCANCODE_UP
;
77 keycode
|= SCANCODE_GREY
;
80 qemu_input_event_send_key_number(NULL
, keycode
, !up
);
83 static uint8_t kbd_get_leds(SpiceKbdInstance
*sin
)
85 QemuSpiceKbd
*kbd
= container_of(sin
, QemuSpiceKbd
, sin
);
89 static void kbd_leds(void *opaque
, int ledstate
)
91 QemuSpiceKbd
*kbd
= opaque
;
94 if (ledstate
& QEMU_SCROLL_LOCK_LED
) {
95 kbd
->ledstate
|= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK
;
97 if (ledstate
& QEMU_NUM_LOCK_LED
) {
98 kbd
->ledstate
|= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK
;
100 if (ledstate
& QEMU_CAPS_LOCK_LED
) {
101 kbd
->ledstate
|= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK
;
103 spice_server_kbd_leds(&kbd
->sin
, kbd
->ledstate
);
108 typedef struct QemuSpicePointer
{
109 SpiceMouseInstance mouse
;
110 SpiceTabletInstance tablet
;
117 static void spice_update_buttons(QemuSpicePointer
*pointer
,
118 int wheel
, uint32_t button_mask
)
120 static uint32_t bmap
[INPUT_BUTTON__MAX
] = {
121 [INPUT_BUTTON_LEFT
] = 0x01,
122 [INPUT_BUTTON_MIDDLE
] = 0x04,
123 [INPUT_BUTTON_RIGHT
] = 0x02,
124 [INPUT_BUTTON_WHEEL_UP
] = 0x10,
125 [INPUT_BUTTON_WHEEL_DOWN
] = 0x20,
126 [INPUT_BUTTON_SIDE
] = 0x40,
127 [INPUT_BUTTON_EXTRA
] = 0x80,
137 if (pointer
->last_bmask
== button_mask
) {
140 qemu_input_update_buttons(NULL
, bmap
, pointer
->last_bmask
, button_mask
);
141 pointer
->last_bmask
= button_mask
;
144 static void mouse_motion(SpiceMouseInstance
*sin
, int dx
, int dy
, int dz
,
145 uint32_t buttons_state
)
147 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, mouse
);
148 spice_update_buttons(pointer
, dz
, buttons_state
);
149 qemu_input_queue_rel(NULL
, INPUT_AXIS_X
, dx
);
150 qemu_input_queue_rel(NULL
, INPUT_AXIS_Y
, dy
);
151 qemu_input_event_sync();
154 static void mouse_buttons(SpiceMouseInstance
*sin
, uint32_t buttons_state
)
156 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, mouse
);
157 spice_update_buttons(pointer
, 0, buttons_state
);
158 qemu_input_event_sync();
161 static const SpiceMouseInterface mouse_interface
= {
162 .base
.type
= SPICE_INTERFACE_MOUSE
,
163 .base
.description
= "mouse",
164 .base
.major_version
= SPICE_INTERFACE_MOUSE_MAJOR
,
165 .base
.minor_version
= SPICE_INTERFACE_MOUSE_MINOR
,
166 .motion
= mouse_motion
,
167 .buttons
= mouse_buttons
,
170 static void tablet_set_logical_size(SpiceTabletInstance
* sin
, int width
, int height
)
172 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, tablet
);
180 pointer
->width
= width
;
181 pointer
->height
= height
;
184 static void tablet_position(SpiceTabletInstance
* sin
, int x
, int y
,
185 uint32_t buttons_state
)
187 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, tablet
);
189 spice_update_buttons(pointer
, 0, buttons_state
);
190 qemu_input_queue_abs(NULL
, INPUT_AXIS_X
, x
, 0, pointer
->width
);
191 qemu_input_queue_abs(NULL
, INPUT_AXIS_Y
, y
, 0, pointer
->height
);
192 qemu_input_event_sync();
196 static void tablet_wheel(SpiceTabletInstance
* sin
, int wheel
,
197 uint32_t buttons_state
)
199 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, tablet
);
201 spice_update_buttons(pointer
, wheel
, buttons_state
);
202 qemu_input_event_sync();
205 static void tablet_buttons(SpiceTabletInstance
*sin
,
206 uint32_t buttons_state
)
208 QemuSpicePointer
*pointer
= container_of(sin
, QemuSpicePointer
, tablet
);
210 spice_update_buttons(pointer
, 0, buttons_state
);
211 qemu_input_event_sync();
214 static const SpiceTabletInterface tablet_interface
= {
215 .base
.type
= SPICE_INTERFACE_TABLET
,
216 .base
.description
= "tablet",
217 .base
.major_version
= SPICE_INTERFACE_TABLET_MAJOR
,
218 .base
.minor_version
= SPICE_INTERFACE_TABLET_MINOR
,
219 .set_logical_size
= tablet_set_logical_size
,
220 .position
= tablet_position
,
221 .wheel
= tablet_wheel
,
222 .buttons
= tablet_buttons
,
225 static void mouse_mode_notifier(Notifier
*notifier
, void *data
)
227 QemuSpicePointer
*pointer
= container_of(notifier
, QemuSpicePointer
, mouse_mode
);
228 bool is_absolute
= qemu_input_is_absolute();
230 if (pointer
->absolute
== is_absolute
) {
235 qemu_spice_add_interface(&pointer
->tablet
.base
);
237 spice_server_remove_interface(&pointer
->tablet
.base
);
239 pointer
->absolute
= is_absolute
;
242 void qemu_spice_input_init(void)
245 QemuSpicePointer
*pointer
;
247 kbd
= g_malloc0(sizeof(*kbd
));
248 kbd
->sin
.base
.sif
= &kbd_interface
.base
;
249 qemu_spice_add_interface(&kbd
->sin
.base
);
250 qemu_add_led_event_handler(kbd_leds
, kbd
);
252 pointer
= g_malloc0(sizeof(*pointer
));
253 pointer
->mouse
.base
.sif
= &mouse_interface
.base
;
254 pointer
->tablet
.base
.sif
= &tablet_interface
.base
;
255 qemu_spice_add_interface(&pointer
->mouse
.base
);
257 pointer
->absolute
= false;
258 pointer
->mouse_mode
.notify
= mouse_mode_notifier
;
259 qemu_add_mouse_mode_change_notifier(&pointer
->mouse_mode
);
260 mouse_mode_notifier(&pointer
->mouse_mode
, NULL
);