Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

MacOS Touchpad Behavior Analysis

Single Touch

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).

In AREA, i.e. above upper_thumb_line

  • Finger: Live touch, no speed threshold, free movement
  • Thumb: Live touch, no speed threshold, free movement

Below upper_thumb_line but above lower_thumb_line

  • 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

Below lower_thumb_line

  • 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.

Existing resting touch, then add second touch above

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.

Examples

1

  • 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.

2

  • 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.

3

  • 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.

4

  • 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.

5

  • 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.

6

  • 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.

Existing resting touch, then add second touch below

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.

Example

  • 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

Speed-based thumb detection

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

Recommendation: Simplify this slightly; use current logic for detecting thumbs by speed, adapted to use new thumb rules.

2+ Finger Gestures

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.

Examples

Live thumb 2-finger pinch/scroll vs. dead thumb cursor movement

  • 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)
  • 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.)

Two fingers vs. Finger + Thumb

  • 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).

Live thumb 3-finger pinch vs. dead thumb 2-finger scroll

  • 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)

Live thumb 4-finger pinch vs. dead thumb 3-finger swipe

  • 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

Live thumb 5-finger pinch vs. dead thumb 4-finger swipe

  • Behavior is identical to above (4-finger pinch)
  • macOS doesn't seem to differentiate between 4 and 5 finger pinches

Scrolling Behavior

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.)

Physical clicks

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.

Gestures with physical button down

  • 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

Tap-to-click

  • 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.

Configurable Options

  • 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.