a11y: Add new QAccessibleAttributesInterface

This adds a new QAccessibleAttributes interface
that implements support for reporting (object)
attributes (as compared to offset-specific text
attributes, which are handled by the
QAccessibleTextInterface).

The concept of object attributes/properties can
be found in all of ARIA, AT-SPI2 on Linux,
IAccessible2 and UIA on Windows and NSAccessibility
on macOS, and while some of the properties/attributes
on these platforms can be mapped to from information
retrieved via existing QAccessible* interfaces, a lot
of relevant information cannot be made available this
way.

The new interface is meant to bridge this gap.

Each attribute is handled as a key-value pair.
Other than for the handling of text attributes
(where a single string is used for all attributes,
s. QAccessibleTextInterface::attributes), the
object attributes handled by the new interface
use the newly introduced QAccessible::Attribute enum class
for keys. This helps to clearly define the semantics
of each attribute and simplifies mapping to the different
platform representations in the platform a11y bridges.

Initially, two attribute types, Custom
and Level are added, s. the documentation added
with this commit for more details.

Mapping of these two attributes to their platform
equivalent for AT-SPI2 on Linux and UIA on Windows
will be added in following commits.

The Core Accessibility API Mappings specification [1]
can be very useful when considering new attributes
to add and how to bridge them to the specific
platform APIs.

Conceptually, the possibility to expose object-specific
attributes might seem a good fit for the existing
QAccessibleInterface, but adding new virtual methods
to non-leaf classes would be an ABI-incompatible
change [2], so adding a new interface/class is
necessary.

There is also a related discussion for Gtk 4 in [3],
which - other than Gtk 3 - currently also lacks
API to support many AT-SPI object attributes relevant
for assistive technology like screen readers.
The implementation here is also inspired by the
dicussion there.

A sample implementation for LibreOffice can be
found at [4].

[1] https://www.w3.org/TR/core-aam-1.2/
[2] https://community.kde.org/Policies/Binary_Compatibility_Examples#Add_new_virtuals_to_a_non-leaf_class
[3] https://gitlab.gnome.org/GNOME/gtk/-/issues/6196
[4] https://gerrit.libreoffice.org/c/core/+/159309

[ChangeLog][QtGui][QAccessibleAttributesInterface] Added new
QAccessibleAttributesInterface that can be used to expose
object attributes/properties to assistive technology.

Task-number: QTBUG-119057
Change-Id: I9d51c818e82673d1e755a3c909d3e8f5bb064a35
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Michael Weghorn 2023-11-10 18:25:02 +01:00 committed by Volker Hilsheimer
parent 6164b17d22
commit fb5ffe8626
3 changed files with 107 additions and 2 deletions

View File

