CopperSpice API
1.9.2
|
Group of classes which connect to the operating system accessibility functionality. More...
Classes | |
class | QAccessible |
Enums and static functions relating to accessibility More... | |
class | QAccessible::State |
Structure which defines bit flags that indicate the state of an accessible object More... | |
class | QAccessibleActionInterface |
Implements support for invocable actions in the interface More... | |
class | QAccessibleBridge |
Base class for accessibility back-ends More... | |
class | QAccessibleBridgePlugin |
Abstract base for accessibility bridge plugins More... | |
class | QAccessibleEvent |
Base class for accessibility notifications More... | |
class | QAccessibleInterface |
Defines an interface that exposes information about accessible objects More... | |
class | QAccessibleObject |
Implements parts of the QAccessibleInterface for QObjects More... | |
class | QAccessiblePlugin |
Abstract base for accessibility plugins More... | |
class | QAccessibleTableCellInterface |
Implements support for the IAccessibleTable2 Cell interface More... | |
class | QAccessibleTableInterface |
Implements support for the IAccessibleTable2 interface More... | |
class | QAccessibleTableModelChangeEvent |
Indicates a change in a table, list, or tree when cells are added or removed More... | |
class | QAccessibleTextInterface |
Implements support for text handling More... | |
class | QAccessibleValueInterface |
Support for objects which represent a value More... | |
class | QAccessibleWidget |
Implements the QAccessibleInterface for QWidgets More... | |
class | QPlatformAccessibility |
Base class for integrating accessibility backends More... | |
Accessibility in computer software is making applications usable for people with different abilities. It is important to take different people's needs into account, for example, in case of low vision, hearing, dexterity, or cognitive problems. Some examples of accessibility measures are keyboard shortcuts, a high-contrast user interface that uses specially selected colors and fonts, or support for assistive tools such as screen readers and braille displays.
An application should consider the following items to provide accessibility.
This remainder of this documentation assumes the foundation for accessibility have been implemented in your application and focuses more specifically on supporting assistive technology.
There are a number of different Assistive Tools which can be used to provide a solution for users who require special accessibility features. The information needed by the specific tool will differ depending upon what it does. CopperSpice applications should provide a generic API to the Assistive Tool so it can query information about what is on the screen and then provide the appropriate accessibility to the end user.
Applications do not usually communicate directly with the assistive tools, but rather through a platform specific API. Accessibility support to your application may only require a few changes to provide accessibility information.
Generally the communication with the ATs works though an IPC mechanism. Semantic information about user interface elements, such as buttons and scroll bars, is exposed to the assistive technologies. CopperSpice supports Microsoft Active Accessibility (MSAA) and IAccessible2 on Windows, macOS Accessibility on macOS, and AT-SPI via DBus on Unix/X11. The platform specific technologies are abstracted by CopperSpice so applications do not need any platform specific changes to work with the different native APIs.
In this overview document, we will examine the overall accessibility architecture and how to implement accessibility for custom widgets and elements.
When we communicate with the assistive technologies, we need to describe the CopperSpice user interface in a way that they can understand. CopperSpice applications use QAccessibleInterface to expose information about the individual UI elements. Currently, CopperSpice provides support for its widgets and widget parts, e.g., slider handles, but the interface could also be implemented for any QObject if necessary. QAccessible contains enums that describe the UI. The description is mainly based on MSAA and is independent of CopperSpice.
The structure of the UI is represented as a tree of QAccessibleInterface subclasses. You can think of this as a representation of a UI like the QObject tree built by CopperSpice. Objects can be widgets or widget parts (such as scroll bar handles).
Servers notify clients through QAccessible::updateAccessibility() about changes in objects by sending events and the clients register to receive the events. The available events are defined by the QAccessible::Event enum. The clients may then query for the object that generated the event through QAccessible::queryAccessibleInterface().
The members and enums in QAccessible are used to describe accessible objects.
A client can also retrieve the content of objects. For example, to retrieve a button's text, use the QAccessible::Text enum.
As mentioned, a tree structure is built from the accessible objects of an application. By navigating through the tree, the clients can access all elements in the UI. Object relations give clients information about the UI. For instance, a slider handle is a child of the slider to which it belongs. QAccessible::Relation describes the various relationships the clients can ask objects about.
There is no direct mapping between a QObject tree and the accessible object tree. For instance, scroll bar handles are accessible objects but are not widgets or objects in CopperSpice.
AT-Clients have access to the accessibility object tree through the root object in the tree, which is the QApplication. They can navigate the tree with the QAccessibleInterface::parent(), QAccessibleInterface::childCount() and QAccessibleInterface::child() methods.
CopperSpice provides accessible interfaces for its widgets. Interfaces for any QObject subclass can be requested through QAccessible::queryAccessibleInterface(). A default implementation is provided if a more specialized interface is not defined. An AT-Client can not acquire an interface for accessible objects that do not have an equivalent QObject, e.g., scroll bar handles, but they appear as normal objects through interfaces of parent accessible objects, e.g., you can query their relationships with QAccessibleInterface::relations().
To illustrate, the following is an image of an accessible object tree. Beneath the tree is a table with examples of object relationships.
The labels in top-down order are: the QAccessibleInterface class name, the widget for which an interface is provided, and the Role of the object. The PageLeft, Position, and PageRight correspond to the slider groove left, slider handle, and the slider groove right, respectively. These accessible objects do not have an equivalent QObject.
Source Object | Target Object | Relation |
---|---|---|
Slider | Indicator | Controller |
Indicator | Slider | Controlled |
Slider | Application | Ancestor |
Application | Slider | Child |
PushButton | Indicator | Sibling |
Accessibility is managed by static methods in the QAccessible class, These methods are responsible for building the object tree and initiating the connection with MSAA or the other platform specific technologies. If your interest is in making an application accessible, you can skip over this section to Implementing Accessibility.
Communication between clients and the server is set up when QAccessible::setRootObject() is called. This will automatically happen when a QApplication is instantiated in your program. When a QObject calls QAccessible::updateAccessibility(), clients that are listening to events are notified of the changes and events are posted to the assistive technology.
The method QAccessible::queryAccessibleInterface() returns accessible interfaces for any given QObject. Since all of the widgets in CopperSpice provide interfaces, if you need interfaces to control the behavior of other QObject subclasses you will need to implement these interfaces. The QAccessibleObject class can be used to implement parts of this functionality.
The factory that produces accessibility interfaces for QObjects is a function of type QAccessible::InterfaceFactory. It is possible to have several factories installed. The last factory installed will be the first one invoked. Normally you will not need to implement a factory since implementing a plugin will provide an interface.
To provide accessibility support for a widget or another user interface element, you need to implement the QAccessibleInterface and distribute it in a QAccessiblePlugin. It is also possible to compile the interface into the application and provide a QAccessible::InterfaceFactory. The factory can be used if you link statically or do not want the added complexity of plugins.
If you want your application to support accessibility you will need to consider the following items.
You should be familiar with MSAA, which the CopperSpice accessibility architecture is based on. You should also study the enum values of QAccessible as these describe the roles, actions, relationships, and events you need to consider.
One major problem with the MSAA standard is that some interfaces are implemented in an inconsistent way. This can make things difficult for clients and often leads to guesswork on object functionality.
It is possible to implement interfaces by inheriting from QAccessibleInterface and overriding its pure virtual methods. In practice it is better to inherit from QAccessibleObject or QAccessibleWidget, which implement part of the functionality for you. In the next section, we will see an example of implementing accessibility for a widget by inheriting the QAccessibleWidget class.
When implementing an accessibility interface for widgets you normally inherit from QAccessibleWidget. Another option is to inherit directly from the parent QAccessibleObject class, which implements part of the interface for QObject.
The QAccessibleWidget provides the following functionality.
Instead of creating a custom widget and implementing an interface, we will show how accessibility is implemented for one of the CopperSpice standard widgets, namely QSlider. The accessible interface class QAccessibleSlider, inherits from QAccessibleAbstractSlider, which in turn inherits from QAccessibleWidget.
The following code is the constructor for QAccessibleSlider. The slider is a complex control that functions as a Controller for its accessible children. This relationship must be known by the interface for QAccessibleInterface::parent(), QAccessibleInterface::child() and QAccessibleInterface::relations(). This can be done using a controlling signal, which is a mechanism provided by QAccessibleWidget.
When an accessible object is changed in a way that users need to know about, it notifies clients of the change by sending them an event via the accessible interface. This is how QSlider calls updateAccessibility() to indicate that its value has changed.
The call is made after the value of the slider has changed because clients may query the new value immediately after receiving the event.
The interface must be able to calculate bounding rectangles of itself and any children that do not provide an interface of their own. The QAccessibleSlider has three such children identified by the private enum, SliderElements
, which has the following values: PageLeft
(the rectangle on the left hand side of the slider handle), PageRight
(the rectangle on the right hand side of the handle), and Position
, (the slider handle).
The first part of the method which we have omitted, uses the current style to calculate the slider handle's bounding rectangle and is stored in srect
. If child is 0 the default case is used and we return the QSlider bounding rectangle obtained from the superclass. This is effectively the value obtained from QAccessibleWidget::rect(). Before the rectangle is returned it must be mapped to screen coordinates.
The following is an implementation of the rect() method.
The QAccessibleSlider must reimplement QAccessibleInterface::childCount() since it manages children without interfaces. The text() method returns the QAccessible::Text strings for the slider.
The call to the slider()
method returns a pointer to the interface's QSlider. Some values are left for the superclass implementation. Not all values are appropriate for all accessible objects, as you can see for the QAccessible::Value case. You should just return an empty string for those values where no relevant text can be provided.
The implementation of the role() method is pretty straightforward. It should reimplement all objects and describe the role of the slider and any children which do not provide accessible interfaces of their own.
Next, the accessible interface needs to return the QAccessible::State that the slider can be in. The following is a look at a few parts of the implementation to show they are handled.
The superclass implementation of state() uses the QAccessibleInterface::state() implementation. We simply need to disable the buttons if the slider is at its minimum or maximum.
We have now exposed the information about the slider to the clients. For the clients to be able to alter the slider and change its value, we must provide information about the actions that can be performed and perform them upon request.
Applications can expose actions which can be invoked by the client. In order to support actions in an object inherit from the QAccessibleActionInterface class. Interactive elements should expose and functionality invoked by user input. For example a push button should expose a click action.
Setting the focus is another action that should be implemented for widgets that accept receive the focus. You will need to reimplement QAccessibleActionInterface::actionNames() to return a list of all actions that the object supports. This list should not be localized.
There are two methods that give information about the actions that must return localized strings: QAccessibleActionInterface::localizedActionName() and QAccessibleActionInterface::localizedActionDescription(). These methods can be used by the client to present the actions to the user. In general, the name should be concise and only consist of a single word, such as "press".
There is a list of standard action names and localizations available that should be used when the action fits. This makes it easier for clients to understand the semantics and CopperSpice will try to expose them correctly on the different platforms. Of course the action also needs a way to be triggered. For example, QAccessibleActionInterface::doAction() should invoke the action as advertised by name and description.
This section covers the steps required to implement accessible plugins. A plugin is a class stored in a shared library which is loaded at run time. It can be convenient to distribute interfaces as plugins since they will only be loaded when required.
Creating an accessible plugin is achieved by subclassing QAccessiblePlugin, reimplementing the pure virtual method create() and then exporting the class with the CS_PLUGIN_REGISTER() macro.
In the header file you will need the following class.
This code shows an implementation of the create() method. We check whether the interface requested is for QSlider. If it is, then you instantiate an accessible interface and return it. The object will always be an instance of classname. You must return a nullptr if the className is not supported
The last step is to include the following macro in the cpp file. The CS_PLUGIN_REGISTER macro exports the plugin in the SliderPlugin class. The argument is the name of the plugin class.
If you do not want to provide plugins for your accessibility interfaces, you can use an interface factory such as QAccessible::InterfaceFactory. This is the recommended way to provide accessible interfaces in a statically linked application.
A factory is a function pointer for a function that takes the same parameters as QAccessiblePlugin's create(), a QString and a QObject. It works the same way, you simply install the factory with the installFactory() method. The following is an example showing how to create a factory for the QAccessibleSlider interface,