[PATCH 2/2] touchpad: don't apply tap config until all fingers are up

Peter Hutterer peter.hutterer at who-t.net
Wed Apr 29 23:00:01 PDT 2015


If tapping is enabled while at least one finger is down, we underrun
tp->tap.tap_finger_count on touch release. Avoid this by only switching
tap config whenever there are no fingers down.

Reported-by: Rui Matos <tiagomatos at gmail.com>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev-mt-touchpad-tap.c | 47 +++++++++++++++++++++++++++++++++++----------
 src/evdev-mt-touchpad.h     |  1 +
 test/touchpad.c             | 47 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+), 10 deletions(-)

diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c
index bd58bb1..0962899 100644
--- a/src/evdev-mt-touchpad-tap.c
+++ b/src/evdev-mt-touchpad-tap.c
@@ -622,12 +622,33 @@ tp_tap_enabled(struct tp_dispatch *tp)
 	return tp->tap.enabled && !tp->tap.suspended;
 }
 
+static void
+tp_tap_apply_config(struct tp_dispatch *tp)
+{
+	struct tp_touch *t;
+	bool finger_down = false;
+
+	if (tp->tap.enabled == tp->tap.want_enabled)
+		return;
+
+	tp_for_each_touch(tp, t) {
+		if (t->state != TOUCH_NONE) {
+			finger_down = true;
+			break;
+		}
+	}
+
+	if (!finger_down)
+		tp->tap.enabled = tp->tap.want_enabled;
+}
+
 int
 tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
 {
 	struct tp_touch *t;
 	int filter_motion = 0;
 
+	tp_tap_apply_config(tp);
 	if (!tp_tap_enabled(tp))
 		return 0;
 
@@ -647,6 +668,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
 
 		if (t->state == TOUCH_BEGIN) {
 			tp->tap.tap_finger_count++;
+			assert(tp->tap.tap_finger_count > 0);
 			t->tap.state = TAP_TOUCH_STATE_TOUCH;
 			t->tap.initial = t->point;
 			tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time);
@@ -659,6 +681,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
 				tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time);
 
 		} else if (t->state == TOUCH_END) {
+			assert(tp->tap.tap_finger_count > 0);
 			tp->tap.tap_finger_count--;
 			tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time);
 			t->tap.state = TAP_TOUCH_STATE_IDLE;
@@ -719,12 +742,14 @@ tp_tap_handle_timeout(uint64_t time, void *data)
 }
 
 static void
-tp_tap_enabled_update(struct tp_dispatch *tp, bool suspended, bool enabled, uint64_t time)
+tp_tap_enabled_update(struct tp_dispatch *tp,
+		      bool suspended,
+		      uint64_t time)
 {
 	bool was_enabled = tp_tap_enabled(tp);
 
+	tp_tap_apply_config(tp);
 	tp->tap.suspended = suspended;
-	tp->tap.enabled = enabled;
 
 	if (tp_tap_enabled(tp) == was_enabled)
 		return;
@@ -758,9 +783,8 @@ tp_tap_config_set_enabled(struct libinput_device *device,
 	struct tp_dispatch *tp = NULL;
 
 	tp = container_of(dispatch, tp, base);
-	tp_tap_enabled_update(tp, tp->tap.suspended,
-			      (enabled == LIBINPUT_CONFIG_TAP_ENABLED),
-			      libinput_now(device->seat->libinput));
+	tp->tap.want_enabled = (enabled == LIBINPUT_CONFIG_TAP_ENABLED),
+	tp_tap_apply_config(tp);
 
 	return LIBINPUT_CONFIG_STATUS_SUCCESS;
 }
@@ -774,8 +798,9 @@ tp_tap_config_is_enabled(struct libinput_device *device)
 	dispatch = ((struct evdev_device *) device)->dispatch;
 	tp = container_of(dispatch, tp, base);
 
-	return tp->tap.enabled ? LIBINPUT_CONFIG_TAP_ENABLED :
-				 LIBINPUT_CONFIG_TAP_DISABLED;
+	return tp->tap.want_enabled ?
+			LIBINPUT_CONFIG_TAP_ENABLED :
+			LIBINPUT_CONFIG_TAP_DISABLED;
 }
 
 static enum libinput_config_tap_state
