Skip to content

Commit 7cdcfb2

Browse files
authored
DefaultTextEditingShortcuts should use meta-based shortcut for iOS (#103077)
1 parent 72dff58 commit 7cdcfb2

File tree

4 files changed

+130
-56
lines changed

4 files changed

+130
-56
lines changed

packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart

+4-19
Original file line numberDiff line numberDiff line change
@@ -231,25 +231,6 @@ class DefaultTextEditingShortcuts extends Shortcuts {
231231

232232
static final Map<ShortcutActivator, Intent> _fuchsiaShortcuts = _androidShortcuts;
233233

234-
// The following key combinations have no effect on text editing on this
235-
// platform:
236-
// * End
237-
// * Home
238-
// * Meta + X
239-
// * Meta + C
240-
// * Meta + V
241-
// * Meta + A
242-
// * Meta + shift? + Z
243-
// * Meta + shift? + arrow down
244-
// * Meta + shift? + arrow left
245-
// * Meta + shift? + arrow right
246-
// * Meta + shift? + arrow up
247-
// * Shift + end
248-
// * Shift + home
249-
// * Meta + shift? + delete
250-
// * Meta + shift? + backspace
251-
static final Map<ShortcutActivator, Intent> _iOSShortcuts = _commonShortcuts;
252-
253234
static final Map<ShortcutActivator, Intent> _linuxShortcuts = <ShortcutActivator, Intent>{
254235
..._commonShortcuts,
255236
const SingleActivator(LogicalKeyboardKey.home): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true),
@@ -342,6 +323,10 @@ class DefaultTextEditingShortcuts extends Shortcuts {
342323
// * Control + shift? + Z
343324
};
344325

326+
// There is no complete documentation of iOS shortcuts. Use mac shortcuts for
327+
// now.
328+
static final Map<ShortcutActivator, Intent> _iOSShortcuts = _macShortcuts;
329+
345330
// The following key combinations have no effect on text editing on this
346331
// platform:
347332
// * Meta + X

packages/flutter/test/widgets/app_test.dart

+89
Original file line numberDiff line numberDiff line change
@@ -643,11 +643,100 @@ void main() {
643643
);
644644
expect(MediaQuery.of(capturedContext), isNotNull);
645645
});
646+
647+
testWidgets('WidgetsApp provides meta based shortcuts for iOS and macOS', (WidgetTester tester) async {
648+
final FocusNode focusNode = FocusNode();
649+
final SelectAllSpy selectAllSpy = SelectAllSpy();
650+
final CopySpy copySpy = CopySpy();
651+
final PasteSpy pasteSpy = PasteSpy();
652+
final Map<Type, Action<Intent>> actions = <Type, Action<Intent>>{
653+
// Copy Paste
654+
SelectAllTextIntent: selectAllSpy,
655+
CopySelectionTextIntent: copySpy,
656+
PasteTextIntent: pasteSpy,
657+
};
658+
await tester.pumpWidget(
659+
WidgetsApp(
660+
builder: (BuildContext context, Widget? child) {
661+
return Actions(
662+
actions: actions,
663+
child: Focus(
664+
focusNode: focusNode,
665+
child: const Placeholder(),
666+
),
667+
);
668+
},
669+
color: const Color(0xFF123456),
670+
),
671+
);
672+
focusNode.requestFocus();
673+
await tester.pump();
674+
expect(selectAllSpy.invoked, isFalse);
675+
expect(copySpy.invoked, isFalse);
676+
expect(pasteSpy.invoked, isFalse);
677+
678+
// Select all.
679+
await tester.sendKeyDownEvent(LogicalKeyboardKey.metaLeft);
680+
await tester.sendKeyDownEvent(LogicalKeyboardKey.keyA);
681+
await tester.sendKeyUpEvent(LogicalKeyboardKey.keyA);
682+
await tester.sendKeyUpEvent(LogicalKeyboardKey.metaLeft);
683+
await tester.pump();
684+
685+
expect(selectAllSpy.invoked, isTrue);
686+
expect(copySpy.invoked, isFalse);
687+
expect(pasteSpy.invoked, isFalse);
688+
689+
// Copy.
690+
await tester.sendKeyDownEvent(LogicalKeyboardKey.metaLeft);
691+
await tester.sendKeyDownEvent(LogicalKeyboardKey.keyC);
692+
await tester.sendKeyUpEvent(LogicalKeyboardKey.keyC);
693+
await tester.sendKeyUpEvent(LogicalKeyboardKey.metaLeft);
694+
await tester.pump();
695+
696+
expect(selectAllSpy.invoked, isTrue);
697+
expect(copySpy.invoked, isTrue);
698+
expect(pasteSpy.invoked, isFalse);
699+
700+
// Paste.
701+
await tester.sendKeyDownEvent(LogicalKeyboardKey.metaLeft);
702+
await tester.sendKeyDownEvent(LogicalKeyboardKey.keyV);
703+
await tester.sendKeyUpEvent(LogicalKeyboardKey.keyV);
704+
await tester.sendKeyUpEvent(LogicalKeyboardKey.metaLeft);
705+
await tester.pump();
706+
707+
expect(selectAllSpy.invoked, isTrue);
708+
expect(copySpy.invoked, isTrue);
709+
expect(pasteSpy.invoked, isTrue);
710+
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), skip: kIsWeb); // [intended] Web uses a different set of shortcuts.
646711
}
647712

648713
typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation);
649714
typedef SimpleNavigatorRouterDelegatePopPage<T> = bool Function(Route<T> route, T result, SimpleNavigatorRouterDelegate delegate);
650715

