mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-01-01 03:30:08 +01:00
touchpad: avoid motion events when moving one finger into AREA
If a 2fg scroll motion starts with both fingers in the bottom button area and one finger moves into the main area before the other, we used to send motion events for that finger. Once the second finger moved into the main area the scroll was detected correctly but by then the cursor may have moved out of the intended focus area. We have two transitions where we may start sending motion events: when we move out of the bottom area and when the finger moves by more than 5mm within the button area. In both cases, check for any touches that are in the bottom area and started at the 'same' time as our moving touch. Mark those as 'moved' to release them for gestures so we get the right finger count and axis/gesture events instead of just motion events. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
60d9defdb7
commit
df1f6ba40f
4 changed files with 92 additions and 1 deletions
|
|
@ -251,6 +251,36 @@ tp_button_area_handle_event(struct tp_dispatch *tp,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release any button in the bottom area, provided it started within a
|
||||
* threshold around start_time (i.e. simultaneously with the other touch
|
||||
* that triggered this call).
|
||||
*/
|
||||
static inline void
|
||||
tp_button_release_other_bottom_touches(struct tp_dispatch *tp,
|
||||
uint64_t other_start_time)
|
||||
{
|
||||
struct tp_touch *t;
|
||||
|
||||
tp_for_each_touch(tp, t) {
|
||||
uint64_t tdelta;
|
||||
|
||||
if (t->button.state != BUTTON_STATE_BOTTOM ||
|
||||
t->button.has_moved)
|
||||
continue;
|
||||
|
||||
if (other_start_time > t->button.initial_time)
|
||||
tdelta = other_start_time - t->button.initial_time;
|
||||
else
|
||||
tdelta = t->button.initial_time - other_start_time;
|
||||
|
||||
if (tdelta > ms2us(80))
|
||||
continue;
|
||||
|
||||
t->button.has_moved = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_button_bottom_handle_event(struct tp_dispatch *tp,
|
||||
struct tp_touch *t,
|
||||
|
|
@ -271,6 +301,14 @@ tp_button_bottom_handle_event(struct tp_dispatch *tp,
|
|||
case BUTTON_EVENT_IN_TOP_L:
|
||||
case BUTTON_EVENT_IN_AREA:
|
||||
tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
|
||||
|
||||
/* We just transitioned one finger from BOTTOM to AREA,
|
||||
* if there are other fingers in BOTTOM that started
|
||||
* simultaneously with this finger, release those fingers
|
||||
* because they're part of a gesture.
|
||||
*/
|
||||
tp_button_release_other_bottom_touches(tp,
|
||||
t->button.initial_time);
|
||||
break;
|
||||
case BUTTON_EVENT_UP:
|
||||
tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
|
||||
|
|
@ -485,8 +523,12 @@ tp_button_check_for_movement(struct tp_dispatch *tp, struct tp_touch *t)
|
|||
mm = evdev_device_unit_delta_to_mm(tp->device, &delta);
|
||||
vector_length = hypot(mm.x, mm.y);
|
||||
|
||||
if (vector_length > 5.0 /* mm */)
|
||||
if (vector_length > 5.0 /* mm */) {
|
||||
t->button.has_moved = true;
|
||||
|
||||
tp_button_release_other_bottom_touches(tp,
|
||||
t->button.initial_time);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -500,6 +542,7 @@ tp_button_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|||
|
||||
if (t->state == TOUCH_BEGIN) {
|
||||
t->button.initial = t->point;
|
||||
t->button.initial_time = time;
|
||||
t->button.has_moved = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ struct tp_touch {
|
|||
struct libinput_timer timer;
|
||||
struct device_coords initial;
|
||||
bool has_moved; /* has moved more than threshold */
|
||||
uint64_t initial_time;
|
||||
} button;
|
||||
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -961,6 +961,15 @@ litest_has_clickfinger(struct litest_device *dev)
|
|||
return methods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
litest_has_btnareas(struct litest_device *dev)
|
||||
{
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
uint32_t methods = libinput_device_config_click_get_methods(device);
|
||||
|
||||
return methods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
|
||||
}
|
||||
|
||||
static inline void
|
||||
litest_enable_clickfinger(struct litest_device *dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -511,6 +511,43 @@ START_TEST(touchpad_2fg_scroll_return_to_motion)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_2fg_scroll_from_btnareas)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
if (!litest_has_2fg_scroll(dev) ||
|
||||
!litest_has_btnareas(dev))
|
||||
return;
|
||||
|
||||
litest_enable_2fg_scroll(dev);
|
||||
litest_enable_buttonareas(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 30, 95);
|
||||
litest_touch_down(dev, 1, 50, 95);
|
||||
libinput_dispatch(li);
|
||||
|
||||
/* First finger moves out of the area first but it's a scroll
|
||||
* motion, should not trigger POINTER_MOTION */
|
||||
for (int i = 0; i < 5; i++) {
|
||||
litest_touch_move(dev, 0, 30, 95 - i);
|
||||
}
|
||||
libinput_dispatch(li);
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
litest_touch_move(dev, 0, 30, 90 - i);
|
||||
litest_touch_move(dev, 1, 30, 95 - i);
|
||||
}
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_touch_up(dev, 0);
|
||||
litest_touch_up(dev, 1);
|
||||
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_scroll_natural_defaults)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -6713,6 +6750,7 @@ TEST_COLLECTION(touchpad)
|
|||
litest_add("touchpad:scroll", touchpad_2fg_scroll_return_to_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:scroll", touchpad_2fg_scroll_source, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:scroll", touchpad_2fg_scroll_semi_mt, LITEST_SEMI_MT, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:scroll", touchpad_2fg_scroll_from_btnareas, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:scroll", touchpad_scroll_natural_defaults, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:scroll", touchpad_scroll_natural_enable_config, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:scroll", touchpad_scroll_natural_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue