Accessibility Objects and the Accessibility Hierarchy

At the heart of OS X accessibility is the accessibility object. This object represents a user-accessible element in your application, such as a button or a menu item, regardless of the application framework on which your application depends. An assistive application uses an accessibility object to make the user interface element it represents accessible to users and to manage the user’s interaction with that element.

This article describes the accessibility object as it is implemented by the Application Kit. It describes the components of accessibility objects and the hierarchy in which they are arranged. It also describes the methods to which accessibility objects can respond.

Attributes

Accessibility objects are described by a set of attributes. These attributes include the type of object, the object’s place in the accessibility hierarchy (described in “The Accessibility Hierarchy”), its value, its size and position on the display screen, and so on. In Cocoa, attributes are identified by NSString values, such as NSAccessibilityWindowAttribute and NSAccessibilityZoomButtonAttribute (see NSAccessibility Protocol Reference for the complete list of attribute names).

Each attribute has a value that provides an assistive application with information about the user interface element the accessibility object represents. For example, the value of a button’s role attribute is NSAccessibilityButtonRole and the value of its enabled attribute might be YES (if the button is enabled). In addition, many accessibility objects include a value attribute (NSAccessibilityValueAttribute) that contains the current value of a user interface object. For example, the value of a text field object is the contents of the text field and the value of a selected radio button is true.

Attribute values are always handled as objects. They must be either objects that conform to the NSAccessibility protocol or one of the following types of objects:

The NSValue objects must be created with the appropriate convenience methods, such as valueWithPoint:, to be properly recognized and transmitted to an assistive application. An attribute value can also be nil, although this causes a “No Value” error to be seen by an assistive application.

An assistive application needs to know which attributes a given accessibility object supports to be able to accurately represent the user interface object to the user. This is because an assistive application uses the values of supported attributes to manipulate the object and give the user information about it. An accessibility object returns a list of its supported attributes in the accessibilityAttributeNames method. When an assistive application needs to get the value of a specific attribute, an accessibility object returns it in the accessibilityAttributeValue: method.

Some attributes are read-only, such as the role, but others, such as a slider’s value, can be modified by the assistive application. An attribute whose value is modifiable by an assistive application is called settable. The modification of attribute values is one way an assistive application can manipulate the user interface of another application (the other way is through actions, described in “Actions”).

An accessibility object indicates that a specific attribute’s value can be modified by an assistive application by returning YES from the accessibilityIsAttributeSettable: method. An assistive application modifies the value of a specific attribute using the accessibilitySetValue:forAttribute: method.

In NSAccessibility.h, Cocoa defines a large number of constants for standard attributes, many of which are relevant to only a few classes. For example, there are a large set of attributes that are for use with objects that handle text. A few of the attributes, however, are required for every accessibility object. If you must create an accessibility object to represent a custom user interface element, you should at a minimum implement the following attributes. (See “Make Custom Classes and Subclasses Accessible” for details.)

For more information on the required and optional attributes associated with each role, see the appendix “Roles and Associated Attributes” in Accessibility Overview for OS X.

Actions

Accessibility objects can have actions associated with them. These actions are the generic actions a user can take on the user interface object the accessibility object represents. This means that accessibility actions are not context-specific. Because an assistive application is driving the user interface of your application, actions typically correspond to a single mouse click or key press. For example, a Print button supports the generic press action, not a context-specific print action. Actions are identified by NSString values, such as NSAccessibilityPressAction.

An accessibility object returns a list of its supported actions in the accessibilityActionNames method. When an assistive application needs to cause your application to perform a specific action, it sends the accessibilityPerformAction: message. When your application receives the accessibilityPerformAction: message, it performs the requested action in the same way it does when the request comes directly from the mouse or keyboard.

In NSAccessibility.h, Cocoa defines a small number of constants for standard actions. If you are creating (or extending) an accessibility object, you must restrict yourself to these actions. If you do not, an assistive application is likely to be unable to handle your custom action.

See “Supporting Actions” for details on implementing an action.

The Accessibility Hierarchy

Accessibility objects are arranged into a hierarchy that represents your application’s user interface. The application-level accessibility object (representing the NSApplication object) is at the top of the hierarchy and its first-order children are the accessibility objects that represent the main application windows and the menu bar. An assistive application can traverse the hierarchy using various attributes, primarily NSAccessibilityParentAttribute and NSAccessibilityChildrenAttribute (see “Attributes” for more information on specific attributes).

Assistive applications can also move through the hierarchy using attributes that lead to accessibility objects not related by containment. If, for example, an application displays a list of documents in one view and the contents of a selected document in another view, the application can use the NSAccessibilityLinkedUIElementsAttribute attribute to link these two views. Using the value of this attribute, an assistive application can allow a user to jump easily between the related views. Other attributes, such as NSAccessibilityMenuBarAttribute and NSAccessibilityTopLevelUIElementAttribute, provide direct, convenient access to specific objects in the application’s user interface.

The accessibility hierarchy is built into the object hierarchy that already exists in a Cocoa application. For example, the top-level NSApplication object manages a collection of windows. An assistive application accesses these windows by asking the accessibility object representing the NSApplication object for the value of its NSAccessibilityWindowsAttribute attribute. (The windows can also be obtained by requesting the value of the children attribute, but the menu bar is included in this value.) Each of these windows contains a view hierarchy wherein the window’s top view, the content view, contains any number of subviews, each of which can contain even more subviews, and so on. This hierarchy can be traversed by asking for the value of each object’s NSAccessibilityChildrenAttribute. At the bottom of the hierarchy are the objects with which the user usually interacts, such as buttons and text fields.

In some cases, however, an object needed in the Cocoa object hierarchy is not interesting to an assistive application. For example, the top-level view inside a window (the content view) is just a container for other views, which are the real objects that make up the user interface. Because a user never interacts directly with the content view itself, this implementation detail is hidden from the assistive application by marking the accessibility object representing the view as “ignored”. Therefore, when a window is asked for its children, instead of returning its content view, the window should return the content view’s children.

NSControl objects are also often hidden. An NSControl usually has a one-to-one relationship to an NSCell object, which implements the majority of the control’s behavior. In these cases, the NSControl object is ignored and the accessibility hierarchy jumps from the view that contains the control to the control’s cell. Controls that can represent more than one cell, however, such as NSMatrix or NSTableView, are not ignored.

It’s important to note that ignored accessibility objects are not excised from an application’s accessibility hierarchy; rather, they are not reported to an assistive application. An ignored object must remain in its place in the accessibility hierarchy to provide a bridge between its surrounding objects and to implement the functions and attributes needed by its children.

Figure 1 compares the view hierarchy for a window and the accessibility hierarchy for the same window. The content view and the button control (an NSButton) are ignored objects, which are in the view hierarchy but not the accessibility hierarchy. The accessibility hierarchy skips the content view and goes directly to its children and the button is replaced by the button’s cell (an NSButtonCell).

Figure 1  View hierarchy versus accessibility hierarchy
View hierarchy versus accessibility hierarchy

Objects indicate that they should be ignored by implementing the accessibilityIsIgnored method and returning YES. In fact, the default NSView implementation returns YES. To make themselves visible to an assistive application, therefore, NSView subclasses must override the accessibilityIsIgnored method and return NO. For details on working with ignored objects, see “Manipulating the Accessibility Hierarchy.”