a11y uia: Support UIA_LabeledByPropertyId

In the Windows accessibility bridge, bridge the
QAccessible::Label relation to the corresponding
UIA property, UIA_LabeledByPropertyId [1].

Unlike UIA_DescribedByPropertyId,
UIA_FlowsFromPropertyId and UIA_FlowsToPropertyId
which all support "VT_UNKNOWN | VT_ARRAY",
i.e. returning an array of relation targets,
UIA_LabeledByPropertyId only supports "VT_UNKNOWN",
i.e. returning a single element.
Therefore, return only the first relation target.

Sample use with NVDA's Python console:

1) start the NVDA screen reader
2) run the "calendarwidget" example
   (examples/widgets/widgets/calendarwidget/calendarwidget.exe)
3) move focus to the "Locale" combobox
4) start NVDA's Python console (Ctrl+Insert+Z)
5) print information about the object reported
   via the UIA_LabeledByPropertyId property
   in NVDA's Python console:

    >>> focus.UIAElement.CurrentLabeledBy
    <POINTER(IUIAutomationElement) ptr=0x831b6c8 at cfb8b20>
    >>> focus.UIAElement.CurrentLabeledBy.CurrentName
    'Locale'
    >>> focus.UIAElement.CurrentLabeledBy.CurrentControlType
    50020

[1] https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-automation-element-propids

Change-Id: Ib03bfc00356b9bdab826c4c9c3d6b2b2b9fe531f
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
This commit is contained in:
Michael Weghorn 2024-11-26 11:45:14 +01:00
parent ead6f79dc0
commit 8bb9a1f247
2 changed files with 22 additions and 0 deletions

View File

@ -357,6 +357,24 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
return S_OK;
}
void QWindowsUiaMainProvider::setLabelledBy(QAccessibleInterface *accessible, VARIANT *pRetVal)
{
Q_ASSERT(accessible);
typedef std::pair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
const QList<RelationPair> relationInterfaces = accessible->relations(QAccessible::Label);
if (relationInterfaces.empty())
return;
// UIA_LabeledByPropertyId only supports one relation
ComPtr<IRawElementProviderSimple> provider = providerForAccessible(relationInterfaces.first().first);
if (!provider)
return;
pRetVal->vt = VT_UNKNOWN;
pRetVal->punkVal = provider.Detach();
}
void QWindowsUiaMainProvider::fillVariantArrayForRelation(QAccessibleInterface* accessible,
QAccessible::Relation relation, VARIANT *pRetVal)
{
@ -512,6 +530,9 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
case UIA_FlowsToPropertyId:
fillVariantArrayForRelation(accessible, QAccessible::FlowsFrom, pRetVal);
break;
case UIA_LabeledByPropertyId:
setLabelledBy(accessible, pRetVal);
break;
case UIA_FrameworkIdPropertyId:
*pRetVal = QComVariant{ QStringLiteral("Qt") }.release();
break;

View File

@ -59,6 +59,7 @@ public:
HRESULT STDMETHODCALLTYPE GetFocus(IRawElementProviderFragment **pRetVal) override;
private:
static void setLabelledBy(QAccessibleInterface *accessible, VARIANT *pRetVal);
static void fillVariantArrayForRelation(QAccessibleInterface *accessible, QAccessible::Relation relation, VARIANT *pRetVal);
static void setAriaProperties(QAccessibleInterface *accessible, VARIANT *pRetVal);
static void setStyle(QAccessibleInterface *accessible, VARIANT *pRetVal);