Skip to content

Docs on the interaction between Shortcuts and text input #144328

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import 'text_editing_intents.dart';
/// cause CJK input methods to discard more text than they should when the
/// backspace key is pressed during text composition on iOS.
///
/// {@macro flutter.widgets.editableText.shortcutsAndTextInput}
///
/// {@tool snippet}
///
/// This example shows how to use an additional [Shortcuts] widget to override
Expand Down
41 changes: 38 additions & 3 deletions packages/flutter/lib/src/widgets/editable_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,10 @@ class _DiscreteKeyFrameSimulation extends Simulation {
/// This widget provides default [Action]s for handling common text editing
/// [Intent]s such as deleting, copying and pasting in the text field. These
/// [Action]s can be directly invoked using [Actions.invoke] or the
/// [Actions.maybeInvoke] method. The default text editing keyboard [Shortcuts]
/// also use these [Intent]s and [Action]s to perform the text editing
/// operations they are bound to.
/// [Actions.maybeInvoke] method. The default text editing keyboard [Shortcuts],
/// typically declared in [DefaultTextEditingShortcuts], also use these
/// [Intent]s and [Action]s to perform the text editing operations they are
/// bound to.
///
/// The default handling of a specific [Intent] can be overridden by placing an
/// [Actions] widget above this widget. See the [Action] class and the
Expand Down Expand Up @@ -683,6 +684,40 @@ class _DiscreteKeyFrameSimulation extends Simulation {
/// | [CopySelectionTextIntent] | Copies or cuts the selected text into the clipboard |
/// | [PasteTextIntent] | Inserts the current text in the clipboard after the caret location, or replaces the selected text if the selection is not collapsed. |
///
/// ## Text Editing [Shortcuts]
///
/// It's also possible to directly remap keyboard shortcuts to new [Intent]s by
/// inserting a [Shortcuts] widget above this in the widget tree. When using
/// [WidgetsApp], the large set of default text editing keyboard shortcuts are
/// declared near the top of the widget tree in [DefaultTextEditingShortcuts],
/// and any [Shortcuts] widget between it and this [EditableText] will override
/// those defaults.
///
/// {@template flutter.widgets.editableText.shortcutsAndTextInput}
/// ### Interactions Between [Shortcuts] and Text Input
///
/// Shortcuts prevent text input fields from receiving their keystrokes as text
/// input. For example, placing a [Shortcuts] widget in the widget tree above
/// a text input field and creating a shortcut for [LogicalKeyboardKey.keyA]
/// will prevent the field from receiving that key as text input. In other
/// words, typing key "A" into the field will trigger the shortcut and will not
/// insert a letter "a" into the field.
///
/// This happens because of the way that key strokes are handled in Flutter.
/// When a keystroke is received in Flutter's engine, it first gives the
/// framework the opportunity to handle it as a raw key event through
/// [SystemChannels.keyEvent]. This is what [Shortcuts] listens to indirectly
/// through its [FocusNode]. If it is not handled, then it will proceed to try
/// handling it as text input through [SystemChannels.textInput], which is what
/// [EditableTextState] listens to through [TextInputClient].
///
/// This behavior, where a shortcut prevents text input into some field, can be
/// overridden by using another [Shortcuts] widget lower in the widget tree and
/// mapping the desired key stroke(s) to [DoNothingAndStopPropagationIntent].
/// The key event will be reported as unhandled by the framework and will then
/// be sent as text input as usual.
/// {@endtemplate}
///
/// ## Gesture Events Handling
///
/// When [rendererIgnoresPointer] is false (the default), this widget provides
Expand Down