tablet: fix double proximity out on slow proximity out pens
authorPeter Hutterer <peter.hutterer@who-t.net>
Mon, 17 Jun 2019 01:18:57 +0000 (11:18 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Mon, 17 Jun 2019 04:39:58 +0000 (14:39 +1000)
Where the proximity out event is delayed by the kernel, libinput would cause
an extra proxmity in-out after the forced proximity out event.

Event sequence is basically (k: kernel, l: libinput)

k: tablet axis events
l: tablet axis events
k: nothing for $proximity timer milliseconds
l: tablet proximity out
k: proximity out event
l: proximity in event
l: proximity out event

Fixes #306

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
src/evdev-tablet.c
src/evdev-tablet.h
test/test-tablet.c

index 6ef2db2..279e93b 100644 (file)
@@ -806,6 +806,7 @@ tablet_process_key(struct tablet_dispatch *tablet,
        case BTN_TOOL_MOUSE:
        case BTN_TOOL_LENS:
                type = tablet_evcode_to_tool(e->code);
+               tablet_set_status(tablet, TABLET_TOOL_UPDATED);
                if (e->value)
                        tablet->tool_state |= bit(type);
                else
@@ -1721,13 +1722,22 @@ tablet_update_tool_state(struct tablet_dispatch *tablet,
         *   BTN_TOOL_PEN and the state for the tool was 0, this device will
         *   never send the event.
         * We don't do this for pure button events because we discard those.
+        *
+        * But: on some devices the proximity out is delayed by the kernel,
+        * so we get it after our forced prox-out has triggered. In that
+        * case we need to just ignore the change.
         */
-       if (tablet_has_status(tablet, TABLET_AXES_UPDATED) &&
-           (tablet->quirks.proximity_out_forced ||
-            (tablet->tool_state == 0 &&
-             tablet->current_tool.type == LIBINPUT_TOOL_NONE))) {
-               tablet->tool_state = bit(LIBINPUT_TABLET_TOOL_TYPE_PEN);
-               tablet->quirks.proximity_out_forced = false;
+       if (tablet_has_status(tablet, TABLET_AXES_UPDATED)) {
+               if (tablet->quirks.proximity_out_forced) {
+                       if (!tablet_has_status(tablet, TABLET_TOOL_UPDATED) ||
+                           tablet->tool_state)
+                               tablet->tool_state = bit(LIBINPUT_TABLET_TOOL_TYPE_PEN);
+                       tablet->quirks.proximity_out_forced = false;
+               } else if (tablet->tool_state == 0 &&
+                           tablet->current_tool.type == LIBINPUT_TOOL_NONE) {
+                       tablet->tool_state = bit(LIBINPUT_TABLET_TOOL_TYPE_PEN);
+                       tablet->quirks.proximity_out_forced = false;
+               }
        }
 
        if (tablet->tool_state == tablet->prev_tool_state)
@@ -1886,6 +1896,7 @@ tablet_reset_state(struct tablet_dispatch *tablet)
        memcpy(&tablet->prev_button_state,
               &tablet->button_state,
               sizeof(tablet->button_state));
+       tablet_unset_status(tablet, TABLET_TOOL_UPDATED);
 }
 
 static void
index 86ed5ed..e288fc7 100644 (file)
@@ -38,13 +38,14 @@ enum tablet_status {
        TABLET_AXES_UPDATED             = bit(0),
        TABLET_BUTTONS_PRESSED          = bit(1),
        TABLET_BUTTONS_RELEASED         = bit(2),
-       TABLET_TOOL_IN_CONTACT          = bit(3),
-       TABLET_TOOL_LEAVING_PROXIMITY   = bit(4),
-       TABLET_TOOL_OUT_OF_PROXIMITY    = bit(5),
-       TABLET_TOOL_ENTERING_PROXIMITY  = bit(6),
-       TABLET_TOOL_ENTERING_CONTACT    = bit(7),
-       TABLET_TOOL_LEAVING_CONTACT     = bit(8),
-       TABLET_TOOL_OUT_OF_RANGE        = bit(9),
+       TABLET_TOOL_UPDATED             = bit(3),
+       TABLET_TOOL_IN_CONTACT          = bit(4),
+       TABLET_TOOL_LEAVING_PROXIMITY   = bit(5),
+       TABLET_TOOL_OUT_OF_PROXIMITY    = bit(6),
+       TABLET_TOOL_ENTERING_PROXIMITY  = bit(7),
+       TABLET_TOOL_ENTERING_CONTACT    = bit(8),
+       TABLET_TOOL_LEAVING_CONTACT     = bit(9),
+       TABLET_TOOL_OUT_OF_RANGE        = bit(10),
 };
 
 struct button_state {
index 6f333c8..12beba9 100644 (file)
@@ -1506,6 +1506,32 @@ START_TEST(proximity_range_button_release)
 }
 END_TEST
 
+START_TEST(proximity_out_slow_event)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+       struct axis_replacement axes[] = {
+               { ABS_DISTANCE, 90 },
+               { -1, -1 }
+       };
+
+       litest_tablet_proximity_in(dev, 10, 10, axes);
+       litest_tablet_motion(dev, 12, 12, axes);
+       litest_drain_events(li);
+
+       litest_timeout_tablet_proxout();
+       libinput_dispatch(li);
+
+       /* The forced prox out */
+       litest_assert_tablet_proximity_event(li,
+                                            LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
+       litest_assert_empty_queue(li);
+
+       litest_tablet_proximity_out(dev);
+       litest_assert_empty_queue(li);
+}
+END_TEST
+
 START_TEST(proximity_out_on_delete)
 {
        struct libinput *li = litest_create_context();
@@ -5651,6 +5677,8 @@ TEST_COLLECTION(tablet)
        litest_add("tablet:proximity", proximity_range_button_click, LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_MOUSE, LITEST_ANY);
        litest_add("tablet:proximity", proximity_range_button_press, LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_MOUSE, LITEST_ANY);
        litest_add("tablet:proximity", proximity_range_button_release, LITEST_TABLET | LITEST_DISTANCE | LITEST_TOOL_MOUSE, LITEST_ANY);
+       litest_add("tablet:proximity", proximity_out_slow_event, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY);
+
        litest_add_no_device("tablet:proximity", proximity_out_on_delete);
        litest_add("tablet:button", button_down_up, LITEST_TABLET, LITEST_ANY);
        litest_add("tablet:button", button_seat_count, LITEST_TABLET, LITEST_ANY);