From 1e606ddb32d59320b579100844dee69978720d91 Mon Sep 17 00:00:00 2001 From: reuk Date: Mon, 19 Apr 2021 17:55:33 +0100 Subject: [PATCH] MainMenu: Allow components to directly handle shortcut keys which trigger menu items This fixes a regression introduced by 6e9261ea66e0769546f8485efefb1233cadd3fde which meant that components were not given a chance to respond to shortcut keypresses if those same keypresses were registered for a menu item. This resulted in behaviour where shortcuts such as 'cmd+c' would not be passed to a focused TextEditor if a different command with the same shortcut was registered in the main menu. With this change in place, we now check whether the menu item's shortcut keys match the current event's pressed keys. If the keypresses match, we can assume that the event was triggered by the keyboard, and dispatch the keypresses to the ComponentPeer. If the keypresses do not match, then the menu item was likely selected using space/return, or by clicking, in which case the event is dispatched directly to the ApplicationCommandManager. --- .../native/juce_mac_MainMenu.mm | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/modules/juce_gui_basics/native/juce_mac_MainMenu.mm b/modules/juce_gui_basics/native/juce_mac_MainMenu.mm index 2389f7faa6..8d6c1bbc67 100644 --- a/modules/juce_gui_basics/native/juce_mac_MainMenu.mm +++ b/modules/juce_gui_basics/native/juce_mac_MainMenu.mm @@ -537,12 +537,43 @@ private: } private: + /* Returns true if and only if the peer handles the event. */ + static bool tryPassingKeyEventToPeer (NSMenuItem* item) + { + auto* e = [NSApp currentEvent]; + + if ([e type] != NSEventTypeKeyDown && [e type] != NSEventTypeKeyUp) + return false; + + const auto triggeredByShortcut = [[e charactersIgnoringModifiers] isEqualToString: [item keyEquivalent]] + && ([e modifierFlags] & ~(NSUInteger) 0xFFFF) == [item keyEquivalentModifierMask]; + + if (! triggeredByShortcut) + return false; + + if (auto* focused = juce::Component::getCurrentlyFocusedComponent()) + { + if (auto* peer = dynamic_cast (focused->getPeer())) + { + if ([e type] == NSEventTypeKeyDown) + peer->redirectKeyDown (e); + else + peer->redirectKeyUp (e); + + return true; + } + } + + return false; + } + static void menuItemInvoked (id self, SEL, NSMenuItem* item) { - auto owner = getIvar (self, "owner"); + if (tryPassingKeyEventToPeer (item)) + return; if (auto* juceItem = getJuceClassFromNSObject ([item representedObject])) - owner->invoke (*juceItem, static_cast ([item tag])); + getIvar (self, "owner")->invoke (*juceItem, static_cast ([item tag])); } static void menuNeedsUpdate (id self, SEL, NSMenu* menu)