[PATCH] dix: pre-scale relative events from abs devices to desktop ratio (#31636)

Peter Hutterer peter.hutterer at who-t.net
Thu Jan 10 22:28:49 PST 2013


Absolute devices may send relative events depending on the mode (synaptics
by default, wacom per option). The relative events are added to the previous
position, converted into device coordinates and then scaled into desktop
coordinates for pointer movement.

Because the device range must be mapped into the desktop coordinate range,
this results in uneven scaling depending dimensions, e.g. on a setup with
width == 2 * height, a relative movement of 10/10 in device coordinates
results in a cursor movement of 20/10 (+ acceleration)

Other commonly user-visible results:
* the touchpad changing acceleration once an external monitor as added.
* drawing a circle on a wacom tablet in relative mode gives an ellipsis in
  the same ratio as the desktop dimensions.

Solution: pre-scale the incoming relative x/y coordinates by width/height
ratio of the total desktop size. Then add them to the previous
coordinates and scale back with the previous mapping, which will undo the
pre-scaling and give us the right movement.

X.Org Bug 31636 <http://bugs.freedesktop.org/show_bug.cgi?id=31636>

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 dix/getevents.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/dix/getevents.c b/dix/getevents.c
index a1e1938..5100607 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -776,11 +776,33 @@ add_to_scroll_valuator(DeviceIntPtr dev, ValuatorMask *mask, int valuator, doubl
  * @param[in,out] mask Valuator data for this event, modified in-place.
  */
 static void
-moveRelative(DeviceIntPtr dev, ValuatorMask *mask)
+moveRelative(DeviceIntPtr dev, int flags, ValuatorMask *mask)
 {
     int i;
     Bool clip_xy = IsMaster(dev) || !IsFloating(dev);
 
+    /* for abs devices in relative mode, we've just scaled wrong, since we
+       mapped the device's shape into the screen shape. Undo this. */
+    if ((flags & POINTER_ABSOLUTE) == 0 && dev->valuator &&
+        dev->valuator->axes[0].min_value < dev->valuator->axes[0].max_value) {
+
+        double ratio = 1.0 * screenInfo.width/screenInfo.height;
+
+        if (ratio > 1.0) {
+            double y;
+            if (valuator_mask_fetch_double(mask, 1, &y)) {
+                y *= ratio;
+                valuator_mask_set_double(mask, 1, y);
+            }
+        } else {
+            double x;
+            if (valuator_mask_fetch_double(mask, 0, &x)) {
+                x *= ratio;
+                valuator_mask_set_double(mask, 0, x);
+            }
+        }
+    }
+
     /* calc other axes, clip, drop back into valuators */
     for (i = 0; i < valuator_mask_size(mask); i++) {
         double val = dev->last.valuators[i];
@@ -1380,7 +1402,7 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
         if ((flags & POINTER_NORAW) == 0)
             set_raw_valuators(raw, &mask, raw->valuators.data);
 
-        moveRelative(pDev, &mask);
+        moveRelative(pDev, flags, &mask);
     }
 
     /* valuators are in device coordinate system in absolute coordinates */
-- 
1.8.1



More information about the xorg-devel mailing list