Unverified Commit baac9a8a authored by Tong Mu's avatar Tong Mu Committed by GitHub

[Keyboard, Windows] Fix that IME events are still dispatched to FocusNode.onKey (#104244)

parent a79233cb
...@@ -766,6 +766,11 @@ class KeyEventManager { ...@@ -766,6 +766,11 @@ class KeyEventManager {
// dispatchable [RawKeyEvent] is available. // dispatchable [RawKeyEvent] is available.
final List<KeyEvent> _keyEventsSinceLastMessage = <KeyEvent>[]; final List<KeyEvent> _keyEventsSinceLastMessage = <KeyEvent>[];
// When a RawKeyDownEvent is skipped ([RawKeyEventData.shouldDispatchEvent]
// is false), its physical key will be recorded here, so that its up event
// can also be properly skipped.
final Set<PhysicalKeyboardKey> _skippedRawKeysPressed = <PhysicalKeyboardKey>{};
/// Dispatch a key data to global and leaf listeners. /// Dispatch a key data to global and leaf listeners.
/// ///
/// This method is the handler to the global `onKeyData` API. /// This method is the handler to the global `onKeyData` API.
...@@ -843,9 +848,27 @@ class KeyEventManager { ...@@ -843,9 +848,27 @@ class KeyEventManager {
_rawKeyboard.addListener(_convertRawEventAndStore); _rawKeyboard.addListener(_convertRawEventAndStore);
} }
final RawKeyEvent rawEvent = RawKeyEvent.fromMessage(message as Map<String, dynamic>); final RawKeyEvent rawEvent = RawKeyEvent.fromMessage(message as Map<String, dynamic>);
bool shouldDispatch = true;
if (rawEvent is RawKeyDownEvent) {
if (!rawEvent.data.shouldDispatchEvent()) {
shouldDispatch = false;
_skippedRawKeysPressed.add(rawEvent.physicalKey);
} else {
_skippedRawKeysPressed.remove(rawEvent.physicalKey);
}
} else if (rawEvent is RawKeyUpEvent) {
if (_skippedRawKeysPressed.contains(rawEvent.physicalKey)) {
_skippedRawKeysPressed.remove(rawEvent.physicalKey);
shouldDispatch = false;
}
}
bool handled = true;
if (shouldDispatch) {
// The following `handleRawKeyEvent` will call `_convertRawEventAndStore` // The following `handleRawKeyEvent` will call `_convertRawEventAndStore`
// unless the event is not dispatched. // unless the event is not dispatched.
bool handled = _rawKeyboard.handleRawKeyEvent(rawEvent); handled = _rawKeyboard.handleRawKeyEvent(rawEvent);
for (final KeyEvent event in _keyEventsSinceLastMessage) { for (final KeyEvent event in _keyEventsSinceLastMessage) {
handled = _hardwareKeyboard.handleKeyEvent(event) || handled; handled = _hardwareKeyboard.handleKeyEvent(event) || handled;
...@@ -858,6 +881,7 @@ class KeyEventManager { ...@@ -858,6 +881,7 @@ class KeyEventManager {
handled = _dispatchKeyMessage(_keyEventsSinceLastMessage, rawEvent) || handled; handled = _dispatchKeyMessage(_keyEventsSinceLastMessage, rawEvent) || handled;
_keyEventsSinceLastMessage.clear(); _keyEventsSinceLastMessage.clear();
}
return <String, dynamic>{ 'handled': handled }; return <String, dynamic>{ 'handled': handled };
} }
......
...@@ -661,27 +661,13 @@ class RawKeyboard { ...@@ -661,27 +661,13 @@ class RawKeyboard {
/// Process a new [RawKeyEvent] by recording the state changes and /// Process a new [RawKeyEvent] by recording the state changes and
/// dispatching to listeners. /// dispatching to listeners.
bool handleRawKeyEvent(RawKeyEvent event) { bool handleRawKeyEvent(RawKeyEvent event) {
bool shouldDispatch = true;
if (event is RawKeyDownEvent) { if (event is RawKeyDownEvent) {
if (event.data.shouldDispatchEvent()) {
_keysPressed[event.physicalKey] = event.logicalKey; _keysPressed[event.physicalKey] = event.logicalKey;
} else {
shouldDispatch = false;
_hiddenKeysPressed.add(event.physicalKey);
}
} else if (event is RawKeyUpEvent) { } else if (event is RawKeyUpEvent) {
if (!_hiddenKeysPressed.contains(event.physicalKey)) {
// Use the physical key in the key up event to find the physical key from // Use the physical key in the key up event to find the physical key from
// the corresponding key down event and remove it, even if the logical // the corresponding key down event and remove it, even if the logical
// keys don't match. // keys don't match.
_keysPressed.remove(event.physicalKey); _keysPressed.remove(event.physicalKey);
} else {
_hiddenKeysPressed.remove(event.physicalKey);
shouldDispatch = false;
}
}
if (!shouldDispatch) {
return true;
} }
// Make sure that the modifiers reflect reality, in case a modifier key was // Make sure that the modifiers reflect reality, in case a modifier key was
// pressed/released while the app didn't have focus. // pressed/released while the app didn't have focus.
...@@ -855,7 +841,6 @@ class RawKeyboard { ...@@ -855,7 +841,6 @@ class RawKeyboard {
} }
final Map<PhysicalKeyboardKey, LogicalKeyboardKey> _keysPressed = <PhysicalKeyboardKey, LogicalKeyboardKey>{}; final Map<PhysicalKeyboardKey, LogicalKeyboardKey> _keysPressed = <PhysicalKeyboardKey, LogicalKeyboardKey>{};
final Set<PhysicalKeyboardKey> _hiddenKeysPressed = <PhysicalKeyboardKey>{};
/// Returns the set of keys currently pressed. /// Returns the set of keys currently pressed.
Set<LogicalKeyboardKey> get keysPressed => _keysPressed.values.toSet(); Set<LogicalKeyboardKey> get keysPressed => _keysPressed.values.toSet();
......
...@@ -1936,6 +1936,28 @@ void main() { ...@@ -1936,6 +1936,28 @@ void main() {
const String platform = 'windows'; const String platform = 'windows';
bool lastHandled = true; bool lastHandled = true;
final List<RawKeyEvent> events = <RawKeyEvent>[]; final List<RawKeyEvent> events = <RawKeyEvent>[];
// Test both code paths: addListener, and FocusNode.onKey.
RawKeyboard.instance.addListener(events.add);
final FocusNode node = FocusNode(
onKey: (_, RawKeyEvent event) {
events.add(event);
return KeyEventResult.ignored;
},
);
await tester.pumpWidget(RawKeyboardListener(
focusNode: node,
child: Container(),
));
node.requestFocus();
await tester.pumpAndSettle();
// Dispatch an arbitrary key press for the correct transit mode.
await simulateKeyDownEvent(LogicalKeyboardKey.keyA);
await simulateKeyUpEvent(LogicalKeyboardKey.keyA);
expect(events, hasLength(4));
events.clear();
// Simulate raw events because VK_PROCESSKEY does not exist in the key mapping. // Simulate raw events because VK_PROCESSKEY does not exist in the key mapping.
Future<void> simulateKeyEventMessage(String type, int keyCode, int scanCode) { Future<void> simulateKeyEventMessage(String type, int keyCode, int scanCode) {
return ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage( return ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage(
...@@ -1953,7 +1975,7 @@ void main() { ...@@ -1953,7 +1975,7 @@ void main() {
}, },
); );
} }
RawKeyboard.instance.addListener(events.add);
await simulateKeyEventMessage('keydown', 229, 30); await simulateKeyEventMessage('keydown', 229, 30);
expect(events, isEmpty); expect(events, isEmpty);
expect(lastHandled, true); expect(lastHandled, true);
...@@ -1962,7 +1984,7 @@ void main() { ...@@ -1962,7 +1984,7 @@ void main() {
expect(events, isEmpty); expect(events, isEmpty);
expect(lastHandled, true); expect(lastHandled, true);
expect(RawKeyboard.instance.keysPressed, isEmpty); expect(RawKeyboard.instance.keysPressed, isEmpty);
}); }, variant: KeySimulatorTransitModeVariant.keyDataThenRawKeyData());
test('data.toString', () { test('data.toString', () {
expect(RawKeyEvent.fromMessage(const <String, Object?>{ expect(RawKeyEvent.fromMessage(const <String, Object?>{
......
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