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 | 560 | s->common.update_arg = update_arg; |
| 561 | 561 | ps2_reset(&s->common); |
| 562 | 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 | 564 | qemu_register_reset(ps2_reset, &s->common); |
| 565 | 565 | return s; |
| 566 | 566 | } | ... | ... |
hw/usb-hid.c
| ... | ... | @@ -30,9 +30,15 @@ |
| 30 | 30 | #define SET_IDLE 0x210a |
| 31 | 31 | #define SET_PROTOCOL 0x210b |
| 32 | 32 | |
| 33 | +#define USB_MOUSE 1 | |
| 34 | +#define USB_TABLET 2 | |
| 35 | + | |
| 33 | 36 | typedef struct USBMouseState { |
| 34 | 37 | USBDevice dev; |
| 35 | 38 | int dx, dy, dz, buttons_state; |
| 39 | + int x, y; | |
| 40 | + int kind; | |
| 41 | + int mouse_grabbed; | |
| 36 | 42 | } USBMouseState; |
| 37 | 43 | |
| 38 | 44 | /* mostly the same values as the Bochs USB Mouse device */ |
| ... | ... | @@ -93,6 +99,15 @@ static const uint8_t qemu_mouse_config_descriptor[] = { |
| 93 | 99 | 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ |
| 94 | 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 | 111 | /* one endpoint (status change endpoint) */ |
| 97 | 112 | 0x07, /* u8 ep_bLength; */ |
| 98 | 113 | 0x05, /* u8 ep_bDescriptorType; Endpoint */ |
| ... | ... | @@ -100,6 +115,44 @@ static const uint8_t qemu_mouse_config_descriptor[] = { |
| 100 | 115 | 0x03, /* u8 ep_bmAttributes; Interrupt */ |
| 101 | 116 | 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ |
| 102 | 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 | 157 | /* HID descriptor */ |
| 105 | 158 | 0x09, /* u8 bLength; */ |
| ... | ... | @@ -108,7 +161,15 @@ static const uint8_t qemu_mouse_config_descriptor[] = { |
| 108 | 161 | 0x00, /* u8 country_code */ |
| 109 | 162 | 0x01, /* u8 num_descriptors */ |
| 110 | 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 | 175 | static const uint8_t qemu_mouse_hid_report_descriptor[] = { |
| ... | ... | @@ -121,6 +182,46 @@ static const uint8_t qemu_mouse_hid_report_descriptor[] = { |
| 121 | 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 | 225 | static void usb_mouse_event(void *opaque, |
| 125 | 226 | int dx1, int dy1, int dz1, int buttons_state) |
| 126 | 227 | { |
| ... | ... | @@ -132,6 +233,17 @@ static void usb_mouse_event(void *opaque, |
| 132 | 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 | 247 | static inline int int_clamp(int val, int vmin, int vmax) |
| 136 | 248 | { |
| 137 | 249 | if (val < vmin) |
| ... | ... | @@ -146,6 +258,11 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) |
| 146 | 258 | { |
| 147 | 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 | 266 | dx = int_clamp(s->dx, -128, 127); |
| 150 | 267 | dy = int_clamp(s->dy, -128, 127); |
| 151 | 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 | 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 | 326 | static void usb_mouse_handle_reset(USBDevice *dev) |
| 177 | 327 | { |
| 178 | 328 | USBMouseState *s = (USBMouseState *)dev; |
| ... | ... | @@ -180,6 +330,8 @@ static void usb_mouse_handle_reset(USBDevice *dev) |
| 180 | 330 | s->dx = 0; |
| 181 | 331 | s->dy = 0; |
| 182 | 332 | s->dz = 0; |
| 333 | + s->x = 0; | |
| 334 | + s->y = 0; | |
| 183 | 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 | 339 | int index, int length, uint8_t *data) |
| 188 | 340 | { |
| 189 | 341 | USBMouseState *s = (USBMouseState *)dev; |
| 190 | - int ret; | |
| 342 | + int ret = 0; | |
| 191 | 343 | |
| 192 | 344 | switch(request) { |
| 193 | 345 | case DeviceRequest | USB_REQ_GET_STATUS: |
| ... | ... | @@ -224,9 +376,15 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, |
| 224 | 376 | ret = sizeof(qemu_mouse_dev_descriptor); |
| 225 | 377 | break; |
| 226 | 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 | 388 | break; |
| 231 | 389 | case USB_DT_STRING: |
| 232 | 390 | switch(value & 0xff) { |
| ... | ... | @@ -244,7 +402,10 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, |
| 244 | 402 | break; |
| 245 | 403 | case 2: |
| 246 | 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 | 409 | break; |
| 249 | 410 | case 3: |
| 250 | 411 | /* vendor description */ |
| ... | ... | @@ -282,16 +443,25 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, |
| 282 | 443 | case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: |
| 283 | 444 | switch(value >> 8) { |
| 284 | 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 | 456 | default: |
| 290 | 457 | goto fail; |
| 291 | 458 | } |
| 292 | 459 | break; |
| 293 | 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 | 465 | break; |
| 296 | 466 | case SET_IDLE: |
| 297 | 467 | ret = 0; |
| ... | ... | @@ -308,12 +478,15 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, |
| 308 | 478 | uint8_t devep, uint8_t *data, int len) |
| 309 | 479 | { |
| 310 | 480 | USBMouseState *s = (USBMouseState *)dev; |
| 311 | - int ret; | |
| 481 | + int ret = 0; | |
| 312 | 482 | |
| 313 | 483 | switch(pid) { |
| 314 | 484 | case USB_TOKEN_IN: |
| 315 | 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 | 490 | } else { |
| 318 | 491 | goto fail; |
| 319 | 492 | } |
| ... | ... | @@ -327,6 +500,24 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, |
| 327 | 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 | 521 | USBDevice *usb_mouse_init(void) |
| 331 | 522 | { |
| 332 | 523 | USBMouseState *s; |
| ... | ... | @@ -340,8 +531,7 @@ USBDevice *usb_mouse_init(void) |
| 340 | 531 | s->dev.handle_reset = usb_mouse_handle_reset; |
| 341 | 532 | s->dev.handle_control = usb_mouse_handle_control; |
| 342 | 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 | 536 | return (USBDevice *)s; |
| 347 | 537 | } | ... | ... |
hw/usb.h
sdl.c
| ... | ... | @@ -39,6 +39,10 @@ static int gui_keysym; |
| 39 | 39 | static int gui_fullscreen_initial_grab; |
| 40 | 40 | static int gui_grab_code = KMOD_LALT | KMOD_LCTRL; |
| 41 | 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 | 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 | 60 | if (gui_fullscreen) |
| 57 | 61 | flags |= SDL_FULLSCREEN; |
| 58 | 62 | |
| 63 | + width = w; | |
| 64 | + height = h; | |
| 65 | + | |
| 59 | 66 | again: |
| 60 | 67 | screen = SDL_SetVideoMode(w, h, 0, flags); |
| 61 | 68 | if (!screen) { |
| ... | ... | @@ -271,9 +278,21 @@ static void sdl_update_caption(void) |
| 271 | 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 | 293 | static void sdl_grab_start(void) |
| 275 | 294 | { |
| 276 | - SDL_ShowCursor(0); | |
| 295 | + sdl_hide_cursor(); | |
| 277 | 296 | SDL_WM_GrabInput(SDL_GRAB_ON); |
| 278 | 297 | /* dummy read to avoid moving the mouse */ |
| 279 | 298 | SDL_GetRelativeMouseState(NULL, NULL); |
| ... | ... | @@ -284,7 +303,7 @@ static void sdl_grab_start(void) |
| 284 | 303 | static void sdl_grab_end(void) |
| 285 | 304 | { |
| 286 | 305 | SDL_WM_GrabInput(SDL_GRAB_OFF); |
| 287 | - SDL_ShowCursor(1); | |
| 306 | + sdl_show_cursor(); | |
| 288 | 307 | gui_grab = 0; |
| 289 | 308 | sdl_update_caption(); |
| 290 | 309 | } |
| ... | ... | @@ -300,6 +319,21 @@ static void sdl_send_mouse_event(int dz) |
| 300 | 319 | buttons |= MOUSE_EVENT_RBUTTON; |
| 301 | 320 | if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) |
| 302 | 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 | 337 | kbd_mouse_event(dx, dy, dz, buttons); |
| 304 | 338 | } |
| 305 | 339 | |
| ... | ... | @@ -423,7 +457,7 @@ static void sdl_refresh(DisplayState *ds) |
| 423 | 457 | qemu_system_shutdown_request(); |
| 424 | 458 | break; |
| 425 | 459 | case SDL_MOUSEMOTION: |
| 426 | - if (gui_grab) { | |
| 460 | + if (gui_grab || kbd_mouse_is_absolute()) { | |
| 427 | 461 | sdl_send_mouse_event(0); |
| 428 | 462 | } |
| 429 | 463 | break; |
| ... | ... | @@ -431,7 +465,7 @@ static void sdl_refresh(DisplayState *ds) |
| 431 | 465 | case SDL_MOUSEBUTTONUP: |
| 432 | 466 | { |
| 433 | 467 | SDL_MouseButtonEvent *bev = &ev->button; |
| 434 | - if (!gui_grab) { | |
| 468 | + if (!gui_grab && !kbd_mouse_is_absolute()) { | |
| 435 | 469 | if (ev->type == SDL_MOUSEBUTTONDOWN && |
| 436 | 470 | (bev->state & SDL_BUTTON_LMASK)) { |
| 437 | 471 | /* start grabbing all events */ |
| ... | ... | @@ -441,9 +475,9 @@ static void sdl_refresh(DisplayState *ds) |
| 441 | 475 | int dz; |
| 442 | 476 | dz = 0; |
| 443 | 477 | #ifdef SDL_BUTTON_WHEELUP |
| 444 | - if (bev->button == SDL_BUTTON_WHEELUP) { | |
| 478 | + if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) { | |
| 445 | 479 | dz = -1; |
| 446 | - } else if (bev->button == SDL_BUTTON_WHEELDOWN) { | |
| 480 | + } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) { | |
| 447 | 481 | dz = 1; |
| 448 | 482 | } |
| 449 | 483 | #endif |
| ... | ... | @@ -471,6 +505,7 @@ static void sdl_cleanup(void) |
| 471 | 505 | void sdl_display_init(DisplayState *ds, int full_screen) |
| 472 | 506 | { |
| 473 | 507 | int flags; |
| 508 | + uint8_t data = 0; | |
| 474 | 509 | |
| 475 | 510 | #if defined(__APPLE__) |
| 476 | 511 | /* always use generic keymaps */ |
| ... | ... | @@ -504,6 +539,9 @@ void sdl_display_init(DisplayState *ds, int full_screen) |
| 504 | 539 | SDL_EnableUNICODE(1); |
| 505 | 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 | 545 | atexit(sdl_cleanup); |
| 508 | 546 | if (full_screen) { |
| 509 | 547 | gui_fullscreen = 1; | ... | ... |
vl.c
| ... | ... | @@ -474,6 +474,7 @@ static QEMUPutKBDEvent *qemu_put_kbd_event; |
| 474 | 474 | static void *qemu_put_kbd_event_opaque; |
| 475 | 475 | static QEMUPutMouseEvent *qemu_put_mouse_event; |
| 476 | 476 | static void *qemu_put_mouse_event_opaque; |
| 477 | +static int qemu_put_mouse_event_absolute; | |
| 477 | 478 | |
| 478 | 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 | 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 | 487 | qemu_put_mouse_event_opaque = opaque; |
| 487 | 488 | qemu_put_mouse_event = func; |
| 489 | + qemu_put_mouse_event_absolute = absolute; | |
| 488 | 490 | } |
| 489 | 491 | |
| 490 | 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 | 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 | 513 | /* timers */ |
| 507 | 514 | |
| ... | ... | @@ -3242,6 +3249,10 @@ static int usb_device_add(const char *devname) |
| 3242 | 3249 | dev = usb_mouse_init(); |
| 3243 | 3250 | if (!dev) |
| 3244 | 3251 | return -1; |
| 3252 | + } else if (!strcmp(devname, "tablet")) { | |
| 3253 | + dev = usb_tablet_init(); | |
| 3254 | + if (!dev) | |
| 3255 | + return -1; | |
| 3245 | 3256 | } else { |
| 3246 | 3257 | return -1; |
| 3247 | 3258 | } | ... | ... |
vl.h
| ... | ... | @@ -158,10 +158,11 @@ typedef void QEMUPutKBDEvent(void *opaque, int keycode); |
| 158 | 158 | typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); |
| 159 | 159 | |
| 160 | 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 | 163 | void kbd_put_keycode(int keycode); |
| 164 | 164 | void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); |
| 165 | +int kbd_mouse_is_absolute(void); | |
| 165 | 166 | |
| 166 | 167 | /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx |
| 167 | 168 | constants) */ | ... | ... |