diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index 96acb7796e..4a4883e544 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -1149,6 +1149,10 @@ class WidgetsApp extends StatefulWidget { /// with "s". static bool debugAllowBannerOverride = true; + // Any shortcuts added here have the potential to conflict with normal text + // input. If this should not happen and text input should take preference, + // then add a shortcut for the relevant key in DefaultTextEditingShortcuts + // mapped to DoNothingAndStopPropagationTextIntent. static const Map _defaultShortcuts = { // Activation SingleActivator(LogicalKeyboardKey.enter): ActivateIntent(), @@ -1206,6 +1210,11 @@ class WidgetsApp extends StatefulWidget { }; // Default shortcuts for the macOS platform. + // + // Any shortcuts added here have the potential to conflict with normal text + // input. If this should not happen and text input should take preference, + // then add a shortcut for the relevant key in DefaultTextEditingShortcuts + // mapped to DoNothingAndStopPropagationTextIntent. static const Map _defaultAppleOsShortcuts = { // Activation SingleActivator(LogicalKeyboardKey.enter): ActivateIntent(), diff --git a/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart b/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart index a18dc58fcb..4ecd36fff8 100644 --- a/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart +++ b/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart @@ -160,6 +160,13 @@ class DefaultTextEditingShortcuts extends Shortcuts { child: child, ); + static const Map _commonShortcuts = { + // Allows space and enter to be used as input instead of a shortcut by + // another widget. See https://github.com/flutter/flutter/issues/90907 + SingleActivator(LogicalKeyboardKey.space): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.enter): DoNothingAndStopPropagationTextIntent(), + }; + static const Map _androidShortcuts = { SingleActivator(LogicalKeyboardKey.backspace): DeleteTextIntent(), SingleActivator(LogicalKeyboardKey.backspace, control: true): DeleteByWordTextIntent(), @@ -532,7 +539,7 @@ class DefaultTextEditingShortcuts extends Shortcuts { SingleActivator(LogicalKeyboardKey.keyA, meta: true): DoNothingAndStopPropagationTextIntent(), }; - static Map get _shortcuts { + static Map get _platformShortcuts { if (kIsWeb) { return _webShortcuts; } @@ -552,4 +559,11 @@ class DefaultTextEditingShortcuts extends Shortcuts { return _windowsShortcuts; } } + + static Map get _shortcuts { + return { + ..._commonShortcuts, + ..._platformShortcuts, + }; + } } diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 7f28c9dd8c..eb54e1416f 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; @@ -8635,6 +8636,71 @@ void main() { await tester.pump(); expect(scrollController.offset.roundToDouble(), 0.0); }); + + // Regression test for https://github.com/flutter/flutter/issues/90907. + testWidgets("ActivateIntent doesn't block space entry", (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + bool invoked = false; + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 100, + child: ListTile( + title: Actions( + actions: >{ + ActivateIntent: CallbackAction( + onInvoke: (ActivateIntent intent) { + invoked = true; + }, + ), + }, + child: Column( + children: [ + EditableText( + autofocus: true, + showSelectionHandles: true, + maxLines: 2, + controller: TextEditingController(), + focusNode: FocusNode(), + cursorColor: Colors.red, + backgroundCursorColor: Colors.blue, + style: Typography.material2018(platform: TargetPlatform.android).black.subtitle1!.copyWith(fontFamily: 'Roboto'), + keyboardType: TextInputType.text, + ), + Focus( + focusNode: focusNode, + child: const Text('Hello'), + ), + ], + ), + ), + ), + ), + ), + ), + )); + + await tester.sendKeyEvent(LogicalKeyboardKey.space); + await tester.sendKeyEvent(LogicalKeyboardKey.enter); + await tester.pump(); + expect(invoked, isFalse); + + focusNode.requestFocus(); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.space); + await tester.pump(); + expect(invoked, isTrue); + + invoked = false; + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.enter); + await tester.pump(); + // On the web, enter doesn't activate any controls except for buttons. + expect(invoked, kIsWeb ? isFalse : isTrue); + }); } class UnsettableController extends TextEditingController {