Skip to content

Two-thumb: deleted gesture trail leaks into the next fresh swipe (ghost-merge, esp. at start of a text box) #60

Description

@SHAWNERZZ

Summary

Under two-thumb multi-part composition, a previous gesture's stroke geometry can leak into the next fresh swipe, fusing a deleted word's swipe into the new one. It is most visible when swiping a fresh word at the start of a text box: the new word comes out merged with previously-deleted gesture geometry instead of being recognized on its own.

Root cause

WordComposer.mExtendBatchInputBase (the multi-part merged-trail base consumed by WordComposer.setBatchInputPointers) is only cleared by a normally-completing gesture — onUpdateTailBatchInputCompleted, which is the lone routine clear and sits after two empty-recognition early-returns. An abnormal gesture end leaves mExtendBatchInputBaseSet armed:

  • onCancelBatchInput never clears it,
  • the empty-top-word early-returns in onUpdateTailBatchInputCompleted skip the clear,
  • WordComposer.reset() doesn't touch it, so no deletion path clears it either.

Once leaked, the flag survives every backspace / selection-delete / commit. A later fresh gesture (no composing word ⇒ onStartBatchInput's extend branch never runs, so it neither sets nor clears the base) hits the merge guard in setBatchInputPointers and prepends the ghost trail. Start-of-text-box maximizes visibility because there is no composing word there to legitimately re-set the base.

This is the same class of bug as the mLiveStroke handling, which is already dropped on every word-end path; mExtendBatchInputBase simply never got the same treatment.

Steps to reproduce

  1. Enable two-thumb typing (manual spacing or combining grace).
  2. Swipe a word, then trigger an abnormal gesture end (cancel a follow-up gesture, or hit an empty recognition).
  3. Delete everything.
  4. Swipe a fresh word at the start of the text box.

Expected: the fresh word is recognized on its own.
Actual: it sometimes fuses with the previously-deleted gesture's geometry.

Proposed fix

Clear mExtendBatchInputBase at the same word-end sites where mLiveStroke is already dropped (handleBackspaceEvent, resetComposingState, commitChosenWord, the composing-desync recovery) plus the two gesture-lifecycle origins (onStartBatchInput top, onCancelBatchInput). This avoids touching the hot WordComposer.reset() path. PR to follow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions