diff --git a/doc/normalization-of-relative-motion.dox b/doc/normalization-of-relative-motion.dox index aaa1735f..dd5d39b3 100644 --- a/doc/normalization-of-relative-motion.dox +++ b/doc/normalization-of-relative-motion.dox @@ -12,10 +12,33 @@ physical movement or 10 millimeters, depending on the sensor. This affects pointer acceleration in libinput and interpretation of relative coordinates in callers. -libinput normalizes all relative input to a physical resolution of -1000dpi, the same delta from two different devices thus represents the -same physical movement of those two devices (within sensor error -margins). +libinput does partial normalization of relative input. For devices with a +resolution of 1000dpi and higher, motion events are normalized to a default +of 1000dpi before pointer acceleration is applied. As a result, devices with +1000dpi and above feel the same. + +Devices below 1000dpi are not normalized (normalization of a 1-device unit +movement on a 400dpi mouse would cause a 2.5 pixel movement). Instead, +libinput applies a dpi-dependent acceleration function. At low speeds, a +1-device unit movement usually translates into a 1-pixel movements. As the +movement speed increases, acceleration is applied - at high speeds a low-dpi +device will roughly feel the same as a higher-dpi mouse. + +This normalization only applies to accelerated coordinates, unaccelerated +coordiantes are left in device-units. It is up to the caller to interpret +those coordinates correctly. + +@section Normalization of touchpad coordinates + +Touchpads may have a different resolution for the horizontal and vertical +axis. Interpreting coordinates from the touchpad without taking resolutino +into account results in uneven motion. + +libinput scales unaccelerated touchpad motion do the resolution of the +touchpad's x axis, i.e. the unaccelerated value for the y axis is: + y = (x / resolution_x) * resolution_y + +@section Setting custom DPI settings Devices usually do not advertise their resolution and libinput relies on the udev property MOUSE_DPI for this information. This property is usually diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 328a744b..e85a9d77 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -91,6 +91,7 @@ static void tp_gesture_post_pointer_motion(struct tp_dispatch *tp, uint64_t time) { struct normalized_coords delta, unaccel; + struct device_float_coords raw; /* When a clickpad is clicked, combine motion of all active touches */ if (tp->buttons.is_clickpad && tp->buttons.state) @@ -101,8 +102,11 @@ tp_gesture_post_pointer_motion(struct tp_dispatch *tp, uint64_t time) delta = tp_filter_motion(tp, &unaccel, time); if (!normalized_is_zero(delta) || !normalized_is_zero(unaccel)) { - pointer_notify_motion(&tp->device->base, time, - &delta, &unaccel); + raw = tp_unnormalize_for_xaxis(tp, unaccel); + pointer_notify_motion(&tp->device->base, + time, + &delta, + &raw); } } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 36260c68..a12c87a7 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -318,6 +318,21 @@ tp_normalize_delta(struct tp_dispatch *tp, struct device_float_coords delta) return normalized; } +/** + * Takes a dpi-normalized set of coordinates, returns a set of coordinates + * in the x-axis' coordinate space. + */ +static inline struct device_float_coords +tp_unnormalize_for_xaxis(struct tp_dispatch *tp, struct normalized_coords delta) +{ + struct device_float_coords raw; + + raw.x = delta.x / tp->accel.x_scale_coeff; + raw.y = delta.y / tp->accel.x_scale_coeff; /* <--- not a typo */ + + return raw; +} + struct normalized_coords tp_get_delta(struct tp_touch *t); diff --git a/src/evdev.c b/src/evdev.c index 63d2ca8e..9602587c 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -281,6 +281,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) struct libinput_seat *seat = base->seat; struct normalized_coords accel, unaccel; struct device_coords point; + struct device_float_coords raw; slot = device->mt.slot; @@ -289,6 +290,8 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) return; case EVDEV_RELATIVE_MOTION: normalize_delta(device, &device->rel, &unaccel); + raw.x = device->rel.x; + raw.y = device->rel.y; device->rel.x = 0; device->rel.y = 0; @@ -305,7 +308,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) if (normalized_is_zero(accel) && normalized_is_zero(unaccel)) break; - pointer_notify_motion(base, time, &accel, &unaccel); + pointer_notify_motion(base, time, &accel, &raw); break; case EVDEV_ABSOLUTE_MT_DOWN: if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) diff --git a/src/libinput-private.h b/src/libinput-private.h index 5192b651..d11f000f 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -324,7 +324,7 @@ void pointer_notify_motion(struct libinput_device *device, uint64_t time, const struct normalized_coords *delta, - const struct normalized_coords *unaccel); + const struct device_float_coords *raw); void pointer_notify_motion_absolute(struct libinput_device *device, diff --git a/src/libinput.c b/src/libinput.c index 319934ac..d164604c 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -96,7 +96,7 @@ struct libinput_event_pointer { struct libinput_event base; uint32_t time; struct normalized_coords delta; - struct normalized_coords delta_unaccel; + struct device_float_coords delta_raw; struct device_coords absolute; struct discrete_coords discrete; uint32_t button; @@ -339,7 +339,7 @@ libinput_event_pointer_get_dx_unaccelerated( 0, LIBINPUT_EVENT_POINTER_MOTION); - return event->delta_unaccel.x; + return event->delta_raw.x; } LIBINPUT_EXPORT double @@ -351,7 +351,7 @@ libinput_event_pointer_get_dy_unaccelerated( 0, LIBINPUT_EVENT_POINTER_MOTION); - return event->delta_unaccel.y; + return event->delta_raw.y; } LIBINPUT_EXPORT double @@ -1130,7 +1130,7 @@ void pointer_notify_motion(struct libinput_device *device, uint64_t time, const struct normalized_coords *delta, - const struct normalized_coords *unaccel) + const struct device_float_coords *raw) { struct libinput_event_pointer *motion_event; @@ -1144,7 +1144,7 @@ pointer_notify_motion(struct libinput_device *device, *motion_event = (struct libinput_event_pointer) { .time = time, .delta = *delta, - .delta_unaccel = *unaccel, + .delta_raw = *raw, }; post_device_event(device, time, diff --git a/src/libinput.h b/src/libinput.h index 7d907f16..5df71836 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -462,8 +462,8 @@ libinput_event_pointer_get_time(struct libinput_event_pointer *event); * If a device employs pointer acceleration, the delta returned by this * function is the accelerated delta. * - * Relative motion deltas are normalized to represent those of a device with - * 1000dpi resolution. See @ref motion_normalization for more details. + * Relative motion deltas are to be interpreted as pixel movement of a + * standardized mouse. See @ref motion_normalization for more details. * * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. @@ -483,8 +483,8 @@ libinput_event_pointer_get_dx(struct libinput_event_pointer *event); * If a device employs pointer acceleration, the delta returned by this * function is the accelerated delta. * - * Relative motion deltas are normalized to represent those of a device with - * 1000dpi resolution. See @ref motion_normalization for more details. + * Relative motion deltas are to be interpreted as pixel movement of a + * standardized mouse. See @ref motion_normalization for more details. * * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. @@ -501,10 +501,11 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event); * current event. For pointer events that are not of type @ref * LIBINPUT_EVENT_POINTER_MOTION, this function returns 0. * - * Relative unaccelerated motion deltas are normalized to represent those of a - * device with 1000dpi resolution. See @ref motion_normalization for more - * details. Note that unaccelerated events are not equivalent to 'raw' events - * as read from the device. + * Relative unaccelerated motion deltas are raw device coordinates. + * Note that these coordinates are subject to the device's native + * resolution. Touchpad coordinates represent raw device coordinates in the + * X resolution of the touchpad. See @ref motion_normalization for more + * details. * * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION. @@ -522,10 +523,11 @@ libinput_event_pointer_get_dx_unaccelerated( * current event. For pointer events that are not of type @ref * LIBINPUT_EVENT_POINTER_MOTION, this function returns 0. * - * Relative unaccelerated motion deltas are normalized to represent those of a - * device with 1000dpi resolution. See @ref motion_normalization for more - * details. Note that unaccelerated events are not equivalent to 'raw' events - * as read from the device. + * Relative unaccelerated motion deltas are raw device coordinates. + * Note that these coordinates are subject to the device's native + * resolution. Touchpad coordinates represent raw device coordinates in the + * X resolution of the touchpad. See @ref motion_normalization for more + * details. * * @note It is an application bug to call this function for events other than * @ref LIBINPUT_EVENT_POINTER_MOTION.