From 1318ffadb527bdc9e924d4a67becb6a8aa5b1644 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 11 Nov 2015 13:39:43 +1000 Subject: [PATCH] tablet: split out tip handling into a separate event The tablet tip works like a button in the kernel but is otherwise not really a button. Split it into an explicit tip up/down event instead. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/libinput-private.h | 7 +++++++ src/libinput.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/libinput.h | 41 +++++++++++++++++++++++++++++++++++++++++ src/libinput.sym | 1 + test/litest.c | 8 ++++++++ test/tablet.c | 4 +++- tools/event-debug.c | 18 ++++++++++++++++++ tools/event-gui.c | 34 ++++++++++++++++++++++++++++++++++ 8 files changed, 154 insertions(+), 1 deletion(-) diff --git a/src/libinput-private.h b/src/libinput-private.h index 3d612221..0e7ddff3 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -476,6 +476,13 @@ tablet_notify_proximity(struct libinput_device *device, unsigned char *changed_axes, double *axes); +void +tablet_notify_tip(struct libinput_device *device, + uint64_t time, + struct libinput_tool *tool, + enum libinput_tool_tip_state tip_state, + double *axes); + void tablet_notify_button(struct libinput_device *device, uint64_t time, diff --git a/src/libinput.c b/src/libinput.c index 79e4863c..c47f9fcb 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -137,6 +137,7 @@ struct libinput_event_tablet { unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)]; struct libinput_tool *tool; enum libinput_tool_proximity_state proximity_state; + enum libinput_tool_tip_state tip_state; }; static void @@ -313,6 +314,7 @@ libinput_event_get_tablet_event(struct libinput_event *event) NULL, LIBINPUT_EVENT_TABLET_AXIS, LIBINPUT_EVENT_TABLET_PROXIMITY, + LIBINPUT_EVENT_TABLET_TIP, LIBINPUT_EVENT_TABLET_BUTTON); return (struct libinput_event_tablet *) event; @@ -918,6 +920,7 @@ libinput_event_tablet_axis_has_changed(struct libinput_event_tablet *event, event->base.type, 0, LIBINPUT_EVENT_TABLET_AXIS, + LIBINPUT_EVENT_TABLET_TIP, LIBINPUT_EVENT_TABLET_PROXIMITY); return (NCHARS(axis) <= sizeof(event->changed_axes)) ? @@ -935,6 +938,7 @@ libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event, event->base.type, 0, LIBINPUT_EVENT_TABLET_AXIS, + LIBINPUT_EVENT_TABLET_TIP, LIBINPUT_EVENT_TABLET_PROXIMITY); switch(axis) { @@ -968,6 +972,7 @@ libinput_event_tablet_get_axis_delta(struct libinput_event_tablet *event, event->base.type, 0, LIBINPUT_EVENT_TABLET_AXIS, + LIBINPUT_EVENT_TABLET_TIP, LIBINPUT_EVENT_TABLET_PROXIMITY); switch(axis) { @@ -999,6 +1004,7 @@ libinput_event_tablet_get_axis_delta_discrete( event->base.type, 0, LIBINPUT_EVENT_TABLET_AXIS, + LIBINPUT_EVENT_TABLET_TIP, LIBINPUT_EVENT_TABLET_PROXIMITY); switch(axis) { @@ -1028,6 +1034,7 @@ libinput_event_tablet_get_x_transformed(struct libinput_event_tablet *event, event->base.type, 0, LIBINPUT_EVENT_TABLET_AXIS, + LIBINPUT_EVENT_TABLET_TIP, LIBINPUT_EVENT_TABLET_PROXIMITY); return evdev_device_transform_x(device, @@ -1046,6 +1053,7 @@ libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event, event->base.type, 0, LIBINPUT_EVENT_TABLET_AXIS, + LIBINPUT_EVENT_TABLET_TIP, LIBINPUT_EVENT_TABLET_PROXIMITY); return evdev_device_transform_y(device, @@ -1065,6 +1073,12 @@ libinput_event_tablet_get_proximity_state(struct libinput_event_tablet *event) return event->proximity_state; } +LIBINPUT_EXPORT enum libinput_tool_tip_state +libinput_event_tablet_get_tip_state(struct libinput_event_tablet *event) +{ + return event->tip_state; +} + LIBINPUT_EXPORT uint32_t libinput_event_tablet_get_time(struct libinput_event_tablet *event) { @@ -1969,6 +1983,34 @@ tablet_notify_proximity(struct libinput_device *device, &proximity_event->base); } +void +tablet_notify_tip(struct libinput_device *device, + uint64_t time, + struct libinput_tool *tool, + enum libinput_tool_tip_state tip_state, + double *axes) +{ + struct libinput_event_tablet *tip_event; + + tip_event = zalloc(sizeof *tip_event); + if (!tip_event) + return; + + *tip_event = (struct libinput_event_tablet) { + .time = time, + .tool = tool, + .tip_state = tip_state, + }; + memcpy(tip_event->axes, + axes, + sizeof(tip_event->axes)); + + post_device_event(device, + time, + LIBINPUT_EVENT_TABLET_TIP, + &tip_event->base); +} + void tablet_notify_button(struct libinput_device *device, uint64_t time, diff --git a/src/libinput.h b/src/libinput.h index c5f9da7e..dc7e7d85 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -216,6 +216,20 @@ enum libinput_tool_proximity_state { LIBINPUT_TOOL_PROXIMITY_IN = 1, }; +/** + * @ingroup device + * + * The tip contact state for a tool on a device. The device must have + * the @ref LIBINPUT_DEVICE_CAP_TABLET capability. + * + * The tip contact state of a tool is a binary state signalling whether the tool is + * touching the surface of the tablet device. + */ +enum libinput_tool_tip_state { + LIBINPUT_TOOL_TIP_UP = 0, + LIBINPUT_TOOL_TIP_DOWN = 1, +}; + /** * @ingroup base * @@ -301,6 +315,19 @@ enum libinput_event_type { * proximity out event. */ LIBINPUT_EVENT_TABLET_PROXIMITY, + /** + * Signals that a tool has come in contact with the surface of a + * device with the @ref LIBINPUT_DEVICE_CAP_TABLET capability. + * + * On devices without distance proximity detection, the @ref + * LIBINPUT_EVENT_TABLET_TIP is sent immediately after @ref + * LIBINPUT_EVENT_TABLET_PROXIMITY for the tip down event, and + * immediately before for the tip up event. + * + * If a button and/or axis state change occurs at the same time as a + * tip state change, the order of events is device-dependent. + */ + LIBINPUT_EVENT_TABLET_TIP, LIBINPUT_EVENT_TABLET_BUTTON, LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800, @@ -1499,6 +1526,20 @@ libinput_event_tablet_get_tool(struct libinput_event_tablet *event); enum libinput_tool_proximity_state libinput_event_tablet_get_proximity_state(struct libinput_event_tablet *event); +/** + * @ingroup event_tablet + * + * Returns the new tip state of a tool from a tip event. + * Used to check whether or not a tool came in contact with the tablet + * surface or left contact with the tablet surface during an + * event of type @ref LIBINPUT_EVENT_TABLET_TIP. + * + * @param event The libinput tablet event + * @return The new tip state of the tool from the event. + */ +enum libinput_tool_tip_state +libinput_event_tablet_get_tip_state(struct libinput_event_tablet *event); + /** * @ingroup event_tablet * diff --git a/src/libinput.sym b/src/libinput.sym index 1c297c7f..33d5b33f 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -195,6 +195,7 @@ LIBINPUT_TABLET_SUPPORT { libinput_event_tablet_get_proximity_state; libinput_event_tablet_get_seat_button_count; libinput_event_tablet_get_time; + libinput_event_tablet_get_tip_state; libinput_event_tablet_get_tool; libinput_event_tablet_get_x_transformed; libinput_event_tablet_get_y_transformed; diff --git a/test/litest.c b/test/litest.c index ce2a6a7b..4bbabb20 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1887,6 +1887,9 @@ litest_event_type_str(struct libinput_event *event) case LIBINPUT_EVENT_TABLET_PROXIMITY: str = "TABLET PROX"; break; + case LIBINPUT_EVENT_TABLET_TIP: + str = "TABLET TIP"; + break; case LIBINPUT_EVENT_TABLET_BUTTON: str = "TABLET BUTTON"; break; @@ -1949,6 +1952,11 @@ litest_print_event(struct libinput_event *event) fprintf(stderr, "proximity %d\n", libinput_event_tablet_get_proximity_state(t)); break; + case LIBINPUT_EVENT_TABLET_TIP: + t = libinput_event_get_tablet_event(event); + fprintf(stderr, "tip %d\n", + libinput_event_tablet_get_tip_state(t)); + break; case LIBINPUT_EVENT_TABLET_BUTTON: t = libinput_event_get_tablet_event(event); fprintf(stderr, "button %d state %d\n", diff --git a/test/tablet.c b/test/tablet.c index 5dcb9d30..444290c2 100644 --- a/test/tablet.c +++ b/test/tablet.c @@ -118,7 +118,7 @@ START_TEST(proximity_out_clear_buttons) /* Test that proximity out events send button releases for any currently * pressed stylus buttons */ - for (button = BTN_TOUCH; button <= BTN_STYLUS2; button++) { + for (button = BTN_TOUCH + 1; button <= BTN_STYLUS2; button++) { bool button_released = false; uint32_t event_button; enum libinput_button_state state; @@ -155,6 +155,8 @@ START_TEST(proximity_out_clear_buttons) libevdev_event_code_get_name(EV_KEY, button), event_button); } + + litest_assert_empty_queue(li); } END_TEST diff --git a/tools/event-debug.c b/tools/event-debug.c index 05fb1a7f..f0ae1dc8 100644 --- a/tools/event-debug.c +++ b/tools/event-debug.c @@ -115,6 +115,9 @@ print_event_header(struct libinput_event *ev) case LIBINPUT_EVENT_TABLET_PROXIMITY: type = "TABLET_PROXIMITY"; break; + case LIBINPUT_EVENT_TABLET_TIP: + type = "TABLET_TIP"; + break; case LIBINPUT_EVENT_TABLET_BUTTON: type = "TABLET_BUTTON"; break; @@ -278,6 +281,18 @@ print_pointer_button_event(struct libinput_event *ev) libinput_event_pointer_get_seat_button_count(p)); } +static void +print_tablet_tip_event(struct libinput_event *ev) +{ + struct libinput_event_tablet *p = libinput_event_get_tablet_event(ev); + enum libinput_tool_tip_state state; + + print_event_time(libinput_event_tablet_get_time(p)); + + state = libinput_event_tablet_get_tip_state(p); + printf("%s\n", state == LIBINPUT_TOOL_TIP_DOWN ? "down" : "up"); +} + static void print_tablet_button_event(struct libinput_event *ev) { @@ -667,6 +682,9 @@ handle_and_print_events(struct libinput *li) case LIBINPUT_EVENT_TABLET_PROXIMITY: print_proximity_event(ev); break; + case LIBINPUT_EVENT_TABLET_TIP: + print_tablet_tip_event(ev); + break; case LIBINPUT_EVENT_TABLET_BUTTON: print_tablet_button_event(ev); break; diff --git a/tools/event-gui.c b/tools/event-gui.c index c07213f9..a7d8dd93 100644 --- a/tools/event-gui.c +++ b/tools/event-gui.c @@ -88,6 +88,8 @@ struct window { struct { double x, y; double x_in, y_in; + double x_down, y_down; + double x_up, y_up; double pressure; double distance; double tilt_x, tilt_y; @@ -234,6 +236,20 @@ draw(GtkWidget *widget, cairo_t *cr, gpointer data) cairo_save(cr); } + if (w->tool.x_down && w->tool.y_down) { + cairo_rectangle(cr, w->tool.x_down - 10, w->tool.y_down - 10, 20, 20); + cairo_stroke(cr); + cairo_restore(cr); + cairo_save(cr); + } + + if (w->tool.x_up && w->tool.y_up) { + cairo_rectangle(cr, w->tool.x_up - 10, w->tool.y_up - 10, 20, 20); + cairo_stroke(cr); + cairo_restore(cr); + cairo_save(cr); + } + if (w->tool.pressure) cairo_set_source_rgb(cr, .8, .8, .2); @@ -584,6 +600,7 @@ static void handle_event_tablet(struct libinput_event *ev, struct window *w) { struct libinput_event_tablet *t = libinput_event_get_tablet_event(ev); + double x, y; switch (libinput_event_get_type(ev)) { case LIBINPUT_EVENT_TABLET_PROXIMITY: @@ -591,6 +608,10 @@ handle_event_tablet(struct libinput_event *ev, struct window *w) LIBINPUT_TOOL_PROXIMITY_OUT) { w->tool.x_in = 0; w->tool.y_in = 0; + w->tool.x_down = 0; + w->tool.y_down = 0; + w->tool.x_up = 0; + w->tool.y_up = 0; } else { w->tool.x_in = libinput_event_tablet_get_x_transformed(t, w->width); @@ -612,6 +633,18 @@ handle_event_tablet(struct libinput_event *ev, struct window *w) w->tool.tilt_y = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_TILT_Y); break; + case LIBINPUT_EVENT_TABLET_TIP: + x = libinput_event_tablet_get_x_transformed(t, w->width); + y = libinput_event_tablet_get_y_transformed(t, w->height); + if (libinput_event_tablet_get_tip_state(t) == + LIBINPUT_TOOL_TIP_DOWN) { + w->tool.x_down = x; + w->tool.y_down = y; + } else { + w->tool.x_up = x; + w->tool.y_up = y; + } + break; case LIBINPUT_EVENT_TABLET_BUTTON: break; default: @@ -676,6 +709,7 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data) break; case LIBINPUT_EVENT_TABLET_AXIS: case LIBINPUT_EVENT_TABLET_PROXIMITY: + case LIBINPUT_EVENT_TABLET_TIP: case LIBINPUT_EVENT_TABLET_BUTTON: handle_event_tablet(ev, w); break;