summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);