From 6b06943c32bef040bd177ac10de073a090c7430c Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Wed, 14 Apr 2021 23:52:27 +0000 Subject: [PATCH] Handle null primary focus when receiving key events (#80302) This allows the key handling code in the shortcut manager to function when there is a null primaryFocus. The primary focus can be null only in some special circumstances (e.g. when an app hasn't set any focus at all), but that shouldn't cause a crash. --- .../flutter/lib/src/widgets/shortcuts.dart | 23 +++++++------- .../flutter/test/widgets/shortcuts_test.dart | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index 61593c9e42..7be3496f10 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -356,17 +356,18 @@ class ShortcutManager extends ChangeNotifier with Diagnosticable { ); final Intent? matchedIntent = _find(keysPressed: keysPressed); if (matchedIntent != null) { - final BuildContext primaryContext = primaryFocus!.context!; - assert (primaryContext != null); - final Action? action = Actions.maybeFind( - primaryContext, - intent: matchedIntent, - ); - if (action != null && action.isEnabled(matchedIntent)) { - Actions.of(primaryContext).invokeAction(action, matchedIntent, primaryContext); - return action.consumesKey(matchedIntent) - ? KeyEventResult.handled - : KeyEventResult.skipRemainingHandlers; + final BuildContext? primaryContext = primaryFocus?.context; + if (primaryContext != null) { + final Action? action = Actions.maybeFind( + primaryContext, + intent: matchedIntent, + ); + if (action != null && action.isEnabled(matchedIntent)) { + Actions.of(primaryContext).invokeAction(action, matchedIntent, primaryContext); + return action.consumesKey(matchedIntent) + ? KeyEventResult.handled + : KeyEventResult.skipRemainingHandlers; + } } } return modal ? KeyEventResult.skipRemainingHandlers : KeyEventResult.ignored; diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart index 8a4eb859c7..eb00b9d3df 100644 --- a/packages/flutter/test/widgets/shortcuts_test.dart +++ b/packages/flutter/test/widgets/shortcuts_test.dart @@ -290,6 +290,37 @@ void main() { expect(invoked, isTrue); expect(pressedKeys, equals([LogicalKeyboardKey.shiftLeft])); }); + testWidgets('ShortcutManager ignores keypresses with no primary focus', (WidgetTester tester) async { + final GlobalKey containerKey = GlobalKey(); + final List pressedKeys = []; + final TestShortcutManager testManager = TestShortcutManager(pressedKeys); + bool invoked = false; + await tester.pumpWidget( + Actions( + actions: >{ + TestIntent: TestAction( + onInvoke: (Intent intent) { + invoked = true; + return true; + }, + ), + }, + child: Shortcuts( + manager: testManager, + shortcuts: { + LogicalKeySet(LogicalKeyboardKey.shift): const TestIntent(), + }, + child: SizedBox(key: containerKey, width: 100, height: 100), + ), + ), + ); + await tester.pump(); + expect(primaryFocus, isNull); + expect(Shortcuts.of(containerKey.currentContext!), isNotNull); + await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft); + expect(invoked, isFalse); + expect(pressedKeys, isEmpty); + }); testWidgets("Shortcuts passes to the next Shortcuts widget if it doesn't map the key", (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final List pressedKeys = [];