spice-input.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright (C) 2010 Red Hat, Inc.
  3. *
  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.
  8. *
  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.
  13. *
  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/>.
  16. */
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <stdbool.h>
  20. #include <string.h>
  21. #include <spice.h>
  22. #include <spice/enums.h>
  23. #include "qemu-common.h"
  24. #include "qemu-spice.h"
  25. #include "console.h"
  26. /* keyboard bits */
  27. typedef struct QemuSpiceKbd {
  28. SpiceKbdInstance sin;
  29. int ledstate;
  30. } QemuSpiceKbd;
  31. static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
  32. static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
  33. static void kbd_leds(void *opaque, int l);
  34. static const SpiceKbdInterface kbd_interface = {
  35. .base.type = SPICE_INTERFACE_KEYBOARD,
  36. .base.description = "qemu keyboard",
  37. .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
  38. .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
  39. .push_scan_freg = kbd_push_key,
  40. .get_leds = kbd_get_leds,
  41. };
  42. static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
  43. {
  44. kbd_put_keycode(frag);
  45. }
  46. static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
  47. {
  48. QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
  49. return kbd->ledstate;
  50. }
  51. static void kbd_leds(void *opaque, int ledstate)
  52. {
  53. QemuSpiceKbd *kbd = opaque;
  54. kbd->ledstate = 0;
  55. if (ledstate & QEMU_SCROLL_LOCK_LED) {
  56. kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK;
  57. }
  58. if (ledstate & QEMU_NUM_LOCK_LED) {
  59. kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK;
  60. }
  61. if (ledstate & QEMU_CAPS_LOCK_LED) {
  62. kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK;
  63. }
  64. spice_server_kbd_leds(&kbd->sin, ledstate);
  65. }
  66. /* mouse bits */
  67. typedef struct QemuSpicePointer {
  68. SpiceMouseInstance mouse;
  69. SpiceTabletInstance tablet;
  70. int width, height, x, y;
  71. Notifier mouse_mode;
  72. bool absolute;
  73. } QemuSpicePointer;
  74. static int map_buttons(int spice_buttons)
  75. {
  76. int qemu_buttons = 0;
  77. /*
  78. * Note: SPICE_MOUSE_BUTTON_* specifies the wire protocol but this
  79. * isn't what we get passed in via interface callbacks for the
  80. * middle and right button ...
  81. */
  82. if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_LEFT) {
  83. qemu_buttons |= MOUSE_EVENT_LBUTTON;
  84. }
  85. if (spice_buttons & 0x04 /* SPICE_MOUSE_BUTTON_MASK_MIDDLE */) {
  86. qemu_buttons |= MOUSE_EVENT_MBUTTON;
  87. }
  88. if (spice_buttons & 0x02 /* SPICE_MOUSE_BUTTON_MASK_RIGHT */) {
  89. qemu_buttons |= MOUSE_EVENT_RBUTTON;
  90. }
  91. return qemu_buttons;
  92. }
  93. static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
  94. uint32_t buttons_state)
  95. {
  96. kbd_mouse_event(dx, dy, dz, map_buttons(buttons_state));
  97. }
  98. static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
  99. {
  100. kbd_mouse_event(0, 0, 0, map_buttons(buttons_state));
  101. }
  102. static const SpiceMouseInterface mouse_interface = {
  103. .base.type = SPICE_INTERFACE_MOUSE,
  104. .base.description = "mouse",
  105. .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR,
  106. .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR,
  107. .motion = mouse_motion,
  108. .buttons = mouse_buttons,
  109. };
  110. static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height)
  111. {
  112. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
  113. if (height < 16) {
  114. height = 16;
  115. }
  116. if (width < 16) {
  117. width = 16;
  118. }
  119. pointer->width = width;
  120. pointer->height = height;
  121. }
  122. static void tablet_position(SpiceTabletInstance* sin, int x, int y,
  123. uint32_t buttons_state)
  124. {
  125. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
  126. pointer->x = x * 0x7FFF / (pointer->width - 1);
  127. pointer->y = y * 0x7FFF / (pointer->height - 1);
  128. kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
  129. }
  130. static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
  131. uint32_t buttons_state)
  132. {
  133. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
  134. kbd_mouse_event(pointer->x, pointer->y, wheel, map_buttons(buttons_state));
  135. }
  136. static void tablet_buttons(SpiceTabletInstance *sin,
  137. uint32_t buttons_state)
  138. {
  139. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
  140. kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
  141. }
  142. static const SpiceTabletInterface tablet_interface = {
  143. .base.type = SPICE_INTERFACE_TABLET,
  144. .base.description = "tablet",
  145. .base.major_version = SPICE_INTERFACE_TABLET_MAJOR,
  146. .base.minor_version = SPICE_INTERFACE_TABLET_MINOR,
  147. .set_logical_size = tablet_set_logical_size,
  148. .position = tablet_position,
  149. .wheel = tablet_wheel,
  150. .buttons = tablet_buttons,
  151. };
  152. static void mouse_mode_notifier(Notifier *notifier, void *data)
  153. {
  154. QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
  155. bool is_absolute = kbd_mouse_is_absolute();
  156. if (pointer->absolute == is_absolute) {
  157. return;
  158. }
  159. if (is_absolute) {
  160. qemu_spice_add_interface(&pointer->tablet.base);
  161. } else {
  162. spice_server_remove_interface(&pointer->tablet.base);
  163. }
  164. pointer->absolute = is_absolute;
  165. }
  166. void qemu_spice_input_init(void)
  167. {
  168. QemuSpiceKbd *kbd;
  169. QemuSpicePointer *pointer;
  170. kbd = g_malloc0(sizeof(*kbd));
  171. kbd->sin.base.sif = &kbd_interface.base;
  172. qemu_spice_add_interface(&kbd->sin.base);
  173. qemu_add_led_event_handler(kbd_leds, kbd);
  174. pointer = g_malloc0(sizeof(*pointer));
  175. pointer->mouse.base.sif = &mouse_interface.base;
  176. pointer->tablet.base.sif = &tablet_interface.base;
  177. qemu_spice_add_interface(&pointer->mouse.base);
  178. pointer->absolute = false;
  179. pointer->mouse_mode.notify = mouse_mode_notifier;
  180. qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode);
  181. mouse_mode_notifier(&pointer->mouse_mode, NULL);
  182. }