Bug 1680177 - Set the correct modifier flags on command events dispatched by the native menu system. r=mac-reviewers,spohl

Differential Revision: https://phabricator.services.mozilla.com/D109635
This commit is contained in:
Markus Stange 2021-03-24 16:51:32 +00:00
parent 1f3704b5c0
commit d1504abf93
5 changed files with 22 additions and 13 deletions

View File

@ -874,13 +874,18 @@ static BOOL gMenuItemsExecuteCommands = YES;
menuBar = menuGroupOwner->GetMenuBar();
}
// Get the modifier flags for this menu item activation. The menu system does not pass an NSEvent
// to our action selector, but we can query the current NSEvent instead. The current NSEvent can
// be a key event or a mouseup event, depending on how the menu item is activated.
NSEventModifierFlags modifierFlags = NSApp.currentEvent ? NSApp.currentEvent.modifierFlags : 0;
// Do special processing if this is for an app-global command.
if (tag == eCommand_ID_About) {
nsIContent* mostSpecificContent = sAboutItemContent;
if (menuBar && menuBar->mAboutItemContent) {
mostSpecificContent = menuBar->mAboutItemContent;
}
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent);
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent, modifierFlags);
return;
}
if (tag == eCommand_ID_Prefs) {
@ -888,7 +893,7 @@ static BOOL gMenuItemsExecuteCommands = YES;
if (menuBar && menuBar->mPrefItemContent) {
mostSpecificContent = menuBar->mPrefItemContent;
}
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent);
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent, modifierFlags);
return;
}
if (tag == eCommand_ID_HideApp) {
@ -916,7 +921,7 @@ static BOOL gMenuItemsExecuteCommands = YES;
// message. If you want to stop a quit from happening, provide quit content and return
// the event as unhandled.
if (mostSpecificContent) {
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent);
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent, modifierFlags);
} else {
nsCOMPtr<nsIAppStartup> appStartup = mozilla::components::AppStartup::Service();
if (appStartup) {
@ -932,7 +937,7 @@ static BOOL gMenuItemsExecuteCommands = YES;
if (menuGroupOwner) {
nsMenuItemX* menuItem = menuGroupOwner->GetMenuItemForCommandID(static_cast<uint32_t>(tag));
if (menuItem) {
menuItem->DoCommand();
menuItem->DoCommand(modifierFlags);
}
}
}

View File

@ -70,7 +70,7 @@ class nsMenuItemX final : public nsChangeObserver,
// nsMenuItemX
nsresult SetChecked(bool aIsChecked);
EMenuItemType GetMenuItemType();
void DoCommand();
void DoCommand(NSEventModifierFlags aModifierFlags);
nsresult DispatchDOMEvent(const nsString& eventName,
bool* preventDefaultCalled);
void SetupIcon();

View File

@ -141,7 +141,7 @@ EMenuItemType nsMenuItemX::GetMenuItemType() { return mType; }
// Executes the "cached" javaScript command.
// Returns NS_OK if the command was executed properly, otherwise an error code.
void nsMenuItemX::DoCommand() {
void nsMenuItemX::DoCommand(NSEventModifierFlags aModifierFlags) {
// flip "checked" state if we're a checkbox menu, or an un-checked radio menu
if (mType == eCheckboxMenuItemType || (mType == eRadioMenuItemType && !mIsChecked)) {
if (!mContent->IsElement() ||
@ -152,7 +152,7 @@ void nsMenuItemX::DoCommand() {
/* the AttributeChanged code will update all the internal state */
}
nsMenuUtilsX::DispatchCommandTo(mContent);
nsMenuUtilsX::DispatchCommandTo(mContent, aModifierFlags);
}
nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventDefaultCalled) {

View File

@ -17,7 +17,7 @@ class nsMenuX;
// Namespace containing utility functions used in our native menu implementation.
namespace nsMenuUtilsX {
void DispatchCommandTo(nsIContent* aTargetContent);
void DispatchCommandTo(nsIContent* aTargetContent, NSEventModifierFlags aModifierFlags);
NSString* GetTruncatedCocoaLabel(const nsString& itemLabel);
uint8_t GeckoModifiersForNodeAttribute(const nsString& modifiersAttribute);
unsigned int MacModifiersForGeckoModifiers(uint8_t geckoModifiers);

View File

@ -24,7 +24,8 @@
using namespace mozilla;
void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent) {
void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
NSEventModifierFlags aModifierFlags) {
MOZ_ASSERT(aTargetContent, "null ptr");
dom::Document* doc = aTargetContent->OwnerDoc();
@ -32,12 +33,15 @@ void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent) {
RefPtr<dom::XULCommandEvent> event =
new dom::XULCommandEvent(doc, doc->GetPresContext(), nullptr);
bool ctrlKey = aModifierFlags & NSEventModifierFlagControl;
bool altKey = aModifierFlags & NSEventModifierFlagOption;
bool shiftKey = aModifierFlags & NSEventModifierFlagShift;
bool cmdKey = aModifierFlags & NSEventModifierFlagCommand;
IgnoredErrorResult rv;
event->InitCommandEvent(u"command"_ns, true, true,
nsGlobalWindowInner::Cast(doc->GetInnerWindow()), 0, false, false,
false, false, nullptr, 0, rv);
// FIXME: Should probably figure out how to init this with the actual
// pressed keys, but this is a big old edge case anyway. -dwh
nsGlobalWindowInner::Cast(doc->GetInnerWindow()), 0, ctrlKey, altKey,
shiftKey, cmdKey, nullptr, 0, rv);
if (!rv.Failed()) {
event->SetTrusted(true);
aTargetContent->DispatchEvent(*event);