gecko-dev/accessible/accessible-docs.html

1008 строки
48 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Implementing an MSAA Server - How Mozilla Does It, and
Practical Tips for Developers</title>
</head>
<body>
<h1>Implementing an MSAA Server</h1>
<h2>Practical Tips for Developers, and How Mozilla Does It<br>
</h2>
<h2>Contents</h2>
<div style="margin-left: 40px;">
<p>This document is for people working to support MSAA in an
application in order to make it accessible with 3rd party assistive
technologies, as well as for hackers wishing to be involved in Mozilla's
MSAA support specifically.<br>
You may also wish to read <a
href="http://www.mozilla.org/projects/ui/accessibility/vendors-win.html">Gecko
Info for Windows Accessibility Vendors</a>, a primer for vendors of 3rd
party accessibility software, on how MSAA clients can utilize Gecko's
MSAA support.</p>
<a href="#intro">1. Intro: What is MSAA</a><br>
<br>
</div>
<div style="margin-left: 40px;"><a href="#cheatsheets">2. Deciding
Which MSAA Features to Support</a><br>
<div style="margin-left: 40px;"><big></big><a href="#methods">Methods</a><br>
<a href="#events">Events</a><br>
<a href="#states">States</a><br>
<a href="#roles">Roles</a><br>
<a href="#objid">Object Identifiers</a><br>
<br>
</div>
<a href="#quirks">3. </a><a href="#quirks">MSAA's Quirks and
Workarounds</a><br>
<div style="margin-left: 40px;"><a href="#Crash_prone">MSAA can be
crash prone</a><br>
<a href="#Hacky_caret_tracking_not_working">Hacky caret tracking not
working</a><br>
<a href="#Event_window_confusion">Event window confusion</a><br>
<a href="#Confusion_with_system-generated_events">Confusion with
system-generated events</a><br>
<a href="#Hacky_caret_tracking_not_working">No unique child ID for
object in window</a><br>
<a href="#Not_all_MSAA_features_utilized_by_3rd">Not all MSAA features
utilized by 3rd party vendors</a><br>
<a href="#Missing_functionality_in_MSAA">Missing functionality in MSAA</a><br>
<a href="#Dueling_text_equivalents">Dueling text equivalents</a><br>
<a href="#Issues_with_Links">Issues with Links</a><br>
<a href="#MSAA_Implementation_is_Not_Performant">Performance Problems</a><br>
<a href="#Differing_client_implementations">Differing client
implementations</a><br>
<a href="#Undocumented_Window_Class_Usage">Undocumented Window Class
Usage</a><br>
<a href="#Vendor_quirks">Vendor quirks</a><br>
<br>
</div>
<a href="#geckoimpl">4.
Example: How Gecko and Mozilla Implement MSAA</a><br>
<div style="margin-left: 40px;"><a
href="#Creation_of_IAccessible_Objects">Creation
of IAccessible Objects</a><br>
<a
href="#The_Accessible_Tree_vs._the_DOM_Tree">The
Accessible Tree vs. the DOM Tree</a><br>
<a
href="#The_Implementations_Behind_IAccessible">The
Various Implementations of IAccessible</a><br>
<a
href="#Generating_MSAA_Events">Generating
MSAA Events</a><br>
<br>
</div>
<a href="#feedback">5. Feedback</a><br>
</div>
<h2><a name="intro"></a>1. Intro: What is MSAA?</h2>
<ul>
<p>MSAA is the <a
href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaastart_9w2t.asp?frame=true">Microsoft
Active Accessibility (MSAA) API</a> , used on Windows operating systems.
to support assistive technologies for users with disabilities. <br>
</p>
<p>Third party assistive technology, such as screen readers, screen
magnifiers and voice input software, want to track what's happening
inside Mozilla. They needs to know about focus changes and other events,
and it needs to know what objects are contained in the current document
or dialog box. Using this information, a screen reader will speak out
loud important changes to the document or UI, and allow the user to
track where they navigate. The screen reader user can navigate the web
page using screen reader commands or browser commands, and the two
pieces of software must remain in sync. Some screen readers can even
show information on a <a href="http://www.deafblind.com/display.html">refreshable
braille display</a>. Screen magnifiers will zoom to the focus, keeping
it on the screen at all times, or even allow the user to enter a special
low vision document reading mode, with a variety of features such as
ticker mode where text is streamed on a single line.&nbsp; Finally,
voice dictation software needs to know what's in the current document or
UI in order to implement "say what you see" kinds of features.<br>
<br>
On Microsoft Windows, these kinds of assistive technology acquire this
necessary information via a combination of&nbsp; hacks, MSAA and
proprietary DOMs. MSAA is supposed to be the "right way" for
accessibility aids to get information, but sometimes the hacks are more
effective. For example, screen readers look for screen draws of a
vertical blinking line, to determine the location of the caret. Without
doing this, screen readers would not be able to let the user know where
there caret has moved to in most programs, because so many applications
do not use the system caret (Gecko does not). This is so commonly done,
that no one even bothers to support the MSAA caret, after all the hack
is general solution works with pretty much all applications.</p>
<p>MSAA provides information in several different ways: </p>
<ol>
<li>A COM interface (IAccessible) that allows applications to
expose the tree of data nodes that make up each window in the user
interface currently being interacted with and</li>
<li>Custom interface extensions via interfaces via QueryInterface
and QueryService. This can provide assistive technology with contextual
information specific to your object model. For example, Gecko support
ISimpleDOMNode to provide information about the DOM node for an
accessible object.<br>
</li>
<li>A set of system messages that confer accessibility-related
events such as focus changes, changes to document content and state
changes in UI objects like checkboxes.<br>
</li>
</ol>
<p></p>
<p> To really learn about MSAA, you need to download the entire <a
href="http://msdn.microsoft.com/library/default.asp?URL=/downloads/list/accessibility.asp">MSAA
SDK</a>. Without downloading the SDK, you won't get the extremely
useful tools, which help a great deal in the learning process. The
Accessible Event Watcher shows what accessible events are being
generated by a given piece of software. The Accessible Explorer and
Inspect Object tools show the tree of data nodes the Accessible object
is exposing through COM, and what the screen boundaries of each object
are. In addition, MSDN has improved their <a
href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaastart_9w2t.asp">MSAA
documentation</a>.<br>
</p>
</ul>
<h2><a name="cheatsheets"></a>2. Deciding Which MSAA Features to Support<br>
</h2>
<h2 style="margin-left: 40px;"><a name="methods"></a>MSAA Methods -
Cheat Sheet for Developers</h2>
<div style="margin-left: 40px;"> </div>
<ul style="margin-left: 40px;">
<p> The IAccessible interface is used in a tree of IAccessible's, each
one representing a data node, similar to a DOM. </p>
<p> Here are the methods supported in IAccessible - a minimal
implementation would contain those marked "<span
style="font-weight: bold;">[important]</span>" :<br>
</p>
<ul>
<li>get_accParent: Get the parent of an IAccessible. <span
style="font-weight: bold;">[important]</span><br>
</li>
<li>get_accChildCount: Get the number of children of an
IAccessible. <span style="font-weight: bold;">[important]</span></li>
<li>get_accChild: Get the child of an IAccessible. <span
style="font-weight: bold;">[important]</span></li>
<li>get_accName: Get the "name" of the IAccessible, for example the
name of a button, checkbox or menu item. <span
style="font-weight: bold;">[important]</span></li>
<li>get_accValue: Get the "value" of the IAccessible, for example a
number in a slider, a URL for a link, the text a user entered in a
field. <span style="font-weight: bold;">[important]</span></li>
<li>get_accDescription: Get a long description of the current
IAccessible. This is not really too useful.</li>
<li>get_accRole: Get an enumerated value representing what this
IAccessible is used for, for example. <br>
</li>
is it a link, static text, editable text, a checkbox, or a table
cell, etc. <span style="font-weight: bold;">[important]</span><span
style="font-weight: bold;"></span><li>get_accState: a 32 bit field
representing possible on/off states, such as focused, focusable,
selected, selectable, visible, protected (for passwords), checked, etc. <span
style="font-weight: bold;">[important]</span> </li>
<li>get_accHelp: Get context sensitive help for the IAccessible.</li>
<li>get_accHelpTopic: We don't use this, it's only if the Windows
help system is used.</li>
<li>get_accKeyboardShortcut: What is the keyboard shortcut for this
IAccessible (underlined alt+combo mnemonic)<br>
</li>
<li>get_accFocus: Which child is focused? <span
style="font-weight: bold;">[important]</span></li>
<li>get_accSelection: Which children of this item are selected?</li>
<li>get_accDefaultAction: Get a description or name of the default
action for this component, such as "jump" for links.</li>
<li>accSelect: Select the item associated with this IAccessible. <span
style="font-weight: bold;">[important]</span></li>
<li>accLocation: Get the x,y coordinates, and the height and width
of this IAccessible node. <span style="font-weight: bold;">[important]<br>
</span></li>
<li>accNavigate: Navigate to the first/last child, previous/next
sibling, up, down, left or right from this IAccessible. <span
style="font-weight: bold;">[important, </span><span
style="font-weight: bold;">but no need to implement up/down/left/right</span><span
style="font-weight: bold;">]</span></li>
<li>accHitTest: Find out what IAccessible exists and a specific
coordinate.</li>
<li>accDoDefaultAction: Perform the action described by
get_accDefaultAction.</li>
<li>put_accName: Change the name.</li>
<li>put_accValue: Change the value.</li>
</ul>
</ul>
<div style="margin-left: 40px;"> </div>
<h2 style="margin-left: 40px;"><a name="events"></a>MSAA Events Cheat
Sheet<br>
</h2>
<div style="margin-left: 40px;"> </div>
<ul style="margin-left: 40px;">
<p>For information on what each event does, see the <a
href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaaccrf_7jlf.asp">MSDN
Event Constants page</a>.</p>
<p>Check with your assistive technology partners to find out what
events you need to support. There's a very good chance they won't ask
for more than the events marked <span style="font-weight: bold;">[important]</span>:<br>
</p>
</ul>
<div style="margin-left: 40px;"> </div>
<table
style="text-align: left; width: 75%; margin-right: auto; margin-left: auto;"
border="0" cellspacing="2" cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">EVENT_SYSTEM_SOUND<br>
EVENT_SYSTEM_ALERT<br>
EVENT_SYSTEM_FOREGROUND<br>
EVENT_SYSTEM_MENUSTART<br>
EVENT_SYSTEM_MENUEND<br>
EVENT_SYSTEM_MENUPOPUPSTART <span style="font-weight: bold;">[important]</span><br>
EVENT_SYSTEM_MENUPOPUPEND <span style="font-weight: bold;">[important]</span><br>
EVENT_SYSTEM_CAPTURESTART<br>
EVENT_SYSTEM_CAPTUREEND<br>
EVENT_SYSTEM_MOVESIZESTART<br>
EVENT_SYSTEM_MOVESIZEEND<br>
EVENT_SYSTEM_CONTEXTHELPSTART<br>
EVENT_SYSTEM_CONTEXTHELPEND<br>
EVENT_SYSTEM_DRAGDROPSTART<br>
EVENT_SYSTEM_DRAGDROPEND<br>
EVENT_SYSTEM_DIALOGSTART<br>
EVENT_SYSTEM_DIALOGEND<br>
EVENT_SYSTEM_SCROLLINGSTART<br>
EVENT_SYSTEM_SCROLLINGEND <span style="font-weight: bold;">[possibly
important, talk to AT vendor]</span><br>
EVENT_SYSTEM_SWITCHSTART<br>
EVENT_SYSTEM_SWITCHEND<br>
EVENT_SYSTEM_MINIMIZESTART<br>
EVENT_SYSTEM_MINIMIZEEND<br>
</td>
<td style="vertical-align: top;">EVENT_OBJECT_CREATE <span
style="font-weight: bold;">[don't implement, watching system generated
versions of this event causes </span><span style="font-weight: bold;">assistive
technology </span><span style="font-weight: bold;">crashes]</span><br>
EVENT_OBJECT_DESTROY <span style="font-weight: bold;">[don't
implement, watching system generated versions of this event causes
assistive technology crashes]</span><br>
EVENT_OBJECT_SHOW<br>
EVENT_OBJECT_HIDE<br>
EVENT_OBJECT_REORDER <span style="font-weight: bold;">[important for
mutating docs in future, but not yet]</span><br>
EVENT_OBJECT_FOCUS <span style="font-weight: bold;">[important]</span><br>
EVENT_OBJECT_SELECTION<br>
EVENT_OBJECT_SELECTIONADD<br>
EVENT_OBJECT_SELECTIONREMOVE<br>
EVENT_OBJECT_SELECTIONWITHIN<br>
EVENT_OBJECT_STATECHANGE <span style="font-weight: bold;">[important
for checkboxes and radio buttons]</span><br>
EVENT_OBJECT_LOCATIONCHANGE<br>
EVENT_OBJECT_NAMECHANGE<br>
EVENT_OBJECT_DESCRIPTIONCHANGE<br>
EVENT_OBJECT_VALUECHANGE<br>
EVENT_OBJECT_PARENTCHANGE<br>
EVENT_OBJECT_HELPCHANGE<br>
EVENT_OBJECT_DEFACTIONCHANGE<br>
EVENT_OBJECT_ACCELERATORCHANGE<br>
</td>
</tr>
</tbody>
</table>
<div style="margin-left: 40px;"> </div>
<h2 style="margin-left: 40px;"><a name="states"></a>MSAA States Cheat
Sheet<br>
</h2>
<div style="margin-left: 40px;"> </div>
<ul style="margin-left: 40px;">
<p>For information on what each state does, see the <a
href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaaccrf_7jlf.asp">MSDN
State Constants page</a>.</p>
<p>Check with your assistive technology partners to find out what
states you need to support. There's a very good chance they won't ask
for more than the states marked <span style="font-weight: bold;">[important]</span>:</p>
</ul>
<div style="margin-left: 40px;"></div>
<table
style="text-align: left; width: 75%; margin-right: auto; margin-left: auto;"
border="0" cellspacing="2" cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">STATE_UNAVAILABLE <span
style="font-weight: bold;">[important]</span><br>
STATE_SELECTED <span style="font-weight: bold;">[important]</span><br>
STATE_FOCUSED <span style="font-weight: bold;">[important]</span><br>
STATE_PRESSED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
STATE_CHECKED <span style="font-weight: bold;">[important]</span><br>
STATE_MIXED<br>
STATE_READONLY <span style="font-weight: bold;">[important]</span><br>
STATE_HOTTRACKED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>
STATE_DEFAULT <span style="font-weight: bold;">[important]</span><br>
STATE_EXPANDED <span style="font-weight: bold;">[important]</span><br>
STATE_COLLAPSED <span style="font-weight: bold;">[important]</span><br>
STATE_BUSY <span style="font-weight: bold;">[important]</span><br>
STATE_FLOATING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
STATE_MARQUEED&nbsp; <br>
STATE_ANIMATED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>
STATE_INVISIBLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>
<br>
</td>
<td style="vertical-align: top;">STATE_OFFSCREEN <span
style="font-weight: bold;">[important]</span><br>
STATE_SIZEABLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
STATE_MOVEABLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
STATE_SELFVOICING&nbsp;&nbsp; &nbsp;<br>
STATE_FOCUSABLE <span style="font-weight: bold;">[important]</span><br>
STATE_SELECTABLE <span style="font-weight: bold;">[important]</span><br>
STATE_LINKED <span style="font-weight: bold;">[important]</span><br>
STATE_TRAVERSED <span style="font-weight: bold;">[important]</span><br>
STATE_MULTISELECTABLE <span style="font-weight: bold;">[important]</span><br>
STATE_EXTSELECTABLE &nbsp;<br>
STATE_ALERT_LOW&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
STATE_ALERT_MEDIUM&nbsp; &nbsp;<br>
STATE_ALERT_HIGH&nbsp;&nbsp;&nbsp; &nbsp;<br>
STATE_PROTECTED <span style="font-weight: bold;">[important]</span><br>
STATE_HASPOPUP <br>
</td>
</tr>
</tbody>
</table>
<h2 style="margin-left: 40px;"><a name="roles"></a>MSAA Roles Cheat
Sheet<br>
</h2>
<div style="margin-left: 40px;"> </div>
<ul style="margin-left: 40px;">
<p>For information on what each role does, see the <a
href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaaccrf_7jlf.asp">MSDN
Role Constants page</a>.</p>
<p>Check with your assistive technology partners to find out what
roles you need to support. There's a very good chance they won't ask for
more than the roles marked <span style="font-weight: bold;">[important]</span>:<br>
There is no need to support the objects marked <span
style="font-weight: bold;">[inserted by system]. </span>Windows will
add those objects to your hierarchy for you.<br>
</p>
</ul>
<div style="margin-left: 40px;"> </div>
<table
style="text-align: left; width: 75%; margin-right: auto; margin-left: auto;"
border="0" cellspacing="2" cellpadding="2">
<tbody>
<tr>
<td style="vertical-align: top;">ROLE_TITLEBAR <span
style="font-weight: bold;">[inserted by system]</span><br>
ROLE_MENUBAR <span style="font-weight: bold;">[important if you don't
use native menus]</span><br>
ROLE_SCROLLBAR<br>
ROLE_GRIP<br>
ROLE_SOUND<br>
ROLE_CURSOR<br>
ROLE_CARET<br>
ROLE_ALERT<br>
ROLE_WINDOW <span style="font-weight: bold;">[inserted by system]</span><br>
ROLE_CLIENT <span style="font-weight: bold;">[important]</span><br>
ROLE_MENUPOPUP <span style="font-weight: bold;">[important]</span><br>
ROLE_MENUITEM <span style="font-weight: bold;">[important]</span><br>
ROLE_TOOLTIP<br>
ROLE_APPLICATION<br>
ROLE_DOCUMENT<br>
ROLE_PANE <span style="font-weight: bold;">[important]</span><br>
ROLE_CHART<br>
ROLE_DIALOG<br>
ROLE_BORDER<br>
ROLE_GROUPING<br>
ROLE_SEPARATOR <span style="font-weight: bold;">[important]</span><br>
ROLE_TOOLBAR<br>
ROLE_STATUSBAR <span style="font-weight: bold;">[important]</span><br>
ROLE_TABLE <span style="font-weight: bold;">[important]</span><br>
ROLE_COLUMNHEADER<br>
ROLE_ROWHEADER<br>
ROLE_COLUMN<br>
ROLE_ROW<br>
ROLE_CELL <span style="font-weight: bold;">[important]</span><br>
ROLE_LINK <span style="font-weight: bold;">[important]</span><br>
ROLE_HELPBALLOON<br>
ROLE_CHARACTER<br>
</td>
<td style="vertical-align: top;">ROLE_LIST <span
style="font-weight: bold;">[important]</span><br>
ROLE_LISTITEM <span style="font-weight: bold;">[important]</span><br>
ROLE_OUTLINE <span style="font-weight: bold;">[important]</span><br>
ROLE_OUTLINEITEM <span style="font-weight: bold;">[important]</span><br>
ROLE_PAGETAB <span style="font-weight: bold;">[important]</span><br>
ROLE_PROPERTYPAGE <span style="font-weight: bold;">[important]</span><br>
ROLE_INDICATOR<br>
ROLE_GRAPHIC <span style="font-weight: bold;">[important]</span><br>
ROLE_STATICTEXT <span style="font-weight: bold;">[important]</span><br>
ROLE_TEXT <span style="font-weight: bold;">[important]</span><br>
ROLE_PUSHBUTTON <span style="font-weight: bold;">[important]</span><br>
ROLE_CHECKBUTTON <span style="font-weight: bold;">[important]</span><br>
ROLE_RADIOBUTTON <span style="font-weight: bold;">[important]</span><br>
ROLE_COMBOBOX <span style="font-weight: bold;">[important]</span><br>
ROLE_DROPLIST <span style="font-weight: bold;">[important]</span><br>
ROLE_PROGRESSBAR <span style="font-weight: bold;">[important]</span><br>
ROLE_DIAL<br>
ROLE_HOTKEYFIELD<br>
ROLE_SLIDER<br>
ROLE_SPINBUTTON<br>
ROLE_DIAGRAM<br>
ROLE_ANIMATION<br>
ROLE_EQUATION<br>
ROLE_BUTTONDROPDOWN<br>
ROLE_BUTTONMENU<br>
ROLE_BUTTONDROPDOWNGRID<br>
ROLE_WHITESPACE<br>
ROLE_PAGETABLIST <span style="font-weight: bold;">[important]</span><br>
ROLE_CLOCK<br>
ROLE_SPLITBUTTON<br>
ROLE_IPADDRESS<br>
ROLE_NOTHING<br>
<br>
</td>
</tr>
</tbody>
</table>
<div style="margin-left: 40px;"></div>
<h2 style="margin-left: 40px;"><a name="objid"></a>MSAA Object
Identifiers Cheat Sheet<br>
</h2>
<div style="margin-left: 40px;"> </div>
<p style="margin-left: 80px;">For information on what each object
identifier does, see the <a
href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaaccrf_7jlf.asp">MSDN
Object Identifiers Constants page</a>.</p>
<div style="margin-left: 80px;">Check with <big><big></big></big>our
assistive technology partners to find out what object identifiers you
need to support. There's a very good chance they won't ask for more than
the object itentifiers marked <span style="font-weight: bold;">[important]</span>:<br>
</div>
<dl style="margin-left: 120px;">
<dt>OBJID_ALERT<br>
OBJID_CARET<br>
OBJID_CLIENT <span style="font-weight: bold;">[important]</span><br>
OBJID_CURSOR<br>
OBJID_HSCROLL<br>
OBJID_NATIVEOM <span style="font-weight: bold;">[important? might be
useful for supporting custom interfaces, need to research]</span><br>
OBJID_MENU<br>
OBJID_QUERYCLASSNAMEIDX<br>
OBJID_SIZEGRIP<br>
OBJID_SOUND<br>
OBJID_SYSMENU<br>
OBJID_TITLEBAR<br>
OBJID_VSCROLL<br>
OBJID_WINDOW<br>
</dt>
</dl>
<h2><a name="quirks"></a>3. Dealing with the Quirks of MSAA</h2>
<div style="margin-left: 40px;"> </div>
<p style="margin-left: 40px;">MSAA has a well deseved reputation for
quirkiness. It is not "plug and play", and will take a lot of
testing/refinement before your solution works with any product. Here are
some of its quirks and some solutions/workarounds:<br>
</p>
<div style="margin-left: 40px;"><big><a name="Crash_prone"></a>MSAA can
be crash prone</big><br>
</div>
<div style="margin-left: 80px;"><br>
<span style="text-decoration: underline;">Problem</span>: Many of
MSAA's crash occur because more than one process is refcounting the same
objects, and because pointers are being shared between processes. When
your application closes, different signals are typically broadcast. For
example, the application window closes and the window is blurred. It is
impossible to know if and when the 3rd party assistive technology will
use one of these signals to release the objects of yours that is is
refcounting. This can lead to crashes where it releases something and
the wrong time, when some of your dll's are unloaded but not others,
and a destructor is called in an unloaded DLL.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: Create a
"shutdown" method for each internal accessible object, to remove any
references to other internal objects before any of your dll's are
unloaded. In order to do this effectively, you will have to keep track
of every accessible object that you create. The shutdown method for an
accessibility object should be called whenever the document or UI object
it refers to goes away. The easiest way to do that is to keep a pointer
to an accessible in each internal UI object. If that pointer is
non-null, then there is an accessible object for it. Whenever the UI
object is destroyed, shutdown its accessible object as well. In
Gecko/Mozilla we are not allowed to keep this extra pointer for each
accessible object, so when accessibility is turned on we use a hash
table to cache these objects. Such a cache must be kept in perfect sync
with the tree of UI and document objects, which is difficult. Therefore,
unless 4 bytes extra on each object is criticial in your application,
just keep the extra pointer around instead of using a hash table.<br>
<br>
Also, don't implement EVENT_OBJECT_CREATE or EVENT_OBJECT_DESTROY.
Vendors have found that watching these events causes crashes.<br>
<br>
</div>
<div style="margin-left: 40px;"><big><a
name="Hacky_caret_tracking_not_working"></a>Hacky caret tracking
causes problems<br>
</big></div>
<div style="margin-left: 80px;"><br>
<span style="text-decoration: underline;">Problem</span>: Assistive
technologies do not use the MSAA caret. They follow screen draws,
looking for a vertical blinking line. Unfortunately, some products can
get confused by the vertical lines on other objects, such as list boxes,
even though those lines are not blinking. The assistive technology may
not see your caret at all.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: Make sure
there is a configuration file for each assistive technology specific to
your application. Read the manual or help, and find the keystroke or
commands for training the caret, and save this information in the
configuration file. Don't support the MSAA caret, none of the vendors
use it.<br>
<br>
</div>
<div style="margin-left: 40px;"> <big><a name="Event_window_confusion"></a>Event
window handle is incorrect</big><br>
<br>
<div style="margin-left: 40px;"><span
style="text-decoration: underline;">Problem</span>: The screen reader
or other assistive technology does not track the focus or other events
correctly.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: This may be
because you are reporting that the events in a different window from the
current system focused. The assistive technology may be asking
GetGUIThreadInfo for its hwndFocus, and throwing away MSAA events that
are not in the currently focused window. Even if you are visibly showing
window focus on the correct window, you must also tell the operating
system to focus this window before any other accessibility events get
fired in it. </div>
<br>
<big><a name="Confusion_with_system-generated_events"></a>Confusion
with system-generated events</big><br>
<br>
<div style="margin-left: 40px;"> <span
style="text-decoration: underline;">Problem</span>: When you test with
Accessible Event Watcher in the MSAA SDK, you will see many events that
your application did not generate. Microsoft Windows generates some
events for you. This is extremely annoying. The assistive technology has
no way to tell whether the event came from your application or from
Windows. For example, when you set window focus, Windows will generate
an EVENT_OBJECT_FOCUS event an a ROLE_WINDOW object it also generated
for you. If you happen to set window focus after you fired your own
EVENT_OBJECT_FOCUS event on an object in the widnow, your event will be
ignored, because assistive technology software tends to pay attention
only to the last focus event.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: When an
object is about to get focused in a different window, make sure you
focus a window before you fire your own focus events for objects inside
it. Test using Accessible Event Watcher in the MSAA SDK, and use the
settings panel to watch subsets of accessibility events. Count on the
assistive technology to make sense out the jumble of extra
system-generated events, it's not your problem.<br>
</div>
<br>
<big><a name="No_unique_child_ID_for_object_in_window"></a>No unique
child ID for event target in window</big><br>
<br>
<div style="margin-left: 40px;"> <span
style="text-decoration: underline;">Problem</span>: MSAA expects
events to be reported using NotifyWinEvent(eventNum, hWnd, worldID,
childID), and there may not be an obvious way to get a window handle and
a 32 bit childID for an object. You may be using windowless controls, or
have an entire document with lots of objects in a given window. The
child ID must be unique, because this is what the assistive technology
will use to retrieve the accessible via AccessibleObjectFromEvent()
which ends up using get_accChild on the accessible for the given window.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: In
Gecko/Mozilla, we did not want to store an extra 32 bit unique ID value
on every object. Instead, we hand back a 32 bit value derived from the
UI object's pointer, which is unique. We ensure that the value we hand
back is always negative. When the get_accChild call comes back, we check
our hash table cache for that window to see if there's an accessible
object still associated with that unique value. This means the client
must use AccessibleObjectFromEvent immediately, because there is a
danger that the object will go away, and another different object will
be created with the same pointer value.That case seems extremely remote,
because information from events is generally retrieved right after the
event.<br>
<br>
If you're not using a hash table to keep track of unique ID's, store
the child ID's and objects for the last 50 or so events in a circular
array. In practice, this is enough to keep AccessibleObjectFromEvent()
happy.<br>
</div>
<br>
<big><a name="Not_all_MSAA_features_utilized_by_3rd"></a>Not all MSAA
features utilized by 3rd party vendors</big><br>
<br>
<div style="margin-left: 40px;"> <span
style="text-decoration: underline;">Problem</span>: The assistive
technology does not use 50% of what's available in MSAA, e.g. MSAA
caret, a lot of events, roles, states and methods. It's difficult to
know which things to support.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: Use this
document to see what is generally considered important by assistive
technology manufacturers. Contact the the top vendors early and often as
you plan and implement your architecture, to see what's important to
them. Implement only what's needed -- supporting everything would take
too long for zero results.<br>
</div>
<br>
<big><a name="Missing_functionality_in_MSAA"></a>Missing functionality
in MSAA</big><br>
<br>
<div style="margin-left: 40px;"><span
style="text-decoration: underline;">Problem and solutions:</span>
Assistive technology vendors need some things which MSAA does not
provide, such as:<br>
</div>
</div>
<ul style="margin-left: 40px;">
<ul>
<li>No way of signifying that a document has finished
loading.&nbsp; Fire EVENT_OBJECT_STATECHANGE for a window/client/pane
object when it starts to load a new document. Use STATE_BUSY to indicate
that a new document is being loaded. When the loading has finished, fire
another EVENT_OBJECT_STATECHANGE event and clear the STATE_BUSY
flag.&nbsp; </li>
<li>No method to get clipped/unclipped bounds of a piece of text
within a text object. This is needed by screen magnifiers. No scrollTo
method, also needed by screen magnifiers. Implement a custom interface
for text objects, and support it through QueryInterface or QueryService
if it's being implemented on a different object than IAccessible is.
Support a scrollTo method which takes a text index, and a
getClippedBounds and getUnclippedBounds method which takes a start and
end index. Publish your custom interface.</li>
<li>No way for assistive technology to know when scrolling has
stopped. Fire the EVENT_SYSTEM_SCROLLINGEND event to indicate when
scrolling has ended (try not to fire too many of these, wait until
scrolling has truly stopped). There is no need to support
EVENT_SYSTEM_SCROLLINGSTART, it is not used by assistive technology.<br>
</li>
</ul>
<ul>
<li>No support for document formatting or "DOM" as requested by
some vendors: support a custom interface that gives them the formatting
information they are requesting.<br>
</li>
</ul>
</ul>
<div style="margin-left: 40px;"><big><a name="Dueling_text_equivalents"></a>Dueling
text equivalents</big><br>
<br>
<div style="margin-left: 40px;"><span
style="text-decoration: underline;"> Problem</span>: There are three
kinds of text equivalents, and it is difficult to know when to use each.
Different applications behave differently in this regard. For example,
Acrobat uses accessible value for text labels where as most programs use
accessible name. There are different roles for text objects,
ROLE_STATICTEXT and ROLE_TEXT (editable text), which seems to be used
for non-editable text in many places.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: Be as
consistent with Internet Explorer as possible. Use accessible name for
most text equivalents, and accessible value for URL's. Don't use
accessible description unless you really do have a long description for
the object you need to expose -- most assistive technology makes little
use of it. Use ROLE_STATICTEXT for labels specific to dialog and UI
controls, and always use ROLE_TEXT for document text even if the text is
not editable (in that case use ROLE_TEXT with STATE_READONLY).<br>
</div>
<br>
<big><a name="Issues_with_Links"></a>Issues with Links</big><br>
<br>
<div style="margin-left: 40px;"> <span
style="text-decoration: underline;">Problem</span>: The assistive
technology has inflexible heuristics when it comes to reading links.
First, it won't read the object unless the states are correctly set.
Second, it can mishandle the object if it cannot parse the whitespace
according to its own rules.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: Make sure
the ROLE_LINK object and its child ROLE_TEXT objects all have
STATE_LINKED set. For multi-line links with a line break in the middle,
make sure there is no whitespace at the beginning or end of any of the
accessible names, and make sure there is a \r\n where the line breaks
occur in the accessible name for the ROLE_LINK. For an example of how to
do this properly, see Internet Explorer or Gecko. Again, if it's not
done exactly this way, some links will not be read.<br>
</div>
<br>
<big><a name="MSAA_Implementation_is_Not_Performant"></a>MSAA
Implementation is Not Performant</big><br>
<br>
<div style="margin-left: 40px;"><span
style="text-decoration: underline;"> Problem</span>: The assistive
technology may interact slowly with your application.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: Try not to
calculate the same things more than once or create the same objects more
than once. For example, create and cache an object's children when you
look for them in get_accChildCount(), so that you can just hand them
back when asked for using get_accChild() or accNavigate(). Support
IEnumVARIANT so that the MSAA client can ask for a number of children in
one call. In custom interfaces, create methods that hand back a lot of
data in one call, rather than requiring a large number of calls. Fewer
calls are much better better because COM Marshaling is slow.<br>
</div>
<br>
<big><a name="Differing_client_implementations"></a>Differing client
implementations</big><br>
<br>
<div style="margin-left: 40px;"> <span
style="text-decoration: underline;">Problem</span>: Every assistive
technology uses MSAA differently.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: We don't
know of any outright conflicts in the differing uses of MSAA (yet).
However, be on guard. If a vendors asks you to do something different
from the spec, it's better to check with the other vendors before moving
forward. Check to see what applications from Microsoft do in a similar
situation.<br>
</div>
<br>
<big><a name="Undocumented_Window_Class_Usage"></a>Undocumented Window
Class Usage</big><br>
<br>
<div style="margin-left: 40px;"> <span
style="text-decoration: underline;">Problem</span>: most assistive
technologies won't use your MSAA implementation out of the box. They
must list your window classes somewhere in their implementation, and
then turn on MSAA support when a window of that class receives focus.
The window class is also used to determine a host of hard-coded
behaviors, such as whether or not a screen reader will load the entire
MSAA tree into a special buffer for the user to navigate with screen
reader commands. This is only supposed to occur for document navigation,
not for UI/dialogs. where your application's keyboard commands will be
solely used to navigate.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: Contact each
vendor and let them know what window classes you will be using MSAA for.
If possible, use a different window class name for documents/content
than you use for UI/dialogs. Or, do what Mozilla does&nbsp; - expose a
control ID (GWL_ID) of 1 for content, and 0 for UI. Consistent window
class names are important for the assistive technology vendors, so that
they can determine what code to run for a given window. Don't change
window class names after you have shipped a version.<br>
</div>
<br>
<big><a name="Vendor_quirks"></a>Vendor quirks</big><br>
<br>
<div style="margin-left: 40px;"> <span
style="text-decoration: underline;">Problem</span>: Because assistive
technology tends to utilize MSAA as an additional solution resting on
top of old hacks, rather than a completely clean and separate way to
deal with an application, and because of the quirky nature of MSAA and
of the inflexible heuristics that screen readers use, we do not have a
"plug and play solution". In addition, assistive technology vendors are
tiny companies, often scrambling to keep up with changes in the
applications they already support, or new products other than yours
which they need to support. It's very difficult to get vendors to spend
time testing an MSAA implementation, send feedback or help find out why
things aren't working. Time and version commitments often fall through.
There is always a belated new version due around corner, after which you
will be promised to be the next priority.<br>
<br>
<span style="text-decoration: underline;">Solution</span>: Try to reach
out in a friendly manner to the assistive technology company. Be as easy
to work with as you possibly can -- this includes being extremely
responsive to their bug reports with new test builds, as well as being
very communicative about what you have changed and when. Do as much work
as you possibly can without their help. See if your organization can
offer something they can't get for themselves. Be patient, and set your
expectations to a reasonable level. Realize that it's about both pride
and revenue for these companies, and that they need to sell a lot of
copies of their software to make up the work they put in to support
your app. Remember that no matter how small they are, you need them more
than they need you, unless your application's accessibility is being
demanded by end-users.</div>
</div>
<h2><a name="geckoimpl"></a>4. Example: How Gecko and Mozilla Implement
MSAA<br>
</h2>
<p style="margin-left: 40px;">The <a
href="http://lxr.mozilla.org/seamonkey/source/accessible/">Accessible
module</a> is where the Mozilla MSAA implementation lives. Feel free to <a
href="http://lxr.mozilla.org/seamonkey/source/accessible/">peruse the
source code in the accessible module</a> whenever you want to see how
something can be implemented.<br>
</p>
<p style="margin-left: 40px;">The accessible module is also where
support for Sun's <a
href="http://wwws.sun.com/software/star/gnome/accessibility/architecture.html">ATK</a>
accessibility API for Linux and UNIX is implemented. For documentation
specific to the Mozilla ATK effort, supported by Sun Microsystems, see
the <a
href="http://www.mozilla.org/projects/ui/accessibility/unix/index.html">Mozilla
accessibility on Unix</a> page.</p>
<h3 style="margin-left: 40px;"><a name="Creation_of_IAccessible_Objects"></a>Creation
of IAccessible Objects<br>
</h3>
<ul style="margin-left: 40px;">
<p> The first thing that happens when an assistive technology wants to
watch our application is that calls the Windows API function
AccessibleObjectFromWindow(). This usually happens right after a window
gets focused.<br>
</p>
<p>When the WIN32 API function AccessibleObjectFromWindow() is
called, Windows sends the window in question a <a
href="http://lxr.mozilla.org/seamonkey/search?string=WM_GETOBJECT">WM_GETOBJECT</a>
message requesting an IAccessible for your root object in the window. In
our case, this event is received in <a
href="http://lxr.mozilla.org/mozilla-central/source/widget/windows/nsWindow.cpp#4370">mozilla/widget/windows/nsWindow.cpp</a>.
We send back an IAccessible pointer which can be used by the client to
get information about this root object. The assistive technology will
use that root IAccessible to traverse the rest of the object tree, by
navigating to children and then siblings, etc. Every navigation function
such as accNavigate(), get_accChild() and get_accParent() returns an
IAccessible pointer. <br>
</p>
<p>To create the root IAccessible for a window the first time it gets
the <a
href="http://lxr.mozilla.org/seamonkey/search?string=WM_GETOBJECT">WM_GETOBJECT</a>
message in, nsWindow.cpp first generates an internal event called <a
href="http://lxr.mozilla.org/seamonkey/search?string=NS_GETACCESSIBLE">NS_GETACCESSIBLE</a>,
which is handled in <a
href="http://lxr.mozilla.org/seamonkey/source/layout/html/base/src/nsPresShell.cpp#6345">PresShell::HandleEventInternal()</a>
via the creation of an <a
href="http://lxr.mozilla.org/seamonkey/find?string=msaa/nsDocAccessibleWrap">nsDocAccessibleWrap</a>
for an inner window or <a
href="http://lxr.mozilla.org/seamonkey/find?string=msaa/nsRootAccessibleWrap">nsRootAccessibleWrap</a>
for a top level window. These classes implement both nsIAccessible, our
cross platform API, as well as IAccessible, which is specific to
Windows/MSAA/COM. The cross-platform nsDocAccessible and
nsRootAccessible classes they inherit from are then told to start
listening for DOM, page load and scroll events.&nbsp; These events cause
MSAA-specific events, such as EVENT_OBJECT_FOCUS or
EVENT_OBJECT_STATECHANGE, to fire on UI and document objects within the
applicable window. We'll explain more about events later in this section.<br>
</p>
<p>Until the WM_GETOBJECT message is processed, the Gecko
accessibility service is not used, and thus the accessibility.dll is not
loaded, so there is almost zero overhead for accessibility API support
in Mozilla or Gecko, in the general case. Once the accessibility
service is created, however, Gecko loads code to create an object on
demand for every UI or document object that should support IAccessible.
The created objects are cached in a hash table, and shutdown when
they're no longer needed. They may still exist in memory in a
nonfunctional state until the assistive technology completely releases
them. See the section on accessible roles to see what kinds of objects
Gecko support IAccessible for.<br>
</p>
</ul>
<div style="margin-left: 40px;"> </div>
<h3 style="margin-left: 40px;"><a
name="The_Accessible_Tree_vs._the_DOM_Tree"></a>The Accessible Tree
vs. the DOM Tree<br>
</h3>
<div style="margin-left: 40px;"> </div>
<ul style="margin-left: 40px;">
<p>After the root or doc accessible for a window has been created and
handed back to the MSAA client, it is used to traverse the rest of the
IAccessible tree using accNavigation, get_accChild and get_accParent.
Any IAccessible will support those methods. We also support
IEnumVARIANT::Next() which allows for fast marshaling of all of an
objects children to a client via COM. In other words, the assistive
technology can say "give me all 20 children of this object into this
array". That's much faster than 20 separate calls, one for each child.<br>
</p>
<p>In Mozilla, the client has another choice for tree navigation --
it can utilize data stored in the DOM via Mozilla's custom <a
href="http://lxr.mozilla.org/seamonkey/source/accessible/public/msaa/ISimpleDOMNode.idl">ISimpleDOMNode</a>
COM interface. Any IAccessible can be used to QueryInterface to an
ISimpleDOMNode, and vice versa for a round trip. However, one might QI
ISimpleDOMNode to IAccessible only to find it is null, which means that
particular node in question is not exposed in the IAccessible tree. See
the following diagram for examples of nodes that do no support
IAccessible.<br>
</p>
</ul>
<div style="margin-left: 40px;"> </div>
<h3 style="margin-left: 40px;">MSAA tree vs. DOM tree - what's the
relationship?</h3>
<div style="margin-left: 40px;"> </div>
<ul style="margin-left: 40px;">
<p> <img
src="http://www.mozilla.org/projects/ui/accessibility/images/tree-relativity.gif"
alt="Diagram showing MSAA tree is a subset of the DOM tree"
title="Diagram showing MSAA tree is a subset of the DOM tree"> </p>
The MSAA tree and the DOM tree are parallel structures, although the
MSAA tree is a subset of the DOM tree. <code>QueryInterface()</code> can
be used to switch between the interfaces used in the two trees
(IAccessible and ISimpleDOMNode). If there is no MSAA node for a DOM
node,&nbsp; pAccessible-&gt;<code>QueryInterface(IID_IAccessible)</code>
will return null.
</ul>
<h3 style="margin-left: 40px;"><a
name="The_Implementations_Behind_IAccessible"></a>A Variety of
Implementations for IAccessible</h3>
<div style="margin-left: 40px;">
<div style="margin-left: 40px;">
<p>There are two main kinds of classes in Mozilla's accessibility class
hierarchy, platform-specifc and cross-platform. All of the
platform-specific classes have the word "Wrap" appended to them. The
Wrap classes contain implementations and interfaces specific to MSAA or
ATK. These platform-specific classes inherit from cross-platform
classes, where the most of the implementation is done. For example,
nsAccessibleWrap inherits from nsAccessible. Every accessible object in
the MSAA tree has an implementation dertived from nsAccessible, which
exposes accessibility information through nsIAccessible, in a generic
cross-platform manner. <br>
</p>
<p>This default implementation for nsIAccessible knows how to use
nsAccessibleTreeWalker to walk Mozilla's content DOM and frame tree,
exposing only the objects that are needed for accessibility. The
nsAccessibleTreeWalker class knows what it needs to expose by asking
each DOM node's primary frame (a Gecko formatting object) for an
nsIAccessible, using the nsIFrame::GetAccessible() method. If
nsAccessibleTreeWalker gets an nsIAccessible back, then the DOM node
considered to be an accessible object. The nsIAccessible that is
returned is either a new one, or reused from the accessibility cache,
and the correct type of accessibility object to correctly expose that
DOM node through the cross-platform nsIAccessible and MSAA-specific
IAccessible interfaces.<br>
</p>
<p>Every accessibility object created must be cached, and must inherit
from nsAccessibleWrap so that it supports a base implementation of
nsIAccessible and IAccessible. Apart from that, it is free to override
IAccessible or nsIAccessible methods. In this way each class is tailored
to the specific abilities and properties of the HTML or XUL/UI objects
it applies to, and can support both MSAA, ATK and hopefully any future
accessibility API's we need to support. For example
nsHTMLButtonAccessible overrides nsIAccessible::GetAccRole to expose
ROLE_BUTTON for IAccessible::get_accRole which uses that. <br>
</p>
</div>
</div>
<ul style="margin-left: 40px;">
<p>A more complicated set of nsIAccessible methods which can be
overridden are GetAccFirstChild/GetAccLastChild/GetAccChildCount, which
allows for objects to define their own decendant subtrees. The default
behavior for nsIAccessible::getAccFirstChild is to instantiate a
nsDOMTreeWalker, and ask it for the first child. However,
nsImageAccessible overrides getAccFirstChild, returning the first area
of an image map if there is one, otherwise nsnull. This is necessary
because the image map areas can be in a completely different area of the
DOM from the image they apply to.<br>
</p>
</ul>
<div style="margin-left: 40px;"> </div>
<h3 style="margin-left: 40px;"><a name="Generating_MSAA_Events"></a>Generating
MSAA Events</h3>
<div style="margin-left: 40px;"> </div>
<ul style="margin-left: 40px;">
<p>First, keep in mind that most MSAA events aren't utilized by
accessibility aids. Therefore we implement only the handful that matter.
See the <a
href="file:///c%7C/moz/mozdocs/mozilla-org/html/projects/ui/accessibility/accessible-architecture.html#events">Events</a>
cheat sheet above for the list of events we implement. By far the most
important one is EVENT_OBJECT_FOCUS.<br>
</p>
<p>When a potential accessibility-related event occurs within
Mozilla, it is typically listened for by nsDocAccessible or
nsRootAccessible. The event listeners on these classes call
FireToolkitEvent(), which is implemented for every accessible.
Eventually, the event ends up at nsDocAccessibleWrap::FireToolkitEvent()
which calls NotifyWinEvent from the Win32 API. NotifyWinEvent is passed
arguments for the window the event occurred in, and the ID of the child
within that window. Accessibility aids use the Win32 call
SetWinEventHook() to register as a listener for these events. Creating
a unique child ID for every object within a window can be difficult,
see the problem and solution for <a
href="file:///c%7C/moz/mozdocs/mozilla-org/html/projects/ui/accessibility/accessible-architecture.html#Hacky_caret_tracking_not_working">no
unique child ID for object in window</a>.<br>
</p>
<p>The assistive technology chooses which events it is interested in
learning more about by calling the Win32 method
AccessibleObjectFromEvent, which returns the IAccessible to the node
corresponding to the child number that had been indicated from
NotifyWinEvent(). This ends up asking
nsDocAccessibleWrap::get_accChild() for a child IAccessible which
matches the child ID we indicated through NotifyWinEvent(). </p>
<p>In Mozilla, we use the DOM node pointer in the accessible object
as a basis for its child ID, which is also used as a hash key into our
cache. We also negate the 32 bit value so that it is always &lt;0,
telling us that they're really looking for the IAccessible for an event,
not child number x. During the callback, we look up the original
accessible node in the nsDocAccessible's cache and return it. <br>
</p>
</ul>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;"> </div>
<h2><a name="feedback"></a>5. Feedback</h2>
<div style="margin-left: 40px;">How can this document be improved? Was
it useful? Questions? Contact <a href="mailto:aaronl@netscape.com">aaronl@netscape.com</a><br>
</div>
</body>
</html>