Soumyajyotii Ssarkar <[email protected]> writes:

> 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) {
> +        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;
> +        }
> +
> +        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;
> +        }
> +    }
> +
>      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;
> +
>      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;
>          break;
>      }
>      hs->head = 0;
> @@ -619,6 +674,7 @@ static const VMStateDescription vmstate_hid_ptr_queue = {
>          VMSTATE_INT32(xdx, HIDPointerEvent),
>          VMSTATE_INT32(ydy, HIDPointerEvent),
>          VMSTATE_INT32(dz, HIDPointerEvent),
> +        VMSTATE_INT32(pan, HIDPointerEvent),
>          VMSTATE_INT32(buttons_state, HIDPointerEvent),
>          VMSTATE_END_OF_LIST()
>      }
> @@ -636,6 +692,10 @@ const VMStateDescription vmstate_hid_ptr_device = {
>          VMSTATE_UINT32(n, HIDState),
>          VMSTATE_INT32(protocol, HIDState),
>          VMSTATE_UINT8(idle, HIDState),
> +        VMSTATE_UINT8(ptr.wheel_multiplier, HIDState),
> +        VMSTATE_UINT8(ptr.pan_multiplier, HIDState),
> +        VMSTATE_INT32(ptr.wheel_residual, HIDState),
> +        VMSTATE_INT32(ptr.pan_residual, HIDState),
>          VMSTATE_END_OF_LIST(),

If you update migration state you also need to ensure that older systems
can be migrated to newer ones. There are some docs in docs/devel that
give some guidance on handling these cases. 

>      }
>  };
> diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h
> index 1a1941d371..db902fa023 100644
> --- a/include/hw/input/hid.h
> +++ b/include/hw/input/hid.h
> @@ -25,6 +25,8 @@ typedef struct HIDMouseState {
>      int mouse_grabbed;
>      uint8_t wheel_multiplier;
>      uint8_t pan_multiplier;
> +    int32_t wheel_residual;
> +    int32_t pan_residual;
>  } HIDMouseState;
>
>  typedef struct HIDKeyboardState {

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro

Reply via email to