Have the emulated mouse report horizontal wheel events when in exps/2
mode.

Signed-off-by: Brad Jorsch <ano...@users.sourceforge.net>
---
 hw/ps2.c |   56 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/hw/ps2.c b/hw/ps2.c
index db5605d..09e4365 100644
--- a/hw/ps2.c
+++ b/hw/ps2.c
@@ -105,7 +105,9 @@ typedef struct {
     int mouse_dx; /* current values, needed for 'poll' mode */
     int mouse_dy;
     int mouse_dz;
+    int mouse_dw;
     uint8_t mouse_buttons;
+    uint8_t mouse_buttons_changed;
 } PS2MouseState;
 
 /* Table to convert from PC scancodes to raw scancodes.  */
@@ -284,11 +286,12 @@ void ps2_keyboard_set_translation(void *opaque, int mode)
 static void ps2_mouse_send_packet(PS2MouseState *s)
 {
     unsigned int b;
-    int dx1, dy1, dz1;
+    int dx1, dy1, dz1, dw1;
 
     dx1 = s->mouse_dx;
     dy1 = s->mouse_dy;
     dz1 = s->mouse_dz;
+    dw1 = s->mouse_dw;
     /* XXX: increase range to 8 bits ? */
     if (dx1 > 127)
         dx1 = 127;
@@ -299,12 +302,17 @@ static void ps2_mouse_send_packet(PS2MouseState *s)
     else if (dy1 < -127)
         dy1 = -127;
     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
+    s->mouse_buttons_changed &= ~0x07;
     ps2_queue(&s->common, b);
     ps2_queue(&s->common, dx1 & 0xff);
     ps2_queue(&s->common, dy1 & 0xff);
     /* extra byte for IMPS/2 or IMEX */
     switch(s->mouse_type) {
     default:
+        /* Just ignore the wheels if not supported */
+        s->mouse_dz = 0;
+        s->mouse_dw = 0;
+        s->mouse_buttons_changed &= 0x07;
         break;
     case 3:
         if (dz1 > 127)
@@ -312,13 +320,29 @@ static void ps2_mouse_send_packet(PS2MouseState *s)
         else if (dz1 < -127)
                 dz1 = -127;
         ps2_queue(&s->common, dz1 & 0xff);
+        s->mouse_dz -= dz1;
+        s->mouse_dw = 0;
+        s->mouse_buttons_changed &= 0x07;
         break;
     case 4:
-        if (dz1 > 7)
-            dz1 = 7;
-        else if (dz1 < -7)
-            dz1 = -7;
-        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
+        /* This matches what the Linux kernel expects for exps/2 in
+         * drivers/input/mouse/psmouse-base.c. */
+        if (dw1 != 0) {
+            if (dw1 > 31)
+                dw1 = 31;
+            else if (dw1 < -31)
+                dw1 = -31;
+            b = (dw1 & 0x3f) | 0x40;
+            s->mouse_dw -= dw1;
+        } else {
+            if (dz1 > 7)
+                dz1 = 7;
+            else if (dz1 < -7)
+                dz1 = -7;
+            b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
+            s->mouse_dz -= dz1;
+            s->mouse_buttons_changed &= 0x07;
+        }
         ps2_queue(&s->common, b);
         break;
     }
@@ -326,7 +350,6 @@ static void ps2_mouse_send_packet(PS2MouseState *s)
     /* update deltas */
     s->mouse_dx -= dx1;
     s->mouse_dy -= dy1;
-    s->mouse_dz -= dz1;
 }
 
 static void ps2_mouse_event(void *opaque,
@@ -341,11 +364,13 @@ static void ps2_mouse_event(void *opaque,
     s->mouse_dx += dx;
     s->mouse_dy -= dy;
     s->mouse_dz += dz;
+    s->mouse_dw -= dw;
+    s->mouse_buttons_changed |= s->mouse_buttons ^ buttons_state;
+    s->mouse_buttons = buttons_state;
     /* XXX: SDL sometimes generates nul events: we delete them */
     if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
-        s->mouse_buttons == buttons_state)
+        s->mouse_dw == 0 && s->mouse_buttons_changed == 0)
        return;
-    s->mouse_buttons = buttons_state;
 
     if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
         (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
@@ -353,7 +378,8 @@ static void ps2_mouse_event(void *opaque,
             /* if not remote, send event. Multiple events are sent if
                too big deltas */
             ps2_mouse_send_packet(s);
-            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
+            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
+                s->mouse_dw == 0 && s->mouse_buttons_changed == 0)
                 break;
         }
     }
@@ -525,7 +551,9 @@ static void ps2_mouse_reset(void *opaque)
     s->mouse_dx = 0;
     s->mouse_dy = 0;
     s->mouse_dz = 0;
+    s->mouse_dw = 0;
     s->mouse_buttons = 0;
+    s->mouse_buttons_changed = 0;
 }
 
 static const VMStateDescription vmstate_ps2_common = {
@@ -569,9 +597,9 @@ static const VMStateDescription vmstate_ps2_keyboard = {
 
 static const VMStateDescription vmstate_ps2_mouse = {
     .name = "ps2mouse",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
     .fields      = (VMStateField []) {
         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
         VMSTATE_UINT8(mouse_status, PS2MouseState),
@@ -583,7 +611,9 @@ static const VMStateDescription vmstate_ps2_mouse = {
         VMSTATE_INT32(mouse_dx, PS2MouseState),
         VMSTATE_INT32(mouse_dy, PS2MouseState),
         VMSTATE_INT32(mouse_dz, PS2MouseState),
+        VMSTATE_INT32(mouse_dw, PS2MouseState),
         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
+        VMSTATE_UINT8(mouse_buttons_changed, PS2MouseState),
         VMSTATE_END_OF_LIST()
     }
 };
-- 
1.7.1



Reply via email to