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
1dd6a233
Unverified
Commit
1dd6a233
authored
Aug 30, 2022
by
chunhtai
Committed by
GitHub
Aug 30, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor macOS text editing shortcuts (#110289)
parent
6ce01ed8
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
510 additions
and
66 deletions
+510
-66
default_text_editing_shortcuts.dart
...utter/lib/src/widgets/default_text_editing_shortcuts.dart
+71
-66
default_text_editing_shortcuts_test.dart
...ter/test/widgets/default_text_editing_shortcuts_test.dart
+439
-0
No files found.
packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart
View file @
1dd6a233
...
...
@@ -258,32 +258,7 @@ class DefaultTextEditingShortcuts extends StatelessWidget {
// macOS document shortcuts: https://support.apple.com/en-us/HT201236.
// 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
// 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
(),
},
};
static
final
Map
<
ShortcutActivator
,
Intent
>
_macShortcuts
=
_iOSShortcuts
;
// There is no complete documentation of iOS shortcuts.
static
final
Map
<
ShortcutActivator
,
Intent
>
_iOSShortcuts
=
<
ShortcutActivator
,
Intent
>{
...
...
@@ -399,42 +374,7 @@ class DefaultTextEditingShortcuts extends StatelessWidget {
SingleActivator
(
LogicalKeyboardKey
.
backspace
,
meta:
true
,
shift:
pressShift
):
const
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
delete
,
meta:
true
,
shift:
pressShift
):
const
DoNothingAndStopPropagationTextIntent
(),
},
const
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
alt:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
alt:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
alt:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
alt:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
shift:
true
,
alt:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
shift:
true
,
alt:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
shift:
true
,
alt:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
shift:
true
,
alt:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
control:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
control:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
shift:
true
,
control:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
shift:
true
,
control:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
end
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
home
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
meta:
true
):
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
,
shift:
true
,
meta:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
shift:
true
,
meta:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
shift:
true
,
meta:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
shift:
true
,
meta:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
shift:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
shift:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
shift:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
shift:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
end
,
shift:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
home
,
shift:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
end
,
control:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
home
,
control:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
space
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
enter
):
const
DoNothingAndStopPropagationTextIntent
(),
...
_commonDisablingTextShortcuts
,
const
SingleActivator
(
LogicalKeyboardKey
.
keyX
,
control:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
keyX
,
meta:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
keyC
,
control:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
...
...
@@ -445,6 +385,53 @@ class DefaultTextEditingShortcuts extends StatelessWidget {
const
SingleActivator
(
LogicalKeyboardKey
.
keyA
,
meta:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
};
static
const
Map
<
ShortcutActivator
,
Intent
>
_commonDisablingTextShortcuts
=
<
ShortcutActivator
,
Intent
>{
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
alt:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
alt:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
alt:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
alt:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
shift:
true
,
alt:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
shift:
true
,
alt:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
shift:
true
,
alt:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
shift:
true
,
alt:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
meta:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
meta:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
meta:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
meta:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
shift:
true
,
meta:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
shift:
true
,
meta:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
shift:
true
,
meta:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
shift:
true
,
meta:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
,
shift:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
shift:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
shift:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
,
shift:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
end
,
shift:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
home
,
shift:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowDown
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowUp
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
control:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
control:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
shift:
true
,
control:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
shift:
true
,
control:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
end
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
home
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
end
,
control:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
home
,
control:
true
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
space
):
DoNothingAndStopPropagationTextIntent
(),
SingleActivator
(
LogicalKeyboardKey
.
enter
):
DoNothingAndStopPropagationTextIntent
(),
};
static
final
Map
<
ShortcutActivator
,
Intent
>
_macDisablingTextShortcuts
=
<
ShortcutActivator
,
Intent
>{
...
_commonDisablingTextShortcuts
,
const
SingleActivator
(
LogicalKeyboardKey
.
escape
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
tab
):
const
DoNothingAndStopPropagationTextIntent
(),
const
SingleActivator
(
LogicalKeyboardKey
.
tab
,
shift:
true
):
const
DoNothingAndStopPropagationTextIntent
(),
};
static
Map
<
ShortcutActivator
,
Intent
>
get
_shortcuts
{
switch
(
defaultTargetPlatform
)
{
case
TargetPlatform
.
android
:
...
...
@@ -462,21 +449,39 @@ class DefaultTextEditingShortcuts extends StatelessWidget {
}
}
Map
<
ShortcutActivator
,
Intent
>?
_getDisablingShortcut
()
{
if
(
kIsWeb
)
{
return
_webDisablingTextShortcuts
;
}
switch
(
defaultTargetPlatform
)
{
case
TargetPlatform
.
android
:
case
TargetPlatform
.
fuchsia
:
case
TargetPlatform
.
iOS
:
case
TargetPlatform
.
linux
:
case
TargetPlatform
.
windows
:
return
null
;
case
TargetPlatform
.
macOS
:
return
_macDisablingTextShortcuts
;
}
}
@override
Widget
build
(
BuildContext
context
)
{
Widget
result
=
child
;
if
(
kIsWeb
)
{
// On the web, these shortcuts make sure of the following:
final
Map
<
ShortcutActivator
,
Intent
>?
disablingShortcut
=
_getDisablingShortcut
();
if
(
disablingShortcut
!=
null
)
{
// These shortcuts make sure of the following:
//
// 1. Shortcuts fired when an EditableText is focused are ignored and
// forwarded to the
browser
by the EditableText's Actions, because it
// forwarded to the
platform
by the EditableText's Actions, because it
// maps DoNothingAndStopPropagationTextIntent to DoNothingAction.
// 2. Shortcuts fired when no EditableText is focused will still trigger
// _shortcuts assuming DoNothingAndStopPropagationTextIntent is
// unhandled elsewhere.
result
=
Shortcuts
(
debugLabel:
'<Web Disabling Text Editing Shortcuts>'
,
shortcuts:
_webDisablingTextShortcuts
,
shortcuts:
disablingShortcut
,
child:
result
);
}
...
...
packages/flutter/test/widgets/default_text_editing_shortcuts_test.dart
0 → 100644
View file @
1dd6a233
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
Future
<
void
>
sendKeyCombination
(
WidgetTester
tester
,
SingleActivator
activator
,
)
async
{
final
List
<
LogicalKeyboardKey
>
modifiers
=
<
LogicalKeyboardKey
>[
if
(
activator
.
control
)
LogicalKeyboardKey
.
control
,
if
(
activator
.
shift
)
LogicalKeyboardKey
.
shift
,
if
(
activator
.
alt
)
LogicalKeyboardKey
.
alt
,
if
(
activator
.
meta
)
LogicalKeyboardKey
.
meta
,
];
for
(
final
LogicalKeyboardKey
modifier
in
modifiers
)
{
await
tester
.
sendKeyDownEvent
(
modifier
);
}
await
tester
.
sendKeyDownEvent
(
activator
.
trigger
);
await
tester
.
sendKeyUpEvent
(
activator
.
trigger
);
await
tester
.
pump
();
for
(
final
LogicalKeyboardKey
modifier
in
modifiers
.
reversed
)
{
await
tester
.
sendKeyUpEvent
(
modifier
);
}
}
void
main
(
)
{
Widget
buildSpyAboveEditableText
({
required
FocusNode
editableFocusNode
,
required
FocusNode
spyFocusNode
,
})
{
return
MaterialApp
(
home:
Align
(
alignment:
Alignment
.
topLeft
,
child:
SizedBox
(
// Softwrap at exactly 20 characters.
width:
201
,
height:
200
,
child:
ActionSpy
(
focusNode:
spyFocusNode
,
child:
EditableText
(
controller:
TextEditingController
(
text:
'dummy text'
),
showSelectionHandles:
true
,
autofocus:
true
,
focusNode:
editableFocusNode
,
style:
const
TextStyle
(
fontSize:
10.0
),
textScaleFactor:
1
,
// Avoid the cursor from taking up width.
cursorWidth:
0
,
cursorColor:
Colors
.
blue
,
backgroundCursorColor:
Colors
.
grey
,
selectionControls:
materialTextSelectionControls
,
keyboardType:
TextInputType
.
text
,
maxLines:
null
,
textAlign:
TextAlign
.
left
,
),
),
),
),
);
}
group
(
'macOS does not accept shortcuts if focus under EditableText'
,
()
{
final
TargetPlatformVariant
macOSOnly
=
TargetPlatformVariant
.
only
(
TargetPlatform
.
macOS
);
testWidgets
(
'word modifier + arrowLeft'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
editable
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
},
variant:
macOSOnly
);
testWidgets
(
'word modifier + arrowRight'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
editable
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
},
variant:
macOSOnly
);
testWidgets
(
'line modifier + arrowLeft'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
editable
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
},
variant:
macOSOnly
);
testWidgets
(
'line modifier + arrowRight'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
editable
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
},
variant:
macOSOnly
);
testWidgets
(
'word modifier + arrow key movement'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
editable
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
},
variant:
macOSOnly
);
testWidgets
(
'line modifier + arrow key movement'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
editable
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isNull
);
},
variant:
macOSOnly
);
});
group
(
'macOS does accept shortcuts if focus above EditableText'
,
()
{
final
TargetPlatformVariant
macOSOnly
=
TargetPlatformVariant
.
only
(
TargetPlatform
.
macOS
);
testWidgets
(
'word modifier + arrowLeft'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
spy
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToNextWordBoundaryIntent
>());
},
variant:
macOSOnly
);
testWidgets
(
'word modifier + arrowRight'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
spy
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToNextWordBoundaryIntent
>());
},
variant:
macOSOnly
);
testWidgets
(
'line modifier + arrowLeft'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
spy
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToLineBreakIntent
>());
},
variant:
macOSOnly
);
testWidgets
(
'line modifier + arrowRight'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
spy
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToLineBreakIntent
>());
},
variant:
macOSOnly
);
testWidgets
(
'word modifier + arrow key movement'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
spy
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToNextWordBoundaryIntent
>());
state
.
lastIntent
=
null
;
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToNextWordBoundaryIntent
>());
state
.
lastIntent
=
null
;
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToNextWordBoundaryIntent
>());
state
.
lastIntent
=
null
;
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
alt:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToNextWordBoundaryIntent
>());
},
variant:
macOSOnly
);
testWidgets
(
'line modifier + arrow key movement'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
testTextInput
.
unregister
();
addTearDown
((){
tester
.
binding
.
testTextInput
.
register
();
});
final
FocusNode
editable
=
FocusNode
();
final
FocusNode
spy
=
FocusNode
();
await
tester
.
pumpWidget
(
buildSpyAboveEditableText
(
editableFocusNode:
editable
,
spyFocusNode:
spy
,
),
);
spy
.
requestFocus
();
await
tester
.
pump
();
final
ActionSpyState
state
=
tester
.
state
<
ActionSpyState
>(
find
.
byType
(
ActionSpy
));
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToLineBreakIntent
>());
state
.
lastIntent
=
null
;
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowLeft
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToLineBreakIntent
>());
state
.
lastIntent
=
null
;
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToLineBreakIntent
>());
state
.
lastIntent
=
null
;
await
sendKeyCombination
(
tester
,
const
SingleActivator
(
LogicalKeyboardKey
.
arrowRight
,
meta:
true
));
await
tester
.
pump
();
expect
(
state
.
lastIntent
,
isA
<
ExtendSelectionToLineBreakIntent
>());
},
variant:
macOSOnly
);
},
skip:
kIsWeb
);
// [intended] specific tests target non-web.
}
class
ActionSpy
extends
StatefulWidget
{
const
ActionSpy
({
super
.
key
,
required
this
.
focusNode
,
required
this
.
child
});
final
FocusNode
focusNode
;
final
Widget
child
;
@override
State
<
ActionSpy
>
createState
()
=>
ActionSpyState
();
}
class
ActionSpyState
extends
State
<
ActionSpy
>
{
Intent
?
lastIntent
;
late
final
Map
<
Type
,
Action
<
Intent
>>
_actions
=
<
Type
,
Action
<
Intent
>>{
ExtendSelectionByCharacterIntent:
CallbackAction
<
ExtendSelectionByCharacterIntent
>(
onInvoke:
_captureIntent
),
ExtendSelectionToNextWordBoundaryIntent:
CallbackAction
<
ExtendSelectionToNextWordBoundaryIntent
>(
onInvoke:
_captureIntent
),
ExtendSelectionToLineBreakIntent:
CallbackAction
<
ExtendSelectionToLineBreakIntent
>(
onInvoke:
_captureIntent
),
ExpandSelectionToLineBreakIntent:
CallbackAction
<
ExpandSelectionToLineBreakIntent
>(
onInvoke:
_captureIntent
),
ExpandSelectionToDocumentBoundaryIntent:
CallbackAction
<
ExpandSelectionToDocumentBoundaryIntent
>(
onInvoke:
_captureIntent
),
ExtendSelectionVerticallyToAdjacentLineIntent:
CallbackAction
<
ExtendSelectionVerticallyToAdjacentLineIntent
>(
onInvoke:
_captureIntent
),
ExtendSelectionToDocumentBoundaryIntent:
CallbackAction
<
ExtendSelectionToDocumentBoundaryIntent
>(
onInvoke:
_captureIntent
),
ExtendSelectionToNextWordBoundaryOrCaretLocationIntent:
CallbackAction
<
ExtendSelectionToNextWordBoundaryOrCaretLocationIntent
>(
onInvoke:
_captureIntent
),
};
// ignore: use_setters_to_change_properties
void
_captureIntent
(
Intent
intent
)
{
lastIntent
=
intent
;
}
@override
Widget
build
(
BuildContext
context
)
{
return
Actions
(
actions:
_actions
,
child:
Focus
(
focusNode:
widget
.
focusNode
,
child:
widget
.
child
,
),
);
}
}
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