msmouse.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * QEMU Microsoft serial mouse emulation
  3. *
  4. * Copyright (c) 2008 Lubomir Rintel
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include "qemu-common.h"
  26. #include "sysemu/char.h"
  27. #include "ui/console.h"
  28. #include "ui/input.h"
  29. #define MSMOUSE_LO6(n) ((n) & 0x3f)
  30. #define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
  31. typedef struct {
  32. Chardev parent;
  33. QemuInputHandlerState *hs;
  34. int axis[INPUT_AXIS__MAX];
  35. bool btns[INPUT_BUTTON__MAX];
  36. bool btnc[INPUT_BUTTON__MAX];
  37. uint8_t outbuf[32];
  38. int outlen;
  39. } MouseChardev;
  40. #define TYPE_CHARDEV_MSMOUSE "chardev-msmouse"
  41. #define MOUSE_CHARDEV(obj) \
  42. OBJECT_CHECK(MouseChardev, (obj), TYPE_CHARDEV_MSMOUSE)
  43. static void msmouse_chr_accept_input(Chardev *chr)
  44. {
  45. MouseChardev *mouse = MOUSE_CHARDEV(chr);
  46. int len;
  47. len = qemu_chr_be_can_write(chr);
  48. if (len > mouse->outlen) {
  49. len = mouse->outlen;
  50. }
  51. if (!len) {
  52. return;
  53. }
  54. qemu_chr_be_write(chr, mouse->outbuf, len);
  55. mouse->outlen -= len;
  56. if (mouse->outlen) {
  57. memmove(mouse->outbuf, mouse->outbuf + len, mouse->outlen);
  58. }
  59. }
  60. static void msmouse_queue_event(MouseChardev *mouse)
  61. {
  62. unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 };
  63. int dx, dy, count = 3;
  64. dx = mouse->axis[INPUT_AXIS_X];
  65. mouse->axis[INPUT_AXIS_X] = 0;
  66. dy = mouse->axis[INPUT_AXIS_Y];
  67. mouse->axis[INPUT_AXIS_Y] = 0;
  68. /* Movement deltas */
  69. bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx);
  70. bytes[1] |= MSMOUSE_LO6(dx);
  71. bytes[2] |= MSMOUSE_LO6(dy);
  72. /* Buttons */
  73. bytes[0] |= (mouse->btns[INPUT_BUTTON_LEFT] ? 0x20 : 0x00);
  74. bytes[0] |= (mouse->btns[INPUT_BUTTON_RIGHT] ? 0x10 : 0x00);
  75. if (mouse->btns[INPUT_BUTTON_MIDDLE] ||
  76. mouse->btnc[INPUT_BUTTON_MIDDLE]) {
  77. bytes[3] |= (mouse->btns[INPUT_BUTTON_MIDDLE] ? 0x20 : 0x00);
  78. mouse->btnc[INPUT_BUTTON_MIDDLE] = false;
  79. count = 4;
  80. }
  81. if (mouse->outlen <= sizeof(mouse->outbuf) - count) {
  82. memcpy(mouse->outbuf + mouse->outlen, bytes, count);
  83. mouse->outlen += count;
  84. } else {
  85. /* queue full -> drop event */
  86. }
  87. }
  88. static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
  89. InputEvent *evt)
  90. {
  91. MouseChardev *mouse = MOUSE_CHARDEV(dev);
  92. InputMoveEvent *move;
  93. InputBtnEvent *btn;
  94. switch (evt->type) {
  95. case INPUT_EVENT_KIND_REL:
  96. move = evt->u.rel.data;
  97. mouse->axis[move->axis] += move->value;
  98. break;
  99. case INPUT_EVENT_KIND_BTN:
  100. btn = evt->u.btn.data;
  101. mouse->btns[btn->button] = btn->down;
  102. mouse->btnc[btn->button] = true;
  103. break;
  104. default:
  105. /* keep gcc happy */
  106. break;
  107. }
  108. }
  109. static void msmouse_input_sync(DeviceState *dev)
  110. {
  111. MouseChardev *mouse = MOUSE_CHARDEV(dev);
  112. Chardev *chr = CHARDEV(dev);
  113. msmouse_queue_event(mouse);
  114. msmouse_chr_accept_input(chr);
  115. }
  116. static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len)
  117. {
  118. /* Ignore writes to mouse port */
  119. return len;
  120. }
  121. static void char_msmouse_finalize(Object *obj)
  122. {
  123. MouseChardev *mouse = MOUSE_CHARDEV(obj);
  124. qemu_input_handler_unregister(mouse->hs);
  125. }
  126. static QemuInputHandler msmouse_handler = {
  127. .name = "QEMU Microsoft Mouse",
  128. .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
  129. .event = msmouse_input_event,
  130. .sync = msmouse_input_sync,
  131. };
  132. static void msmouse_chr_open(Chardev *chr,
  133. ChardevBackend *backend,
  134. bool *be_opened,
  135. Error **errp)
  136. {
  137. MouseChardev *mouse = MOUSE_CHARDEV(chr);
  138. *be_opened = false;
  139. mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
  140. &msmouse_handler);
  141. }
  142. static void char_msmouse_class_init(ObjectClass *oc, void *data)
  143. {
  144. ChardevClass *cc = CHARDEV_CLASS(oc);
  145. cc->open = msmouse_chr_open;
  146. cc->chr_write = msmouse_chr_write;
  147. cc->chr_accept_input = msmouse_chr_accept_input;
  148. }
  149. static const TypeInfo char_msmouse_type_info = {
  150. .name = TYPE_CHARDEV_MSMOUSE,
  151. .parent = TYPE_CHARDEV,
  152. .instance_size = sizeof(MouseChardev),
  153. .instance_finalize = char_msmouse_finalize,
  154. .class_init = char_msmouse_class_init,
  155. };
  156. static void register_types(void)
  157. {
  158. type_register_static(&char_msmouse_type_info);
  159. }
  160. type_init(register_types);