diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index 6ef2db2e..279e93b8 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -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 diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h index 86ed5ed3..e288fc79 100644 --- a/src/evdev-tablet.h +++ b/src/evdev-tablet.h @@ -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 { diff --git a/test/test-tablet.c b/test/test-tablet.c index 6f333c8a..12beba9f 100644 --- a/test/test-tablet.c +++ b/test/test-tablet.c @@ -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);