touchpad: sync BTN_TOOL_FINGER state on init
authorPeter Hutterer <peter.hutterer@who-t.net>
Mon, 5 Dec 2016 03:39:42 +0000 (13:39 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Mon, 5 Dec 2016 21:28:15 +0000 (07:28 +1000)
The Elantech touchpad on my Asus Vivobook doesn't release BTN_TOOL_FINGER on
up. If the touchpad was used before libinput initializes, the kernel filters
the event because its state is already set. We never receive it and keep
ignoring all events until the first switch to BTN_TOOL_DOUBLETAP and back.

On touchpad init sync the BTN_TOOL_FINGER state and set it accordingly. This
is the only event that can be legitimately down on init. We don't care about
BTN_TOUCH because ignoring an ongoing touch on init is generally a good idea
and we can ignore any multifinger gesture as well.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
src/evdev-mt-touchpad.c
test/touchpad.c

index 0a261a3b8a2874ce9cf3900f940be6ea1d3d2f73..762f5396d71b6830f50d282e37dbc391f23133f2 100644 (file)
@@ -1804,6 +1804,14 @@ tp_init_slots(struct tp_dispatch *tp,
        for (i = 1; i < tp->num_slots; i++)
                tp_sync_touch(tp, device, &tp->touches[i], i);
 
+       /* Some touchpads don't reset BTN_TOOL_FINGER on touch up and only
+        * change to/from it when BTN_TOOL_DOUBLETAP is set. This causes us
+        * to ignore the first touches events until a two-finger gesture is
+        * performed.
+        */
+       if (libevdev_get_event_value(device->evdev, EV_KEY, BTN_TOOL_FINGER))
+               tp_fake_finger_set(tp, BTN_TOOL_FINGER, 1);
+
        return true;
 }
 
index cdc261bc841d475b451a759489dab0e7db8cbb13..5b6f0a4e0ebbb08c408ae8b3c6b54da94956f0e0 100644 (file)
@@ -4365,6 +4365,29 @@ START_TEST(touchpad_slot_swap)
 }
 END_TEST
 
+START_TEST(touchpad_finger_always_down)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li;
+
+       /* Set BTN_TOOL_FINGER before a new context is initialized */
+       litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
+       litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+       li = litest_create_context();
+       libinput_path_add_device(li,
+                                libevdev_uinput_get_devnode(dev->uinput));
+       litest_drain_events(li);
+
+       litest_touch_down(dev, 0, 50, 50);
+       litest_touch_move_to(dev, 0, 50, 50, 70, 50, 10, 0);
+
+       litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+
+       libinput_unref(li);
+}
+END_TEST
+
 START_TEST(touchpad_time_usec)
 {
        struct litest_device *dev = litest_current_device();
@@ -4742,6 +4765,7 @@ litest_setup_tests_touchpad(void)
 
        litest_add_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count, LITEST_SYNAPTICS_TOPBUTTONPAD);
        litest_add_for_device("touchpad:bugs", touchpad_slot_swap, LITEST_SYNAPTICS_TOPBUTTONPAD);
+       litest_add_for_device("touchpad:bugs", touchpad_finger_always_down, LITEST_SYNAPTICS_TOPBUTTONPAD);
 
        litest_add("touchpad:time", touchpad_time_usec, LITEST_TOUCHPAD, LITEST_ANY);