mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-04 01:10:25 +01:00
tablet: add axis smoothing
Taking the tablet events as-is produces the occasional wobble in what should be a straight line. Bug 99961 has a jpg attachment to illustrate that. Emulate the wacom driver behavior and average x/y across the last 4 values to smoothen out these dents. https://bugs.freedesktop.org/show_bug.cgi?id=99961 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Ping Cheng <pingc@wacom.com>
This commit is contained in:
parent
ae11eaa265
commit
411a3a4766
3 changed files with 110 additions and 19 deletions
|
|
@ -423,10 +423,10 @@ static inline struct normalized_coords
|
|||
tablet_tool_process_delta(struct tablet_dispatch *tablet,
|
||||
struct libinput_tablet_tool *tool,
|
||||
const struct evdev_device *device,
|
||||
struct tablet_axes *axes,
|
||||
uint64_t time)
|
||||
{
|
||||
const struct normalized_coords zero = { 0.0, 0.0 };
|
||||
const struct tablet_axes *last, *current;
|
||||
struct device_coords delta = { 0, 0 };
|
||||
struct device_float_coords accel;
|
||||
|
||||
|
|
@ -434,13 +434,12 @@ tablet_tool_process_delta(struct tablet_dispatch *tablet,
|
|||
TABLET_TOOL_ENTERING_PROXIMITY) &&
|
||||
(bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X) ||
|
||||
bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y))) {
|
||||
current = &tablet->axes;
|
||||
last = tablet_history_get(tablet, 0);
|
||||
|
||||
delta.x = current->point.x - last->point.x;
|
||||
delta.y = current->point.y - last->point.y;
|
||||
delta.x = axes->point.x - tablet->last_smooth_point.x;
|
||||
delta.y = axes->point.y - tablet->last_smooth_point.y;
|
||||
}
|
||||
|
||||
tablet->last_smooth_point = axes->point;
|
||||
|
||||
accel.x = 1.0 * delta.x;
|
||||
accel.y = 1.0 * delta.y;
|
||||
|
||||
|
|
@ -591,6 +590,31 @@ tablet_update_wheel(struct tablet_dispatch *tablet,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tablet_smoothen_axes(const struct tablet_dispatch *tablet,
|
||||
struct tablet_axes *axes)
|
||||
{
|
||||
size_t i;
|
||||
size_t count = tablet_history_size(tablet);
|
||||
struct tablet_axes smooth = { 0 };
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
const struct tablet_axes *a = tablet_history_get(tablet, i);
|
||||
|
||||
smooth.point.x += a->point.x;
|
||||
smooth.point.y += a->point.y;
|
||||
|
||||
smooth.tilt.x += a->tilt.x;
|
||||
smooth.tilt.y += a->tilt.y;
|
||||
}
|
||||
|
||||
axes->point.x = smooth.point.x/count;
|
||||
axes->point.y = smooth.point.y/count;
|
||||
|
||||
axes->tilt.x = smooth.tilt.x/count;
|
||||
axes->tilt.y = smooth.tilt.y/count;
|
||||
}
|
||||
|
||||
static bool
|
||||
tablet_check_notify_axes(struct tablet_dispatch *tablet,
|
||||
struct evdev_device *device,
|
||||
|
|
@ -626,18 +650,20 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
|
|||
axes.wheel_discrete = tablet->axes.wheel_discrete;
|
||||
axes.rotation = tablet->axes.rotation;
|
||||
|
||||
axes.delta = tablet_tool_process_delta(tablet, tool, device, time);
|
||||
|
||||
*axes_out = axes;
|
||||
|
||||
rc = true;
|
||||
|
||||
out:
|
||||
tablet_history_push(tablet, &tablet->axes);
|
||||
tablet_smoothen_axes(tablet, &axes);
|
||||
|
||||
/* The delta relies on the last *smooth* point, so we do it last */
|
||||
axes.delta = tablet_tool_process_delta(tablet, tool, device, &axes, time);
|
||||
|
||||
*axes_out = axes;
|
||||
|
||||
return rc;
|
||||
}
|
||||
/**/
|
||||
|
||||
static void
|
||||
tablet_update_button(struct tablet_dispatch *tablet,
|
||||
uint32_t evcode,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ struct tablet_dispatch {
|
|||
struct evdev_device *device;
|
||||
unsigned int status;
|
||||
unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)];
|
||||
struct tablet_axes axes;
|
||||
struct tablet_axes axes; /* for assembling the current state */
|
||||
struct device_coords last_smooth_point;
|
||||
struct {
|
||||
unsigned int index;
|
||||
unsigned int count;
|
||||
|
|
|
|||
|
|
@ -1013,6 +1013,13 @@ START_TEST(proximity_has_axes)
|
|||
litest_axis_set_value(axes, ABS_DISTANCE, 20);
|
||||
litest_axis_set_value(axes, ABS_TILT_X, 15);
|
||||
litest_axis_set_value(axes, ABS_TILT_Y, 25);
|
||||
|
||||
/* work around axis smoothing */
|
||||
litest_tablet_motion(dev, 20, 30, axes);
|
||||
litest_tablet_motion(dev, 20, 29, axes);
|
||||
litest_tablet_motion(dev, 20, 31, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_tablet_motion(dev, 20, 30, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
|
|
@ -1044,8 +1051,10 @@ START_TEST(proximity_has_axes)
|
|||
|
||||
x = libinput_event_tablet_tool_get_x(tablet_event);
|
||||
y = libinput_event_tablet_tool_get_y(tablet_event);
|
||||
litest_assert_double_eq(x, last_x);
|
||||
litest_assert_double_eq(y, last_y);
|
||||
litest_assert_double_ge(x, last_x - 1);
|
||||
litest_assert_double_le(x, last_x + 1);
|
||||
litest_assert_double_ge(y, last_y - 1);
|
||||
litest_assert_double_le(y, last_y + 1);
|
||||
|
||||
if (libinput_tablet_tool_has_distance(tool)) {
|
||||
ck_assert(!libinput_event_tablet_tool_distance_has_changed(
|
||||
|
|
@ -1428,6 +1437,16 @@ START_TEST(left_handed)
|
|||
|
||||
libinput_event_destroy(event);
|
||||
|
||||
/* work around smoothing */
|
||||
litest_axis_set_value(axes, ABS_DISTANCE, 9);
|
||||
litest_tablet_motion(dev, 100, 0, axes);
|
||||
litest_axis_set_value(axes, ABS_DISTANCE, 7);
|
||||
litest_tablet_motion(dev, 100, 0, axes);
|
||||
litest_axis_set_value(axes, ABS_DISTANCE, 10);
|
||||
litest_tablet_motion(dev, 100, 0, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_axis_set_value(axes, ABS_DISTANCE, 5);
|
||||
litest_tablet_motion(dev, 100, 0, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
|
|
@ -1468,6 +1487,16 @@ START_TEST(left_handed)
|
|||
|
||||
libinput_event_destroy(event);
|
||||
|
||||
/* work around smoothing */
|
||||
litest_axis_set_value(axes, ABS_DISTANCE, 9);
|
||||
litest_tablet_motion(dev, 100, 0, axes);
|
||||
litest_axis_set_value(axes, ABS_DISTANCE, 7);
|
||||
litest_tablet_motion(dev, 100, 0, axes);
|
||||
litest_axis_set_value(axes, ABS_DISTANCE, 10);
|
||||
litest_tablet_motion(dev, 100, 0, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_axis_set_value(axes, ABS_DISTANCE, 5);
|
||||
litest_tablet_motion(dev, 100, 0, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
|
|
@ -1768,6 +1797,7 @@ START_TEST(motion_outside_bounds)
|
|||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *tablet_event;
|
||||
double val;
|
||||
int i;
|
||||
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_DISTANCE, 10 },
|
||||
|
|
@ -1778,6 +1808,15 @@ START_TEST(motion_outside_bounds)
|
|||
litest_tablet_proximity_in(dev, 50, 50, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* Work around smoothing */
|
||||
for (i = 5; i > 0; i--) {
|
||||
litest_event(dev, EV_ABS, ABS_X, 0 + 5 * i);
|
||||
litest_event(dev, EV_ABS, ABS_Y, 1000);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
litest_drain_events(li);
|
||||
|
||||
/* On the 24HD x/y of 0 is outside the limit */
|
||||
litest_event(dev, EV_ABS, ABS_X, 0);
|
||||
litest_event(dev, EV_ABS, ABS_Y, 1000);
|
||||
|
|
@ -1797,6 +1836,15 @@ START_TEST(motion_outside_bounds)
|
|||
|
||||
libinput_event_destroy(event);
|
||||
|
||||
/* Work around smoothing */
|
||||
for (i = 5; i > 0; i--) {
|
||||
litest_event(dev, EV_ABS, ABS_X, 1000);
|
||||
litest_event(dev, EV_ABS, ABS_Y, 0 + 5 * i);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
litest_drain_events(li);
|
||||
|
||||
/* On the 24HD x/y of 0 is outside the limit */
|
||||
litest_event(dev, EV_ABS, ABS_X, 1000);
|
||||
litest_event(dev, EV_ABS, ABS_Y, 0);
|
||||
|
|
@ -3341,12 +3389,18 @@ START_TEST(tablet_pressure_min_max)
|
|||
litest_tablet_motion(dev, 5, 100, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* need to fill the motion history */
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, 100);
|
||||
litest_tablet_motion(dev, 5, 100, axes);
|
||||
litest_tablet_motion(dev, 6, 100, axes);
|
||||
litest_tablet_motion(dev, 7, 100, axes);
|
||||
litest_tablet_motion(dev, 8, 100, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_tablet_motion(dev, 5, 100, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
ck_assert(libinput_event_tablet_tool_pressure_has_changed(tev));
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_ge(p, 1.0);
|
||||
libinput_event_destroy(event);
|
||||
|
|
@ -3630,7 +3684,12 @@ START_TEST(tilt_x)
|
|||
|
||||
for (tilt = 0; tilt <= 100; tilt += 5) {
|
||||
litest_axis_set_value(axes, ABS_TILT_X, tilt);
|
||||
/* work around smoothing */
|
||||
litest_tablet_motion(dev, 10, 10, axes);
|
||||
litest_tablet_motion(dev, 10, 11, axes);
|
||||
litest_tablet_motion(dev, 10, 10, axes);
|
||||
litest_drain_events(li);
|
||||
litest_tablet_motion(dev, 10, 11, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event,
|
||||
|
|
@ -3699,6 +3758,11 @@ START_TEST(tilt_y)
|
|||
|
||||
for (tilt = 0; tilt <= 100; tilt += 5) {
|
||||
litest_axis_set_value(axes, ABS_TILT_Y, tilt);
|
||||
/* work around smoothing */
|
||||
litest_tablet_motion(dev, 10, 11, axes);
|
||||
litest_tablet_motion(dev, 10, 10, axes);
|
||||
litest_tablet_motion(dev, 10, 11, axes);
|
||||
litest_drain_events(li);
|
||||
litest_tablet_motion(dev, 10, 10, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
|
|
@ -3815,7 +3879,7 @@ START_TEST(relative_delta)
|
|||
ck_assert(dy == 0.0);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_tablet_motion(dev, 10, 10, axes);
|
||||
litest_tablet_motion(dev, 5, 10, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event,
|
||||
|
|
@ -3837,7 +3901,7 @@ START_TEST(relative_delta)
|
|||
ck_assert(dy > 0.0);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_tablet_motion(dev, 10, 10, axes);
|
||||
litest_tablet_motion(dev, 10, 5, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event,
|
||||
|
|
@ -3888,7 +3952,7 @@ START_TEST(relative_calibration)
|
|||
ck_assert(dy == 0.0);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_tablet_motion(dev, 10, 10, axes);
|
||||
litest_tablet_motion(dev, 5, 10, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event,
|
||||
|
|
@ -3910,7 +3974,7 @@ START_TEST(relative_calibration)
|
|||
ck_assert(dy < 0.0);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_tablet_motion(dev, 10, 10, axes);
|
||||
litest_tablet_motion(dev, 10, 5, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue