mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-03-21 19:10:42 +01:00
Introduce unaccelerated motion event vectors
For certain applications (such as FPS games) it is necessary to use unaccelerated motion events (the motion vector that is passed to the acceleration filter) to get a more natural feeling. Supply this information by passing both accelerated and unaccelerated motion vectors to the existing motion event. Note that the unaccelerated motion event is not equivalent to 'raw' events as read from devices. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
1fa07bbafb
commit
93eca929ae
9 changed files with 188 additions and 24 deletions
|
|
@ -338,7 +338,7 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
|
|||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -58,13 +58,20 @@ tp_motion_history_offset(struct tp_touch *t, int offset)
|
|||
|
||||
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);
|
||||
|
||||
|
|
@ -426,7 +433,7 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t 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);
|
||||
}
|
||||
|
|
@ -586,6 +593,7 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
|
|||
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) {
|
||||
|
|
@ -617,10 +625,12 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
|
|||
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
|
||||
|
|
|
|||
|
|
@ -276,7 +276,9 @@ tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t);
|
|||
|
||||
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);
|
||||
|
|
|
|||
19
src/evdev.c
19
src/evdev.c
|
|
@ -196,6 +196,7 @@ evdev_flush_pending_event(struct evdev_device *device, 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;
|
||||
|
|
@ -209,8 +210,10 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
|
|||
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;
|
||||
|
||||
|
|
@ -219,17 +222,23 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
|
|||
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))
|
||||
|
|
|
|||
|
|
@ -259,7 +259,9 @@ void
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ struct libinput_event_pointer {
|
|||
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;
|
||||
|
|
@ -303,6 +305,20 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event)
|
|||
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)
|
||||
{
|
||||
|
|
@ -891,7 +907,9 @@ void
|
|||
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;
|
||||
|
||||
|
|
@ -903,6 +921,8 @@ pointer_notify_motion(struct libinput_device *device,
|
|||
.time = time,
|
||||
.x = dx,
|
||||
.y = dy,
|
||||
.dx_unaccel = dx_unaccel,
|
||||
.dy_unaccel = dy_unaccel,
|
||||
};
|
||||
|
||||
post_device_event(device, time,
|
||||
|
|
|
|||
|
|
@ -555,6 +555,48 @@ libinput_event_pointer_get_dx(struct libinput_event_pointer *event);
|
|||
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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -29,15 +29,43 @@
|
|||
#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;
|
||||
|
|
@ -56,12 +84,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy)
|
|||
|
||||
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);
|
||||
|
|
@ -78,7 +101,7 @@ test_relative_event(struct litest_device *dev, int dx, int 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);
|
||||
}
|
||||
|
|
@ -139,6 +162,57 @@ START_TEST(pointer_motion_absolute)
|
|||
}
|
||||
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)
|
||||
{
|
||||
|
|
@ -652,6 +726,7 @@ int main (int argc, char **argv) {
|
|||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -1173,8 +1173,12 @@ START_TEST(clickpad_softbutton_left_2nd_fg_move)
|
|||
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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue