2003-04-28 17:32:08 +04:00
|
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
2001-05-12 01:11:38 +04:00
|
|
|
<html>
|
|
|
|
<head>
|
2003-04-28 17:32:08 +04:00
|
|
|
<title>How the Accessible Module works</title>
|
2001-05-12 01:11:38 +04:00
|
|
|
</head>
|
|
|
|
<body>
|
2003-04-28 17:32:08 +04:00
|
|
|
<h1>Explanation of Mozilla's MSAA implementation<br>
|
|
|
|
and Cheat Sheet for Engineers new to MSAA</h1>
|
2001-05-12 01:11:38 +04:00
|
|
|
<ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<p> See also: <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 to use our MSAA and other relevant
|
|
|
|
API's. This has the details of what we do and do not support.<br>
|
|
|
|
</p>
|
|
|
|
<p>Mozilla supports 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
|
|
|
|
sytstems. to support assistive technologies for users with disabilities.
|
|
|
|
The <a href="http://lxr.mozilla.org/seamonkey/source/accessible/">Accessible
|
|
|
|
module</a> is where we implement the support for MSAA (<a
|
|
|
|
href="http://bugzilla.mozilla.org/show_bug.cgi?id=12952">bug 12952</a>)
|
|
|
|
as well as for Sun's <a
|
|
|
|
href="http://wwws.sun.com/software/star/gnome/accessibility/architecture.html">ATK</a>
|
|
|
|
API for Linux and UNIX. For documentatin 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.<br>
|
|
|
|
</p>
|
2001-05-12 01:11:38 +04:00
|
|
|
</ul>
|
|
|
|
<h2>What is MSAA?</h2>
|
|
|
|
<ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<p>3rd party assistive technology, such as screen readers, screen
|
|
|
|
magnifiers amd 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.audiodata.de/e/produkte/pc/lapbraille/">refreshable
|
|
|
|
braille display</a>. Screen magnifers 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. Finally, voice dictation
|
|
|
|
software needs to know what's in the current document or UI in order to
|
|
|
|
implement "say what you see" style features.<br>
|
|
|
|
</p>
|
|
|
|
<p> On Microsoft Windows, these kinds of assistive technology acquire
|
|
|
|
this necessary information via a comination 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 (ours is an example). This is so commonly
|
|
|
|
done, that no one even bothers to support the MSAA caret, because the
|
|
|
|
hack works. </p>
|
|
|
|
<p> MSAA provides information in two 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> a set of system messages that confer accessibility-related
|
|
|
|
events such as focus changes, changes to document content and alerts.</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 very 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.<br>
|
|
|
|
</p>
|
2001-05-12 01:11:38 +04:00
|
|
|
</ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<h2>How to hook in / How the IAccessible's are Created</h2>
|
2001-05-12 01:11:38 +04:00
|
|
|
<ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<p> The first thing that happens when an accessibility aid wants to
|
|
|
|
watch our application is calls the Windows API function
|
|
|
|
AccessibleObjectFromWindow(). This in turns 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 the window. In our case, this
|
|
|
|
event is received in mozilla/widget/src/windows/nsWindow.cpp. We send
|
|
|
|
back an IAccessible interface that represents that root window. The
|
|
|
|
accessibility aid will use that first IAccessible to reach rest of the
|
|
|
|
IAccessible hierarchy, by asking for it's children IAccessibles, asking
|
|
|
|
the children for the grandchildren IAccessibles, and so on. Until this
|
|
|
|
WM_GETOBJECT message is processed, the accessibility.dll is not loaded,
|
|
|
|
so there is almost zero overhead for accessibility in Mozilla.<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 nsFrame.cpp 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, and IAccessible, which is specific to
|
|
|
|
Windows/MSAA/COM. The nsRootAccessibleWrap class is then told to listen
|
|
|
|
for DOM, page load and scroll events. implementation It uses
|
|
|
|
these events to fire MSAA-specific events such as EVENT_OBJECT_FOCUS or
|
|
|
|
EVENT_OBJECT_STATECHANGE.. We'll explain more about events in a moment.<br>
|
|
|
|
</p>
|
|
|
|
</ul>
|
|
|
|
<h2>The Accessible Tree and the DOM Tree<br>
|
|
|
|
</h2>
|
|
|
|
<ul>
|
|
|
|
<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 "guve 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 use the DOM via Mozilla's <a
|
|
|
|
href="http://lxr.mozilla.org/seamonkey/source/accessible/public/msaa/ISimpleDOMNode.idl">ISimpleDOMNode</a>interface.
|
|
|
|
An 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.<br>
|
|
|
|
</p>
|
|
|
|
</ul>
|
|
|
|
<h3>MSAA tree vs. DOM tree - what's the relationship?</h3>
|
|
|
|
<ul>
|
|
|
|
<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, <code>QueryInterface()</code> will return null.
|
|
|
|
</ul>
|
|
|
|
<h2>IAccessible Methods - Cheatsheet for Implementors</h2>
|
2001-05-12 01:11:38 +04:00
|
|
|
<ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<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 IAccesible. <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 menuitem. <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, fousable,
|
|
|
|
selected, selectable, visible, protected (for passwords), checked, etc. <span
|
|
|
|
style="font-weight: bold;">[important]</span> </li>
|
2001-05-12 01:11:38 +04:00
|
|
|
<li>get_accHelp: Get context sensitive help for the IAccessible.</li>
|
2003-04-28 17:32:08 +04:00
|
|
|
<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>
|
2001-06-30 04:25:09 +04:00
|
|
|
<li>get_accSelection: Which children of this item are selected?</li>
|
2003-04-28 17:32:08 +04:00
|
|
|
<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]</span></li>
|
|
|
|
<li>accNavigate: Navigate up, down, left or right from this
|
|
|
|
IAccessible. <span style="font-weight: bold;">[important]</span></li>
|
|
|
|
<li>accHitTest: Find out what IAccessible exists and a specific
|
|
|
|
coordinate.</li>
|
|
|
|
<li>accDoDefaultAction: Perform the action described by
|
|
|
|
get_accDefaultAction.</li>
|
2001-05-12 01:11:38 +04:00
|
|
|
<li>put_accName: Change the name.</li>
|
|
|
|
<li>put_accValue: Change the value.</li>
|
2003-04-28 17:32:08 +04:00
|
|
|
</ul>
|
2001-05-12 01:11:38 +04:00
|
|
|
</ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<h2>The Implementations Behind IAccessible</h2>
|
2001-06-30 04:25:09 +04:00
|
|
|
<ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<p>The methods in ns*AccessibleWrap classes don't implement much
|
|
|
|
accessibility support. These platform-specific classes inherit from
|
|
|
|
cross-platform classes, where the real implementations exist. For
|
|
|
|
example, nsAccessibleWrap inherits from nsAccessible. Every accessible
|
|
|
|
object in the MSAA tree has an nsAccessible class, which exposes
|
|
|
|
accessibility information through nsIAccessible, in a cross-platform
|
|
|
|
manner. This base implementation for nsIAccessible knows how to walk
|
|
|
|
Mozilla's content DOM and frame tree, exposing only the objects that are
|
|
|
|
needed for accessibility.<br>
|
|
|
|
</p>
|
|
|
|
<p>Essentially, nsAccessible knows what it needs to expose by asking
|
|
|
|
each DOM node's primary frame for an nsIAccessible, using the
|
|
|
|
GetAccessible() method. If it gets one, it's considered an accessible
|
|
|
|
object. A frame that wishes to return an nsIAccessible GetAccessible()
|
|
|
|
is called, creates one of the correct type on the fly using
|
|
|
|
nsIAccessibilityService methods built for that purpose.</p>
|
|
|
|
<p>The nsIAccessible interface is implemented by a variety of
|
|
|
|
cross-platform classes for each of the various objects in HTML. Each
|
|
|
|
class is tailored to the specific abilities and properties of the HTML
|
|
|
|
objects it applies to, and can support both MSAA, ATK and hopefully any
|
|
|
|
future accessibility API's we need to support.<br>
|
|
|
|
</p>
|
|
|
|
<p>The specific implementations of nsIAccessible for each widget or
|
|
|
|
content type override methods from nsAccessible. For example
|
|
|
|
nsHTMLButtonAccessible overrides get_accRole to expose ROLE_BUTTON for
|
|
|
|
that getter. <br>
|
|
|
|
</p>
|
|
|
|
<p>A more complicated set of nsIAccessible methods which can be
|
|
|
|
overriden are GetAccFirstChild/GetAccLastChild/GetAccChildCount, which
|
|
|
|
allows for objects to define their own decendent 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>
|
2001-06-30 04:25:09 +04:00
|
|
|
</ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<h2>MSAA Events</h2>
|
2001-06-30 04:25:09 +04:00
|
|
|
<ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<p> When an accessibility-related event occurs within an application
|
|
|
|
such as Mozilla, it must use NotifyWinEvent from the Win32 API.
|
|
|
|
NotifyWinEvent is passed arguments for the window the event occured in,
|
|
|
|
and the number of the child within that window. Accessibility aids use
|
|
|
|
the Win32 call SetWinEventHook() to register as a listener for these
|
|
|
|
events. </p>
|
|
|
|
<p> The accessibility aid is choose which events it is interested in
|
|
|
|
learning more about by using the Win32 API call
|
|
|
|
AccessibleObjectFromEvent, requesting the IAccessible to the node
|
|
|
|
corresponding to the child number that had been indicated from
|
|
|
|
NotifyWinEvent(). This ends up asking our nsDocAccessibleWrap or
|
|
|
|
nsRootAccessibleWrap for the child IAccessible that matches the window
|
|
|
|
handle and child id we indicated through NotofyWinEvent(). </p>
|
|
|
|
<p>In Mozilla, we use the DOM node pointer in the accessible object
|
|
|
|
as its child ID, which is also used as a hashkey into our cache. During
|
|
|
|
the callback, we look up the original accessible node in the
|
|
|
|
nsDocAccessible's cache and return it.<br>
|
|
|
|
</p>
|
2001-06-30 04:25:09 +04:00
|
|
|
</ul>
|
|
|
|
<ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<p>Most MSAA events aren't utilized by accessibility aids. Therefore
|
|
|
|
we implement only the handful that matter. See <a
|
|
|
|
href="http://www.mozilla.org/projects/ui/accessibility/vendors-win.html">Gecko
|
|
|
|
Info for Windows Accessibility Vendors</a> for the list of events we
|
|
|
|
implement. By far the most important one is EVENT_OBJECT_FOCUS.<br>
|
|
|
|
</p>
|
|
|
|
</ul>
|
|
|
|
<h2>MSAA Events - Cheatsheet for Implementors<br>
|
2001-06-30 04:25:09 +04:00
|
|
|
</h2>
|
2003-04-28 17:32:08 +04:00
|
|
|
<ul>
|
|
|
|
<p>For information on what each event does, see the <a
|
|
|
|
href="file:///c:/moz/mozilla/accessible/Hello">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>
|
|
|
|
<table
|
|
|
|
style="text-align: left; margin-left: auto; width: 75%; margin-right: 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>
|
|
|
|
<br>
|
|
|
|
</td>
|
|
|
|
<td style="vertical-align: top;">EVENT_SYSTEM_MINIMIZESTART<br>
|
|
|
|
EVENT_SYSTEM_MINIMIZEEND<br>
|
|
|
|
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>
|
|
|
|
<h2>Dealing with the Quirks of MSAA</h2>
|
|
|
|
<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 it's quirks and some solutions/workarounds:<br>
|
2001-05-12 01:11:38 +04:00
|
|
|
</p>
|
2003-04-28 17:32:08 +04:00
|
|
|
<ul>
|
|
|
|
<li>Crash prone - more than one process refcounting same object</li>
|
2001-05-12 01:11:38 +04:00
|
|
|
</ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<div style="margin-left: 40px;">Problem: When your application closes,
|
|
|
|
different signals are 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 are being refcounted. This can lead
|
|
|
|
to crashes where some of your dll's are unloaded but not others, and a
|
|
|
|
destructor is called in an unloaded DLL.<br>
|
|
|
|
<br>
|
|
|
|
Solution: 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
|
|
|
|
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 a UI object is destroyed, shutdown
|
|
|
|
it's accessible object as well. In Gecko/Mozilla we are not allowed to
|
|
|
|
keep this extra pointer for each accessible object, so we use a hash
|
|
|
|
table cache, which is kept in sync with the tree of UI objects. Also,
|
|
|
|
don't implement EVENT_OBJECT_CREATE or EVENT_OBJECT_DESTROY. Vendors
|
|
|
|
have found that watching these events causes crashes.<br>
|
|
|
|
</div>
|
2001-05-12 01:11:38 +04:00
|
|
|
<ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<li>Hacky caret tracking interferes with MSAA solution<br>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
<div style="margin-left: 40px;">Problem: The screen reader does not use
|
|
|
|
the MSAA caret. It follows screen draws, and looks for a vertical
|
|
|
|
blinking line. Unfortunately, some screen readers can get confused by
|
|
|
|
the vertical lines on other objects, such as list boxes, even though
|
|
|
|
those lines are not blinking.<br>
|
|
|
|
<br>
|
|
|
|
Solution: Make sure there is a configuration file for each screen
|
|
|
|
reader specific to your application. Read the manual and find the
|
|
|
|
keystroke or commands for training the caret, and save this information
|
|
|
|
in the configuration file.<br>
|
|
|
|
</div>
|
|
|
|
<ul>
|
|
|
|
<li> Event window confusion<br>
|
|
|
|
<br>
|
|
|
|
Problem: The screen reader or other assistive technology does not track
|
|
|
|
the focus or other events correctly.<br>
|
|
|
|
<br>
|
|
|
|
Solution: This may be because you are reporting that the events are
|
|
|
|
occuring in a different window from the system window focus that the
|
|
|
|
screen reader gets from the Win32 call GetGUIThreadInfo() in the
|
|
|
|
hwndFocus field. This might be because although you are visibly showing
|
|
|
|
window focus on the correct window, you have not told the operating
|
|
|
|
system to change focus to this window. You must keep the two in sync.<br>
|
|
|
|
<br>
|
|
|
|
</li>
|
|
|
|
<li>Confusion with system-generated events<br>
|
|
|
|
<br>
|
|
|
|
Problem: When you test with Accessible Event Watcher in the MSAA SDK,
|
|
|
|
you will see many events that you yourself did not generate. Microsoft
|
|
|
|
Windows generates some events, like focus 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. If you happen to set window focus after you fired your own
|
|
|
|
EVENT_OBJECT_FOCUS event, your event will be ignored, because assitive
|
|
|
|
techology software tends to pay attention only to the last focus event.<br>
|
|
|
|
<br>
|
|
|
|
Solution: 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 to watch subsets of accessibility events. Count on
|
|
|
|
the assistive technology to make sense out the jumble.<br>
|
|
|
|
<br>
|
|
|
|
</li>
|
|
|
|
<li>No unique child id for object in window.<br>
|
|
|
|
<br>
|
|
|
|
Problem: 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>
|
|
|
|
Solution: 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
|
|
|
|
differnt object will be created with the same pointer value.<br>
|
|
|
|
<br>
|
|
|
|
</li>
|
|
|
|
<li>Not all features utilized by 3rd party vendors<br>
|
|
|
|
<br>
|
|
|
|
Problem: 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.<br>
|
|
|
|
<br>
|
|
|
|
Solution: Use this document to see what is generally considered
|
|
|
|
important by assistive technology manufacturers. Contact the vendors
|
|
|
|
early and often as you plan and implement your architecture, to see
|
|
|
|
what's important to them. Ignore every OBJID except for OBJID_CLIENT in
|
|
|
|
the WM_GETOBJECT message. Don't try to build a palace that no one will
|
|
|
|
live in. Implement only what's needed.<br>
|
|
|
|
<br>
|
|
|
|
</li>
|
|
|
|
<li>Missing functionality in MSAA<br>
|
|
|
|
<br>
|
|
|
|
Problem and Solutions: Assistive technology vendors need some things
|
|
|
|
which MSAA does not provide, such as:<br>
|
|
|
|
</li>
|
|
|
|
<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>
|
|
|
|
</ul>
|
|
|
|
<ul>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
<br>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
<li>Dueling text equivalents<br>
|
|
|
|
<br>
|
|
|
|
Problem: There are three kinds of text equivalents, and it is difficult
|
|
|
|
to know when to use each. 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>
|
|
|
|
Solution: 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 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>
|
|
|
|
<br>
|
|
|
|
</li>
|
|
|
|
<li>Issues with Links<br>
|
|
|
|
<br>
|
|
|
|
Problem: 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 won't read the object if it cannot
|
|
|
|
parse the whitespace according to its own rules.<br>
|
|
|
|
<br>
|
|
|
|
Solution: 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>
|
|
|
|
<br>
|
|
|
|
</li>
|
|
|
|
<li>MSAA Implementation is Not Performant<br>
|
|
|
|
<br>
|
|
|
|
Problem: The assistive technology may interact slowly with your
|
|
|
|
application.<br>
|
|
|
|
<br>
|
|
|
|
Solution: 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. The fewer calls, the better, because a lot of slowness
|
|
|
|
is caused by COM Marshaling.<br>
|
|
|
|
<br>
|
|
|
|
</li>
|
|
|
|
<li>Differing client implementations<br>
|
|
|
|
<br>
|
|
|
|
Problem: Every assistive technology uses MSAA differently.<br>
|
|
|
|
<br>
|
|
|
|
Solution: 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>
|
|
|
|
<br>
|
|
|
|
</li>
|
|
|
|
<li>Vendor quirks:<br>
|
|
|
|
<br>
|
|
|
|
Problem: 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 prioritiy.<br>
|
|
|
|
<br>
|
|
|
|
Solution: Try to reach out as a friend of the assistive technology
|
|
|
|
company. Be as easy to work with as you possibly can, including being
|
|
|
|
extremely responsibe to bug reports with new test builds, as well as
|
|
|
|
being very communicative about what you have fixed. 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, set your
|
|
|
|
expectations to a reasonable level. Realize that it's still business
|
|
|
|
for these companies, and that they need to sell more copies of their
|
|
|
|
software to make up for the time they spend on compatibility with your
|
|
|
|
application. 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.</li>
|
2001-05-12 01:11:38 +04:00
|
|
|
</ul>
|
2003-04-28 17:32:08 +04:00
|
|
|
<h2>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>
|
2001-05-12 01:11:38 +04:00
|
|
|
</body>
|
2003-04-28 17:32:08 +04:00
|
|
|
</html>
|