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) */ | ... | ... |