Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions lib/web_ui/lib/src/engine/keyboard_binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -475,20 +475,25 @@ class KeyboardConverter {

// After updating _pressingRecords, synchronize modifier states. The
// `event.***Key` fields can be used to reduce some omitted modifier key
// events. We can deduce key cancel events if they are false. Key sync
// events can not be deduced since we don't know which physical key they
// events. We can synthesize key up events if they are false. Key down
// events can not be synthesized since we don't know which physical key they
// represent.
_kLogicalKeyToModifierGetter.forEach((int logicalKey, _ModifierGetter getModifier) {
if (_pressingRecords.containsValue(logicalKey) && !getModifier(event)) {
_kLogicalKeyToModifierGetter.forEach((int testeeLogicalKey, _ModifierGetter getModifier) {
// Do not synthesize for the key of the current event. The event is the
// ground truth.
if (logicalKey == testeeLogicalKey) {
return;
}
if (_pressingRecords.containsValue(testeeLogicalKey) && !getModifier(event)) {
_pressingRecords.removeWhere((int physicalKey, int logicalRecord) {
if (logicalRecord != logicalKey)
if (logicalRecord != testeeLogicalKey)
return false;

_dispatchKeyData!(ui.KeyData(
timeStamp: timeStamp,
type: ui.KeyEventType.up,
physical: physicalKey,
logical: logicalKey,
logical: testeeLogicalKey,
character: null,
synthesized: true,
));
Expand Down
54 changes: 54 additions & 0 deletions lib/web_ui/test/keyboard_converter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,60 @@ void testMain() {
character: 'a',
);
});

// Regression test for https://github.com/flutter/flutter/issues/99297.
//
// On Linux Chrome, when holding ShiftLeft and pressing MetaLeft (Win key),
// the MetaLeft down event has metaKey true, while the Meta up event has
// metaKey false. This violates the definition of metaKey, and does not happen
// in nearly any other cases for any other keys.
test('Ignore inconsistent modifier flag of the current modifier', () {
final List<ui.KeyData> keyDataList = <ui.KeyData>[];
final KeyboardConverter converter = KeyboardConverter((ui.KeyData key) {
keyDataList.add(key);
return true;
}, onMacOs: false);

converter.handleEvent(keyDownEvent('ShiftLeft', 'Shift', kShift, kLocationLeft));
expectKeyData(keyDataList.last,
type: ui.KeyEventType.down,
physical: kPhysicalShiftLeft,
logical: kLogicalShiftLeft,
character: null,
);
keyDataList.clear();

converter.handleEvent(keyDownEvent('MetaLeft', 'Meta', kShift /* No kMeta here! */, kLocationLeft));
// Only a MetaLeft down event, no synthesized MetaLeft up events.
expect(keyDataList, hasLength(1));
expectKeyData(keyDataList.first,
type: ui.KeyEventType.down,
physical: kPhysicalMetaLeft,
logical: kLogicalMetaLeft,
character: null,
);
keyDataList.clear();

converter.handleEvent(keyUpEvent('MetaLeft', 'Meta', kShift | kMeta /* Yes, kMeta here! */, kLocationLeft));
// Only a MetaLeft down event, no synthesized MetaLeft up events.
expect(keyDataList, hasLength(1));
expectKeyData(keyDataList.first,
type: ui.KeyEventType.up,
physical: kPhysicalMetaLeft,
logical: kLogicalMetaLeft,
character: null,
);
keyDataList.clear();

converter.handleEvent(keyUpEvent('ShiftLeft', 'Shift', 0, kLocationLeft));
expectKeyData(keyDataList.last,
type: ui.KeyEventType.up,
physical: kPhysicalShiftLeft,
logical: kLogicalShiftLeft,
character: null,
);
keyDataList.clear();
});
}

class MockKeyboardEvent implements FlutterHtmlKeyboardEvent {
Expand Down