}
tp_get_delta(t, &dx, &dy);
- tp_filter_motion(tp, &dx, &dy, time);
+ tp_filter_motion(tp, &dx, &dy, NULL, NULL, time);
if (fabs(*delta) < t->scroll.threshold)
continue;
void
tp_filter_motion(struct tp_dispatch *tp,
- double *dx, double *dy, uint64_t time)
+ double *dx, double *dy,
+ double *dx_unaccel, double *dy_unaccel,
+ uint64_t time)
{
struct motion_params motion;
motion.dx = *dx * tp->accel.x_scale_coeff;
motion.dy = *dy * tp->accel.y_scale_coeff;
+ if (dx_unaccel)
+ *dx_unaccel = motion.dx;
+ if (dy_unaccel)
+ *dy_unaccel = motion.dy;
+
if (motion.dx != 0.0 || motion.dy != 0.0)
filter_dispatch(tp->device->pointer.filter, &motion, tp, time);
dx /= nchanged;
dy /= nchanged;
- tp_filter_motion(tp, &dx, &dy, time);
+ tp_filter_motion(tp, &dx, &dy, NULL, NULL, time);
evdev_post_scroll(tp->device, time, dx, dy);
}
struct tp_touch *t = tp_current_touch(tp);
double dx, dy;
int filter_motion = 0;
+ double dx_unaccel, dy_unaccel;
/* Only post (top) button events while suspended */
if (tp->device->suspended) {
return;
tp_get_delta(t, &dx, &dy);
- tp_filter_motion(tp, &dx, &dy, time);
+ tp_filter_motion(tp, &dx, &dy, &dx_unaccel, &dy_unaccel, time);
- if (dx != 0.0 || dy != 0.0)
- pointer_notify_motion(&tp->device->base, time, dx, dy);
+ if (dx != 0.0 || dy != 0.0 || dx_unaccel != 0.0 || dy_unaccel != 0.0) {
+ pointer_notify_motion(&tp->device->base, time,
+ dx, dy, dx_unaccel, dy_unaccel);
+ }
}
static void
void
tp_filter_motion(struct tp_dispatch *tp,
- double *dx, double *dy, uint64_t time);
+ double *dx, double *dy,
+ double *dx_unaccel, double *dy_unaccel,
+ uint64_t time);
int
tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time);
{
struct libinput *libinput = device->base.seat->libinput;
struct motion_params motion;
+ double dx_unaccel, dy_unaccel;
int32_t cx, cy;
int32_t x, y;
int slot;
case EVDEV_NONE:
return;
case EVDEV_RELATIVE_MOTION:
- motion.dx = device->rel.dx / ((double)device->dpi / DEFAULT_MOUSE_DPI);
- motion.dy = device->rel.dy / ((double)device->dpi / DEFAULT_MOUSE_DPI);
+ dx_unaccel = device->rel.dx / ((double) device->dpi /
+ DEFAULT_MOUSE_DPI);
+ dy_unaccel = device->rel.dy / ((double) device->dpi /
+ DEFAULT_MOUSE_DPI);
device->rel.dx = 0;
device->rel.dy = 0;
hw_is_key_down(device, device->scroll.button)) {
if (device->scroll.button_scroll_active)
evdev_post_scroll(device, time,
- motion.dx, motion.dy);
+ dx_unaccel, dy_unaccel);
break;
}
/* Apply pointer acceleration. */
+ motion.dx = dx_unaccel;
+ motion.dy = dy_unaccel;
filter_dispatch(device->pointer.filter, &motion, device, time);
- if (motion.dx == 0.0 && motion.dy == 0.0)
+ if (motion.dx == 0.0 && motion.dy == 0.0 &&
+ dx_unaccel == 0.0 && dy_unaccel == 0.0) {
break;
+ }
- pointer_notify_motion(base, time, motion.dx, motion.dy);
+ pointer_notify_motion(base, time,
+ motion.dx, motion.dy,
+ dx_unaccel, dy_unaccel);
break;
case EVDEV_ABSOLUTE_MT_DOWN:
if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
pointer_notify_motion(struct libinput_device *device,
uint64_t time,
double dx,
- double dy);
+ double dy,
+ double dx_noaccel,
+ double dy_noaccel);
void
pointer_notify_motion_absolute(struct libinput_device *device,
uint32_t time;
double x;
double y;
+ double dx_unaccel;
+ double dy_unaccel;
uint32_t button;
uint32_t seat_button_count;
enum libinput_button_state state;
return event->y;
}
+LIBINPUT_EXPORT double
+libinput_event_pointer_get_dx_unaccelerated(
+ struct libinput_event_pointer *event)
+{
+ return event->dx_unaccel;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_pointer_get_dy_unaccelerated(
+ struct libinput_event_pointer *event)
+{
+ return event->dy_unaccel;
+}
+
LIBINPUT_EXPORT double
libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event)
{
pointer_notify_motion(struct libinput_device *device,
uint64_t time,
double dx,
- double dy)
+ double dy,
+ double dx_unaccel,
+ double dy_unaccel)
{
struct libinput_event_pointer *motion_event;
.time = time,
.x = dx,
.y = dy,
+ .dx_unaccel = dx_unaccel,
+ .dy_unaccel = dy_unaccel,
};
post_device_event(device, time,
double
libinput_event_pointer_get_dy(struct libinput_event_pointer *event);
+/**
+ * @ingroup event_pointer
+ *
+ * Return the relative delta of the unaccelerated motion vector of the
+ * 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.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_POINTER_MOTION.
+ *
+ * @return the unaccelerated relative x movement since the last event
+ */
+double
+libinput_event_pointer_get_dx_unaccelerated(
+ struct libinput_event_pointer *event);
+
+/**
+ * @ingroup event_pointer
+ *
+ * Return the relative delta of the unaccelerated motion vector of the
+ * 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.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_POINTER_MOTION.
+ *
+ * @return the unaccelerated relative y movement since the last event
+ */
+double
+libinput_event_pointer_get_dy_unaccelerated(
+ struct libinput_event_pointer *event);
+
/**
* @ingroup event_pointer
*
#include <libinput.h>
#include <math.h>
#include <unistd.h>
+#include <values.h>
#include "libinput-util.h"
#include "litest.h"
+static struct libinput_event_pointer *
+get_accelerated_motion_event(struct libinput *li)
+{
+ struct libinput_event *event;
+ struct libinput_event_pointer *ptrev;
+
+ while (1) {
+ event = libinput_get_event(li);
+ ck_assert_notnull(event);
+ ck_assert_int_eq(libinput_event_get_type(event),
+ LIBINPUT_EVENT_POINTER_MOTION);
+
+ ptrev = libinput_event_get_pointer_event(event);
+ ck_assert_notnull(ptrev);
+
+ if (fabs(libinput_event_pointer_get_dx(ptrev)) < DBL_MIN &&
+ fabs(libinput_event_pointer_get_dy(ptrev)) < DBL_MIN) {
+ libinput_event_destroy(event);
+ continue;
+ }
+
+ return ptrev;
+ }
+
+ ck_abort_msg("No accelerated pointer motion event found");
+ return NULL;
+}
+
static void
test_relative_event(struct litest_device *dev, int dx, int dy)
{
struct libinput *li = dev->libinput;
- struct libinput_event *event;
struct libinput_event_pointer *ptrev;
double ev_dx, ev_dy;
double expected_dir;
libinput_dispatch(li);
- event = libinput_get_event(li);
- ck_assert(event != NULL);
- ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_POINTER_MOTION);
-
- ptrev = libinput_event_get_pointer_event(event);
- ck_assert(ptrev != NULL);
+ ptrev = get_accelerated_motion_event(li);
expected_length = sqrt(4 * dx*dx + 4 * dy*dy);
expected_dir = atan2(dx, dy);
* indifference). */
ck_assert(fabs(expected_dir - actual_dir) < M_PI_2);
- libinput_event_destroy(event);
+ libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev));
litest_drain_events(dev->libinput);
}
}
END_TEST
+static void
+test_unaccel_event(struct litest_device *dev, int dx, int dy)
+{
+ struct libinput *li = dev->libinput;
+ struct libinput_event *event;
+ struct libinput_event_pointer *ptrev;
+ double ev_dx, ev_dy;
+
+ litest_event(dev, EV_REL, REL_X, dx);
+ litest_event(dev, EV_REL, REL_Y, dy);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ ck_assert_notnull(event);
+ ck_assert_int_eq(libinput_event_get_type(event),
+ LIBINPUT_EVENT_POINTER_MOTION);
+
+ ptrev = libinput_event_get_pointer_event(event);
+ ck_assert(ptrev != NULL);
+
+ ev_dx = libinput_event_pointer_get_dx_unaccelerated(ptrev);
+ ev_dy = libinput_event_pointer_get_dy_unaccelerated(ptrev);
+
+ ck_assert_int_eq(dx, ev_dx);
+ ck_assert_int_eq(dy, ev_dy);
+
+ libinput_event_destroy(event);
+
+ litest_drain_events(dev->libinput);
+}
+
+START_TEST(pointer_motion_unaccel)
+{
+ struct litest_device *dev = litest_current_device();
+
+ litest_drain_events(dev->libinput);
+
+ test_unaccel_event(dev, 10, 0);
+ test_unaccel_event(dev, 10, 10);
+ test_unaccel_event(dev, 10, -10);
+ test_unaccel_event(dev, 0, 10);
+
+ test_unaccel_event(dev, -10, 0);
+ test_unaccel_event(dev, -10, 10);
+ test_unaccel_event(dev, -10, -10);
+ test_unaccel_event(dev, 0, -10);
+}
+END_TEST
+
static void
test_button_event(struct litest_device *dev, unsigned int button, int state)
{
litest_add("pointer:motion", pointer_motion_relative, LITEST_RELATIVE, LITEST_ANY);
litest_add("pointer:motion", pointer_motion_absolute, LITEST_ABSOLUTE, LITEST_ANY);
+ litest_add("pointer:motion", pointer_motion_unaccel, LITEST_RELATIVE, LITEST_ANY);
litest_add("pointer:button", pointer_button, LITEST_BUTTON, LITEST_CLICKPAD);
litest_add_no_device("pointer:button_auto_release", pointer_button_auto_release);
litest_add("pointer:scroll", pointer_scroll_wheel, LITEST_WHEEL, LITEST_ANY);
x = libinput_event_pointer_get_dx(p);
y = libinput_event_pointer_get_dy(p);
- ck_assert(x > 0);
- ck_assert(y == 0);
+ /* Ignore events only containing an unaccelerated motion
+ * vector. */
+ if (x != 0 || y != 0) {
+ ck_assert(x > 0);
+ ck_assert(y == 0);
+ }
libinput_event_destroy(event);
libinput_dispatch(li);