From 75e9318d7f7e3432cd33f6c131c8db5deece31ec Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Wed, 16 Jun 2021 15:54:03 -0700 Subject: [PATCH] Revert "TextField terminal the enter and space raw key events by default (#82671)" (#84739) --- .../flutter/lib/src/cupertino/text_field.dart | 55 ++-------------- .../flutter/lib/src/material/text_field.dart | 46 ------------- .../test/cupertino/text_field_test.dart | 65 ------------------- .../test/material/text_field_test.dart | 63 ------------------ 4 files changed, 4 insertions(+), 225 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index ba5ed4035e..7b7489bc74 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -507,30 +507,6 @@ class CupertinoTextField extends StatefulWidget { final TextEditingController? controller; /// {@macro flutter.widgets.Focus.focusNode} - /// - /// ## Key handling - /// - /// By default, [CupertinoTextField] absorbs key events of the Space key and - /// Enter key, because they are commonly used as both shortcuts and text field - /// inputs. This means that, if these keys are pressed when - /// [CupertinoTextField] is the primary focus, they will not be sent to other - /// enclosing widgets. - /// - /// If [FocusNode.onKey] is not null, this filter is bypassed. In the likely - /// case that this filter is still desired, check these keys and return - /// [KeyEventResult.skipRemainingHandlers]. - /// - /// ```dart - /// final FocusNode focusNode = FocusNode( - /// onKey: (FocusNode node, RawKeyEvent event) { - /// if (event.logicalKey == LogicalKeyboardKey.space - /// || event.logicalKey == LogicalKeyboardKey.enter) { - /// return KeyEventResult.skipRemainingHandlers; - /// } - /// // Now process the event as desired. - /// }, - /// ); - /// ``` final FocusNode? focusNode; /// Controls the [BoxDecoration] of the box behind the text input. @@ -1091,25 +1067,11 @@ class _CupertinoTextFieldState extends State with Restoratio ); } - KeyEventResult _handleRawKeyEvent(FocusNode node, RawKeyEvent event) { - assert(node.hasFocus); - // TextField uses "enter" to finish the input or create a new line, and "space" as - // a normal input character, so we default to terminate the handling of these - // two keys to avoid ancestor behaving incorrectly for handling the two keys - // (such as `ListTile` or `Material`). - if (event.logicalKey == LogicalKeyboardKey.space - || event.logicalKey == LogicalKeyboardKey.enter) { - return KeyEventResult.skipRemainingHandlers; - } - return KeyEventResult.ignored; - } - @override Widget build(BuildContext context) { super.build(context); // See AutomaticKeepAliveClientMixin. assert(debugCheckHasDirectionality(context)); final TextEditingController controller = _effectiveController; - final FocusNode focusNode = _effectiveFocusNode; TextSelectionControls? textSelectionControls = widget.selectionControls; VoidCallback? handleDidGainAccessibilityFocus; @@ -1127,8 +1089,8 @@ class _CupertinoTextFieldState extends State with Restoratio handleDidGainAccessibilityFocus = () { // macOS automatically activated the TextField when it receives // accessibility focus. - if (!focusNode.hasFocus && focusNode.canRequestFocus) { - focusNode.requestFocus(); + if (!_effectiveFocusNode.hasFocus && _effectiveFocusNode.canRequestFocus) { + _effectiveFocusNode.requestFocus(); } }; break; @@ -1191,7 +1153,7 @@ class _CupertinoTextFieldState extends State with Restoratio final Color selectionColor = CupertinoTheme.of(context).primaryColor.withOpacity(0.2); - Widget paddedEditable = Padding( + final Widget paddedEditable = Padding( padding: widget.padding, child: RepaintBoundary( child: UnmanagedRestorationScope( @@ -1203,7 +1165,7 @@ class _CupertinoTextFieldState extends State with Restoratio toolbarOptions: widget.toolbarOptions, showCursor: widget.showCursor, showSelectionHandles: _showSelectionHandles, - focusNode: focusNode, + focusNode: _effectiveFocusNode, keyboardType: widget.keyboardType, textInputAction: widget.textInputAction, textCapitalization: widget.textCapitalization, @@ -1253,15 +1215,6 @@ class _CupertinoTextFieldState extends State with Restoratio ), ); - if (focusNode.onKey == null) { - paddedEditable = Focus( - onKey: _handleRawKeyEvent, - includeSemantics: false, - skipTraversal: true, - child: paddedEditable, - ); - } - return Semantics( enabled: enabled, onTap: !enabled || widget.readOnly ? null : () { diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 10d2b04ecc..cdcad90f91 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -486,30 +486,6 @@ class TextField extends StatefulWidget { /// /// This widget builds an [EditableText] and will ensure that the keyboard is /// showing when it is tapped by calling [EditableTextState.requestKeyboard()]. - /// - /// ## Key handling - /// - /// By default, [TextField] absorbs key events of the Space key and Enter key, - /// because they are commonly used as both shortcuts and text field inputs. - /// This means that, if these keys are pressed when [TextField] is the - /// primary focus, they will not be sent to other widgets (such as triggering - /// an enclosing [ListTile]). - /// - /// If [FocusNode.onKey] is not null, this filter is bypassed. In the likely - /// case that this filter is still desired, check these keys and return - /// [KeyEventResult.skipRemainingHandlers]. - /// - /// ```dart - /// final FocusNode focusNode = FocusNode( - /// onKey: (FocusNode node, RawKeyEvent event) { - /// if (event.logicalKey == LogicalKeyboardKey.space - /// || event.logicalKey == LogicalKeyboardKey.enter) { - /// return KeyEventResult.skipRemainingHandlers; - /// } - /// // Now process the event as desired. - /// }, - /// ); - /// ``` final FocusNode? focusNode; /// The decoration to show around the text field. @@ -1135,19 +1111,6 @@ class _TextFieldState extends State with RestorationMixin implements } } - KeyEventResult _handleRawKeyEvent(FocusNode node, RawKeyEvent event) { - assert(node.hasFocus); - // TextField uses "enter" to finish the input or create a new line, and "space" as - // a normal input character, so we default to terminate the handling of these - // two keys to avoid ancestor behaving incorrectly for handling the two keys - // (such as `ListTile` or `Material`). - if (event.logicalKey == LogicalKeyboardKey.space - || event.logicalKey == LogicalKeyboardKey.enter) { - return KeyEventResult.skipRemainingHandlers; - } - return KeyEventResult.ignored; - } - @override Widget build(BuildContext context) { assert(debugCheckHasMaterial(context)); @@ -1300,15 +1263,6 @@ class _TextFieldState extends State with RestorationMixin implements ), ); - if (focusNode.onKey == null) { - child = Focus( - onKey: _handleRawKeyEvent, - includeSemantics: false, - skipTraversal: true, - child: child, - ); - } - if (widget.decoration != null) { child = AnimatedBuilder( animation: Listenable.merge([ focusNode, controller ]), diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index 5404ddb873..daf43f33ea 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -4779,69 +4779,4 @@ void main() { expect(disabledColor, isSameColorAs(const Color(0xFFFAFAFA))); }, ); - - // Regression test for https://github.com/flutter/flutter/issues/81233 - testWidgets('CupertinoTextField should terminate the `space` and `enter` raw key events by default', (WidgetTester tester) async { - final Set outerReceivedAnEvent = {}; - final FocusNode outerFocusNode = FocusNode(debugLabel: 'outerFocusNode'); - KeyEventResult outerHandleEvent(FocusNode node, RawKeyEvent event) { - outerReceivedAnEvent.add(node); - return KeyEventResult.handled; - } - outerFocusNode.onKey = outerHandleEvent; - - final Set innerReceivedAnEvent = {}; - final FocusNode innerFocusNode = FocusNode(debugLabel: 'innerFocusNode'); - - Future sendEvent(LogicalKeyboardKey key) async { - await tester.sendKeyEvent(key, platform: 'windows'); - } - - Widget buildFrame() { - return CupertinoApp( - home: Center( - child: Focus( - onKey: outerFocusNode.onKey, - focusNode: outerFocusNode, - child: CupertinoTextField( - focusNode: innerFocusNode, - ), - ), - ), - ); - } - - await tester.pumpWidget(buildFrame()); - innerFocusNode.requestFocus(); - await tester.pump(); - - // The inner TextField's focus node terminal the raw key event by default. - await sendEvent(LogicalKeyboardKey.space); - expect(outerReceivedAnEvent.length, 0); - - await sendEvent(LogicalKeyboardKey.enter); - expect(outerReceivedAnEvent.length, 0); - - // The `onKey` of the focus node of the TextField can be customized. - KeyEventResult innerHandleEvent(FocusNode node, RawKeyEvent event) { - innerReceivedAnEvent.add(node); - // The key event has not been handled, and the event should continue to be - // propagated to the outer key event handlers. - return KeyEventResult.ignored; - } - innerFocusNode.onKey = innerHandleEvent; - await tester.pumpWidget(buildFrame()); - - await sendEvent(LogicalKeyboardKey.space); - - expect(innerReceivedAnEvent.length, 1); - expect(outerReceivedAnEvent.length, 1); - - outerReceivedAnEvent.clear(); - innerReceivedAnEvent.clear(); - - await sendEvent(LogicalKeyboardKey.enter); - expect(outerReceivedAnEvent.length, 1); - expect(innerReceivedAnEvent.length, 1); - }, skip: kIsWeb); } diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 178dade549..7efe682751 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -4537,69 +4537,6 @@ void main() { await tester.pump(); } - // Regression test for https://github.com/flutter/flutter/issues/81233 - testWidgets('TextField should terminate the `space` and `enter` raw key events by default', (WidgetTester tester) async { - final Set outerReceivedAnEvent = {}; - final FocusNode outerFocusNode = FocusNode(); - KeyEventResult outerHandleEvent(FocusNode node, RawKeyEvent event) { - outerReceivedAnEvent.add(node); - return KeyEventResult.handled; - } - outerFocusNode.onKey = outerHandleEvent; - - final Set innerReceivedAnEvent = {}; - final FocusNode innerFocusNode = FocusNode(); - - Future sendEvent(LogicalKeyboardKey key) async { - await tester.sendKeyEvent(key, platform: 'windows'); - } - - Widget buildFrame() { - return MaterialApp( - home: Material( - child: Focus( - onKey: outerFocusNode.onKey, - focusNode: outerFocusNode, - child: TextField( - focusNode: innerFocusNode, - ), - ), - ), - ); - } - await tester.pumpWidget(buildFrame()); - innerFocusNode.requestFocus(); - await tester.pump(); - - // The inner TextField's focus node terminal the raw key event by default. - await sendEvent(LogicalKeyboardKey.space); - expect(outerReceivedAnEvent.length, 0); - - await sendEvent(LogicalKeyboardKey.enter); - expect(outerReceivedAnEvent.length, 0); - - // The `onKey` of the focus node of the TextField can be customized. - KeyEventResult innerHandleEvent(FocusNode node, RawKeyEvent event) { - innerReceivedAnEvent.add(node); - // The key event has not been handled, and the event should continue to be - // propagated to the outer key event handlers. - return KeyEventResult.ignored; - } - innerFocusNode.onKey = innerHandleEvent; - await tester.pumpWidget(buildFrame()); - - await sendEvent(LogicalKeyboardKey.space); - expect(outerReceivedAnEvent.length, 1); - expect(innerReceivedAnEvent.length, 1); - - outerReceivedAnEvent.clear(); - innerReceivedAnEvent.clear(); - - await sendEvent(LogicalKeyboardKey.enter); - expect(outerReceivedAnEvent.length, 1); - expect(innerReceivedAnEvent.length, 1); - }, skip: areKeyEventsHandledByPlatform); - testWidgets('Shift test 1', (WidgetTester tester) async { await setupWidget(tester); const String testValue = 'a big house';