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
01c98fa9
Unverified
Commit
01c98fa9
authored
3 years ago
by
Tong Mu
Committed by
GitHub
3 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Character activator (#81807)
parent
7cdd33fe
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
289 additions
and
54 deletions
+289
-54
shortcuts.dart
packages/flutter/lib/src/widgets/shortcuts.dart
+148
-26
shortcuts_test.dart
packages/flutter/test/widgets/shortcuts_test.dart
+111
-2
controller.dart
packages/flutter_test/lib/src/controller.dart
+2
-2
event_simulation.dart
packages/flutter_test/lib/src/event_simulation.dart
+28
-24
No files found.
packages/flutter/lib/src/widgets/shortcuts.dart
View file @
01c98fa9
...
...
@@ -160,6 +160,8 @@ class KeySet<T extends KeyboardKey> {
///
/// * [SingleActivator], an implementation that represents a single key combined
/// with modifiers (control, shift, alt, meta).
/// * [CharacterActivator], an implementation that represents key combinations
/// that result in the specified character, such as question mark.
/// * [LogicalKeySet], an implementation that requires one or more
/// [LogicalKeyboardKey]s to be pressed at the same time. Prefer
/// [SingleActivator] when possible.
...
...
@@ -179,7 +181,13 @@ abstract class ShortcutActivator {
/// [Intent]s are stored in a [Map] and indexed by trigger keys. Subclasses
/// should make sure that the return value of this method does not change
/// throughout the lifespan of this object.
Iterable
<
LogicalKeyboardKey
>
get
triggers
;
///
/// This method might also return null, which means this activator declares
/// all keys as the trigger key. All activators whose [triggers] returns null
/// will be tested with [accepts] on every event. Since this becomes a
/// linear search, and having too many might impact performance, it is
/// preferred to return non-null [triggers] whenever possible.
Iterable
<
LogicalKeyboardKey
>?
get
triggers
;
/// Whether the triggering `event` and the keyboard `state` at the time of the
/// event meet required conditions, providing that the event is a triggering
...
...
@@ -194,6 +202,9 @@ abstract class ShortcutActivator {
/// this is only used to query whether [RawKeyboard.keysPressed] contains
/// a key.
///
/// Since [ShortcutActivator] accepts all event types, subclasses might want
/// to check the event type in [accepts].
///
/// See also:
///
/// * [LogicalKeyboardKey.collapseSynonyms], which helps deciding whether a
...
...
@@ -323,9 +334,6 @@ class LogicalKeySet extends KeySet<LogicalKeyboardKey> with Diagnosticable
LogicalKeyboardKey
.
meta
:
<
LogicalKeyboardKey
>[
LogicalKeyboardKey
.
metaLeft
,
LogicalKeyboardKey
.
metaRight
],
};
/// Returns a description of the key set that is short and readable.
///
/// Intended to be used in debug mode for logging purposes.
@override
String
debugDescribeKeys
()
{
final
List
<
LogicalKeyboardKey
>
sortedKeys
=
keys
.
toList
()..
sort
(
...
...
@@ -387,7 +395,7 @@ class ShortcutMapProperty extends DiagnosticsProperty<Map<ShortcutActivator, Int
/// A shortcut key combination of a single key and modifiers.
///
/// Th
is [Shortcut
Activator] implements typical shortcuts such as:
/// Th
e [Single
Activator] implements typical shortcuts such as:
///
/// * ArrowLeft
/// * Shift + Delete
...
...
@@ -412,6 +420,11 @@ class ShortcutMapProperty extends DiagnosticsProperty<Map<ShortcutActivator, Int
/// * [SingleActivator]s do not consider modifiers to be a trigger key. For
/// example, pressing ControlLeft while holding key X *will not* activate a
/// `SingleActivator(LogicalKeyboardKey.keyX, control: true)`.
///
/// See also:
///
/// * [CharacterActivator], an activator that represents key combinations
/// that result in the specified character, such as question mark.
class SingleActivator with Diagnosticable implements ShortcutActivator {
/// Create an activator of a trigger key and modifiers.
///
...
...
@@ -474,8 +487,8 @@ class SingleActivator with Diagnosticable implements ShortcutActivator {
this.meta = false,
}) : // The enumerated check with `identical` is cumbersome but the only way
// since const constructors can not call functions such as `==` or
// `Set.contains`. Checking with `identical`
is sufficient sinc
e
//
`LogicalKeyboardKey` only provides cached valu
es.
// `Set.contains`. Checking with `identical`
might not work when th
e
//
key object is created from ID, but it covers common cas
es.
assert(
!identical(trigger, LogicalKeyboardKey.control) &&
!identical(trigger, LogicalKeyboardKey.controlLeft) &&
...
...
@@ -585,6 +598,110 @@ class SingleActivator with Diagnosticable implements ShortcutActivator {
}
}
/// A shortcut combination that is triggered by a key event that produces a
/// specific character.
///
/// Keys often produce different characters when combined with modifiers. For
/// example, it might be helpful for the user to bring up a help menu by
/// pressing the question mark ('
?
'). However, there is no logical key that
/// directly represents a question mark. Althouh '
Shift
+
Slash
' produces a '
?
'
/// character on a US keyboard, its logical key is still considered a Slash key,
/// and hard-coding '
Shift
+
Slash
' in this situation is unfriendly to other
/// keyboard layouts.
///
/// For example, `CharacterActivator('
?
')` is triggered when a key combination
/// results in a question mark, which is '
Shift
+
Slash
' on a US keyboard, but
/// '
Shift
+
Comma
' on a French keyboard.
///
/// {@tool dartpad --template=stateful_widget_scaffold_center}
/// In the following example, when a key combination results in a question mark,
/// the counter is increased:
///
/// ```dart preamble
/// class HelpMenuIntent extends Intent {
/// const HelpMenuIntent();
/// }
/// ```
///
/// ```dart
/// @override
/// Widget build(BuildContext context) {
/// return Shortcuts(
/// shortcuts: const <ShortcutActivator, Intent>{
/// CharacterActivator('
?
'): HelpMenuIntent(),
/// },
/// child: Actions(
/// actions: <Type, Action<Intent>>{
/// HelpMenuIntent: CallbackAction<HelpMenuIntent>(
/// onInvoke: (HelpMenuIntent intent) {
/// ScaffoldMessenger.of(context).showSnackBar(
/// const SnackBar(content: Text('
Keep
calm
and
carry
on
!
')),
/// );
/// return null;
/// },
/// ),
/// },
/// child: Focus(
/// autofocus: true,
/// child: Column(
/// children: const <Widget>[
/// Text('
Press
question
mark
for
help
'),
/// ],
/// ),
/// ),
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [SingleActivator], an activator that represents a single key combined
/// with modifiers, such as `Ctrl+C`.
class CharacterActivator with Diagnosticable implements ShortcutActivator {
/// Create a [CharacterActivator] from the triggering character.
const CharacterActivator(this.character);
/// The character of the triggering event.
///
/// This is typically a single-character string, such as '
?
' or '
œ
', although
/// [CharacterActivator] doesn'
t
check
the
length
of
[
character
]
or
whether
it
/// can be matched by any key combination at all. It is case-sensitive, since
/// the [character] is directly compared by `==` to the character reported by
/// the platform.
///
/// See also:
///
/// * [RawKeyEvent.character], the character of a key event.
final
String
character
;
@override
Iterable
<
LogicalKeyboardKey
>?
get
triggers
=>
null
;
@override
bool
accepts
(
RawKeyEvent
event
,
RawKeyboard
state
)
{
return
event
is
RawKeyDownEvent
&&
event
.
character
==
character
;
}
@override
String
debugDescribeKeys
()
{
String
result
=
''
;
assert
(()
{
result
=
"'
$character
'"
;
return
true
;
}());
return
result
;
}
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
add
(
StringProperty
(
'character'
,
character
));
}
}
class
_ActivatorIntentPair
with
Diagnosticable
{
const
_ActivatorIntentPair
(
this
.
activator
,
this
.
intent
);
final
ShortcutActivator
activator
;
...
...
@@ -639,20 +756,22 @@ class ShortcutManager extends ChangeNotifier with Diagnosticable {
}
}
static
Map
<
LogicalKeyboardKey
,
List
<
_ActivatorIntentPair
>>
_indexShortcuts
(
Map
<
ShortcutActivator
,
Intent
>
source
)
{
final
Map
<
LogicalKeyboardKey
,
List
<
_ActivatorIntentPair
>>
result
=
<
LogicalKeyboardKey
,
List
<
_ActivatorIntentPair
>>{};
static
Map
<
LogicalKeyboardKey
?
,
List
<
_ActivatorIntentPair
>>
_indexShortcuts
(
Map
<
ShortcutActivator
,
Intent
>
source
)
{
final
Map
<
LogicalKeyboardKey
?,
List
<
_ActivatorIntentPair
>>
result
=
<
LogicalKeyboardKey
?
,
List
<
_ActivatorIntentPair
>>{};
source
.
forEach
((
ShortcutActivator
activator
,
Intent
intent
)
{
for
(
final
LogicalKeyboardKey
trigger
in
activator
.
triggers
)
{
// This intermediate variable is necessary to comply with Dart analyzer.
final
Iterable
<
LogicalKeyboardKey
?>?
nullableTriggers
=
activator
.
triggers
;
for
(
final
LogicalKeyboardKey
?
trigger
in
nullableTriggers
??
<
LogicalKeyboardKey
?>[
null
])
{
result
.
putIfAbsent
(
trigger
,
()
=>
<
_ActivatorIntentPair
>[])
.
add
(
_ActivatorIntentPair
(
activator
,
intent
));
}
});
return
result
;
}
Map
<
LogicalKeyboardKey
,
List
<
_ActivatorIntentPair
>>
get
_indexedShortcuts
{
Map
<
LogicalKeyboardKey
?
,
List
<
_ActivatorIntentPair
>>
get
_indexedShortcuts
{
return
_indexedShortcutsCache
??=
_indexShortcuts
(
_shortcuts
);
}
Map
<
LogicalKeyboardKey
,
List
<
_ActivatorIntentPair
>>?
_indexedShortcutsCache
;
Map
<
LogicalKeyboardKey
?
,
List
<
_ActivatorIntentPair
>>?
_indexedShortcutsCache
;
/// Returns the [Intent], if any, that matches the current set of pressed
/// keys.
...
...
@@ -662,9 +781,12 @@ class ShortcutManager extends ChangeNotifier with Diagnosticable {
/// Defaults to a set derived from [RawKeyboard.keysPressed] if `keysPressed`
/// is not supplied.
Intent
?
_find
(
RawKeyEvent
event
,
RawKeyboard
state
)
{
final
List
<
_ActivatorIntentPair
>?
candidates
=
_indexedShortcuts
[
event
.
logicalKey
];
if
(
candidates
==
null
)
return
null
;
final
List
<
_ActivatorIntentPair
>?
candidatesByKey
=
_indexedShortcuts
[
event
.
logicalKey
];
final
List
<
_ActivatorIntentPair
>?
candidatesByNull
=
_indexedShortcuts
[
null
];
final
List
<
_ActivatorIntentPair
>
candidates
=
<
_ActivatorIntentPair
>[
if
(
candidatesByKey
!=
null
)
...
candidatesByKey
,
if
(
candidatesByNull
!=
null
)
...
candidatesByNull
,
];
for
(
final
_ActivatorIntentPair
activatorIntent
in
candidates
)
{
if
(
activatorIntent
.
activator
.
accepts
(
event
,
state
))
{
return
activatorIntent
.
intent
;
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/shortcuts_test.dart
View file @
01c98fa9
...
...
@@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart';
typedef
PostInvokeCallback
=
void
Function
({
Action
<
Intent
>
action
,
Intent
intent
,
BuildContext
?
context
,
ActionDispatcher
dispatcher
});
class
TestAction
extends
CallbackAction
<
Test
Intent
>
{
class
TestAction
extends
CallbackAction
<
Intent
>
{
TestAction
({
required
OnInvokeCallback
onInvoke
,
})
:
assert
(
onInvoke
!=
null
),
...
...
@@ -31,10 +31,47 @@ class TestDispatcher extends ActionDispatcher {
}
}
/// An activator that accepts down events that has [key] as the logical key.
///
/// This class is used only to tests. It is intentionally designed poorly by
/// returning null in [triggers], and checks [key] in [accepts].
class
DumbLogicalActivator
extends
ShortcutActivator
{
const
DumbLogicalActivator
(
this
.
key
);
final
LogicalKeyboardKey
key
;
@override
Iterable
<
LogicalKeyboardKey
>?
get
triggers
=>
null
;
@override
bool
accepts
(
RawKeyEvent
event
,
RawKeyboard
state
)
{
return
event
is
RawKeyDownEvent
&&
event
.
logicalKey
==
key
;
}
/// Returns a short and readable description of the key combination.
///
/// Intended to be used in debug mode for logging purposes. In release mode,
/// [debugDescribeKeys] returns an empty string.
@override
String
debugDescribeKeys
()
{
String
result
=
''
;
assert
(()
{
result
=
key
.
keyLabel
;
return
true
;
}());
return
result
;
}
}
class
TestIntent
extends
Intent
{
const
TestIntent
();
}
class
TestIntent2
extends
Intent
{
const
TestIntent2
();
}
class
TestShortcutManager
extends
ShortcutManager
{
TestShortcutManager
(
this
.
keys
);
...
...
@@ -49,7 +86,13 @@ class TestShortcutManager extends ShortcutManager {
}
}
Widget
activatorTester
(
ShortcutActivator
activator
,
ValueSetter
<
Intent
>
onInvoke
)
{
Widget
activatorTester
(
ShortcutActivator
activator
,
ValueSetter
<
Intent
>
onInvoke
,
[
ShortcutActivator
?
activator2
,
ValueSetter
<
Intent
>?
onInvoke2
,
])
{
final
bool
hasSecond
=
activator2
!=
null
&&
onInvoke2
!=
null
;
return
Actions
(
key:
GlobalKey
(),
actions:
<
Type
,
Action
<
Intent
>>{
...
...
@@ -57,10 +100,16 @@ Widget activatorTester(ShortcutActivator activator, ValueSetter<Intent> onInvoke
onInvoke
(
intent
);
return
true
;
}),
if
(
hasSecond
)
TestIntent2:
TestAction
(
onInvoke:
(
Intent
intent
)
{
onInvoke2
(
intent
);
}),
},
child:
Shortcuts
(
shortcuts:
<
ShortcutActivator
,
Intent
>{
activator:
const
TestIntent
(),
if
(
hasSecond
)
activator2:
const
TestIntent2
(),
},
child:
const
Focus
(
autofocus:
true
,
...
...
@@ -967,5 +1016,65 @@ void main() {
expect
(
value
,
isTrue
);
expect
(
controller
.
position
.
pixels
,
0.0
);
});
testWidgets
(
'Shortcuts support activators that returns null in triggers'
,
(
WidgetTester
tester
)
async
{
int
invoked
=
0
;
await
tester
.
pumpWidget
(
activatorTester
(
const
DumbLogicalActivator
(
LogicalKeyboardKey
.
keyC
),
(
Intent
intent
)
{
invoked
+=
1
;
},
const
SingleActivator
(
LogicalKeyboardKey
.
keyC
,
control:
true
),
(
Intent
intent
)
{
invoked
+=
10
;
},
));
await
tester
.
pump
();
// Press KeyC: Accepted by DumbLogicalActivator
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
keyC
);
expect
(
invoked
,
1
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
keyC
);
expect
(
invoked
,
1
);
invoked
=
0
;
// Press ControlLeft + KeyC: Accepted by SingleActivator
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
controlLeft
);
expect
(
invoked
,
0
);
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
keyC
);
expect
(
invoked
,
10
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
keyC
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
controlLeft
);
expect
(
invoked
,
10
);
invoked
=
0
;
// Press ControlLeft + ShiftLeft + KeyC: Accepted by DumbLogicalActivator
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
shiftLeft
);
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
controlLeft
);
expect
(
invoked
,
0
);
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
keyC
);
expect
(
invoked
,
1
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
keyC
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
controlLeft
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
shiftLeft
);
expect
(
invoked
,
1
);
invoked
=
0
;
});
});
group
(
'CharacterActivator'
,
()
{
testWidgets
(
'is triggered on events with correct character'
,
(
WidgetTester
tester
)
async
{
int
invoked
=
0
;
await
tester
.
pumpWidget
(
activatorTester
(
const
CharacterActivator
(
'?'
),
(
Intent
intent
)
{
invoked
+=
1
;
},
));
await
tester
.
pump
();
// Press KeyC: Accepted by DumbLogicalActivator
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
shiftLeft
);
await
tester
.
sendKeyDownEvent
(
LogicalKeyboardKey
.
slash
,
character:
'?'
);
expect
(
invoked
,
1
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
slash
);
await
tester
.
sendKeyUpEvent
(
LogicalKeyboardKey
.
shiftLeft
);
expect
(
invoked
,
1
);
invoked
=
0
;
});
});
}
This diff is collapsed.
Click to expand it.
packages/flutter_test/lib/src/controller.dart
View file @
01c98fa9
...
...
@@ -1021,10 +1021,10 @@ abstract class WidgetController {
///
/// - [sendKeyUpEvent] to simulate the corresponding key up event.
/// - [sendKeyEvent] to simulate both the key up and key down in the same call.
Future
<
bool
>
sendKeyDownEvent
(
LogicalKeyboardKey
key
,
{
String
platform
=
_defaultPlatform
})
async
{
Future
<
bool
>
sendKeyDownEvent
(
LogicalKeyboardKey
key
,
{
String
?
character
,
String
platform
=
_defaultPlatform
})
async
{
assert
(
platform
!=
null
);
// Internally wrapped in async guard.
return
simulateKeyDownEvent
(
key
,
platform:
platform
);
return
simulateKeyDownEvent
(
key
,
character:
character
,
platform:
platform
);
}
/// Simulates sending a physical key up event through the system channel.
...
...
This diff is collapsed.
Click to expand it.
packages/flutter_test/lib/src/event_simulation.dart
View file @
01c98fa9
...
...
@@ -194,6 +194,7 @@ class KeyEventSimulator {
required
String
platform
,
bool
isDown
=
true
,
PhysicalKeyboardKey
?
physicalKey
,
String
?
character
,
})
{
assert
(
_osIsSupported
(
platform
),
'Platform
$platform
not supported for key simulation'
);
...
...
@@ -211,27 +212,31 @@ class KeyEventSimulator {
'keymap'
:
platform
,
};
if
(
kIsWeb
)
{
final
String
resultCharacter
=
character
??
_keyLabel
(
key
);
void
assignWeb
()
{
result
[
'code'
]
=
_getWebKeyCode
(
key
);
result
[
'key'
]
=
_keyLabel
(
key
)
;
result
[
'key'
]
=
resultCharacter
;
result
[
'metaState'
]
=
_getWebModifierFlags
(
key
,
isDown
);
}
if
(
kIsWeb
)
{
assignWeb
();
return
result
;
}
switch
(
platform
)
{
case
'android'
:
result
[
'keyCode'
]
=
keyCode
;
if
(
_keyLabel
(
key
)
.
isNotEmpty
)
{
result
[
'codePoint'
]
=
_keyLabel
(
key
)
.
codeUnitAt
(
0
);
result
[
'character'
]
=
_keyLabel
(
key
)
;
if
(
resultCharacter
.
isNotEmpty
)
{
result
[
'codePoint'
]
=
resultCharacter
.
codeUnitAt
(
0
);
result
[
'character'
]
=
resultCharacter
;
}
result
[
'scanCode'
]
=
scanCode
;
result
[
'metaState'
]
=
_getAndroidModifierFlags
(
key
,
isDown
);
break
;
case
'fuchsia'
:
result
[
'hidUsage'
]
=
physicalKey
.
usbHidUsage
;
if
(
_keyLabel
(
key
)
.
isNotEmpty
)
{
result
[
'codePoint'
]
=
_keyLabel
(
key
)
.
codeUnitAt
(
0
);
if
(
resultCharacter
.
isNotEmpty
)
{
result
[
'codePoint'
]
=
resultCharacter
.
codeUnitAt
(
0
);
}
result
[
'modifiers'
]
=
_getFuchsiaModifierFlags
(
key
,
isDown
);
break
;
...
...
@@ -240,34 +245,33 @@ class KeyEventSimulator {
result
[
'keyCode'
]
=
keyCode
;
result
[
'scanCode'
]
=
scanCode
;
result
[
'modifiers'
]
=
_getGlfwModifierFlags
(
key
,
isDown
);
result
[
'unicodeScalarValues'
]
=
_keyLabel
(
key
).
isNotEmpty
?
_keyLabel
(
key
)
.
codeUnitAt
(
0
)
:
0
;
result
[
'unicodeScalarValues'
]
=
resultCharacter
.
isNotEmpty
?
resultCharacter
.
codeUnitAt
(
0
)
:
0
;
break
;
case
'macos'
:
result
[
'keyCode'
]
=
scanCode
;
if
(
_keyLabel
(
key
)
.
isNotEmpty
)
{
result
[
'characters'
]
=
_keyLabel
(
key
)
;
result
[
'charactersIgnoringModifiers'
]
=
_keyLabel
(
key
)
;
if
(
resultCharacter
.
isNotEmpty
)
{
result
[
'characters'
]
=
resultCharacter
;
result
[
'charactersIgnoringModifiers'
]
=
resultCharacter
;
}
result
[
'modifiers'
]
=
_getMacOsModifierFlags
(
key
,
isDown
);
break
;
case
'ios'
:
result
[
'keyCode'
]
=
scanCode
;
result
[
'characters'
]
=
_keyLabel
(
key
)
;
result
[
'charactersIgnoringModifiers'
]
=
_keyLabel
(
key
)
;
result
[
'characters'
]
=
resultCharacter
;
result
[
'charactersIgnoringModifiers'
]
=
resultCharacter
;
result
[
'modifiers'
]
=
_getIOSModifierFlags
(
key
,
isDown
);
break
;
case
'web'
:
result
[
'code'
]
=
_getWebKeyCode
(
key
);
result
[
'key'
]
=
_keyLabel
(
key
);
result
[
'metaState'
]
=
_getWebModifierFlags
(
key
,
isDown
);
break
;
case
'windows'
:
result
[
'keyCode'
]
=
keyCode
;
result
[
'scanCode'
]
=
scanCode
;
if
(
_keyLabel
(
key
)
.
isNotEmpty
)
{
result
[
'characterCodePoint'
]
=
_keyLabel
(
key
)
.
codeUnitAt
(
0
);
if
(
resultCharacter
.
isNotEmpty
)
{
result
[
'characterCodePoint'
]
=
resultCharacter
.
codeUnitAt
(
0
);
}
result
[
'modifiers'
]
=
_getWindowsModifierFlags
(
key
,
isDown
);
break
;
case
'web'
:
assignWeb
();
break
;
}
return
result
;
}
...
...
@@ -631,12 +635,12 @@ class KeyEventSimulator {
/// See also:
///
/// - [simulateKeyUpEvent] to simulate the corresponding key up event.
static
Future
<
bool
>
simulateKeyDownEvent
(
LogicalKeyboardKey
key
,
{
String
?
platform
,
PhysicalKeyboardKey
?
physicalKey
})
async
{
static
Future
<
bool
>
simulateKeyDownEvent
(
LogicalKeyboardKey
key
,
{
String
?
platform
,
PhysicalKeyboardKey
?
physicalKey
,
String
?
character
})
async
{
return
TestAsyncUtils
.
guard
<
bool
>(()
async
{
platform
??=
Platform
.
operatingSystem
;
assert
(
_osIsSupported
(
platform
!),
'Platform
$platform
not supported for key simulation'
);
final
Map
<
String
,
dynamic
>
data
=
getKeyData
(
key
,
platform:
platform
!,
isDown:
true
,
physicalKey:
physicalKey
);
final
Map
<
String
,
dynamic
>
data
=
getKeyData
(
key
,
platform:
platform
!,
isDown:
true
,
physicalKey:
physicalKey
,
character:
character
);
bool
result
=
false
;
await
ServicesBinding
.
instance
!.
defaultBinaryMessenger
.
handlePlatformMessage
(
SystemChannels
.
keyEvent
.
name
,
...
...
@@ -715,8 +719,8 @@ class KeyEventSimulator {
/// See also:
///
/// - [simulateKeyUpEvent] to simulate the corresponding key up event.
Future
<
bool
>
simulateKeyDownEvent
(
LogicalKeyboardKey
key
,
{
String
?
platform
,
PhysicalKeyboardKey
?
physicalKey
})
{
return
KeyEventSimulator
.
simulateKeyDownEvent
(
key
,
platform:
platform
,
physicalKey:
physicalKey
);
Future
<
bool
>
simulateKeyDownEvent
(
LogicalKeyboardKey
key
,
{
String
?
platform
,
PhysicalKeyboardKey
?
physicalKey
,
String
?
character
})
{
return
KeyEventSimulator
.
simulateKeyDownEvent
(
key
,
platform:
platform
,
physicalKey:
physicalKey
,
character:
character
);
}
/// Simulates sending a hardware key up event through the system channel.
...
...
This diff is collapsed.
Click to expand it.
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