716+
class SelectAllSpy extends Action<SelectAllTextIntent> {
717+
bool invoked = false;
718+
@override
719+
void invoke(SelectAllTextIntent intent) {
720+
invoked = true;
721+
}
722+
}
723+
724+
class CopySpy extends Action<CopySelectionTextIntent> {
725+
bool invoked = false;
726+
@override
727+
void invoke(CopySelectionTextIntent intent) {
728+
invoked = true;
729+
}
730+
}
731+
732+
class PasteSpy extends Action<PasteTextIntent> {
733+
bool invoked = false;
734+
@override
735+
void invoke(PasteTextIntent intent) {
736+
invoked = true;
737+
}
738+
}
739+
651740
class SimpleRouteInformationParser extends RouteInformationParser<RouteInformation> {
652741
SimpleRouteInformationParser();
653742

packages/flutter/test/widgets/editable_text_shortcuts_test.dart

+15-15
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ void main() {
124124

125125
group('Common text editing shortcuts: ',
126126
() {
127-
final TargetPlatformVariant allExceptMacOS = TargetPlatformVariant(TargetPlatform.values.toSet()..remove(TargetPlatform.macOS));
127+
final TargetPlatformVariant allExceptApple = TargetPlatformVariant(TargetPlatform.values.toSet()..removeAll(<TargetPlatform>[TargetPlatform.macOS, TargetPlatform.iOS]));
128128

129129
group('backspace', () {
130130
const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace;
@@ -491,8 +491,8 @@ void main() {
491491
group('word modifier + backspace', () {
492492
const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace;
493493
SingleActivator wordModifierBackspace() {
494-
final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS;
495-
return SingleActivator(trigger, control: !isMacOS, alt: isMacOS);
494+
final bool isApple = defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS;
495+
return SingleActivator(trigger, control: !isApple, alt: isApple);
496496
}
497497

498498
testWidgets('WordModifier-backspace', (WidgetTester tester) async {
@@ -631,8 +631,8 @@ void main() {
631631
group('word modifier + delete', () {
632632
const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete;
633633
SingleActivator wordModifierDelete() {
634-
final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS;
635-
return SingleActivator(trigger, control: !isMacOS, alt: isMacOS);
634+
final bool isApple = defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS;
635+
return SingleActivator(trigger, control: !isApple, alt: isApple);
636636
}
637637

638638
testWidgets('WordModifier-delete', (WidgetTester tester) async {
@@ -764,8 +764,8 @@ void main() {
764764
group('line modifier + backspace', () {
765765
const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace;
766766
SingleActivator lineModifierBackspace() {
767-
final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS;
768-
return SingleActivator(trigger, meta: isMacOS, alt: !isMacOS);
767+
final bool isApple = defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS;
768+
return SingleActivator(trigger, meta: isApple, alt: !isApple);
769769
}
770770

771771
testWidgets('alt-backspace', (WidgetTester tester) async {
@@ -945,8 +945,8 @@ void main() {
945945
group('line modifier + delete', () {
946946
const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete;
947947
SingleActivator lineModifierDelete() {
948-
final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS;
949-
return SingleActivator(trigger, meta: isMacOS, alt: !isMacOS);
948+
final bool isApple = defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.iOS;
949+
return SingleActivator(trigger, meta: isApple, alt: !isApple);
950950
}
951951

952952
testWidgets('alt-delete', (WidgetTester tester) async {
@@ -1167,7 +1167,7 @@ void main() {
11671167
expect(controller.selection, const TextSelection.collapsed(
11681168
offset: 4,
11691169
));
1170-
}, variant: allExceptMacOS);
1170+
}, variant: allExceptApple);
11711171

11721172
testWidgets('line modifier + arrow key movement', (WidgetTester tester) async {
11731173
controller.text = testText;
@@ -1181,7 +1181,7 @@ void main() {
11811181
expect(controller.selection, const TextSelection.collapsed(
11821182
offset: 20,
11831183
));
1184-
}, variant: allExceptMacOS);
1184+
}, variant: allExceptApple);
11851185
});
11861186

11871187
group('right', () {
@@ -1230,7 +1230,7 @@ void main() {
12301230
expect(controller.selection, const TextSelection.collapsed(
12311231
offset: 10,
12321232
));
1233-
}, variant: allExceptMacOS);
1233+
}, variant: allExceptApple);
12341234

12351235
testWidgets('line modifier + arrow key movement', (WidgetTester tester) async {
12361236
controller.text = testText;
@@ -1245,7 +1245,7 @@ void main() {
12451245
offset: 35, // Before the newline character.
12461246
affinity: TextAffinity.upstream,
12471247
));
1248-
}, variant: allExceptMacOS);
1248+
}, variant: allExceptApple);
12491249
});
12501250

12511251
group('With initial non-collapsed selection', () {
@@ -1352,7 +1352,7 @@ void main() {
13521352
expect(controller.selection, const TextSelection.collapsed(
13531353
offset: 28, // After "good".
13541354
));
1355-
}, variant: allExceptMacOS);
1355+
}, variant: allExceptApple);
13561356

13571357
testWidgets('line modifier + arrow key movement', (WidgetTester tester) async {
13581358
controller.text = testText;
@@ -1406,7 +1406,7 @@ void main() {
14061406
offset: 35, // After "people".
14071407
affinity: TextAffinity.upstream,
14081408
));
1409-
}, variant: allExceptMacOS);
1409+
}, variant: allExceptApple);
14101410
});
14111411

14121412
group('vertical movement', () {

0 commit comments

Comments
 (0)