Unverified Commit 37005e8f authored by Tong Mu's avatar Tong Mu Committed by GitHub

RawKeyboard synthesizes key pressing state for modifier (#93897)

parent 7355cec5
......@@ -772,15 +772,22 @@ class RawKeyboard {
..._keysPressed.keys,
if (event is RawKeyDownEvent) event.physicalKey,
};
for (final ModifierKey key in modifiersPressed.keys) {
ModifierKey? thisKeyModifier;
for (final ModifierKey key in ModifierKey.values) {
final Set<PhysicalKeyboardKey>? thisModifierKeys = _modifierKeyMap[_ModifierSidePair(key, KeyboardSide.all)];
if (thisModifierKeys == null)
continue;
if (thisModifierKeys.contains(event.physicalKey)) {
thisKeyModifier = key;
}
if (modifiersPressed[key] == KeyboardSide.any) {
final Set<PhysicalKeyboardKey>? thisModifierKeys = _modifierKeyMap[_ModifierSidePair(key, KeyboardSide.all)];
anySideKeys.addAll(thisModifierKeys!);
anySideKeys.addAll(thisModifierKeys);
if (thisModifierKeys.any(keysPressedAfterEvent.contains)) {
continue;
}
}
final Set<PhysicalKeyboardKey>? mappedKeys = _modifierKeyMap[_ModifierSidePair(key, modifiersPressed[key])];
final Set<PhysicalKeyboardKey>? mappedKeys = modifiersPressed[key] == null ?
<PhysicalKeyboardKey>{} : _modifierKeyMap[_ModifierSidePair(key, modifiersPressed[key])];
assert(() {
if (mappedKeys == null) {
debugPrint(
......@@ -809,6 +816,20 @@ class RawKeyboard {
_keysPressed.remove(PhysicalKeyboardKey.fn);
}
_keysPressed.addAll(modifierKeys);
// In rare cases, the event presses a modifier key but the key does not
// exist in the modifier list. Enforce the pressing state.
if (event is RawKeyDownEvent && thisKeyModifier != null
&& !_keysPressed.containsKey(event.physicalKey)) {
// So far this inconsistancy is only found on Linux GTK for AltRight in a
// rare case. (See https://github.com/flutter/flutter/issues/93278 .) In
// other cases, this inconsistancy will be caught by an assertion later.
if (event.data is RawKeyEventDataLinux && event.physicalKey == PhysicalKeyboardKey.altRight) {
final LogicalKeyboardKey? logicalKey = _allModifiersExceptFn[event.physicalKey];
if (logicalKey != null) {
_keysPressed[event.physicalKey] = logicalKey;
}
}
}
}
final Map<PhysicalKeyboardKey, LogicalKeyboardKey> _keysPressed = <PhysicalKeyboardKey, LogicalKeyboardKey>{};
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
......@@ -348,6 +350,55 @@ void main() {
);
}, skip: isBrowser); // [intended] This is a GLFW-specific test.
// Regression test for https://github.com/flutter/flutter/issues/93278 .
//
// GTK has some weird behavior where the tested key event sequence will
// result in a AltRight down event without Alt bitmask.
testWidgets('keysPressed modifiers are synchronized with key events on Linux GTK (down events)', (WidgetTester tester) async {
expect(RawKeyboard.instance.keysPressed, isEmpty);
Future<void> simulate(bool keyDown, int scancode, int keycode, int modifiers) async {
final Map<String, dynamic> data = <String, dynamic>{
'type': keyDown ? 'keydown' : 'keyup',
'keymap': 'linux',
'toolkit': 'gtk',
'scanCode': scancode,
'keyCode': keycode,
'modifiers': modifiers,
};
// Dispatch an empty key data to disable HardwareKeyboard sanity check,
// since we're only testing if the raw keyboard can handle the message.
// In real application the embedder responder will send correct key data
// (which is tested in the engine.)
TestDefaultBinaryMessengerBinding.instance!.keyEventManager.handleKeyData(const ui.KeyData(
type: ui.KeyEventType.down,
timeStamp: Duration.zero,
logical: 0,
physical: 0,
character: null,
synthesized: false,
));
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
);
}
await simulate(true, 0x6c/*AltRight*/, 0xffea/*AltRight*/, 0x2000000);
await simulate(true, 0x32/*ShiftLeft*/, 0xfe08/*NextGroup*/, 0x2000008/*MOD3*/);
await simulate(false, 0x6c/*AltRight*/, 0xfe03/*AltRight*/, 0x2002008/*MOD3|Reserve14*/);
await simulate(true, 0x6c/*AltRight*/, 0xfe03/*AltRight*/, 0x2002000/*Reserve14*/);
expect(
RawKeyboard.instance.keysPressed,
equals(
<LogicalKeyboardKey>{
LogicalKeyboardKey.altRight,
},
),
);
}, skip: isBrowser); // [intended] This is a GTK-specific test.
testWidgets('keysPressed modifiers are synchronized with key events on web', (WidgetTester tester) async {
expect(RawKeyboard.instance.keysPressed, isEmpty);
// Generate the data for a regular key down event. Change the modifiers so
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment