summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2015-12-01 11:07:57 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2015-12-15 08:21:39 +1000
commitdb852ef0dbb61eb68d26affb3d01c194e0242369 (patch)
treeab6fd3e1da1e7c66ee8c77c8af708868146dac58 /src
parent09456ebf23b1ec9036bf22ebcecd19dcfef26615 (diff)
tablet: support tool-specific pressure offsets
If a tool wears out, it may have a pre-loaded pressure offset. In that case, even when the tool is not physically in contact with the tablet surface it will send pressure events. Use automatic pressure offset detection, similar to what the X.Org wacom driver does. On proximity-in, check the pressure and if the distance is above 50% of the range and the pressure is nonzero but below 20% of the range, use that value as pressure offset. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Ping Cheng <pingc@wacom.com>
Diffstat (limited to 'src')
-rw-r--r--src/evdev-tablet.c85
-rw-r--r--src/evdev-tablet.h21
-rw-r--r--src/libinput-private.h3
3 files changed, 106 insertions, 3 deletions
diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 7f6eecb4..2f4d6804 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -21,6 +21,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config.h"
+#include "libinput-version.h"
#include "evdev-tablet.h"
#include <assert.h>
@@ -202,7 +203,7 @@ tablet_update_tool(struct tablet_dispatch *tablet,
}
static inline double
-normalize_pressure_dist_slider(const struct input_absinfo *absinfo)
+normalize_dist_slider(const struct input_absinfo *absinfo)
{
double range = absinfo->maximum - absinfo->minimum;
double value = (absinfo->value - absinfo->minimum) / range;
@@ -211,6 +212,18 @@ normalize_pressure_dist_slider(const struct input_absinfo *absinfo)
}
static inline double
+normalize_pressure(const struct input_absinfo *absinfo,
+ struct libinput_tablet_tool *tool)
+{
+ double range = absinfo->maximum - absinfo->minimum;
+ int offset = tool->has_pressure_offset ?
+ tool->pressure_offset : 0;
+ double value = (absinfo->value - offset - absinfo->minimum) / range;
+
+ return value;
+}
+
+static inline double
normalize_tilt(const struct input_absinfo *absinfo)
{
double range = absinfo->maximum - absinfo->minimum;
@@ -398,10 +411,12 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
axis_to_evcode(a));
switch (a) {
- case LIBINPUT_TABLET_TOOL_AXIS_DISTANCE:
case LIBINPUT_TABLET_TOOL_AXIS_PRESSURE:
+ tablet->axes[a] = normalize_pressure(absinfo, tool);
+ break;
+ case LIBINPUT_TABLET_TOOL_AXIS_DISTANCE:
case LIBINPUT_TABLET_TOOL_AXIS_SLIDER:
- tablet->axes[a] = normalize_pressure_dist_slider(absinfo);
+ tablet->axes[a] = normalize_dist_slider(absinfo);
break;
case LIBINPUT_TABLET_TOOL_AXIS_TILT_X:
case LIBINPUT_TABLET_TOOL_AXIS_TILT_Y:
@@ -809,6 +824,8 @@ tablet_get_tool(struct tablet_dispatch *tablet,
.refcount = 1,
};
+ tool->pressure_offset = 0;
+ tool->has_pressure_offset = false;
tool_set_bits(tablet, tool);
list_insert(tool_list, &tool->link);
@@ -922,6 +939,67 @@ sanitize_tablet_axes(struct tablet_dispatch *tablet)
set_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
}
+static inline int
+axis_range_percentage(const struct input_absinfo *a, int percent)
+{
+ return (a->maximum - a->minimum) * percent/100 + a->minimum;
+}
+
+static void
+detect_pressure_offset(struct tablet_dispatch *tablet,
+ struct evdev_device *device,
+ struct libinput_tablet_tool *tool)
+{
+ const struct input_absinfo *pressure, *distance;
+ int offset;
+
+ if (!bit_is_set(tablet->changed_axes,
+ LIBINPUT_TABLET_TOOL_AXIS_PRESSURE))
+ return;
+
+ pressure = libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
+ distance = libevdev_get_abs_info(device->evdev, ABS_DISTANCE);
+
+ if (!pressure || !distance)
+ return;
+
+ offset = pressure->value - pressure->minimum;
+
+ if (tool->has_pressure_offset) {
+ if (offset < tool->pressure_offset)
+ tool->pressure_offset = offset;
+ return;
+ }
+
+ /* we only set a pressure offset on proximity in */
+ if (!tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY))
+ return;
+
+ /* If we're closer than 50% of the distance axis, skip pressure
+ * offset detection, too likely to be wrong */
+ if (distance->value < axis_range_percentage(distance, 50))
+ return;
+
+ if (offset > axis_range_percentage(pressure, 20)) {
+ log_error(device->base.seat->libinput,
+ "Ignoring pressure offset greater than 20%% detected on tool %s (serial %#x). "
+ "See http://wayland.freedesktop.org/libinput/doc/%s/tablet-support.html\n",
+ tablet_tool_type_to_string(tool->type),
+ tool->serial,
+ LIBINPUT_VERSION);
+ return;
+ }
+
+ log_info(device->base.seat->libinput,
+ "Pressure offset detected on tool %s (serial %#x). "
+ "See http://wayland.freedesktop.org/libinput/doc/%s/tablet-support.html\n",
+ tablet_tool_type_to_string(tool->type),
+ tool->serial,
+ LIBINPUT_VERSION);
+ tool->pressure_offset = offset;
+ tool->has_pressure_offset = true;
+}
+
static void
tablet_flush(struct tablet_dispatch *tablet,
struct evdev_device *device,
@@ -946,6 +1024,7 @@ tablet_flush(struct tablet_dispatch *tablet,
tablet_set_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
} else if (tablet_has_status(tablet, TABLET_AXES_UPDATED) ||
tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY)) {
+ detect_pressure_offset(tablet, device, tool);
sanitize_tablet_axes(tablet);
tablet_check_notify_axes(tablet, device, time, tool);
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index 162b5366..4dcbccc6 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -178,4 +178,25 @@ tablet_tool_to_evcode(enum libinput_tablet_tool_type type)
return code;
}
+
+static inline const char *
+tablet_tool_type_to_string(enum libinput_tablet_tool_type type)
+{
+ const char *str;
+
+ switch (type) {
+ case LIBINPUT_TABLET_TOOL_TYPE_PEN: str = "pen"; break;
+ case LIBINPUT_TABLET_TOOL_TYPE_ERASER: str = "eraser"; break;
+ case LIBINPUT_TABLET_TOOL_TYPE_BRUSH: str = "brush"; break;
+ case LIBINPUT_TABLET_TOOL_TYPE_PENCIL: str = "pencil"; break;
+ case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH: str = "airbrush"; break;
+ case LIBINPUT_TABLET_TOOL_TYPE_MOUSE: str = "mouse"; break;
+ case LIBINPUT_TABLET_TOOL_TYPE_LENS: str = "lens"; break;
+ default:
+ abort();
+ }
+
+ return str;
+}
+
#endif
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 38a14b8f..f5b26483 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -259,6 +259,9 @@ struct libinput_tablet_tool {
unsigned char buttons[NCHARS(KEY_MAX) + 1];
int refcount;
void *user_data;
+
+ int pressure_offset;
+ bool has_pressure_offset;
};
struct libinput_event {