spice-input.c 7.2 KB

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