Implement HID feature report handlers (GET_REPORT/SET_REPORT) for
report ID 0x02 to allow guests to configure wheel/pan resolution
multipliers.
Multiplier encoding:
- Bits [1:0]: wheel_multiplier (0=+-1, 1=+-4, 2=+-8, 3=+-16)
- Bits [3:2]: pan_multiplier (0=+-1, 1=+-4, 2=+-8, 3=+-16)
Supports flexible payload formats (with/without report ID byte).
Allows Windows guests to dynamically adjust scroll sensitivity without
driver installation.
Signed-off-by: Soumyajyotii Ssarkar <soumyajyotisarkar23@gmail.com>
---
hw/usb/dev-hid.c | 65 ++++++++++++++++++++++++++++++++++++------
include/hw/input/hid.h | 2 ++
2 files changed, 59 insertions(+), 8 deletions(-)
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index 49e23c2319..cdcf2a4a0e 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -672,17 +672,66 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
}
break;
case HID_GET_REPORT:
- if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- p->actual_length = hid_pointer_poll(hs, data, length);
- } else if (hs->kind == HID_KEYBOARD) {
- p->actual_length = hid_keyboard_poll(hs, data, length);
+ {
+ uint8_t mult;
+ uint8_t report_type = (value >> 8) & 0xFF;
+ uint8_t report_id = value & 0xFF;
+
+ if (report_type == 0x03 && report_id == 0x02 &&
+ hs->kind == HID_MOUSE) {
+
+ if (length < 1) {
+ goto fail;
+ }
+
+ mult = ((hs->ptr.pan_multiplier & 0x03) << 2) |
+ (hs->ptr.wheel_multiplier & 0x03);
+ if (length >= 2) {
+ data[0] = 0x02;
+ data[1] = mult;
+ p->actual_length = 2;
+ } else {
+ data[0] = mult;
+ p->actual_length = 1;
+ }
+
+ } else if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+ p->actual_length = hid_pointer_poll(hs, data, length);
+ } else if (hs->kind == HID_KEYBOARD) {
+ p->actual_length = hid_keyboard_poll(hs, data, length);
+ } else {
+ goto fail;
+ }
}
break;
case HID_SET_REPORT:
- if (hs->kind == HID_KEYBOARD) {
- p->actual_length = hid_keyboard_write(hs, data, length);
- } else {
- goto fail;
+ {
+ uint8_t mult;
+ uint8_t report_type = (value >> 8) & 0xFF;
+ uint8_t report_id = value & 0xFF;
+
+ if (report_type == 0x03 && report_id == 0x02 &&
+ hs->kind == HID_MOUSE) {
+
+ if (length < 1) {
+ goto fail;
+ }
+
+ if (length >= 2 && data[0] == 0x02) {
+ mult = data[1];
+ } else {
+ mult = data[0];
+ }
+
+ hs->ptr.wheel_multiplier = mult & 0x03;
+ hs->ptr.pan_multiplier = (mult >> 2) & 0x03;
+ p->actual_length = length;
+
+ } else if (hs->kind == HID_KEYBOARD) {
+ p->actual_length = hid_keyboard_write(hs, data, length);
+ } else {
+ goto fail;
+ }
}
break;
case HID_GET_PROTOCOL:
diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h
index 1bb1778ee7..1a1941d371 100644
--- a/include/hw/input/hid.h
+++ b/include/hw/input/hid.h
@@ -23,6 +23,8 @@ typedef void (*HIDEventFunc)(HIDState *s);
typedef struct HIDMouseState {
HIDPointerEvent queue[QUEUE_LENGTH];
int mouse_grabbed;
+ uint8_t wheel_multiplier;
+ uint8_t pan_multiplier;
} HIDMouseState;
typedef struct HIDKeyboardState {
--
2.53.0