-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Closed
flutter/engine
#43267Labels
P1High-priority issues at the top of the work listHigh-priority issues at the top of the work lista: text inputEntering text in a text field or keyboard related problemsEntering text in a text field or keyboard related problemsengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.10Found to occur in 3.10Found to occur in 3.10found in release: 3.12Found to occur in 3.12Found to occur in 3.12frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onplatform-iosiOS applications specificallyiOS applications specificallyr: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer versionteam-iosOwned by iOS platform teamOwned by iOS platform teamtriaged-iosTriaged by iOS platform teamTriaged by iOS platform team
Description
Is there an existing issue for this?
- I have searched the existing issues
- I have read the guide to filing a bug
Steps to reproduce
- Run the sample code on iOS.
- Press "Attach to IME"
- Type "-"
- Type another "-"
Expected results
Receive a replacement delta, or both deltas in a single call to updateEditingValueWithDeltas.
Actual results
A call to updateEditingValueWithDeltas with a deletion delta followed by a call to updateEditingValueWithDeltas with an insertion delta.
Code sample
Code sample
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(
const MaterialApp(
home: Scaffold(
body: TextInputExample(),
),
),
);
}
class TextInputExample extends StatefulWidget {
const TextInputExample({Key? key}) : super(key: key);
@override
State<TextInputExample> createState() => _TextInputExampleState();
}
class _TextInputExampleState extends State<TextInputExample> implements DeltaTextInputClient {
final emptyParagraphPlaceholder = '. ';
final firstParagraphText = '';
TextInputConnection? _inputConnection;
late TextEditingValue _currentEditingValue;
@override
void initState() {
super.initState();
_currentEditingValue = _placeHolderEditingValue;
}
@override
void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {
print('Received ${textEditingDeltas.length} deltas');
TextEditingValue newEditingValue = _currentEditingValue;
for (final delta in textEditingDeltas) {
print('IME: received delta $delta');
if (delta.oldText != _currentEditingValue.text) {
print('Out of sync with IME');
print('OS text - "${delta.oldText}"');
print('OS selection - ${delta.selection}');
print('OS composing - ${delta.composing}');
print('App text - "${_currentEditingValue.text}"');
print('App selection - ${_currentEditingValue.selection}');
print('App composing - ${_currentEditingValue.composing}');
}
if (delta is TextEditingDeltaInsertion) {
newEditingValue = _applyInsertionDelta(newEditingValue, delta);
} else if (delta is TextEditingDeltaDeletion) {
newEditingValue = _applyDeletionDelta(newEditingValue, delta);
} else if (delta is TextEditingDeltaNonTextUpdate) {
newEditingValue = _applyNonTextDelta(newEditingValue, delta);
} else {
newEditingValue = delta.apply(newEditingValue);
}
if (newEditingValue.text.isEmpty) {
newEditingValue = _placeHolderEditingValue;
}
}
_syncWithOS(newEditingValue);
setState(() {
_currentEditingValue = newEditingValue;
});
}
void _syncWithOS(TextEditingValue textEditingValue) async {
_inputConnection?.setEditingState(textEditingValue);
}
void _run() {
_detach();
_attach();
_syncWithOS(_currentEditingValue);
}
void _attach() {
if (_inputConnection != null) {
return;
}
_inputConnection = TextInput.attach(
this,
const TextInputConfiguration(
enableDeltaModel: true,
inputType: TextInputType.multiline,
inputAction: TextInputAction.newline,
),
);
_inputConnection!.show();
}
void _detach() {
_inputConnection?.close();
_inputConnection = null;
}
/// Placehold which the editor sends to the framework to represent an empty paragraph.
TextEditingValue get _placeHolderEditingValue => TextEditingValue(
text: emptyParagraphPlaceholder,
selection: const TextSelection.collapsed(offset: 2),
composing: const TextRange(start: -1, end: -1),
);
TextEditingValue _applyInsertionDelta(TextEditingValue current, TextEditingDeltaInsertion delta) {
TextEditingValue newEditingValue = current;
if (delta.oldText == emptyParagraphPlaceholder) {
// The text contains only the placeholder, so we are in an empty paragraph.
// The inserted text should be the new text.
newEditingValue = TextEditingValue(
text: delta.textInserted,
composing: const TextRange(start: -1, end: -1),
selection: const TextSelection.collapsed(offset: 1),
);
} else {
newEditingValue = delta.apply(current);
}
return newEditingValue;
}
TextEditingValue _applyDeletionDelta(TextEditingValue current, TextEditingDeltaDeletion delta) {
return delta.apply(current);
}
TextEditingValue _applyNonTextDelta(TextEditingValue current, TextEditingDeltaNonTextUpdate delta) {
print("IME: Non-text change:");
print("IME: OS-side text - ${delta.oldText}");
print("IME: OS-side selection - ${delta.selection}");
print("IME: OS-side composing - ${delta.composing}");
return current.copyWith(composing: delta.composing);
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_currentEditingValue.toString(),
textAlign: TextAlign.center,
),
ElevatedButton(
onPressed: _run,
child: const Text('Attach to IME'),
),
],
),
);
}
@override
void connectionClosed() {}
@override
AutofillScope? get currentAutofillScope => null;
@override
TextEditingValue? get currentTextEditingValue => null;
@override
void insertTextPlaceholder(Size size) {}
@override
void performAction(TextInputAction action) {}
@override
void performPrivateCommand(String action, Map<String, dynamic> data) {}
@override
void removeTextPlaceholder() {}
@override
void showAutocorrectionPromptRect(int start, int end) {}
@override
void showToolbar() {}
@override
void updateEditingValue(TextEditingValue value) {}
@override
void updateFloatingCursor(RawFloatingCursorPoint point) {}
@override
void didChangeInputControl(TextInputControl? oldControl, TextInputControl? newControl) {
// TODO: implement didChangeInputControl
}
@override
void insertContent(KeyboardInsertedContent content) {
// TODO: implement insertContent
}
@override
void performSelector(String selectorName) {
// TODO: implement performSelector
}
}
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
Launching lib/main.dart on iPhone Xs Max in debug mode...
Xcode build done. 7,9s
Connecting to VM Service at ws://127.0.0.1:49869/vbH1MpsAuWA=/ws
flutter: Received 1 deltas
flutter: IME: received delta TextEditingDeltaInsertion#a006d(oldText: ., textInserted: -, insertionOffset: 2, selection: TextSelection.collapsed(offset: 3, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1))
flutter: Received 1 deltas
flutter: IME: received delta TextEditingDeltaNonTextUpdate#93e41(oldText: -, selection: TextSelection(baseOffset: 0, extentOffset: 1, isDirectional: false), composing: TextRange(start: -1, end: -1))
flutter: IME: Non-text change:
flutter: IME: OS-side text - -
flutter: IME: OS-side selection - TextSelection(baseOffset: 0, extentOffset: 1, isDirectional: false)
flutter: IME: OS-side composing - TextRange(start: -1, end: -1)
flutter: Received 1 deltas
flutter: IME: received delta TextEditingDeltaDeletion#17112(oldText: -, textDeleted: -, deletedRange: TextRange(start: 0, end: 1), selection: TextSelection.collapsed(offset: 0, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1))
flutter: Received 1 deltas
flutter: IME: received delta TextEditingDeltaInsertion#c5e9d(oldText, textInserted: —, insertionOffset: 0, selection: TextSelection.collapsed(offset: 1, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1))
flutter: Out of sync with IME
flutter: OS text - ""
flutter: OS selection - TextSelection.collapsed(offset: 1, affinity: TextAffinity.downstream, isDirectional: false)
flutter: OS composing - TextRange(start: -1, end: -1)
flutter: App text - ". "
flutter: App selection - TextSelection.collapsed(offset: 2, affinity: TextAffinity.downstream, isDirectional: false)
flutter: App composing - TextRange(start: -1, end: -1)
Flutter Doctor output
Doctor output
[✓] Flutter (Channel master, 3.12.0-4.0.pre.110, on macOS 12.6.5 21G531 darwin-x64, locale pt-BR)
• Flutter version 3.12.0-4.0.pre.110 on channel master at /Users/user223563/Downloads/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision c29b570678 (12 hours ago), 2023-06-16 20:07:25 -0400
• Engine revision 7ffa1355f7
• Dart version 3.1.0 (build 3.1.0-213.0.dev)
• DevTools version 2.24.0
[✗] Android toolchain - develop for Android devices
✗ Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
If the Android SDK has been installed to a custom location, please use
`flutter config --android-sdk` to update to that location.
[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 14C18
• CocoaPods version 1.12.1
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2022.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
[✓] IntelliJ IDEA Community Edition (version 2020.3.3)
• IntelliJ at /Applications/IntelliJ IDEA CE.app
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
[✓] VS Code (version 1.75.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.66.0
[✓] Connected device (3 available)
• iPhone Xs Max (mobile) • 8983A467-63BE-408C-A44C-8D898C7A8471 • ios • com.apple.CoreSimulator.SimRuntime.iOS-12-4 (simulator)
• macOS (desktop) • macos • darwin-x64 • macOS 12.6.5 21G531 darwin-x64
• Chrome (web) • chrome • web-javascript • Google Chrome 114.0.5735.133
[✓] Network resources
• All expected network resources are available.
! Doctor found issues in 1 category.
raulmabe-labhouse
Metadata
Metadata
Assignees
Labels
P1High-priority issues at the top of the work listHigh-priority issues at the top of the work lista: text inputEntering text in a text field or keyboard related problemsEntering text in a text field or keyboard related problemsengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.10Found to occur in 3.10Found to occur in 3.10found in release: 3.12Found to occur in 3.12Found to occur in 3.12frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onplatform-iosiOS applications specificallyiOS applications specificallyr: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer versionteam-iosOwned by iOS platform teamOwned by iOS platform teamtriaged-iosTriaged by iOS platform teamTriaged by iOS platform team