[PATCH v2 libinput 5/6] touchpad: add touch-size-based palm detection

Peter Hutterer peter.hutterer at who-t.net
Tue Jul 11 04:09:25 UTC 2017


Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev-mt-touchpad.c            | 66 ++++++++++++++++++++++++++++++++++++--
 src/evdev-mt-touchpad.h            |  4 +++
 src/libinput-util.c                | 25 +++++++++++++++
 src/libinput-util.h                |  1 +
 test/litest.h                      | 18 +++++++++++
 test/test-device.c                 | 20 ++----------
 test/test-touchpad.c               | 36 +++++++++++++++++++++
 udev/90-libinput-model-quirks.hwdb |  1 +
 udev/parse_hwdb.py                 |  1 +
 9 files changed, 152 insertions(+), 20 deletions(-)

diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 0f009ef6..a3751289 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -746,6 +746,30 @@ tp_palm_detect_multifinger(struct tp_dispatch *tp, struct tp_touch *t, uint64_t
 }
 
 static inline bool
+tp_palm_detect_touch_size_triggered(struct tp_dispatch *tp,
+				    struct tp_touch *t,
+				    uint64_t time)
+{
+	if (!tp->palm.use_size)
+		return false;
+
+	/* If a finger size is large enough for palm, we stick with that and
+	 * force the user to release and reset the finger */
+	if (t->palm.state != PALM_NONE && t->palm.state != PALM_TOUCH_SIZE)
+		return false;
+
+	if (t->major > tp->palm.size_threshold ||
+	    t->minor > tp->palm.size_threshold) {
+		evdev_log_debug(tp->device,
+				"palm: touch size exceeded\n");
+		t->palm.state = PALM_TOUCH_SIZE;
+		return true;
+	}
+
+	return false;
+}
+
+static inline bool
 tp_palm_detect_edge(struct tp_dispatch *tp,
 		    struct tp_touch *t,
 		    uint64_t time)
@@ -828,6 +852,9 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
 	if (tp_palm_detect_tool_triggered(tp, t, time))
 		goto out;
 
+	if (tp_palm_detect_touch_size_triggered(tp, t, time))
+		goto out;
+
 	if (tp_palm_detect_edge(tp, t, time))
 		goto out;
 
@@ -862,6 +889,9 @@ out:
 	case PALM_PRESSURE:
 		palm_state = "pressure";
 		break;
+	case PALM_TOUCH_SIZE:
+		palm_state = "touch size";
+		break;
 	case PALM_NONE:
 	default:
 		abort();
@@ -2415,10 +2445,14 @@ tp_init_palmdetect_edge(struct tp_dispatch *tp,
 	struct phys_coords mm = { 0.0, 0.0 };
 	struct device_coords edges;
 
+	if (device->tags & EVDEV_TAG_EXTERNAL_TOUCHPAD &&
+	    !tp_is_tpkb_combo_below(device))
+		return;
+
 	evdev_device_get_size(device, &width, &height);
 
-	/* Enable palm detection on touchpads >= 70 mm. Anything smaller
-	   probably won't need it, until we find out it does */
+	/* Enable edge palm detection on touchpads >= 70 mm. Anything
+	   smaller probably won't need it, until we find out it does */
 	if (width < 70.0)
 		return;
 
@@ -2475,6 +2509,33 @@ tp_init_palmdetect_pressure(struct tp_dispatch *tp,
 			tp->palm.pressure_threshold);
 }
 
+static inline void
+tp_init_palmdetect_size(struct tp_dispatch *tp,
+			struct evdev_device *device)
+{
+	const char *prop;
+	int threshold;
+
+	if (!tp->touch_size.use_touch_size)
+		return;
+
+	prop = udev_device_get_property_value(device->udev_device,
+					      "LIBINPUT_ATTR_PALM_SIZE_THRESHOLD");
+	if (!prop)
+		return;
+
+	threshold = parse_palm_size_property(prop);
+	if (threshold == 0) {
+		evdev_log_bug_client(device,
+				     "palm: ignoring invalid threshold %s\n",
+				     prop);
+		return;
+	}
+
+	tp->palm.use_size = true;
+	tp->palm.size_threshold = threshold;
+}
+
 static void
 tp_init_palmdetect(struct tp_dispatch *tp,
 		   struct evdev_device *device)
