summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2014-07-14 11:34:38 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2014-07-14 13:40:08 +1000
commitd385afd324f15d1903ba1a5abadb59e8f5299540 (patch)
tree151c7c185e2aa3b628a574d128e3afcb051f60ba
parentd70fc32e12ffb257903c280c0c81c1ebb2be0734 (diff)
dix: apply pointer acceleration between mapping to phys and back to screenwip/touchpad-resolution-scaling
Mapping the device-relative deltas to something within the desktop ratio means stretching dx or dy. This can cause different accelerations for the same input data depending on the screen size. Split this up and convert to physical movements first, accelerate that, then convert back to map to the screen data. Double the magic factor, because otherwise we're too slow, magic of 8 feels about alright for both the touchpad and a Wacom I5 in relative mode. Note to those looking at this in the future: ideally we should convert the delta into equivalent deltas on a standard 400 DPI USB mouse: in scale_for_device_resolution: double xmagic = 25.4/400000.0 * xres; x = valuator_mask_get_double(mask, 0) / xmagic; valuator_mask_set_double(mask, 0, x); The deltas would thus correspond to the deltas coming from a mouse. That can be accelerated in the same way, and then converted back. in map_to_screen: double xmagic = 25.4/400000.0 * xres; x = valuator_mask_get_double(mask, 0) * xmagic; x = x/xres * screen_res/screenInfo.width * xrange; valuator_mask_set_double(mask, 0, x); This should provide the same "feel" of pointer acceleration on both devices if we have the same acceleration methods. Synaptics uses it's own acceleration method however, so we need to trick around in the server here until we fix it simultaneously in both packages, at which point we only have Wacom to worry about and mummy can I go home yet? Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--dix/getevents.c77
1 files changed, 62 insertions, 15 deletions
diff --git a/dix/getevents.c b/dix/getevents.c
index 59f95f0d1..ffc563f26 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -777,6 +777,9 @@ add_to_scroll_valuator(DeviceIntPtr dev, ValuatorMask *mask, int valuator, doubl
what we do here is a hack to make touchpads usable. for a given relative
motion vector in device coordinates:
1. calculate physical movement on the device in metres
+ 1.5. apply pointer acceleration on the physical movement
+
+ [see map_into_screen for steps 2-5]
2. calculate pixel vector that is the same physical movement on the
screen (times some magic number to provide sensible base speed)
3. calculate what percentage this vector is of the current screen
@@ -799,18 +802,16 @@ scale_for_device_resolution(DeviceIntPtr dev, ValuatorMask *mask)
ValuatorClassPtr v = dev->valuator;
int xrange = v->axes[0].max_value - v->axes[0].min_value + 1;
int yrange = v->axes[1].max_value - v->axes[1].min_value + 1;
-
int xres, yres;
- /* If we have multiple screens with different dpi, it gets complicated:
- we have to map which screen we're on and then take the dpi of that
- screen to be somewhat accurate. */
- const ScreenPtr s = screenInfo.screens[0];
- const double screen_res = 1000.0 * s->width/s->mmWidth; /* units/m */
-
- /* some magic multiplier, so unaccelerated movement of x mm on the
- device reflects x * magic mm on the screen */
- const double magic = 4;
+ /* we're converting to mm here before applying an acceleration. that
+ will feel too slow for touchpads, so apply some magic multiplier
+ here to make it feel right. Wacom tablets in relative mode will feel
+ too fast then, but that's the price we pay for now. This can really
+ only be fixed by dropping the synaptics-specific acceleration
+ profile.
+ */
+ const double magic = 8;
if (v->axes[0].resolution != 0 && v->axes[1].resolution != 0) {
xres = v->axes[0].resolution;
@@ -829,13 +830,41 @@ scale_for_device_resolution(DeviceIntPtr dev, ValuatorMask *mask)
if (valuator_mask_isset(mask, 0)) {
x = valuator_mask_get_double(mask, 0);
- x = magic * x/xres * screen_res/screenInfo.width * xrange;
+ x = magic * x/xres;
+ valuator_mask_set_double(mask, 0, x);
+ }
+
+ if (valuator_mask_isset(mask, 1)) {
+ y = valuator_mask_get_double(mask, 1);
+ y = magic * y/yres;
+ valuator_mask_set_double(mask, 1, y);
+ }
+}
+
+/* See comment in scale_for_device_resolution, this is steps 2-5 */
+static void
+map_into_screen(DeviceIntPtr dev, ValuatorMask *mask)
+{
+ double x, y;
+ ValuatorClassPtr v = dev->valuator;
+ /* If we have multiple screens with different dpi, it gets complicated:
+ we have to map which screen we're on and then take the dpi of that
+ screen to be somewhat accurate. */
+ const ScreenPtr s = screenInfo.screens[0];
+ const double screen_res = 1000.0 * s->width/s->mmWidth; /* units/m */
+
+ int xrange = v->axes[0].max_value - v->axes[0].min_value + 1;
+ int yrange = v->axes[1].max_value - v->axes[1].min_value + 1;
+
+ if (valuator_mask_isset(mask, 0)) {
+ x = valuator_mask_get_double(mask, 0);
+ x = x * screen_res/screenInfo.width * xrange;
valuator_mask_set_double(mask, 0, x);
}
if (valuator_mask_isset(mask, 1)) {
y = valuator_mask_get_double(mask, 1);
- y = magic * y/yres * screen_res/screenInfo.height * yrange;
+ y = y * screen_res/screenInfo.height * yrange;
valuator_mask_set_double(mask, 1, y);
}
}
@@ -1479,21 +1508,39 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
set_raw_valuators(raw, &mask, raw->valuators.data);
}
else {
+ int is_absolute_device = 0;
ValuatorClassPtr v = pDev->valuator;
transformRelative(pDev, &mask);
- /* for abs devices in relative mode, we've just scaled wrong, since we
- mapped the device's shape into the screen shape. Undo this. */
+ /* read the comment in scale_for_device_resolution and weep */
if (v && v->numAxes > 1 &&
v->axes[0].min_value < v->axes[0].max_value &&
- v->axes[1].min_value < v->axes[1].max_value) {
+ v->axes[1].min_value < v->axes[1].max_value)
+ is_absolute_device = 1;;
+
+ if (is_absolute_device) {
scale_for_device_resolution(pDev, &mask);
+ /* mask is now in mm, not units */
}
+ /* We've just changed dx/dy based on the device and screen
+ resolution. Depending on the desktop size this gives us a
+ stretched or compressed dx/dy, which then kicks in differently
+ for pointer acceleration. Solution:
+ * scale for device resolution so we have units in mm
+ * accelerate pointer
+ * scale back into what the screen res is
+ */
+ /* now accelerate, either the mm or the dx/dy in units for
+ pure relative devices */
if (flags & POINTER_ACCELERATE)
accelPointer(pDev, &mask, ms);
+ if (is_absolute_device) {
+ map_into_screen(pDev, &mask);
+ }
+
if ((flags & POINTER_NORAW) == 0 && raw)
set_raw_valuators(raw, &mask, raw->valuators.data);