Impl and test (flutter/engine#30488)
This commit is contained in:
@@ -371,9 +371,7 @@ class KeyboardConverter {
|
||||
// followed by an immediate cancel event.
|
||||
(_shouldSynthesizeCapsLockUp() && event.code! == _kPhysicalCapsLock);
|
||||
|
||||
final int? lastLogicalRecord = _pressingRecords[physicalKey];
|
||||
|
||||
ui.KeyEventType type;
|
||||
final ui.KeyEventType type;
|
||||
|
||||
if (_shouldSynthesizeCapsLockUp() && event.code! == _kPhysicalCapsLock) {
|
||||
// Case 1: Handle CapsLock on macOS
|
||||
@@ -399,28 +397,45 @@ class KeyboardConverter {
|
||||
|
||||
} else if (isPhysicalDown) {
|
||||
// Case 2: Handle key down of normal keys
|
||||
type = ui.KeyEventType.down;
|
||||
if (lastLogicalRecord != null) {
|
||||
if (_pressingRecords[physicalKey] != null) {
|
||||
// This physical key is being pressed according to the record.
|
||||
if (event.repeat ?? false) {
|
||||
// A normal repeated key.
|
||||
type = ui.KeyEventType.repeat;
|
||||
} else {
|
||||
// A non-repeated key has been pressed that has the exact physical key as
|
||||
// a currently pressed one, usually indicating multiple keyboards are
|
||||
// pressing keys with the same physical key, or the up event was lost
|
||||
// during a loss of focus. The down event is ignored.
|
||||
event.preventDefault();
|
||||
return;
|
||||
// a currently pressed one. This can mean one of the following cases:
|
||||
//
|
||||
// * Multiple keyboards are pressing keys with the same physical key.
|
||||
// * The up event was lost during a loss of focus.
|
||||
// * The previous down event was a system shortcut and its release
|
||||
// was skipped (see `_startGuardingKey`,) such as holding Ctrl and
|
||||
// pressing V then V, within the "guard window".
|
||||
//
|
||||
// The three cases can't be distinguished, and in the 3rd case, the
|
||||
// latter event must be dispatched as down events for the framework to
|
||||
// correctly recognize and choose to not to handle. Therefore, an up
|
||||
// event is synthesized before it.
|
||||
_dispatchKeyData!(ui.KeyData(
|
||||
timeStamp: timeStamp,
|
||||
type: ui.KeyEventType.up,
|
||||
physical: physicalKey,
|
||||
logical: logicalKey,
|
||||
character: null,
|
||||
synthesized: true,
|
||||
));
|
||||
_pressingRecords.remove(physicalKey);
|
||||
type = ui.KeyEventType.down;
|
||||
}
|
||||
} else {
|
||||
// This physical key is not being pressed according to the record. It's a
|
||||
// normal down event, whether the system event is a repeat or not.
|
||||
type = ui.KeyEventType.down;
|
||||
}
|
||||
|
||||
} else { // isPhysicalDown is false and not CapsLock
|
||||
// Case 2: Handle key up of normal keys
|
||||
if (lastLogicalRecord == null) {
|
||||
if (_pressingRecords[physicalKey] == null) {
|
||||
// The physical key has been released before. It indicates multiple
|
||||
// keyboards pressed keys with the same physical key. Ignore the up event.
|
||||
event.preventDefault();
|
||||
@@ -430,6 +445,10 @@ class KeyboardConverter {
|
||||
type = ui.KeyEventType.up;
|
||||
}
|
||||
|
||||
// The _pressingRecords[physicalKey] might have been changed during the last
|
||||
// `if` clause.
|
||||
final int? lastLogicalRecord = _pressingRecords[physicalKey];
|
||||
|
||||
final int? nextLogicalRecord;
|
||||
switch (type) {
|
||||
case ui.KeyEventType.down:
|
||||
|
||||
@@ -378,7 +378,7 @@ void testMain() {
|
||||
converter.handleEvent(keyUpEvent('ShiftLeft', 'Shift', 0, kLocationLeft));
|
||||
});
|
||||
|
||||
test('Duplicate down is ignored', () {
|
||||
test('Duplicate down is preceded with synthesized up', () {
|
||||
final List<ui.KeyData> keyDataList = <ui.KeyData>[];
|
||||
final KeyboardConverter converter = KeyboardConverter((ui.KeyData key) {
|
||||
keyDataList.add(key);
|
||||
@@ -392,15 +392,26 @@ void testMain() {
|
||||
);
|
||||
expect(preventedDefault, isTrue);
|
||||
preventedDefault = false;
|
||||
// A KeyUp of ShiftLeft is missed due to loss of focus.
|
||||
// A KeyUp of ShiftLeft is missed.
|
||||
|
||||
keyDataList.clear();
|
||||
converter.handleEvent(keyDownEvent('ShiftLeft', 'Shift', kShift, kLocationLeft)
|
||||
..onPreventDefault = onPreventDefault
|
||||
);
|
||||
expect(keyDataList, hasLength(1));
|
||||
expect(keyDataList[0].physical, 0);
|
||||
expect(keyDataList[0].logical, 0);
|
||||
expect(keyDataList, hasLength(2));
|
||||
expectKeyData(keyDataList.first,
|
||||
type: ui.KeyEventType.up,
|
||||
physical: kPhysicalShiftLeft,
|
||||
logical: kLogicalShiftLeft,
|
||||
character: null,
|
||||
synthesized: true,
|
||||
);
|
||||
expectKeyData(keyDataList.last,
|
||||
type: ui.KeyEventType.down,
|
||||
physical: kPhysicalShiftLeft,
|
||||
logical: kLogicalShiftLeft,
|
||||
character: null,
|
||||
);
|
||||
expect(preventedDefault, isTrue);
|
||||
|
||||
keyDataList.clear();
|
||||
|
||||
Reference in New Issue
Block a user