1 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
---|
2 | <html> |
---|
3 | <head> |
---|
4 | <title>Implementing an MSAA Server - How Mozilla Does It, and |
---|
5 | Practical Tips for Developers</title> |
---|
6 | </head> |
---|
7 | <body> |
---|
8 | <h1>Implementing an MSAA Server</h1> |
---|
9 | <h2>Practical Tips for Developers, and How Mozilla Does It<br> |
---|
10 | </h2> |
---|
11 | <h2>Contents</h2> |
---|
12 | <div style="margin-left: 40px;"> |
---|
13 | <p>This document is for people working to support MSAA in an |
---|
14 | application in order to make it accessible with 3rd party assistive |
---|
15 | technologies, as well as for hackers wishing to be involved in Mozilla's |
---|
16 | MSAA support specifically.<br> |
---|
17 | You may also wish to read <a |
---|
18 | href="http://www.mozilla.org/projects/ui/accessibility/vendors-win.html">Gecko |
---|
19 | Info for Windows Accessibility Vendors</a>, a primer for vendors of 3rd |
---|
20 | party accessibility software, on how MSAA clients can utilize Gecko's |
---|
21 | MSAA support.</p> |
---|
22 | <a href="#intro">1. Intro: What is MSAA</a><br> |
---|
23 | <br> |
---|
24 | </div> |
---|
25 | <div style="margin-left: 40px;"><a href="#cheatsheets">2. Deciding |
---|
26 | Which MSAA Features to Support</a><br> |
---|
27 | <div style="margin-left: 40px;"><big></big><a href="#methods">Methods</a><br> |
---|
28 | <a href="#events">Events</a><br> |
---|
29 | <a href="#states">States</a><br> |
---|
30 | <a href="#roles">Roles</a><br> |
---|
31 | <a href="#objid">Object Identifiers</a><br> |
---|
32 | <br> |
---|
33 | </div> |
---|
34 | <a href="#quirks">3. </a><a href="#quirks">MSAA's Quirks and |
---|
35 | Workarounds</a><br> |
---|
36 | <div style="margin-left: 40px;"><a href="#Crash_prone">MSAA can be |
---|
37 | crash prone</a><br> |
---|
38 | <a href="#Hacky_caret_tracking_not_working">Hacky caret tracking not |
---|
39 | working</a><br> |
---|
40 | <a href="#Event_window_confusion">Event window confusion</a><br> |
---|
41 | <a href="#Confusion_with_system-generated_events">Confusion with |
---|
42 | system-generated events</a><br> |
---|
43 | <a href="#Hacky_caret_tracking_not_working">No unique child ID for |
---|
44 | object in window</a><br> |
---|
45 | <a href="#Not_all_MSAA_features_utilized_by_3rd">Not all MSAA features |
---|
46 | utilized by 3rd party vendors</a><br> |
---|
47 | <a href="#Missing_functionality_in_MSAA">Missing functionality in MSAA</a><br> |
---|
48 | <a href="#Dueling_text_equivalents">Dueling text equivalents</a><br> |
---|
49 | <a href="#Issues_with_Links">Issues with Links</a><br> |
---|
50 | <a href="#MSAA_Implementation_is_Not_Performant">Performance Problems</a><br> |
---|
51 | <a href="#Differing_client_implementations">Differing client |
---|
52 | implementations</a><br> |
---|
53 | <a href="#Undocumented_Window_Class_Usage">Undocumented Window Class |
---|
54 | Usage</a><br> |
---|
55 | <a href="#Vendor_quirks">Vendor quirks</a><br> |
---|
56 | <br> |
---|
57 | </div> |
---|
58 | <a href="#geckoimpl">4. |
---|
59 | Example: How Gecko and Mozilla Implement MSAA</a><br> |
---|
60 | <div style="margin-left: 40px;"><a |
---|
61 | href="#Creation_of_IAccessible_Objects">Creation |
---|
62 | of IAccessible Objects</a><br> |
---|
63 | <a |
---|
64 | href="#The_Accessible_Tree_vs._the_DOM_Tree">The |
---|
65 | Accessible Tree vs. the DOM Tree</a><br> |
---|
66 | <a |
---|
67 | href="#The_Implementations_Behind_IAccessible">The |
---|
68 | Various Implementations of IAccessible</a><br> |
---|
69 | <a |
---|
70 | href="#Generating_MSAA_Events">Generating |
---|
71 | MSAA Events</a><br> |
---|
72 | <br> |
---|
73 | </div> |
---|
74 | <a href="#feedback">5. Feedback</a><br> |
---|
75 | </div> |
---|
76 | <h2><a name="intro"></a>1. Intro: What is MSAA?</h2> |
---|
77 | <ul> |
---|
78 | <p>MSAA is the <a |
---|
79 | href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaastart_9w2t.asp?frame=true">Microsoft |
---|
80 | Active Accessibility (MSAA) API</a> , used on Windows operating systems. |
---|
81 | to support assistive technologies for users with disabilities. <br> |
---|
82 | </p> |
---|
83 | <p>Third party assistive technology, such as screen readers, screen |
---|
84 | magnifiers and voice input software, want to track what's happening |
---|
85 | inside Mozilla. They needs to know about focus changes and other events, |
---|
86 | and it needs to know what objects are contained in the current document |
---|
87 | or dialog box. Using this information, a screen reader will speak out |
---|
88 | loud important changes to the document or UI, and allow the user to |
---|
89 | track where they navigate. The screen reader user can navigate the web |
---|
90 | page using screen reader commands or browser commands, and the two |
---|
91 | pieces of software must remain in sync. Some screen readers can even |
---|
92 | show information on a <a href="http://www.deafblind.com/display.html">refreshable |
---|
93 | braille display</a>. Screen magnifiers will zoom to the focus, keeping |
---|
94 | it on the screen at all times, or even allow the user to enter a special |
---|
95 | low vision document reading mode, with a variety of features such as |
---|
96 | ticker mode where text is streamed on a single line. Finally, |
---|
97 | voice dictation software needs to know what's in the current document or |
---|
98 | UI in order to implement "say what you see" kinds of features.<br> |
---|
99 | <br> |
---|
100 | On Microsoft Windows, these kinds of assistive technology acquire this |
---|
101 | necessary information via a combination of hacks, MSAA and |
---|
102 | proprietary DOMs. MSAA is supposed to be the "right way" for |
---|
103 | accessibility aids to get information, but sometimes the hacks are more |
---|
104 | effective. For example, screen readers look for screen draws of a |
---|
105 | vertical blinking line, to determine the location of the caret. Without |
---|
106 | doing this, screen readers would not be able to let the user know where |
---|
107 | there caret has moved to in most programs, because so many applications |
---|
108 | do not use the system caret (Gecko does not). This is so commonly done, |
---|
109 | that no one even bothers to support the MSAA caret, after all the hack |
---|
110 | is general solution works with pretty much all applications.</p> |
---|
111 | <p>MSAA provides information in several different ways: </p> |
---|
112 | <ol> |
---|
113 | <li>A COM interface (IAccessible) that allows applications to |
---|
114 | expose the tree of data nodes that make up each window in the user |
---|
115 | interface currently being interacted with and</li> |
---|
116 | <li>Custom interface extensions via interfaces via QueryInterface |
---|
117 | and QueryService. This can provide assistive technology with contextual |
---|
118 | information specific to your object model. For example, Gecko support |
---|
119 | ISimpleDOMNode to provide information about the DOM node for an |
---|
120 | accessible object.<br> |
---|
121 | </li> |
---|
122 | <li>A set of system messages that confer accessibility-related |
---|
123 | events such as focus changes, changes to document content and state |
---|
124 | changes in UI objects like checkboxes.<br> |
---|
125 | </li> |
---|
126 | </ol> |
---|
127 | <p></p> |
---|
128 | <p> To really learn about MSAA, you need to download the entire <a |
---|
129 | href="http://msdn.microsoft.com/library/default.asp?URL=/downloads/list/accessibility.asp">MSAA |
---|
130 | SDK</a>. Without downloading the SDK, you won't get the extremely |
---|
131 | useful tools, which help a great deal in the learning process. The |
---|
132 | Accessible Event Watcher shows what accessible events are being |
---|
133 | generated by a given piece of software. The Accessible Explorer and |
---|
134 | Inspect Object tools show the tree of data nodes the Accessible object |
---|
135 | is exposing through COM, and what the screen boundaries of each object |
---|
136 | are. In addition, MSDN has improved their <a |
---|
137 | href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaastart_9w2t.asp">MSAA |
---|
138 | documentation</a>.<br> |
---|
139 | </p> |
---|
140 | </ul> |
---|
141 | <h2><a name="cheatsheets"></a>2. Deciding Which MSAA Features to Support<br> |
---|
142 | </h2> |
---|
143 | <h2 style="margin-left: 40px;"><a name="methods"></a>MSAA Methods - |
---|
144 | Cheat Sheet for Developers</h2> |
---|
145 | <div style="margin-left: 40px;"> </div> |
---|
146 | <ul style="margin-left: 40px;"> |
---|
147 | <p> The IAccessible interface is used in a tree of IAccessible's, each |
---|
148 | one representing a data node, similar to a DOM. </p> |
---|
149 | <p> Here are the methods supported in IAccessible - a minimal |
---|
150 | implementation would contain those marked "<span |
---|
151 | style="font-weight: bold;">[important]</span>" :<br> |
---|
152 | </p> |
---|
153 | <ul> |
---|
154 | <li>get_accParent: Get the parent of an IAccessible. <span |
---|
155 | style="font-weight: bold;">[important]</span><br> |
---|
156 | </li> |
---|
157 | <li>get_accChildCount: Get the number of children of an |
---|
158 | IAccessible. <span style="font-weight: bold;">[important]</span></li> |
---|
159 | <li>get_accChild: Get the child of an IAccessible. <span |
---|
160 | style="font-weight: bold;">[important]</span></li> |
---|
161 | <li>get_accName: Get the "name" of the IAccessible, for example the |
---|
162 | name of a button, checkbox or menu item. <span |
---|
163 | style="font-weight: bold;">[important]</span></li> |
---|
164 | <li>get_accValue: Get the "value" of the IAccessible, for example a |
---|
165 | number in a slider, a URL for a link, the text a user entered in a |
---|
166 | field. <span style="font-weight: bold;">[important]</span></li> |
---|
167 | <li>get_accDescription: Get a long description of the current |
---|
168 | IAccessible. This is not really too useful.</li> |
---|
169 | <li>get_accRole: Get an enumerated value representing what this |
---|
170 | IAccessible is used for, for example. <br> |
---|
171 | </li> |
---|
172 | is it a link, static text, editable text, a checkbox, or a table |
---|
173 | cell, etc. <span style="font-weight: bold;">[important]</span><span |
---|
174 | style="font-weight: bold;"></span><li>get_accState: a 32 bit field |
---|
175 | representing possible on/off states, such as focused, focusable, |
---|
176 | selected, selectable, visible, protected (for passwords), checked, etc. <span |
---|
177 | style="font-weight: bold;">[important]</span> </li> |
---|
178 | <li>get_accHelp: Get context sensitive help for the IAccessible.</li> |
---|
179 | <li>get_accHelpTopic: We don't use this, it's only if the Windows |
---|
180 | help system is used.</li> |
---|
181 | <li>get_accKeyboardShortcut: What is the keyboard shortcut for this |
---|
182 | IAccessible (underlined alt+combo mnemonic)<br> |
---|
183 | </li> |
---|
184 | <li>get_accFocus: Which child is focused? <span |
---|
185 | style="font-weight: bold;">[important]</span></li> |
---|
186 | <li>get_accSelection: Which children of this item are selected?</li> |
---|
187 | <li>get_accDefaultAction: Get a description or name of the default |
---|
188 | action for this component, such as "jump" for links.</li> |
---|
189 | <li>accSelect: Select the item associated with this IAccessible. <span |
---|
190 | style="font-weight: bold;">[important]</span></li> |
---|
191 | <li>accLocation: Get the x,y coordinates, and the height and width |
---|
192 | of this IAccessible node. <span style="font-weight: bold;">[important]<br> |
---|
193 | </span></li> |
---|
194 | <li>accNavigate: Navigate to the first/last child, previous/next |
---|
195 | sibling, up, down, left or right from this IAccessible. <span |
---|
196 | style="font-weight: bold;">[important, </span><span |
---|
197 | style="font-weight: bold;">but no need to implement up/down/left/right</span><span |
---|
198 | style="font-weight: bold;">]</span></li> |
---|
199 | <li>accHitTest: Find out what IAccessible exists and a specific |
---|
200 | coordinate.</li> |
---|
201 | <li>accDoDefaultAction: Perform the action described by |
---|
202 | get_accDefaultAction.</li> |
---|
203 | <li>put_accName: Change the name.</li> |
---|
204 | <li>put_accValue: Change the value.</li> |
---|
205 | </ul> |
---|
206 | </ul> |
---|
207 | <div style="margin-left: 40px;"> </div> |
---|
208 | <h2 style="margin-left: 40px;"><a name="events"></a>MSAA Events Cheat |
---|
209 | Sheet<br> |
---|
210 | </h2> |
---|
211 | <div style="margin-left: 40px;"> </div> |
---|
212 | <ul style="margin-left: 40px;"> |
---|
213 | <p>For information on what each event does, see the <a |
---|
214 | href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaaccrf_7jlf.asp">MSDN |
---|
215 | Event Constants page</a>.</p> |
---|
216 | <p>Check with your assistive technology partners to find out what |
---|
217 | events you need to support. There's a very good chance they won't ask |
---|
218 | for more than the events marked <span style="font-weight: bold;">[important]</span>:<br> |
---|
219 | </p> |
---|
220 | </ul> |
---|
221 | <div style="margin-left: 40px;"> </div> |
---|
222 | <table |
---|
223 | style="text-align: left; width: 75%; margin-right: auto; margin-left: auto;" |
---|
224 | border="0" cellspacing="2" cellpadding="2"> |
---|
225 | <tbody> |
---|
226 | <tr> |
---|
227 | <td style="vertical-align: top;">EVENT_SYSTEM_SOUND<br> |
---|
228 | EVENT_SYSTEM_ALERT<br> |
---|
229 | EVENT_SYSTEM_FOREGROUND<br> |
---|
230 | EVENT_SYSTEM_MENUSTART<br> |
---|
231 | EVENT_SYSTEM_MENUEND<br> |
---|
232 | EVENT_SYSTEM_MENUPOPUPSTART <span style="font-weight: bold;">[important]</span><br> |
---|
233 | EVENT_SYSTEM_MENUPOPUPEND <span style="font-weight: bold;">[important]</span><br> |
---|
234 | EVENT_SYSTEM_CAPTURESTART<br> |
---|
235 | EVENT_SYSTEM_CAPTUREEND<br> |
---|
236 | EVENT_SYSTEM_MOVESIZESTART<br> |
---|
237 | EVENT_SYSTEM_MOVESIZEEND<br> |
---|
238 | EVENT_SYSTEM_CONTEXTHELPSTART<br> |
---|
239 | EVENT_SYSTEM_CONTEXTHELPEND<br> |
---|
240 | EVENT_SYSTEM_DRAGDROPSTART<br> |
---|
241 | EVENT_SYSTEM_DRAGDROPEND<br> |
---|
242 | EVENT_SYSTEM_DIALOGSTART<br> |
---|
243 | EVENT_SYSTEM_DIALOGEND<br> |
---|
244 | EVENT_SYSTEM_SCROLLINGSTART<br> |
---|
245 | EVENT_SYSTEM_SCROLLINGEND <span style="font-weight: bold;">[possibly |
---|
246 | important, talk to AT vendor]</span><br> |
---|
247 | EVENT_SYSTEM_SWITCHSTART<br> |
---|
248 | EVENT_SYSTEM_SWITCHEND<br> |
---|
249 | EVENT_SYSTEM_MINIMIZESTART<br> |
---|
250 | EVENT_SYSTEM_MINIMIZEEND<br> |
---|
251 | </td> |
---|
252 | <td style="vertical-align: top;">EVENT_OBJECT_CREATE <span |
---|
253 | style="font-weight: bold;">[don't implement, watching system generated |
---|
254 | versions of this event causes </span><span style="font-weight: bold;">assistive |
---|
255 | technology </span><span style="font-weight: bold;">crashes]</span><br> |
---|
256 | EVENT_OBJECT_DESTROY <span style="font-weight: bold;">[don't |
---|
257 | implement, watching system generated versions of this event causes |
---|
258 | assistive technology crashes]</span><br> |
---|
259 | EVENT_OBJECT_SHOW<br> |
---|
260 | EVENT_OBJECT_HIDE<br> |
---|
261 | EVENT_OBJECT_REORDER <span style="font-weight: bold;">[important for |
---|
262 | mutating docs in future, but not yet]</span><br> |
---|
263 | EVENT_OBJECT_FOCUS <span style="font-weight: bold;">[important]</span><br> |
---|
264 | EVENT_OBJECT_SELECTION<br> |
---|
265 | EVENT_OBJECT_SELECTIONADD<br> |
---|
266 | EVENT_OBJECT_SELECTIONREMOVE<br> |
---|
267 | EVENT_OBJECT_SELECTIONWITHIN<br> |
---|
268 | EVENT_OBJECT_STATECHANGE <span style="font-weight: bold;">[important |
---|
269 | for checkboxes and radio buttons]</span><br> |
---|
270 | EVENT_OBJECT_LOCATIONCHANGE<br> |
---|
271 | EVENT_OBJECT_NAMECHANGE<br> |
---|
272 | EVENT_OBJECT_DESCRIPTIONCHANGE<br> |
---|
273 | EVENT_OBJECT_VALUECHANGE<br> |
---|
274 | EVENT_OBJECT_PARENTCHANGE<br> |
---|
275 | EVENT_OBJECT_HELPCHANGE<br> |
---|
276 | EVENT_OBJECT_DEFACTIONCHANGE<br> |
---|
277 | EVENT_OBJECT_ACCELERATORCHANGE<br> |
---|
278 | </td> |
---|
279 | </tr> |
---|
280 | </tbody> |
---|
281 | </table> |
---|
282 | <div style="margin-left: 40px;"> </div> |
---|
283 | <h2 style="margin-left: 40px;"><a name="states"></a>MSAA States Cheat |
---|
284 | Sheet<br> |
---|
285 | </h2> |
---|
286 | <div style="margin-left: 40px;"> </div> |
---|
287 | <ul style="margin-left: 40px;"> |
---|
288 | <p>For information on what each state does, see the <a |
---|
289 | href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaaccrf_7jlf.asp">MSDN |
---|
290 | State Constants page</a>.</p> |
---|
291 | <p>Check with your assistive technology partners to find out what |
---|
292 | states you need to support. There's a very good chance they won't ask |
---|
293 | for more than the states marked <span style="font-weight: bold;">[important]</span>:</p> |
---|
294 | </ul> |
---|
295 | <div style="margin-left: 40px;"></div> |
---|
296 | <table |
---|
297 | style="text-align: left; width: 75%; margin-right: auto; margin-left: auto;" |
---|
298 | border="0" cellspacing="2" cellpadding="2"> |
---|
299 | <tbody> |
---|
300 | <tr> |
---|
301 | <td style="vertical-align: top;">STATE_UNAVAILABLE <span |
---|
302 | style="font-weight: bold;">[important]</span><br> |
---|
303 | STATE_SELECTED <span style="font-weight: bold;">[important]</span><br> |
---|
304 | STATE_FOCUSED <span style="font-weight: bold;">[important]</span><br> |
---|
305 | STATE_PRESSED <br> |
---|
306 | STATE_CHECKED <span style="font-weight: bold;">[important]</span><br> |
---|
307 | STATE_MIXED<br> |
---|
308 | STATE_READONLY <span style="font-weight: bold;">[important]</span><br> |
---|
309 | STATE_HOTTRACKED <br> |
---|
310 | STATE_DEFAULT <span style="font-weight: bold;">[important]</span><br> |
---|
311 | STATE_EXPANDED <span style="font-weight: bold;">[important]</span><br> |
---|
312 | STATE_COLLAPSED <span style="font-weight: bold;">[important]</span><br> |
---|
313 | STATE_BUSY <span style="font-weight: bold;">[important]</span><br> |
---|
314 | STATE_FLOATING <br> |
---|
315 | STATE_MARQUEED <br> |
---|
316 | STATE_ANIMATED <br> |
---|
317 | STATE_INVISIBLE <br> |
---|
318 | <br> |
---|
319 | </td> |
---|
320 | <td style="vertical-align: top;">STATE_OFFSCREEN <span |
---|
321 | style="font-weight: bold;">[important]</span><br> |
---|
322 | STATE_SIZEABLE <br> |
---|
323 | STATE_MOVEABLE <br> |
---|
324 | STATE_SELFVOICING <br> |
---|
325 | STATE_FOCUSABLE <span style="font-weight: bold;">[important]</span><br> |
---|
326 | STATE_SELECTABLE <span style="font-weight: bold;">[important]</span><br> |
---|
327 | STATE_LINKED <span style="font-weight: bold;">[important]</span><br> |
---|
328 | STATE_TRAVERSED <span style="font-weight: bold;">[important]</span><br> |
---|
329 | STATE_MULTISELECTABLE <span style="font-weight: bold;">[important]</span><br> |
---|
330 | STATE_EXTSELECTABLE <br> |
---|
331 | STATE_ALERT_LOW <br> |
---|
332 | STATE_ALERT_MEDIUM <br> |
---|
333 | STATE_ALERT_HIGH <br> |
---|
334 | STATE_PROTECTED <span style="font-weight: bold;">[important]</span><br> |
---|
335 | STATE_HASPOPUP <br> |
---|
336 | </td> |
---|
337 | </tr> |
---|
338 | </tbody> |
---|
339 | </table> |
---|
340 | <h2 style="margin-left: 40px;"><a name="roles"></a>MSAA Roles Cheat |
---|
341 | Sheet<br> |
---|
342 | </h2> |
---|
343 | <div style="margin-left: 40px;"> </div> |
---|
344 | <ul style="margin-left: 40px;"> |
---|
345 | <p>For information on what each role does, see the <a |
---|
346 | href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaaccrf_7jlf.asp">MSDN |
---|
347 | Role Constants page</a>.</p> |
---|
348 | <p>Check with your assistive technology partners to find out what |
---|
349 | roles you need to support. There's a very good chance they won't ask for |
---|
350 | more than the roles marked <span style="font-weight: bold;">[important]</span>:<br> |
---|
351 | There is no need to support the objects marked <span |
---|
352 | style="font-weight: bold;">[inserted by system]. </span>Windows will |
---|
353 | add those objects to your hierarchy for you.<br> |
---|
354 | </p> |
---|
355 | </ul> |
---|
356 | <div style="margin-left: 40px;"> </div> |
---|
357 | <table |
---|
358 | style="text-align: left; width: 75%; margin-right: auto; margin-left: auto;" |
---|
359 | border="0" cellspacing="2" cellpadding="2"> |
---|
360 | <tbody> |
---|
361 | <tr> |
---|
362 | <td style="vertical-align: top;">ROLE_TITLEBAR <span |
---|
363 | style="font-weight: bold;">[inserted by system]</span><br> |
---|
364 | ROLE_MENUBAR <span style="font-weight: bold;">[important if you don't |
---|
365 | use native menus]</span><br> |
---|
366 | ROLE_SCROLLBAR<br> |
---|
367 | ROLE_GRIP<br> |
---|
368 | ROLE_SOUND<br> |
---|
369 | ROLE_CURSOR<br> |
---|
370 | ROLE_CARET<br> |
---|
371 | ROLE_ALERT<br> |
---|
372 | ROLE_WINDOW <span style="font-weight: bold;">[inserted by system]</span><br> |
---|
373 | ROLE_CLIENT <span style="font-weight: bold;">[important]</span><br> |
---|
374 | ROLE_MENUPOPUP <span style="font-weight: bold;">[important]</span><br> |
---|
375 | ROLE_MENUITEM <span style="font-weight: bold;">[important]</span><br> |
---|
376 | ROLE_TOOLTIP<br> |
---|
377 | ROLE_APPLICATION<br> |
---|
378 | ROLE_DOCUMENT<br> |
---|
379 | ROLE_PANE <span style="font-weight: bold;">[important]</span><br> |
---|
380 | ROLE_CHART<br> |
---|
381 | ROLE_DIALOG<br> |
---|
382 | ROLE_BORDER<br> |
---|
383 | ROLE_GROUPING<br> |
---|
384 | ROLE_SEPARATOR <span style="font-weight: bold;">[important]</span><br> |
---|
385 | ROLE_TOOLBAR<br> |
---|
386 | ROLE_STATUSBAR <span style="font-weight: bold;">[important]</span><br> |
---|
387 | ROLE_TABLE <span style="font-weight: bold;">[important]</span><br> |
---|
388 | ROLE_COLUMNHEADER<br> |
---|
389 | ROLE_ROWHEADER<br> |
---|
390 | ROLE_COLUMN<br> |
---|
391 | ROLE_ROW<br> |
---|
392 | ROLE_CELL <span style="font-weight: bold;">[important]</span><br> |
---|
393 | ROLE_LINK <span style="font-weight: bold;">[important]</span><br> |
---|
394 | ROLE_HELPBALLOON<br> |
---|
395 | ROLE_CHARACTER<br> |
---|
396 | </td> |
---|
397 | <td style="vertical-align: top;">ROLE_LIST <span |
---|
398 | style="font-weight: bold;">[important]</span><br> |
---|
399 | ROLE_LISTITEM <span style="font-weight: bold;">[important]</span><br> |
---|
400 | ROLE_OUTLINE <span style="font-weight: bold;">[important]</span><br> |
---|
401 | ROLE_OUTLINEITEM <span style="font-weight: bold;">[important]</span><br> |
---|
402 | ROLE_PAGETAB <span style="font-weight: bold;">[important]</span><br> |
---|
403 | ROLE_PROPERTYPAGE <span style="font-weight: bold;">[important]</span><br> |
---|
404 | ROLE_INDICATOR<br> |
---|
405 | ROLE_GRAPHIC <span style="font-weight: bold;">[important]</span><br> |
---|
406 | ROLE_STATICTEXT <span style="font-weight: bold;">[important]</span><br> |
---|
407 | ROLE_TEXT <span style="font-weight: bold;">[important]</span><br> |
---|
408 | ROLE_PUSHBUTTON <span style="font-weight: bold;">[important]</span><br> |
---|
409 | ROLE_CHECKBUTTON <span style="font-weight: bold;">[important]</span><br> |
---|
410 | ROLE_RADIOBUTTON <span style="font-weight: bold;">[important]</span><br> |
---|
411 | ROLE_COMBOBOX <span style="font-weight: bold;">[important]</span><br> |
---|
412 | ROLE_DROPLIST <span style="font-weight: bold;">[important]</span><br> |
---|
413 | ROLE_PROGRESSBAR <span style="font-weight: bold;">[important]</span><br> |
---|
414 | ROLE_DIAL<br> |
---|
415 | ROLE_HOTKEYFIELD<br> |
---|
416 | ROLE_SLIDER<br> |
---|
417 | ROLE_SPINBUTTON<br> |
---|
418 | ROLE_DIAGRAM<br> |
---|
419 | ROLE_ANIMATION<br> |
---|
420 | ROLE_EQUATION<br> |
---|
421 | ROLE_BUTTONDROPDOWN<br> |
---|
422 | ROLE_BUTTONMENU<br> |
---|
423 | ROLE_BUTTONDROPDOWNGRID<br> |
---|
424 | ROLE_WHITESPACE<br> |
---|
425 | ROLE_PAGETABLIST <span style="font-weight: bold;">[important]</span><br> |
---|
426 | ROLE_CLOCK<br> |
---|
427 | ROLE_SPLITBUTTON<br> |
---|
428 | ROLE_IPADDRESS<br> |
---|
429 | ROLE_NOTHING<br> |
---|
430 | <br> |
---|
431 | </td> |
---|
432 | </tr> |
---|
433 | </tbody> |
---|
434 | </table> |
---|
435 | <div style="margin-left: 40px;"></div> |
---|
436 | <h2 style="margin-left: 40px;"><a name="objid"></a>MSAA Object |
---|
437 | Identifiers Cheat Sheet<br> |
---|
438 | </h2> |
---|
439 | <div style="margin-left: 40px;"> </div> |
---|
440 | <p style="margin-left: 80px;">For information on what each object |
---|
441 | identifier does, see the <a |
---|
442 | href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msaa/msaaccrf_7jlf.asp">MSDN |
---|
443 | Object Identifiers Constants page</a>.</p> |
---|
444 | <div style="margin-left: 80px;">Check with <big><big></big></big>our |
---|
445 | assistive technology partners to find out what object identifiers you |
---|
446 | need to support. There's a very good chance they won't ask for more than |
---|
447 | the object itentifiers marked <span style="font-weight: bold;">[important]</span>:<br> |
---|
448 | </div> |
---|
449 | <dl style="margin-left: 120px;"> |
---|
450 | <dt>OBJID_ALERT<br> |
---|
451 | OBJID_CARET<br> |
---|
452 | OBJID_CLIENT <span style="font-weight: bold;">[important]</span><br> |
---|
453 | OBJID_CURSOR<br> |
---|
454 | OBJID_HSCROLL<br> |
---|
455 | OBJID_NATIVEOM <span style="font-weight: bold;">[important? might be |
---|
456 | useful for supporting custom interfaces, need to research]</span><br> |
---|
457 | OBJID_MENU<br> |
---|
458 | OBJID_QUERYCLASSNAMEIDX<br> |
---|
459 | OBJID_SIZEGRIP<br> |
---|
460 | OBJID_SOUND<br> |
---|
461 | OBJID_SYSMENU<br> |
---|
462 | OBJID_TITLEBAR<br> |
---|
463 | OBJID_VSCROLL<br> |
---|
464 | OBJID_WINDOW<br> |
---|
465 | </dt> |
---|
466 | </dl> |
---|
467 | <h2><a name="quirks"></a>3. Dealing with the Quirks of MSAA</h2> |
---|
468 | <div style="margin-left: 40px;"> </div> |
---|
469 | <p style="margin-left: 40px;">MSAA has a well deseved reputation for |
---|
470 | quirkiness. It is not "plug and play", and will take a lot of |
---|
471 | testing/refinement before your solution works with any product. Here are |
---|
472 | some of it's quirks and some solutions/workarounds:<br> |
---|
473 | </p> |
---|
474 | <div style="margin-left: 40px;"><big><a name="Crash_prone"></a>MSAA can |
---|
475 | be crash prone</big><br> |
---|
476 | </div> |
---|
477 | <div style="margin-left: 80px;"><br> |
---|
478 | <span style="text-decoration: underline;">Problem</span>: Many of |
---|
479 | MSAA's crash occur because more than one process is refcounting the same |
---|
480 | objects, and because pointers are being shared between processes. When |
---|
481 | your application closes, different signals are typically broadcast. For |
---|
482 | example, the application window closes and the window is blurred. It is |
---|
483 | impossible to know if and when the 3rd party assistive technology will |
---|
484 | use one of these signals to release the objects of yours that is is |
---|
485 | refcounting. This can lead to crashes where it releases something and |
---|
486 | the wrong time, when some of your dll's are unloaded but not others, |
---|
487 | and a destructor is called in an unloaded DLL.<br> |
---|
488 | <br> |
---|
489 | <span style="text-decoration: underline;">Solution</span>: Create a |
---|
490 | "shutdown" method for each internal accessible object, to remove any |
---|
491 | references to other internal objects before any of your dll's are |
---|
492 | unloaded. In order to do this effectively, you will have to keep track |
---|
493 | of every accessible object that you create. The shutdown method for an |
---|
494 | accessibility object should be called whenever the document or UI object |
---|
495 | it refers to goes away. The easiest way to do that is to keep a pointer |
---|
496 | to an accessible in each internal UI object. If that pointer is |
---|
497 | non-null, then there is an accessible object for it. Whenever the UI |
---|
498 | object is destroyed, shutdown it's accessible object as well. In |
---|
499 | Gecko/Mozilla we are not allowed to keep this extra pointer for each |
---|
500 | accessible object, so when accessibility is turned on we use a hash |
---|
501 | table to cache these objects. Such a cache must be kept in perfect sync |
---|
502 | with the tree of UI and document objects, which is difficult. Therefore, |
---|
503 | unless 4 bytes extra on each object is criticial in your application, |
---|
504 | just keep the extra pointer around instead of using a hash table.<br> |
---|
505 | <br> |
---|
506 | Also, don't implement EVENT_OBJECT_CREATE or EVENT_OBJECT_DESTROY. |
---|
507 | Vendors have found that watching these events causes crashes.<br> |
---|
508 | <br> |
---|
509 | </div> |
---|
510 | <div style="margin-left: 40px;"><big><a |
---|
511 | name="Hacky_caret_tracking_not_working"></a>Hacky caret tracking |
---|
512 | causes problems<br> |
---|
513 | </big></div> |
---|
514 | <div style="margin-left: 80px;"><br> |
---|
515 | <span style="text-decoration: underline;">Problem</span>: Assistive |
---|
516 | technologies do not use the MSAA caret. They follow screen draws, |
---|
517 | looking for a vertical blinking line. Unfortunately, some products can |
---|
518 | get confused by the vertical lines on other objects, such as list boxes, |
---|
519 | even though those lines are not blinking. The assistive technology may |
---|
520 | not see your caret at all.<br> |
---|
521 | <br> |
---|
522 | <span style="text-decoration: underline;">Solution</span>: Make sure |
---|
523 | there is a configuration file for each assistive technology specific to |
---|
524 | your application. Read the manual or help, and find the keystroke or |
---|
525 | commands for training the caret, and save this information in the |
---|
526 | configuration file. Don't support the MSAA caret, none of the vendors |
---|
527 | use it.<br> |
---|
528 | <br> |
---|
529 | </div> |
---|
530 | <div style="margin-left: 40px;"> <big><a name="Event_window_confusion"></a>Event |
---|
531 | window handle is incorrect</big><br> |
---|
532 | <br> |
---|
533 | <div style="margin-left: 40px;"><span |
---|
534 | style="text-decoration: underline;">Problem</span>: The screen reader |
---|
535 | or other assistive technology does not track the focus or other events |
---|
536 | correctly.<br> |
---|
537 | <br> |
---|
538 | <span style="text-decoration: underline;">Solution</span>: This may be |
---|
539 | because you are reporting that the events in a different window from the |
---|
540 | current system focused. The assistive technology may be asking |
---|
541 | GetGUIThreadInfo for its hwndFocus, and throwing away MSAA events that |
---|
542 | are not in the currently focused window. Even if you are visibly showing |
---|
543 | window focus on the correct window, you must also tell the operating |
---|
544 | system to focus this window before any other accessibility events get |
---|
545 | fired in it. </div> |
---|
546 | <br> |
---|
547 | <big><a name="Confusion_with_system-generated_events"></a>Confusion |
---|
548 | with system-generated events</big><br> |
---|
549 | <br> |
---|
550 | <div style="margin-left: 40px;"> <span |
---|
551 | style="text-decoration: underline;">Problem</span>: When you test with |
---|
552 | Accessible Event Watcher in the MSAA SDK, you will see many events that |
---|
553 | your application did not generate. Microsoft Windows generates some |
---|
554 | events for you. This is extremely annoying. The assistive technology has |
---|
555 | no way to tell whether the event came from your application or from |
---|
556 | Windows. For example, when you set window focus, Windows will generate |
---|
557 | an EVENT_OBJECT_FOCUS event an a ROLE_WINDOW object it also generated |
---|
558 | for you. If you happen to set window focus after you fired your own |
---|
559 | EVENT_OBJECT_FOCUS event on an object in the widnow, your event will be |
---|
560 | ignored, because assistive technology software tends to pay attention |
---|
561 | only to the last focus event.<br> |
---|
562 | <br> |
---|
563 | <span style="text-decoration: underline;">Solution</span>: When an |
---|
564 | object is about to get focused in a different window, make sure you |
---|
565 | focus a window before you fire your own focus events for objects inside |
---|
566 | it. Test using Accessible Event Watcher in the MSAA SDK, and use the |
---|
567 | settings panel to watch subsets of accessibility events. Count on the |
---|
568 | assistive technology to make sense out the jumble of extra |
---|
569 | system-generated events, it's not your problem.<br> |
---|
570 | </div> |
---|
571 | <br> |
---|
572 | <big><a name="No_unique_child_ID_for_object_in_window"></a>No unique |
---|
573 | child ID for event target in window</big><br> |
---|
574 | <br> |
---|
575 | <div style="margin-left: 40px;"> <span |
---|
576 | style="text-decoration: underline;">Problem</span>: MSAA expects |
---|
577 | events to be reported using NotifyWinEvent(eventNum, hWnd, worldID, |
---|
578 | childID), and there may not be an obvious way to get a window handle and |
---|
579 | a 32 bit childID for an object. You may be using windowless controls, or |
---|
580 | have an entire document with lots of objects in a given window. The |
---|
581 | child ID must be unique, because this is what the assistive technology |
---|
582 | will use to retrieve the accessible via AccessibleObjectFromEvent() |
---|
583 | which ends up using get_accChild on the accessible for the given window.<br> |
---|
584 | <br> |
---|
585 | <span style="text-decoration: underline;">Solution</span>: In |
---|
586 | Gecko/Mozilla, we did not want to store an extra 32 bit unique ID value |
---|
587 | on every object. Instead, we hand back a 32 bit value derived from the |
---|
588 | UI object's pointer, which is unique. We ensure that the value we hand |
---|
589 | back is always negative. When the get_accChild call comes back, we check |
---|
590 | our hash table cache for that window to see if there's an accessible |
---|
591 | object still associated with that unique value. This means the client |
---|
592 | must use AccessibleObjectFromEvent immediately, because there is a |
---|
593 | danger that the object will go away, and another different object will |
---|
594 | be created with the same pointer value.That case seems extremely remote, |
---|
595 | because information from events is generally retrieved right after the |
---|
596 | event.<br> |
---|
597 | <br> |
---|
598 | If you're not using a hash table to keep track of unique ID's, store |
---|
599 | the child ID's and objects for the last 50 or so events in a circular |
---|
600 | array. In practice, this is enough to keep AccessibleObjectFromEvent() |
---|
601 | happy.<br> |
---|
602 | </div> |
---|
603 | <br> |
---|
604 | <big><a name="Not_all_MSAA_features_utilized_by_3rd"></a>Not all MSAA |
---|
605 | features utilized by 3rd party vendors</big><br> |
---|
606 | <br> |
---|
607 | <div style="margin-left: 40px;"> <span |
---|
608 | style="text-decoration: underline;">Problem</span>: The assistive |
---|
609 | technology does not use 50% of what's available in MSAA, e.g. MSAA |
---|
610 | caret, a lot of events, roles, states and methods. It's difficult to |
---|
611 | know which things to support.<br> |
---|
612 | <br> |
---|
613 | <span style="text-decoration: underline;">Solution</span>: Use this |
---|
614 | document to see what is generally considered important by assistive |
---|
615 | technology manufacturers. Contact the the top vendors early and often as |
---|
616 | you plan and implement your architecture, to see what's important to |
---|
617 | them. Implement only what's needed -- supporting everything would take |
---|
618 | too long for zero results.<br> |
---|
619 | </div> |
---|
620 | <br> |
---|
621 | <big><a name="Missing_functionality_in_MSAA"></a>Missing functionality |
---|
622 | in MSAA</big><br> |
---|
623 | <br> |
---|
624 | <div style="margin-left: 40px;"><span |
---|
625 | style="text-decoration: underline;">Problem and solutions:</span> |
---|
626 | Assistive technology vendors need some things which MSAA does not |
---|
627 | provide, such as:<br> |
---|
628 | </div> |
---|
629 | </div> |
---|
630 | <ul style="margin-left: 40px;"> |
---|
631 | <ul> |
---|
632 | <li>No way of signifying that a document has finished |
---|
633 | loading. Fire EVENT_OBJECT_STATECHANGE for a window/client/pane |
---|
634 | object when it starts to load a new document. Use STATE_BUSY to indicate |
---|
635 | that a new document is being loaded. When the loading has finished, fire |
---|
636 | another EVENT_OBJECT_STATECHANGE event and clear the STATE_BUSY |
---|
637 | flag. </li> |
---|
638 | <li>No method to get clipped/unclipped bounds of a piece of text |
---|
639 | within a text object. This is needed by screen magnifiers. No scrollTo |
---|
640 | method, also needed by screen magnifiers. Implement a custom interface |
---|
641 | for text objects, and support it through QueryInterface or QueryService |
---|
642 | if it's being implemented on a different object than IAccessible is. |
---|
643 | Support a scrollTo method which takes a text index, and a |
---|
644 | getClippedBounds and getUnclippedBounds method which takes a start and |
---|
645 | end index. Publish your custom interface.</li> |
---|
646 | <li>No way for assistive technology to know when scrolling has |
---|
647 | stopped. Fire the EVENT_SYSTEM_SCROLLINGEND event to indicate when |
---|
648 | scrolling has ended (try not to fire too many of these, wait until |
---|
649 | scrolling has truly stopped). There is no need to support |
---|
650 | EVENT_SYSTEM_SCROLLINGSTART, it is not used by assistive technology.<br> |
---|
651 | </li> |
---|
652 | </ul> |
---|
653 | <ul> |
---|
654 | <li>No support for document formatting or "DOM" as requested by |
---|
655 | some vendors: support a custom interface that gives them the formatting |
---|
656 | information they are requesting.<br> |
---|
657 | </li> |
---|
658 | </ul> |
---|
659 | </ul> |
---|
660 | <div style="margin-left: 40px;"><big><a name="Dueling_text_equivalents"></a>Dueling |
---|
661 | text equivalents</big><br> |
---|
662 | <br> |
---|
663 | <div style="margin-left: 40px;"><span |
---|
664 | style="text-decoration: underline;"> Problem</span>: There are three |
---|
665 | kinds of text equivalents, and it is difficult to know when to use each. |
---|
666 | Different applications behave differently in this regard. For example, |
---|
667 | Acrobat uses accessible value for text labels where as most programs use |
---|
668 | accessible name. There are different roles for text objects, |
---|
669 | ROLE_STATICTEXT and ROLE_TEXT (editable text), which seems to be used |
---|
670 | for non-editable text in many places.<br> |
---|
671 | <br> |
---|
672 | <span style="text-decoration: underline;">Solution</span>: Be as |
---|
673 | consistent with Internet Explorer as possible. Use accessible name for |
---|
674 | most text equivalents, and accessible value for URL's. Don't use |
---|
675 | accessible description unless you really do have a long description for |
---|
676 | the object you need to expose -- most assistive technology makes little |
---|
677 | use of it. Use ROLE_STATICTEXT for labels specific to dialog and UI |
---|
678 | controls, and always use ROLE_TEXT for document text even if the text is |
---|
679 | not editable (in that case use ROLE_TEXT with STATE_READONLY).<br> |
---|
680 | </div> |
---|
681 | <br> |
---|
682 | <big><a name="Issues_with_Links"></a>Issues with Links</big><br> |
---|
683 | <br> |
---|
684 | <div style="margin-left: 40px;"> <span |
---|
685 | style="text-decoration: underline;">Problem</span>: The assistive |
---|
686 | technology has inflexible heuristics when it comes to reading links. |
---|
687 | First, it won't read the object unless the states are correctly set. |
---|
688 | Second, it can mishandle the object if it cannot parse the whitespace |
---|
689 | according to its own rules.<br> |
---|
690 | <br> |
---|
691 | <span style="text-decoration: underline;">Solution</span>: Make sure |
---|
692 | the ROLE_LINK object and its child ROLE_TEXT objects all have |
---|
693 | STATE_LINKED set. For multi-line links with a line break in the middle, |
---|
694 | make sure there is no whitespace at the beginning or end of any of the |
---|
695 | accessible names, and make sure there is a \r\n where the line breaks |
---|
696 | occur in the accessible name for the ROLE_LINK. For an example of how to |
---|
697 | do this properly, see Internet Explorer or Gecko. Again, if it's not |
---|
698 | done exactly this way, some links will not be read.<br> |
---|
699 | </div> |
---|
700 | <br> |
---|
701 | <big><a name="MSAA_Implementation_is_Not_Performant"></a>MSAA |
---|
702 | Implementation is Not Performant</big><br> |
---|
703 | <br> |
---|
704 | <div style="margin-left: 40px;"><span |
---|
705 | style="text-decoration: underline;"> Problem</span>: The assistive |
---|
706 | technology may interact slowly with your application.<br> |
---|
707 | <br> |
---|
708 | <span style="text-decoration: underline;">Solution</span>: Try not to |
---|
709 | calculate the same things more than once or create the same objects more |
---|
710 | than once. For example, create and cache an object's children when you |
---|
711 | look for them in get_accChildCount(), so that you can just hand them |
---|
712 | back when asked for using get_accChild() or accNavigate(). Support |
---|
713 | IEnumVARIANT so that the MSAA client can ask for a number of children in |
---|
714 | one call. In custom interfaces, create methods that hand back a lot of |
---|
715 | data in one call, rather than requiring a large number of calls. Fewer |
---|
716 | calls are much better better because COM Marshaling is slow.<br> |
---|
717 | </div> |
---|
718 | <br> |
---|
719 | <big><a name="Differing_client_implementations"></a>Differing client |
---|
720 | implementations</big><br> |
---|
721 | <br> |
---|
722 | <div style="margin-left: 40px;"> <span |
---|
723 | style="text-decoration: underline;">Problem</span>: Every assistive |
---|
724 | technology uses MSAA differently.<br> |
---|
725 | <br> |
---|
726 | <span style="text-decoration: underline;">Solution</span>: We don't |
---|
727 | know of any outright conflicts in the differing uses of MSAA (yet). |
---|
728 | However, be on guard. If a vendors asks you to do something different |
---|
729 | from the spec, it's better to check with the other vendors before moving |
---|
730 | forward. Check to see what applications from Microsoft do in a similar |
---|
731 | situation.<br> |
---|
732 | </div> |
---|
733 | <br> |
---|
734 | <big><a name="Undocumented_Window_Class_Usage"></a>Undocumented Window |
---|
735 | Class Usage</big><br> |
---|
736 | <br> |
---|
737 | <div style="margin-left: 40px;"> <span |
---|
738 | style="text-decoration: underline;">Problem</span>: most assistive |
---|
739 | technologies won't use your MSAA implementation out of the box. They |
---|
740 | must list your window classes somewhere in their implementation, and |
---|
741 | then turn on MSAA support when a window of that class receives focus. |
---|
742 | The window class is also used to determine a host of hard-coded |
---|
743 | behaviors, such as whether or not a screen reader will load the entire |
---|
744 | MSAA tree into a special buffer for the user to navigate with screen |
---|
745 | reader commands. This is only supposed to occur for document navigation, |
---|
746 | not for UI/dialogs. where your application's keyboard commands will be |
---|
747 | solely used to navigate.<br> |
---|
748 | <br> |
---|
749 | <span style="text-decoration: underline;">Solution</span>: Contact each |
---|
750 | vendor and let them know what window classes you will be using MSAA for. |
---|
751 | If possible, use a different window class name for documents/content |
---|
752 | than you use for UI/dialogs. Or, do what Mozilla does - expose a |
---|
753 | control ID (GWL_ID) of 1 for content, and 0 for UI. Consistent window |
---|
754 | class names are important for the assistive technology vendors, so that |
---|
755 | they can determine what code to run for a given window. Don't change |
---|
756 | window class names after you have shipped a version.<br> |
---|
757 | </div> |
---|
758 | <br> |
---|
759 | <big><a name="Vendor_quirks"></a>Vendor quirks</big><br> |
---|
760 | <br> |
---|
761 | <div style="margin-left: 40px;"> <span |
---|
762 | style="text-decoration: underline;">Problem</span>: Because assistive |
---|
763 | technology tends to utilize MSAA as an additional solution resting on |
---|
764 | top of old hacks, rather than a completely clean and separate way to |
---|
765 | deal with an application, and because of the quirky nature of MSAA and |
---|
766 | of the inflexible heuristics that screen readers use, we do not have a |
---|
767 | "plug and play solution". In addition, assistive technology vendors are |
---|
768 | tiny companies, often scrambling to keep up with changes in the |
---|
769 | applications they already support, or new products other than yours |
---|
770 | which they need to support. It's very difficult to get vendors to spend |
---|
771 | time testing an MSAA implementation, send feedback or help find out why |
---|
772 | things aren't working. Time and version commitments often fall through. |
---|
773 | There is always a belated new version due around corner, after which you |
---|
774 | will be promised to be the next priority.<br> |
---|
775 | <br> |
---|
776 | <span style="text-decoration: underline;">Solution</span>: Try to reach |
---|
777 | out in a friendly manner to the assistive technology company. Be as easy |
---|
778 | to work with as you possibly can -- this includes being extremely |
---|
779 | responsive to their bug reports with new test builds, as well as being |
---|
780 | very communicative about what you have changed and when. Do as much work |
---|
781 | as you possibly can without their help. See if your organization can |
---|
782 | offer something they can't get for themselves. Be patient, and set your |
---|
783 | expectations to a reasonable level. Realize that it's about both pride |
---|
784 | and revenue for these companies, and that they need to sell a lot of |
---|
785 | copies of their software to make up the work they put in to support |
---|
786 | your app. Remember that no matter how small they are, you need them more |
---|
787 | than they need you, unless your application's accessibility is being |
---|
788 | demanded by end-users.</div> |
---|
789 | </div> |
---|
790 | <h2><a name="geckoimpl"></a>4. Example: How Gecko and Mozilla Implement |
---|
791 | MSAA<br> |
---|
792 | </h2> |
---|
793 | <p style="margin-left: 40px;">The <a |
---|
794 | href="http://lxr.mozilla.org/seamonkey/source/accessible/">Accessible |
---|
795 | module</a> is where the Mozilla MSAA implementation lives. Feel free to <a |
---|
796 | href="http://lxr.mozilla.org/seamonkey/source/accessible/">peruse the |
---|
797 | source code in the accessible module</a> whenever you want to see how |
---|
798 | something can be implemented.<br> |
---|
799 | </p> |
---|
800 | <p style="margin-left: 40px;">The accessible module is also where |
---|
801 | support for Sun's <a |
---|
802 | href="http://wwws.sun.com/software/star/gnome/accessibility/architecture.html">ATK</a> |
---|
803 | accessibility API for Linux and UNIX is implemented. For documentation |
---|
804 | specific to the Mozilla ATK effort, supported by Sun Microsystems, see |
---|
805 | the <a |
---|
806 | href="http://www.mozilla.org/projects/ui/accessibility/unix/index.html">Mozilla |
---|
807 | accessibility on Unix</a> page.</p> |
---|
808 | <h3 style="margin-left: 40px;"><a name="Creation_of_IAccessible_Objects"></a>Creation |
---|
809 | of IAccessible Objects<br> |
---|
810 | </h3> |
---|
811 | <ul style="margin-left: 40px;"> |
---|
812 | <p> The first thing that happens when an assistive technology wants to |
---|
813 | watch our application is that calls the Windows API function |
---|
814 | AccessibleObjectFromWindow(). This usually happens right after a window |
---|
815 | gets focused.<br> |
---|
816 | </p> |
---|
817 | <p>When the WIN32 API function AccessibleObjectFromWindow() is |
---|
818 | called, Windows sends the window in question a <a |
---|
819 | href="http://lxr.mozilla.org/seamonkey/search?string=WM_GETOBJECT">WM_GETOBJECT</a> |
---|
820 | message requesting an IAccessible for your root object in the window. In |
---|
821 | our case, this event is received in <a |
---|
822 | href="http://lxr.mozilla.org/seamonkey/source/widget/src/windows/nsWindow.cpp#4370">mozilla/widget/src/windows/nsWindow.cpp</a>. |
---|
823 | We send back an IAccessible pointer which can be used by the client to |
---|
824 | get information about this root object. The assistive technology will |
---|
825 | use that root IAccessible to traverse the rest of the object tree, by |
---|
826 | navigating to children and then siblings, etc. Every navigation function |
---|
827 | such as accNavigate(), get_accChild() and get_accParent() returns an |
---|
828 | IAccessible pointer. <br> |
---|
829 | </p> |
---|
830 | <p>To create the root IAccessible for a window the first time it gets |
---|
831 | the <a |
---|
832 | href="http://lxr.mozilla.org/seamonkey/search?string=WM_GETOBJECT">WM_GETOBJECT</a> |
---|
833 | message in, nsWindow.cpp first generates an internal event called <a |
---|
834 | href="http://lxr.mozilla.org/seamonkey/search?string=NS_GETACCESSIBLE">NS_GETACCESSIBLE</a>, |
---|
835 | which is handled in <a |
---|
836 | href="http://lxr.mozilla.org/seamonkey/source/layout/html/base/src/nsPresShell.cpp#6345">PresShell::HandleEventInternal()</a> |
---|
837 | via the creation of an <a |
---|
838 | href="http://lxr.mozilla.org/seamonkey/find?string=msaa/nsDocAccessibleWrap">nsDocAccessibleWrap</a> |
---|
839 | for an inner window or <a |
---|
840 | href="http://lxr.mozilla.org/seamonkey/find?string=msaa/nsRootAccessibleWrap">nsRootAccessibleWrap</a> |
---|
841 | for a top level window. These classes implement both nsIAccessible, our |
---|
842 | cross platform API, as well as IAccessible, which is specific to |
---|
843 | Windows/MSAA/COM. The cross-platform nsDocAccessible and |
---|
844 | nsRootAccessible classes they inherit from are then told to start |
---|
845 | listening for DOM, page load and scroll events. These events cause |
---|
846 | MSAA-specific events, such as EVENT_OBJECT_FOCUS or |
---|
847 | EVENT_OBJECT_STATECHANGE, to fire on UI and document objects within the |
---|
848 | applicable window. We'll explain more about events later in this section.<br> |
---|
849 | </p> |
---|
850 | <p>Until the WM_GETOBJECT message is processed, the Gecko |
---|
851 | accessibility service is not used, and thus the accessibility.dll is not |
---|
852 | loaded, so there is almost zero overhead for accessibility API support |
---|
853 | in Mozilla or Gecko, in the general case. Once the accessibility |
---|
854 | service is created, however, Gecko loads code to create an object on |
---|
855 | demand for every UI or document object that should support IAccessible. |
---|
856 | The created objects are cached in a hash table, and shutdown when |
---|
857 | they're no longer needed. They may still exist in memory in a |
---|
858 | nonfunctional state until the assistive technology completely releases |
---|
859 | them. See the section on accessible roles to see what kinds of objects |
---|
860 | Gecko support IAccessible for.<br> |
---|
861 | </p> |
---|
862 | </ul> |
---|
863 | <div style="margin-left: 40px;"> </div> |
---|
864 | <h3 style="margin-left: 40px;"><a |
---|
865 | name="The_Accessible_Tree_vs._the_DOM_Tree"></a>The Accessible Tree |
---|
866 | vs. the DOM Tree<br> |
---|
867 | </h3> |
---|
868 | <div style="margin-left: 40px;"> </div> |
---|
869 | <ul style="margin-left: 40px;"> |
---|
870 | <p>After the root or doc accessible for a window has been created and |
---|
871 | handed back to the MSAA client, it is used to traverse the rest of the |
---|
872 | IAccessible tree using accNavigation, get_accChild and get_accParent. |
---|
873 | Any IAccessible will support those methods. We also support |
---|
874 | IEnumVARIANT::Next() which allows for fast marshaling of all of an |
---|
875 | objects children to a client via COM. In other words, the assistive |
---|
876 | technology can say "give me all 20 children of this object into this |
---|
877 | array". That's much faster than 20 separate calls, one for each child.<br> |
---|
878 | </p> |
---|
879 | <p>In Mozilla, the client has another choice for tree navigation -- |
---|
880 | it can utilize data stored in the DOM via Mozilla's custom <a |
---|
881 | href="http://lxr.mozilla.org/seamonkey/source/accessible/public/msaa/ISimpleDOMNode.idl">ISimpleDOMNode</a> |
---|
882 | COM interface. Any IAccessible can be used to QueryInterface to an |
---|
883 | ISimpleDOMNode, and vice versa for a round trip. However, one might QI |
---|
884 | ISimpleDOMNode to IAccessible only to find it is null, which means that |
---|
885 | particular node in question is not exposed in the IAccessible tree. See |
---|
886 | the following diagram for examples of nodes that do no support |
---|
887 | IAccessible.<br> |
---|
888 | </p> |
---|
889 | </ul> |
---|
890 | <div style="margin-left: 40px;"> </div> |
---|
891 | <h3 style="margin-left: 40px;">MSAA tree vs. DOM tree - what's the |
---|
892 | relationship?</h3> |
---|
893 | <div style="margin-left: 40px;"> </div> |
---|
894 | <ul style="margin-left: 40px;"> |
---|
895 | <p> <img |
---|
896 | src="http://www.mozilla.org/projects/ui/accessibility/images/tree-relativity.gif" |
---|
897 | alt="Diagram showing MSAA tree is a subset of the DOM tree" |
---|
898 | title="Diagram showing MSAA tree is a subset of the DOM tree"> </p> |
---|
899 | The MSAA tree and the DOM tree are parallel structures, although the |
---|
900 | MSAA tree is a subset of the DOM tree. <code>QueryInterface()</code> can |
---|
901 | be used to switch between the interfaces used in the two trees |
---|
902 | (IAccessible and ISimpleDOMNode). If there is no MSAA node for a DOM |
---|
903 | node, pAccessible-><code>QueryInterface(IID_IAccessible)</code> |
---|
904 | will return null. |
---|
905 | </ul> |
---|
906 | <h3 style="margin-left: 40px;"><a |
---|
907 | name="The_Implementations_Behind_IAccessible"></a>A Variety of |
---|
908 | Implementations for IAccessible</h3> |
---|
909 | <div style="margin-left: 40px;"> |
---|
910 | <div style="margin-left: 40px;"> |
---|
911 | <p>There are two main kinds of classes in Mozilla's accessibility class |
---|
912 | hierarchy, platform-specifc and cross-platform. All of the |
---|
913 | platform-specific classes have the word "Wrap" appended to them. The |
---|
914 | Wrap classes contain implementations and interfaces specific to MSAA or |
---|
915 | ATK. These platform-specific classes inherit from cross-platform |
---|
916 | classes, where the most of the implementation is done. For example, |
---|
917 | nsAccessibleWrap inherits from nsAccessible. Every accessible object in |
---|
918 | the MSAA tree has an implementation dertived from nsAccessible, which |
---|
919 | exposes accessibility information through nsIAccessible, in a generic |
---|
920 | cross-platform manner. <br> |
---|
921 | </p> |
---|
922 | <p>This default implementation for nsIAccessible knows how to use |
---|
923 | nsAccessibleTreeWalker to walk Mozilla's content DOM and frame tree, |
---|
924 | exposing only the objects that are needed for accessibility. The |
---|
925 | nsAccessibleTreeWalker class knows what it needs to expose by asking |
---|
926 | each DOM node's primary frame (a Gecko formatting object) for an |
---|
927 | nsIAccessible, using the nsIFrame::GetAccessible() method. If |
---|
928 | nsAccessibleTreeWalker gets an nsIAccessible back, then the DOM node |
---|
929 | considered to be an accessible object. The nsIAccessible that is |
---|
930 | returned is either a new one, or reused from the accessibility cache, |
---|
931 | and the correct type of accessibility object to correctly expose that |
---|
932 | DOM node through the cross-platform nsIAccessible and MSAA-specific |
---|
933 | IAccessible interfaces.<br> |
---|
934 | </p> |
---|
935 | <p>Every accessibility object created must be cached, and must inherit |
---|
936 | from nsAccessibleWrap so that it supports a base implementation of |
---|
937 | nsIAccessible and IAccessible. Apart from that, it is free to override |
---|
938 | IAccessible or nsIAccessible methods. In this way each class is tailored |
---|
939 | to the specific abilities and properties of the HTML or XUL/UI objects |
---|
940 | it applies to, and can support both MSAA, ATK and hopefully any future |
---|
941 | accessibility API's we need to support. For example |
---|
942 | nsHTMLButtonAccessible overrides nsIAccessible::GetAccRole to expose |
---|
943 | ROLE_BUTTON for IAccessible::get_accRole which uses that. <br> |
---|
944 | </p> |
---|
945 | </div> |
---|
946 | </div> |
---|
947 | <ul style="margin-left: 40px;"> |
---|
948 | <p>A more complicated set of nsIAccessible methods which can be |
---|
949 | overridden are GetAccFirstChild/GetAccLastChild/GetAccChildCount, which |
---|
950 | allows for objects to define their own decendant subtrees. The default |
---|
951 | behavior for nsIAccessible::getAccFirstChild is to instantiate a |
---|
952 | nsDOMTreeWalker, and ask it for the first child. However, |
---|
953 | nsImageAccessible overrides getAccFirstChild, returning the first area |
---|
954 | of an image map if there is one, otherwise nsnull. This is necessary |
---|
955 | because the image map areas can be in a completely different area of the |
---|
956 | DOM from the image they apply to.<br> |
---|
957 | </p> |
---|
958 | </ul> |
---|
959 | <div style="margin-left: 40px;"> </div> |
---|
960 | <h3 style="margin-left: 40px;"><a name="Generating_MSAA_Events"></a>Generating |
---|
961 | MSAA Events</h3> |
---|
962 | <div style="margin-left: 40px;"> </div> |
---|
963 | <ul style="margin-left: 40px;"> |
---|
964 | <p>First, keep in mind that most MSAA events aren't utilized by |
---|
965 | accessibility aids. Therefore we implement only the handful that matter. |
---|
966 | See the <a |
---|
967 | href="file:///c%7C/moz/mozdocs/mozilla-org/html/projects/ui/accessibility/accessible-architecture.html#events">Events</a> |
---|
968 | cheat sheet above for the list of events we implement. By far the most |
---|
969 | important one is EVENT_OBJECT_FOCUS.<br> |
---|
970 | </p> |
---|
971 | <p>When a potential accessibility-related event occurs within |
---|
972 | Mozilla, it is typically listened for by nsDocAccessible or |
---|
973 | nsRootAccessible. The event listeners on these classes call |
---|
974 | FireToolkitEvent(), which is implemented for every accessible. |
---|
975 | Eventually, the event ends up at nsDocAccessibleWrap::FireToolkitEvent() |
---|
976 | which calls NotifyWinEvent from the Win32 API. NotifyWinEvent is passed |
---|
977 | arguments for the window the event occurred in, and the ID of the child |
---|
978 | within that window. Accessibility aids use the Win32 call |
---|
979 | SetWinEventHook() to register as a listener for these events. Creating |
---|
980 | a unique child ID for every object within a window can be difficult, |
---|
981 | see the problem and solution for <a |
---|
982 | href="file:///c%7C/moz/mozdocs/mozilla-org/html/projects/ui/accessibility/accessible-architecture.html#Hacky_caret_tracking_not_working">no |
---|
983 | unique child ID for object in window</a>.<br> |
---|
984 | </p> |
---|
985 | <p>The assistive technology chooses which events it is interested in |
---|
986 | learning more about by calling the Win32 method |
---|
987 | AccessibleObjectFromEvent, which returns the IAccessible to the node |
---|
988 | corresponding to the child number that had been indicated from |
---|
989 | NotifyWinEvent(). This ends up asking |
---|
990 | nsDocAccessibleWrap::get_accChild() for a child IAccessible which |
---|
991 | matches the child ID we indicated through NotifyWinEvent(). </p> |
---|
992 | <p>In Mozilla, we use the DOM node pointer in the accessible object |
---|
993 | as a basis for its child ID, which is also used as a hash key into our |
---|
994 | cache. We also negate the 32 bit value so that it is always <0, |
---|
995 | telling us that they're really looking for the IAccessible for an event, |
---|
996 | not child number x. During the callback, we look up the original |
---|
997 | accessible node in the nsDocAccessible's cache and return it. <br> |
---|
998 | </p> |
---|
999 | </ul> |
---|
1000 | <div style="margin-left: 40px;"> </div> |
---|
1001 | <div style="margin-left: 40px;"> </div> |
---|
1002 | <h2><a name="feedback"></a>5. Feedback</h2> |
---|
1003 | <div style="margin-left: 40px;">How can this document be improved? Was |
---|
1004 | it useful? Questions? Contact <a href="mailto:aaronl@netscape.com">aaronl@netscape.com</a><br> |
---|
1005 | </div> |
---|
1006 | </body> |
---|
1007 | </html> |
---|