evdev: recover from a lost button count
authorPeter Hutterer <peter.hutterer@who-t.net>
Tue, 18 Jul 2017 06:12:27 +0000 (16:12 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Wed, 6 Sep 2017 09:38:41 +0000 (19:38 +1000)
If the kernel sends us a button press for a button that is thought to be down
we have lost track of the state of the button. Ignore the button press event,
in the hope that the next release makes things right again.

A release event may be masked if another process grabs the device for some
period of time, e.g. libinput debug-events --grab.

https://bugs.freedesktop.org/show_bug.cgi?id=101796

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 399c50dbeb9dd96ee959dc270bcb9f4be7ab6710)

src/evdev.c
test/test-pointer.c
test/valgrind.suppressions

index a6804149a40c60547a9afe85f2277bbe147cd818..ea0ed7adf9db193c347e1dc20c455c8424dd8499 100644 (file)
@@ -836,16 +836,16 @@ fallback_process_key(struct fallback_dispatch *dispatch,
        type = get_key_type(e->code);
 
        /* Ignore key release events from the kernel for keys that libinput
-        * never got a pressed event for. */
-       if (e->value == 0) {
-               switch (type) {
-               case EVDEV_KEY_TYPE_NONE:
-                       break;
-               case EVDEV_KEY_TYPE_KEY:
-               case EVDEV_KEY_TYPE_BUTTON:
-                       if (!hw_is_key_down(dispatch, e->code))
-                               return;
-               }
+        * never got a pressed event for or key presses for keys that we
+        * think are still down */
+       switch (type) {
+       case EVDEV_KEY_TYPE_NONE:
+               break;
+       case EVDEV_KEY_TYPE_KEY:
+       case EVDEV_KEY_TYPE_BUTTON:
+               if ((e->value && hw_is_key_down(dispatch, e->code)) ||
+                   (e->value == 0 && !hw_is_key_down(dispatch, e->code)))
+                       return;
        }
 
        hw_set_key_down(dispatch, e->code, e->value);
index e09f8f8aa9d9fc6b550b9ec81634533b9c794841..2f03195a44fee581f4ec0ca1c874a7b1f0e01c7e 100644 (file)
@@ -490,6 +490,40 @@ START_TEST(pointer_button_has_no_button)
 }
 END_TEST
 
+START_TEST(pointer_recover_from_lost_button_count)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+       struct libevdev *evdev = dev->evdev;
+
+       disable_button_scrolling(dev);
+
+       litest_drain_events(dev->libinput);
+
+       litest_button_click(dev, BTN_LEFT, 1);
+
+       litest_assert_button_event(li,
+                                  BTN_LEFT,
+                                  LIBINPUT_BUTTON_STATE_PRESSED);
+
+       /* Grab for the release to make libinput lose count */
+       libevdev_grab(evdev, LIBEVDEV_GRAB);
+       litest_button_click(dev, BTN_LEFT, 0);
+       libevdev_grab(evdev, LIBEVDEV_UNGRAB);
+
+       litest_assert_empty_queue(li);
+
+       litest_button_click(dev, BTN_LEFT, 1);
+       litest_assert_empty_queue(li);
+
+       litest_button_click(dev, BTN_LEFT, 0);
+       litest_assert_button_event(li,
+                                  BTN_LEFT,
+                                  LIBINPUT_BUTTON_STATE_RELEASED);
+       litest_assert_empty_queue(li);
+}
+END_TEST
+
 static inline double
 wheel_click_count(struct litest_device *dev, int which)
 {
@@ -2088,6 +2122,7 @@ litest_setup_tests_pointer(void)
        litest_add_no_device("pointer:button", pointer_button_auto_release);
        litest_add_no_device("pointer:button", pointer_seat_button_count);
        litest_add_for_device("pointer:button", pointer_button_has_no_button, LITEST_KEYBOARD);
+       litest_add("pointer:button", pointer_recover_from_lost_button_count, LITEST_BUTTON, LITEST_CLICKPAD);
        litest_add("pointer:scroll", pointer_scroll_wheel, LITEST_WHEEL, LITEST_TABLET);
        litest_add("pointer:scroll", pointer_scroll_button, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY);
        litest_add("pointer:scroll", pointer_scroll_button_noscroll, LITEST_ABSOLUTE|LITEST_BUTTON, LITEST_RELATIVE);
index e3ad874f40ed6da0e9ea7c1756fb8c38612a341a..dd573f570e76eab493b2ac5c726ee9adf8adb956 100644 (file)
    ...
    obj:/usr/lib*/libpython3*.so*
 }
+{
+   libevdev:grab
+   Memcheck:Param
+   ioctl(generic)
+   fun:ioctl
+   fun:libevdev_grab
+}