static void usb_pointer_event(void *hs_v, int x1, int y1, int z1, int buttons_state) { /* We combine events where feasible to keep the queue small. * We shouldn't combine anything with the first event with * a particular button state, as that would change the * location of the button state change. */ USBHIDState *hs= hs_v; USBPointerState *s = &hs->ptr; unsigned use_slot= (s->tail-1) & QUEUEINDEXMASK; unsigned previous_slot= (use_slot-1) & QUEUEINDEXMASK; if (s->tail == s->head) { use_slot= s->tail; QUEUE_INCR(s->tail); usb_pointer_event_clear(&s->queue[use_slot], buttons_state); } else if (use_slot == s->head || s->queue[use_slot].buttons_state != buttons_state || s->queue[previous_slot].buttons_state != buttons_state) { /* can't or shouldn't combine this event with previous one */ use_slot= s->tail; QUEUE_INCR(s->tail); if (use_slot == s->head) { /* queue full, oh well, discard something */ s->head++; s->head &= QUEUEINDEXMASK; /* but we preserve the relative motions */ usb_pointer_event_combine(&s->queue[s->head], s->xyrel, s->queue[use_slot].xdx, s->queue[use_slot].ydy, s->queue[use_slot].dz); } usb_pointer_event_clear(&s->queue[use_slot], buttons_state); } usb_pointer_event_combine(&s->queue[use_slot],s->xyrel, x1,y1,z1); }
static void hid_keyboard_process_keycode(HIDState *hs) { uint8_t hid_code, key; int i, keycode, slot; if (hs->n == 0) { return; } slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; keycode = hs->kbd.keycodes[slot]; key = keycode & 0x7f; hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))]; hs->kbd.modifiers &= ~(1 << 8); switch (hid_code) { case 0x00: return; case 0xe0: if (hs->kbd.modifiers & (1 << 9)) { hs->kbd.modifiers ^= 3 << 8; return; } case 0xe1 ... 0xe7: if (keycode & (1 << 7)) { hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f)); return; } case 0xe8 ... 0xef: hs->kbd.modifiers |= 1 << (hid_code & 0x0f); return; } if (keycode & (1 << 7)) { for (i = hs->kbd.keys - 1; i >= 0; i--) { if (hs->kbd.key[i] == hid_code) { hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys]; hs->kbd.key[hs->kbd.keys] = 0x00; break; } } if (i < 0) { return; } } else { for (i = hs->kbd.keys - 1; i >= 0; i--) { if (hs->kbd.key[i] == hid_code) { break; } } if (i < 0) { if (hs->kbd.keys < sizeof(hs->kbd.key)) { hs->kbd.key[hs->kbd.keys++] = hid_code; } } else { return; } } }
static void hid_pointer_event(void *opaque, int x1, int y1, int z1, int buttons_state) { HIDState *hs = opaque; unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK; unsigned previous_slot = (use_slot - 1) & QUEUE_MASK; /* We combine events where feasible to keep the queue small. We shouldn't * combine anything with the first event of a particular button state, as * that would change the location of the button state change. When the * queue is empty, a second event is needed because we don't know if * the first event changed the button state. */ if (hs->n == QUEUE_LENGTH) { /* Queue full. Discard old button state, combine motion normally. */ hs->ptr.queue[use_slot].buttons_state = buttons_state; } else if (hs->n < 2 || hs->ptr.queue[use_slot].buttons_state != buttons_state || hs->ptr.queue[previous_slot].buttons_state != hs->ptr.queue[use_slot].buttons_state) { /* Cannot or should not combine, so add an empty item to the queue. */ QUEUE_INCR(use_slot); hs->n++; hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state); } hid_pointer_event_combine(&hs->ptr.queue[use_slot], hs->kind == HID_MOUSE, x1, y1, z1); hs->event(hs); }
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) { int dx, dy, dz, b, l; int index; HIDPointerEvent *e; hs->idle_pending = false; hid_pointer_activate(hs); /* When the buffer is empty, return the last event. Relative movements will all be zero. */ index = (hs->n ? hs->head : hs->head - 1); e = &hs->ptr.queue[index & QUEUE_MASK]; if (hs->kind == HID_MOUSE) { dx = int_clamp(e->xdx, -127, 127); dy = int_clamp(e->ydy, -127, 127); e->xdx -= dx; e->ydy -= dy; } else { dx = e->xdx; dy = e->ydy; } dz = int_clamp(e->dz, -127, 127); e->dz -= dz; b = 0; if (e->buttons_state & MOUSE_EVENT_LBUTTON) { b |= 0x01; } if (e->buttons_state & MOUSE_EVENT_RBUTTON) { b |= 0x02; } if (e->buttons_state & MOUSE_EVENT_MBUTTON) { b |= 0x04; } if (hs->n && !e->dz && (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { /* that deals with this event */ QUEUE_INCR(hs->head); hs->n--; } /* Appears we have to invert the wheel direction */ dz = 0 - dz; l = 0; switch (hs->kind) { case HID_MOUSE: if (len > l) { buf[l++] = b; } if (len > l) { buf[l++] = dx; } if (len > l) { buf[l++] = dy; } if (len > l) { buf[l++] = dz; } break; case HID_TABLET: if (len > l) { buf[l++] = b; } if (len > l) { buf[l++] = dx & 0xff; } if (len > l) { buf[l++] = dx >> 8; } if (len > l) { buf[l++] = dy & 0xff; } if (len > l) { buf[l++] = dy >> 8; }
static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len) { int dx, dy, dz, b, l; USBPointerState *s = &hs->ptr; USBPointerEvent *e; if (usb_suppress_report(hs, s->head == s->tail)) return USB_RET_NAK; if (!s->mouse_grabbed) { s->eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, hs, !s->xyrel, "QEMU USB Pointer"); s->mouse_grabbed = 1; } if (s->head == s->tail) /* use the last report */ s->head = (s->head - 1) & QUEUEINDEXMASK; e = &s->queue[s->head]; dz = int_clamp(e->dz, -127, 127); if (s->xyrel) { dx = int_clamp(e->xdx, -127, 127); dy = int_clamp(e->ydy, -127, 127); e->xdx -= dx; e->ydy -= dy; } else { dx = e->xdx; dy = e->ydy; } /* Appears we have to invert the wheel direction */ dz = 0 - dz; if (!(e->dz || (s->xyrel && (e->xdx || e->ydy)))) { /* that deals with this event */ QUEUE_INCR(s->head); } b = 0; if (e->buttons_state & MOUSE_EVENT_LBUTTON) b |= 0x01; if (e->buttons_state & MOUSE_EVENT_RBUTTON) b |= 0x02; if (e->buttons_state & MOUSE_EVENT_MBUTTON) b |= 0x04; switch (hs->kind) { case USB_MOUSE: l = 0; if (len > l) buf[l ++] = b; if (len > l) buf[l ++] = dx; if (len > l) buf[l ++] = dy; if (len > l) buf[l ++] = dz; break; case USB_TABLET: /* Appears we have to invert the wheel direction */ dz = 0 - dz; buf[0] = b; buf[1] = dx & 0xff; buf[2] = dx >> 8; buf[3] = dy & 0xff; buf[4] = dy >> 8; buf[5] = dz; l = 6; break; default: abort(); } return l; }