mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-04 17:30:28 +01:00
touchpad: Support finger-pinnnig during physical button presses
On a clickpad, one finger has be on the trackpad to trigger a physical button press. For drag and drop, we still want motion events though when a second finger is down. This patch adds finger-pinning. If the touchpad is pressed, the pressing finger is "pinned" and ignored for further motion events. A second finger may then be used to drag. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
f3accd3c05
commit
92f5860bfa
2 changed files with 85 additions and 3 deletions
|
|
@ -152,6 +152,8 @@ tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
|
|||
static inline void
|
||||
tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
|
||||
{
|
||||
struct tp_touch *tmp;
|
||||
|
||||
if (t->state != TOUCH_UPDATE) {
|
||||
tp_motion_history_reset(t);
|
||||
t->dirty = true;
|
||||
|
|
@ -160,8 +162,14 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
|
|||
assert(tp->nfingers_down >= 1);
|
||||
tp->queued |= TOUCHPAD_EVENT_MOTION;
|
||||
|
||||
if (tp->nfingers_down == 1)
|
||||
tp_for_each_touch(tp, tmp) {
|
||||
if (tmp->is_pointer)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tmp->is_pointer) {
|
||||
t->is_pointer = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,6 +344,53 @@ tp_process_key(struct tp_dispatch *tp,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_unpin_finger(struct tp_dispatch *tp)
|
||||
{
|
||||
struct tp_touch *t;
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (t->is_pinned) {
|
||||
t->is_pinned = false;
|
||||
|
||||
if (t->state != TOUCH_END &&
|
||||
tp->nfingers_down == 1)
|
||||
t->is_pointer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_pin_finger(struct tp_dispatch *tp)
|
||||
{
|
||||
struct tp_touch *t,
|
||||
*pinned = NULL;
|
||||
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (t->is_pinned) {
|
||||
pinned = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(!pinned);
|
||||
|
||||
pinned = tp_current_touch(tp);
|
||||
|
||||
if (tp->nfingers_down != 1) {
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (t == pinned)
|
||||
continue;
|
||||
|
||||
if (t->y > pinned->y)
|
||||
pinned = t;
|
||||
}
|
||||
}
|
||||
|
||||
pinned->is_pinned = true;
|
||||
pinned->is_pointer = false;
|
||||
}
|
||||
|
||||
static void
|
||||
tp_process_state(struct tp_dispatch *tp, uint32_t time)
|
||||
{
|
||||
|
|
@ -354,6 +409,15 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time)
|
|||
tp_motion_hysteresis(tp, t);
|
||||
tp_motion_history_push(t);
|
||||
}
|
||||
|
||||
/* We have a physical button down event on a clickpad. For drag and
|
||||
drop, this means we try to identify which finger pressed the
|
||||
physical button and "pin" it, i.e. remove pointer-moving
|
||||
capabilities from it.
|
||||
*/
|
||||
if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
|
||||
!tp->buttons.has_buttons)
|
||||
tp_pin_finger(tp);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -376,6 +440,9 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time)
|
|||
|
||||
tp->buttons.old_state = tp->buttons.state;
|
||||
|
||||
if (tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE)
|
||||
tp_unpin_finger(tp);
|
||||
|
||||
tp->queued = TOUCHPAD_EVENT_NONE;
|
||||
}
|
||||
|
||||
|
|
@ -441,6 +508,11 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time)
|
|||
static int
|
||||
tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time)
|
||||
{
|
||||
/* don't scroll if a clickpad is held down */
|
||||
if (!tp->buttons.has_buttons &&
|
||||
(tp->buttons.state || tp->buttons.old_state))
|
||||
return 0;
|
||||
|
||||
if (tp->nfingers_down != 2) {
|
||||
/* terminate scrolling with a zero scroll event to notify
|
||||
* caller that it really ended now */
|
||||
|
|
@ -561,8 +633,17 @@ tp_post_events(struct tp_dispatch *tp, uint32_t time)
|
|||
if (tp_post_scroll_events(tp, time) != 0)
|
||||
return;
|
||||
|
||||
if (t->history.count >= TOUCHPAD_MIN_SAMPLES &&
|
||||
tp->nfingers_down == 1) {
|
||||
if (t->history.count >= TOUCHPAD_MIN_SAMPLES) {
|
||||
if (!t->is_pointer) {
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (t->is_pointer)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!t->is_pointer)
|
||||
return;
|
||||
|
||||
tp_get_delta(t, &dx, &dy);
|
||||
tp_filter_motion(tp, &dx, &dy, time);
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ struct tp_touch {
|
|||
bool dirty;
|
||||
bool fake; /* a fake touch */
|
||||
bool is_pointer; /* the pointer-controlling touch */
|
||||
bool is_pinned; /* holds the phys. button */
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
uint32_t millis;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue