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 <[email protected]>
---
 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 3d61222..0e7ddff 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -477,6 +477,13 @@ tablet_notify_proximity(struct libinput_device *device,
                        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,
                     struct libinput_tool *tool,
diff --git a/src/libinput.c b/src/libinput.c
index 79e4863..c47f9fc 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)
 {
@@ -1970,6 +1984,34 @@ tablet_notify_proximity(struct libinput_device *device,
 }
 
 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,
                     struct libinput_tool *tool,
diff --git a/src/libinput.h b/src/libinput.h
index c5f9da7..dc7e7d8 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -217,6 +217,20 @@ enum libinput_tool_proximity_state {
 };
 
 /**
+ * @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
  *
  * Event type for events returned by libinput_get_event().
@@ -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,
@@ -1502,6 +1529,20 @@ 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
+ *
  * Return the button that triggered this event.
  * For tablet events that are not of type @ref LIBINPUT_EVENT_TABLET_BUTTON, 
this
  * function returns 0.
diff --git a/src/libinput.sym b/src/libinput.sym
index 1c297c7..33d5b33 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 ce2a6a7..4bbabb2 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 5dcb9d3..444290c 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 05fb1a7..f0ae1dc 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;
@@ -279,6 +282,18 @@ print_pointer_button_event(struct libinput_event *ev)
 }
 
 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)
 {
        struct libinput_event_tablet *p = libinput_event_get_tablet_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 c07213f..a7d8dd9 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;
-- 
2.4.3

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to