@@ -2497,6 +2558,7 @@ tp_init_palmdetect(struct tp_dispatch *tp,
 
 	tp_init_palmdetect_edge(tp, device);
 	tp_init_palmdetect_pressure(tp, device);
+	tp_init_palmdetect_size(tp, device);
 }
 
 static void
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 7391e6ce..664514de 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -59,6 +59,7 @@ enum touch_palm_state {
 	PALM_TRACKPOINT,
 	PALM_TOOL_PALM,
 	PALM_PRESSURE,
+	PALM_TOUCH_SIZE,
 };
 
 enum button_event {
@@ -360,6 +361,9 @@ struct tp_dispatch {
 
 		bool use_pressure;
 		int pressure_threshold;
+
+		bool use_size;
+		int size_threshold;
 	} palm;
 
 	struct {
diff --git a/src/libinput-util.c b/src/libinput-util.c
index df7a1f3b..7eb88e3c 100644
--- a/src/libinput-util.c
+++ b/src/libinput-util.c
@@ -432,6 +432,31 @@ parse_palm_pressure_property(const char *prop)
 }
 
 /**
+ * Helper function to parse the LIBINPUT_ATTR_PALM_SIZE_THRESHOLD property
+ * from udev. Property is of the form:
+ * LIBINPUT_ATTR_PALM_SIZE_THRESHOLD=<integer>
+ * Where the number indicates the minimum threshold to consider a touch to
+ * be a palm.
+ *
+ * @param prop The value of the udev property (without the
+ * LIBINPUT_ATTR_PALM_SIZE_THRESHOLD=)
+ * @return The pressure threshold or 0 on error
+ */
+int
+parse_palm_size_property(const char *prop)
+{
+	int thr = 0;
+
+	if (!prop)
+		return 0;
+
+	if (!safe_atoi(prop, &thr) || thr < 0 || thr > 1024)
+		return 0;
+
+        return thr;
+}
+
+/**
  * Return the next word in a string pointed to by state before the first
  * separator character. Call repeatedly to tokenize a whole string.
  *
diff --git a/src/libinput-util.h b/src/libinput-util.h
index 30ab48cd..6886c6dd 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -390,6 +390,7 @@ bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
 bool parse_calibration_property(const char *prop, float calibration[6]);
 bool parse_range_property(const char *prop, int *hi, int *lo);
 int parse_palm_pressure_property(const char *prop);
+int parse_palm_size_property(const char *prop);
 
 enum tpkbcombo_layout {
 	TPKBCOMBO_LAYOUT_UNKNOWN,
diff --git a/test/litest.h b/test/litest.h
index 73f9ac2e..7086804e 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -33,6 +33,8 @@
 #include <libinput.h>
 #include <math.h>
 
+#include "libinput-util.h"
+
 extern void litest_setup_tests_udev(void);
 extern void litest_setup_tests_path(void);
 extern void litest_setup_tests_pointer(void);
@@ -915,6 +917,22 @@ litest_disable_middleemu(struct litest_device *dev)
 	litest_assert_int_eq(status, expected);
 }
 
+static inline bool
+litest_touchpad_is_external(struct litest_device *dev)
+{
+	struct udev_device *udev_device;
+	const char *prop;
+	bool is_external;
+
+	udev_device = libinput_device_get_udev_device(dev->libinput_device);
+	prop = udev_device_get_property_value(udev_device,
+					      "ID_INPUT_TOUCHPAD_INTEGRATION");
+	is_external = prop && streq(prop, "external");
+	udev_device_unref(udev_device);
+
+	return is_external;
+}
+
 #undef ck_assert_double_eq
 #undef ck_assert_double_ne
 #undef ck_assert_double_lt
diff --git a/test/test-device.c b/test/test-device.c
index 018b194f..c4dfdd47 100644
--- a/test/test-device.c
+++ b/test/test-device.c
@@ -61,22 +61,6 @@ START_TEST(device_sendevents_config_invalid)
 }
 END_TEST
 
-static inline bool
-touchpad_is_external(struct litest_device *dev)
-{
-	struct udev_device *udev_device;
-	const char *prop;
-	bool is_external;
-
-	udev_device = libinput_device_get_udev_device(dev->libinput_device);
-	prop = udev_device_get_property_value(udev_device,
-					      "ID_INPUT_TOUCHPAD_INTEGRATION");
-	is_external = prop && streq(prop, "external");
-	udev_device_unref(udev_device);
-
-	return is_external;
-}
-
 START_TEST(device_sendevents_config_touchpad)
 {
 	struct litest_device *dev = litest_current_device();
@@ -87,7 +71,7 @@ START_TEST(device_sendevents_config_touchpad)
 
 	/* The wacom devices in the test suite are external */
 	if (libevdev_get_id_vendor(dev->evdev) != VENDOR_ID_WACOM &&
-	    !touchpad_is_external(dev))
+	    !litest_touchpad_is_external(dev))
 		expected |=
 			LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
 
