Conversation
Replace the Windows TextInput.show/hide no-ops with Chromium-shaped touch-keyboard control: TSF owns the IME session (ITextStoreACP with TS_SD_INPUTPANEMANUALDISPLAYENABLE) so the OS does not auto-invoke the SIP, and IInputPane2 TryShow/TryHide with a 300ms debounce owns visibility. OccludedRect is converted from root-window client DIPs to physical pixels before viewInsets.bottom is sent. Fixes flutter#97269 Fixes flutter#99050 Fixes flutter#119807 Fixes flutter#135492 Fixes flutter#187722 Co-authored-by: Kevin McDermott-Carpenter <kevin.mcdermottcarpenter@ou.ac.uk>
The geometry source_set is not a dep of flutter_windows_unittests, so gn check rejects a direct include. Rect/Size already come in through tsf_text_store.h. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Windows SIP heuristics follow the TSF document associated with the HWND, not thread focus. Chromium never AssociateFocuses an editable store onto the window: editors use SetFocus only, and TEXT_INPUT_TYPE_NONE uses AssociateFocus of the empty document only. Flutter tap-outside does not clearClient, so a pointer that misses the field now maps to NONE. InputPane hide still does not change TSF. Co-authored-by: Kevin McDermott-Carpenter <kevin.mcdermottcarpenter@ou.ac.uk>
KevMCarp
pushed a commit
that referenced
this pull request
Sep 9, 2026
…termination (flutter#192294) ## Description When a target application process exits prematurely (e.g. exit code 255) before the Debug Adapter Protocol (DAP) initialization handshake completes, `flutter_tools` crashed with an unhandled `DebugAdapterException` in the Dart Zone. In Flutter 3.47.2 telemetry, this was the #3 top crasher with 203 crashes (`DebugAdapterException-34d39b25`). ### Root Cause 1. `FlutterBaseDebugAdapter.handleSessionTerminate` completed `debuggerInitializationFailedCompleter.completeError(...)` before calling `super.handleSessionTerminate(...)`. 2. In `package:dap_adapters` (`DartDebugAdapter`), `handleSessionTerminate` is asynchronous and awaits pending output events before setting `isTerminating = true`. 3. In `FlutterDebugAdapter._handleAppStarted`, the unawaited asynchronous message handler caught the error while `isTerminating` was still `false`, rethrowing `DebugAdapterException` into the Zone. ### Fix 1. Synchronously set `isTerminating = true` in `FlutterBaseDebugAdapter.handleSessionTerminate`. 2. In `FlutterDebugAdapter._handleAppStarted`, catch `DebugAdapterException` and send the message to console output rather than rethrowing into the Zone. 3. Clean up early termination message formatting when `exitSuffix` is provided. ## Related Issues * Fixes crasher `DebugAdapterException-34d39b25` in Flutter 3.47.1 and 3.47.2 telemetry. ## Tests * Added regression tests in `packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart` and `flutter_test_adapter_test.dart` verifying that early process exit outputs cleanly to console and does not produce unhandled asynchronous exceptions.
AssociateFocus does not AddRef the document manager, so the bridge now unassociates the HWND before releasing TSF documents. Null FocusNonEditable reuses the last HWND instead of forgetting it. The Win11 dummy NONE store reports the HWND from GetWnd, matching Chromium SetFocusedTextInputClient. Co-authored-by: Kevin McDermott-Carpenter <kevin.mcdermottcarpenter@ou.ac.uk>
InputPane is MANUALDISPLAYENABLE, so AssociateFocus alone does not hide the pane. A miss (or a tap with no text client) now TryHides as well as switching TSF to NONE. A hit on the field unsuppresses and Displays without waiting for a second TextInput.show. Requested TryHide no longer clears the pointer latch, so the same tap's setClient/show is not ignored. User dismiss still suppresses until a later field tap. Co-authored-by: Kevin McDermott-Carpenter <kevin.mcdermottcarpenter@ou.ac.uk>
Chromium applies TEXT_INPUT_TYPE_NONE at the type change (clearClient / AssociateFocus empty), not on later pointers. TryHide or AssociateFocus on those taps races the OS auto-show and pops the keyboard. Tap-outside while a client is attached still maps to NONE plus TryHide, because Flutter does not clearClient on blur. Co-authored-by: Kevin McDermott-Carpenter <kevin.mcdermottcarpenter@ou.ac.uk>
KevMCarp
force-pushed
the
kevin/windows-tsf-052c
branch
2 times, most recently
from
September 18, 2026 20:58
c26a8b7 to
7caa463
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Windows SIP heuristics follow the TSF document associated with the HWND, not thread focus. After tap-outside the keyboard was closable but pop / later UI still reopened it because we
AssociateFocus’d the editable store onto the Flutter window.Chromium (
ui/base/ime/win)ITfThreadMgr::SetFocus(editable)onlyFocusEditableno longerAssociateFocuses the HWNDAssociateFocus(hwnd, empty_doc)only (internally SetFocuses; they never call both)FocusNonEditablematches thatITextStoreACP+KEYBOARD_DISABLED/EMPTYCONTEXT,TS_SD_READONLY, denyRequestLockTryShow/TryHide; Showing/Hiding only notify observersOnTextInputTypeChanged(NONE)clearClient, so a pointer that misses the field maps to NONETS_SD_INPUTPANEMANUALDISPLAYENABLEis still always set. Chromium still callsTryShow(TODO to drop it once TSF input-pane policy is “serviced”).Flutter mapping
setClient/showafter a pointer on the field →SetFocus(editable)+TryShowclearClientor pointer that misses the field →AssociateFocus(empty)TryShowonly (no TSF change)Fixes the “closable but reopens on pop / other UI” path without the sticky loop from SetFocus-on-hide.
Related: flutter#97269, flutter#99050, flutter#119807, flutter#135492, flutter#187722.
Rebuild the demo against
host_debug. Filtered tests:--gtest_filter=*OnScreenKeyboard*:*TextInputPlugin*:*TsfTextStore*(not run on this Linux host).