touchpad: allow edge scrolling on clickpads

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Peter Hutterer 2015-07-03 14:33:41 +10:00
parent 77aca3c194
commit abff4a1c24
5 changed files with 230 additions and 17 deletions

View file

@ -55,10 +55,8 @@ scroll).
Due to the layout of the edges, diagonal scrolling is not possible. The
behavior of edge scrolling using both edges at the same time is undefined.
Edge scrolling conflicts with @ref clickpad_softbuttons and is
not usually available on clickpads. See
http://who-t.blogspot.com.au/2015/03/why-libinput-doesnt-support-edge.html
for details.
Edge scrolling overlaps with @ref clickpad_softbuttons. A physical click on
a clickpad ends scrolling.
@section button_scrolling On-Button scrolling

View file

@ -941,6 +941,10 @@ tp_notify_clickpadbutton(struct tp_dispatch *tp,
if (tp->device->suspended)
return 0;
/* A button click always terminates edge scrolling, even if we
* don't end up sending a button event. */
tp_edge_scroll_stop_events(tp, time);
/*
* If the user has requested clickfinger replace the button chosen
* by the softbutton code with one based on the number of fingers.

View file

@ -34,7 +34,6 @@
#define CASE_RETURN_STRING(a) case a: return #a
#define DEFAULT_SCROLL_LOCK_TIMEOUT 300 /* ms */
/* Use a reasonably large threshold until locked into scrolling mode, to
avoid accidentally locking in scrolling mode when trying to use the entire
touchpad to move the pointer. The user can wait for the timeout to trigger
@ -92,6 +91,23 @@ tp_touch_get_edge(struct tp_dispatch *tp, struct tp_touch *t)
return edge;
}
static inline void
tp_edge_scroll_set_timer(struct tp_dispatch *tp,
struct tp_touch *t)
{
const int DEFAULT_SCROLL_LOCK_TIMEOUT = 300; /* ms */
/* if we use software buttons, we disable timeout-based
* edge scrolling. A finger resting on the button areas is
* likely there to trigger a button event.
*/
if (tp->buttons.click_method ==
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS)
return;
libinput_timer_set(&t->scroll.timer,
t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT);
}
static void
tp_edge_scroll_set_state(struct tp_dispatch *tp,
struct tp_touch *t,
@ -108,8 +124,7 @@ tp_edge_scroll_set_state(struct tp_dispatch *tp,
case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
t->scroll.edge = tp_touch_get_edge(tp, t);
t->scroll.initial = t->point;
libinput_timer_set(&t->scroll.timer,
t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT);
tp_edge_scroll_set_timer(tp, t);
break;
case EDGE_SCROLL_TOUCH_STATE_EDGE:
break;

View file

@ -1349,14 +1349,11 @@ tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
uint32_t methods = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
uint32_t methods = LIBINPUT_CONFIG_SCROLL_EDGE;
if (tp->ntouches >= 2)
methods |= LIBINPUT_CONFIG_SCROLL_2FG;
if (!tp->buttons.is_clickpad)
methods |= LIBINPUT_CONFIG_SCROLL_EDGE;
return methods;
}

View file

@ -1490,6 +1490,42 @@ START_TEST(touchpad_edge_scroll)
}
END_TEST
START_TEST(touchpad_scroll_defaults)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device = dev->libinput_device;
struct libevdev *evdev = dev->evdev;
enum libinput_config_scroll_method method, expected;
enum libinput_config_status status;
method = libinput_device_config_scroll_get_methods(device);
ck_assert(method & LIBINPUT_CONFIG_SCROLL_EDGE);
if (libevdev_get_num_slots(evdev) > 1)
ck_assert(method & LIBINPUT_CONFIG_SCROLL_2FG);
if (libevdev_get_num_slots(evdev) > 1)
expected = LIBINPUT_CONFIG_SCROLL_2FG;
else
expected = LIBINPUT_CONFIG_SCROLL_EDGE;
method = libinput_device_config_scroll_get_method(device);
ck_assert_int_eq(method, expected);
method = libinput_device_config_scroll_get_default_method(device);
ck_assert_int_eq(method, expected);
status = libinput_device_config_scroll_set_method(device,
LIBINPUT_CONFIG_SCROLL_EDGE);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
status = libinput_device_config_scroll_set_method(device,
LIBINPUT_CONFIG_SCROLL_2FG);
if (libevdev_get_num_slots(evdev) > 1)
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
else
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
}
END_TEST
START_TEST(touchpad_edge_scroll_timeout)
{
struct litest_device *dev = litest_current_device();
@ -1639,6 +1675,164 @@ START_TEST(touchpad_edge_scroll_no_2fg)
}
END_TEST
START_TEST(touchpad_edge_scroll_into_buttonareas)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
enable_buttonareas(dev);
enable_edge_scroll(dev);
litest_drain_events(li);
litest_touch_down(dev, 0, 99, 40);
litest_touch_move_to(dev, 0, 99, 40, 99, 95, 10, 0);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_AXIS);
/* in the button zone now, make sure we still get events */
litest_touch_move_to(dev, 0, 99, 95, 99, 100, 10, 0);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_AXIS);
/* and out of the zone again */
litest_touch_move_to(dev, 0, 99, 100, 99, 70, 10, 0);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_AXIS);
/* still out of the zone */
litest_touch_move_to(dev, 0, 99, 70, 99, 50, 10, 0);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_AXIS);
}
END_TEST
START_TEST(touchpad_edge_scroll_within_buttonareas)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
enable_buttonareas(dev);
enable_edge_scroll(dev);
litest_drain_events(li);
litest_touch_down(dev, 0, 20, 99);
/* within left button */
litest_touch_move_to(dev, 0, 20, 99, 40, 99, 10, 0);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_AXIS);
/* over to right button */
litest_touch_move_to(dev, 0, 40, 99, 60, 99, 10, 0);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_AXIS);
/* within right button */
litest_touch_move_to(dev, 0, 60, 99, 80, 99, 10, 0);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_AXIS);
}
END_TEST
START_TEST(touchpad_edge_scroll_buttonareas_click_stops_scroll)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
double val;
enable_buttonareas(dev);
enable_edge_scroll(dev);
litest_drain_events(li);
litest_touch_down(dev, 0, 20, 95);
litest_touch_move_to(dev, 0, 20, 95, 70, 95, 10, 5);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_AXIS);
litest_button_click(dev, BTN_LEFT, true);
libinput_dispatch(li);
event = libinput_get_event(li);
ptrev = litest_is_axis_event(event,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
val = libinput_event_pointer_get_axis_value(ptrev,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
ck_assert(val == 0.0);
libinput_event_destroy(event);
event = libinput_get_event(li);
ptrev = litest_is_button_event(event,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
libinput_event_destroy(event);
/* within button areas -> no movement */
litest_touch_move_to(dev, 0, 70, 95, 90, 95, 10, 0);
litest_assert_empty_queue(li);
litest_button_click(dev, BTN_LEFT, false);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_BUTTON);
litest_touch_up(dev, 0);
}
END_TEST
START_TEST(touchpad_edge_scroll_clickfinger_click_stops_scroll)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
double val;
enable_clickfinger(dev);
enable_edge_scroll(dev);
litest_drain_events(li);
litest_touch_down(dev, 0, 20, 95);
litest_touch_move_to(dev, 0, 20, 95, 70, 95, 10, 5);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_AXIS);
litest_button_click(dev, BTN_LEFT, true);
libinput_dispatch(li);
event = libinput_get_event(li);
ptrev = litest_is_axis_event(event,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
val = libinput_event_pointer_get_axis_value(ptrev,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
ck_assert(val == 0.0);
libinput_event_destroy(event);
event = libinput_get_event(li);
ptrev = litest_is_button_event(event,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
libinput_event_destroy(event);
/* clickfinger releases pointer -> expect movement */
litest_touch_move_to(dev, 0, 70, 95, 90, 95, 10, 0);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_MOTION);
litest_assert_empty_queue(li);
litest_button_click(dev, BTN_LEFT, false);
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_BUTTON);
litest_touch_up(dev, 0);
}
END_TEST
static int
touchpad_has_palm_detect_size(struct litest_device *dev)
{
@ -3522,12 +3716,17 @@ litest_setup_tests(void)
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, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:scroll", touchpad_edge_scroll, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:scroll", touchpad_edge_scroll_no_motion, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:scroll", touchpad_edge_scroll_no_edge_after_motion, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:scroll", touchpad_edge_scroll_timeout, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:scroll", touchpad_edge_scroll_source, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:scroll", touchpad_edge_scroll_no_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_CLICKPAD);
litest_add("touchpad:scroll", touchpad_scroll_defaults, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_edge_scroll, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_edge_scroll_no_motion, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_edge_scroll_no_edge_after_motion, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_edge_scroll_timeout, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_edge_scroll_source, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_edge_scroll_no_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:scroll", touchpad_edge_scroll_into_buttonareas, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_edge_scroll_within_buttonareas, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_edge_scroll_buttonareas_click_stops_scroll, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_edge_scroll_clickfinger_click_stops_scroll, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_at_edge, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_at_bottom_corners, LITEST_TOUCHPAD, LITEST_CLICKPAD);