From 47621b72087bab6b119f187725e7b44dce435527 Mon Sep 17 00:00:00 2001 From: "surkov.alexander%gmail.com" Date: Wed, 29 Aug 2007 06:52:47 +0000 Subject: [PATCH] Bug 174889 - unable to get keyboard shortcut for treeitem node, r=smaug, ginn.chen, mats, sr=mats, a=sicking git-svn-id: svn://10.0.0.236/trunk@233290 18797224-902f-48f8-a5cc-f745e15eee43 --- .../src/base/nsAccessibilityUtils.cpp | 36 ++++++++ .../src/base/nsAccessibilityUtils.h | 8 ++ mozilla/accessible/src/base/nsAccessible.cpp | 83 ++++++++++--------- .../src/xul/nsXULMenuAccessible.cpp | 13 ++- .../events/public/nsIEventStateManager.h | 28 ++++++- .../events/src/nsEventStateManager.cpp | 41 +++++++++ .../content/events/src/nsEventStateManager.h | 1 + 7 files changed, 163 insertions(+), 47 deletions(-) diff --git a/mozilla/accessible/src/base/nsAccessibilityUtils.cpp b/mozilla/accessible/src/base/nsAccessibilityUtils.cpp index 98aae9d6036..91d46b3605e 100755 --- a/mozilla/accessible/src/base/nsAccessibilityUtils.cpp +++ b/mozilla/accessible/src/base/nsAccessibilityUtils.cpp @@ -46,6 +46,9 @@ #include "nsIDOMXULSelectCntrlEl.h" #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsIEventListenerManager.h" +#include "nsIPresShell.h" +#include "nsPresContext.h" +#include "nsIEventStateManager.h" #include "nsISelection2.h" #include "nsISelectionController.h" @@ -176,6 +179,39 @@ nsAccUtils::HasListener(nsIContent *aContent, const nsAString& aEventType) return listenerManager && listenerManager->HasListenersFor(aEventType); } +PRUint32 +nsAccUtils::GetAccessKeyFor(nsIContent *aContent) +{ + if (!aContent) + return 0; + + // Accesskeys are registered by @accesskey attribute only. At first check + // whether it is presented on the given element to avoid the slow + // nsIEventStateManager::GetRegisteredAccessKey() method. + if (!aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::accesskey)) + return 0; + + nsCOMPtr doc = aContent->GetOwnerDoc(); + if (!doc) + return 0; + + nsCOMPtr presShell = doc->GetPrimaryShell(); + if (!presShell) + return 0; + + nsPresContext *presContext = presShell->GetPresContext(); + if (!presContext) + return 0; + + nsIEventStateManager *esm = presContext->EventStateManager(); + if (!esm) + return 0; + + PRUint32 key = 0; + esm->GetRegisteredAccessKey(aContent, &key); + return key; +} + nsresult nsAccUtils::FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible, PRBool aIsAsynch) diff --git a/mozilla/accessible/src/base/nsAccessibilityUtils.h b/mozilla/accessible/src/base/nsAccessibilityUtils.h index 0bc16626cea..13eef1db06d 100755 --- a/mozilla/accessible/src/base/nsAccessibilityUtils.h +++ b/mozilla/accessible/src/base/nsAccessibilityUtils.h @@ -109,6 +109,14 @@ public: */ static PRBool HasListener(nsIContent *aContent, const nsAString& aEventType); + /** + * Return an accesskey registered on the given element by + * nsIEventStateManager or 0 if there is no registered accesskey. + * + * @param aContent - the given element. + */ + static PRUint32 GetAccessKeyFor(nsIContent *aContent); + /** * Fire accessible event of the given type for the given accessible. */ diff --git a/mozilla/accessible/src/base/nsAccessible.cpp b/mozilla/accessible/src/base/nsAccessible.cpp index 767f58e538f..a6457374b0b 100644 --- a/mozilla/accessible/src/base/nsAccessible.cpp +++ b/mozilla/accessible/src/base/nsAccessible.cpp @@ -349,7 +349,7 @@ NS_IMETHODIMP nsAccessible::GetDescription(nsAString& aDescription) // returns the accesskey modifier mask used in the given node's context // (i.e. chrome or content), or 0 if an error occurs static PRInt32 -GetAccessModifierMask(nsIDOMElement* aDOMNode) +GetAccessModifierMask(nsIContent* aContent) { nsCOMPtr prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID); @@ -370,8 +370,7 @@ GetAccessModifierMask(nsIDOMElement* aDOMNode) } // get the docShell to this DOMNode, return 0 on failure - nsCOMPtr content(do_QueryInterface(aDOMNode)); - nsCOMPtr document = content->GetCurrentDoc(); + nsCOMPtr document = aContent->GetCurrentDoc(); if (!document) return 0; nsCOMPtr container = document->GetContainer(); @@ -398,47 +397,49 @@ GetAccessModifierMask(nsIDOMElement* aDOMNode) return NS_SUCCEEDED(rv) ? accessModifierMask : 0; } -NS_IMETHODIMP nsAccessible::GetKeyboardShortcut(nsAString& _retval) +NS_IMETHODIMP +nsAccessible::GetKeyboardShortcut(nsAString& aAccessKey) { - nsCOMPtr elt(do_QueryInterface(mDOMNode)); - if (elt) { - nsAutoString accesskey; - elt->GetAttribute(NS_LITERAL_STRING("accesskey"), accesskey); - if (accesskey.IsEmpty()) { - nsCOMPtr content = do_QueryInterface(elt); - nsIContent *labelContent = GetLabelContent(content); - if (labelContent) { - labelContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::accesskey, accesskey); - } - if (accesskey.IsEmpty()) { - return NS_ERROR_FAILURE; - } - } + aAccessKey.Truncate(); - // append the modifiers in reverse order - // (result: Control+Alt+Shift+Meta+) - nsAutoString propertyKey; - PRInt32 modifierMask = GetAccessModifierMask(elt); - if (modifierMask & NS_MODIFIER_META) { - propertyKey.AssignLiteral("VK_META"); - nsAccessible::GetFullKeyName(propertyKey, accesskey, accesskey); - } - if (modifierMask & NS_MODIFIER_SHIFT) { - propertyKey.AssignLiteral("VK_SHIFT"); - nsAccessible::GetFullKeyName(propertyKey, accesskey, accesskey); - } - if (modifierMask & NS_MODIFIER_ALT) { - propertyKey.AssignLiteral("VK_ALT"); - nsAccessible::GetFullKeyName(propertyKey, accesskey, accesskey); - } - if (modifierMask & NS_MODIFIER_CONTROL) { - propertyKey.AssignLiteral("VK_CONTROL"); - nsAccessible::GetFullKeyName(propertyKey, accesskey, accesskey); - } - _retval= accesskey; - return NS_OK; + nsCOMPtr content(do_QueryInterface(mDOMNode)); + if (!content) + return NS_ERROR_FAILURE; + + PRUint32 key = nsAccUtils::GetAccessKeyFor(content); + if (!key) { + nsCOMPtr labelContent(GetLabelContent(content)); + if (labelContent) + key = nsAccUtils::GetAccessKeyFor(labelContent); } - return NS_ERROR_FAILURE; + + if (!key) + return NS_OK; + + nsAutoString accesskey(key); + + // Append the modifiers in reverse order, result: Control+Alt+Shift+Meta+ + nsAutoString propertyKey; + PRInt32 modifierMask = GetAccessModifierMask(content); + if (modifierMask & NS_MODIFIER_META) { + propertyKey.AssignLiteral("VK_META"); + nsAccessible::GetFullKeyName(propertyKey, accesskey, accesskey); + } + if (modifierMask & NS_MODIFIER_SHIFT) { + propertyKey.AssignLiteral("VK_SHIFT"); + nsAccessible::GetFullKeyName(propertyKey, accesskey, accesskey); + } + if (modifierMask & NS_MODIFIER_ALT) { + propertyKey.AssignLiteral("VK_ALT"); + nsAccessible::GetFullKeyName(propertyKey, accesskey, accesskey); + } + if (modifierMask & NS_MODIFIER_CONTROL) { + propertyKey.AssignLiteral("VK_CONTROL"); + nsAccessible::GetFullKeyName(propertyKey, accesskey, accesskey); + } + + aAccessKey = accesskey; + return NS_OK; } NS_IMETHODIMP nsAccessible::SetParent(nsIAccessible *aParent) diff --git a/mozilla/accessible/src/xul/nsXULMenuAccessible.cpp b/mozilla/accessible/src/xul/nsXULMenuAccessible.cpp index 5e0d5335651..ce89a0640fc 100644 --- a/mozilla/accessible/src/xul/nsXULMenuAccessible.cpp +++ b/mozilla/accessible/src/xul/nsXULMenuAccessible.cpp @@ -391,13 +391,18 @@ NS_IMETHODIMP nsXULMenuitemAccessible::GetDescription(nsAString& aDescription) } //return menu accesskey: N or Alt+F -NS_IMETHODIMP nsXULMenuitemAccessible::GetKeyboardShortcut(nsAString& _retval) +NS_IMETHODIMP +nsXULMenuitemAccessible::GetKeyboardShortcut(nsAString& aAccessKey) { + aAccessKey.Truncate(); + static PRInt32 gMenuAccesskeyModifier = -1; // magic value of -1 indicates unitialized state nsCOMPtr elt(do_QueryInterface(mDOMNode)); if (elt) { nsAutoString accesskey; + // We do not use nsAccUtils::GetAccesskeyFor() because accesskeys for + // menu are't registered by nsIEventStateManager. elt->GetAttribute(NS_LITERAL_STRING("accesskey"), accesskey); if (accesskey.IsEmpty()) return NS_OK; @@ -423,11 +428,11 @@ NS_IMETHODIMP nsXULMenuitemAccessible::GetKeyboardShortcut(nsAString& _retval) case nsIDOMKeyEvent::DOM_VK_META: propertyKey.AssignLiteral("VK_META"); break; } if (!propertyKey.IsEmpty()) - nsAccessible::GetFullKeyName(propertyKey, accesskey, _retval); + nsAccessible::GetFullKeyName(propertyKey, accesskey, aAccessKey); } } - if (_retval.IsEmpty()) - _retval = accesskey; + if (aAccessKey.IsEmpty()) + aAccessKey = accesskey; return NS_OK; } return NS_ERROR_FAILURE; diff --git a/mozilla/content/events/public/nsIEventStateManager.h b/mozilla/content/events/public/nsIEventStateManager.h index 7f30f1feb6d..24afac8bf9a 100644 --- a/mozilla/content/events/public/nsIEventStateManager.h +++ b/mozilla/content/events/public/nsIEventStateManager.h @@ -54,8 +54,8 @@ class imgIContainer; */ // {fb7516ff-2f01-4893-84e8-e4b282813023} #define NS_IEVENTSTATEMANAGER_IID \ -{ 0xfb7516ff, 0x2f01, 0x4893, \ - { 0x84, 0xe8, 0xe4, 0xb2, 0x82, 0x81, 0x30, 0x23 } } +{ 0x522d12ec, 0xde51, 0x4635, \ + { 0xb0, 0x10, 0x4, 0x2a, 0x6d, 0x5, 0xa0, 0x3e } } #define NS_EVENT_NEEDS_FRAME(event) (!NS_IS_FOCUS_EVENT(event)) @@ -132,9 +132,33 @@ public: NS_IMETHOD ChangeFocusWith(nsIContent *aFocusContent, EFocusedWithType aFocusedWith) = 0; // Access Key Registration + + /** + * Register accesskey on the given element. When accesskey is activated then + * the element will be notified via nsIContent::PerformAccesskey() method. + * + * @param aContent the given element + * @param aKey accesskey + */ NS_IMETHOD RegisterAccessKey(nsIContent* aContent, PRUint32 aKey) = 0; + + /** + * Unregister accesskey for the given element. + * + * @param aContent the given element + * @param aKey accesskey + */ NS_IMETHOD UnregisterAccessKey(nsIContent* aContent, PRUint32 aKey) = 0; + /** + * Get accesskey registered on the given element or 0 if there is none. + * + * @param aContent the given element + * @param aKey registered accesskey + * @return NS_OK + */ + NS_IMETHOD GetRegisteredAccessKey(nsIContent* aContent, PRUint32* aKey) = 0; + NS_IMETHOD SetCursor(PRInt32 aCursor, imgIContainer* aContainer, PRBool aHaveHotspot, float aHotspotX, float aHotspotY, nsIWidget* aWidget, PRBool aLockCursor) = 0; diff --git a/mozilla/content/events/src/nsEventStateManager.cpp b/mozilla/content/events/src/nsEventStateManager.cpp index 9b1482b6c33..5d04ceb331c 100644 --- a/mozilla/content/events/src/nsEventStateManager.cpp +++ b/mozilla/content/events/src/nsEventStateManager.cpp @@ -179,6 +179,27 @@ enum { MOUSE_SCROLL_PIXELS }; +struct AccessKeyInfo { + PRUint32 mAccessKey; + nsIContent* mTarget; + + AccessKeyInfo(nsIContent* aTarget) : mAccessKey(0), mTarget(aTarget) {} +}; + +static PRIntn PR_CALLBACK +FindTargetForAccessKey(nsHashKey *aKey, void *aData, void* aClosure) +{ + AccessKeyInfo* info = static_cast(aClosure); + nsIContent* aTarget = static_cast(aData); + + if (aTarget == info->mTarget) { + info->mAccessKey = aKey->HashCode(); + return kHashEnumerateStop; + } + + return kHashEnumerateNext; +} + // mask values for ui.key.chromeAccess and ui.key.contentAccess #define NS_MODIFIER_SHIFT 1 #define NS_MODIFIER_CONTROL 2 @@ -4659,6 +4680,8 @@ nsEventStateManager::RegisterAccessKey(nsIContent* aContent, PRUint32 aKey) PRUint32 accKey = (IS_IN_BMP(aKey)) ? ToLowerCase((PRUnichar)aKey) : aKey; nsVoidKey key(NS_INT32_TO_PTR(accKey)); + NS_ASSERTION(key.HashCode() == accKey, + "nsHashKey::HashCode() doesn't return an accesskey"); #ifdef DEBUG_jag nsCOMPtr oldContent = dont_AddRef(static_cast(mAccessKeys->Get(&key))); @@ -4694,6 +4717,24 @@ nsEventStateManager::UnregisterAccessKey(nsIContent* aContent, PRUint32 aKey) return NS_OK; } +NS_IMETHODIMP +nsEventStateManager::GetRegisteredAccessKey(nsIContent* aContent, + PRUint32* aKey) +{ + NS_ENSURE_ARG(aContent); + NS_ENSURE_ARG_POINTER(aKey); + *aKey = 0; + + if (!mAccessKeys) + return NS_OK; + + AccessKeyInfo info(aContent); + mAccessKeys->Enumerate(FindTargetForAccessKey, &info); + + *aKey = info.mAccessKey; + return NS_OK; +} + void nsEventStateManager::ForceViewUpdate(nsIView* aView) { diff --git a/mozilla/content/events/src/nsEventStateManager.h b/mozilla/content/events/src/nsEventStateManager.h index b87e723ceea..d66c7d2480c 100644 --- a/mozilla/content/events/src/nsEventStateManager.h +++ b/mozilla/content/events/src/nsEventStateManager.h @@ -127,6 +127,7 @@ public: // Access Key Registration NS_IMETHOD RegisterAccessKey(nsIContent* aContent, PRUint32 aKey); NS_IMETHOD UnregisterAccessKey(nsIContent* aContent, PRUint32 aKey); + NS_IMETHOD GetRegisteredAccessKey(nsIContent* aContent, PRUint32* aKey); NS_IMETHOD SetCursor(PRInt32 aCursor, imgIContainer* aContainer, PRBool aHaveHotspot, float aHotspotX, float aHotspotY,