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

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@who-t.net>
Reviewed-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
Peter Hutterer 2013-01-11 14:22:07 +10:00
parent a6ba2b79ae
commit 61a99aff9d

View File

@ -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 */