Commit 09b26c5ec06ff7531a2a2a7b1146011c87285f81
1 parent
6a15fd12
USB tablet support (Brad Campbell, Anthony Liguori)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1810 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
265 additions
and
24 deletions
hw/ps2.c
| @@ -560,7 +560,7 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) | @@ -560,7 +560,7 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) | ||
| 560 | s->common.update_arg = update_arg; | 560 | s->common.update_arg = update_arg; |
| 561 | ps2_reset(&s->common); | 561 | ps2_reset(&s->common); |
| 562 | register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s); | 562 | register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s); |
| 563 | - qemu_add_mouse_event_handler(ps2_mouse_event, s); | 563 | + qemu_add_mouse_event_handler(ps2_mouse_event, s, 0); |
| 564 | qemu_register_reset(ps2_reset, &s->common); | 564 | qemu_register_reset(ps2_reset, &s->common); |
| 565 | return s; | 565 | return s; |
| 566 | } | 566 | } |
hw/usb-hid.c
| @@ -30,9 +30,15 @@ | @@ -30,9 +30,15 @@ | ||
| 30 | #define SET_IDLE 0x210a | 30 | #define SET_IDLE 0x210a |
| 31 | #define SET_PROTOCOL 0x210b | 31 | #define SET_PROTOCOL 0x210b |
| 32 | 32 | ||
| 33 | +#define USB_MOUSE 1 | ||
| 34 | +#define USB_TABLET 2 | ||
| 35 | + | ||
| 33 | typedef struct USBMouseState { | 36 | typedef struct USBMouseState { |
| 34 | USBDevice dev; | 37 | USBDevice dev; |
| 35 | int dx, dy, dz, buttons_state; | 38 | int dx, dy, dz, buttons_state; |
| 39 | + int x, y; | ||
| 40 | + int kind; | ||
| 41 | + int mouse_grabbed; | ||
| 36 | } USBMouseState; | 42 | } USBMouseState; |
| 37 | 43 | ||
| 38 | /* mostly the same values as the Bochs USB Mouse device */ | 44 | /* mostly the same values as the Bochs USB Mouse device */ |
| @@ -93,6 +99,15 @@ static const uint8_t qemu_mouse_config_descriptor[] = { | @@ -93,6 +99,15 @@ static const uint8_t qemu_mouse_config_descriptor[] = { | ||
| 93 | 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ | 99 | 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ |
| 94 | 0x05, /* u8 if_iInterface; */ | 100 | 0x05, /* u8 if_iInterface; */ |
| 95 | 101 | ||
| 102 | + /* HID descriptor */ | ||
| 103 | + 0x09, /* u8 bLength; */ | ||
| 104 | + 0x21, /* u8 bDescriptorType; */ | ||
| 105 | + 0x01, 0x00, /* u16 HID_class */ | ||
| 106 | + 0x00, /* u8 country_code */ | ||
| 107 | + 0x01, /* u8 num_descriptors */ | ||
| 108 | + 0x22, /* u8 type; Report */ | ||
| 109 | + 50, 0, /* u16 len */ | ||
| 110 | + | ||
| 96 | /* one endpoint (status change endpoint) */ | 111 | /* one endpoint (status change endpoint) */ |
| 97 | 0x07, /* u8 ep_bLength; */ | 112 | 0x07, /* u8 ep_bLength; */ |
| 98 | 0x05, /* u8 ep_bDescriptorType; Endpoint */ | 113 | 0x05, /* u8 ep_bDescriptorType; Endpoint */ |
| @@ -100,6 +115,44 @@ static const uint8_t qemu_mouse_config_descriptor[] = { | @@ -100,6 +115,44 @@ static const uint8_t qemu_mouse_config_descriptor[] = { | ||
| 100 | 0x03, /* u8 ep_bmAttributes; Interrupt */ | 115 | 0x03, /* u8 ep_bmAttributes; Interrupt */ |
| 101 | 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ | 116 | 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ |
| 102 | 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ | 117 | 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ |
| 118 | +}; | ||
| 119 | + | ||
| 120 | +static const uint8_t qemu_tablet_config_descriptor[] = { | ||
| 121 | + /* one configuration */ | ||
| 122 | + 0x09, /* u8 bLength; */ | ||
| 123 | + 0x02, /* u8 bDescriptorType; Configuration */ | ||
| 124 | + 0x22, 0x00, /* u16 wTotalLength; */ | ||
| 125 | + 0x01, /* u8 bNumInterfaces; (1) */ | ||
| 126 | + 0x01, /* u8 bConfigurationValue; */ | ||
| 127 | + 0x04, /* u8 iConfiguration; */ | ||
| 128 | + 0xa0, /* u8 bmAttributes; | ||
| 129 | + Bit 7: must be set, | ||
| 130 | + 6: Self-powered, | ||
| 131 | + 5: Remote wakeup, | ||
| 132 | + 4..0: resvd */ | ||
| 133 | + 50, /* u8 MaxPower; */ | ||
| 134 | + | ||
| 135 | + /* USB 1.1: | ||
| 136 | + * USB 2.0, single TT organization (mandatory): | ||
| 137 | + * one interface, protocol 0 | ||
| 138 | + * | ||
| 139 | + * USB 2.0, multiple TT organization (optional): | ||
| 140 | + * two interfaces, protocols 1 (like single TT) | ||
| 141 | + * and 2 (multiple TT mode) ... config is | ||
| 142 | + * sometimes settable | ||
| 143 | + * NOT IMPLEMENTED | ||
| 144 | + */ | ||
| 145 | + | ||
| 146 | + /* one interface */ | ||
| 147 | + 0x09, /* u8 if_bLength; */ | ||
| 148 | + 0x04, /* u8 if_bDescriptorType; Interface */ | ||
| 149 | + 0x00, /* u8 if_bInterfaceNumber; */ | ||
| 150 | + 0x00, /* u8 if_bAlternateSetting; */ | ||
| 151 | + 0x01, /* u8 if_bNumEndpoints; */ | ||
| 152 | + 0x03, /* u8 if_bInterfaceClass; */ | ||
| 153 | + 0x01, /* u8 if_bInterfaceSubClass; */ | ||
| 154 | + 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ | ||
| 155 | + 0x05, /* u8 if_iInterface; */ | ||
| 103 | 156 | ||
| 104 | /* HID descriptor */ | 157 | /* HID descriptor */ |
| 105 | 0x09, /* u8 bLength; */ | 158 | 0x09, /* u8 bLength; */ |
| @@ -108,7 +161,15 @@ static const uint8_t qemu_mouse_config_descriptor[] = { | @@ -108,7 +161,15 @@ static const uint8_t qemu_mouse_config_descriptor[] = { | ||
| 108 | 0x00, /* u8 country_code */ | 161 | 0x00, /* u8 country_code */ |
| 109 | 0x01, /* u8 num_descriptors */ | 162 | 0x01, /* u8 num_descriptors */ |
| 110 | 0x22, /* u8 type; Report */ | 163 | 0x22, /* u8 type; Report */ |
| 111 | - 50, 0, /* u16 len */ | 164 | + 74, 0, /* u16 len */ |
| 165 | + | ||
| 166 | + /* one endpoint (status change endpoint) */ | ||
| 167 | + 0x07, /* u8 ep_bLength; */ | ||
| 168 | + 0x05, /* u8 ep_bDescriptorType; Endpoint */ | ||
| 169 | + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ | ||
| 170 | + 0x03, /* u8 ep_bmAttributes; Interrupt */ | ||
| 171 | + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ | ||
| 172 | + 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ | ||
| 112 | }; | 173 | }; |
| 113 | 174 | ||
| 114 | static const uint8_t qemu_mouse_hid_report_descriptor[] = { | 175 | static const uint8_t qemu_mouse_hid_report_descriptor[] = { |
| @@ -121,6 +182,46 @@ static const uint8_t qemu_mouse_hid_report_descriptor[] = { | @@ -121,6 +182,46 @@ static const uint8_t qemu_mouse_hid_report_descriptor[] = { | ||
| 121 | 0xC0, 0xC0, | 182 | 0xC0, 0xC0, |
| 122 | }; | 183 | }; |
| 123 | 184 | ||
| 185 | +static const uint8_t qemu_tablet_hid_report_descriptor[] = { | ||
| 186 | + 0x05, 0x01, /* Usage Page Generic Desktop */ | ||
| 187 | + 0x09, 0x01, /* Usage Mouse */ | ||
| 188 | + 0xA1, 0x01, /* Collection Application */ | ||
| 189 | + 0x09, 0x01, /* Usage Pointer */ | ||
| 190 | + 0xA1, 0x00, /* Collection Physical */ | ||
| 191 | + 0x05, 0x09, /* Usage Page Button */ | ||
| 192 | + 0x19, 0x01, /* Usage Minimum Button 1 */ | ||
| 193 | + 0x29, 0x03, /* Usage Maximum Button 3 */ | ||
| 194 | + 0x15, 0x00, /* Logical Minimum 0 */ | ||
| 195 | + 0x25, 0x01, /* Logical Maximum 1 */ | ||
| 196 | + 0x95, 0x03, /* Report Count 3 */ | ||
| 197 | + 0x75, 0x01, /* Report Size 1 */ | ||
| 198 | + 0x81, 0x02, /* Input (Data, Var, Abs) */ | ||
| 199 | + 0x95, 0x01, /* Report Count 1 */ | ||
| 200 | + 0x75, 0x05, /* Report Size 5 */ | ||
| 201 | + 0x81, 0x01, /* Input (Cnst, Var, Abs) */ | ||
| 202 | + 0x05, 0x01, /* Usage Page Generic Desktop */ | ||
| 203 | + 0x09, 0x30, /* Usage X */ | ||
| 204 | + 0x09, 0x31, /* Usage Y */ | ||
| 205 | + 0x15, 0x00, /* Logical Minimum 0 */ | ||
| 206 | + 0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */ | ||
| 207 | + 0x35, 0x00, /* Physical Minimum 0 */ | ||
| 208 | + 0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */ | ||
| 209 | + 0x75, 0x10, /* Report Size 16 */ | ||
| 210 | + 0x95, 0x02, /* Report Count 2 */ | ||
| 211 | + 0x81, 0x02, /* Input (Data, Var, Abs) */ | ||
| 212 | + 0x05, 0x01, /* Usage Page Generic Desktop */ | ||
| 213 | + 0x09, 0x38, /* Usage Wheel */ | ||
| 214 | + 0x15, 0x81, /* Logical Minimum -127 */ | ||
| 215 | + 0x25, 0x7F, /* Logical Maximum 127 */ | ||
| 216 | + 0x35, 0x00, /* Physical Minimum 0 (same as logical) */ | ||
| 217 | + 0x45, 0x00, /* Physical Maximum 0 (same as logical) */ | ||
| 218 | + 0x75, 0x08, /* Report Size 8 */ | ||
| 219 | + 0x95, 0x01, /* Report Count 1 */ | ||
| 220 | + 0x81, 0x02, /* Input (Data, Var, Rel) */ | ||
| 221 | + 0xC0, /* End Collection */ | ||
| 222 | + 0xC0, /* End Collection */ | ||
| 223 | +}; | ||
| 224 | + | ||
| 124 | static void usb_mouse_event(void *opaque, | 225 | static void usb_mouse_event(void *opaque, |
| 125 | int dx1, int dy1, int dz1, int buttons_state) | 226 | int dx1, int dy1, int dz1, int buttons_state) |
| 126 | { | 227 | { |
| @@ -132,6 +233,17 @@ static void usb_mouse_event(void *opaque, | @@ -132,6 +233,17 @@ static void usb_mouse_event(void *opaque, | ||
| 132 | s->buttons_state = buttons_state; | 233 | s->buttons_state = buttons_state; |
| 133 | } | 234 | } |
| 134 | 235 | ||
| 236 | +static void usb_tablet_event(void *opaque, | ||
| 237 | + int x, int y, int dz, int buttons_state) | ||
| 238 | +{ | ||
| 239 | + USBMouseState *s = opaque; | ||
| 240 | + | ||
| 241 | + s->x = x; | ||
| 242 | + s->y = y; | ||
| 243 | + s->dz += dz; | ||
| 244 | + s->buttons_state = buttons_state; | ||
| 245 | +} | ||
| 246 | + | ||
| 135 | static inline int int_clamp(int val, int vmin, int vmax) | 247 | static inline int int_clamp(int val, int vmin, int vmax) |
| 136 | { | 248 | { |
| 137 | if (val < vmin) | 249 | if (val < vmin) |
| @@ -146,6 +258,11 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) | @@ -146,6 +258,11 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) | ||
| 146 | { | 258 | { |
| 147 | int dx, dy, dz, b, l; | 259 | int dx, dy, dz, b, l; |
| 148 | 260 | ||
| 261 | + if (!s->mouse_grabbed) { | ||
| 262 | + qemu_add_mouse_event_handler(usb_mouse_event, s, 0); | ||
| 263 | + s->mouse_grabbed = 1; | ||
| 264 | + } | ||
| 265 | + | ||
| 149 | dx = int_clamp(s->dx, -128, 127); | 266 | dx = int_clamp(s->dx, -128, 127); |
| 150 | dy = int_clamp(s->dy, -128, 127); | 267 | dy = int_clamp(s->dy, -128, 127); |
| 151 | dz = int_clamp(s->dz, -128, 127); | 268 | dz = int_clamp(s->dz, -128, 127); |
| @@ -173,6 +290,39 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) | @@ -173,6 +290,39 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) | ||
| 173 | return l; | 290 | return l; |
| 174 | } | 291 | } |
| 175 | 292 | ||
| 293 | +static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) | ||
| 294 | +{ | ||
| 295 | + int dz, b, l; | ||
| 296 | + | ||
| 297 | + if (!s->mouse_grabbed) { | ||
| 298 | + qemu_add_mouse_event_handler(usb_tablet_event, s, 1); | ||
| 299 | + s->mouse_grabbed = 1; | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + dz = int_clamp(s->dz, -128, 127); | ||
| 303 | + s->dz -= dz; | ||
| 304 | + | ||
| 305 | + /* Appears we have to invert the wheel direction */ | ||
| 306 | + dz = 0 - dz; | ||
| 307 | + b = 0; | ||
| 308 | + if (s->buttons_state & MOUSE_EVENT_LBUTTON) | ||
| 309 | + b |= 0x01; | ||
| 310 | + if (s->buttons_state & MOUSE_EVENT_RBUTTON) | ||
| 311 | + b |= 0x02; | ||
| 312 | + if (s->buttons_state & MOUSE_EVENT_MBUTTON) | ||
| 313 | + b |= 0x04; | ||
| 314 | + | ||
| 315 | + buf[0] = b; | ||
| 316 | + buf[1] = s->x & 0xff; | ||
| 317 | + buf[2] = s->x >> 8; | ||
| 318 | + buf[3] = s->y & 0xff; | ||
| 319 | + buf[4] = s->y >> 8; | ||
| 320 | + buf[5] = dz; | ||
| 321 | + l = 6; | ||
| 322 | + | ||
| 323 | + return l; | ||
| 324 | +} | ||
| 325 | + | ||
| 176 | static void usb_mouse_handle_reset(USBDevice *dev) | 326 | static void usb_mouse_handle_reset(USBDevice *dev) |
| 177 | { | 327 | { |
| 178 | USBMouseState *s = (USBMouseState *)dev; | 328 | USBMouseState *s = (USBMouseState *)dev; |
| @@ -180,6 +330,8 @@ static void usb_mouse_handle_reset(USBDevice *dev) | @@ -180,6 +330,8 @@ static void usb_mouse_handle_reset(USBDevice *dev) | ||
| 180 | s->dx = 0; | 330 | s->dx = 0; |
| 181 | s->dy = 0; | 331 | s->dy = 0; |
| 182 | s->dz = 0; | 332 | s->dz = 0; |
| 333 | + s->x = 0; | ||
| 334 | + s->y = 0; | ||
| 183 | s->buttons_state = 0; | 335 | s->buttons_state = 0; |
| 184 | } | 336 | } |
| 185 | 337 | ||
| @@ -187,7 +339,7 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | @@ -187,7 +339,7 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | ||
| 187 | int index, int length, uint8_t *data) | 339 | int index, int length, uint8_t *data) |
| 188 | { | 340 | { |
| 189 | USBMouseState *s = (USBMouseState *)dev; | 341 | USBMouseState *s = (USBMouseState *)dev; |
| 190 | - int ret; | 342 | + int ret = 0; |
| 191 | 343 | ||
| 192 | switch(request) { | 344 | switch(request) { |
| 193 | case DeviceRequest | USB_REQ_GET_STATUS: | 345 | case DeviceRequest | USB_REQ_GET_STATUS: |
| @@ -224,9 +376,15 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | @@ -224,9 +376,15 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | ||
| 224 | ret = sizeof(qemu_mouse_dev_descriptor); | 376 | ret = sizeof(qemu_mouse_dev_descriptor); |
| 225 | break; | 377 | break; |
| 226 | case USB_DT_CONFIG: | 378 | case USB_DT_CONFIG: |
| 227 | - memcpy(data, qemu_mouse_config_descriptor, | ||
| 228 | - sizeof(qemu_mouse_config_descriptor)); | ||
| 229 | - ret = sizeof(qemu_mouse_config_descriptor); | 379 | + if (s->kind == USB_MOUSE) { |
| 380 | + memcpy(data, qemu_mouse_config_descriptor, | ||
| 381 | + sizeof(qemu_mouse_config_descriptor)); | ||
| 382 | + ret = sizeof(qemu_mouse_config_descriptor); | ||
| 383 | + } else if (s->kind == USB_TABLET) { | ||
| 384 | + memcpy(data, qemu_tablet_config_descriptor, | ||
| 385 | + sizeof(qemu_tablet_config_descriptor)); | ||
| 386 | + ret = sizeof(qemu_tablet_config_descriptor); | ||
| 387 | + } | ||
| 230 | break; | 388 | break; |
| 231 | case USB_DT_STRING: | 389 | case USB_DT_STRING: |
| 232 | switch(value & 0xff) { | 390 | switch(value & 0xff) { |
| @@ -244,7 +402,10 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | @@ -244,7 +402,10 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | ||
| 244 | break; | 402 | break; |
| 245 | case 2: | 403 | case 2: |
| 246 | /* product description */ | 404 | /* product description */ |
| 247 | - ret = set_usb_string(data, "QEMU USB Mouse"); | 405 | + if (s->kind == USB_MOUSE) |
| 406 | + ret = set_usb_string(data, "QEMU USB Mouse"); | ||
| 407 | + else if (s->kind == USB_TABLET) | ||
| 408 | + ret = set_usb_string(data, "QEMU USB Tablet"); | ||
| 248 | break; | 409 | break; |
| 249 | case 3: | 410 | case 3: |
| 250 | /* vendor description */ | 411 | /* vendor description */ |
| @@ -282,16 +443,25 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | @@ -282,16 +443,25 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | ||
| 282 | case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: | 443 | case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: |
| 283 | switch(value >> 8) { | 444 | switch(value >> 8) { |
| 284 | case 0x22: | 445 | case 0x22: |
| 285 | - memcpy(data, qemu_mouse_hid_report_descriptor, | ||
| 286 | - sizeof(qemu_mouse_hid_report_descriptor)); | ||
| 287 | - ret = sizeof(qemu_mouse_hid_report_descriptor); | ||
| 288 | - break; | 446 | + if (s->kind == USB_MOUSE) { |
| 447 | + memcpy(data, qemu_mouse_hid_report_descriptor, | ||
| 448 | + sizeof(qemu_mouse_hid_report_descriptor)); | ||
| 449 | + ret = sizeof(qemu_mouse_hid_report_descriptor); | ||
| 450 | + } else if (s->kind == USB_TABLET) { | ||
| 451 | + memcpy(data, qemu_tablet_hid_report_descriptor, | ||
| 452 | + sizeof(qemu_tablet_hid_report_descriptor)); | ||
| 453 | + ret = sizeof(qemu_tablet_hid_report_descriptor); | ||
| 454 | + } | ||
| 455 | + break; | ||
| 289 | default: | 456 | default: |
| 290 | goto fail; | 457 | goto fail; |
| 291 | } | 458 | } |
| 292 | break; | 459 | break; |
| 293 | case GET_REPORT: | 460 | case GET_REPORT: |
| 294 | - ret = usb_mouse_poll(s, data, length); | 461 | + if (s->kind == USB_MOUSE) |
| 462 | + ret = usb_mouse_poll(s, data, length); | ||
| 463 | + else if (s->kind == USB_TABLET) | ||
| 464 | + ret = usb_tablet_poll(s, data, length); | ||
| 295 | break; | 465 | break; |
| 296 | case SET_IDLE: | 466 | case SET_IDLE: |
| 297 | ret = 0; | 467 | ret = 0; |
| @@ -308,12 +478,15 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, | @@ -308,12 +478,15 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, | ||
| 308 | uint8_t devep, uint8_t *data, int len) | 478 | uint8_t devep, uint8_t *data, int len) |
| 309 | { | 479 | { |
| 310 | USBMouseState *s = (USBMouseState *)dev; | 480 | USBMouseState *s = (USBMouseState *)dev; |
| 311 | - int ret; | 481 | + int ret = 0; |
| 312 | 482 | ||
| 313 | switch(pid) { | 483 | switch(pid) { |
| 314 | case USB_TOKEN_IN: | 484 | case USB_TOKEN_IN: |
| 315 | if (devep == 1) { | 485 | if (devep == 1) { |
| 316 | - ret = usb_mouse_poll(s, data, len); | 486 | + if (s->kind == USB_MOUSE) |
| 487 | + ret = usb_mouse_poll(s, data, len); | ||
| 488 | + else if (s->kind == USB_TABLET) | ||
| 489 | + ret = usb_tablet_poll(s, data, len); | ||
| 317 | } else { | 490 | } else { |
| 318 | goto fail; | 491 | goto fail; |
| 319 | } | 492 | } |
| @@ -327,6 +500,24 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, | @@ -327,6 +500,24 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, | ||
| 327 | return ret; | 500 | return ret; |
| 328 | } | 501 | } |
| 329 | 502 | ||
| 503 | +USBDevice *usb_tablet_init(void) | ||
| 504 | +{ | ||
| 505 | + USBMouseState *s; | ||
| 506 | + | ||
| 507 | + s = qemu_mallocz(sizeof(USBMouseState)); | ||
| 508 | + if (!s) | ||
| 509 | + return NULL; | ||
| 510 | + s->dev.speed = USB_SPEED_FULL; | ||
| 511 | + s->dev.handle_packet = usb_generic_handle_packet; | ||
| 512 | + | ||
| 513 | + s->dev.handle_reset = usb_mouse_handle_reset; | ||
| 514 | + s->dev.handle_control = usb_mouse_handle_control; | ||
| 515 | + s->dev.handle_data = usb_mouse_handle_data; | ||
| 516 | + s->kind = USB_TABLET; | ||
| 517 | + | ||
| 518 | + return (USBDevice *)s; | ||
| 519 | +} | ||
| 520 | + | ||
| 330 | USBDevice *usb_mouse_init(void) | 521 | USBDevice *usb_mouse_init(void) |
| 331 | { | 522 | { |
| 332 | USBMouseState *s; | 523 | USBMouseState *s; |
| @@ -340,8 +531,7 @@ USBDevice *usb_mouse_init(void) | @@ -340,8 +531,7 @@ USBDevice *usb_mouse_init(void) | ||
| 340 | s->dev.handle_reset = usb_mouse_handle_reset; | 531 | s->dev.handle_reset = usb_mouse_handle_reset; |
| 341 | s->dev.handle_control = usb_mouse_handle_control; | 532 | s->dev.handle_control = usb_mouse_handle_control; |
| 342 | s->dev.handle_data = usb_mouse_handle_data; | 533 | s->dev.handle_data = usb_mouse_handle_data; |
| 534 | + s->kind = USB_MOUSE; | ||
| 343 | 535 | ||
| 344 | - qemu_add_mouse_event_handler(usb_mouse_event, s); | ||
| 345 | - | ||
| 346 | return (USBDevice *)s; | 536 | return (USBDevice *)s; |
| 347 | } | 537 | } |
hw/usb.h
sdl.c
| @@ -39,6 +39,10 @@ static int gui_keysym; | @@ -39,6 +39,10 @@ static int gui_keysym; | ||
| 39 | static int gui_fullscreen_initial_grab; | 39 | static int gui_fullscreen_initial_grab; |
| 40 | static int gui_grab_code = KMOD_LALT | KMOD_LCTRL; | 40 | static int gui_grab_code = KMOD_LALT | KMOD_LCTRL; |
| 41 | static uint8_t modifiers_state[256]; | 41 | static uint8_t modifiers_state[256]; |
| 42 | +static int width, height; | ||
| 43 | +static SDL_Cursor *sdl_cursor_normal; | ||
| 44 | +static SDL_Cursor *sdl_cursor_hidden; | ||
| 45 | +static int absolute_enabled = 0; | ||
| 42 | 46 | ||
| 43 | static void sdl_update(DisplayState *ds, int x, int y, int w, int h) | 47 | static void sdl_update(DisplayState *ds, int x, int y, int w, int h) |
| 44 | { | 48 | { |
| @@ -56,6 +60,9 @@ static void sdl_resize(DisplayState *ds, int w, int h) | @@ -56,6 +60,9 @@ static void sdl_resize(DisplayState *ds, int w, int h) | ||
| 56 | if (gui_fullscreen) | 60 | if (gui_fullscreen) |
| 57 | flags |= SDL_FULLSCREEN; | 61 | flags |= SDL_FULLSCREEN; |
| 58 | 62 | ||
| 63 | + width = w; | ||
| 64 | + height = h; | ||
| 65 | + | ||
| 59 | again: | 66 | again: |
| 60 | screen = SDL_SetVideoMode(w, h, 0, flags); | 67 | screen = SDL_SetVideoMode(w, h, 0, flags); |
| 61 | if (!screen) { | 68 | if (!screen) { |
| @@ -271,9 +278,21 @@ static void sdl_update_caption(void) | @@ -271,9 +278,21 @@ static void sdl_update_caption(void) | ||
| 271 | SDL_WM_SetCaption(buf, "QEMU"); | 278 | SDL_WM_SetCaption(buf, "QEMU"); |
| 272 | } | 279 | } |
| 273 | 280 | ||
| 281 | +static void sdl_hide_cursor(void) | ||
| 282 | +{ | ||
| 283 | + SDL_SetCursor(sdl_cursor_hidden); | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | +static void sdl_show_cursor(void) | ||
| 287 | +{ | ||
| 288 | + if (!kbd_mouse_is_absolute()) { | ||
| 289 | + SDL_SetCursor(sdl_cursor_normal); | ||
| 290 | + } | ||
| 291 | +} | ||
| 292 | + | ||
| 274 | static void sdl_grab_start(void) | 293 | static void sdl_grab_start(void) |
| 275 | { | 294 | { |
| 276 | - SDL_ShowCursor(0); | 295 | + sdl_hide_cursor(); |
| 277 | SDL_WM_GrabInput(SDL_GRAB_ON); | 296 | SDL_WM_GrabInput(SDL_GRAB_ON); |
| 278 | /* dummy read to avoid moving the mouse */ | 297 | /* dummy read to avoid moving the mouse */ |
| 279 | SDL_GetRelativeMouseState(NULL, NULL); | 298 | SDL_GetRelativeMouseState(NULL, NULL); |
| @@ -284,7 +303,7 @@ static void sdl_grab_start(void) | @@ -284,7 +303,7 @@ static void sdl_grab_start(void) | ||
| 284 | static void sdl_grab_end(void) | 303 | static void sdl_grab_end(void) |
| 285 | { | 304 | { |
| 286 | SDL_WM_GrabInput(SDL_GRAB_OFF); | 305 | SDL_WM_GrabInput(SDL_GRAB_OFF); |
| 287 | - SDL_ShowCursor(1); | 306 | + sdl_show_cursor(); |
| 288 | gui_grab = 0; | 307 | gui_grab = 0; |
| 289 | sdl_update_caption(); | 308 | sdl_update_caption(); |
| 290 | } | 309 | } |
| @@ -300,6 +319,21 @@ static void sdl_send_mouse_event(int dz) | @@ -300,6 +319,21 @@ static void sdl_send_mouse_event(int dz) | ||
| 300 | buttons |= MOUSE_EVENT_RBUTTON; | 319 | buttons |= MOUSE_EVENT_RBUTTON; |
| 301 | if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) | 320 | if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) |
| 302 | buttons |= MOUSE_EVENT_MBUTTON; | 321 | buttons |= MOUSE_EVENT_MBUTTON; |
| 322 | + | ||
| 323 | + if (kbd_mouse_is_absolute()) { | ||
| 324 | + if (!absolute_enabled) { | ||
| 325 | + sdl_hide_cursor(); | ||
| 326 | + if (gui_grab) { | ||
| 327 | + sdl_grab_end(); | ||
| 328 | + } | ||
| 329 | + absolute_enabled = 1; | ||
| 330 | + } | ||
| 331 | + | ||
| 332 | + SDL_GetMouseState(&dx, &dy); | ||
| 333 | + dx = dx * 0x7FFF / width; | ||
| 334 | + dy = dy * 0x7FFF / height; | ||
| 335 | + } | ||
| 336 | + | ||
| 303 | kbd_mouse_event(dx, dy, dz, buttons); | 337 | kbd_mouse_event(dx, dy, dz, buttons); |
| 304 | } | 338 | } |
| 305 | 339 | ||
| @@ -423,7 +457,7 @@ static void sdl_refresh(DisplayState *ds) | @@ -423,7 +457,7 @@ static void sdl_refresh(DisplayState *ds) | ||
| 423 | qemu_system_shutdown_request(); | 457 | qemu_system_shutdown_request(); |
| 424 | break; | 458 | break; |
| 425 | case SDL_MOUSEMOTION: | 459 | case SDL_MOUSEMOTION: |
| 426 | - if (gui_grab) { | 460 | + if (gui_grab || kbd_mouse_is_absolute()) { |
| 427 | sdl_send_mouse_event(0); | 461 | sdl_send_mouse_event(0); |
| 428 | } | 462 | } |
| 429 | break; | 463 | break; |
| @@ -431,7 +465,7 @@ static void sdl_refresh(DisplayState *ds) | @@ -431,7 +465,7 @@ static void sdl_refresh(DisplayState *ds) | ||
| 431 | case SDL_MOUSEBUTTONUP: | 465 | case SDL_MOUSEBUTTONUP: |
| 432 | { | 466 | { |
| 433 | SDL_MouseButtonEvent *bev = &ev->button; | 467 | SDL_MouseButtonEvent *bev = &ev->button; |
| 434 | - if (!gui_grab) { | 468 | + if (!gui_grab && !kbd_mouse_is_absolute()) { |
| 435 | if (ev->type == SDL_MOUSEBUTTONDOWN && | 469 | if (ev->type == SDL_MOUSEBUTTONDOWN && |
| 436 | (bev->state & SDL_BUTTON_LMASK)) { | 470 | (bev->state & SDL_BUTTON_LMASK)) { |
| 437 | /* start grabbing all events */ | 471 | /* start grabbing all events */ |
| @@ -441,9 +475,9 @@ static void sdl_refresh(DisplayState *ds) | @@ -441,9 +475,9 @@ static void sdl_refresh(DisplayState *ds) | ||
| 441 | int dz; | 475 | int dz; |
| 442 | dz = 0; | 476 | dz = 0; |
| 443 | #ifdef SDL_BUTTON_WHEELUP | 477 | #ifdef SDL_BUTTON_WHEELUP |
| 444 | - if (bev->button == SDL_BUTTON_WHEELUP) { | 478 | + if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) { |
| 445 | dz = -1; | 479 | dz = -1; |
| 446 | - } else if (bev->button == SDL_BUTTON_WHEELDOWN) { | 480 | + } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) { |
| 447 | dz = 1; | 481 | dz = 1; |
| 448 | } | 482 | } |
| 449 | #endif | 483 | #endif |
| @@ -471,6 +505,7 @@ static void sdl_cleanup(void) | @@ -471,6 +505,7 @@ static void sdl_cleanup(void) | ||
| 471 | void sdl_display_init(DisplayState *ds, int full_screen) | 505 | void sdl_display_init(DisplayState *ds, int full_screen) |
| 472 | { | 506 | { |
| 473 | int flags; | 507 | int flags; |
| 508 | + uint8_t data = 0; | ||
| 474 | 509 | ||
| 475 | #if defined(__APPLE__) | 510 | #if defined(__APPLE__) |
| 476 | /* always use generic keymaps */ | 511 | /* always use generic keymaps */ |
| @@ -504,6 +539,9 @@ void sdl_display_init(DisplayState *ds, int full_screen) | @@ -504,6 +539,9 @@ void sdl_display_init(DisplayState *ds, int full_screen) | ||
| 504 | SDL_EnableUNICODE(1); | 539 | SDL_EnableUNICODE(1); |
| 505 | gui_grab = 0; | 540 | gui_grab = 0; |
| 506 | 541 | ||
| 542 | + sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); | ||
| 543 | + sdl_cursor_normal = SDL_GetCursor(); | ||
| 544 | + | ||
| 507 | atexit(sdl_cleanup); | 545 | atexit(sdl_cleanup); |
| 508 | if (full_screen) { | 546 | if (full_screen) { |
| 509 | gui_fullscreen = 1; | 547 | gui_fullscreen = 1; |
vl.c
| @@ -474,6 +474,7 @@ static QEMUPutKBDEvent *qemu_put_kbd_event; | @@ -474,6 +474,7 @@ static QEMUPutKBDEvent *qemu_put_kbd_event; | ||
| 474 | static void *qemu_put_kbd_event_opaque; | 474 | static void *qemu_put_kbd_event_opaque; |
| 475 | static QEMUPutMouseEvent *qemu_put_mouse_event; | 475 | static QEMUPutMouseEvent *qemu_put_mouse_event; |
| 476 | static void *qemu_put_mouse_event_opaque; | 476 | static void *qemu_put_mouse_event_opaque; |
| 477 | +static int qemu_put_mouse_event_absolute; | ||
| 477 | 478 | ||
| 478 | void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) | 479 | void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) |
| 479 | { | 480 | { |
| @@ -481,10 +482,11 @@ void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) | @@ -481,10 +482,11 @@ void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) | ||
| 481 | qemu_put_kbd_event = func; | 482 | qemu_put_kbd_event = func; |
| 482 | } | 483 | } |
| 483 | 484 | ||
| 484 | -void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque) | 485 | +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute) |
| 485 | { | 486 | { |
| 486 | qemu_put_mouse_event_opaque = opaque; | 487 | qemu_put_mouse_event_opaque = opaque; |
| 487 | qemu_put_mouse_event = func; | 488 | qemu_put_mouse_event = func; |
| 489 | + qemu_put_mouse_event_absolute = absolute; | ||
| 488 | } | 490 | } |
| 489 | 491 | ||
| 490 | void kbd_put_keycode(int keycode) | 492 | void kbd_put_keycode(int keycode) |
| @@ -502,6 +504,11 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | @@ -502,6 +504,11 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | ||
| 502 | } | 504 | } |
| 503 | } | 505 | } |
| 504 | 506 | ||
| 507 | +int kbd_mouse_is_absolute(void) | ||
| 508 | +{ | ||
| 509 | + return qemu_put_mouse_event_absolute; | ||
| 510 | +} | ||
| 511 | + | ||
| 505 | /***********************************************************/ | 512 | /***********************************************************/ |
| 506 | /* timers */ | 513 | /* timers */ |
| 507 | 514 | ||
| @@ -3242,6 +3249,10 @@ static int usb_device_add(const char *devname) | @@ -3242,6 +3249,10 @@ static int usb_device_add(const char *devname) | ||
| 3242 | dev = usb_mouse_init(); | 3249 | dev = usb_mouse_init(); |
| 3243 | if (!dev) | 3250 | if (!dev) |
| 3244 | return -1; | 3251 | return -1; |
| 3252 | + } else if (!strcmp(devname, "tablet")) { | ||
| 3253 | + dev = usb_tablet_init(); | ||
| 3254 | + if (!dev) | ||
| 3255 | + return -1; | ||
| 3245 | } else { | 3256 | } else { |
| 3246 | return -1; | 3257 | return -1; |
| 3247 | } | 3258 | } |
vl.h
| @@ -158,10 +158,11 @@ typedef void QEMUPutKBDEvent(void *opaque, int keycode); | @@ -158,10 +158,11 @@ typedef void QEMUPutKBDEvent(void *opaque, int keycode); | ||
| 158 | typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); | 158 | typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); |
| 159 | 159 | ||
| 160 | void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); | 160 | void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); |
| 161 | -void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque); | 161 | +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute); |
| 162 | 162 | ||
| 163 | void kbd_put_keycode(int keycode); | 163 | void kbd_put_keycode(int keycode); |
| 164 | void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); | 164 | void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); |
| 165 | +int kbd_mouse_is_absolute(void); | ||
| 165 | 166 | ||
| 166 | /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx | 167 | /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx |
| 167 | constants) */ | 168 | constants) */ |