From 57bba7f8a516b98b0eb87bda2759f89521768a37 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 20 Feb 2015 12:03:52 +1000 Subject: [PATCH] tablet: add libinput_tablet_get_axis_delta() Signed-off-by: Peter Hutterer Reviewed-by: Stephen Chandler Paul --- src/evdev-tablet.c | 56 ++++++++++++++++++++++++++++--- src/libinput-private.h | 3 +- src/libinput.c | 38 ++++++++++++++++++++- src/libinput.h | 27 +++++++++++++-- src/libinput.sym | 1 + test/tablet.c | 75 +++++++++++++++++++++++++++++++++++++++--- tools/event-debug.c | 54 +++++++++++++++++++++--------- 7 files changed, 227 insertions(+), 27 deletions(-) diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index 8de6fc43..f5cd63fe 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -264,6 +264,48 @@ normalize_wheel(struct tablet_dispatch *tablet, return value * device->scroll.wheel_click_angle; } +static inline double +guess_wheel_delta(double current, double old) +{ + double d1, d2, d3; + + d1 = current - old; + d2 = (current + 360.0) - old; + d3 = current - (old + 360.0); + + if (fabs(d2) < fabs(d1)) + d1 = d2; + + if (fabs(d3) < fabs(d1)) + d1 = d3; + + return d1; +} + +static inline double +get_delta(enum libinput_tablet_axis axis, double current, double old) +{ + double delta = 0; + + switch (axis) { + case LIBINPUT_TABLET_AXIS_X: + case LIBINPUT_TABLET_AXIS_Y: + case LIBINPUT_TABLET_AXIS_DISTANCE: + case LIBINPUT_TABLET_AXIS_PRESSURE: + case LIBINPUT_TABLET_AXIS_SLIDER: + case LIBINPUT_TABLET_AXIS_TILT_X: + case LIBINPUT_TABLET_AXIS_TILT_Y: + delta = current - old; + break; + case LIBINPUT_TABLET_AXIS_ROTATION_Z: + delta = guess_wheel_delta(current, old); + break; + default: + abort(); + } + return delta; +} + static void tablet_check_notify_axes(struct tablet_dispatch *tablet, struct evdev_device *device, @@ -274,6 +316,8 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet, bool axis_update_needed = false; int a; double axes[LIBINPUT_TABLET_AXIS_MAX + 1] = {0}; + double deltas[LIBINPUT_TABLET_AXIS_MAX + 1] = {0}; + double oldval; for (a = LIBINPUT_TABLET_AXIS_X; a <= LIBINPUT_TABLET_AXIS_MAX; a++) { const struct input_absinfo *absinfo; @@ -284,6 +328,7 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet, } axis_update_needed = true; + oldval = tablet->axes[a]; /* ROTATION_Z is higher than TILT_X/Y so we know that the tilt axes are already normalized and set */ @@ -294,11 +339,12 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet, axes[LIBINPUT_TABLET_AXIS_TILT_X] = 0; axes[LIBINPUT_TABLET_AXIS_TILT_Y] = 0; axes[a] = tablet->axes[a]; + deltas[a] = get_delta(a, tablet->axes[a], oldval); continue; } else if (a == LIBINPUT_TABLET_AXIS_REL_WHEEL) { - tablet->axes[a] = normalize_wheel(tablet, - tablet->deltas[a]); - axes[a] = tablet->axes[a]; + deltas[a] = normalize_wheel(tablet, + tablet->deltas[a]); + axes[a] = 0; continue; } @@ -333,6 +379,7 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet, } axes[a] = tablet->axes[a]; + deltas[a] = get_delta(a, tablet->axes[a], oldval); } /* We need to make sure that we check that the tool is not out of @@ -355,7 +402,8 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet, time, tool, tablet->changed_axes, - axes); + axes, + deltas); } memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes)); diff --git a/src/libinput-private.h b/src/libinput-private.h index 071204ef..3a4e4a5a 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -349,7 +349,8 @@ tablet_notify_axis(struct libinput_device *device, uint32_t time, struct libinput_tool *tool, unsigned char *changed_axes, - double *axes); + double *axes, + double *deltas); void tablet_notify_proximity(struct libinput_device *device, diff --git a/src/libinput.c b/src/libinput.c index 2640321e..71271827 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -86,6 +86,7 @@ struct libinput_event_tablet { uint32_t seat_button_count; uint32_t time; double axes[LIBINPUT_TABLET_AXIS_MAX + 1]; + double deltas[LIBINPUT_TABLET_AXIS_MAX + 1]; unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)]; struct libinput_tool *tool; enum libinput_tool_proximity_state proximity_state; @@ -593,6 +594,37 @@ libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event, } } +LIBINPUT_EXPORT double +libinput_event_tablet_get_axis_delta(struct libinput_event_tablet *event, + enum libinput_tablet_axis axis) +{ + struct evdev_device *device = + (struct evdev_device *) event->base.device; + + if (event->base.type != LIBINPUT_EVENT_TABLET_AXIS && + event->base.type != LIBINPUT_EVENT_TABLET_PROXIMITY) + return 0; + + switch(axis) { + case LIBINPUT_TABLET_AXIS_X: + return evdev_convert_to_mm(device->abs.absinfo_x, + event->deltas[axis]); + case LIBINPUT_TABLET_AXIS_Y: + return evdev_convert_to_mm(device->abs.absinfo_y, + event->deltas[axis]); + case LIBINPUT_TABLET_AXIS_DISTANCE: + case LIBINPUT_TABLET_AXIS_PRESSURE: + case LIBINPUT_TABLET_AXIS_TILT_X: + case LIBINPUT_TABLET_AXIS_TILT_Y: + case LIBINPUT_TABLET_AXIS_ROTATION_Z: + case LIBINPUT_TABLET_AXIS_SLIDER: + case LIBINPUT_TABLET_AXIS_REL_WHEEL: + return event->deltas[axis]; + default: + return 0; + } +} + LIBINPUT_EXPORT double libinput_event_tablet_get_x_transformed(struct libinput_event_tablet *event, uint32_t width) @@ -1400,7 +1432,8 @@ tablet_notify_axis(struct libinput_device *device, uint32_t time, struct libinput_tool *tool, unsigned char *changed_axes, - double *axes) + double *axes, + double *deltas) { struct libinput_event_tablet *axis_event; @@ -1417,6 +1450,7 @@ tablet_notify_axis(struct libinput_device *device, changed_axes, sizeof(axis_event->changed_axes)); memcpy(axis_event->axes, axes, sizeof(axis_event->axes)); + memcpy(axis_event->deltas, deltas, sizeof(axis_event->deltas)); post_device_event(device, time, @@ -1450,6 +1484,8 @@ tablet_notify_proximity(struct libinput_device *device, changed_axes, sizeof(proximity_event->changed_axes)); + /* deltas are always 0 on prox-in/out */ + post_device_event(device, time, LIBINPUT_EVENT_TABLET_PROXIMITY, diff --git a/src/libinput.h b/src/libinput.h index a22f8bc7..60fdfb01 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1062,8 +1062,8 @@ libinput_event_tablet_axis_has_changed(struct libinput_event_tablet *event, * - @ref LIBINPUT_TABLET_AXIS_SLIDER - A slider on the tool, normalized * from 0 to 1. e.g. the wheel-like tool on the Wacom Airbrush. * - @ref LIBINPUT_TABLET_AXIS_REL_WHEEL - A relative wheel on the tool, - * similar or equivalent to a mouse wheel. The value is a delta from the - * device's previous position, in degrees. + * similar or equivalent to a mouse wheel. The value is always 0, use + * libinput_event_tablet_get_axis_delta() instead. * * @note This function may be called for a specific axis even if * libinput_event_tablet_axis_has_changed() returns 0 for that axis. @@ -1077,6 +1077,29 @@ double libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event, enum libinput_tablet_axis axis); +/** + * @ingroup event_tablet + * + * Return the delta for a given axis for a tablet. The interpretation of the + * value is axis-dependent: + * - @ref LIBINPUT_TABLET_AXIS_REL_WHEEL - A relative wheel on the tool, + * similar or equivalent to a mouse wheel. The value is a delta from the + * device's previous position, in degrees. + * For all other axes, see libinput_event_tablet_get_axis_value() for + * details. + * + * @note The delta is *not* the delta to the previous event, but the delta + * to the previous axis state, i.e. the delta to the last event that + * libinput_event_tablet_axis_has_changed() returned true for this axis. + * + * @param event The libinput tablet event + * @param axis The axis to retrieve the value of + * @return The delta to the previous axis value + */ +double +libinput_event_tablet_get_axis_delta(struct libinput_event_tablet *event, + enum libinput_tablet_axis axis); + /** * @ingroup event_tablet * diff --git a/src/libinput.sym b/src/libinput.sym index e6742266..cb94d60b 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -146,6 +146,7 @@ LIBINPUT_0.12.0 { LIBINPUT_TABLET_SUPPORT { libinput_event_get_tablet_event; libinput_event_tablet_axis_has_changed; + libinput_event_tablet_get_axis_delta; libinput_event_tablet_get_axis_value; libinput_event_tablet_get_button; libinput_event_tablet_get_button_state; diff --git a/test/tablet.c b/test/tablet.c index afc654eb..1eb91c69 100644 --- a/test/tablet.c +++ b/test/tablet.c @@ -381,6 +381,67 @@ START_TEST(motion) } END_TEST +START_TEST(motion_delta) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event_tablet *tablet_event; + struct libinput_event *event; + double x1, y1, x2, y2, dist1, dist2; + double delta; + struct axis_replacement axes[] = { + { ABS_DISTANCE, 10 }, + { -1, -1 } + }; + + litest_drain_events(li); + + litest_tablet_proximity_in(dev, 5, 100, axes); + libinput_dispatch(li); + + litest_wait_for_event_of_type(li, + LIBINPUT_EVENT_TABLET_PROXIMITY, + -1); + + event = libinput_get_event(li); + tablet_event = libinput_event_get_tablet_event(event); + x1 = libinput_event_tablet_get_axis_value(tablet_event, + LIBINPUT_TABLET_AXIS_X); + y1 = libinput_event_tablet_get_axis_value(tablet_event, + LIBINPUT_TABLET_AXIS_Y); + dist1 = libinput_event_tablet_get_axis_value(tablet_event, + LIBINPUT_TABLET_AXIS_DISTANCE); + libinput_event_destroy(event); + + axes[0].value = 40; + litest_tablet_motion(dev, 40, 100, axes); + + litest_wait_for_event_of_type(li, + LIBINPUT_EVENT_TABLET_AXIS, + -1); + event = libinput_get_event(li); + tablet_event = libinput_event_get_tablet_event(event); + x2 = libinput_event_tablet_get_axis_value(tablet_event, + LIBINPUT_TABLET_AXIS_X); + y2 = libinput_event_tablet_get_axis_value(tablet_event, + LIBINPUT_TABLET_AXIS_Y); + dist2 = libinput_event_tablet_get_axis_value(tablet_event, + LIBINPUT_TABLET_AXIS_DISTANCE); + + delta = libinput_event_tablet_get_axis_delta(tablet_event, + LIBINPUT_TABLET_AXIS_X); + litest_assert_double_eq(delta, x2 - x1); + delta = libinput_event_tablet_get_axis_delta(tablet_event, + LIBINPUT_TABLET_AXIS_Y); + litest_assert_double_eq(delta, y2 - y1); + delta = libinput_event_tablet_get_axis_delta(tablet_event, + LIBINPUT_TABLET_AXIS_DISTANCE); + litest_assert_double_eq(delta, dist2 - dist1); + + libinput_event_destroy(event); +} +END_TEST + START_TEST(left_handed) { #if HAVE_LIBWACOM @@ -1415,20 +1476,19 @@ START_TEST(artpen_rotation) abs = libevdev_get_abs_info(dev->evdev, ABS_Z); ck_assert_notnull(abs); + scale = (abs->maximum - abs->minimum + 1)/360.0; litest_event(dev, EV_KEY, BTN_TOOL_BRUSH, 1); litest_event(dev, EV_ABS, ABS_MISC, 0x804); /* Art Pen */ litest_event(dev, EV_MSC, MSC_SERIAL, 1000); litest_event(dev, EV_SYN, SYN_REPORT, 0); - /* start with non-zero */ - litest_event(dev, EV_ABS, ABS_Z, 10); + litest_event(dev, EV_ABS, ABS_Z, abs->minimum); litest_event(dev, EV_SYN, SYN_REPORT, 0); litest_drain_events(li); - scale = (abs->maximum - abs->minimum + 1)/360.0; - for (angle = 0; angle < 360; angle += 8) { + for (angle = 8; angle < 360; angle += 8) { int a = angle * scale + abs->minimum; litest_event(dev, EV_ABS, ABS_Z, a); @@ -1446,8 +1506,14 @@ START_TEST(artpen_rotation) /* artpen has a 90 deg offset cw */ ck_assert_int_eq(round(val), (angle + 90) % 360); + + val = libinput_event_tablet_get_axis_delta(tev, + LIBINPUT_TABLET_AXIS_ROTATION_Z); + ck_assert_int_eq(val, 8); + libinput_event_destroy(event); litest_assert_empty_queue(li); + } } END_TEST @@ -1467,6 +1533,7 @@ main(int argc, char **argv) litest_add("tablet:proximity", proximity_has_axes, LITEST_TABLET, LITEST_ANY); litest_add("tablet:proximity", bad_distance_events, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY); litest_add("tablet:motion", motion, LITEST_TABLET, LITEST_ANY); + litest_add("tablet:motion", motion_delta, LITEST_TABLET, LITEST_ANY); litest_add("tablet:motion", motion_event_state, LITEST_TABLET, LITEST_ANY); litest_add_for_device("tablet:left_handed", left_handed, LITEST_WACOM_INTUOS); litest_add_for_device("tablet:left_handed", no_left_handed, LITEST_WACOM_CINTIQ); diff --git a/tools/event-debug.c b/tools/event-debug.c index 09edac09..7b68d96b 100644 --- a/tools/event-debug.c +++ b/tools/event-debug.c @@ -291,15 +291,19 @@ static void print_tablet_axes(struct libinput_event_tablet *t) { struct libinput_tool *tool = libinput_event_tablet_get_tool(t); - double x, y; + double x, y, dx, dy; double dist, pressure; double rotation, slider, wheel; + double delta; x = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_X); y = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_Y); - printf("\t%.2f%s/%.2f%s", + dx = libinput_event_tablet_get_axis_delta(t, LIBINPUT_TABLET_AXIS_X); + dy = libinput_event_tablet_get_axis_delta(t, LIBINPUT_TABLET_AXIS_Y); + printf("\t%.2f%s/%.2f%s (%.2f/%.2f)", x, tablet_axis_changed_sym(t, LIBINPUT_TABLET_AXIS_X), - y, tablet_axis_changed_sym(t, LIBINPUT_TABLET_AXIS_Y)); + y, tablet_axis_changed_sym(t, LIBINPUT_TABLET_AXIS_Y), + dx, dy); if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_TILT_X) || libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_TILT_Y)) { @@ -307,11 +311,16 @@ print_tablet_axes(struct libinput_event_tablet *t) LIBINPUT_TABLET_AXIS_TILT_X); y = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_TILT_Y); - printf("\ttilt: %.2f%s/%.2f%s ", + dx = libinput_event_tablet_get_axis_delta(t, + LIBINPUT_TABLET_AXIS_TILT_X); + dy = libinput_event_tablet_get_axis_delta(t, + LIBINPUT_TABLET_AXIS_TILT_Y); + printf("\ttilt: %.2f%s/%.2f%s (%.2f/%.2f)", x, tablet_axis_changed_sym(t, LIBINPUT_TABLET_AXIS_TILT_X), y, tablet_axis_changed_sym(t, - LIBINPUT_TABLET_AXIS_TILT_Y)); + LIBINPUT_TABLET_AXIS_TILT_Y), + dx, dy); } if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_DISTANCE) || @@ -321,43 +330,58 @@ print_tablet_axes(struct libinput_event_tablet *t) pressure = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_PRESSURE); if (dist) { - printf("\tdistance: %.2f%s", + delta = libinput_event_tablet_get_axis_delta(t, + LIBINPUT_TABLET_AXIS_DISTANCE); + printf("\tdistance: %.2f%s (%.2f)", dist, tablet_axis_changed_sym(t, - LIBINPUT_TABLET_AXIS_DISTANCE)); + LIBINPUT_TABLET_AXIS_DISTANCE), + delta); } else { - printf("\tpressure: %.2f%s", + delta = libinput_event_tablet_get_axis_delta(t, + LIBINPUT_TABLET_AXIS_PRESSURE); + printf("\tpressure: %.2f%s (%.2f)", pressure, tablet_axis_changed_sym(t, - LIBINPUT_TABLET_AXIS_PRESSURE)); + LIBINPUT_TABLET_AXIS_PRESSURE), + delta); } } if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_ROTATION_Z)) { rotation = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_ROTATION_Z); - printf("\trotation: %.2f%s", + delta = libinput_event_tablet_get_axis_delta(t, + LIBINPUT_TABLET_AXIS_ROTATION_Z); + printf("\trotation: %.2f%s (%.2f)", rotation, tablet_axis_changed_sym(t, - LIBINPUT_TABLET_AXIS_ROTATION_Z)); + LIBINPUT_TABLET_AXIS_ROTATION_Z), + delta); } if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_SLIDER)) { slider = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_SLIDER); - printf("\tslider: %.2f%s", + delta = libinput_event_tablet_get_axis_delta(t, + LIBINPUT_TABLET_AXIS_SLIDER); + printf("\tslider: %.2f%s (%.2f)", slider, tablet_axis_changed_sym(t, - LIBINPUT_TABLET_AXIS_SLIDER)); + LIBINPUT_TABLET_AXIS_SLIDER), + delta); } if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_REL_WHEEL)) { wheel = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_REL_WHEEL); - printf("\twheel: %.2f%s", + delta = libinput_event_tablet_get_axis_delta(t, + LIBINPUT_TABLET_AXIS_REL_WHEEL); + printf("\twheel: %.2f%s (%.2f)", wheel, tablet_axis_changed_sym(t, - LIBINPUT_TABLET_AXIS_REL_WHEEL)); + LIBINPUT_TABLET_AXIS_REL_WHEEL), + delta); } }