@@ -107,7 +91,7 @@ START_TEST(device_sendevents_config_touchpad_superset)
 
 	/* The wacom devices in the test suite are external */
 	if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM ||
-	    touchpad_is_external(dev))
+	    litest_touchpad_is_external(dev))
 		return;
 
 	device = dev->libinput_device;
diff --git a/test/test-touchpad.c b/test/test-touchpad.c
index 77618155..5e029a45 100644
--- a/test/test-touchpad.c
+++ b/test/test-touchpad.c
@@ -5376,6 +5376,41 @@ START_TEST(touchpad_touch_size_2fg)
 }
 END_TEST
 
+START_TEST(touchpad_palm_detect_touch_size)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+       struct axis_replacement axes[] = {
+               { ABS_MT_TOUCH_MAJOR, 0 },
+               { ABS_MT_TOUCH_MINOR, 0 },
+               { -1, 0 }
+       };
+
+       if (!touchpad_has_touch_size(dev) ||
+	   litest_touchpad_is_external(dev))
+               return;
+
+       litest_drain_events(li);
+       litest_axis_set_value(axes, ABS_MT_TOUCH_MAJOR, 30);
+       litest_axis_set_value(axes, ABS_MT_TOUCH_MINOR, 30);
+       litest_touch_down_extended(dev, 0, 50, 50, axes);
+       litest_touch_move_to_extended(dev, 0,
+                                     50, 50,
+                                     80, 80,
+                                     axes, 10, 1);
+       litest_assert_only_typed_events(li,
+                                       LIBINPUT_EVENT_POINTER_MOTION);
+
+       litest_axis_set_value_unchecked(axes, ABS_MT_TOUCH_MAJOR, 90);
+       litest_axis_set_value(axes, ABS_MT_TOUCH_MINOR, 90);
+       litest_touch_move_to_extended(dev, 0,
+                                     80, 80,
+                                     50, 50,
+                                     axes, 10, 1);
+       litest_assert_empty_queue(li);
+}
+END_TEST
+
 void
 litest_setup_tests_touchpad(void)
 {
@@ -5430,6 +5465,7 @@ litest_setup_tests_touchpad(void)
 	litest_add("touchpad:palm", touchpad_palm_detect_tool_palm, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
 	litest_add("touchpad:palm", touchpad_palm_detect_tool_palm_on_off, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
 	litest_add("touchpad:palm", touchpad_palm_detect_tool_palm_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+	litest_add("touchpad:palm", touchpad_palm_detect_touch_size, LITEST_APPLE_CLICKPAD, LITEST_ANY);
 
 	litest_add("touchpad:palm", touchpad_palm_detect_pressure, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
 	litest_add("touchpad:palm", touchpad_palm_detect_pressure_late, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb
index 5d9b2cbc..2754c5d5 100644
--- a/udev/90-libinput-model-quirks.hwdb
+++ b/udev/90-libinput-model-quirks.hwdb
@@ -51,6 +51,7 @@ libinput:touchpad:input:b0005v05ACp*
  LIBINPUT_MODEL_APPLE_TOUCHPAD=1
  LIBINPUT_ATTR_SIZE_HINT=104x75
  LIBINPUT_ATTR_TOUCH_SIZE_RANGE=150:130
+ LIBINPUT_ATTR_PALM_SIZE_THRESHOLD=800
 
 libinput:name:*Apple Inc. Apple Internal Keyboard*:dmi:*
  LIBINPUT_ATTR_KEYBOARD_INTEGRATION=internal
diff --git a/udev/parse_hwdb.py b/udev/parse_hwdb.py
index 102fb3e7..f6b9ec0a 100755
--- a/udev/parse_hwdb.py
+++ b/udev/parse_hwdb.py
@@ -119,6 +119,7 @@ def property_grammar():
 
     tprops = (
         ('LIBINPUT_ATTR_PALM_PRESSURE_THRESHOLD', INTEGER('X')),
+        ('LIBINPUT_ATTR_PALM_SIZE_THRESHOLD', INTEGER('X')),
     )
     typed_props = [Literal(name)('NAME') - Suppress('=') - val
                    for name, val in tprops]
-- 
2.13.0



More information about the wayland-devel mailing list