Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b08c6b9

Browse files
authored
Fixing synthesizing keys for multiple keys pressed down on flutter web (#19632)
1 parent bb9dfcf commit b08c6b9

File tree

2 files changed

+42
-14
lines changed

2 files changed

+42
-14
lines changed

lib/web_ui/lib/src/engine/keyboard.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ class Keyboard {
9191

9292
final String timerKey = keyboardEvent.code!;
9393

94-
// Don't synthesize a keyup event for modifier keys because the browser always
95-
// sends a keyup event for those.
94+
// Don't handle synthesizing a keyup event for modifier keys
9695
if (!_isModifierKey(event)) {
9796
// When the user enters a browser/system shortcut (e.g. `cmd+alt+i`) the
9897
// browser doesn't send a keyup for it. This puts the framework in a
@@ -103,7 +102,10 @@ class Keyboard {
103102
// event within a specific duration ([_keydownCancelDuration]) we assume
104103
// the user has released the key and we synthesize a keyup event.
105104
_keydownTimers[timerKey]?.cancel();
106-
if (event.type == 'keydown') {
105+
106+
// Only keys affected by modifiers, require synthesizing
107+
// because the browser always sends a keyup event otherwise
108+
if (event.type == 'keydown' && _isAffectedByModifiers(event)) {
107109
_keydownTimers[timerKey] = Timer(_keydownCancelDuration, () {
108110
_keydownTimers.remove(timerKey);
109111
_synthesizeKeyup(event);
@@ -185,4 +187,11 @@ bool _isModifierKey(html.KeyboardEvent event) {
185187
return key == 'Meta' || key == 'Shift' || key == 'Alt' || key == 'Control';
186188
}
187189

190+
/// Returns true if the [event] is been affects by any of the modifiers key
191+
///
192+
/// This is a strong indication that this key is been used for a shortcut
193+
bool _isAffectedByModifiers(html.KeyboardEvent event) {
194+
return event.ctrlKey || event.shiftKey || event.altKey || event.metaKey;
195+
}
196+
188197
void _noopCallback(ByteData? data) {}

lib/web_ui/test/keyboard_test.dart

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -473,18 +473,37 @@ void testMain() {
473473
}
474474
messages.clear();
475475

476-
// When repeat events stop for a long-enough period of time, a keyup
477-
// should be synthesized.
476+
Keyboard.instance.dispose();
477+
},
478+
);
479+
480+
testFakeAsync(
481+
'do not synthesize keyup when keys are not affected by meta modifiers',
482+
(FakeAsync async) {
483+
Keyboard.initialize();
484+
485+
List<Map<String, dynamic>> messages = <Map<String, dynamic>>[];
486+
ui.window.onPlatformMessage = (String channel, ByteData data,
487+
ui.PlatformMessageResponseCallback callback) {
488+
messages.add(const JSONMessageCodec().decodeMessage(data));
489+
};
490+
491+
dispatchKeyboardEvent(
492+
'keydown',
493+
key: 'i',
494+
code: 'KeyI',
495+
);
496+
dispatchKeyboardEvent(
497+
'keydown',
498+
key: 'o',
499+
code: 'KeyO',
500+
);
501+
messages.clear();
502+
503+
// Wait for a long-enough period of time and no events
504+
// should be synthesized
478505
async.elapse(Duration(seconds: 3));
479-
expect(messages, <Map<String, dynamic>>[
480-
<String, dynamic>{
481-
'type': 'keyup',
482-
'keymap': 'web',
483-
'key': 'i',
484-
'code': 'KeyI',
485-
'metaState': 0x0,
486-
}
487-
]);
506+
expect(messages, hasLength(0));
488507

489508
Keyboard.instance.dispose();
490509
},

0 commit comments

Comments
 (0)