On Sunday, December 13, 2015, Peter Hutterer <<a href="mailto:peter.hutterer@who-t.net">peter.hutterer@who-t.net</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">If a tool wears out, it may have a pre-loaded pressure offset. In that case,<br>
even when the tool is not physically in contact with the tablet surface it<br>
will send pressure events.<br>
<br>
Use automatic pressure offset detection, similar to what the X.Org wacom<br>
driver does. On proximity-in, check the pressure and if the distance is above<br>
50% of the range and the pressure is nonzero but below 20% of the range, use<br>
that value as pressure offset.<br>
<br>
Signed-off-by: Peter Hutterer <<a href="javascript:;" onclick="_e(event, 'cvml', 'peter.hutterer@who-t.net')">peter.hutterer@who-t.net</a>></blockquote><div><span style="color:rgb(34,34,34);font-size:14px"><br></span></div><div><span style="color:rgb(34,34,34);font-size:14px">There is no logical change in this version. So, it is still</span></div><div><span style="color:rgb(34,34,34);font-size:14px"><br></span></div><div><span style="color:rgb(34,34,34);font-size:14px">Reviewed-by: Ping Cheng <</span><a style="color:rgb(17,85,204);font-size:14px">pingc@wacom.com</a><span style="color:rgb(34,34,34);font-size:14px">></span><br></div><br style="color:rgb(34,34,34);font-size:14px"><span style="color:rgb(34,34,34);font-size:14px">Ping</span><br style="color:rgb(34,34,34);font-size:14px"><br style="color:rgb(34,34,34);font-size:14px"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> ---<br>
Changes to v2:<br>
- rather than using offset != INT_MIN everywhere, add a has_pressure_offset<br>
  boolean and check that. Makes the code much nicer<br>
<br>
 doc/tablet-support.dox                   |  29 +++<br>
 src/evdev-tablet.c                       |  86 ++++++++-<br>
 src/evdev-tablet.h                       |  21 +++<br>
 src/libinput-private.h                   |   3 +<br>
 test/litest-device-wacom-intuos-tablet.c |   1 +<br>
 test/tablet.c                            | 313 ++++++++++++++++++++++++++++++-<br>
 6 files changed, 449 insertions(+), 4 deletions(-)<br>
<br>
diff --git a/doc/tablet-support.dox b/doc/tablet-support.dox<br>
index 24d08d2..5468c6f 100644<br>
--- a/doc/tablet-support.dox<br>
+++ b/doc/tablet-support.dox<br>
@@ -92,4 +92,33 @@ if (value < min) {<br>
 }<br>
 @endcode<br>
<br>
+@section tablet-pressure-offset Pressure offset on worn-out tools<br>
+<br>
+When a tool is used for an extended period it can wear down physically. A<br>
+worn-down tool may never return a zero pressure value. Even when hovering<br>
+above the surface, the pressure value returned by the tool is nonzero,<br>
+creating a fake surface touch and making interaction with the tablet less<br>
+predictable.<br>
+<br>
+libinput automatically detects pressure offsets and rescales the remaining<br>
+pressure range into the available range, making pressure-offsets transparent<br>
+to the caller. A tool with a pressure offset will thus send a 0 pressure<br>
+value for the detected offset and nonzero pressure values for values higher<br>
+than that offset.<br>
+<br>
+Some limitations apply to avoid misdetection of pressure offsets,<br>
+specifically:<br>
+- pressure offset is only detected on proximity in, and if a device is<br>
+  capable of detection distances,<br>
+- pressure offset is only detected if the distance between the tool and the<br>
+  tablet is high enough,<br>
+- pressure offset is only used if it is 20% or less of the pressure range<br>
+  available to the tool. A pressure offset higher than 20% indicates either<br>
+  a misdetection or a tool that should be replaced, and<br>
+- if a pressure value less than the current pressure offset is seen, the<br>
+  offset resets to that value.<br>
+<br>
+Pressure offsets are not detected on @ref LIBINPUT_TABLET_TOOL_TYPE_MOUSE<br>
+and @ref LIBINPUT_TABLET_TOOL_TYPE_LENS tools.<br>
+<br>
 */<br>
diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c<br>
index cd208a8..2a45575 100644<br>
--- a/src/evdev-tablet.c<br>
+++ b/src/evdev-tablet.c<br>
@@ -21,9 +21,11 @@<br>
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.<br>
  */<br>
 #include "config.h"<br>
+#include "libinput-version.h"<br>
 #include "evdev-tablet.h"<br>
<br>
 #include <assert.h><br>
+#include <inttypes.h><br>
 #include <stdbool.h><br>
 #include <string.h><br>
<br>
@@ -202,7 +204,7 @@ tablet_update_tool(struct tablet_dispatch *tablet,<br>
 }<br>
<br>
 static inline double<br>
-normalize_pressure_dist_slider(const struct input_absinfo *absinfo)<br>
+normalize_dist_slider(const struct input_absinfo *absinfo)<br>
 {<br>
        double range = absinfo->maximum - absinfo->minimum;<br>
        double value = (absinfo->value - absinfo->minimum) / range;<br>
@@ -211,6 +213,18 @@ normalize_pressure_dist_slider(const struct input_absinfo *absinfo)<br>
 }<br>
<br>
 static inline double<br>
+normalize_pressure(const struct input_absinfo *absinfo,<br>
+                  struct libinput_tablet_tool *tool)<br>
+{<br>
+       double range = absinfo->maximum - absinfo->minimum;<br>
+       int offset = tool->has_pressure_offset ?<br>
+                       tool->pressure_offset : 0;<br>
+       double value = (absinfo->value - offset - absinfo->minimum) / range;<br>
+<br>
+       return value;<br>
+}<br>
+<br>
+static inline double<br>
 normalize_tilt(const struct input_absinfo *absinfo)<br>
 {<br>
        double range = absinfo->maximum - absinfo->minimum;<br>
@@ -405,10 +419,12 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,<br>
                        else<br>
                                tablet->axes[a] = absinfo->value;<br>
                        break;<br>
-               case LIBINPUT_TABLET_TOOL_AXIS_DISTANCE:<br>
                case LIBINPUT_TABLET_TOOL_AXIS_PRESSURE:<br>
+                       tablet->axes[a] = normalize_pressure(absinfo, tool);<br>
+                       break;<br>
+               case LIBINPUT_TABLET_TOOL_AXIS_DISTANCE:<br>
                case LIBINPUT_TABLET_TOOL_AXIS_SLIDER:<br>
-                       tablet->axes[a] = normalize_pressure_dist_slider(absinfo);<br>
+                       tablet->axes[a] = normalize_dist_slider(absinfo);<br>
                        break;<br>
                case LIBINPUT_TABLET_TOOL_AXIS_TILT_X:<br>
                case LIBINPUT_TABLET_TOOL_AXIS_TILT_Y:<br>
@@ -816,6 +832,8 @@ tablet_get_tool(struct tablet_dispatch *tablet,<br>
                        .refcount = 1,<br>
                };<br>
<br>
+               tool->pressure_offset = 0;<br>
+               tool->has_pressure_offset = false;<br>
                tool_set_bits(tablet, tool);<br>
<br>
                list_insert(tool_list, &tool->link);<br>
@@ -929,6 +947,67 @@ sanitize_tablet_axes(struct tablet_dispatch *tablet)<br>
                set_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);<br>
 }<br>
<br>
+static inline int<br>
+axis_range_percentage(const struct input_absinfo *a, int percent)<br>
+{<br>
+       return (a->maximum - a->minimum) * percent/100 + a->minimum;<br>
+}<br>
+<br>
+static void<br>
+detect_pressure_offset(struct tablet_dispatch *tablet,<br>
+                      struct evdev_device *device,<br>
+                      struct libinput_tablet_tool *tool)<br>
+{<br>
+       const struct input_absinfo *pressure, *distance;<br>
+       int offset;<br>
+<br>
+       if (!bit_is_set(tablet->changed_axes,<br>
+                       LIBINPUT_TABLET_TOOL_AXIS_PRESSURE))<br>
+               return;<br>
+<br>
+       pressure = libevdev_get_abs_info(device->evdev, ABS_PRESSURE);<br>
+       distance = libevdev_get_abs_info(device->evdev, ABS_DISTANCE);<br>
+<br>
+       if (!pressure || !distance)<br>
+               return;<br>
+<br>
+       offset = pressure->value - pressure->minimum;<br>
+<br>
+       if (tool->has_pressure_offset) {<br>
+               if (offset < tool->pressure_offset)<br>
+                       tool->pressure_offset = offset;<br>
+               return;<br>
+       }<br>
+<br>
+       /* we only set a pressure offset on proximity in */<br>
+       if (!tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY))<br>
+               return;<br>
+<br>
+       /* If we're closer than 50% of the distance axis, skip pressure<br>
+        * offset detection, too likely to be wrong */<br>
+       if (distance->value < axis_range_percentage(distance, 50))<br>
+               return;<br>
+<br>
+       if (offset > axis_range_percentage(pressure, 20)) {<br>
+               log_error(device->base.seat->libinput,<br>
+                        "Ignoring pressure offset greater than 20%% detected on tool %s (serial %#x). "<br>
+                        "See <a href="http://wayland.freedesktop.org/libinput/doc/%s/tablet-support.html\n" target="_blank">http://wayland.freedesktop.org/libinput/doc/%s/tablet-support.html\n</a>",<br>
+                        tablet_tool_type_to_string(tool->type),<br>
+                        tool->serial,<br>
+                        LIBINPUT_VERSION);<br>
+               return;<br>
+       }<br>
+<br>
+       log_info(device->base.seat->libinput,<br>
+                "Pressure offset detected on tool %s (serial %#x).  "<br>
+                "See <a href="http://wayland.freedesktop.org/libinput/doc/%s/tablet-support.html\n" target="_blank">http://wayland.freedesktop.org/libinput/doc/%s/tablet-support.html\n</a>",<br>
+                tablet_tool_type_to_string(tool->type),<br>
+                tool->serial,<br>
+                LIBINPUT_VERSION);<br>
+       tool->pressure_offset = offset;<br>
+       tool->has_pressure_offset = true;<br>
+}<br>
+<br>
 static void<br>
 tablet_flush(struct tablet_dispatch *tablet,<br>
             struct evdev_device *device,<br>
@@ -953,6 +1032,7 @@ tablet_flush(struct tablet_dispatch *tablet,<br>
                        tablet_set_status(tablet, TABLET_TOOL_LEAVING_CONTACT);<br>
        } else if (tablet_has_status(tablet, TABLET_AXES_UPDATED) ||<br>
                   tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY)) {<br>
+               detect_pressure_offset(tablet, device, tool);<br>
                sanitize_tablet_axes(tablet);<br>
                tablet_check_notify_axes(tablet, device, time, tool);<br>
<br>
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h<br>
index 162b536..4dcbccc 100644<br>
--- a/src/evdev-tablet.h<br>
+++ b/src/evdev-tablet.h<br>
@@ -178,4 +178,25 @@ tablet_tool_to_evcode(enum libinput_tablet_tool_type type)<br>
<br>
        return code;<br>
 }<br>
+<br>
+static inline const char *<br>
+tablet_tool_type_to_string(enum libinput_tablet_tool_type type)<br>
+{<br>
+       const char *str;<br>
+<br>
+       switch (type) {<br>
+       case LIBINPUT_TABLET_TOOL_TYPE_PEN:       str = "pen";          break;<br>
+       case LIBINPUT_TABLET_TOOL_TYPE_ERASER:    str = "eraser";       break;<br>
+       case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:     str = "brush";        break;<br>
+       case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:    str = "pencil";       break;<br>
+       case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:  str = "airbrush";     break;<br>
+       case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:     str = "mouse";        break;<br>
+       case LIBINPUT_TABLET_TOOL_TYPE_LENS:      str = "lens";         break;<br>
+       default:<br>
+               abort();<br>
+       }<br>
+<br>
+       return str;<br>
+}<br>
+<br>
 #endif<br>
diff --git a/src/libinput-private.h b/src/libinput-private.h<br>
index 38a14b8..f5b2648 100644<br>
--- a/src/libinput-private.h<br>
+++ b/src/libinput-private.h<br>
@@ -259,6 +259,9 @@ struct libinput_tablet_tool {<br>
        unsigned char buttons[NCHARS(KEY_MAX) + 1];<br>
        int refcount;<br>
        void *user_data;<br>
+<br>
+       int pressure_offset;<br>
+       bool has_pressure_offset;<br>
 };<br>
<br>
 struct libinput_event {<br>
diff --git a/test/litest-device-wacom-intuos-tablet.c b/test/litest-device-wacom-intuos-tablet.c<br>
index e0e1d44..ef0a1f1 100644<br>
--- a/test/litest-device-wacom-intuos-tablet.c<br>
+++ b/test/litest-device-wacom-intuos-tablet.c<br>
@@ -37,6 +37,7 @@ static struct input_event proximity_in[] = {<br>
        { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },<br>
        { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },<br>
        { .type = EV_ABS, .code = ABS_DISTANCE, .value = LITEST_AUTO_ASSIGN },<br>
+       { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },<br>
        { .type = EV_ABS, .code = ABS_TILT_X, .value = LITEST_AUTO_ASSIGN },<br>
        { .type = EV_ABS, .code = ABS_TILT_Y, .value = LITEST_AUTO_ASSIGN },<br>
        { .type = EV_ABS, .code = ABS_MISC, .value = 1050626 },<br>
diff --git a/test/tablet.c b/test/tablet.c<br>
index 18f08b2..9cfc42f 100644<br>
--- a/test/tablet.c<br>
+++ b/test/tablet.c<br>
@@ -2313,7 +2313,7 @@ START_TEST(tablet_pressure_distance_exclusive)<br>
        struct libinput_event_tablet_tool *tev;<br>
        struct axis_replacement axes[] = {<br>
                { ABS_DISTANCE, 10 },<br>
-               { ABS_PRESSURE, 20 },<br>
+               { ABS_PRESSURE, 20 }, /* see the litest device */<br>
                { -1, -1 },<br>
        };<br>
        double pressure, distance;<br>
@@ -2530,6 +2530,310 @@ START_TEST(tablet_calibration_set_matrix)<br>
 }<br>
 END_TEST<br>
<br>
+START_TEST(tablet_pressure_offset)<br>
+{<br>
+       struct litest_device *dev = litest_current_device();<br>
+       struct libinput *li = dev->libinput;<br>
+       struct libinput_event *event;<br>
+       struct libinput_event_tablet_tool *tev;<br>
+       struct axis_replacement axes[] = {<br>
+               { ABS_DISTANCE, 70 },<br>
+               { ABS_PRESSURE, 20 },<br>
+               { -1, -1 },<br>
+       };<br>
+       double pressure;<br>
+<br>
+       litest_tablet_proximity_in(dev, 5, 100, axes);<br>
+       litest_drain_events(li);<br>
+<br>
+       axes[0].value = 0;<br>
+       axes[1].value = 21;<br>
+       litest_push_event_frame(dev);<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       litest_event(dev, EV_KEY, BTN_TOUCH, 1);<br>
+       litest_pop_event_frame(dev);<br>
+       libinput_dispatch(li);<br>
+       litest_drain_events(li);<br>
+<br>
+       axes[1].value = 20;<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       libinput_dispatch(li);<br>
+<br>
+       event = libinput_get_event(li);<br>
+       tev = litest_is_tablet_event(event,<br>
+                                    LIBINPUT_EVENT_TABLET_TOOL_AXIS);<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+       ck_assert_double_eq(pressure, 0.0);<br>
+<br>
+       libinput_event_destroy(event);<br>
+       litest_drain_events(li);<br>
+<br>
+       axes[1].value = 21;<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+<br>
+       libinput_dispatch(li);<br>
+       event = libinput_get_event(li);<br>
+       tev = litest_is_tablet_event(event,<br>
+                                    LIBINPUT_EVENT_TABLET_TOOL_AXIS);<br>
+<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+<br>
+       /* can't use the double_eq here, the pressure value is too tiny */<br>
+       ck_assert(pressure > 0.0);<br>
+       ck_assert(pressure < 1.0);<br>
+       libinput_event_destroy(event);<br>
+}<br>
+END_TEST<br>
+<br>
+START_TEST(tablet_pressure_offset_decrease)<br>
+{<br>
+       struct litest_device *dev = litest_current_device();<br>
+       struct libinput *li = dev->libinput;<br>
+       struct libinput_event *event;<br>
+       struct libinput_event_tablet_tool *tev;<br>
+       struct axis_replacement axes[] = {<br>
+               { ABS_DISTANCE, 70 },<br>
+               { ABS_PRESSURE, 20 },<br>
+               { -1, -1 },<br>
+       };<br>
+       double pressure;<br>
+<br>
+       /* offset 20 on prox in */<br>
+       litest_tablet_proximity_in(dev, 5, 100, axes);<br>
+       litest_drain_events(li);<br>
+<br>
+       /* a reduced pressure value must reduce the offset */<br>
+       axes[0].value = 0;<br>
+       axes[1].value = 10;<br>
+       litest_push_event_frame(dev);<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       litest_event(dev, EV_KEY, BTN_TOUCH, 1);<br>
+       litest_pop_event_frame(dev);<br>
+       libinput_dispatch(li);<br>
+<br>
+       event = libinput_get_event(li);<br>
+       tev = litest_is_tablet_event(event,<br>
+                                    LIBINPUT_EVENT_TABLET_TOOL_AXIS);<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+       ck_assert_double_eq(pressure, 0.0);<br>
+<br>
+       libinput_event_destroy(event);<br>
+       litest_drain_events(li);<br>
+<br>
+       axes[1].value = 11;<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       libinput_dispatch(li);<br>
+<br>
+       event = libinput_get_event(li);<br>
+       tev = litest_is_tablet_event(event,<br>
+                                    LIBINPUT_EVENT_TABLET_TOOL_AXIS);<br>
+<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+<br>
+       /* can't use the double_eq here, the pressure value is too tiny */<br>
+       ck_assert(pressure > 0.0);<br>
+       ck_assert(pressure < 1.0);<br>
+       libinput_event_destroy(event);<br>
+}<br>
+END_TEST<br>
+<br>
+START_TEST(tablet_pressure_offset_increase)<br>
+{<br>
+       struct litest_device *dev = litest_current_device();<br>
+       struct libinput *li = dev->libinput;<br>
+       struct libinput_event *event;<br>
+       struct libinput_event_tablet_tool *tev;<br>
+       struct axis_replacement axes[] = {<br>
+               { ABS_DISTANCE, 70 },<br>
+               { ABS_PRESSURE, 20 },<br>
+               { -1, -1 },<br>
+       };<br>
+       double pressure;<br>
+<br>
+       /* offset 20 on first prox in */<br>
+       litest_tablet_proximity_in(dev, 5, 100, axes);<br>
+       litest_tablet_proximity_out(dev);<br>
+       litest_drain_events(li);<br>
+<br>
+       /* offset 30 on second prox in - must not change the offset */<br>
+       axes[1].value = 30;<br>
+       litest_tablet_proximity_in(dev, 5, 100, axes);<br>
+       litest_drain_events(li);<br>
+<br>
+       axes[0].value = 0;<br>
+       axes[1].value = 31;<br>
+       litest_push_event_frame(dev);<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       litest_event(dev, EV_KEY, BTN_TOUCH, 1);<br>
+       litest_pop_event_frame(dev);<br>
+       libinput_dispatch(li);<br>
+       litest_drain_events(li);<br>
+<br>
+       axes[1].value = 30;<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       libinput_dispatch(li);<br>
+<br>
+       event = libinput_get_event(li);<br>
+       tev = litest_is_tablet_event(event,<br>
+                                    LIBINPUT_EVENT_TABLET_TOOL_AXIS);<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+       /* can't use the double_eq here, the pressure value is too tiny */<br>
+       ck_assert(pressure > 0.0);<br>
+       ck_assert(pressure < 1.0);<br>
+       libinput_event_destroy(event);<br>
+<br>
+       litest_drain_events(li);<br>
+<br>
+       axes[1].value = 20;<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       libinput_dispatch(li);<br>
+<br>
+       event = libinput_get_event(li);<br>
+       tev = litest_is_tablet_event(event,<br>
+                                    LIBINPUT_EVENT_TABLET_TOOL_AXIS);<br>
+<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+<br>
+       ck_assert_double_eq(pressure, 0.0);<br>
+       libinput_event_destroy(event);<br>
+}<br>
+END_TEST<br>
+<br>
+START_TEST(tablet_pressure_offset_exceed_threshold)<br>
+{<br>
+       struct litest_device *dev = litest_current_device();<br>
+       struct libinput *li = dev->libinput;<br>
+       struct libinput_event *event;<br>
+       struct libinput_event_tablet_tool *tev;<br>
+       struct axis_replacement axes[] = {<br>
+               { ABS_DISTANCE, 70 },<br>
+               { ABS_PRESSURE, 30 },<br>
+               { -1, -1 },<br>
+       };<br>
+       double pressure;<br>
+<br>
+       litest_drain_events(li);<br>
+<br>
+       litest_disable_log_handler(li);<br>
+       litest_tablet_proximity_in(dev, 5, 100, axes);<br>
+       libinput_dispatch(li);<br>
+       event = libinput_get_event(li);<br>
+       tev = litest_is_tablet_event(event,<br>
+                                    LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+       ck_assert_double_eq(pressure, 0.0);<br>
+       libinput_event_destroy(event);<br>
+       litest_restore_log_handler(li);<br>
+<br>
+       axes[0].value = 0;<br>
+       axes[1].value = 31;<br>
+       litest_push_event_frame(dev);<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       litest_event(dev, EV_KEY, BTN_TOUCH, 1);<br>
+       litest_pop_event_frame(dev);<br>
+       libinput_dispatch(li);<br>
+       litest_drain_events(li);<br>
+<br>
+       axes[1].value = 30;<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       libinput_dispatch(li);<br>
+<br>
+       event = libinput_get_event(li);<br>
+       tev = litest_is_tablet_event(event,<br>
+                                    LIBINPUT_EVENT_TABLET_TOOL_AXIS);<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+       ck_assert_double_gt(pressure, 0.0);<br>
+<br>
+       libinput_event_destroy(event);<br>
+}<br>
+END_TEST<br>
+<br>
+START_TEST(tablet_pressure_offset_none_for_zero_distance)<br>
+{<br>
+       struct litest_device *dev = litest_current_device();<br>
+       struct libinput *li = dev->libinput;<br>
+       struct libinput_event *event;<br>
+       struct libinput_event_tablet_tool *tev;<br>
+       struct axis_replacement axes[] = {<br>
+               { ABS_DISTANCE, 0 },<br>
+               { ABS_PRESSURE, 20 },<br>
+               { -1, -1 },<br>
+       };<br>
+       double pressure;<br>
+<br>
+       litest_drain_events(li);<br>
+<br>
+       /* we're going straight to touch on proximity, make sure we don't<br>
+        * offset the pressure here */<br>
+       litest_push_event_frame(dev);<br>
+       litest_tablet_proximity_in(dev, 5, 100, axes);<br>
+       litest_event(dev, EV_KEY, BTN_TOUCH, 1);<br>
+       litest_pop_event_frame(dev);<br>
+       libinput_dispatch(li);<br>
+<br>
+       event = libinput_get_event(li);<br>
+       tev = litest_is_tablet_event(event,<br>
+                                    LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+       ck_assert_double_gt(pressure, 0.0);<br>
+<br>
+       libinput_event_destroy(event);<br>
+}<br>
+END_TEST<br>
+<br>
+START_TEST(tablet_pressure_offset_none_for_small_distance)<br>
+{<br>
+       struct litest_device *dev = litest_current_device();<br>
+       struct libinput *li = dev->libinput;<br>
+       struct libinput_event *event;<br>
+       struct libinput_event_tablet_tool *tev;<br>
+       struct axis_replacement axes[] = {<br>
+               { ABS_DISTANCE, 20 },<br>
+               { ABS_PRESSURE, 20 },<br>
+               { -1, -1 },<br>
+       };<br>
+       double pressure;<br>
+<br>
+       /* stylus too close to the tablet on the proximity in, ignore any<br>
+        * pressure offset */<br>
+       litest_tablet_proximity_in(dev, 5, 100, axes);<br>
+       litest_drain_events(li);<br>
+       libinput_dispatch(li);<br>
+<br>
+       axes[0].value = 0;<br>
+       axes[1].value = 21;<br>
+       litest_push_event_frame(dev);<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       litest_event(dev, EV_KEY, BTN_TOUCH, 1);<br>
+       litest_pop_event_frame(dev);<br>
+       litest_drain_events(li);<br>
+<br>
+       axes[1].value = 20;<br>
+       litest_tablet_motion(dev, 70, 70, axes);<br>
+       libinput_dispatch(li);<br>
+<br>
+       litest_wait_for_event_of_type(li,<br>
+                                     LIBINPUT_EVENT_TABLET_TOOL_AXIS,<br>
+                                     -1);<br>
+       event = libinput_get_event(li);<br>
+       tev = libinput_event_get_tablet_tool_event(event);<br>
+       pressure = libinput_event_tablet_tool_get_axis_value(tev,<br>
+                                                            LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);<br>
+       ck_assert_double_gt(pressure, 0.0);<br>
+<br>
+       libinput_event_destroy(event);<br>
+}<br>
+END_TEST<br>
+<br>
 void<br>
 litest_setup_tests(void)<br>
 {<br>
@@ -2578,4 +2882,11 @@ litest_setup_tests(void)<br>
        litest_add("tablet:calibration", tablet_calibration_has_matrix, LITEST_TABLET, LITEST_ANY);<br>
        litest_add("tablet:calibration", tablet_calibration_set_matrix, LITEST_TABLET, LITEST_ANY);<br>
        litest_add("tablet:calibration", tablet_calibration_set_matrix_delta, LITEST_TABLET, LITEST_ANY);<br>
+<br>
+       litest_add_for_device("tablet:pressure", tablet_pressure_offset, LITEST_WACOM_INTUOS);<br>
+       litest_add_for_device("tablet:pressure", tablet_pressure_offset_decrease, LITEST_WACOM_INTUOS);<br>
+       litest_add_for_device("tablet:pressure", tablet_pressure_offset_increase, LITEST_WACOM_INTUOS);<br>
+       litest_add_for_device("tablet:pressure", tablet_pressure_offset_exceed_threshold, LITEST_WACOM_INTUOS);<br>
+       litest_add_for_device("tablet:pressure", tablet_pressure_offset_none_for_zero_distance, LITEST_WACOM_INTUOS);<br>
+       litest_add_for_device("tablet:pressure", tablet_pressure_offset_none_for_small_distance, LITEST_WACOM_INTUOS);<br>
 }<br>
--<br>
2.5.0<br>
<br>
</blockquote>