2014-11-24 12:16:06 +01:00
|
|
|
/*
|
2015-05-28 08:23:59 +10:00
|
|
|
* Copyright © 2014-2015 Red Hat, Inc.
|
2014-11-24 12:16:06 +01:00
|
|
|
*
|
2015-06-11 12:09:18 +10:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
2014-11-24 12:16:06 +01:00
|
|
|
*
|
2015-06-11 12:09:18 +10:00
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
2014-11-24 12:16:06 +01:00
|
|
|
*/
|
|
|
|
|
|
2015-06-01 08:09:26 +10:00
|
|
|
#include "config.h"
|
|
|
|
|
|
2014-11-24 12:16:06 +01:00
|
|
|
#include <limits.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "evdev-mt-touchpad.h"
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
to do a small scroll. */
|
2015-06-19 10:11:13 +10:00
|
|
|
#define DEFAULT_SCROLL_THRESHOLD TP_MM_TO_DPI_NORMALIZED(3)
|
2014-11-24 12:16:06 +01:00
|
|
|
|
|
|
|
|
enum scroll_event {
|
|
|
|
|
SCROLL_EVENT_TOUCH,
|
|
|
|
|
SCROLL_EVENT_MOTION,
|
|
|
|
|
SCROLL_EVENT_RELEASE,
|
|
|
|
|
SCROLL_EVENT_TIMEOUT,
|
|
|
|
|
SCROLL_EVENT_POSTED,
|
|
|
|
|
};
|
|
|
|
|
|
2015-04-08 14:54:39 +10:00
|
|
|
static inline const char*
|
|
|
|
|
edge_state_to_str(enum tp_edge_scroll_touch_state state)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
CASE_RETURN_STRING(EDGE_SCROLL_TOUCH_STATE_NONE);
|
|
|
|
|
CASE_RETURN_STRING(EDGE_SCROLL_TOUCH_STATE_EDGE_NEW);
|
|
|
|
|
CASE_RETURN_STRING(EDGE_SCROLL_TOUCH_STATE_EDGE);
|
|
|
|
|
CASE_RETURN_STRING(EDGE_SCROLL_TOUCH_STATE_AREA);
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline const char*
|
|
|
|
|
edge_event_to_str(enum scroll_event event)
|
|
|
|
|
{
|
|
|
|
|
switch (event) {
|
|
|
|
|
CASE_RETURN_STRING(SCROLL_EVENT_TOUCH);
|
|
|
|
|
CASE_RETURN_STRING(SCROLL_EVENT_MOTION);
|
|
|
|
|
CASE_RETURN_STRING(SCROLL_EVENT_RELEASE);
|
|
|
|
|
CASE_RETURN_STRING(SCROLL_EVENT_TIMEOUT);
|
|
|
|
|
CASE_RETURN_STRING(SCROLL_EVENT_POSTED);
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-16 15:39:48 +10:00
|
|
|
uint32_t
|
2016-01-07 13:04:58 +10:00
|
|
|
tp_touch_get_edge(const struct tp_dispatch *tp, const struct tp_touch *t)
|
2014-11-24 12:16:06 +01:00
|
|
|
{
|
|
|
|
|
uint32_t edge = EDGE_NONE;
|
|
|
|
|
|
|
|
|
|
if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE)
|
|
|
|
|
return EDGE_NONE;
|
|
|
|
|
|
2015-03-11 09:24:52 +10:00
|
|
|
if (t->point.x > tp->scroll.right_edge)
|
2014-11-24 12:16:06 +01:00
|
|
|
edge |= EDGE_RIGHT;
|
|
|
|
|
|
2015-03-11 09:24:52 +10:00
|
|
|
if (t->point.y > tp->scroll.bottom_edge)
|
2014-11-24 12:16:06 +01:00
|
|
|
edge |= EDGE_BOTTOM;
|
|
|
|
|
|
|
|
|
|
return edge;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-03 14:33:41 +10:00
|
|
|
static inline void
|
|
|
|
|
tp_edge_scroll_set_timer(struct tp_dispatch *tp,
|
2021-03-11 14:45:17 +10:00
|
|
|
struct tp_touch *t,
|
|
|
|
|
uint64_t time)
|
2015-07-03 14:33:41 +10:00
|
|
|
{
|
2015-07-27 17:51:52 +08:00
|
|
|
const int DEFAULT_SCROLL_LOCK_TIMEOUT = ms2us(300);
|
2015-07-03 14:33:41 +10:00
|
|
|
/* 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,
|
2021-03-11 14:45:17 +10:00
|
|
|
time + DEFAULT_SCROLL_LOCK_TIMEOUT);
|
2015-07-03 14:33:41 +10:00
|
|
|
}
|
|
|
|
|
|
2014-11-24 12:16:06 +01:00
|
|
|
static void
|
|
|
|
|
tp_edge_scroll_set_state(struct tp_dispatch *tp,
|
|
|
|
|
struct tp_touch *t,
|
2021-03-11 14:45:17 +10:00
|
|
|
enum tp_edge_scroll_touch_state state,
|
|
|
|
|
uint64_t time)
|
2014-11-24 12:16:06 +01:00
|
|
|
{
|
|
|
|
|
libinput_timer_cancel(&t->scroll.timer);
|
|
|
|
|
|
2014-12-18 10:21:48 +10:00
|
|
|
t->scroll.edge_state = state;
|
2014-11-24 12:16:06 +01:00
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_NONE:
|
|
|
|
|
t->scroll.edge = EDGE_NONE;
|
|
|
|
|
break;
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
|
|
|
|
|
t->scroll.edge = tp_touch_get_edge(tp, t);
|
2015-03-11 09:24:52 +10:00
|
|
|
t->scroll.initial = t->point;
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_set_timer(tp, t, time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_EDGE:
|
|
|
|
|
break;
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_AREA:
|
|
|
|
|
t->scroll.edge = EDGE_NONE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tp_edge_scroll_handle_none(struct tp_dispatch *tp,
|
|
|
|
|
struct tp_touch *t,
|
2021-03-11 14:45:17 +10:00
|
|
|
enum scroll_event event,
|
|
|
|
|
uint64_t time)
|
2014-11-24 12:16:06 +01:00
|
|
|
{
|
|
|
|
|
switch (event) {
|
|
|
|
|
case SCROLL_EVENT_TOUCH:
|
|
|
|
|
if (tp_touch_get_edge(tp, t)) {
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_set_state(tp,
|
|
|
|
|
t,
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_EDGE_NEW,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
} else {
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_set_state(tp,
|
|
|
|
|
t,
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_AREA,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SCROLL_EVENT_MOTION:
|
|
|
|
|
case SCROLL_EVENT_RELEASE:
|
|
|
|
|
case SCROLL_EVENT_TIMEOUT:
|
|
|
|
|
case SCROLL_EVENT_POSTED:
|
2017-02-13 14:17:52 +10:00
|
|
|
evdev_log_bug_libinput(tp->device,
|
2018-02-20 13:27:10 +10:00
|
|
|
"edge-scroll: touch %d: unexpected scroll event %d in none state\n",
|
|
|
|
|
t->index,
|
2014-12-12 11:21:05 +10:00
|
|
|
event);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tp_edge_scroll_handle_edge_new(struct tp_dispatch *tp,
|
|
|
|
|
struct tp_touch *t,
|
2021-03-11 14:45:17 +10:00
|
|
|
enum scroll_event event,
|
|
|
|
|
uint64_t time)
|
2014-11-24 12:16:06 +01:00
|
|
|
{
|
|
|
|
|
switch (event) {
|
|
|
|
|
case SCROLL_EVENT_TOUCH:
|
2017-02-13 14:17:52 +10:00
|
|
|
evdev_log_bug_libinput(tp->device,
|
2018-02-20 13:27:10 +10:00
|
|
|
"edge-scroll: touch %d: unexpected scroll event %d in edge new state\n",
|
|
|
|
|
t->index,
|
2017-02-13 14:17:52 +10:00
|
|
|
event);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case SCROLL_EVENT_MOTION:
|
|
|
|
|
t->scroll.edge &= tp_touch_get_edge(tp, t);
|
|
|
|
|
if (!t->scroll.edge)
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_set_state(tp,
|
|
|
|
|
t,
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_AREA,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case SCROLL_EVENT_RELEASE:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_set_state(tp,
|
|
|
|
|
t,
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_NONE,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case SCROLL_EVENT_TIMEOUT:
|
|
|
|
|
case SCROLL_EVENT_POSTED:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_set_state(tp,
|
|
|
|
|
t,
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_EDGE,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tp_edge_scroll_handle_edge(struct tp_dispatch *tp,
|
|
|
|
|
struct tp_touch *t,
|
2021-03-11 14:45:17 +10:00
|
|
|
enum scroll_event event,
|
|
|
|
|
uint64_t time)
|
2014-11-24 12:16:06 +01:00
|
|
|
{
|
|
|
|
|
switch (event) {
|
|
|
|
|
case SCROLL_EVENT_TOUCH:
|
|
|
|
|
case SCROLL_EVENT_TIMEOUT:
|
2017-02-13 14:17:52 +10:00
|
|
|
evdev_log_bug_libinput(tp->device,
|
2018-02-20 13:27:10 +10:00
|
|
|
"edge-scroll: touch %d: unexpected scroll event %d in edge state\n",
|
|
|
|
|
t->index,
|
2014-12-12 11:21:05 +10:00
|
|
|
event);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case SCROLL_EVENT_MOTION:
|
|
|
|
|
/* If started at the bottom right, decide in which dir to scroll */
|
|
|
|
|
if (t->scroll.edge == (EDGE_RIGHT | EDGE_BOTTOM)) {
|
|
|
|
|
t->scroll.edge &= tp_touch_get_edge(tp, t);
|
|
|
|
|
if (!t->scroll.edge)
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_set_state(tp,
|
|
|
|
|
t,
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_AREA,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SCROLL_EVENT_RELEASE:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_set_state(tp,
|
|
|
|
|
t,
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_NONE,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case SCROLL_EVENT_POSTED:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tp_edge_scroll_handle_area(struct tp_dispatch *tp,
|
|
|
|
|
struct tp_touch *t,
|
2021-03-11 14:45:17 +10:00
|
|
|
enum scroll_event event,
|
|
|
|
|
uint64_t time)
|
2014-11-24 12:16:06 +01:00
|
|
|
{
|
|
|
|
|
switch (event) {
|
|
|
|
|
case SCROLL_EVENT_TOUCH:
|
|
|
|
|
case SCROLL_EVENT_TIMEOUT:
|
|
|
|
|
case SCROLL_EVENT_POSTED:
|
2017-02-13 14:17:52 +10:00
|
|
|
evdev_log_bug_libinput(tp->device,
|
2014-12-12 11:21:05 +10:00
|
|
|
"unexpected scroll event %d in area state\n",
|
|
|
|
|
event);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case SCROLL_EVENT_MOTION:
|
|
|
|
|
break;
|
|
|
|
|
case SCROLL_EVENT_RELEASE:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_set_state(tp,
|
|
|
|
|
t,
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_NONE,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tp_edge_scroll_handle_event(struct tp_dispatch *tp,
|
|
|
|
|
struct tp_touch *t,
|
2021-03-11 14:45:17 +10:00
|
|
|
enum scroll_event event,
|
|
|
|
|
uint64_t time)
|
2014-11-24 12:16:06 +01:00
|
|
|
{
|
2015-04-08 14:54:39 +10:00
|
|
|
enum tp_edge_scroll_touch_state current = t->scroll.edge_state;
|
|
|
|
|
|
|
|
|
|
switch (current) {
|
2014-11-24 12:16:06 +01:00
|
|
|
case EDGE_SCROLL_TOUCH_STATE_NONE:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_handle_none(tp, t, event, time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_handle_edge_new(tp, t, event, time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_EDGE:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_handle_edge(tp, t, event, time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_AREA:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_handle_area(tp, t, event, time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2015-04-08 14:54:39 +10:00
|
|
|
|
2019-07-10 11:56:52 +10:00
|
|
|
if (current != t->scroll.edge_state)
|
|
|
|
|
evdev_log_debug(tp->device,
|
|
|
|
|
"edge-scroll: touch %d state %s → %s → %s\n",
|
|
|
|
|
t->index,
|
|
|
|
|
edge_state_to_str(current),
|
|
|
|
|
edge_event_to_str(event),
|
|
|
|
|
edge_state_to_str(t->scroll.edge_state));
|
2014-11-24 12:16:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tp_edge_scroll_handle_timeout(uint64_t now, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct tp_touch *t = data;
|
|
|
|
|
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_handle_event(t->tp, t, SCROLL_EVENT_TIMEOUT, now);
|
2014-11-24 12:16:06 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-13 07:55:13 +10:00
|
|
|
void
|
2014-11-24 12:16:06 +01:00
|
|
|
tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device)
|
|
|
|
|
{
|
|
|
|
|
struct tp_touch *t;
|
2016-07-13 11:47:30 +10:00
|
|
|
double width, height;
|
|
|
|
|
bool want_horiz_scroll = true;
|
2016-07-15 11:31:07 +10:00
|
|
|
struct device_coords edges;
|
|
|
|
|
struct phys_coords mm = { 0.0, 0.0 };
|
2017-07-03 11:28:18 +10:00
|
|
|
int i;
|
2016-07-13 11:47:30 +10:00
|
|
|
|
2016-07-15 11:31:07 +10:00
|
|
|
evdev_device_get_size(device, &width, &height);
|
2017-02-27 11:02:06 +10:00
|
|
|
/* Touchpads smaller than 40mm are not tall enough to have a
|
2016-07-13 11:47:30 +10:00
|
|
|
horizontal scroll area, it takes too much space away. But
|
|
|
|
|
clickpads have enough space here anyway because of the
|
|
|
|
|
software button area (and all these tiny clickpads were built
|
|
|
|
|
when software buttons were a thing, e.g. Lenovo *20 series)
|
|
|
|
|
*/
|
2016-07-15 11:31:07 +10:00
|
|
|
if (!tp->buttons.is_clickpad)
|
2017-02-27 11:02:06 +10:00
|
|
|
want_horiz_scroll = (height >= 40);
|
2014-11-24 12:16:06 +01:00
|
|
|
|
2015-07-13 12:56:39 +10:00
|
|
|
/* 7mm edge size */
|
2016-07-15 11:31:07 +10:00
|
|
|
mm.x = width - 7;
|
|
|
|
|
mm.y = height - 7;
|
|
|
|
|
edges = evdev_device_mm_to_units(device, &mm);
|
2014-11-24 12:16:06 +01:00
|
|
|
|
2016-07-15 11:31:07 +10:00
|
|
|
tp->scroll.right_edge = edges.x;
|
2016-07-13 11:47:30 +10:00
|
|
|
if (want_horiz_scroll)
|
2016-07-15 11:31:07 +10:00
|
|
|
tp->scroll.bottom_edge = edges.y;
|
2016-07-13 11:47:30 +10:00
|
|
|
else
|
|
|
|
|
tp->scroll.bottom_edge = INT_MAX;
|
2014-11-24 12:16:06 +01:00
|
|
|
|
2017-07-03 11:28:18 +10:00
|
|
|
i = 0;
|
2014-11-24 12:16:06 +01:00
|
|
|
tp_for_each_touch(tp, t) {
|
2017-07-03 11:28:18 +10:00
|
|
|
char timer_name[64];
|
|
|
|
|
|
|
|
|
|
snprintf(timer_name,
|
|
|
|
|
sizeof(timer_name),
|
|
|
|
|
"%s (%d) edgescroll",
|
|
|
|
|
evdev_device_get_sysname(device),
|
|
|
|
|
i);
|
2014-11-24 12:16:06 +01:00
|
|
|
t->scroll.direction = -1;
|
|
|
|
|
libinput_timer_init(&t->scroll.timer,
|
2015-05-22 15:16:31 +10:00
|
|
|
tp_libinput_context(tp),
|
2017-07-03 11:28:18 +10:00
|
|
|
timer_name,
|
2014-11-24 12:16:06 +01:00
|
|
|
tp_edge_scroll_handle_timeout, t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2014-12-05 12:50:39 +01:00
|
|
|
tp_remove_edge_scroll(struct tp_dispatch *tp)
|
2014-11-24 12:16:06 +01:00
|
|
|
{
|
|
|
|
|
struct tp_touch *t;
|
|
|
|
|
|
2017-07-03 11:28:18 +10:00
|
|
|
tp_for_each_touch(tp, t) {
|
2014-11-24 12:16:06 +01:00
|
|
|
libinput_timer_cancel(&t->scroll.timer);
|
2017-07-03 11:28:18 +10:00
|
|
|
libinput_timer_destroy(&t->scroll.timer);
|
|
|
|
|
}
|
2014-11-24 12:16:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|
|
|
|
{
|
|
|
|
|
struct tp_touch *t;
|
|
|
|
|
|
2016-05-30 18:46:54 +10:00
|
|
|
if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE) {
|
|
|
|
|
tp_for_each_touch(tp, t) {
|
|
|
|
|
if (t->state == TOUCH_BEGIN)
|
|
|
|
|
t->scroll.edge_state =
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_AREA;
|
2016-08-22 16:06:59 +10:00
|
|
|
else if (t->state == TOUCH_END)
|
|
|
|
|
t->scroll.edge_state =
|
|
|
|
|
EDGE_SCROLL_TOUCH_STATE_NONE;
|
2016-05-30 18:46:54 +10:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-24 12:16:06 +01:00
|
|
|
tp_for_each_touch(tp, t) {
|
|
|
|
|
if (!t->dirty)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
switch (t->state) {
|
|
|
|
|
case TOUCH_NONE:
|
2014-12-11 16:39:04 +10:00
|
|
|
case TOUCH_HOVERING:
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case TOUCH_BEGIN:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_handle_event(tp,
|
|
|
|
|
t,
|
|
|
|
|
SCROLL_EVENT_TOUCH,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case TOUCH_UPDATE:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_handle_event(tp,
|
|
|
|
|
t,
|
|
|
|
|
SCROLL_EVENT_MOTION,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
2018-02-28 12:51:27 +10:00
|
|
|
case TOUCH_MAYBE_END:
|
|
|
|
|
/* This shouldn't happen we transfer to TOUCH_END
|
|
|
|
|
* before processing state */
|
|
|
|
|
evdev_log_debug(tp->device,
|
|
|
|
|
"touch %d: unexpected state %d\n",
|
|
|
|
|
t->index,
|
|
|
|
|
t->state);
|
2021-07-22 15:00:32 +10:00
|
|
|
_fallthrough_;
|
2014-11-24 12:16:06 +01:00
|
|
|
case TOUCH_END:
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_handle_event(tp,
|
|
|
|
|
t,
|
|
|
|
|
SCROLL_EVENT_RELEASE,
|
|
|
|
|
time);
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
|
|
|
|
|
{
|
2015-08-11 12:40:45 +10:00
|
|
|
struct evdev_device *device = tp->device;
|
2014-11-24 12:16:06 +01:00
|
|
|
struct tp_touch *t;
|
|
|
|
|
enum libinput_pointer_axis axis;
|
2015-03-11 09:58:11 +10:00
|
|
|
double *delta;
|
2018-01-10 11:48:58 +10:00
|
|
|
struct device_coords raw;
|
|
|
|
|
struct device_float_coords fraw;
|
2015-06-19 09:21:58 +10:00
|
|
|
struct normalized_coords normalized, tmp;
|
2015-03-11 10:36:44 +10:00
|
|
|
const struct normalized_coords zero = { 0.0, 0.0 };
|
2014-11-24 12:16:06 +01:00
|
|
|
|
|
|
|
|
tp_for_each_touch(tp, t) {
|
|
|
|
|
if (!t->dirty)
|
|
|
|
|
continue;
|
|
|
|
|
|
2019-06-18 10:16:33 +10:00
|
|
|
if (t->palm.state != PALM_NONE || tp_thumb_ignored(tp, t))
|
2015-05-21 16:32:42 +10:00
|
|
|
continue;
|
|
|
|
|
|
2015-07-13 14:14:42 +10:00
|
|
|
/* only scroll with the finger in the previous edge */
|
|
|
|
|
if (t->scroll.edge &&
|
|
|
|
|
(tp_touch_get_edge(tp, t) & t->scroll.edge) == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
2014-11-24 12:16:06 +01:00
|
|
|
switch (t->scroll.edge) {
|
|
|
|
|
case EDGE_NONE:
|
|
|
|
|
if (t->scroll.direction != -1) {
|
|
|
|
|
/* Send stop scroll event */
|
2018-11-22 10:24:54 +10:00
|
|
|
evdev_notify_axis_finger(device,
|
|
|
|
|
time,
|
|
|
|
|
bit(t->scroll.direction),
|
|
|
|
|
&zero);
|
2014-11-24 12:16:06 +01:00
|
|
|
t->scroll.direction = -1;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
case EDGE_RIGHT:
|
|
|
|
|
axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
|
2015-03-11 09:58:11 +10:00
|
|
|
delta = &normalized.y;
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
case EDGE_BOTTOM:
|
|
|
|
|
axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
|
2015-03-11 09:58:11 +10:00
|
|
|
delta = &normalized.x;
|
2014-11-24 12:16:06 +01:00
|
|
|
break;
|
|
|
|
|
default: /* EDGE_RIGHT | EDGE_BOTTOM */
|
|
|
|
|
continue; /* Don't know direction yet, skip */
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-10 11:48:58 +10:00
|
|
|
raw = tp_get_delta(t);
|
|
|
|
|
fraw.x = raw.x;
|
|
|
|
|
fraw.y = raw.y;
|
2015-08-06 14:59:38 +10:00
|
|
|
/* scroll is not accelerated */
|
2018-01-10 11:48:58 +10:00
|
|
|
normalized = tp_filter_motion_unaccelerated(tp, &fraw, time);
|
2014-11-24 12:16:06 +01:00
|
|
|
|
2015-03-06 14:36:31 +10:00
|
|
|
switch (t->scroll.edge_state) {
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_NONE:
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_AREA:
|
2017-02-13 14:17:52 +10:00
|
|
|
evdev_log_bug_libinput(device,
|
2015-03-06 14:36:31 +10:00
|
|
|
"unexpected scroll state %d\n",
|
|
|
|
|
t->scroll.edge_state);
|
|
|
|
|
break;
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
|
2015-06-19 09:21:58 +10:00
|
|
|
tmp = normalized;
|
2015-03-24 13:14:18 +01:00
|
|
|
normalized = tp_normalize_delta(tp,
|
|
|
|
|
device_delta(t->point,
|
|
|
|
|
t->scroll.initial));
|
2015-03-24 13:14:17 +01:00
|
|
|
if (fabs(*delta) < DEFAULT_SCROLL_THRESHOLD)
|
|
|
|
|
normalized = zero;
|
2015-06-19 09:21:58 +10:00
|
|
|
else
|
|
|
|
|
normalized = tmp;
|
2015-03-06 14:36:31 +10:00
|
|
|
break;
|
|
|
|
|
case EDGE_SCROLL_TOUCH_STATE_EDGE:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*delta == 0.0)
|
2014-11-24 12:16:06 +01:00
|
|
|
continue;
|
|
|
|
|
|
2018-11-22 10:24:54 +10:00
|
|
|
evdev_notify_axis_finger(device, time,
|
|
|
|
|
bit(axis),
|
|
|
|
|
&normalized);
|
2014-11-24 12:16:06 +01:00
|
|
|
t->scroll.direction = axis;
|
|
|
|
|
|
2021-03-11 14:45:17 +10:00
|
|
|
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_POSTED, time);
|
2014-11-24 12:16:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0; /* Edge touches are suppressed by edge_scroll_touch_active */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time)
|
|
|
|
|
{
|
2015-08-11 12:40:45 +10:00
|
|
|
struct evdev_device *device = tp->device;
|
2014-11-24 12:16:06 +01:00
|
|
|
struct tp_touch *t;
|
2015-03-11 10:36:44 +10:00
|
|
|
const struct normalized_coords zero = { 0.0, 0.0 };
|
2014-11-24 12:16:06 +01:00
|
|
|
|
|
|
|
|
tp_for_each_touch(tp, t) {
|
|
|
|
|
if (t->scroll.direction != -1) {
|
2018-11-22 10:24:54 +10:00
|
|
|
evdev_notify_axis_finger(device,
|
|
|
|
|
time,
|
|
|
|
|
bit(t->scroll.direction),
|
|
|
|
|
&zero);
|
2014-11-24 12:16:06 +01:00
|
|
|
t->scroll.direction = -1;
|
2015-05-25 11:36:34 +10:00
|
|
|
/* reset touch to area state, avoids loading the
|
|
|
|
|
* state machine with special case handling */
|
|
|
|
|
t->scroll.edge = EDGE_NONE;
|
|
|
|
|
t->scroll.edge_state = EDGE_SCROLL_TOUCH_STATE_AREA;
|
2014-11-24 12:16:06 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2016-01-07 13:04:58 +10:00
|
|
|
tp_edge_scroll_touch_active(const struct tp_dispatch *tp,
|
|
|
|
|
const struct tp_touch *t)
|
2014-11-24 12:16:06 +01:00
|
|
|
{
|
2014-12-18 10:21:48 +10:00
|
|
|
return t->scroll.edge_state == EDGE_SCROLL_TOUCH_STATE_AREA;
|
2014-11-24 12:16:06 +01:00
|
|
|
}
|