Unverified Commit 0ec0bf50 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Make RawKeyboard assert when no keys are in keysPressed when sending a key down event. (#63426)

This adds an assert in RawKeyboard that catches the case where it tries to send a key down event, but (after synchronizing modifiers) there are no keys in keysPressed. This state can occur if the modifier flags are not set properly for the platform.

Also prevents shortcuts attempting to handle a key down when no keys are pressed at the moment (which was causing a crash in release mode).
parent e3c7fb5b
......@@ -581,6 +581,11 @@ class RawKeyboard {
// Make sure that the modifiers reflect reality, in case a modifier key was
// pressed/released while the app didn't have focus.
_synchronizeModifiers(event);
assert(event is! RawKeyDownEvent || _keysPressed.isNotEmpty,
'Attempted to send a key down event when no keys are in keysPressed. '
"This state can occur if the key event being sent doesn't properly "
'set its modifier flags. This was the event: $event and its data: '
'${event.data}');
// Send the event to passive listeners.
for (final ValueChanged<RawKeyEvent> listener in List<ValueChanged<RawKeyEvent>>.from(_listeners)) {
if (_listeners.contains(listener)) {
......
......@@ -306,7 +306,21 @@ class ShortcutManager extends ChangeNotifier with Diagnosticable {
return false;
}
assert(context != null);
final LogicalKeySet keySet = keysPressed ?? LogicalKeySet.fromSet(RawKeyboard.instance.keysPressed);
LogicalKeySet keySet = keysPressed;
if (keySet == null) {
assert(RawKeyboard.instance.keysPressed.isNotEmpty,
'Received a key down event when no keys are in keysPressed. '
"This state can occur if the key event being sent doesn't properly "
'set its modifier flags. This was the event: $event and its data: '
'${event.data}');
// Avoid the crash in release mode, since it's easy to miss a particular
// bad key sequence in testing, and so shouldn't crash the app in release.
if (RawKeyboard.instance.keysPressed.isNotEmpty) {
keySet = LogicalKeySet.fromSet(RawKeyboard.instance.keysPressed);
} else {
return false;
}
}
Intent matchedIntent = _shortcuts[keySet];
if (matchedIntent == null) {
// If there's not a more specific match, We also look for any keys that
......
......@@ -4,6 +4,7 @@
// @dart = 2.8
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
......@@ -277,6 +278,36 @@ void main() {
),
);
});
testWidgets('RawKeyboard asserts if no keys are in keysPressed after receiving a key down event', (WidgetTester tester) async {
FlutterErrorDetails errorDetails;
final FlutterExceptionHandler oldHandler = FlutterError.onError;
FlutterError.onError = (FlutterErrorDetails details) {
errorDetails = details;
};
try {
await ServicesBinding.instance.defaultBinaryMessenger
.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(const <String, dynamic>{
'type': 'keydown',
'keymap': 'android',
'keyCode': 0x3b, // Left shift key keyCode
'scanCode': 0x2a,
'metaState': 0x0, // No shift key metaState set!
'source': 0x101,
'deviceId': 1,
}),
(ByteData data) {},
);
} finally {
FlutterError.onError = oldHandler;
}
expect(errorDetails, isNotNull);
expect(errorDetails.stack, isNotNull);
final String fullErrorMessage = errorDetails.toString().replaceAll('\n', ' ');
expect(fullErrorMessage, contains('Attempted to send a key down event when no keys are in keysPressed'));
});
});
group('RawKeyEventDataAndroid', () {
......
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