spice-input.c 7.6 KB

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