mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-04 17:30:28 +01:00
touchpad: restore thumb detection while keeping fixes from !292
!292 improved libinput's ability to detect multiple-finger clicks when the fingers were not aligned close to horizontally. However that caused thumb detection to fail in several use cases. This patch restores thumb detection for - 2+ finger physical clickpad presses - resting thumb while two-finger scrolling - touches in the thumb exclusion area during multi-finger taps and improves pinch detection when thumb is centered below fingers. It also further enhances the flexibility of finger position for 2-, 3-, or 4-finger taps: if all tapping fingers land on the touchpad within a short time (currently 100ms), they will all count regardless of position (unless below the lower_thumb_line). Signed-off-by: Matt Mayfield <mdmayfield@yahoo.com>
This commit is contained in:
parent
4ff6d6e317
commit
73870d938e
4 changed files with 62 additions and 27 deletions
|
|
@ -390,28 +390,30 @@ tp_gesture_handle_state_none(struct tp_dispatch *tp, uint64_t time)
|
|||
first = touches[0];
|
||||
second = touches[1];
|
||||
|
||||
/* For 3+ finger gestures we cheat. A human hand's finger
|
||||
* arrangement means that for a 3 or 4 finger swipe gesture, the
|
||||
* fingers are roughly arranged in a horizontal line.
|
||||
* They will all move in the same direction, so we can simply look
|
||||
* at the left and right-most ones only. If we have fake touches, we
|
||||
* just take the left/right-most real touch position, since the fake
|
||||
* touch has the same location as one of those.
|
||||
/* For 3+ finger gestures, we only really need to track two touches.
|
||||
* The human hand's finger arrangement means that for a pinch, the
|
||||
* bottom-most touch will always be the thumb, and the top-most touch
|
||||
* will always be one of the fingers.
|
||||
*
|
||||
* For a 3 or 4 finger pinch gesture, 2 or 3 fingers are roughly in
|
||||
* a horizontal line, with the thumb below and left (right-handed
|
||||
* users) or right (left-handed users). Again, the row of non-thumb
|
||||
* fingers moves identically so we can look at the left and
|
||||
* right-most only and then treat it like a two-finger
|
||||
* gesture.
|
||||
* For 3+ finger swipes, the fingers will likely (but not necessarily)
|
||||
* be in a horizontal line. They all move together, regardless, so it
|
||||
* doesn't really matter which two of those touches we track.
|
||||
*
|
||||
* Tracking top and bottom is a change from previous versions, where
|
||||
* we tracked leftmost and rightmost. This change enables:
|
||||
*
|
||||
* - More accurate pinch detection if thumb is near the center
|
||||
* - Better resting-thumb detection while two-finger scrolling
|
||||
* - On capable hardware, allow 3- or 4-finger swipes with resting
|
||||
* thumb or held-down clickpad
|
||||
*/
|
||||
if (ntouches > 2) {
|
||||
second = touches[0];
|
||||
|
||||
for (i = 1; i < ntouches && i < tp->num_slots; i++) {
|
||||
if (touches[i]->point.x < first->point.x)
|
||||
if (touches[i]->point.y < first->point.y)
|
||||
first = touches[i];
|
||||
else if (touches[i]->point.x > second->point.x)
|
||||
else if (touches[i]->point.y >= second->point.y)
|
||||
second = touches[i];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
/* distance between fingers to assume it is not a scroll */
|
||||
#define SCROLL_MM_X 35
|
||||
#define SCROLL_MM_Y 25
|
||||
#define THUMB_TIMEOUT ms2us(100)
|
||||
|
||||
static inline const char*
|
||||
thumb_state_to_str(enum tp_thumb_state state)
|
||||
|
|
@ -271,13 +272,15 @@ tp_thumb_update_multifinger(struct tp_dispatch *tp)
|
|||
struct tp_touch *t;
|
||||
struct tp_touch *first = NULL,
|
||||
*second = NULL,
|
||||
*newest = NULL;
|
||||
*newest = NULL,
|
||||
*oldest = NULL;
|
||||
struct device_coords distance;
|
||||
struct phys_coords mm;
|
||||
|
||||
unsigned int speed_exceeded_count = 0;
|
||||
|
||||
/* Get the first and second bottom-most touches, the max speed exceeded
|
||||
* count overall, and the newest touch (or one of them, if more).
|
||||
* count overall, and the newest and oldest touches.
|
||||
*/
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (t->state == TOUCH_NONE ||
|
||||
|
|
@ -290,6 +293,10 @@ tp_thumb_update_multifinger(struct tp_dispatch *tp)
|
|||
speed_exceeded_count = max(speed_exceeded_count,
|
||||
t->speed.exceeded_count);
|
||||
|
||||
if (!oldest || t->initial_time < oldest->initial_time) {
|
||||
oldest = t;
|
||||
}
|
||||
|
||||
if (!first) {
|
||||
first = t;
|
||||
continue;
|
||||
|
|
@ -315,11 +322,12 @@ tp_thumb_update_multifinger(struct tp_dispatch *tp)
|
|||
|
||||
/* Speed-based thumb detection: if an existing finger is moving, and
|
||||
* a new touch arrives, mark it as a thumb if it doesn't qualify as a
|
||||
* 2-finger scroll.
|
||||
* 2-finger scroll. Also account for a thumb dropping onto the touchpad
|
||||
* while scrolling or swiping.
|
||||
*/
|
||||
if (newest &&
|
||||
tp->thumb.state == THUMB_STATE_FINGER &&
|
||||
tp->nfingers_down == 2 &&
|
||||
tp->nfingers_down >= 2 &&
|
||||
speed_exceeded_count > 5 &&
|
||||
(tp->scroll.method != LIBINPUT_CONFIG_SCROLL_2FG ||
|
||||
(mm.x > SCROLL_MM_X || mm.y > SCROLL_MM_Y))) {
|
||||
|
|
@ -330,20 +338,43 @@ tp_thumb_update_multifinger(struct tp_dispatch *tp)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Position-based thumb detection: When a new touch arrives, check the
|
||||
* two lowest touches. If they qualify for 2-finger scrolling, clear
|
||||
* thumb status.
|
||||
/* Contextual thumb detection: When a new touch arrives, check the
|
||||
* timing and position of the two lowest touches.
|
||||
*
|
||||
* If they were in distinct diagonal position, then mark the lower
|
||||
* touch (based on pinch_eligible) as either PINCH or SUPPRESSED. If
|
||||
* we're too close together for a thumb, lift that.
|
||||
* If both touches are very close, regardless of timing, and no matter
|
||||
* their absolute position on the touchpad, count them both as live
|
||||
* to support responsive two-finger scrolling.
|
||||
*/
|
||||
if (mm.y > SCROLL_MM_Y && mm.x > SCROLL_MM_X) {
|
||||
|
||||
if (mm.x < SCROLL_MM_X && mm.y < SCROLL_MM_Y) {
|
||||
tp_thumb_lift(tp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If all the touches arrived within a very short time, and all of them
|
||||
* are above the lower_thumb_line, assume the touches are all live to
|
||||
* enable double, triple, and quadruple taps, clicks, and gestures. (If
|
||||
* there is an actual resting thumb, it will be detected later based on
|
||||
* the behavior of the other touches.)
|
||||
*/
|
||||
|
||||
if ((newest->initial_time - oldest->initial_time) < THUMB_TIMEOUT &&
|
||||
first->point.y < tp->thumb.lower_thumb_line) {
|
||||
tp_thumb_lift(tp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we're past the THUMB_TIMEOUT, and the touches are relatively far
|
||||
* apart, then the new touch is unlikely to be a tap or clickfinger.
|
||||
* Proceed with pre-1.14.901 thumb detection.
|
||||
*/
|
||||
|
||||
if (mm.y > SCROLL_MM_Y) {
|
||||
if (tp->thumb.pinch_eligible)
|
||||
tp_thumb_pinch(tp, first);
|
||||
else
|
||||
tp_thumb_suppress(tp, first);
|
||||
} else if (mm.x < SCROLL_MM_X && mm.y < SCROLL_MM_Y) {
|
||||
} else {
|
||||
tp_thumb_lift(tp);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -350,6 +350,7 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
|||
t->dirty = true;
|
||||
t->state = TOUCH_BEGIN;
|
||||
t->time = time;
|
||||
t->initial_time = time;
|
||||
t->was_down = true;
|
||||
tp->nfingers_down++;
|
||||
t->palm.time = time;
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ struct tp_touch {
|
|||
bool dirty;
|
||||
struct device_coords point;
|
||||
uint64_t time;
|
||||
uint64_t initial_time;
|
||||
int pressure;
|
||||
bool is_tool_palm; /* MT_TOOL_PALM */
|
||||
int major, minor;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue