mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
fix performKeyEvent handling so we don't beep when commands are successful. b=376077 r=smichaud sr=roc
This commit is contained in:
parent
59ef880a05
commit
52533a5203
@ -283,7 +283,7 @@ public:
|
||||
|
||||
NS_IMETHOD SetMenuBar(nsIMenuBar * aMenuBar);
|
||||
NS_IMETHOD ShowMenuBar(PRBool aShow);
|
||||
virtual nsIMenuBar* GetMenuBar();
|
||||
|
||||
NS_IMETHOD GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight);
|
||||
NS_IMETHOD SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight);
|
||||
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "nsCursorManager.h"
|
||||
#include "nsWindowMap.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "nsMenuBarX.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxQuartzSurface.h"
|
||||
@ -823,12 +824,6 @@ NS_IMETHODIMP nsChildView::ShowMenuBar(PRBool aShow)
|
||||
}
|
||||
|
||||
|
||||
nsIMenuBar* nsChildView::GetMenuBar()
|
||||
{
|
||||
return nsnull; // subviews don't have menu bars
|
||||
}
|
||||
|
||||
|
||||
// Override to set the cursor on the mac
|
||||
NS_IMETHODIMP nsChildView::SetCursor(nsCursor aCursor)
|
||||
{
|
||||
@ -3221,6 +3216,7 @@ enum
|
||||
kInsertKeyCode = 0x72, // also help key
|
||||
kDeleteKeyCode = 0x75, // also forward delete key
|
||||
kTabKeyCode = 0x30,
|
||||
kTildeKeyCode = 0x32,
|
||||
kBackspaceKeyCode = 0x33,
|
||||
kHomeKeyCode = 0x73,
|
||||
kEndKeyCode = 0x77,
|
||||
@ -4059,18 +4055,46 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
||||
|
||||
- (BOOL)performKeyEquivalent:(NSEvent*)theEvent
|
||||
{
|
||||
// don't bother if we don't have a gecko widget or we're in composition
|
||||
if (!mGeckoChild || nsTSMManager::IsComposing())
|
||||
// First we need to ignore certain system commands. If we don't we'll have
|
||||
// to duplicate their functionality in Gecko, which as of this time we haven't.
|
||||
// The only thing we ignore now is command-tilde, because NSApp handles that for us
|
||||
// and we need the event to propagate to there.
|
||||
unsigned int modifierFlags = [theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
|
||||
if (modifierFlags & NSCommandKeyMask && [theEvent keyCode] == kTildeKeyCode)
|
||||
return NO;
|
||||
|
||||
// see if the menu system will handle the event
|
||||
if ([[NSApp mainMenu] performKeyEquivalent:theEvent])
|
||||
// don't bother if we don't have a gecko widget or we're in composition
|
||||
if (!mGeckoChild || nsTSMManager::IsComposing())
|
||||
return YES;
|
||||
|
||||
// see if the menu system will handle the event
|
||||
if ([[NSApp mainMenu] performKeyEquivalent:theEvent]) {
|
||||
return YES;
|
||||
}
|
||||
else {
|
||||
// On Mac OS X 10.5 NSMenu's performKeyEquivalent: method returns NO for disabled menu
|
||||
// items that have a matching key equiv. We need to know if that was the case so we can
|
||||
// stop here like we would on 10.4 (it returns YES in that case). Since we want to eat
|
||||
// the event if that happens the system won't give the disabled command beep, do it here
|
||||
// manually.
|
||||
if (nsToolkit::OnLeopardOrLater()) {
|
||||
id delegate = [[self window] delegate];
|
||||
if (delegate && [delegate isKindOfClass:[WindowDelegate class]]) {
|
||||
nsCocoaWindow* toplevelWindow = [delegate geckoWidget];
|
||||
if (toplevelWindow) {
|
||||
nsMenuBarX* menuBar = static_cast<nsMenuBarX*>(toplevelWindow->GetMenuBar());
|
||||
if (menuBar && menuBar->ContainsKeyEquiv(modifierFlags, [theEvent characters])) {
|
||||
NSBeep();
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't handle this if certain modifiers are down - those should
|
||||
// be sent as normal key up/down events and cocoa will do so automatically
|
||||
// if we reject here
|
||||
unsigned int modifierFlags = [theEvent modifierFlags];
|
||||
if ((modifierFlags & NSFunctionKeyMask) || (modifierFlags & NSNumericPadKeyMask))
|
||||
return NO;
|
||||
|
||||
@ -4083,7 +4107,9 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
||||
ConvertCocoaKeyEventToMacEvent(theEvent, macEvent);
|
||||
geckoEvent.nativeMsg = &macEvent;
|
||||
|
||||
return (BOOL)mGeckoChild->DispatchWindowEvent(geckoEvent);
|
||||
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
@ -44,10 +44,10 @@
|
||||
|
||||
#include "nsIDOMElement.h"
|
||||
|
||||
// CC986E81-9F46-4AA2-B809-C544789E6F06
|
||||
// 33FA04E3-EAFE-4DD1-AFB3-B3BC8C712716
|
||||
#define NS_IMENUITEM_IID \
|
||||
{ 0xCC986E81, 0x9F46, 0x4AA2, \
|
||||
{ 0xB8, 0x09, 0xC5, 0x44, 0x78, 0x9E, 0x6F, 0x06 } }
|
||||
{ 0x33FA04E3, 0xEAFE, 0x4DD1, \
|
||||
{ 0xAF, 0xB3, 0xB3, 0xBC, 0x8C, 0x71, 0x27, 0x16 } }
|
||||
|
||||
class nsIMenu;
|
||||
class nsIWidget;
|
||||
@ -85,12 +85,6 @@ class nsIMenuItem : public nsISupports {
|
||||
*/
|
||||
NS_IMETHOD GetLabel(nsString &aText) = 0;
|
||||
|
||||
/**
|
||||
* Set the Menu shortcut char
|
||||
*
|
||||
*/
|
||||
NS_IMETHOD SetShortcutChar(const nsString &aText) = 0;
|
||||
|
||||
/**
|
||||
* Get the Menu shortcut char
|
||||
*
|
||||
@ -145,12 +139,6 @@ class nsIMenuItem : public nsISupports {
|
||||
*/
|
||||
NS_IMETHOD DispatchDOMEvent(const nsString &eventName, PRBool *preventDefaultCalled) = 0;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
NS_IMETHOD SetModifiers(PRUint8 aModifiers) = 0;
|
||||
NS_IMETHOD GetModifiers(PRUint8 * aModifiers) = 0;
|
||||
|
||||
/**
|
||||
* Sets an appropriate icon for the menu item.
|
||||
*/
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "nsIMutationObserver.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIContent.h"
|
||||
|
||||
@ -75,8 +76,66 @@ namespace MenuHelpersX
|
||||
@end
|
||||
|
||||
|
||||
struct CocoaKeyEquivContainer {
|
||||
CocoaKeyEquivContainer(const unsigned int modifiers, const NSString* string)
|
||||
{
|
||||
mModifiers = modifiers;
|
||||
mString = [string retain];
|
||||
}
|
||||
|
||||
~CocoaKeyEquivContainer()
|
||||
{
|
||||
[mString release];
|
||||
}
|
||||
|
||||
CocoaKeyEquivContainer(const CocoaKeyEquivContainer& other)
|
||||
{
|
||||
mModifiers = other.mModifiers;
|
||||
mString = [other.mString retain];
|
||||
}
|
||||
|
||||
CocoaKeyEquivContainer& operator=(CocoaKeyEquivContainer& other)
|
||||
{
|
||||
mModifiers = other.mModifiers;
|
||||
if (mString)
|
||||
[mString release];
|
||||
mString = [other.mString retain];
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned int mModifiers;
|
||||
NSString* mString;
|
||||
};
|
||||
|
||||
|
||||
struct CocoaKeyEquivKey : public PLDHashEntryHdr {
|
||||
typedef const CocoaKeyEquivContainer& KeyType;
|
||||
typedef const CocoaKeyEquivContainer* KeyTypePointer;
|
||||
|
||||
CocoaKeyEquivKey(KeyTypePointer aObj) : mObj(*aObj) { }
|
||||
CocoaKeyEquivKey(const CocoaKeyEquivKey& other) : mObj(other.mObj) { }
|
||||
~CocoaKeyEquivKey() { }
|
||||
|
||||
KeyType GetKey() const { return mObj; }
|
||||
|
||||
PRBool KeyEquals(KeyTypePointer aKey) const {
|
||||
return aKey->mModifiers == mObj.mModifiers &&
|
||||
[aKey->mString isEqualToString:mObj.mString];
|
||||
}
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
|
||||
static PLDHashNumber HashKey(KeyTypePointer aKey) {
|
||||
return [aKey->mString hash] ^ aKey->mModifiers;
|
||||
}
|
||||
enum { ALLOW_MEMMOVE = PR_FALSE };
|
||||
private:
|
||||
const CocoaKeyEquivContainer mObj;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Native Mac menu bar wrapper
|
||||
// Native menu bar wrapper
|
||||
//
|
||||
|
||||
class nsMenuBarX : public nsIMenuBar,
|
||||
@ -111,6 +170,7 @@ public:
|
||||
NS_IMETHOD Paint();
|
||||
NS_IMETHOD SetNativeData(void* aData);
|
||||
NS_IMETHOD MenuConstruct(const nsMenuEvent & aMenuEvent, nsIWidget * aParentWindow, void * aMenuNode);
|
||||
PRBool ContainsKeyEquiv(unsigned int modifiers, NSString* string);
|
||||
|
||||
PRUint32 RegisterForCommand(nsIMenuItem* aItem);
|
||||
void UnregisterCommand(PRUint32 aCommandID);
|
||||
@ -119,6 +179,8 @@ public:
|
||||
void UnregisterForContentChanges(nsIContent* aContent);
|
||||
nsChangeObserver* LookupContentChangeObserver(nsIContent* aContent);
|
||||
|
||||
void RegisterKeyEquivalent(unsigned int modifiers, NSString* string);
|
||||
void UnregisterKeyEquivalent(unsigned int modifiers, NSString* string);
|
||||
protected:
|
||||
// Make our menubar conform to Aqua UI guidelines
|
||||
void AquifyMenuBar();
|
||||
@ -150,7 +212,9 @@ protected:
|
||||
nsIDocument* mDocument; // pointer to document
|
||||
|
||||
NSMenu* mRootMenu; // root menu, representing entire menu bar
|
||||
|
||||
|
||||
nsTHashtable<CocoaKeyEquivKey> mKeyEquivTable;
|
||||
|
||||
static EventHandlerUPP sCommandEventHandler; // carbon event handler for commands, shared
|
||||
};
|
||||
|
||||
|
@ -355,6 +355,8 @@ nsMenuBarX::MenuConstruct(const nsMenuEvent & aMenuEvent, nsIWidget* aParentWind
|
||||
NS_IMETHODIMP nsMenuBarX::Create(nsIWidget *aParent)
|
||||
{
|
||||
SetParent(aParent);
|
||||
if (!mKeyEquivTable.Init())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -840,6 +842,27 @@ nsMenuBarX::LookupContentChangeObserver(nsIContent* aContent)
|
||||
}
|
||||
|
||||
|
||||
void nsMenuBarX::RegisterKeyEquivalent(unsigned int modifiers, NSString* string)
|
||||
{
|
||||
const CocoaKeyEquivContainer keyEquiv(modifiers, string);
|
||||
mKeyEquivTable.PutEntry(keyEquiv);
|
||||
}
|
||||
|
||||
|
||||
void nsMenuBarX::UnregisterKeyEquivalent(unsigned int modifiers, NSString* string)
|
||||
{
|
||||
CocoaKeyEquivContainer keyEquiv(modifiers, string);
|
||||
mKeyEquivTable.RemoveEntry(keyEquiv);
|
||||
}
|
||||
|
||||
|
||||
PRBool nsMenuBarX::ContainsKeyEquiv(unsigned int modifiers, NSString* string)
|
||||
{
|
||||
const CocoaKeyEquivContainer keyEquiv(modifiers, string);
|
||||
return (mKeyEquivTable.GetEntry(keyEquiv) != nsnull);
|
||||
}
|
||||
|
||||
|
||||
// Given a menu item, creates a unique 4-character command ID and
|
||||
// maps it to the item. Returns the id for use by the client.
|
||||
PRUint32
|
||||
|
@ -68,7 +68,6 @@ public:
|
||||
NS_IMETHOD Create(nsIMenu* aParent, const nsString & aLabel, EMenuItemType aItemType,
|
||||
nsMenuBarX* aMenuBar, nsIContent* aNode);
|
||||
NS_IMETHOD GetLabel(nsString &aText);
|
||||
NS_IMETHOD SetShortcutChar(const nsString &aText);
|
||||
NS_IMETHOD GetShortcutChar(nsString &aText);
|
||||
NS_IMETHOD GetEnabled(PRBool *aIsEnabled);
|
||||
NS_IMETHOD SetChecked(PRBool aIsEnabled);
|
||||
@ -79,14 +78,13 @@ public:
|
||||
|
||||
NS_IMETHOD DoCommand();
|
||||
NS_IMETHOD DispatchDOMEvent(const nsString &eventName, PRBool *preventDefaultCalled);
|
||||
NS_IMETHOD SetModifiers(PRUint8 aModifiers);
|
||||
NS_IMETHOD GetModifiers(PRUint8 * aModifiers);
|
||||
NS_IMETHOD SetupIcon();
|
||||
NS_IMETHOD GetMenuItemContent(nsIContent ** aMenuItemContent);
|
||||
|
||||
protected:
|
||||
|
||||
void UncheckRadioSiblings(nsIContent* inCheckedElement);
|
||||
void SetKeyEquiv(PRUint8 aModifiers, const nsString &aText);
|
||||
|
||||
NSMenuItem* mNativeMenuItem; // strong ref, we own
|
||||
|
||||
|
@ -151,13 +151,12 @@ NS_METHOD nsMenuItemX::Create(nsIMenu* aParent, const nsString & aLabel, EMenuIt
|
||||
nsCOMPtr<nsIContent> keyContent(do_QueryInterface(keyElement));
|
||||
nsAutoString keyChar(NS_LITERAL_STRING(" "));
|
||||
keyContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::key, keyChar);
|
||||
if (!keyChar.EqualsLiteral(" "))
|
||||
SetShortcutChar(keyChar);
|
||||
|
||||
|
||||
nsAutoString modifiersStr;
|
||||
keyContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::modifiers, modifiersStr);
|
||||
PRUint8 modifiers = MenuHelpersX::GeckoModifiersForNodeAttribute(modifiersStr);
|
||||
SetModifiers(modifiers);
|
||||
|
||||
SetKeyEquiv(modifiers, keyChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -296,39 +295,6 @@ NS_IMETHODIMP nsMenuItemX::DispatchDOMEvent(const nsString &eventName, PRBool *p
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_METHOD nsMenuItemX::GetModifiers(PRUint8 * aModifiers)
|
||||
{
|
||||
*aModifiers = mModifiers;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_METHOD nsMenuItemX::SetModifiers(PRUint8 aModifiers)
|
||||
{
|
||||
mModifiers = aModifiers;
|
||||
|
||||
// set up shortcut key modifiers on native menu item
|
||||
unsigned int macModifiers = MenuHelpersX::MacModifiersForGeckoModifiers(mModifiers);
|
||||
[mNativeMenuItem setKeyEquivalentModifierMask:macModifiers];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_METHOD nsMenuItemX::SetShortcutChar(const nsString &aText)
|
||||
{
|
||||
mKeyEquivalent = aText;
|
||||
|
||||
// set up shortcut key on native menu item
|
||||
NSString *keyEquivalent = [[NSString stringWithCharacters:(unichar*)mKeyEquivalent.get()
|
||||
length:mKeyEquivalent.Length()] lowercaseString];
|
||||
if (![keyEquivalent isEqualToString:@" "])
|
||||
[mNativeMenuItem setKeyEquivalent:keyEquivalent];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_METHOD nsMenuItemX::GetShortcutChar(nsString &aText)
|
||||
{
|
||||
@ -367,6 +333,26 @@ nsMenuItemX::UncheckRadioSiblings(nsIContent* inCheckedContent)
|
||||
}
|
||||
|
||||
|
||||
void nsMenuItemX::SetKeyEquiv(PRUint8 aModifiers, const nsString &aText)
|
||||
{
|
||||
mMenuBar->UnregisterKeyEquivalent([mNativeMenuItem keyEquivalentModifierMask], [mNativeMenuItem keyEquivalent]);
|
||||
|
||||
mModifiers = aModifiers;
|
||||
unsigned int macModifiers = MenuHelpersX::MacModifiersForGeckoModifiers(mModifiers);
|
||||
[mNativeMenuItem setKeyEquivalentModifierMask:macModifiers];
|
||||
|
||||
mKeyEquivalent = aText;
|
||||
NSString *keyEquivalent = [[NSString stringWithCharacters:(unichar*)mKeyEquivalent.get()
|
||||
length:mKeyEquivalent.Length()] lowercaseString];
|
||||
if ([keyEquivalent isEqualToString:@" "])
|
||||
[mNativeMenuItem setKeyEquivalent:@""];
|
||||
else
|
||||
[mNativeMenuItem setKeyEquivalent:keyEquivalent];
|
||||
|
||||
mMenuBar->RegisterKeyEquivalent([mNativeMenuItem keyEquivalentModifierMask], [mNativeMenuItem keyEquivalent]);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// nsChangeObserver
|
||||
//
|
||||
|
@ -531,6 +531,8 @@ static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow)
|
||||
if (!pnsMenuBar)
|
||||
return;
|
||||
|
||||
pnsMenuBar->Create(aParentWindow);
|
||||
|
||||
// fake event
|
||||
nsMenuEvent fake(PR_TRUE, 0, nsnull);
|
||||
pnsMenuBar->MenuConstruct(fake, aParentWindow, menubarNode);
|
||||
|
Loading…
Reference in New Issue
Block a user