2
0

spice-input.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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 "ui/qemu-spice.h"
  25. #include "ui/console.h"
  26. #include "ui/keymaps.h"
  27. #include "ui/input.h"
  28. /* keyboard bits */
  29. typedef struct QemuSpiceKbd {
  30. SpiceKbdInstance sin;
  31. int ledstate;
  32. bool emul0;
  33. } QemuSpiceKbd;
  34. static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
  35. static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
  36. static void kbd_leds(void *opaque, int l);
  37. static const SpiceKbdInterface kbd_interface = {
  38. .base.type = SPICE_INTERFACE_KEYBOARD,
  39. .base.description = "qemu keyboard",
  40. .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
  41. .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
  42. .push_scan_freg = kbd_push_key,
  43. .get_leds = kbd_get_leds,
  44. };
  45. static void kbd_push_key(SpiceKbdInstance *sin, uint8_t scancode)
  46. {
  47. QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
  48. int keycode;
  49. bool up;
  50. if (scancode == SCANCODE_EMUL0) {
  51. kbd->emul0 = true;
  52. return;
  53. }
  54. keycode = scancode & ~SCANCODE_UP;
  55. up = scancode & SCANCODE_UP;
  56. if (kbd->emul0) {
  57. kbd->emul0 = false;
  58. keycode |= SCANCODE_GREY;
  59. }
  60. qemu_input_event_send_key_number(NULL, keycode, !up);
  61. }
  62. static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
  63. {
  64. QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
  65. return kbd->ledstate;
  66. }
  67. static void kbd_leds(void *opaque, int ledstate)
  68. {
  69. QemuSpiceKbd *kbd = opaque;
  70. kbd->ledstate = 0;
  71. if (ledstate & QEMU_SCROLL_LOCK_LED) {
  72. kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK;
  73. }
  74. if (ledstate & QEMU_NUM_LOCK_LED) {
  75. kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK;
  76. }
  77. if (ledstate & QEMU_CAPS_LOCK_LED) {
  78. kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK;
  79. }
  80. spice_server_kbd_leds(&kbd->sin, ledstate);
  81. }
  82. /* mouse bits */
  83. typedef struct QemuSpicePointer {
  84. SpiceMouseInstance mouse;
  85. SpiceTabletInstance tablet;
  86. int width, height;
  87. uint32_t last_bmask;
  88. Notifier mouse_mode;
  89. bool absolute;
  90. } QemuSpicePointer;
  91. static void spice_update_buttons(QemuSpicePointer *pointer,
  92. int wheel, uint32_t button_mask)
  93. {
  94. static uint32_t bmap[INPUT_BUTTON_MAX] = {
  95. [INPUT_BUTTON_LEFT] = 0x01,
  96. [INPUT_BUTTON_MIDDLE] = 0x04,
  97. [INPUT_BUTTON_RIGHT] = 0x02,
  98. [INPUT_BUTTON_WHEEL_UP] = 0x10,
  99. [INPUT_BUTTON_WHEEL_DOWN] = 0x20,
  100. };
  101. if (wheel < 0) {
  102. button_mask |= 0x10;
  103. }
  104. if (wheel > 0) {
  105. button_mask |= 0x20;
  106. }
  107. if (pointer->last_bmask == button_mask) {
  108. return;
  109. }
  110. qemu_input_update_buttons(NULL, bmap, pointer->last_bmask, button_mask);
  111. pointer->last_bmask = button_mask;
  112. }
  113. static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
  114. uint32_t buttons_state)
  115. {
  116. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
  117. spice_update_buttons(pointer, dz, buttons_state);
  118. qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
  119. qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
  120. qemu_input_event_sync();
  121. }
  122. static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
  123. {
  124. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
  125. spice_update_buttons(pointer, 0, buttons_state);
  126. qemu_input_event_sync();
  127. }
  128. static const SpiceMouseInterface mouse_interface = {
  129. .base.type = SPICE_INTERFACE_MOUSE,
  130. .base.description = "mouse",
  131. .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR,
  132. .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR,
  133. .motion = mouse_motion,
  134. .buttons = mouse_buttons,
  135. };
  136. static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height)
  137. {
  138. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
  139. if (height < 16) {
  140. height = 16;
  141. }
  142. if (width < 16) {
  143. width = 16;
  144. }
  145. pointer->width = width;
  146. pointer->height = height;
  147. }
  148. static void tablet_position(SpiceTabletInstance* sin, int x, int y,
  149. uint32_t buttons_state)
  150. {
  151. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
  152. spice_update_buttons(pointer, 0, buttons_state);
  153. qemu_input_queue_abs(NULL, INPUT_AXIS_X, x, pointer->width);
  154. qemu_input_queue_abs(NULL, INPUT_AXIS_Y, y, pointer->height);
  155. qemu_input_event_sync();
  156. }
  157. static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
  158. uint32_t buttons_state)
  159. {
  160. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
  161. spice_update_buttons(pointer, wheel, buttons_state);
  162. qemu_input_event_sync();
  163. }
  164. static void tablet_buttons(SpiceTabletInstance *sin,
  165. uint32_t buttons_state)
  166. {
  167. QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
  168. spice_update_buttons(pointer, 0, buttons_state);
  169. qemu_input_event_sync();
  170. }
  171. static const SpiceTabletInterface tablet_interface = {
  172. .base.type = SPICE_INTERFACE_TABLET,
  173. .base.description = "tablet",
  174. .base.major_version = SPICE_INTERFACE_TABLET_MAJOR,
  175. .base.minor_version = SPICE_INTERFACE_TABLET_MINOR,
  176. .set_logical_size = tablet_set_logical_size,
  177. .position = tablet_position,
  178. .wheel = tablet_wheel,
  179. .buttons = tablet_buttons,
  180. };
  181. static void mouse_mode_notifier(Notifier *notifier, void *data)
  182. {
  183. QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
  184. bool is_absolute = qemu_input_is_absolute();
  185. if (pointer->absolute == is_absolute) {
  186. return;
  187. }
  188. if (is_absolute) {
  189. qemu_spice_add_interface(&pointer->tablet.base);
  190. } else {
  191. spice_server_remove_interface(&pointer->tablet.base);
  192. }
  193. pointer->absolute = is_absolute;
  194. }
  195. void qemu_spice_input_init(void)
  196. {
  197. QemuSpiceKbd *kbd;
  198. QemuSpicePointer *pointer;
  199. kbd = g_malloc0(sizeof(*kbd));
  200. kbd->sin.base.sif = &kbd_interface.base;
  201. qemu_spice_add_interface(&kbd->sin.base);
  202. qemu_add_led_event_handler(kbd_leds, kbd);
  203. pointer = g_malloc0(sizeof(*pointer));
  204. pointer->mouse.base.sif = &mouse_interface.base;
  205. pointer->tablet.base.sif = &tablet_interface.base;
  206. qemu_spice_add_interface(&pointer->mouse.base);
  207. pointer->absolute = false;
  208. pointer->mouse_mode.notify = mouse_mode_notifier;
  209. qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode);
  210. mouse_mode_notifier(&pointer->mouse_mode, NULL);
  211. }