a11y atspi: Bridge QAccessibleAttributesInterface to AT-SPI
This bridges the 2 currently existing attribute types for the newly added QAccessibleAttributesInterface to AT-SPI2 by using the corresponding object attributes. QAccessible::Attribute::Level semantically matches the "aria-level" ARIA attribute, and is mapped to the "level" AT-SPI object attribute as described in the Core Accessibility API Mappings specification for both, headings [1] and non-headings [2]. All of the key-value pairs set in the QAccessible::Attribute::Custom attribute are bridged to the AT-SPI level as object attributes using the same names and values. Together with a corresponding demo change [3] for LibreOffice implementing support for the QAccessible::Attribute::Level attribute in the qt6-based LibreOffice variant, this makes the specific use-case for reporting the heading level mentioned in QTBUG-119057 work with the Orca screen reader. Also tweak the QAccessibleAttributesInterface::attributeValue documentation to clarify the type to be returned in the QVariant. (The newly added AT-SPI implementation has corresponding asserts.) [1] https://www.w3.org/TR/core-aam-1.2/#ariaLevelHeading [2] https://www.w3.org/TR/core-aam-1.2/#ariaLevel [3] https://gerrit.libreoffice.org/c/core/+/159309 Task-number: QTBUG-119057 Change-Id: I7ccdbbcd601c176319ca547d4bdf50b8f93bd7d8 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
658939dae2
commit
2d3f49d797
@ -1647,7 +1647,7 @@ bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QS
|
||||
sendReply(connection, message,
|
||||
QVariant::fromValue(spiStateSetFromSpiStates(spiState)));
|
||||
} else if (function == "GetAttributes"_L1) {
|
||||
sendReply(connection, message, QVariant::fromValue(QSpiAttributeSet()));
|
||||
sendReply(connection, message, QVariant::fromValue(getAttributes(interface)));
|
||||
} else if (function == "GetRelationSet"_L1) {
|
||||
sendReply(connection, message, QVariant::fromValue(relationSet(interface, connection)));
|
||||
} else if (function == "GetApplication"_L1) {
|
||||
@ -2305,6 +2305,38 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
QSpiAttributeSet AtSpiAdaptor::getAttributes(QAccessibleInterface *interface) const
|
||||
{
|
||||
QSpiAttributeSet set;
|
||||
QAccessibleAttributesInterface *attributesIface = interface->attributesInterface();
|
||||
if (!attributesIface)
|
||||
return set;
|
||||
|
||||
const QList<QAccessible::Attribute> attrKeys = attributesIface->attributeKeys();
|
||||
for (QAccessible::Attribute key : attrKeys) {
|
||||
const QVariant value = attributesIface->attributeValue(key);
|
||||
// see "Core Accessibility API Mappings" spec: https://www.w3.org/TR/core-aam-1.2/
|
||||
switch (key) {
|
||||
case QAccessible::Attribute::Custom:
|
||||
{
|
||||
// forward custom attributes to AT-SPI as-is
|
||||
Q_ASSERT((value.canConvert<QHash<QString, QString>>()));
|
||||
const QHash<QString, QString> attrMap = value.value<QHash<QString, QString>>();
|
||||
for (auto [name, val] : attrMap.asKeyValueRange())
|
||||
set.insert(name, val);
|
||||
break;
|
||||
}
|
||||
case QAccessible::Attribute::Level:
|
||||
Q_ASSERT(value.canConvert<int>());
|
||||
set.insert(QStringLiteral("level"), QString::number(value.toInt()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
// FIXME all attribute methods below should share code
|
||||
QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int offset, bool includeDefaults) const
|
||||
{
|
||||
|
@ -89,6 +89,7 @@ private:
|
||||
|
||||
// accessible helper functions
|
||||
AtspiRole getRole(QAccessibleInterface *interface) const;
|
||||
QSpiAttributeSet getAttributes(QAccessibleInterface *) const;
|
||||
QSpiRelationArray relationSet(QAccessibleInterface *interface, const QDBusConnection &connection) const;
|
||||
QStringList accessibleInterfaces(QAccessibleInterface *interface) const;
|
||||
|
||||
|
@ -3192,7 +3192,7 @@ bool QAccessibleSelectionInterface::isSelected(QAccessibleInterface *childItem)
|
||||
|
||||
Attributes are key-value pairs. Values are stored in \l QVariant.
|
||||
|
||||
The \a QAccessible::Attributes enumeration describes the available keys and
|
||||
The \l QAccessible::Attribute enumeration describes the available keys and
|
||||
documents which type to use for the value of each key.
|
||||
|
||||
While the text-specific attributes handled by \l QAccessibleTextInterface::attributes
|
||||
@ -3225,8 +3225,11 @@ QAccessibleAttributesInterface::~QAccessibleAttributesInterface()
|
||||
|
||||
Returns the value of the attribute \a key of this object.
|
||||
|
||||
If the specificed attribute is not set for this object, an invalid
|
||||
\l QVariant is returned.
|
||||
If the attribute is set for this object, a value of the type documented for the
|
||||
given key in the documentation of the \l QAccessible::Attribute enumeration is
|
||||
returned in the \l QVariant.
|
||||
|
||||
Otherwise, an invalid \l QVariant is returned.
|
||||
*/
|
||||
|
||||
/*! \internal */
|
||||
|
Loading…
x
Reference in New Issue
Block a user