@ -412,6 +412,43 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
\sa QAccessibleTextInterface
*/
/*! \enum QAccessible::Attribute
This enum describes different types of attributes used by the
\l QAccessibleAttributesInterface.
\since 6.8
These attributes are comparable to the concept of properties/(object)
attributes found in ARIA, AT-SPI2, IAccessible, UIA and NSAccessibility
and are mapped to their platform counterpart where applicable.
Each attribute is handled as a key-value pair, with the values of this
enumeration being used as keys.
Attribute values are represented in a \l QVariant. The type of the value
stored in the \l QVariant is fixed and specified below for each of the
attribute types.
\value Custom value type: \a QHash<QString, QString>
The \a Custom attribute is special in that
it can effectively represent multiple attributes at
once, since it itself is a \l QHash used to represent
key-value pairs.
For platforms supporting custom key-value pairs for
attributes, those set in the \a Custom attribute
are bridged to the platform layer without applying any
translation to platform-specific attributes. In general,
the other, more strongly typed attributes should be used.
This attribute can e.g. be used for prototyping
before officially adding an official new enumeration value
for a specific feature.
\value Level value type: \a int
Defines the hierarchical level of an element within a structure,
e.g. the heading level of a heading. This attribute conceptually
matches the "aria-level" property in ARIA.
\sa QAccessibleAttributesInterface
*/
/*!
\enum QAccessible::InterfaceType
@ -431,8 +468,9 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
\value TableCellInterface For cells in a TableInterface object.
\value HyperlinkInterface For hyperlink nodes (usually embedded as children of text nodes)
\value [since 6.5] SelectionInterface For non-text objects that support selection of child objects.
\value [since 6.8] AttributesInterface For objects that support object-specific attributes.
\sa QAccessibleInterface::interface_cast(), QAccessibleTextInterface, QAccessibleValueInterface, QAccessibleActionInterface, QAccessibleTableInterface, QAccessibleTableCellInterface, QAccessibleSelectionInterface
\sa QAccessibleInterface::interface_cast(), QAccessibleTextInterface, QAccessibleValueInterface, QAccessibleActionInterface, QAccessibleTableInterface, QAccessibleTableCellInterface, QAccessibleSelectionInterface, QAccessibleAttributesInterface
*/
#if QT_CONFIG(accessibility)
@ -3069,6 +3107,54 @@ bool QAccessibleSelectionInterface::isSelected(QAccessibleInterface *childItem)
*/
/*!
\since 6.8
\class QAccessibleAttributesInterface
\inmodule QtGui
\ingroup accessibility
\brief The QAccessibleAttributesInterface class implements support for
reporting attributes for an accessible object.
Attributes are key-value pairs. Values are stored in \l QVariant.
The \a QAccessible::Attributes 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
are specific to objects implementing text and are specific to a specific text
position/offset, the attributes handled by the \l QAccessibleAttributesInterface
can be used for objects of any role and apply for the whole object.
Classes already implementing \l QAccessibleTextInterface for text-specific attrtibutes
may want to implement \l QAccessibleAttributesInterface in addition for object-specific
attributes.
*/
/*!
Destroys the QAccessibleAttributesInterface.
*/
QAccessibleAttributesInterface::~QAccessibleAttributesInterface()
{
}
/*!
\fn QList<QAccessible::Attribute> QAccessibleAttributesInterface::attributeKeys() const
Returns the keys of all attributes the object supports. The \l QAccessible::Attribute
enumeration describes available keys.
*/
/*!
\fn QVariant QAccessibleAttributesInterface::attributeValue(QAccessible::Attribute key) const
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.
*/
/*! \internal */
QString qAccessibleLocalizedActionDescription(const QString &actionName)
{

View File

@ -43,6 +43,7 @@ class QAccessibleTableInterface;
class QAccessibleTableCellInterface;
class QAccessibleHyperlinkInterface;
class QAccessibleSelectionInterface;
class QAccessibleAttributesInterface;
class QAccessibleTableModelChangeEvent;
class Q_GUI_EXPORT QAccessibleInterface
@ -106,6 +107,9 @@ public:
inline QAccessibleSelectionInterface *selectionInterface()
{ return reinterpret_cast<QAccessibleSelectionInterface *>(interface_cast(QAccessible::SelectionInterface)); }
inline QAccessibleAttributesInterface *attributesInterface()
{ return reinterpret_cast<QAccessibleAttributesInterface *>(interface_cast(QAccessible::AttributesInterface)); }
virtual void virtual_hook(int id, void *data);
virtual void *interface_cast(QAccessible::InterfaceType)
@ -284,6 +288,15 @@ public:
virtual bool clear() = 0;
};
class Q_GUI_EXPORT QAccessibleAttributesInterface
{
public:
virtual ~QAccessibleAttributesInterface();
virtual QList<QAccessible::Attribute> attributeKeys() const = 0;
virtual QVariant attributeValue(QAccessible::Attribute key) const = 0;
};
class Q_GUI_EXPORT QAccessibleEvent
{
Q_DISABLE_COPY(QAccessibleEvent)

View File

@ -349,7 +349,8 @@ public:
TableInterface,
TableCellInterface,
HyperlinkInterface,
SelectionInterface
SelectionInterface,
AttributesInterface,
};
enum TextBoundaryType {
@ -361,6 +362,11 @@ public:
NoBoundary
};
enum class Attribute {
Custom,
Level,
};
typedef QAccessibleInterface*(*InterfaceFactory)(const QString &key, QObject*);
typedef void(*UpdateHandler)(QAccessibleEvent *event);
typedef void(*RootObjectHandler)(QObject*);