1864401c2SGerd Hoffmann /* 2864401c2SGerd Hoffmann * Copyright (C) 2010 Red Hat, Inc. 3864401c2SGerd Hoffmann * 4864401c2SGerd Hoffmann * This program is free software; you can redistribute it and/or 5864401c2SGerd Hoffmann * modify it under the terms of the GNU General Public License as 6864401c2SGerd Hoffmann * published by the Free Software Foundation; either version 2 or 7864401c2SGerd Hoffmann * (at your option) version 3 of the License. 8864401c2SGerd Hoffmann * 9864401c2SGerd Hoffmann * This program is distributed in the hope that it will be useful, 10864401c2SGerd Hoffmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 11864401c2SGerd Hoffmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12864401c2SGerd Hoffmann * GNU General Public License for more details. 13864401c2SGerd Hoffmann * 14864401c2SGerd Hoffmann * You should have received a copy of the GNU General Public License 15864401c2SGerd Hoffmann * along with this program; if not, see <http://www.gnu.org/licenses/>. 16864401c2SGerd Hoffmann */ 17864401c2SGerd Hoffmann 18864401c2SGerd Hoffmann #include <stdlib.h> 19864401c2SGerd Hoffmann #include <stdio.h> 20869564a9SGerd Hoffmann #include <stdbool.h> 21864401c2SGerd Hoffmann #include <string.h> 22864401c2SGerd Hoffmann 23864401c2SGerd Hoffmann #include <spice.h> 24864401c2SGerd Hoffmann #include <spice/enums.h> 25864401c2SGerd Hoffmann 26864401c2SGerd Hoffmann #include "qemu-common.h" 2728ecbaeeSPaolo Bonzini #include "ui/qemu-spice.h" 2828ecbaeeSPaolo Bonzini #include "ui/console.h" 29*de8f580bSGerd Hoffmann #include "ui/keymaps.h" 30*de8f580bSGerd Hoffmann #include "ui/input.h" 31864401c2SGerd Hoffmann 32864401c2SGerd Hoffmann /* keyboard bits */ 33864401c2SGerd Hoffmann 34864401c2SGerd Hoffmann typedef struct QemuSpiceKbd { 35864401c2SGerd Hoffmann SpiceKbdInstance sin; 36864401c2SGerd Hoffmann int ledstate; 37*de8f580bSGerd Hoffmann bool emul0; 38864401c2SGerd Hoffmann } QemuSpiceKbd; 39864401c2SGerd Hoffmann 40864401c2SGerd Hoffmann static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag); 41864401c2SGerd Hoffmann static uint8_t kbd_get_leds(SpiceKbdInstance *sin); 42864401c2SGerd Hoffmann static void kbd_leds(void *opaque, int l); 43864401c2SGerd Hoffmann 44864401c2SGerd Hoffmann static const SpiceKbdInterface kbd_interface = { 45864401c2SGerd Hoffmann .base.type = SPICE_INTERFACE_KEYBOARD, 46864401c2SGerd Hoffmann .base.description = "qemu keyboard", 47864401c2SGerd Hoffmann .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR, 48864401c2SGerd Hoffmann .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR, 49864401c2SGerd Hoffmann .push_scan_freg = kbd_push_key, 50864401c2SGerd Hoffmann .get_leds = kbd_get_leds, 51864401c2SGerd Hoffmann }; 52864401c2SGerd Hoffmann 53*de8f580bSGerd Hoffmann static void kbd_push_key(SpiceKbdInstance *sin, uint8_t scancode) 54864401c2SGerd Hoffmann { 55*de8f580bSGerd Hoffmann QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin); 56*de8f580bSGerd Hoffmann int keycode; 57*de8f580bSGerd Hoffmann bool up; 58*de8f580bSGerd Hoffmann 59*de8f580bSGerd Hoffmann if (scancode == SCANCODE_EMUL0) { 60*de8f580bSGerd Hoffmann kbd->emul0 = true; 61*de8f580bSGerd Hoffmann return; 62*de8f580bSGerd Hoffmann } 63*de8f580bSGerd Hoffmann keycode = scancode & ~SCANCODE_UP; 64*de8f580bSGerd Hoffmann up = scancode & SCANCODE_UP; 65*de8f580bSGerd Hoffmann if (kbd->emul0) { 66*de8f580bSGerd Hoffmann kbd->emul0 = false; 67*de8f580bSGerd Hoffmann keycode |= SCANCODE_GREY; 68*de8f580bSGerd Hoffmann } 69*de8f580bSGerd Hoffmann 70*de8f580bSGerd Hoffmann qemu_input_event_send_key_number(NULL, keycode, !up); 71864401c2SGerd Hoffmann } 72864401c2SGerd Hoffmann 73864401c2SGerd Hoffmann static uint8_t kbd_get_leds(SpiceKbdInstance *sin) 74864401c2SGerd Hoffmann { 75864401c2SGerd Hoffmann QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin); 76864401c2SGerd Hoffmann return kbd->ledstate; 77864401c2SGerd Hoffmann } 78864401c2SGerd Hoffmann 79864401c2SGerd Hoffmann static void kbd_leds(void *opaque, int ledstate) 80864401c2SGerd Hoffmann { 81864401c2SGerd Hoffmann QemuSpiceKbd *kbd = opaque; 82864401c2SGerd Hoffmann 83864401c2SGerd Hoffmann kbd->ledstate = 0; 84864401c2SGerd Hoffmann if (ledstate & QEMU_SCROLL_LOCK_LED) { 85864401c2SGerd Hoffmann kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK; 86864401c2SGerd Hoffmann } 87864401c2SGerd Hoffmann if (ledstate & QEMU_NUM_LOCK_LED) { 88864401c2SGerd Hoffmann kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK; 89864401c2SGerd Hoffmann } 90864401c2SGerd Hoffmann if (ledstate & QEMU_CAPS_LOCK_LED) { 91864401c2SGerd Hoffmann kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK; 92864401c2SGerd Hoffmann } 93864401c2SGerd Hoffmann spice_server_kbd_leds(&kbd->sin, ledstate); 94864401c2SGerd Hoffmann } 95864401c2SGerd Hoffmann 9678dd9ac1SGerd Hoffmann /* mouse bits */ 9778dd9ac1SGerd Hoffmann 98869564a9SGerd Hoffmann typedef struct QemuSpicePointer { 99869564a9SGerd Hoffmann SpiceMouseInstance mouse; 100869564a9SGerd Hoffmann SpiceTabletInstance tablet; 101869564a9SGerd Hoffmann int width, height, x, y; 102869564a9SGerd Hoffmann Notifier mouse_mode; 103869564a9SGerd Hoffmann bool absolute; 104869564a9SGerd Hoffmann } QemuSpicePointer; 10578dd9ac1SGerd Hoffmann 10678dd9ac1SGerd Hoffmann static int map_buttons(int spice_buttons) 10778dd9ac1SGerd Hoffmann { 10878dd9ac1SGerd Hoffmann int qemu_buttons = 0; 10978dd9ac1SGerd Hoffmann 11078dd9ac1SGerd Hoffmann /* 11178dd9ac1SGerd Hoffmann * Note: SPICE_MOUSE_BUTTON_* specifies the wire protocol but this 11278dd9ac1SGerd Hoffmann * isn't what we get passed in via interface callbacks for the 11378dd9ac1SGerd Hoffmann * middle and right button ... 11478dd9ac1SGerd Hoffmann */ 11578dd9ac1SGerd Hoffmann if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_LEFT) { 11678dd9ac1SGerd Hoffmann qemu_buttons |= MOUSE_EVENT_LBUTTON; 11778dd9ac1SGerd Hoffmann } 11878dd9ac1SGerd Hoffmann if (spice_buttons & 0x04 /* SPICE_MOUSE_BUTTON_MASK_MIDDLE */) { 11978dd9ac1SGerd Hoffmann qemu_buttons |= MOUSE_EVENT_MBUTTON; 12078dd9ac1SGerd Hoffmann } 12178dd9ac1SGerd Hoffmann if (spice_buttons & 0x02 /* SPICE_MOUSE_BUTTON_MASK_RIGHT */) { 12278dd9ac1SGerd Hoffmann qemu_buttons |= MOUSE_EVENT_RBUTTON; 12378dd9ac1SGerd Hoffmann } 12478dd9ac1SGerd Hoffmann return qemu_buttons; 12578dd9ac1SGerd Hoffmann } 12678dd9ac1SGerd Hoffmann 12778dd9ac1SGerd Hoffmann static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz, 12878dd9ac1SGerd Hoffmann uint32_t buttons_state) 12978dd9ac1SGerd Hoffmann { 13078dd9ac1SGerd Hoffmann kbd_mouse_event(dx, dy, dz, map_buttons(buttons_state)); 13178dd9ac1SGerd Hoffmann } 13278dd9ac1SGerd Hoffmann 13378dd9ac1SGerd Hoffmann static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state) 13478dd9ac1SGerd Hoffmann { 13578dd9ac1SGerd Hoffmann kbd_mouse_event(0, 0, 0, map_buttons(buttons_state)); 13678dd9ac1SGerd Hoffmann } 13778dd9ac1SGerd Hoffmann 13878dd9ac1SGerd Hoffmann static const SpiceMouseInterface mouse_interface = { 13978dd9ac1SGerd Hoffmann .base.type = SPICE_INTERFACE_MOUSE, 14078dd9ac1SGerd Hoffmann .base.description = "mouse", 14178dd9ac1SGerd Hoffmann .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR, 14278dd9ac1SGerd Hoffmann .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR, 14378dd9ac1SGerd Hoffmann .motion = mouse_motion, 14478dd9ac1SGerd Hoffmann .buttons = mouse_buttons, 14578dd9ac1SGerd Hoffmann }; 14678dd9ac1SGerd Hoffmann 147869564a9SGerd Hoffmann static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height) 148869564a9SGerd Hoffmann { 149869564a9SGerd Hoffmann QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); 150869564a9SGerd Hoffmann 151869564a9SGerd Hoffmann if (height < 16) { 152869564a9SGerd Hoffmann height = 16; 153869564a9SGerd Hoffmann } 154869564a9SGerd Hoffmann if (width < 16) { 155869564a9SGerd Hoffmann width = 16; 156869564a9SGerd Hoffmann } 157869564a9SGerd Hoffmann pointer->width = width; 158869564a9SGerd Hoffmann pointer->height = height; 159869564a9SGerd Hoffmann } 160869564a9SGerd Hoffmann 161869564a9SGerd Hoffmann static void tablet_position(SpiceTabletInstance* sin, int x, int y, 162869564a9SGerd Hoffmann uint32_t buttons_state) 163869564a9SGerd Hoffmann { 164869564a9SGerd Hoffmann QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); 165869564a9SGerd Hoffmann 166869564a9SGerd Hoffmann pointer->x = x * 0x7FFF / (pointer->width - 1); 167869564a9SGerd Hoffmann pointer->y = y * 0x7FFF / (pointer->height - 1); 168869564a9SGerd Hoffmann kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state)); 169869564a9SGerd Hoffmann } 170869564a9SGerd Hoffmann 171869564a9SGerd Hoffmann 172869564a9SGerd Hoffmann static void tablet_wheel(SpiceTabletInstance* sin, int wheel, 173869564a9SGerd Hoffmann uint32_t buttons_state) 174869564a9SGerd Hoffmann { 175869564a9SGerd Hoffmann QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); 176869564a9SGerd Hoffmann 177869564a9SGerd Hoffmann kbd_mouse_event(pointer->x, pointer->y, wheel, map_buttons(buttons_state)); 178869564a9SGerd Hoffmann } 179869564a9SGerd Hoffmann 180869564a9SGerd Hoffmann static void tablet_buttons(SpiceTabletInstance *sin, 181869564a9SGerd Hoffmann uint32_t buttons_state) 182869564a9SGerd Hoffmann { 183869564a9SGerd Hoffmann QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); 184869564a9SGerd Hoffmann 185869564a9SGerd Hoffmann kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state)); 186869564a9SGerd Hoffmann } 187869564a9SGerd Hoffmann 188869564a9SGerd Hoffmann static const SpiceTabletInterface tablet_interface = { 189869564a9SGerd Hoffmann .base.type = SPICE_INTERFACE_TABLET, 190869564a9SGerd Hoffmann .base.description = "tablet", 191869564a9SGerd Hoffmann .base.major_version = SPICE_INTERFACE_TABLET_MAJOR, 192869564a9SGerd Hoffmann .base.minor_version = SPICE_INTERFACE_TABLET_MINOR, 193869564a9SGerd Hoffmann .set_logical_size = tablet_set_logical_size, 194869564a9SGerd Hoffmann .position = tablet_position, 195869564a9SGerd Hoffmann .wheel = tablet_wheel, 196869564a9SGerd Hoffmann .buttons = tablet_buttons, 197869564a9SGerd Hoffmann }; 198869564a9SGerd Hoffmann 1999e8dd451SJan Kiszka static void mouse_mode_notifier(Notifier *notifier, void *data) 200869564a9SGerd Hoffmann { 201869564a9SGerd Hoffmann QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode); 202869564a9SGerd Hoffmann bool is_absolute = kbd_mouse_is_absolute(); 203869564a9SGerd Hoffmann 204869564a9SGerd Hoffmann if (pointer->absolute == is_absolute) { 205869564a9SGerd Hoffmann return; 206869564a9SGerd Hoffmann } 207869564a9SGerd Hoffmann 208869564a9SGerd Hoffmann if (is_absolute) { 209869564a9SGerd Hoffmann qemu_spice_add_interface(&pointer->tablet.base); 210869564a9SGerd Hoffmann } else { 211869564a9SGerd Hoffmann spice_server_remove_interface(&pointer->tablet.base); 212869564a9SGerd Hoffmann } 213869564a9SGerd Hoffmann pointer->absolute = is_absolute; 214869564a9SGerd Hoffmann } 215869564a9SGerd Hoffmann 216864401c2SGerd Hoffmann void qemu_spice_input_init(void) 217864401c2SGerd Hoffmann { 218864401c2SGerd Hoffmann QemuSpiceKbd *kbd; 219869564a9SGerd Hoffmann QemuSpicePointer *pointer; 220864401c2SGerd Hoffmann 2217267c094SAnthony Liguori kbd = g_malloc0(sizeof(*kbd)); 222864401c2SGerd Hoffmann kbd->sin.base.sif = &kbd_interface.base; 223864401c2SGerd Hoffmann qemu_spice_add_interface(&kbd->sin.base); 224864401c2SGerd Hoffmann qemu_add_led_event_handler(kbd_leds, kbd); 22578dd9ac1SGerd Hoffmann 2267267c094SAnthony Liguori pointer = g_malloc0(sizeof(*pointer)); 227869564a9SGerd Hoffmann pointer->mouse.base.sif = &mouse_interface.base; 228869564a9SGerd Hoffmann pointer->tablet.base.sif = &tablet_interface.base; 229869564a9SGerd Hoffmann qemu_spice_add_interface(&pointer->mouse.base); 230869564a9SGerd Hoffmann 231869564a9SGerd Hoffmann pointer->absolute = false; 232869564a9SGerd Hoffmann pointer->mouse_mode.notify = mouse_mode_notifier; 233869564a9SGerd Hoffmann qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode); 2349e8dd451SJan Kiszka mouse_mode_notifier(&pointer->mouse_mode, NULL); 235864401c2SGerd Hoffmann } 236