Skip to content

fix: composing not tracked, setEditingState kills IME, bracket pairin…#73

Closed
TheMostBlack wants to merge 1 commit into
heckmon:mainfrom
TheMostBlack:fix/ime-composing-state-corruption
Closed

fix: composing not tracked, setEditingState kills IME, bracket pairin…#73
TheMostBlack wants to merge 1 commit into
heckmon:mainfrom
TheMostBlack:fix/ime-composing-state-corruption

Conversation

@TheMostBlack
Copy link
Copy Markdown

Summary

Fix three overlapping issues: line buffer flush delay, untracked IME composing
region, and setEditingState being called during composition, which together
caused text corruption, composing state loss, and undo stack pollution.

Root Causes & Fixes

1. Composing region was completely ignored

  • Each delta carries a composing region, but the controller never tracked it.
  • currentTextEditingValue always returned an empty composing region, so the
    platform had no idea an IME composition was in progress.
  • Fix: Added a _composing field synced from delta.composing in real time.
    currentTextEditingValue now includes the correct composing region, and all
    TextEditingValue constructions pass composing: _composing.

2. setEditingState killed the IME session during composition

  • Multiple places called setEditingState while composing, forcibly terminating
    the IME session.
  • Fix:
    • Added if (isComposing) return; at the top of _syncToConnection().
    • Introduced _safelySyncEditingState() helper that skips syncing when composing.
    • Guarded selection changes (setSelection, setSelectionImmediately,
      replaceRange) with !isComposing.
    • Replaced 4 inline setEditingState calls in _handleInsertion with
      _safelySyncEditingState().

3. Bracket pairing corrupted IME text state

  • _handleInsertion performed bracket pairing (turning ( into ()) even
    during composition, breaking the IME’s internal text state.
  • Fix: Added !isComposing precondition to the bracket pairing logic.
    Typing ( while composing no longer produces (), and normal behavior
    resumes after composition ends.

4. Undo stack was polluted by individual keystrokes during composition

  • Each raw pinyin letter was recorded as a separate undo entry.
  • Fix:
    • Introduced _preComposingSelection snapshot at the start of composition.
    • While non-null, _recordInsertion and _recordDeletion are suppressed.
    • When the composition is committed, _recordReplacement records only the
      final result as an InsertOperation.
    • Cancelling the composition (Escape) leaves no undo trace.

Flutter 3.44 Compatibility

  • Flutter 3.44 added bool onFocusReceived() to DeltaTextInputClient, which
    is an abstract method in the interface, causing compilation failure for any
    class that implements it.
  • Switched CodeForgeController from implements DeltaTextInputClient to
    with DeltaTextInputClient, inheriting default implementations from the mixin.
    This prevents future Flutter upgrades from breaking the build when new methods
    are added to the interface.
  • Implemented onFocusReceived() returning true, correctly indicating that
    the controller accepts focus, which is required for normal text input behavior.
    (Returning false would prevent the input field from ever receiving focus.)

Behavior after fix

  • Chinese Pinyin input no longer loses composing state.
  • Typing ( while composing does not trigger bracket pairing.
  • Undo after committing a composition restores the text to exactly the state
    before composition started.
  • Cancelling a composition with Escape leaves the undo stack clean.

@heckmon
Copy link
Copy Markdown
Owner

heckmon commented May 27, 2026

The architecture has been completely changed for the upcoming update. You can inspect the dev branch for details. The whole text and selection management including undo stack has been moved to rust side and called via FFI.

Also an important thing is that, a third buffer has been introduced called _imeProjectionBuffer, which is small text region where the IME sees. Instead of sending whole text on each key press, only the visible region is copied to this IME buffer and send to the IME.

The version 10.0.0 is almost done and I'll release it today or tomorrow. You can check the latest updates in the dev branch.

@heckmon
Copy link
Copy Markdown
Owner

heckmon commented May 27, 2026

The new version has been released. You can contribute to the latest branch. I'm closing this outdated PR.

@heckmon heckmon closed this May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants