2010-03-11 15:13:28 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2010 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 or
|
|
|
|
* (at your option) version 3 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
2010-04-13 09:05:03 +02:00
|
|
|
#include <stdbool.h>
|
2010-03-11 15:13:28 +01:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <spice.h>
|
|
|
|
#include <spice/enums.h>
|
|
|
|
|
|
|
|
#include "qemu-common.h"
|
2012-11-28 12:06:30 +01:00
|
|
|
#include "ui/qemu-spice.h"
|
|
|
|
#include "ui/console.h"
|
2013-12-04 12:23:54 +01:00
|
|
|
#include "ui/keymaps.h"
|
|
|
|
#include "ui/input.h"
|
2010-03-11 15:13:28 +01:00
|
|
|
|
|
|
|
/* keyboard bits */
|
|
|
|
|
|
|
|
typedef struct QemuSpiceKbd {
|
|
|
|
SpiceKbdInstance sin;
|
|
|
|
int ledstate;
|
2013-12-04 12:23:54 +01:00
|
|
|
bool emul0;
|
2010-03-11 15:13:28 +01:00
|
|
|
} QemuSpiceKbd;
|
|
|
|
|
|
|
|
static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
|
|
|
|
static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
|
|
|
|
static void kbd_leds(void *opaque, int l);
|
|
|
|
|
|
|
|
static const SpiceKbdInterface kbd_interface = {
|
|
|
|
.base.type = SPICE_INTERFACE_KEYBOARD,
|
|
|
|
.base.description = "qemu keyboard",
|
|
|
|
.base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
|
|
|
|
.base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
|
|
|
|
.push_scan_freg = kbd_push_key,
|
|
|
|
.get_leds = kbd_get_leds,
|
|
|
|
};
|
|
|
|
|
2013-12-04 12:23:54 +01:00
|
|
|
static void kbd_push_key(SpiceKbdInstance *sin, uint8_t scancode)
|
2010-03-11 15:13:28 +01:00
|
|
|
{
|
2013-12-04 12:23:54 +01:00
|
|
|
QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
|
|
|
|
int keycode;
|
|
|
|
bool up;
|
|
|
|
|
|
|
|
if (scancode == SCANCODE_EMUL0) {
|
|
|
|
kbd->emul0 = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
keycode = scancode & ~SCANCODE_UP;
|
|
|
|
up = scancode & SCANCODE_UP;
|
|
|
|
if (kbd->emul0) {
|
|
|
|
kbd->emul0 = false;
|
|
|
|
keycode |= SCANCODE_GREY;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemu_input_event_send_key_number(NULL, keycode, !up);
|
2010-03-11 15:13:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
|
|
|
|
{
|
|
|
|
QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
|
|
|
|
return kbd->ledstate;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void kbd_leds(void *opaque, int ledstate)
|
|
|
|
{
|
|
|
|
QemuSpiceKbd *kbd = opaque;
|
|
|
|
|
|
|
|
kbd->ledstate = 0;
|
|
|
|
if (ledstate & QEMU_SCROLL_LOCK_LED) {
|
|
|
|
kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK;
|
|
|
|
}
|
|
|
|
if (ledstate & QEMU_NUM_LOCK_LED) {
|
|
|
|
kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK;
|
|
|
|
}
|
|
|
|
if (ledstate & QEMU_CAPS_LOCK_LED) {
|
|
|
|
kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK;
|
|
|
|
}
|
|
|
|
spice_server_kbd_leds(&kbd->sin, ledstate);
|
|
|
|
}
|
|
|
|
|
2010-03-11 15:13:29 +01:00
|
|
|
/* mouse bits */
|
|
|
|
|
2010-04-13 09:05:03 +02:00
|
|
|
typedef struct QemuSpicePointer {
|
|
|
|
SpiceMouseInstance mouse;
|
|
|
|
SpiceTabletInstance tablet;
|
2013-12-04 12:46:34 +01:00
|
|
|
int width, height;
|
|
|
|
uint32_t last_bmask;
|
2010-04-13 09:05:03 +02:00
|
|
|
Notifier mouse_mode;
|
|
|
|
bool absolute;
|
|
|
|
} QemuSpicePointer;
|
2010-03-11 15:13:29 +01:00
|
|
|
|
2013-12-04 12:46:34 +01:00
|
|
|
static void spice_update_buttons(QemuSpicePointer *pointer,
|
|
|
|
int wheel, uint32_t button_mask)
|
2010-03-11 15:13:29 +01:00
|
|
|
{
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 09:52:57 +01:00
|
|
|
static uint32_t bmap[INPUT_BUTTON__MAX] = {
|
2013-12-04 12:46:34 +01:00
|
|
|
[INPUT_BUTTON_LEFT] = 0x01,
|
|
|
|
[INPUT_BUTTON_MIDDLE] = 0x04,
|
|
|
|
[INPUT_BUTTON_RIGHT] = 0x02,
|
qapi: Change munging of CamelCase enum values
When munging enum values, the fact that we were passing the entire
prefix + value through camel_to_upper() meant that enum values
spelled with CamelCase could be turned into CAMEL_CASE. However,
this provides a potential collision (both OneTwo and One-Two would
munge into ONE_TWO) for enum types, when the same two names are
valid side-by-side as QAPI member names. By changing the generation
of enum constants to always be prefix + '_' + c_name(value,
False).upper(), and ensuring that there are no case collisions (in
the next patches), we no longer have to worry about names that
would be distinct as QAPI members but collide as variant tag names,
without having to think about what munging the heuristics in
camel_to_upper() will actually perform on an enum value.
Making the change will affect enums that did not follow coding
conventions, using 'CamelCase' rather than desired 'lower-case'.
Thankfully, there are only two culprits: InputButton and ErrorClass.
We already tweaked ErrorClass to make it an alias of QapiErrorClass,
where only the alias needs changing rather than the whole tree. So
the bulk of this change is modifying INPUT_BUTTON_WHEEL_UP to the
new INPUT_BUTTON_WHEELUP (and likewise for WHEELDOWN). That part
of this commit may later need reverting if we rename the enum
constants from 'WheelUp' to 'wheel-up' as part of moving
x-input-send-event to a stable interface; but at least we have
documentation bread crumbs in place to remind us (commit 513e7cd),
and it matches the fact that SDL constants are also spelled
SDL_BUTTON_WHEELUP.
Suggested by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-27-git-send-email-eblake@redhat.com>
[Commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 09:53:01 +01:00
|
|
|
[INPUT_BUTTON_WHEELUP] = 0x10,
|
|
|
|
[INPUT_BUTTON_WHEELDOWN] = 0x20,
|
2013-12-04 12:46:34 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if (wheel < 0) {
|
|
|
|
button_mask |= 0x10;
|
2010-03-11 15:13:29 +01:00
|
|
|
}
|
2013-12-04 12:46:34 +01:00
|
|
|
if (wheel > 0) {
|
|
|
|
button_mask |= 0x20;
|
2010-03-11 15:13:29 +01:00
|
|
|
}
|
2013-12-04 12:46:34 +01:00
|
|
|
|
|
|
|
if (pointer->last_bmask == button_mask) {
|
|
|
|
return;
|
2010-03-11 15:13:29 +01:00
|
|
|
}
|
2013-12-04 12:46:34 +01:00
|
|
|
qemu_input_update_buttons(NULL, bmap, pointer->last_bmask, button_mask);
|
|
|
|
pointer->last_bmask = button_mask;
|
2010-03-11 15:13:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
|
|
|
|
uint32_t buttons_state)
|
|
|
|
{
|
2013-12-04 12:46:34 +01:00
|
|
|
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
|
|
|
|
spice_update_buttons(pointer, dz, buttons_state);
|
|
|
|
qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
|
|
|
|
qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
|
|
|
|
qemu_input_event_sync();
|
2010-03-11 15:13:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
|
|
|
|
{
|
2013-12-04 12:46:34 +01:00
|
|
|
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
|
|
|
|
spice_update_buttons(pointer, 0, buttons_state);
|
|
|
|
qemu_input_event_sync();
|
2010-03-11 15:13:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static const SpiceMouseInterface mouse_interface = {
|
|
|
|
.base.type = SPICE_INTERFACE_MOUSE,
|
|
|
|
.base.description = "mouse",
|
|
|
|
.base.major_version = SPICE_INTERFACE_MOUSE_MAJOR,
|
|
|
|
.base.minor_version = SPICE_INTERFACE_MOUSE_MINOR,
|
|
|
|
.motion = mouse_motion,
|
|
|
|
.buttons = mouse_buttons,
|
|
|
|
};
|
|
|
|
|
2010-04-13 09:05:03 +02:00
|
|
|
static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height)
|
|
|
|
{
|
|
|
|
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
|
|
|
|
|
|
|
|
if (height < 16) {
|
|
|
|
height = 16;
|
|
|
|
}
|
|
|
|
if (width < 16) {
|
|
|
|
width = 16;
|
|
|
|
}
|
|
|
|
pointer->width = width;
|
|
|
|
pointer->height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tablet_position(SpiceTabletInstance* sin, int x, int y,
|
|
|
|
uint32_t buttons_state)
|
|
|
|
{
|
|
|
|
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
|
|
|
|
|
2013-12-04 12:46:34 +01:00
|
|
|
spice_update_buttons(pointer, 0, buttons_state);
|
|
|
|
qemu_input_queue_abs(NULL, INPUT_AXIS_X, x, pointer->width);
|
2014-03-21 19:28:49 +01:00
|
|
|
qemu_input_queue_abs(NULL, INPUT_AXIS_Y, y, pointer->height);
|
2013-12-04 12:46:34 +01:00
|
|
|
qemu_input_event_sync();
|
2010-04-13 09:05:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
|
|
|
|
uint32_t buttons_state)
|
|
|
|
{
|
|
|
|
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
|
|
|
|
|
2013-12-04 12:46:34 +01:00
|
|
|
spice_update_buttons(pointer, wheel, buttons_state);
|
|
|
|
qemu_input_event_sync();
|
2010-04-13 09:05:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tablet_buttons(SpiceTabletInstance *sin,
|
|
|
|
uint32_t buttons_state)
|
|
|
|
{
|
|
|
|
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
|
|
|
|
|
2013-12-04 12:46:34 +01:00
|
|
|
spice_update_buttons(pointer, 0, buttons_state);
|
|
|
|
qemu_input_event_sync();
|
2010-04-13 09:05:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const SpiceTabletInterface tablet_interface = {
|
|
|
|
.base.type = SPICE_INTERFACE_TABLET,
|
|
|
|
.base.description = "tablet",
|
|
|
|
.base.major_version = SPICE_INTERFACE_TABLET_MAJOR,
|
|
|
|
.base.minor_version = SPICE_INTERFACE_TABLET_MINOR,
|
|
|
|
.set_logical_size = tablet_set_logical_size,
|
|
|
|
.position = tablet_position,
|
|
|
|
.wheel = tablet_wheel,
|
|
|
|
.buttons = tablet_buttons,
|
|
|
|
};
|
|
|
|
|
2011-06-20 14:06:26 +02:00
|
|
|
static void mouse_mode_notifier(Notifier *notifier, void *data)
|
2010-04-13 09:05:03 +02:00
|
|
|
{
|
|
|
|
QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
|
2013-12-04 12:46:34 +01:00
|
|
|
bool is_absolute = qemu_input_is_absolute();
|
2010-04-13 09:05:03 +02:00
|
|
|
|
|
|
|
if (pointer->absolute == is_absolute) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_absolute) {
|
|
|
|
qemu_spice_add_interface(&pointer->tablet.base);
|
|
|
|
} else {
|
|
|
|
spice_server_remove_interface(&pointer->tablet.base);
|
|
|
|
}
|
|
|
|
pointer->absolute = is_absolute;
|
|
|
|
}
|
|
|
|
|
2010-03-11 15:13:28 +01:00
|
|
|
void qemu_spice_input_init(void)
|
|
|
|
{
|
|
|
|
QemuSpiceKbd *kbd;
|
2010-04-13 09:05:03 +02:00
|
|
|
QemuSpicePointer *pointer;
|
2010-03-11 15:13:28 +01:00
|
|
|
|
2011-08-21 05:09:37 +02:00
|
|
|
kbd = g_malloc0(sizeof(*kbd));
|
2010-03-11 15:13:28 +01:00
|
|
|
kbd->sin.base.sif = &kbd_interface.base;
|
|
|
|
qemu_spice_add_interface(&kbd->sin.base);
|
|
|
|
qemu_add_led_event_handler(kbd_leds, kbd);
|
2010-03-11 15:13:29 +01:00
|
|
|
|
2011-08-21 05:09:37 +02:00
|
|
|
pointer = g_malloc0(sizeof(*pointer));
|
2010-04-13 09:05:03 +02:00
|
|
|
pointer->mouse.base.sif = &mouse_interface.base;
|
|
|
|
pointer->tablet.base.sif = &tablet_interface.base;
|
|
|
|
qemu_spice_add_interface(&pointer->mouse.base);
|
|
|
|
|
|
|
|
pointer->absolute = false;
|
|
|
|
pointer->mouse_mode.notify = mouse_mode_notifier;
|
|
|
|
qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode);
|
2011-06-20 14:06:26 +02:00
|
|
|
mouse_mode_notifier(&pointer->mouse_mode, NULL);
|
2010-03-11 15:13:28 +01:00
|
|
|
}
|