-
Notifications
You must be signed in to change notification settings - Fork 28.6k
[macOS] Use editing intents from engine #105407
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
Changes from all commits
07aaf53
8ff3410
b30bc5f
673be76
6d7b9d4
5f293c4
454fcb5
bc81a05
d7e14fe
ee30a6a
ea83a91
2c741d2
0e986ec
5ef4213
1feee7e
828b125
b4185f3
1f081e8
60cb56e
e8e5522
003dc1a
c3cd8ea
2b66d7a
027ec33
9969ab4
fcbbfe9
8660095
056d90f
6ee64a6
ca8b0dd
3b938fa
e66caf3
54a613f
06077e5
ab642d5
85073b6
3310569
79895d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1165,6 +1165,11 @@ mixin TextInputClient { | |
|
||
/// Requests that the client remove the text placeholder. | ||
void removeTextPlaceholder() {} | ||
|
||
/// Performs the specified MacOS-specific selector from the | ||
/// `NSStandardKeyBindingResponding` protocol or user-specified selector | ||
/// from `DefaultKeyBinding.Dict`. | ||
void performSelector(String selectorName) {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this be more generic than text input? Maybe it should have its own class instead of being a part of TextInputClient? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The selector is sent from TextInputContext, which is only used through the TextInputClient. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed after looking at the engine PR again. If anyone is using TextInputClient with the FYI here is a design doc that I wrote recently about adding platform methods. I think in this case we're all onboard with that pattern. |
||
} | ||
|
||
/// An interface to receive focus from the engine. | ||
|
@@ -1819,6 +1824,10 @@ class TextInput { | |
case 'TextInputClient.performAction': | ||
_currentConnection!._client.performAction(_toTextInputAction(args[1] as String)); | ||
break; | ||
case 'TextInputClient.performSelectors': | ||
final List<String> selectors = (args[1] as List<dynamic>).cast<String>(); | ||
selectors.forEach(_currentConnection!._client.performSelector); | ||
break; | ||
case 'TextInputClient.performPrivateCommand': | ||
final Map<String, dynamic> firstArg = args[1] as Map<String, dynamic>; | ||
_currentConnection!._client.performPrivateCommand( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; | |
import 'package:flutter/services.dart'; | ||
|
||
import 'actions.dart'; | ||
import 'focus_traversal.dart'; | ||
import 'framework.dart'; | ||
import 'shortcuts.dart'; | ||
import 'text_editing_intents.dart'; | ||
|
@@ -258,6 +259,34 @@ class DefaultTextEditingShortcuts extends StatelessWidget { | |
// The macOS shortcuts uses different word/line modifiers than most other | ||
// platforms. | ||
static final Map<ShortcutActivator, Intent> _macShortcuts = <ShortcutActivator, Intent>{ | ||
const SingleActivator(LogicalKeyboardKey.keyX, meta: true): const CopySelectionTextIntent.cut(SelectionChangedCause.keyboard), | ||
const SingleActivator(LogicalKeyboardKey.keyC, meta: true): CopySelectionTextIntent.copy, | ||
const SingleActivator(LogicalKeyboardKey.keyV, meta: true): const PasteTextIntent(SelectionChangedCause.keyboard), | ||
const SingleActivator(LogicalKeyboardKey.keyA, meta: true): const SelectAllTextIntent(SelectionChangedCause.keyboard), | ||
const SingleActivator(LogicalKeyboardKey.keyZ, meta: true): const UndoTextIntent(SelectionChangedCause.keyboard), | ||
const SingleActivator(LogicalKeyboardKey.keyZ, shift: true, meta: true): const RedoTextIntent(SelectionChangedCause.keyboard), | ||
|
||
// On desktop these keys should go to the IME when a field is focused, not to other | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On all desktop platforms or only on Mac? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only on Mac (the comment is inside _macShortcuts), but not on web on mac (hence "desktop"). |
||
// Shortcuts. | ||
if (!kIsWeb) ...<ShortcutActivator, Intent>{ | ||
const SingleActivator(LogicalKeyboardKey.arrowLeft): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.arrowRight): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.arrowUp): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.arrowDown): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.escape): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.space): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.enter): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.tab): const DoNothingAndStopPropagationTextIntent(), | ||
const SingleActivator(LogicalKeyboardKey.tab, shift: true): const DoNothingAndStopPropagationTextIntent(), | ||
}, | ||
}; | ||
|
||
// There is no complete documentation of iOS shortcuts. | ||
static final Map<ShortcutActivator, Intent> _iOSShortcuts = <ShortcutActivator, Intent>{ | ||
for (final bool pressShift in const <bool>[true, false]) | ||
...<SingleActivator, Intent>{ | ||
SingleActivator(LogicalKeyboardKey.backspace, shift: pressShift): const DeleteCharacterIntent(forward: false), | ||
|
@@ -296,8 +325,8 @@ class DefaultTextEditingShortcuts extends StatelessWidget { | |
|
||
const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true): const ExpandSelectionToLineBreakIntent(forward: false), | ||
const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true): const ExpandSelectionToLineBreakIntent(forward: true), | ||
const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: false), | ||
const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: false), | ||
const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true): const ExpandSelectionToDocumentBoundaryIntent(forward: false), | ||
const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true): const ExpandSelectionToDocumentBoundaryIntent(forward: true), | ||
knopp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const SingleActivator(LogicalKeyboardKey.keyT, control: true): const TransposeCharactersIntent(), | ||
|
||
|
@@ -331,9 +360,6 @@ class DefaultTextEditingShortcuts extends StatelessWidget { | |
// * Control + shift? + Z | ||
}; | ||
|
||
// There is no complete documentation of iOS shortcuts. Use mac shortcuts for | ||
// now. | ||
static final Map<ShortcutActivator, Intent> _iOSShortcuts = _macShortcuts; | ||
|
||
// The following key combinations have no effect on text editing on this | ||
// platform: | ||
|
@@ -461,3 +487,67 @@ class DefaultTextEditingShortcuts extends StatelessWidget { | |
); | ||
} | ||
} | ||
|
||
/// Maps the selector from NSStandardKeyBindingResponding to the Intent if the | ||
/// selector is recognized. | ||
Intent? intentForMacOSSelector(String selectorName) { | ||
knopp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const Map<String, Intent> selectorToIntent = <String, Intent>{ | ||
knopp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
'deleteBackward:': DeleteCharacterIntent(forward: false), | ||
'deleteWordBackward:': DeleteToNextWordBoundaryIntent(forward: false), | ||
'deleteToBeginningOfLine:': DeleteToLineBreakIntent(forward: false), | ||
'deleteForward:': DeleteCharacterIntent(forward: true), | ||
'deleteWordForward:': DeleteToNextWordBoundaryIntent(forward: true), | ||
'deleteToEndOfLine:': DeleteToLineBreakIntent(forward: true), | ||
|
||
'moveLeft:': ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), | ||
'moveRight:': ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), | ||
'moveForward:': ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), | ||
'moveBackward:': ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), | ||
|
||
'moveUp:': ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: true), | ||
'moveDown:': ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: true), | ||
|
||
'moveLeftAndModifySelection:': ExtendSelectionByCharacterIntent(forward: false, collapseSelection: false), | ||
'moveRightAndModifySelection:': ExtendSelectionByCharacterIntent(forward: true, collapseSelection: false), | ||
'moveUpAndModifySelection:': ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: false), | ||
'moveDownAndModifySelection:': ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: false), | ||
|
||
'moveWordLeft:': ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: true), | ||
'moveWordRight:': ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: true), | ||
'moveToBeginningOfParagraph:': ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), | ||
'moveToEndOfParagraph:': ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), | ||
|
||
'moveWordLeftAndModifySelection:': ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(forward: false), | ||
'moveWordRightAndModifySelection:': ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(forward: true), | ||
'moveParagraphBackwardAndModifySelection:': ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: false, collapseAtReversal: true), | ||
'moveParagraphForwardAndModifySelection:': ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: false, collapseAtReversal: true), | ||
|
||
'moveToLeftEndOfLine:': ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), | ||
'moveToRightEndOfLine:': ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), | ||
'moveToBeginningOfDocument:': ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: true), | ||
'moveToEndOfDocument:': ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: true), | ||
|
||
'moveToLeftEndOfLineAndModifySelection:': ExpandSelectionToLineBreakIntent(forward: false), | ||
'moveToRightEndOfLineAndModifySelection:': ExpandSelectionToLineBreakIntent(forward: true), | ||
'moveToBeginningOfDocumentAndModifySelection:': ExpandSelectionToDocumentBoundaryIntent(forward: false), | ||
'moveToEndOfDocumentAndModifySelection:': ExpandSelectionToDocumentBoundaryIntent(forward: true), | ||
|
||
'transpose:': TransposeCharactersIntent(), | ||
|
||
'scrollToBeginningOfDocument:': ScrollToDocumentBoundaryIntent(forward: false), | ||
'scrollToEndOfDocument:': ScrollToDocumentBoundaryIntent(forward: true), | ||
|
||
// TODO(knopp): Page Up/Down intents are missing (https://github.com/flutter/flutter/pull/105497) | ||
'scrollPageUp:': ScrollToDocumentBoundaryIntent(forward: false), | ||
'scrollPageDown:': ScrollToDocumentBoundaryIntent(forward: true), | ||
'pageUpAndModifySelection': ExpandSelectionToDocumentBoundaryIntent(forward: false), | ||
'pageDownAndModifySelection:': ExpandSelectionToDocumentBoundaryIntent(forward: true), | ||
|
||
// Escape key when there's no IME selection popup. | ||
'cancelOperation:': DismissIntent(), | ||
// Tab when there's no IME selection. | ||
'insertTab:': NextFocusIntent(), | ||
'insertBacktab:': PreviousFocusIntent(), | ||
}; | ||
return selectorToIntent[selectorName]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more thing I just thought of: I want to make sure that this is something that we want to add to TextInputClient and not split out. We've been having a bunch of discussion about this topic, see this design doc: https://docs.google.com/document/d/1OxDsf_eot7TlsRn57z-1_dGbvuqnMxO7QEGIAmOCZtA/edit