mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Mac MainMenu: Allow commands without modifiers to be passed to peer
Ideally, we want to pass shortcut keys to the component to handle, and only fall back to invoking a menu item if the component was unable to handle the keyboard event, or if the action was triggered by clicking/selecting an item in the menu itself. The old implementation tried to work out whether the action was triggered by a shortcut by checking the event's characters and modifiers. This method was inaccurate, because some shortcuts (such as arrow keys) may add unexpected numpad/function modifier flags. We now try handling shortcut keys directly in the peer, and pass events up to the superclass (which will forward them to the main menu) if the event could not be handled. This commit also adjusts some Objective-C method signatures to use the correct string encoding for the BOOL type.
This commit is contained in:
parent
aba8c8c1d3
commit
85226c33d4
5 changed files with 38 additions and 41 deletions
|
|
@ -245,7 +245,7 @@ private:
|
|||
addMethod (@selector (inputBusses), getInputBusses, "@@:");
|
||||
addMethod (@selector (outputBusses), getOutputBusses, "@@:");
|
||||
addMethod (@selector (channelCapabilities), getChannelCapabilities, "@@:");
|
||||
addMethod (@selector (shouldChangeToFormat:forBus:), shouldChangeToFormat, "B@:@@");
|
||||
addMethod (@selector (shouldChangeToFormat:forBus:), shouldChangeToFormat, "c@:@@");
|
||||
|
||||
//==============================================================================
|
||||
addMethod (@selector (virtualMIDICableCount), getVirtualMIDICableCount, @encode (NSInteger), "@:");
|
||||
|
|
@ -262,7 +262,7 @@ private:
|
|||
addMethod (@selector (setRenderingOffline:), setRenderingOffline, "v@:", @encode (BOOL));
|
||||
addMethod (@selector (shouldBypassEffect), getShouldBypassEffect, @encode (BOOL), "@:");
|
||||
addMethod (@selector (setShouldBypassEffect:), setShouldBypassEffect, "v@:", @encode (BOOL));
|
||||
addMethod (@selector (allocateRenderResourcesAndReturnError:), allocateRenderResourcesAndReturnError, "B@:^@");
|
||||
addMethod (@selector (allocateRenderResourcesAndReturnError:), allocateRenderResourcesAndReturnError, "c@:^@");
|
||||
addMethod (@selector (deallocateRenderResources), deallocateRenderResources, "v@:");
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -157,13 +157,13 @@ private:
|
|||
static void mainMenuTrackingBegan (id /*self*/, SEL, NSNotification*)
|
||||
{
|
||||
if (menuTrackingChangedCallback != nullptr)
|
||||
(*menuTrackingChangedCallback) (true);
|
||||
menuTrackingChangedCallback (true);
|
||||
}
|
||||
|
||||
static void mainMenuTrackingEnded (id /*self*/, SEL, NSNotification*)
|
||||
{
|
||||
if (menuTrackingChangedCallback != nullptr)
|
||||
(*menuTrackingChangedCallback) (false);
|
||||
menuTrackingChangedCallback (false);
|
||||
}
|
||||
|
||||
static void dummyMethod (id /*self*/, SEL) {} // (used as a way of running a dummy thread)
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ private:
|
|||
//==============================================================================
|
||||
struct JuceMenuCallbackClass : public ObjCClass<NSObject>
|
||||
{
|
||||
JuceMenuCallbackClass() : ObjCClass<NSObject> ("JUCEMainMenu_")
|
||||
JuceMenuCallbackClass() : ObjCClass ("JUCEMainMenu_")
|
||||
{
|
||||
addIvar<JuceMainMenuHandler*> ("owner");
|
||||
|
||||
|
|
@ -537,41 +537,8 @@ 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<juce::NSViewComponentPeer*> (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)
|
||||
{
|
||||
if (tryPassingKeyEventToPeer (item))
|
||||
return;
|
||||
|
||||
if (auto* juceItem = getJuceClassFromNSObject<PopupMenu::Item> ([item representedObject]))
|
||||
getIvar<JuceMainMenuHandler*> (self, "owner")->invoke (*juceItem, static_cast<int> ([item tag]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1795,6 +1795,8 @@ struct JuceNSViewClass : public NSViewComponentPeerWrapper<ObjCClass<NSView>>
|
|||
addMethod (NSViewComponentPeer::frameChangedSelector, frameChanged, "v@:@");
|
||||
addMethod (NSViewComponentPeer::becomeKeySelector, becomeKey, "v@:@");
|
||||
|
||||
addMethod (@selector (performKeyEquivalent:), performKeyEquivalent, "c@:@");
|
||||
|
||||
addProtocol (@protocol (NSTextInput));
|
||||
|
||||
registerClass();
|
||||
|
|
@ -2156,6 +2158,34 @@ private:
|
|||
|
||||
return sendSuperclassMessage<id> (self, @selector (accessibilityAttributeValue:), attribute);
|
||||
}
|
||||
|
||||
static bool tryPassingKeyEventToPeer (NSEvent* e)
|
||||
{
|
||||
if ([e type] != NSEventTypeKeyDown && [e type] != NSEventTypeKeyUp)
|
||||
return false;
|
||||
|
||||
if (auto* focused = Component::getCurrentlyFocusedComponent())
|
||||
{
|
||||
if (auto* peer = dynamic_cast<NSViewComponentPeer*> (focused->getPeer()))
|
||||
{
|
||||
return [e type] == NSEventTypeKeyDown ? peer->redirectKeyDown (e)
|
||||
: peer->redirectKeyUp (e);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static BOOL performKeyEquivalent (id self, SEL s, NSEvent* event)
|
||||
{
|
||||
// We try passing shortcut keys to the currently focused component first.
|
||||
// If the component doesn't want the event, we'll fall back to the superclass
|
||||
// implementation, which will pass the event to the main menu.
|
||||
if (tryPassingKeyEventToPeer (event))
|
||||
return YES;
|
||||
|
||||
return sendSuperclassMessage<BOOL> (self, s, event);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -2175,7 +2205,7 @@ struct JuceNSWindowClass : public NSViewComponentPeerWrapper<ObjCClass<NSWindo
|
|||
addMethod (@selector (zoom:), zoom, "v@:@");
|
||||
addMethod (@selector (windowWillStartLiveResize:), windowWillStartLiveResize, "v@:@");
|
||||
addMethod (@selector (windowDidEndLiveResize:), windowDidEndLiveResize, "v@:@");
|
||||
addMethod (@selector (window:shouldPopUpDocumentPathMenu:), shouldPopUpPathMenu, "B@:@", @encode (NSMenu*));
|
||||
addMethod (@selector (window:shouldPopUpDocumentPathMenu:), shouldPopUpPathMenu, "c@:@", @encode (NSMenu*));
|
||||
addMethod (@selector (isFlipped), isFlipped, "c@:");
|
||||
|
||||
addMethod (@selector (accessibilityTitle), getAccessibilityTitle, "@@:");
|
||||
|
|
@ -2186,7 +2216,7 @@ struct JuceNSWindowClass : public NSViewComponentPeerWrapper<ObjCClass<NSWindo
|
|||
addMethod (@selector (accessibilitySubrole), getAccessibilitySubrole, "@@:");
|
||||
|
||||
addMethod (@selector (window:shouldDragDocumentWithEvent:from:withPasteboard:),
|
||||
shouldAllowIconDrag, "B@:@", @encode (NSEvent*), @encode (NSPoint), @encode (NSPasteboard*));
|
||||
shouldAllowIconDrag, "c@:@", @encode (NSEvent*), @encode (NSPoint), @encode (NSPasteboard*));
|
||||
|
||||
addProtocol (@protocol (NSWindowDelegate));
|
||||
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ private:
|
|||
addMethod (@selector (application:didReceiveRemoteNotification:), didReceiveRemoteNotification, "v@:@@");
|
||||
addMethod (@selector (userNotificationCenter:didDeliverNotification:), didDeliverNotification, "v@:@@");
|
||||
addMethod (@selector (userNotificationCenter:didActivateNotification:), didActivateNotification, "v@:@@");
|
||||
addMethod (@selector (userNotificationCenter:shouldPresentNotification:), shouldPresentNotification, "B@:@@");
|
||||
addMethod (@selector (userNotificationCenter:shouldPresentNotification:), shouldPresentNotification, "c@:@@");
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue