diff --git a/accessible/basetypes/Accessible.h b/accessible/basetypes/Accessible.h index c0beb34d50fa..92413da2ce2e 100644 --- a/accessible/basetypes/Accessible.h +++ b/accessible/basetypes/Accessible.h @@ -404,6 +404,9 @@ class Accessible { virtual Maybe GetIntARIAAttr(nsAtom* aAttrName) const = 0; + virtual bool GetStringARIAAttr(nsAtom* aAttrName, + nsAString& aAttrValue) const = 0; + /** * Get the relation of the given type. */ diff --git a/accessible/generic/LocalAccessible.cpp b/accessible/generic/LocalAccessible.cpp index a420ae1e3464..bdde86cd58e8 100644 --- a/accessible/generic/LocalAccessible.cpp +++ b/accessible/generic/LocalAccessible.cpp @@ -4490,3 +4490,11 @@ Maybe LocalAccessible::GetIntARIAAttr(nsAtom* aAttrName) const { } return Nothing(); } + +bool LocalAccessible::GetStringARIAAttr(nsAtom* aAttrName, + nsAString& aAttrValue) const { + if (dom::Element* elm = Elm()) { + return nsAccUtils::GetARIAAttr(elm, aAttrName, aAttrValue); + } + return false; +} diff --git a/accessible/generic/LocalAccessible.h b/accessible/generic/LocalAccessible.h index 24bbfc482d30..1a262ef0e074 100644 --- a/accessible/generic/LocalAccessible.h +++ b/accessible/generic/LocalAccessible.h @@ -435,6 +435,9 @@ class LocalAccessible : public nsISupports, public Accessible { virtual Maybe GetIntARIAAttr(nsAtom* aAttrName) const override; + virtual bool GetStringARIAAttr(nsAtom* aAttrName, + nsAString& aAttrValue) const override; + ////////////////////////////////////////////////////////////////////////////// // Downcasting and types diff --git a/accessible/ipc/RemoteAccessible.cpp b/accessible/ipc/RemoteAccessible.cpp index 09eec6ae74ab..9955e5a2cdbd 100644 --- a/accessible/ipc/RemoteAccessible.cpp +++ b/accessible/ipc/RemoteAccessible.cpp @@ -2337,6 +2337,18 @@ Maybe RemoteAccessible::GetIntARIAAttr(nsAtom* aAttrName) const { return Nothing(); } +bool RemoteAccessible::GetStringARIAAttr(nsAtom* aAttrName, + nsAString& aAttrValue) const { + if (RequestDomainsIfInactive(CacheDomain::ARIA)) { + return false; + } + if (auto attrs = GetCachedARIAAttributes()) { + return attrs->GetAttribute(aAttrName, aAttrValue); + } + + return false; +} + void RemoteAccessible::Language(nsAString& aLocale) { if (RequestDomainsIfInactive(CacheDomain::Text)) { return; diff --git a/accessible/ipc/RemoteAccessible.h b/accessible/ipc/RemoteAccessible.h index 17392a84c9ac..b2bbf473ce68 100644 --- a/accessible/ipc/RemoteAccessible.h +++ b/accessible/ipc/RemoteAccessible.h @@ -230,6 +230,9 @@ class RemoteAccessible : public Accessible, public HyperTextAccessibleBase { virtual Maybe GetIntARIAAttr(nsAtom* aAttrName) const override; + virtual bool GetStringARIAAttr(nsAtom* aAttrName, + nsAString& aAttrValue) const override; + virtual void Language(nsAString& aLocale) override; ////////////////////////////////////////////////////////////////////////////// diff --git a/accessible/mac/MOXAccessibleProtocol.h b/accessible/mac/MOXAccessibleProtocol.h index 2d80a081f6ea..8bae8671a609 100644 --- a/accessible/mac/MOXAccessibleProtocol.h +++ b/accessible/mac/MOXAccessibleProtocol.h @@ -341,6 +341,9 @@ // AXLanguage - (NSString* _Nullable)moxLanguage; +// AXKeyShortcutsValue +- (NSString* _Nullable)moxKeyShortcutsValue; + // AXMozDebugDescription - (NSString* _Nullable)moxMozDebugDescription; diff --git a/accessible/mac/mozAccessible.h b/accessible/mac/mozAccessible.h index 90a88e4ab91a..f3c265464d6e 100644 --- a/accessible/mac/mozAccessible.h +++ b/accessible/mac/mozAccessible.h @@ -248,6 +248,9 @@ enum CheckedState { // override - (NSString*)moxLanguage; +// override +- (NSString*)moxKeyShortcutsValue; + #ifndef RELEASE_OR_BETA // override - (NSString*)moxMozDebugDescription; diff --git a/accessible/mac/mozAccessible.mm b/accessible/mac/mozAccessible.mm index 95582b56746e..87c63671f492 100644 --- a/accessible/mac/mozAccessible.mm +++ b/accessible/mac/mozAccessible.mm @@ -769,6 +769,19 @@ struct RoleDescrComparator { return nsCocoaUtils::ToNSString(lang); } +- (NSString*)moxKeyShortcutsValue { + MOZ_ASSERT(mGeckoAccessible); + + nsAutoString shortcut; + + if (!mGeckoAccessible->GetStringARIAAttr(nsGkAtoms::aria_keyshortcuts, + shortcut)) { + return nil; + } + + return nsCocoaUtils::ToNSString(shortcut); +} + #ifndef RELEASE_OR_BETA - (NSString*)moxMozDebugDescription { NS_OBJC_BEGIN_TRY_BLOCK_RETURN; diff --git a/accessible/tests/browser/mac/browser.toml b/accessible/tests/browser/mac/browser.toml index 0ee0d980c6dc..389483de1ea1 100644 --- a/accessible/tests/browser/mac/browser.toml +++ b/accessible/tests/browser/mac/browser.toml @@ -29,6 +29,8 @@ skip-if = ["os == 'mac' && os_version == '15.30' && arch == 'aarch64' && opt"] # ["browser_aria_haspopup.js"] +["browser_aria_keyshortcuts.js"] + ["browser_aria_placeholder.js"] ["browser_aria_setsize.js"] diff --git a/accessible/tests/browser/mac/browser_aria_keyshortcuts.js b/accessible/tests/browser/mac/browser_aria_keyshortcuts.js new file mode 100644 index 000000000000..6bcd990048c6 --- /dev/null +++ b/accessible/tests/browser/mac/browser_aria_keyshortcuts.js @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * Test aria-keyshortcuts + */ +addAccessibleTask( + ` +
bar
+ `, + (browser, accDoc) => { + let btn = getNativeInterface(accDoc, "btn"); + is( + btn.getAttributeValue("AXKeyShortcutsValue"), + "Alt+Shift+f", + "aria-keyshortcuts value is correct" + ); + } +); diff --git a/accessible/tests/browser/windows/ia2/browser.toml b/accessible/tests/browser/windows/ia2/browser.toml index 9554a7cd44e2..025e64c03ea2 100644 --- a/accessible/tests/browser/windows/ia2/browser.toml +++ b/accessible/tests/browser/windows/ia2/browser.toml @@ -15,6 +15,8 @@ prefs = [ ["browser_groupPosition.js"] +["browser_keyboard_shortcut.js"] + ["browser_osPicker.js"] ["browser_role.js"] diff --git a/accessible/tests/browser/windows/ia2/browser_keyboard_shortcut.js b/accessible/tests/browser/windows/ia2/browser_keyboard_shortcut.js new file mode 100644 index 000000000000..773b202c763c --- /dev/null +++ b/accessible/tests/browser/windows/ia2/browser_keyboard_shortcut.js @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +addAccessibleTask( + ` + +
bar
+ + `, + async function () { + is( + await runPython(` + global doc + doc = getDocIa2() + btn = findIa2ByDomId(doc, "btn1") + return btn.accKeyboardShortcut(CHILDID_SELF) + `), + "Alt+Shift+s", + "btn1 has correct keyboard shortcut" + ); + + is( + await runPython(` + btn = findIa2ByDomId(doc, "btn2") + return btn.accKeyboardShortcut(CHILDID_SELF) + `), + "Alt+Shift+f", + "btn2 has correct keyboard shortcut" + ); + }, + { chrome: true, topLevel: true } +); diff --git a/accessible/tests/browser/windows/uia/browser_generalProps.js b/accessible/tests/browser/windows/uia/browser_generalProps.js index 244c9e4b1b6a..50a45c2ea515 100644 --- a/accessible/tests/browser/windows/uia/browser_generalProps.js +++ b/accessible/tests/browser/windows/uia/browser_generalProps.js @@ -453,3 +453,21 @@ addUiaTask( ); } ); + +/** + * Test the AcceleratorKey property. + */ +addUiaTask( + ` +
foo
+ `, + async function testAcceleratorKey() { + await definePyVar("doc", `getDocUia()`); + is( + await runPython(`findUiaByDomId(doc, "button").CurrentAcceleratorKey`), + "Alt+Shift+f", + "button has correct AcceleratorKey" + ); + }, + { uiaEnabled: true, uiaDisabled: false } +); diff --git a/accessible/windows/msaa/MsaaAccessible.cpp b/accessible/windows/msaa/MsaaAccessible.cpp index ff6bd0d3e0f2..9adbed51f0c3 100644 --- a/accessible/windows/msaa/MsaaAccessible.cpp +++ b/accessible/windows/msaa/MsaaAccessible.cpp @@ -865,15 +865,18 @@ MsaaAccessible::get_accKeyboardShortcut( pszKeyboardShortcut); } - KeyBinding keyBinding = mAcc->AccessKey(); - if (keyBinding.IsEmpty()) { - if (LocalAccessible* localAcc = mAcc->AsLocal()) { - keyBinding = localAcc->KeyboardShortcut(); - } - } - nsAutoString shortcut; - keyBinding.ToString(shortcut); + + if (!mAcc->GetStringARIAAttr(nsGkAtoms::aria_keyshortcuts, shortcut)) { + KeyBinding keyBinding = mAcc->AccessKey(); + if (keyBinding.IsEmpty()) { + if (LocalAccessible* localAcc = mAcc->AsLocal()) { + keyBinding = localAcc->KeyboardShortcut(); + } + } + + keyBinding.ToString(shortcut); + } *pszKeyboardShortcut = ::SysAllocStringLen(shortcut.get(), shortcut.Length()); return *pszKeyboardShortcut ? S_OK : E_OUTOFMEMORY; diff --git a/accessible/windows/uia/uiaRawElmProvider.cpp b/accessible/windows/uia/uiaRawElmProvider.cpp index 1f3a14b3fcdc..8e91342b7417 100644 --- a/accessible/windows/uia/uiaRawElmProvider.cpp +++ b/accessible/windows/uia/uiaRawElmProvider.cpp @@ -514,13 +514,14 @@ uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId, switch (aPropertyId) { // Accelerator Key / shortcut. case UIA_AcceleratorKeyPropertyId: { - if (!localAcc) { - // KeyboardShortcut is only currently relevant for LocalAccessible. - break; - } nsAutoString keyString; - localAcc->KeyboardShortcut().ToString(keyString); + if (!acc->GetStringARIAAttr(nsGkAtoms::aria_keyshortcuts, keyString)) { + if (localAcc) { + // KeyboardShortcut is only currently relevant for LocalAccessible. + localAcc->KeyboardShortcut().ToString(keyString); + } + } if (!keyString.IsEmpty()) { aPropertyValue->vt = VT_BSTR;