So I needed to see my thoughts on paper but my desk was so full of stuff
I couldn't make room for pen and paper.  Instead I fired up Gimp, and
drawing with the mouse worked fine until I realized it's next to impossible
to draw diagonal lines that look like lines.

Instead of straight lines, I got waves.  The faster I draw the mouse, the
deeper the waves.  It looked like diagonal mouse motion generated a pair
of pointer motion events, one for the X axis and another for Y.  And Gimp
smoothed that stairstep motion, resulting in waves.  Xev(1) confirmed my
hypothesis.

It turns out wsmouse(4) is breaking the mouse input into multiple events.
This isn't necessarily a bug, since it allows for a very small and simple
event structure which works without modification as new properties (such
as button states, axes, etc.) are added.

Now wsmouse generates all the events it can in a loop before waking up
the process that waits for these events.  So on the receiving side (i.e.
in the xenocara ws(4) driver) we can sum all the consecutive X and Y
deltas from a single read() before issuing a pointer motion event.  This
eliminates the stairsteps as long as the events generated by wsmouse fit
in the buffers involved.

Other approaches would be either extending the event structure, or perhaps
adding a new event type that somehow communicates the intended grouping
for events that follow/precede (but ugh...).  I felt the ws(4) fix was
the least intrusive, and it appears to work just fine here.  What do you
think?

This image (drawn in Gimp) illustrates the problem.  The last two lines
were drawn with my diff applied.

        http://guu.fi/mousebug.png

Index: xenocara/driver/xf86-input-ws/src/ws.c
===================================================================
RCS file: /cvs/xenocara/driver/xf86-input-ws/src/ws.c,v
retrieving revision 1.57
diff -u -p -r1.57 ws.c
--- xenocara/driver/xf86-input-ws/src/ws.c      8 Jul 2012 14:22:03 -0000       
1.57
+++ xenocara/driver/xf86-input-ws/src/ws.c      7 Jul 2013 18:33:57 -0000
@@ -474,7 +474,7 @@ wsReadInput(InputInfoPtr pInfo)
 {
        WSDevicePtr priv = (WSDevicePtr)pInfo->private;
        static struct wscons_event eventList[NUMEVENTS];
-       int n, c;
+       int n, c, dx, dy;
        struct wscons_event *event = eventList;
        unsigned char *pBuf;
 
@@ -488,10 +488,11 @@ wsReadInput(InputInfoPtr pInfo)
        if (n == 0)
                return;
 
+       dx = dy = 0;
        n /= sizeof(struct wscons_event);
        while (n--) {
                int buttons = priv->lastButtons;
-               int dx = 0, dy = 0, dz = 0, dw = 0, ax = 0, ay = 0;
+               int dz = 0, dw = 0, ax = 0, ay = 0;
                int zbutton = 0, wbutton = 0;
 
                switch (event->type) {
@@ -506,11 +507,11 @@ wsReadInput(InputInfoPtr pInfo)
                            buttons));
                        break;
                case WSCONS_EVENT_MOUSE_DELTA_X:
-                       dx = event->value;
+                       dx += event->value;
                        DBG(4, ErrorF("Relative X %d\n", event->value));
                        break;
                case WSCONS_EVENT_MOUSE_DELTA_Y:
-                       dy = -event->value;
+                       dy -= event->value;
                        DBG(4, ErrorF("Relative Y %d\n", event->value));
                        break;
                case WSCONS_EVENT_MOUSE_ABSOLUTE_X:
@@ -548,14 +549,18 @@ wsReadInput(InputInfoPtr pInfo)
                }
                ++event;
 
-               if (dx || dy) {
-                       if (wsWheelEmuFilterMotion(pInfo, dx, dy))
+               if ((dx || dy) && event->type != WSCONS_EVENT_MOUSE_DELTA_X &&
+                   event->type != WSCONS_EVENT_MOUSE_DELTA_Y) {
+                       int tmpx = dx, tmpy = dy;
+                       dx = dy = 0;
+
+                       if (wsWheelEmuFilterMotion(pInfo, tmpx, tmpy))
                                continue;
 
                        /* relative motion event */
                        DBG(3, ErrorF("postMotionEvent dX %d dY %d\n",
-                           dx, dy));
-                       xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy);
+                           tmpx, tmpy));
+                       xf86PostMotionEvent(pInfo->dev, 0, 0, 2, tmpx, tmpy);
                }
                if (dz && priv->Z.negative != WS_NOMAP
                    && priv->Z.positive != WS_NOMAP) {
@@ -583,9 +588,9 @@ wsReadInput(InputInfoPtr pInfo)
                        ay = tmp;
                }
                if (ax) {
-                       dx = ax - priv->old_ax;
+                       int xdelta = ax - priv->old_ax;
                        priv->old_ax = ax;
-                       if (wsWheelEmuFilterMotion(pInfo, dx, 0))
+                       if (wsWheelEmuFilterMotion(pInfo, xdelta, 0))
                                continue;
 
                        /* absolute position event */
@@ -593,15 +598,24 @@ wsReadInput(InputInfoPtr pInfo)
                        xf86PostMotionEvent(pInfo->dev, 1, 0, 1, ax);
                }
                if (ay) {
-                       dy = ay - priv->old_ay;
+                       int ydelta = ay - priv->old_ay;
                        priv->old_ay = ay;
-                       if (wsWheelEmuFilterMotion(pInfo, 0, dy))
+                       if (wsWheelEmuFilterMotion(pInfo, 0, ydelta))
                                continue;
 
                        /* absolute position event */
                        DBG(3, ErrorF("postMotionEvent y %d\n", ay));
                        xf86PostMotionEvent(pInfo->dev, 1, 1, 1, ay);
                }
+       }
+       if (dx || dy) {
+               if (wsWheelEmuFilterMotion(pInfo, dx, dy))
+                       return;
+
+               /* relative motion event */
+               DBG(3, ErrorF("postMotionEvent dX %d dY %d\n",
+                   dx, dy));
+               xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy);
        }
        return;
 }



Reply via email to