Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
b5fc79f9
Unverified
Commit
b5fc79f9
authored
Jun 10, 2021
by
xubaolin
Committed by
GitHub
Jun 10, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TextField terminal the enter and space raw key events by default (#82671)
parent
a0d801f7
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
225 additions
and
4 deletions
+225
-4
text_field.dart
packages/flutter/lib/src/cupertino/text_field.dart
+51
-4
text_field.dart
packages/flutter/lib/src/material/text_field.dart
+46
-0
text_field_test.dart
packages/flutter/test/cupertino/text_field_test.dart
+65
-0
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+63
-0
No files found.
packages/flutter/lib/src/cupertino/text_field.dart
View file @
b5fc79f9
...
...
@@ -507,6 +507,30 @@ 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.
...
...
@@ -1067,11 +1091,25 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> 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
;
...
...
@@ -1089,8 +1127,8 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
handleDidGainAccessibilityFocus
=
()
{
// macOS automatically activated the TextField when it receives
// accessibility focus.
if
(!
_effectiveFocusNode
.
hasFocus
&&
_effectiveF
ocusNode
.
canRequestFocus
)
{
_effectiveF
ocusNode
.
requestFocus
();
if
(!
focusNode
.
hasFocus
&&
f
ocusNode
.
canRequestFocus
)
{
f
ocusNode
.
requestFocus
();
}
};
break
;
...
...
@@ -1153,7 +1191,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
final
Color
selectionColor
=
CupertinoTheme
.
of
(
context
).
primaryColor
.
withOpacity
(
0.2
);
final
Widget
paddedEditable
=
Padding
(
Widget
paddedEditable
=
Padding
(
padding:
widget
.
padding
,
child:
RepaintBoundary
(
child:
UnmanagedRestorationScope
(
...
...
@@ -1165,7 +1203,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
toolbarOptions:
widget
.
toolbarOptions
,
showCursor:
widget
.
showCursor
,
showSelectionHandles:
_showSelectionHandles
,
focusNode:
_effectiveF
ocusNode
,
focusNode:
f
ocusNode
,
keyboardType:
widget
.
keyboardType
,
textInputAction:
widget
.
textInputAction
,
textCapitalization:
widget
.
textCapitalization
,
...
...
@@ -1215,6 +1253,15 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> 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
:
()
{
...
...
packages/flutter/lib/src/material/text_field.dart
View file @
b5fc79f9
...
...
@@ -486,6 +486,30 @@ 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.
...
...
@@ -1111,6 +1135,19 @@ class _TextFieldState extends State<TextField> 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
));
...
...
@@ -1263,6 +1300,15 @@ class _TextFieldState extends State<TextField> 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
(<
Listenable
>[
focusNode
,
controller
]),
...
...
packages/flutter/test/cupertino/text_field_test.dart
View file @
b5fc79f9
...
...
@@ -4779,4 +4779,69 @@ 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
<
FocusNode
>
outerReceivedAnEvent
=
<
FocusNode
>{};
final
FocusNode
outerFocusNode
=
FocusNode
(
debugLabel:
'outerFocusNode'
);
KeyEventResult
outerHandleEvent
(
FocusNode
node
,
RawKeyEvent
event
)
{
outerReceivedAnEvent
.
add
(
node
);
return
KeyEventResult
.
handled
;
}
outerFocusNode
.
onKey
=
outerHandleEvent
;
final
Set
<
FocusNode
>
innerReceivedAnEvent
=
<
FocusNode
>{};
final
FocusNode
innerFocusNode
=
FocusNode
(
debugLabel:
'innerFocusNode'
);
Future
<
void
>
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
);
}
packages/flutter/test/material/text_field_test.dart
View file @
b5fc79f9
...
...
@@ -4537,6 +4537,69 @@ 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
<
FocusNode
>
outerReceivedAnEvent
=
<
FocusNode
>{};
final
FocusNode
outerFocusNode
=
FocusNode
();
KeyEventResult
outerHandleEvent
(
FocusNode
node
,
RawKeyEvent
event
)
{
outerReceivedAnEvent
.
add
(
node
);
return
KeyEventResult
.
handled
;
}
outerFocusNode
.
onKey
=
outerHandleEvent
;
final
Set
<
FocusNode
>
innerReceivedAnEvent
=
<
FocusNode
>{};
final
FocusNode
innerFocusNode
=
FocusNode
();
Future
<
void
>
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'
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment