On a MacBook Air with 104mm x 76mm touchpad, macOS appears to put its equivalent of upper_thumb_line 20mm from the bottom, and lower_thumb_line 10mm from the bottom. On Magic Trackpad, 130mm x 108mm active area, these seem to be the same (20mm/10mm from bottom).
- Finger: Live touch, no speed threshold, free movement
- Thumb: Live touch, no speed threshold, free movement
- Finger: Live touch, no speed threshold, free movement
- Thumb: "Mostly dead" touch until (speed threshold exceeded OR crosses north of upper_thumb_line), then live with free movement
- Finger: "Mostly dead" touch until (speed threshold exceeded OR crosses north of lower_thumb_line), then live with free movement
- Thumb: "Mostly dead" touch until (speed threshold exceeded OR crosses north of upper_thumb_line), then live with free movement
Recommendation: Use existing logic to degrade performance gracefully on semi-MT TPs. On TPs with plenty of slots but no presure/size, give all first touches the same behavior as HW-detected thumbs. On TPs with pressure/size, treat all first touches south of lower_thumb_line as thumbs; follow HW-detected thumb status for touches that move or start north of lower_thumb_line.
In general, a higher-positioned touch will immediately turn a lower resting touch into a temporary thumb ("mostly dead"). When the higher touch is lifted, the resting touch once in its lifetime will immediately revert to the status of a new single touch (making a new shape + position check for whether a speed threshold applies). After this, if the lower touch is turned into a thumb again by a second higher touch, the lower touch becomes permanently and unconditionally a thumb (dead).
A lower touch always becomes a thumb for life unconditionally when it is turned into a temporary thumb for the second time, regardless of whether it actually moved or broke a speed threshold in between the two upper touches.
This could be considered a "two strikes and you're out" policy for thumbhood.
Handedness does not appear to be a factor; all tests were observed to work symmetrically.
- Rest thumb south of upper_thumb_line.
- Add a finger, move cursor. Lift finger.
- Move thumb slowly - touch stays dead; nothing happens.
- Move thumb quickly - touch becomes live and cursor moves.
- Add a finger again, move cursor. Lift finger.
- Move thumb slowly - touch stays dead; nothing happens.
- Move thumb quickly - touch stays dead; nothing happens.
- Rest thumb south of upper_thumb_line.
- Add a finger, move cursor. Lift finger. (Do not move thumb)
- Add a finger again, move cursor. Lift finger.
- Move thumb slowly - touch stays dead; nothing happens.
- Move thumb quickly - touch stays dead; nothing happens.
- Rest index finger #1 anywhere above lower_thumb_line.
- Add opposite hand index finger #2 30-50mm above and to one side, move cursor. Lift finger #2.
- Move finger #1 slowly - touch becomes live and cursor moves.
- Move finger #1 quickly - touch becomes live and cursor moves.
- Add opposite hand index finger #2 again 30-50mm above and to one side, move cursor. Lift finger #2.
- Move finger #1 slowly - touch stays dead; nothing happens.
- Move finger #1 quickly - touch stays dead; nothing happens.
- Rest index finger #1 anywhere above lower_thumb_line.
- Add opposite hand index finger #2 30-50mm above and to one side, move cursor. Lift finger #2. (Do not move finger #1)
- Add opposite hand index finger #2 30-50mm above and to one side, move cursor. Lift finger #2.
- Move finger #1 slowly - touch stays dead; nothing happens.
- Move finger #1 quickly - touch stays dead; nothing happens.
- Rest index finger #1 anywhere below lower_thumb_line.
- Add opposite hand index finger #2 30-50mm above and to either side, move cursor. Lift finger #2.
- Move finger #1 slowly - touch stays dead; nothing happens.
- Move finger #1 quickly - touch becomes live and cursor moves.
- Add opposite hand index finger #2 again 30-50mm above and to either side, move cursor. Lift finger #2.
- Move finger #1 slowly - touch stays dead; nothing happens.
- Move finger #1 quickly - touch stays dead; nothing happens.
- Rest index finger #1 anywhere below lower_thumb_line.
- Add opposite hand index finger #2 30-50mm above and to either side, move cursor. Lift finger #2. (Do not move finger #1)
- Add opposite hand index finger #2 again 30-50mm above and to either side, move cursor. Lift finger #2.
- Move finger #1 slowly - touch stays dead; nothing happens.
- Move finger #1 quickly - touch stays dead; nothing happens.
If there is an existing live touch, and a second touch appears below it, the second touch begins its life as a "mostly dead" temporary thumb. However this status does not count against its "two strikes" before becoming a permanent thumb. All speed threshold rules based on position and HW thumb detection apply as above.
- Place finger #1 on the upper half of the touchpad
- Observe touch #1 is live and can move the cursor
- Place finger #2 30-50mm below and to the side, but above the lower_thumb_line
- Observe touch #1 is still live, but #2 is now (temporarily) dead
- Lift finger #1
- Finger #2 immediately becomes live again (subject to speed threshold rules based on size/shape and Y position, as above)
- Place finger #1 again
- Observe #1 is live and #2 is now (permanently) dead
- Lift finger #1
- Observe touch #2 remains dead
Seems fairly similar to current implementation in libinput 1.11.9, except with "mostly dead" temporary thumb instead of permanent.
-
Place one finger on TP and move it around moderately quickly
-
Rest second finger anywhere >25mm from it while it is still moving
- Second finger detected apparently by speed
- Becomes a temporary thumb as above; if detected again, becomes permanent thumb
-
Place one finger on TP and move it around moderately quickly
-
Rest second finger <25mm near it while it is still moving
- Some very hard-to-analyze complexity/inconsistency exists around this
- Scroll gesture usually begins
- Sometimes only the moving finger would continue to be live
- Sometimes a scroll gesture would start but then be cancelled, returning mouse cursor control to one of the fingers
- Some very hard-to-analyze complexity/inconsistency exists around this
Recommendation: Simplify this slightly; use current logic for detecting thumbs by speed, adapted to use new thumb rules.
With a few rare exceptions, experimentation didn't show evidence of timeouts used to determine gesture mode; the interpretation of gestures is primarily based on positional and speed thresholds.
Permanently "dead" thumbs never count toward gesture detection. A temporary thumb usually doesn't count toward gesture detection, but does in certain circumstances; see below.
Surprisingly, HW size/shape thumb detection doesn't seem enter into this, except for a few edge cases involving touches below the lower_thumb_line.
Recommendation: Use existing logic to degrade performance gracefully on semi-MT TPs. On full-MT TPs with enough slots, but no size/pressure, give the lowest touch the same behavior as a HW-detected thumb. Otherwise follow HW-detected thumb status.
The gesture detection continues to allow cursor movement/2-finger scrolling (from the non-lowest touch(es), regardless of HW thumb size/pressure) until both touches move enough to reveal the type of gesture, OR a touch exceeds a speed threshold and the gesture detection is abandoned. Implementing this would require some added logic to tp_gesture_handle_state_unknown
and the circumstances in which tp_gesture_post_events
calls tp_gesture_post_pointer_motion
.
Thumb + >=3-finger gestures have more complex behavior shown below.
- Place thumb and finger both on TP, at any angle, separated by 5 - 50 mm
- If thumb is kept still (within 2mm) while finger moves (>2mm)
- Finger continues to control cursor, uninterrupted, as if it were the only touch, until one of these happens:
- If finger OR thumb exceeds a speed threshold, thumb becomes "mostly dead" temporary thumb as above, gesture cancelled
- If finger does not exceed the speed treshold, AND thumb begins moving >2mm, pinch or scroll begins (based on directions)
- If finger is kept still (within 2mm) while thumb moves (>2mm)
- Finger (not thumb!) controls cursor as if it were the only touch, until one of these happens:
- If finger OR thumb exceeds a speed threshold, thumb becomes "mostly dead" temporary thumb as above, gesture cancelled
- If thumb does not exceed the speed treshold, AND finger begins moving >2mm, pinch or scroll begins (based on directions)
- If thumb is kept still (within 2mm) while finger moves (>2mm)
- Place thumb and finger both on TP > 50mm apart
- Only pinch gesture is possible
- Other rules from above apply
Note that the finger and thumb can begin their touches at any time and in either order; there is no timeout where any particular gesture is assumed. As long as both touches don't exceed the speed or distance thresholds, they are both gesture-eligible even though the lower becomes a (provisional) temporary thumb for cursor movement purposes.
Ideally, resting a thumb anywhere on the touchpad still allows for both gestures AND cursor movement; while moving the cursor with one finger is not interrupted by dropping a resting thumb (even if the movement is too slow for speed-based detection).
Recommendation: Explore using tp_get_combined_touches_delta
to move the cursor while the gesture state is unknown AND neither touch has exceeded the speed threshold and triggered thumb detection. (I've occasionally witnessed a brief slowdown of cursor speed when dropping a resting thumb; that suggests Apple may be doing something like this.)
- A HW-detected thumb below the upper_thumb_line, but above the lower_thumb_line, is NOT required to exceed the normal thumb speed threshold. Instead, the gesture speed threshold applies.
- If a HW-detected thumb is below the lower_thumb_line, it must rise above the lower_thumb_line before it counts toward a pinch.
- If a HW-detected finger is below the lower_thumb_line, the normal gesture speed threshold applies.
- Otherwise, thumb/finger vs. 2-finger behavior is identical; higher touch counts as "finger" and lower as "thumb"
- HW thumb detection does not seem to be a factor except regarding the lower_thumb_line
- A HW-detected thumb may count as a finger in a two-finger scroll if it is inline with the finger and moves appropriately
Recommendation: Simplify thumb logic by treating all gesture touches below the lower_thumb_line like Apple treats size-based thumbs there (since pressure-based is unreliable at the edge, and it seems not worth implementing just for size-based).
- Same as 2-finger pinch above, except scrolling instead of cursor movement
- Once a pinch OR scroll begins, the opposite is disqualified
- There is no timeout to default to one or the other
- If ONLY thumb moves, it becomes dead (much like 2-finger situation above)
- If ONLY fingers move, thumb becomes dead (much like 2-finger situation above)
- Place thumb and 3 fingers near-simultaneously
- 3-finger swipe is impossible; moving fingers alone does nothing
- Moving thumb + fingers toward/away from each other begins 4-finger pinch
- Place thumb, wait about 200ms, place 3 fingers
- In this state either 3fg-swipe or 4fg-pinch is possible
- Follow similar positional threshold logic as 2fg pinch above
- A HW-detected thumb may count as a finger in a swipe if it is inline with fingers and moves appropriately
- Behavior is identical to above (4-finger pinch)
- macOS doesn't seem to differentiate between 4 and 5 finger pinches
On macOS, two-finger scrolling is constrained to 90° angles - the scroll is rounded off to the nearest cardinal direction. As a side effect, scrolling very near a 45° diagonal results in a "stairstep" movement if the scroll wanders back and forth between the two directions.
(Strangely, I never noticed this before, despite using Mac touchpads for over a decade.)
MacOS behavior when the clickpad is physically pressed follows logically from the thumb detection described above:
- If one or more touches exist above the clicking thumb, the thumb becomes a "temporary thumb" and does not count toward clickfinger.
- If two or three fingers click side-by-side (anywhere on the touchpad), no thumb is detected and all touches count toward clickfinger.
- Two fingers must be within 50mm horizontally to count as a right-click.
- Two fingers must be within 35mm vertically to count as a right-click.
- HW thumb detection prevents a finger + a thumb from counting as a right-click (even if the touches are very close); it counts as a left-click instead.
- In the event of a physical right-click-drag with two fingers but without a thumb, upon clickpad physical button press, both fingers control the cursor together, apparently without changing thumb state (like
tp_get_combined_touches_delta
?) but without triggering a scroll gesture. - MacOS does not support a 3-finger middle click. IF a physical middle-click with three fingers is attempted, a left-click occurs. If a physical middle-click-drag with 3 fingers and no thumb is attempted, a 3-finger swipe or pinch gesture initiates.
Recommendation: Don't follow MacOS on the 3-finger clicks; keep the ability to middle-click. On a physical click with 2-3 fingers but no thumb, temporarily disable scroll, swipe, and pinch gestures.
- 2+ finger gestures are allowed, and behave the same, with the clickpad button down
- The other thumb-detection logic keeps the behavior predictable in this case:
- A moving thumb can be used to drag things at first
- If the thumb is below the upper_thumb_line, it's hard to move accidentally because of the speed threshold
- If moving fingers become involved, the thumb will become (temporarily, then permanently) a thumb
- Two or three fingers above the thumb will affect the thumb's state in the same way as a single finger
- Two fingers must be within 50mm horizontally to count as a right-click.
- Two fingers must be within 35mm vertically to count as a right-click.
- HW thumb detection causes a thumb + finger tap-to-click to be completely ignored when next to each other (no click).
- If the thumb is lower than the other touch, it counts as a left-click.
- MacOS does not support three-finger middle-clicks, but can enable a "look up" feature when tapping with three fingers.
- Three fingers can count as a special click even when spaced across the entire touchpad horizontally (approx. 100mm).
- Three fingers can count as a special click even when spaced across the entire touchpad vertically (approx. 70mm).
- HW thumb detection causes a thumb + two fingers tap-to-click to be completely ignored when in a horizontal row (no click).
- If the thumb is lower than the other touches, it counts as a right-click.
- Tapping with a thumb works only when the thumb is the only active touch, AND there is no other "permanently dead" thumb on the TP.
- Attempting to steer the cursor with a thumb, and tap with a finger, leads to predictably counterproductive results as expected from "Two Strikes" thumb detection.
- On macOS right click can be set to:
- Click or tap with two fingers
- Click in bottom right corner
- Click in bottom left corner
- When one of the latter two options is chosen, thumb detection is the same as the first option.
- The secondary-click area on the lower left or right of the touchpad is less than 50% of the touchpad width - more like 30% of the width, or 30mm, whichever is smaller.