2
0

spice-input.c 7.6 KB

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