2007-03-22 10:30:00 -07:00
|
|
|
<!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. 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 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 <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 <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 <br>
|
|
|
|
STATE_MARQUEED <br>
|
|
|
|
STATE_ANIMATED <br>
|
|
|
|
STATE_INVISIBLE <br>
|
|
|
|
<br>
|
|
|
|
</td>
|
|
|
|
<td style="vertical-align: top;">STATE_OFFSCREEN <span
|
|
|
|
style="font-weight: bold;">[important]</span><br>
|
|
|
|
STATE_SIZEABLE <br>
|
|
|
|
STATE_MOVEABLE <br>
|
|
|
|
STATE_SELFVOICING <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 <br>
|
|
|
|
STATE_ALERT_LOW <br>
|
|
|
|
STATE_ALERT_MEDIUM <br>
|
|
|
|
STATE_ALERT_HIGH <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
|
2008-10-01 23:49:45 -07:00
|
|
|
some of its quirks and some solutions/workarounds:<br>
|
2007-03-22 10:30:00 -07:00
|
|
|
</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
|
2008-10-01 23:49:45 -07:00
|
|
|
object is destroyed, shutdown its accessible object as well. In
|
2007-03-22 10:30:00 -07:00
|
|
|
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. 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. </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 - 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/seamonkey/source/widget/src/windows/nsWindow.cpp#4370">mozilla/widget/src/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. 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, pAccessible-><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 <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>
|