Fixing synthesizing keys for multiple keys pressed down on flutter web (flutter/engine#19632)

This commit is contained in:
Erick 2020-08-26 14:33:03 -03:00 committed by GitHub
parent f6a0c426f9
commit 2faca2ac4e
2 changed files with 42 additions and 14 deletions

View File

@ -91,8 +91,7 @@ class Keyboard {
final String timerKey = keyboardEvent.code!;
// Don't synthesize a keyup event for modifier keys because the browser always
// sends a keyup event for those.
// Don't handle synthesizing a keyup event for modifier keys
if (!_isModifierKey(event)) {
// When the user enters a browser/system shortcut (e.g. `cmd+alt+i`) the
// browser doesn't send a keyup for it. This puts the framework in a
@ -103,7 +102,10 @@ class Keyboard {
// event within a specific duration ([_keydownCancelDuration]) we assume
// the user has released the key and we synthesize a keyup event.
_keydownTimers[timerKey]?.cancel();
if (event.type == 'keydown') {
// Only keys affected by modifiers, require synthesizing
// because the browser always sends a keyup event otherwise
if (event.type == 'keydown' && _isAffectedByModifiers(event)) {
_keydownTimers[timerKey] = Timer(_keydownCancelDuration, () {
_keydownTimers.remove(timerKey);
_synthesizeKeyup(event);
@ -185,4 +187,11 @@ bool _isModifierKey(html.KeyboardEvent event) {
return key == 'Meta' || key == 'Shift' || key == 'Alt' || key == 'Control';
}
/// Returns true if the [event] is been affects by any of the modifiers key
///
/// This is a strong indication that this key is been used for a shortcut
bool _isAffectedByModifiers(html.KeyboardEvent event) {
return event.ctrlKey || event.shiftKey || event.altKey || event.metaKey;
}
void _noopCallback(ByteData? data) {}

View File

@ -473,18 +473,37 @@ void testMain() {
}
messages.clear();
// When repeat events stop for a long-enough period of time, a keyup
// should be synthesized.
Keyboard.instance.dispose();
},
);
testFakeAsync(
'do not synthesize keyup when keys are not affected by meta modifiers',
(FakeAsync async) {
Keyboard.initialize();
List<Map<String, dynamic>> messages = <Map<String, dynamic>>[];
ui.window.onPlatformMessage = (String channel, ByteData data,
ui.PlatformMessageResponseCallback callback) {
messages.add(const JSONMessageCodec().decodeMessage(data));
};
dispatchKeyboardEvent(
'keydown',
key: 'i',
code: 'KeyI',
);
dispatchKeyboardEvent(
'keydown',
key: 'o',
code: 'KeyO',
);
messages.clear();
// Wait for a long-enough period of time and no events
// should be synthesized
async.elapse(Duration(seconds: 3));
expect(messages, <Map<String, dynamic>>[
<String, dynamic>{
'type': 'keyup',
'keymap': 'web',
'key': 'i',
'code': 'KeyI',
'metaState': 0x0,
}
]);
expect(messages, hasLength(0));
Keyboard.instance.dispose();
},