From 25bc19e49d9e948ba45bdb185d534c26bb3df9b2 Mon Sep 17 00:00:00 2001 From: Larry Hsiao Date: Mon, 20 Jul 2026 21:00:25 +0800 Subject: [PATCH] Set viewId on the text input configuration CustomTextEdit built its TextInputConfiguration without a viewId, which Flutter's Windows embedder rejects outright: TextInput.setClient fails with "Could not set client, view ID is null", followed by "Set editing state has been invoked, but no client is set". The connection is never attached. That is fatal to input rather than merely noisy. CustomTextEdit has no hardware-key fallback for printable characters the way CustomKeyboardListener does, so with the connection dead, letters and digits have no route to the terminal at all. Keys that map to a TerminalKey (Enter, arrows, Ctrl-combos) still work through the Focus onKeyEvent path, which makes the failure look selective and puzzling: Enter responds, typing does not. macOS tolerates the omission via its implicit view, so this only ever surfaced on Windows. Fixed by passing View.of(context).viewId, matching how Flutter's own EditableText populates the field. Covered by a regression test asserting the viewId reaches TextInput.setClient. Co-Authored-By: Claude Opus 4.8 --- lib/src/ui/custom_text_edit.dart | 1 + test/src/terminal_view_test.dart | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/lib/src/ui/custom_text_edit.dart b/lib/src/ui/custom_text_edit.dart index 1d33c7a2..0489cd2f 100644 --- a/lib/src/ui/custom_text_edit.dart +++ b/lib/src/ui/custom_text_edit.dart @@ -160,6 +160,7 @@ class CustomTextEditState extends State with TextInputClient { _connection!.show(); } else { final config = TextInputConfiguration( + viewId: View.of(context).viewId, inputType: widget.inputType, inputAction: widget.inputAction, keyboardAppearance: widget.keyboardAppearance, diff --git a/test/src/terminal_view_test.dart b/test/src/terminal_view_test.dart index 0540e09d..b322b4af 100644 --- a/test/src/terminal_view_test.dart +++ b/test/src/terminal_view_test.dart @@ -420,6 +420,43 @@ void main() { }); }); + group('TerminalView text input configuration', () { + testWidgets('carries the view id of the view it belongs to', + (tester) async { + // Flutter's Windows embedder rejects TextInput.setClient outright when + // the configuration carries no viewId ("Could not set client, view ID is + // null"), leaving the connection unattached. Printable characters are + // then dropped entirely, since CustomTextEdit has no hardware key + // fallback for them the way CustomKeyboardListener does. macOS tolerates + // the omission via its implicit view, so it only surfaces on Windows. + final expected = tester.view.viewId; + + int? actual; + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + SystemChannels.textInput, + (call) async { + if (call.method == 'TextInput.setClient') { + actual = ((call.arguments as List).last as Map)['viewId'] as int?; + } + return null; + }, + ); + addTearDown(() { + tester.binding.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.textInput, null); + }); + + await tester.pumpWidget(MaterialApp( + home: TerminalView(Terminal(), autofocus: true), + )); + + await tester.tap(find.byType(TerminalView)); + await tester.pump(Duration(seconds: 1)); + + expect(actual, expected); + }); + }); + group('TerminalView.simulateScroll', () { testWidgets('works', (tester) async { final terminalOutput = [];