On 3/31/26 19:08, Soumyajyotii Ssarkar wrote:
Implement multiplier-based scaling with residual accumulation for
fine-grained mouse wheel and pan sensitivity control in report mode.

Applies divisor based scaling (1, 4, 8, 16) based on negotiated
multiplier values.
Then uses residual based approach to prevent precision loss:

   residual += delta
   output = residual / divisor
   residual -= output * divisor

Residual state preserved across VM migrations via VMState.

Signed-off-by: Soumyajyotii Ssarkar <[email protected]>
---
  hw/input/hid.c         | 60 ++++++++++++++++++++++++++++++++++++++++++
  include/hw/input/hid.h |  2 ++
  2 files changed, 62 insertions(+)

diff --git a/hw/input/hid.c b/hw/input/hid.c
index d0b7af7c13..9b800faeb0 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -365,6 +365,7 @@ void hid_pointer_activate(HIDState *hs)
  int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
  {
      int dx, dy, dz, pan, l;
+    int wheel_divisor, pan_divisor;
      int index;
      HIDPointerEvent *e;

@@ -392,6 +393,54 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
      e->pan -= pan;


+    if (hs->kind == HID_MOUSE && hs->protocol != 0) {

shouldn't this better be "hs->protocol == 1" ?


+        switch (hs->ptr.wheel_multiplier & 0x03) {
+        case 0:
+            wheel_divisor = 1;
+            break;
+        case 1:
+            wheel_divisor = 4;
+            break;
+        case 2:
+            wheel_divisor = 8;
+            break;
+        default:
+            wheel_divisor = 16;
+            break;
+        }
+
+        switch (hs->ptr.pan_multiplier & 0x03) {
+        case 0:
+            pan_divisor = 1;
+            break;
+        case 1:
+            pan_divisor = 4;
+            break;
+        case 2:
+            pan_divisor = 8;
+            break;
+        default:
+            pan_divisor = 16;
+            break;
+        }
+
+        if (wheel_divisor > 1) {
+            hs->ptr.wheel_residual += dz;
+            dz = hs->ptr.wheel_residual / wheel_divisor;
+            hs->ptr.wheel_residual -= dz * wheel_divisor;
+        } else {
+            hs->ptr.wheel_residual = 0;
+        }

maybe instead of the whole above: ?

        if (hs->ptr.wheel_multiplier & 0x03) {
            wheel_divisor = 2 << (hs->ptr.wheel_multiplier & 0x03);
            hs->ptr.wheel_residual += dz;
            dz = hs->ptr.wheel_residual / wheel_divisor;
            hs->ptr.wheel_residual -= dz * wheel_divisor;
        } else {
            hs->ptr.wheel_residual = 0;
        }

+
+        if (pan_divisor > 1) {
+            hs->ptr.pan_residual += pan;
+            pan = hs->ptr.pan_residual / pan_divisor;
+            hs->ptr.pan_residual -= pan * pan_divisor;
+        } else {
+            hs->ptr.pan_residual = 0;
+        }

same here.


+    }
+
      if (hs->n &&
          !e->dz &&
          !e->pan &&
@@ -405,6 +454,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
      dz = 0 - dz;
      pan = 0 - pan;
      l = 0;
+

drop this change.

      switch (hs->kind) {
      case HID_MOUSE:
          if (hs->protocol == 0) {
@@ -528,6 +578,11 @@ void hid_reset(HIDState *hs)
      case HID_MOUSE:
      case HID_TABLET:
          memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
+        hs->ptr.mouse_grabbed = 0;
+        hs->ptr.wheel_multiplier = 0;
+        hs->ptr.pan_multiplier = 0;
+        hs->ptr.wheel_residual = 0;
+        hs->ptr.pan_residual = 0;

and move that in an own patch.

Otherwise the patch seems ok.
I suggest you resend the series with the proposed changes and
make sure it applies against git head.

Thanks!
Helge

Reply via email to