I've just been looking into the keyboard handling for main menus. Using the standard juce menus - when navigating to a menu item and invoking a command using the keyboard - as in using arrow keys to move around and then hit enter to invoke - the command does get triggered as expected. On Mac - when using native menu bars - this does not seem to be the case. Instead it propagates the key press through to the currently focused window which can trigger some unexpected results!
I can reproduce the odd behaviour in the “Tabs and Widgets” section of the Juce demo app. The standard Juce menus perform as expected, hitting enter always triggers the correct command. But if you then select “Use native menu bar” from the Look and Feel menu and then hit enter on any of the native menu bar items it just triggers the “Show Popup Menu” button.
I’m don’t think this should be the default behaviour for the native menu bar - but the code doing this in the juce_mac_MainMenu.mm file looks like it must be there for a reason…
static void menuItemInvoked (id self, SEL, NSMenuItem* item) { JuceMainMenuHandler* const owner = getIvar<JuceMainMenuHandler*> (self, "owner"); if ([[item representedObject] isKindOfClass: [NSArray class]]) { // If the menu is being triggered by a keypress, the OS will have picked it up before we had a chance to offer it to // our own components, which may have wanted to intercept it. So, rather than dispatching directly, we'll feed it back // into the focused component and let it trigger the menu item indirectly. NSEvent* e = [NSApp currentEvent]; if ([e type] == NSKeyDown || [e type] == NSKeyUp) { if (juce::Component* focused = juce::Component::getCurrentlyFocusedComponent()) { if (juce::NSViewComponentPeer* peer = dynamic_cast <juce::NSViewComponentPeer*> (focused->getPeer())) { if ([e type] == NSKeyDown) peer->redirectKeyDown (e); else peer->redirectKeyUp (e); return; } } } NSArray* info = (NSArray*) [item representedObject]; owner->invoke ((int) [item tag], (ApplicationCommandManager*) (pointer_sized_int) [((NSNumber*) [info objectAtIndex: 0]) unsignedLongLongValue], (int) [((NSNumber*) [info objectAtIndex: 1]) intValue]); } }
Am I missing something? Do I have to trigger the command elsewhere? I would think that if a menu is currently open, key presses should not be passed to other components...
Thanks in advance for any pointers!