All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/8] usb-mouse: high-resolution vertical and horizontal wheel support
@ 2026-10-27 19:42 soumyajyotisarkar23
  2026-10-27 19:42 ` [PATCH v2 1/8] ui/input: add high-resolution scroll input event soumyajyotisarkar23
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: soumyajyotisarkar23 @ 2026-10-27 19:42 UTC (permalink / raw)
  To: sarkarsoumyajyoti23, qemu-devel
  Cc: Alex Bennée, Helge Deller, Eric Blake,
	Marc-André Lureau, Markus Armbruster, Soumyajyotii Ssarkar

From: Soumyajyotii Ssarkar <soumyajyotisarkar23@gmail.com>

This series adds high-resolution vertical and horizontal wheel support
to QEMU's USB HID mouse.

As of now the USB mouse only reports whole wheel detents and has no
horizontal wheel. Modern touchpads, trackpoints and free-spinning wheels on
the host produce much finer and often simultaneous horizontal and
vertical, scroll movement, but the guest never sees it: the GTK and
SDL ui turn every smooth scroll event into a single wheel button
click and the HID report has no room for anything finer.

Since Windows Vista, Windows supports Microsoft's enhanced wheel
protocol: a Resolution Multiplier feature report per wheel axis and
horizontal scrolling through the Consumer AC Pan usage. Linux
supports the same multiplier through hid-input. This series
implements it end to end:

 - Patch 1 adds a 'scroll' input event carrying the distance in 1/120
   of a detent (WHEEL_DELTA units). Devices that do not handle it
   keep getting wheel button clicks from the input core, one per
   detent.
 - Patches 2 and 3 make the GTK and SDL ui forward smooth scroll
   deltas on both axes as scroll events instead of rounding them to
   clicks. SDL needs 2.0.18 or newer for preciseX/preciseY.
 - Patch 4 derives the report descriptor length with sizeof() (no
   functional change).
 - Patch 5 makes the HID mouse accept scroll events and track the
   wheel in 1/120 detent units. Guest visible behaviour is unchanged.
 - Patch 6 switches the mouse to a report-ID based descriptor with an
   AC Pan field. Boot protocol keeps the 4-byte report.
 - Patch 7 adds the Resolution Multiplier feature report (ID 2,
   physical maximum 120). Once the guest enables it, each wheel count
   is 1/120 of a detent.
 - Patch 8 clears the wheel state and mouse_grabbed on reset.

Sub-count remainders are carried in a residual per axis, so slow
scrolling adds up instead of being dropped. The new state lives in an
optional "HIDPointerDevice/wheel" vmstate subsection that is only sent
while wheel state is in use.

Testing was done with a Windows 10 guest and -device usb-mouse, with
both -display gtk and -display sdl, using the wheel event viewer at
https://domeventviewer.com/wheel-event-viewer.html:

 - Without the series, deltaY is always +/-100 px (one 120-unit
   detent). With the multiplier of 4 from v1 it was +/-25 px.
 - With the series, deltaX and deltaY arrive in steps of 0.833 px
   (one WHEEL_DELTA unit; Edge maps 120 units to 100 px), horizontal
   scrolling works and both axes can change in the same event.
 - Migration from a QEMU without the series to one with it completes.
   Migration back to an older QEMU only works while the guest has not
   enabled the Resolution Multiplier and no wheel movement is pending;
   otherwise the older QEMU rejects the unknown "HIDPointerDevice/wheel"
   subsection (see the open questions below).

Why the guest cannot match the host 1:1
---------------------------------------
The scroll path is now lossless on the QEMU side: every fraction of a
detent the host UI reports either reaches the guest or is carried over
to the next report. The guest still cannot reproduce the host's
pixel deltas exactly, because the smallest step a USB wheel can
express is one count and with the multiplier enabled one count is
one WHEEL_DELTA unit (1/120 detent). Windows delivers WM_MOUSEWHEEL
deltas as integers in the same unit and Chromium turns them into
pixels as

  deltaY = units * 100 / 120

so the guest sees deltas in steps of 0.833 px. A host movement that
does not land on a whole unit is split: the whole units are sent now
and the remainder later. For example, if the host scrolls by the
equivalent of 26 px:

  26 px * 120 / 100 = 31.2 units
  sent now: 31 units -> 25.833 px in the guest
  carried: 0.2 units -> sent with a later report

Per event the guest is therefore off by less than 0.833 px, but no
movement is lost over time. Movements that are a multiple of 5 px
(6 units) map exactly.

The remaining per-event differences between host and guest come from
outside QEMU: host and guest browsers apply different scroll scaling
and smoothing and several host events can fall into one USB polling
interval (8-10 ms) and reach the guest as a single report.

Changes since RFC:
 - Patch 4 (new): derive the descriptor length with sizeof() instead
   of hard-coding it.
 - Keep the report descriptor comments in their existing column
   instead of moving them.
 - Check "hs->protocol == 1" for report protocol and add boot/report
   protocol comments in hid_pointer_poll().
 - Replace the 1/4/8/16 divisor switch with multiplier scaling in
   hid_scroll_counts(); the guest-selected multiplier now increases
   the resolution instead of dividing it.
 - Drop the stray blank line in hid_pointer_poll().
 - Move the reset changes into their own patch.
 - Move the new migration state into an optional subsection and
   convert queued wheel movement from older QEMU versions.
 - New input-layer scroll event and GTK/SDL support, so the host's
   fine-grained scroll actually reaches the device.

Changes since v1:
 - Added proper suggested by.

Reference:
Enhanced Wheel Support in Windows
https://download.microsoft.com/download/b/d/1/bd1f7ef4-7d72-419e-bc5c-9f79ad7bb66e/wheel.docx

Open questions/known gaps:

 - The descriptor and packet size change is guest visible. A guest
   migrated from an older QEMU keeps the old 52-byte descriptor until
   it re-enumerates the device, but receives the new 6-byte reports.
   Should this be tied to a usb-mouse property that hw_compat_11_1
   turns off? The same property could keep the wheel subsection from
   being sent to older machine types, so that migrating back to an
   older QEMU keeps working after the guest enabled the multiplier.
 - Only the GTK and SDL UIs produce high-resolution scroll events so
   far. VNC, Spice and Cocoa still send wheel clicks.
 - Linux guests are not tested yet.

Feedback is very welcome!

Thank you,
Soumyajyotii Ssarkar

Soumyajyotii Ssarkar (8):
  ui/input: add high-resolution scroll input event
  ui/gtk: forward smooth scroll deltas as high-resolution scroll events
  ui/sdl2: forward precise wheel deltas as high-resolution scroll events
  hw/usb/dev-hid: derive the mouse report descriptor length with
    sizeof()
  hw/input/hid: accept high-resolution vertical scroll events
  hw/usb/dev-hid: report horizontal wheel through AC Pan
  hw/usb/dev-hid: support the wheel Resolution Multiplier feature report
  hw/input/hid: clear wheel state and mouse_grabbed on reset

 hw/input/hid.c         | 187 ++++++++++++++++++++++++++++++++----
 hw/usb/dev-hid.c       | 209 ++++++++++++++++++++++++++++++++---------
 include/hw/input/hid.h |   8 ++
 include/ui/input.h     |   6 ++
 qapi/ui.json           |  45 ++++++++-
 replay/replay-input.c  |   8 ++
 ui/gtk.c               |  34 ++++---
 ui/input.c             |  82 +++++++++++++++-
 ui/sdl2.c              |  28 ++++++
 ui/trace-events        |   1 +
 10 files changed, 531 insertions(+), 77 deletions(-)

-- 
2.56.0



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-10-28  6:27 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-27 19:42 [PATCH v2 0/8] usb-mouse: high-resolution vertical and horizontal wheel support soumyajyotisarkar23
2026-10-27 19:42 ` [PATCH v2 1/8] ui/input: add high-resolution scroll input event soumyajyotisarkar23
2026-10-28  6:26   ` Markus Armbruster
2026-10-27 19:42 ` [PATCH v2 2/8] ui/gtk: forward smooth scroll deltas as high-resolution scroll events soumyajyotisarkar23
2026-10-27 19:42 ` [PATCH v2 3/8] ui/sdl2: forward precise wheel " soumyajyotisarkar23
2026-10-27 19:42 ` [PATCH v2 4/8] hw/usb/dev-hid: derive the mouse report descriptor length with sizeof() soumyajyotisarkar23
2026-10-27 19:42 ` [PATCH v2 5/8] hw/input/hid: accept high-resolution vertical scroll events soumyajyotisarkar23
2026-10-27 19:42 ` [PATCH v2 6/8] hw/usb/dev-hid: report horizontal wheel through AC Pan soumyajyotisarkar23
2026-10-27 19:42 ` [PATCH v2 7/8] hw/usb/dev-hid: support the wheel Resolution Multiplier feature report soumyajyotisarkar23
2026-10-27 19:42 ` [PATCH v2 8/8] hw/input/hid: clear wheel state and mouse_grabbed on reset soumyajyotisarkar23

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.