@@ -818,7 +843,9 @@ tp_init_tap(struct tp_dispatch *tp)
 	tp->device->base.config.tap = &tp->tap.config;
 
 	tp->tap.state = TAP_STATE_IDLE;
-	tp->tap.enabled = tp_tap_default(tp->device);
+	tp->tap.want_enabled = tp_tap_default(tp->device);
+	tp->tap.enabled = !tp->tap.want_enabled;
+	tp_tap_apply_config(tp);
 
 	libinput_timer_init(&tp->tap.timer,
 			    tp->device->base.seat->libinput,
@@ -849,13 +876,13 @@ tp_release_all_taps(struct tp_dispatch *tp, uint64_t now)
 void
 tp_tap_suspend(struct tp_dispatch *tp, uint64_t time)
 {
-	tp_tap_enabled_update(tp, true, tp->tap.enabled, time);
+	tp_tap_enabled_update(tp, true, time);
 }
 
 void
 tp_tap_resume(struct tp_dispatch *tp, uint64_t time)
 {
-	tp_tap_enabled_update(tp, false, tp->tap.enabled, time);
+	tp_tap_enabled_update(tp, false, time);
 }
 
 bool
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 97b17cd..7f90f2b 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -253,6 +253,7 @@ struct tp_dispatch {
 	struct {
 		struct libinput_device_config_tap config;
 		bool enabled;
+		bool want_enabled;
 		bool suspended;
 		struct libinput_timer timer;
 		enum tp_tap_state state;
diff --git a/test/touchpad.c b/test/touchpad.c
index 830e589..c25a5d0 100644
--- a/test/touchpad.c
+++ b/test/touchpad.c
@@ -2944,6 +2944,51 @@ START_TEST(touchpad_tap_invalid)
 }
 END_TEST
 
+START_TEST(touchpad_tap_enable_during_tap)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+
+	libinput_device_config_tap_set_enabled(dev->libinput_device,
+					       LIBINPUT_CONFIG_TAP_DISABLED);
+	litest_drain_events(li);
+
+	litest_touch_down(dev, 0, 50, 50);
+	libinput_dispatch(li);
+	libinput_device_config_tap_set_enabled(dev->libinput_device,
+					       LIBINPUT_CONFIG_TAP_ENABLED);
+	litest_touch_up(dev, 0);
+	libinput_dispatch(li);
+
+	litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_tap_disable_during_tap)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+
+	libinput_device_config_tap_set_enabled(dev->libinput_device,
+					       LIBINPUT_CONFIG_TAP_ENABLED);
+	litest_drain_events(li);
+
+	litest_touch_down(dev, 0, 50, 50);
+	libinput_dispatch(li);
+	libinput_device_config_tap_set_enabled(dev->libinput_device,
+					       LIBINPUT_CONFIG_TAP_DISABLED);
+	litest_touch_up(dev, 0);
+	libinput_dispatch(li);
+
+	litest_assert_button_event(li,
+				   BTN_LEFT,
+				   LIBINPUT_BUTTON_STATE_PRESSED);
+	litest_assert_button_event(li,
+				   BTN_LEFT,
+				   LIBINPUT_BUTTON_STATE_RELEASED);
+}
+END_TEST
+
 static int
 touchpad_has_palm_detect_size(struct litest_device *dev)
 {
@@ -4163,6 +4208,8 @@ int main(int argc, char **argv) {
 	litest_add("touchpad:tap", touchpad_tap_invalid, LITEST_TOUCHPAD, LITEST_ANY);
 	litest_add("touchpad:tap", touchpad_tap_is_available, LITEST_TOUCHPAD, LITEST_ANY);
 	litest_add("touchpad:tap", touchpad_tap_is_not_available, LITEST_ANY, LITEST_TOUCHPAD);
+	litest_add("touchpad:tap", touchpad_tap_enable_during_tap, LITEST_TOUCHPAD, LITEST_ANY);
+	litest_add("touchpad:tap", touchpad_tap_disable_during_tap, LITEST_TOUCHPAD, LITEST_ANY);
 
 	litest_add("touchpad:tap", clickpad_1fg_tap_click, LITEST_CLICKPAD, LITEST_ANY);
 	litest_add("touchpad:tap", clickpad_2fg_tap_click, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD);
-- 
2.3.5



More information about the wayland-devel mailing list