Applications can and should be accessible to users with disabilities, and making your application accessible brings it to a wider audience. Mac†OS†X contains a suite of technologies, including the Accessibility API, for creating assistive technology solutions. With Mac OS X v10.4 Tiger, adding support for accessibility to your application is easier than ever. This two-part series of articles is intended to help you add accessibility to your Cocoa
application. This first article includes a general overview to the Accessibility model in
Mac OS X, and introduces the The Mac OS X Accessibility ModelEach release of Mac OS X has brought increased support of "Universal Access" for disabled users. Before Tiger, Apple implemented several features, such as magnification and inverting the image on the screen, and the ability to move the mouse using the keyboard. In Tiger, Apple has added VoiceOver, a full-featured screen reader and control interface. VoiceOver speaks screen activities, and provides keyboard access to every aspect of an application's user interface. VoiceOver technology doesn't just open up new doors for disabled users. It also helps parents, teachers, and anyone else who interacts or collaborates with disabled users. The devices we use to interact with computers—keyboard, mouse, and monitor—might not be available to users with disabilities. The challenge is to create a generic way to represent the user interface of any application, so that it can be presented in ways that will assist disabled users. The representation—the accessibility model—must then be communicated to an external, assistive application such as VoiceOver, which handles the presentation. Communication between your application and an assistive application is accomplished using the accessibility protocol. Specifically, the term "accessibility protocol" refers to the set of routines developers use to write an assistive application such as VoiceOver. The accessibility model, and the accessibility protocol are built into Mac OS X. Cocoa applications provide accessibility information through the Accessibility Objects and ContainmentThe mechanism by which each user interface element is represented and communicated is the accessibility object. The concept of an accessibility object is simple and generic, and again, it is built directly into Mac OS X. Each user interface element in your application—whether it is a Cocoa application or a Carbon application—is represented by an accessibility object. Accessibility objects are related in a way that roughly mirrors the parent-child hierarchy of AppKit user interface elements. For instance, take the simple example of a Cocoa application with a single window, and in that window is a single button.† For the user, it is enough to know just this much: There is a button in a window, and the button performs some application-specific task. Of course, the real story of what-object-contains-which user interface element is much more involved. Take the case of the button in a window,
described above. The real story is that there is an ![]() Figure 1: Containment Hierarchies To solve this problem, the accessibility protocol allows you to specify that certain interface elements be ignored, and therefore not be represented
by an accessibility object in an assistive application. In fact, in It is important to note that ignored interface elements are not removed from the
accessibility hierarchy. Ignored elements do not generate accessibility objects, but they do implement the Faux ElementsAs we've seen, sometimes items are ignored to present a simplified accessibility hierarchy.†However, sometimes the opposite is the case, and we want to provide an assistive application with more detail than is present in Cocoa's object model. An example of this is an A Cocoa scroll bar doesn't have separate objects for these subelements—so these "faux" elements are represented by a subclass of Figure 2 shows the faux elements reported by ![]() Figure 2: Accessibility Object AttributesAccessibility objects have attributes associated with them. The number and type of attributes an accessibility object has depends on the type of interface element it represents. An assistive application queries (and in some cases sets) the values of accessibility object attributes, and uses this information to present the interface to the user. There are a few attributes that all accessibility objects must have. Others are optional, and some depend on the presence of other attributes. This section describes some of the most common attributes. A complete list of accessibility object attributes is found in the chapter on Roles and Associated Attributes in the Accessibility Overview, located on the ADC website. The Role and Role Description AttributesOne attribute that all accessibility objects must have is the role attribute. The value of the role attribute is a nonlocalized string that
tells an assistive application the type of interface element the object represents. The accessibility object's role is roughly analogous to the class of
the interface element it represents. The role also determines the additional attributes the accessibility object contains. There are many predefined interface
element roles in Mac OS X. These predefined roles are found in the header file In addition to the role attribute, some accessibility objects also have a subrole attribute. If the role is analogous to the class of an
accessibility object, the subrole attribute is analogous to its subclass. For example, the accessibility object for a text field would have a role
attribute value of Another required attribute is the role description. Unlike the role attribute, the role description is a human-readable, localized string. An assistive
application presents this string to the user. In a screen reader application like VoiceOver, the role description string would be spoken. Role description strings
for each predefined role are retrieved using one of the two convenience functions provided in NSString *NSAccessibilityRoleDescription(NSString *role, NSString *subrole); NSString *NSAccessibilityRoleDescriptionForUIElement(id element); Note that both the role and subrole are taken into account when returning the role description. If an accessibility object does not have a subrole attribute,
pass The Description and Title AttributesWhile the role and role description attributes tell an assistive application what an element is, the description attribute tells the user what the element does. The value of the description attribute is an application-specific string that will be presented to the user. As such it must be human-readable and localized. In addition, the description string must be all lower case, and should not include the name of the role. You will see why the name of the role is not included in an example later on. A title attribute is required if the accessibility object represents an element that displays a text title. For example, the text displayed on a button is the value of its accessibility object title attribute. Elements that do not display a text title must either set the description attribute in their accessibility object, or have another control provide their title, as described in the next paragraph. A common example of this is a "back" button in a web browser application. The back button would most likely display an image of an arrow rather than text. Very often a user interface has fields where the user may enter text. These text input controls do not contain a title attribute themselves. Instead,
the title attribute is supplied by a static text control, placed in close proximity to the input field. A blind person, or a person with diminished sight
ability, would not be able to make the connection between the two controls. This is an example of a control relationship that is conceptual rather than hierarchical.
The two controls are linked to each other by the The Relationship AttributesSince they mirror the parent-child hierarchy of Cocoa user interface controls, all accessibility objects have parent and children attributes to link them together. However, we already noted that sometimes the relationship between controls is conceptual. Another example of this might be a master-detail relationship in a customer order entry system. You might have a table of customers positioned above a table of orders placed by the currently selected customer. A blind user would not be able to make the conceptual connection between these two controls. The Accessibility Object ActionsIn addition to attributes, accessibility objects can have actions associated with them. Assistive applications use these actions to control the interface on behalf of the user. An assistive application is not concerned with application-specific actions of the controls in the interface. There is no way to plan or design for every application-specific action a control might perform. Therefore, the set of accessibility object actions is small and generic. For example, your application might have a button that sorts a table of values. An assistive application is not interested in the button's sorting capability. All the assistive application cares about is that there is button, and all buttons support a press action. Action attributes also have descriptions. Action description strings are human-readable and localized, because an assistive application will present them to the user. The actions supported by accessibility objects are defined in the file NSAccessibilityActionDescription(NSString *action); An assistive application controls your application by telling an accessibility object to perform the action for the control it represents. Your application must respond in the same way it would if the request came directly from the user interface, for example by a mouse click. Note that an action is not always the way that an assistive application can control the user interface. Many times this is done not by triggering an action,
but by setting an attribute.† For example, the application's accessibility object (role Access Enabling a Cocoa ApplicationSo far we have looked at some of the general concepts of the Mac OS X accessibility model from a Cocoa perspective. The rest of Part 1 will look specifically at what you need to do to modify or enhance the default accessibility behavior in Cocoa applications. The example application we will use is called ImageMapExample, which you can download from the ADC website. ImageMapExample is a small application that contains a custom control, a segmented control, and a couple of other simple user interface elements. The custom control is an image of a food pyramid, with individual, clickable regions showing each of the food groups. The segmented control determines the highlighting mode to use as the mouse cursor rolls over the pyramid. Figure 3 shows ImageMapExample running. ![]() Figure 3: The ImageMapExample Application Setting the Segmented Control's TitleUIElement AttributeNotice the static text field with the title "ImageMap Mode Selector" in Figure 3. This text field is a specific example of the conceptual
relationship between controls, described earlier. In this case, the text field provides the title for the segmented control. To enable an assistive application
to present this relationship, you need to set the Open the ImageMapExample nib file and select the segmented control in the main window. In the inspector window, open the popup and choose Accessibility. Figure 4 shows the Inspector window with the Accessibility options selected. ![]() Figure 4: The Segmented Control's Inspector Window Setting the Since ImageMapExample already contains code to set this relationship programmatically, disconnect the Setting the attribute programmatically takes a little more work. To see how it's done, open the // set up segmented control accessibility - segmentedControl and segmentedControlTitle are outlets in the controller. id segmentedControlElement = NSAccessibilityUnignoredDescendant(segmentedControl); id segmentedControlTitleElement = NSAccessibilityUnignoredDescendant(segmentedControlTitle); [segmentedControlElement accessibilitySetOverrideValue:segmentedControlTitleElement forAttribute:NSAccessibilityTitleUIElementAttribute]; First, we must get our hands on the accessibility object for the segmented control. Recall from the discussion above, the accessibility object
hierarchy is a simplified version of the Cocoa control containment hierarchy. Every user interface element has a corresponding accessibility object,
but some Cocoa classes in the interface are not relevant to an assistive application. The accessibility objects representing these elements are ignored by
default. To get the accessibility object for the segmented control, we use the utility function The second line of code performs the same action for the static text control. To set the Setting the Segment Description AttributesThe next thing we need to do is set the description attributes for the individual parts of the segmented control. The reason for doing this is because the default descriptions are not particularly useful for telling the user what the individual segments of the control actually do. In fact, the default description is a string such as, "radio button 1 of 3." We don't want VoiceOver to sound like the Borg queen on Star Trek, so we need to change the description so that it tells the user what the control does. As we will see in part II of this article, adding a description attribute for most user interface elements is easily done in Interface Builder by selecting the user
interface element, and entering the description in the AXDescription field of the Accessibility inspector pane (shown above in Figure 4).† However, the segments of a segmented control are one of
the exceptions to the rule, so we must set the descriptions programmatically. Again, look at the SetSegmentDescriptions(segmentedControl, @"invisible hot spots", @"visible hot spots", @"rollover highlighting", nil); In this sample code, hard-coded description strings are used to keep the example simple. In your code, you should use localized strings for description attributes. The work of setting the descriptions has been factored out into the function, Again, we need to make sure we are working with the correct accessibility object. We use the id segmentElement = NSAccessibilityUnignoredDescendant(control); We need to set the description attribute for each part of the segmented control, so we must ask the control for its children. We can get an array
of child accessibility objects by asking for the segmented control's NSArray *segments = [segmentElement accessibilityAttributeValue:NSAccessibilityChildrenAttribute]; Now we simply loop over the contents of the segments array, setting the id segment; NSString *description = firstDescription; NSEnumerator *e = [segments objectEnumerator]; while ((segment = [e nextObject])) { if (description != nil) { [segment accessibilitySetOverrideValue:description forAttribute:NSAccessibilityDescriptionAttribute]; } else { // Exit loop if we run out of descriptions. break; } description = va_arg(args, id); } SummaryThis article looked at the Mac OS X accessibility model and protocol. We covered accessibility objects, and how accessibility objects are related to each other in the accessibility hierarchy. We also covered some of the basic modifications needed to fully access enable a Cocoa application. In part II, we will show you how to access enable a custom control from scratch. For More Information
Updated: 2006-10-16 |