Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(902)

Side by Side Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js

Issue 2601333002: Update json_schema_compiler to handle the Automation extension API (Closed)
Patch Set: Fix select_to_speak Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview Handles automation from a desktop automation node. 6 * @fileoverview Handles automation from a desktop automation node.
7 */ 7 */
8 8
9 goog.provide('DesktopAutomationHandler'); 9 goog.provide('DesktopAutomationHandler');
10 10
11 goog.require('AutomationObjectConstructorInstaller');
12 goog.require('BaseAutomationHandler'); 11 goog.require('BaseAutomationHandler');
13 goog.require('ChromeVoxState'); 12 goog.require('ChromeVoxState');
13 goog.require('CustomAutomationEvent');
14 goog.require('Stubs'); 14 goog.require('Stubs');
15 goog.require('editing.TextEditHandler'); 15 goog.require('editing.TextEditHandler');
16 16
17 goog.scope(function() { 17 goog.scope(function() {
18 var AutomationEvent = chrome.automation.AutomationEvent; 18 var AutomationEvent = chrome.automation.AutomationEvent;
19 var AutomationNode = chrome.automation.AutomationNode; 19 var AutomationNode = chrome.automation.AutomationNode;
20 var Dir = constants.Dir; 20 var Dir = constants.Dir;
21 var EventType = chrome.automation.EventType; 21 var EventType = chrome.automation.EventType;
22 var RoleType = chrome.automation.RoleType; 22 var RoleType = chrome.automation.RoleType;
23 23
(...skipping 12 matching lines...) Expand all
36 */ 36 */
37 this.textEditHandler_ = null; 37 this.textEditHandler_ = null;
38 38
39 /** 39 /**
40 * The last time we handled a value changed event. 40 * The last time we handled a value changed event.
41 * @type {!Date} 41 * @type {!Date}
42 * @private 42 * @private
43 */ 43 */
44 this.lastValueChanged_ = new Date(0); 44 this.lastValueChanged_ = new Date(0);
45 45
46 var e = EventType; 46 this.addListener_(EventType.ACTIVEDESCENDANTCHANGED,
47 this.addListener_(e.activedescendantchanged, this.onActiveDescendantChanged); 47 this.onActiveDescendantChanged);
48 this.addListener_(e.alert, this.onAlert); 48 this.addListener_(EventType.ALERT,
49 this.addListener_(e.ariaAttributeChanged, this.onAriaAttributeChanged); 49 this.onAlert);
50 this.addListener_(e.autocorrectionOccured, this.onEventIfInRange); 50 this.addListener_(EventType.ARIA_ATTRIBUTE_CHANGED,
51 this.addListener_(e.checkedStateChanged, this.onCheckedStateChanged); 51 this.onAriaAttributeChanged);
52 this.addListener_(e.childrenChanged, this.onActiveDescendantChanged); 52 this.addListener_(EventType.AUTOCORRECTION_OCCURED,
53 this.addListener_(e.expandedChanged, this.onEventIfInRange); 53 this.onEventIfInRange);
54 this.addListener_(e.focus, this.onFocus); 54 this.addListener_(EventType.CHECKED_STATE_CHANGED,
55 this.addListener_(e.hover, this.onHover); 55 this.onCheckedStateChanged);
56 this.addListener_(e.invalidStatusChanged, this.onEventIfInRange); 56 this.addListener_(EventType.CHILDREN_CHANGED,
57 this.addListener_(e.loadComplete, this.onLoadComplete); 57 this.onActiveDescendantChanged);
58 this.addListener_(e.menuEnd, this.onMenuEnd); 58 this.addListener_(EventType.EXPANDED_CHANGED,
59 this.addListener_(e.menuListItemSelected, this.onEventIfSelected); 59 this.onEventIfInRange);
60 this.addListener_(e.menuStart, this.onMenuStart); 60 this.addListener_(EventType.FOCUS,
61 this.addListener_(e.rowCollapsed, this.onEventIfInRange); 61 this.onFocus);
62 this.addListener_(e.rowExpanded, this.onEventIfInRange); 62 this.addListener_(EventType.HOVER,
63 this.addListener_(e.scrollPositionChanged, this.onScrollPositionChanged); 63 this.onHover);
64 this.addListener_(e.selection, this.onSelection); 64 this.addListener_(EventType.INVALID_STATUS_CHANGED,
65 this.addListener_(e.textChanged, this.onTextChanged); 65 this.onEventIfInRange);
66 this.addListener_(e.textSelectionChanged, this.onTextSelectionChanged); 66 this.addListener_(EventType.LOAD_COMPLETE,
67 this.addListener_(e.valueChanged, this.onValueChanged); 67 this.onLoadComplete);
68 this.addListener_(EventType.MENU_END,
69 this.onMenuEnd);
70 this.addListener_(EventType.MENU_LIST_ITEM_SELECTED,
71 this.onEventIfSelected);
72 this.addListener_(EventType.MENU_START,
73 this.onMenuStart);
74 this.addListener_(EventType.ROW_COLLAPSED,
75 this.onEventIfInRange);
76 this.addListener_(EventType.ROW_EXPANDED,
77 this.onEventIfInRange);
78 this.addListener_(EventType.SCROLL_POSITION_CHANGED,
79 this.onScrollPositionChanged);
80 this.addListener_(EventType.SELECTION,
81 this.onSelection);
82 this.addListener_(EventType.TEXT_CHANGED,
83 this.onTextChanged);
84 this.addListener_(EventType.TEXT_SELECTION_CHANGED,
85 this.onTextSelectionChanged);
86 this.addListener_(EventType.VALUE_CHANGED,
87 this.onValueChanged);
68 88
69 AutomationObjectConstructorInstaller.init(node, function() { 89 chrome.automation.getFocus((function(focus) {
70 chrome.automation.getFocus((function(focus) { 90 if (ChromeVoxState.instance.mode != ChromeVoxMode.FORCE_NEXT)
71 if (ChromeVoxState.instance.mode != ChromeVoxMode.FORCE_NEXT) 91 return;
72 return;
73 92
74 if (focus) { 93 if (focus) {
75 this.onFocus( 94 var event = new CustomAutomationEvent(EventType.FOCUS, focus, 'page');
76 new chrome.automation.AutomationEvent( 95 this.onFocus(event);
77 EventType.focus, focus, 'page')); 96 }
78 } 97 }).bind(this));
79 }).bind(this));
80 }.bind(this));
81 }; 98 };
82 99
83 /** 100 /**
84 * Time to wait until processing more value changed events. 101 * Time to wait until processing more value changed events.
85 * @const {number} 102 * @const {number}
86 */ 103 */
87 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS = 500; 104 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS = 500;
88 105
89 /** 106 /**
90 * Controls announcement of non-user-initiated events. 107 * Controls announcement of non-user-initiated events.
91 * @type {boolean} 108 * @type {boolean}
92 */ 109 */
93 DesktopAutomationHandler.announceActions = false; 110 DesktopAutomationHandler.announceActions = false;
94 111
95 DesktopAutomationHandler.prototype = { 112 DesktopAutomationHandler.prototype = {
96 __proto__: BaseAutomationHandler.prototype, 113 __proto__: BaseAutomationHandler.prototype,
97 114
98 /** @override */ 115 /** @override */
99 willHandleEvent_: function(evt) { 116 willHandleEvent_: function(evt) {
100 return !cvox.ChromeVox.isActive; 117 return !cvox.ChromeVox.isActive;
101 }, 118 },
102 119
103 /** 120 /**
104 * Provides all feedback once ChromeVox's focus changes. 121 * Provides all feedback once ChromeVox's focus changes.
105 * @param {!AutomationEvent} evt 122 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
106 */ 123 */
107 onEventDefault: function(evt) { 124 onEventDefault: function(evt) {
108 var node = evt.target; 125 var node = evt.target;
109 if (!node) 126 if (!node)
110 return; 127 return;
111 128
112 // Decide whether to announce and sync this event. 129 // Decide whether to announce and sync this event.
113 if (!DesktopAutomationHandler.announceActions && evt.eventFrom == 'action') 130 if (!DesktopAutomationHandler.announceActions && evt.eventFrom == 'action')
114 return; 131 return;
115 132
(...skipping 17 matching lines...) Expand all
133 output.withBraille( 150 output.withBraille(
134 ChromeVoxState.instance.currentRange, prevRange, evt.type); 151 ChromeVoxState.instance.currentRange, prevRange, evt.type);
135 } else { 152 } else {
136 // Delegate event handling to the text edit handler for braille. 153 // Delegate event handling to the text edit handler for braille.
137 this.textEditHandler_.onEvent(evt); 154 this.textEditHandler_.onEvent(evt);
138 } 155 }
139 output.go(); 156 output.go();
140 }, 157 },
141 158
142 /** 159 /**
143 * @param {!AutomationEvent} evt 160 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
144 */ 161 */
145 onEventIfInRange: function(evt) { 162 onEventIfInRange: function(evt) {
146 if (!this.shouldOutput_(evt)) 163 if (!this.shouldOutput_(evt))
147 return; 164 return;
148 165
149 var prev = ChromeVoxState.instance.currentRange; 166 var prev = ChromeVoxState.instance.currentRange;
150 if (prev.contentEquals(cursors.Range.fromNode(evt.target)) || 167 if (prev.contentEquals(cursors.Range.fromNode(evt.target)) ||
151 evt.target.state.focused) { 168 evt.target.state.focused) {
152 // Category flush here since previous focus events via navigation can 169 // Category flush here since previous focus events via navigation can
153 // cause double speak. 170 // cause double speak.
154 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); 171 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH);
155 172
156 // Intentionally skip setting range. 173 // Intentionally skip setting range.
157 new Output() 174 new Output()
158 .withRichSpeechAndBraille(cursors.Range.fromNode(evt.target), 175 .withRichSpeechAndBraille(cursors.Range.fromNode(evt.target),
159 prev, 176 prev,
160 Output.EventType.NAVIGATE) 177 Output.EventType.NAVIGATE)
161 .go(); 178 .go();
162 } 179 }
163 }, 180 },
164 181
165 /** 182 /**
166 * @param {!AutomationEvent} evt 183 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
167 */ 184 */
168 onEventIfSelected: function(evt) { 185 onEventIfSelected: function(evt) {
169 if (evt.target.state.selected) 186 if (evt.target.state.selected)
170 this.onEventDefault(evt); 187 this.onEventDefault(evt);
171 }, 188 },
172 189
173 /** 190 /**
174 * @param {!AutomationEvent} evt 191 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
175 */ 192 */
176 onEventWithFlushedOutput: function(evt) { 193 onEventWithFlushedOutput: function(evt) {
177 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); 194 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH);
178 this.onEventDefault(evt); 195 this.onEventDefault(evt);
179 }, 196 },
180 197
181 /** 198 /**
182 * @param {!AutomationEvent} evt 199 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
183 */ 200 */
184 onAriaAttributeChanged: function(evt) { 201 onAriaAttributeChanged: function(evt) {
185 if (evt.target.state.editable) 202 if (evt.target.state.editable)
186 return; 203 return;
187 this.onEventIfInRange(evt); 204 this.onEventIfInRange(evt);
188 }, 205 },
189 206
190 /** 207 /**
191 * @param {!AutomationEvent} evt 208 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
192 */ 209 */
193 onHover: function(evt) { 210 onHover: function(evt) {
194 if (ChromeVoxState.instance.currentRange && 211 if (ChromeVoxState.instance.currentRange &&
195 evt.target == ChromeVoxState.instance.currentRange.start.node) 212 evt.target == ChromeVoxState.instance.currentRange.start.node)
196 return; 213 return;
197 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); 214 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH);
198 this.onEventDefault(evt); 215 this.onEventDefault(evt);
199 }, 216 },
200 217
201 /** 218 /**
202 * Makes an announcement without changing focus. 219 * Makes an announcement without changing focus.
203 * @param {!AutomationEvent} evt 220 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
204 */ 221 */
205 onActiveDescendantChanged: function(evt) { 222 onActiveDescendantChanged: function(evt) {
206 if (!evt.target.activeDescendant || !evt.target.state.focused) 223 if (!evt.target.activeDescendant || !evt.target.state.focused)
207 return; 224 return;
208 this.onEventDefault(new chrome.automation.AutomationEvent( 225 var event = new CustomAutomationEvent(
209 EventType.focus, evt.target.activeDescendant, evt.eventFrom)); 226 EventType.FOCUS, evt.target.activeDescendant, evt.eventFrom);
227 this.onEventDefault(event);
210 }, 228 },
211 229
212 /** 230 /**
213 * Makes an announcement without changing focus. 231 * Makes an announcement without changing focus.
214 * @param {!AutomationEvent} evt 232 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
215 */ 233 */
216 onAlert: function(evt) { 234 onAlert: function(evt) {
217 var node = evt.target; 235 var node = evt.target;
218 if (!node || !this.shouldOutput_(evt)) 236 if (!node || !this.shouldOutput_(evt))
219 return; 237 return;
220 238
221 var range = cursors.Range.fromNode(node); 239 var range = cursors.Range.fromNode(node);
222 240
223 new Output().withSpeechAndBraille(range, null, evt.type).go(); 241 new Output().withSpeechAndBraille(range, null, evt.type).go();
224 }, 242 },
225 243
226 /** 244 /**
227 * Provides all feedback once a checked state changed event fires. 245 * Provides all feedback once a checked state changed event fires.
228 * @param {!AutomationEvent} evt 246 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
229 */ 247 */
230 onCheckedStateChanged: function(evt) { 248 onCheckedStateChanged: function(evt) {
231 if (!AutomationPredicate.checkable(evt.target)) 249 if (!AutomationPredicate.checkable(evt.target))
232 return; 250 return;
233 251
234 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); 252 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH);
235 this.onEventIfInRange( 253 var event = new CustomAutomationEvent(
236 new chrome.automation.AutomationEvent( 254 EventType.CHECKED_STATE_CHANGED, evt.target, evt.eventFrom);
237 EventType.checkedStateChanged, evt.target, evt.eventFrom)); 255 this.onEventIfInRange(event);
238 }, 256 },
239 257
240 /** 258 /**
241 * Provides all feedback once a focus event fires. 259 * Provides all feedback once a focus event fires.
242 * @param {!AutomationEvent} evt 260 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
243 */ 261 */
244 onFocus: function(evt) { 262 onFocus: function(evt) {
245 // Invalidate any previous editable text handler state. 263 // Invalidate any previous editable text handler state.
246 this.textEditHandler_ = null; 264 this.textEditHandler_ = null;
247 265
248 var node = evt.target; 266 var node = evt.target;
249 267
250 // Discard focus events on embeddedObject. 268 // Discard focus events on embeddedObject.
251 if (node.role == RoleType.embeddedObject) 269 if (node.role == RoleType.EMBEDDED_OBJECT)
252 return; 270 return;
253 271
254 this.createTextEditHandlerIfNeeded_(evt.target); 272 this.createTextEditHandlerIfNeeded_(evt.target);
255 273
256 // Category flush speech triggered by events with no source. This includes 274 // Category flush speech triggered by events with no source. This includes
257 // views. 275 // views.
258 if (evt.eventFrom == '') 276 if (evt.eventFrom == '')
259 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); 277 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH);
260 if (!node.root) 278 if (!node.root)
261 return; 279 return;
262 280
263 var root = AutomationUtil.getTopLevelRoot(node.root); 281 var root = AutomationUtil.getTopLevelRoot(node.root);
264
265 // If we're crossing out of a root, save it in case it needs recovering. 282 // If we're crossing out of a root, save it in case it needs recovering.
266 var prevRange = ChromeVoxState.instance.currentRange; 283 var prevRange = ChromeVoxState.instance.currentRange;
267 var prevNode = prevRange ? prevRange.start.node : null; 284 var prevNode = prevRange ? prevRange.start.node : null;
268 if (prevNode) { 285 if (prevNode) {
269 var prevRoot = AutomationUtil.getTopLevelRoot(prevNode); 286 var prevRoot = AutomationUtil.getTopLevelRoot(prevNode);
270 if (prevRoot && prevRoot !== root) 287 if (prevRoot && prevRoot !== root)
271 ChromeVoxState.instance.focusRecoveryMap.set(prevRoot, prevRange); 288 ChromeVoxState.instance.focusRecoveryMap.set(prevRoot, prevRange);
272 } 289 }
273
274 // If a previous node was saved for this focus, restore it. 290 // If a previous node was saved for this focus, restore it.
275 var savedRange = ChromeVoxState.instance.focusRecoveryMap.get(root); 291 var savedRange = ChromeVoxState.instance.focusRecoveryMap.get(root);
276 ChromeVoxState.instance.focusRecoveryMap.delete(root); 292 ChromeVoxState.instance.focusRecoveryMap.delete(root);
277 if (savedRange) { 293 if (savedRange) {
278 ChromeVoxState.instance.navigateToRange(savedRange, false); 294 ChromeVoxState.instance.navigateToRange(savedRange, false);
279 return; 295 return;
280 } 296 }
281 297 var event = new CustomAutomationEvent(EventType.FOCUS, node, evt.eventFrom);
282 this.onEventDefault(new chrome.automation.AutomationEvent( 298 this.onEventDefault(event);
283 EventType.focus, node, evt.eventFrom));
284 }, 299 },
285 300
286 /** 301 /**
287 * Provides all feedback once a load complete event fires. 302 * Provides all feedback once a load complete event fires.
288 * @param {!AutomationEvent} evt 303 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
289 */ 304 */
290 onLoadComplete: function(evt) { 305 onLoadComplete: function(evt) {
291 chrome.automation.getFocus(function(focus) { 306 chrome.automation.getFocus(function(focus) {
292 if (!focus || !AutomationUtil.isDescendantOf(focus, evt.target)) 307 if (!focus || !AutomationUtil.isDescendantOf(focus, evt.target))
293 return; 308 return;
294 309
295 // Create text edit handler, if needed, now in order not to miss initial 310 // Create text edit handler, if needed, now in order not to miss initial
296 // value change if text field has already been focused when initializing 311 // value change if text field has already been focused when initializing
297 // ChromeVox. 312 // ChromeVox.
298 this.createTextEditHandlerIfNeeded_(focus); 313 this.createTextEditHandlerIfNeeded_(focus);
299 314
300 // If auto read is set, skip focus recovery and start reading from the top . 315 // If auto read is set, skip focus recovery and start reading from the top .
301 if (localStorage['autoRead'] == 'true' && 316 if (localStorage['autoRead'] == 'true' &&
302 AutomationUtil.getTopLevelRoot(evt.target) == evt.target) { 317 AutomationUtil.getTopLevelRoot(evt.target) == evt.target) {
303 ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(evt.targe t)); 318 ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(evt.targe t));
304 cvox.ChromeVox.tts.stop(); 319 cvox.ChromeVox.tts.stop();
305 CommandHandler.onCommand('readFromHere'); 320 CommandHandler.onCommand('readFromHere');
306 return; 321 return;
307 } 322 }
308 323
309 // If initial focus was already placed on this page (e.g. if a user starts 324 // If initial focus was already placed on this page (e.g. if a user starts
310 // tabbing before load complete), then don't move ChromeVox's position on 325 // tabbing before load complete), then don't move ChromeVox's position on
311 // the page. 326 // the page.
312 if (ChromeVoxState.instance.currentRange && 327 if (ChromeVoxState.instance.currentRange &&
313 ChromeVoxState.instance.currentRange.start.node.root == focus.root) 328 ChromeVoxState.instance.currentRange.start.node.root == focus.root)
314 return; 329 return;
315 330
316 var o = new Output(); 331 var o = new Output();
317 if (focus.role == RoleType.rootWebArea) { 332 if (focus.role == RoleType.ROOT_WEB_AREA) {
318 // Restore to previous position. 333 // Restore to previous position.
319 var url = focus.docUrl; 334 var url = focus.docUrl;
320 url = url.substring(0, url.indexOf('#')) || url; 335 url = url.substring(0, url.indexOf('#')) || url;
321 var pos = cvox.ChromeVox.position[url]; 336 var pos = cvox.ChromeVox.position[url];
322 if (pos) { 337 if (pos) {
323 focus = AutomationUtil.hitTest(focus.root, pos) || focus; 338 focus = AutomationUtil.hitTest(focus.root, pos) || focus;
324 if (focus != focus.root) 339 if (focus != focus.root)
325 o.format('$name', focus.root); 340 o.format('$name', focus.root);
326 } 341 }
327 } 342 }
328 ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(focus)); 343 ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(focus));
329 if (!this.shouldOutput_(evt)) 344 if (!this.shouldOutput_(evt))
330 return; 345 return;
331 346
332 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); 347 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH);
333 o.withRichSpeechAndBraille( 348 o.withRichSpeechAndBraille(
334 ChromeVoxState.instance.currentRange, null, evt.type).go(); 349 ChromeVoxState.instance.currentRange, null, evt.type).go();
335 }.bind(this)); 350 }.bind(this));
336 }, 351 },
337 352
338 /** 353 /**
339 * Provides all feedback once a text changed event fires. 354 * Provides all feedback once a text changed event fires.
340 * @param {!AutomationEvent} evt 355 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
341 */ 356 */
342 onTextChanged: function(evt) { 357 onTextChanged: function(evt) {
343 if (evt.target.state.editable) 358 if (evt.target.state.editable)
344 this.onEditableChanged_(evt); 359 this.onEditableChanged_(evt);
345 }, 360 },
346 361
347 /** 362 /**
348 * Provides all feedback once a text selection changed event fires. 363 * Provides all feedback once a text selection changed event fires.
349 * @param {!AutomationEvent} evt 364 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
350 */ 365 */
351 onTextSelectionChanged: function(evt) { 366 onTextSelectionChanged: function(evt) {
352 if (evt.target.state.editable) 367 if (evt.target.state.editable)
353 this.onEditableChanged_(evt); 368 this.onEditableChanged_(evt);
354 }, 369 },
355 370
356 /** 371 /**
357 * Provides all feedback once a change event in a text field fires. 372 * Provides all feedback once a change event in a text field fires.
358 * @param {!AutomationEvent} evt 373 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
359 * @private 374 * @private
360 */ 375 */
361 onEditableChanged_: function(evt) { 376 onEditableChanged_: function(evt) {
362 var topRoot = AutomationUtil.getTopLevelRoot(evt.target); 377 var topRoot = AutomationUtil.getTopLevelRoot(evt.target);
363 if (!evt.target.state.focused || 378 if (!evt.target.state.focused ||
364 (topRoot && 379 (topRoot &&
365 topRoot.parent && 380 topRoot.parent &&
366 !topRoot.parent.state.focused)) 381 !topRoot.parent.state.focused))
367 return; 382 return;
368 383
(...skipping 20 matching lines...) Expand all
389 } 404 }
390 405
391 // TODO(plundblad): This can currently be null for contenteditables. 406 // TODO(plundblad): This can currently be null for contenteditables.
392 // Clean up when it can't. 407 // Clean up when it can't.
393 if (this.textEditHandler_) 408 if (this.textEditHandler_)
394 this.textEditHandler_.onEvent(evt); 409 this.textEditHandler_.onEvent(evt);
395 }, 410 },
396 411
397 /** 412 /**
398 * Provides all feedback once a value changed event fires. 413 * Provides all feedback once a value changed event fires.
399 * @param {!AutomationEvent} evt 414 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
400 */ 415 */
401 onValueChanged: function(evt) { 416 onValueChanged: function(evt) {
402 // Delegate to the edit text handler if this is an editable. 417 // Delegate to the edit text handler if this is an editable.
403 if (evt.target.state.editable) { 418 if (evt.target.state.editable) {
404 this.onEditableChanged_(evt); 419 this.onEditableChanged_(evt);
405 return; 420 return;
406 } 421 }
407 422
408 if (!this.shouldOutput_(evt)) 423 if (!this.shouldOutput_(evt))
409 return; 424 return;
410 425
411 var t = evt.target; 426 var t = evt.target;
412 if (t.state.focused || 427 if (t.state.focused ||
413 t.root.role == RoleType.desktop || 428 t.root.role == RoleType.DESKTOP ||
414 AutomationUtil.isDescendantOf( 429 AutomationUtil.isDescendantOf(
415 ChromeVoxState.instance.currentRange.start.node, t)) { 430 ChromeVoxState.instance.currentRange.start.node, t)) {
416 if (new Date() - this.lastValueChanged_ <= 431 if (new Date() - this.lastValueChanged_ <=
417 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS) 432 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS)
418 return; 433 return;
419 434
420 this.lastValueChanged_ = new Date(); 435 this.lastValueChanged_ = new Date();
421 436
422 var output = new Output(); 437 var output = new Output();
423 438
424 if (t.root.role == RoleType.desktop) 439 if (t.root.role == RoleType.DESKTOP)
425 output.withQueueMode(cvox.QueueMode.FLUSH); 440 output.withQueueMode(cvox.QueueMode.FLUSH);
426 441
427 output.format('$value', evt.target).go(); 442 output.format('$value', evt.target).go();
428 } 443 }
429 }, 444 },
430 445
431 /** 446 /**
432 * Handle updating the active indicator when the document scrolls. 447 * Handle updating the active indicator when the document scrolls.
433 * @param {!AutomationEvent} evt 448 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
434 */ 449 */
435 onScrollPositionChanged: function(evt) { 450 onScrollPositionChanged: function(evt) {
436 var currentRange = ChromeVoxState.instance.currentRange; 451 var currentRange = ChromeVoxState.instance.currentRange;
437 if (currentRange && currentRange.isValid() && this.shouldOutput_(evt)) 452 if (currentRange && currentRange.isValid() && this.shouldOutput_(evt))
438 new Output().withLocation(currentRange, null, evt.type).go(); 453 new Output().withLocation(currentRange, null, evt.type).go();
439 }, 454 },
440 455
441 /** 456 /**
442 * @param {!AutomationEvent} evt 457 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
443 */ 458 */
444 onSelection: function(evt) { 459 onSelection: function(evt) {
445 // Invalidate any previous editable text handler state since some nodes, 460 // Invalidate any previous editable text handler state since some nodes,
446 // like menuitems, can receive selection while focus remains on an editable 461 // like menuitems, can receive selection while focus remains on an editable
447 // leading to braille output routing to the editable. 462 // leading to braille output routing to the editable.
448 this.textEditHandler_ = null; 463 this.textEditHandler_ = null;
449 464
450 chrome.automation.getFocus(function(focus) { 465 chrome.automation.getFocus(function(focus) {
451 // Desktop tabs get "selection" when there's a focused webview during tab 466 // Desktop tabs get "selection" when there's a focused webview during tab
452 // switching. 467 // switching.
453 if (focus.role == RoleType.webView && evt.target.role == RoleType.tab) { 468 if (focus.role == RoleType.WEB_VIEW && evt.target.role == RoleType.TAB) {
454 ChromeVoxState.instance.setCurrentRange( 469 ChromeVoxState.instance.setCurrentRange(
455 cursors.Range.fromNode(focus.firstChild)); 470 cursors.Range.fromNode(focus.firstChild));
456 return; 471 return;
457 } 472 }
458 473
459 // Some cases (e.g. in overview mode), require overriding the assumption 474 // Some cases (e.g. in overview mode), require overriding the assumption
460 // that focus is an ancestor of a selection target. 475 // that focus is an ancestor of a selection target.
461 var override = evt.target.role == RoleType.menuItem || 476 var override = evt.target.role == RoleType.MENU_ITEM ||
462 (evt.target.root == focus.root && 477 (evt.target.root == focus.root &&
463 focus.root.role == RoleType.desktop); 478 focus.root.role == RoleType.DESKTOP);
464 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); 479 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH);
465 if (override || AutomationUtil.isDescendantOf(evt.target, focus)) 480 if (override || AutomationUtil.isDescendantOf(evt.target, focus))
466 this.onEventDefault(evt); 481 this.onEventDefault(evt);
467 }.bind(this)); 482 }.bind(this));
468 }, 483 },
469 484
470 /** 485 /**
471 * Provides all feedback once a menu start event fires. 486 * Provides all feedback once a menu start event fires.
472 * @param {!AutomationEvent} evt 487 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
473 */ 488 */
474 onMenuStart: function(evt) { 489 onMenuStart: function(evt) {
475 ChromeVoxState.instance.markCurrentRange(); 490 ChromeVoxState.instance.markCurrentRange();
476 this.onEventDefault(evt); 491 this.onEventDefault(evt);
477 }, 492 },
478 493
479 /** 494 /**
480 * Provides all feedback once a menu end event fires. 495 * Provides all feedback once a menu end event fires.
481 * @param {!AutomationEvent} evt 496 * @param {!(AutomationEvent|CustomAutomationEvent)} evt
482 */ 497 */
483 onMenuEnd: function(evt) { 498 onMenuEnd: function(evt) {
484 this.onEventDefault(evt); 499 this.onEventDefault(evt);
485 500
486 // This is a work around for Chrome context menus not firing a focus event 501 // This is a work around for Chrome context menus not firing a focus event
487 // after you close them. 502 // after you close them.
488 chrome.automation.getFocus(function(focus) { 503 chrome.automation.getFocus(function(focus) {
489 if (focus) { 504 if (focus) {
490 this.onFocus( 505 var event = new CustomAutomationEvent(EventType.FOCUS, focus, 'page');
491 new chrome.automation.AutomationEvent( 506 this.onFocus(event);
492 EventType.focus, focus, 'page'));
493 } 507 }
494 }.bind(this)); 508 }.bind(this));
495 }, 509 },
496 510
497 /** 511 /**
498 * Create an editable text handler for the given node if needed. 512 * Create an editable text handler for the given node if needed.
499 * @param {!AutomationNode} node 513 * @param {!AutomationNode} node
500 */ 514 */
501 createTextEditHandlerIfNeeded_: function(node) { 515 createTextEditHandlerIfNeeded_: function(node) {
502 if (!this.textEditHandler_ || 516 if (!this.textEditHandler_ ||
503 this.textEditHandler_.node !== node) { 517 this.textEditHandler_.node !== node) {
504 this.textEditHandler_ = editing.TextEditHandler.createForNode(node); 518 this.textEditHandler_ = editing.TextEditHandler.createForNode(node);
505 } 519 }
506 }, 520 },
507 521
508 /** 522 /**
509 * Once an event handler updates ChromeVox's range based on |evt| 523 * Once an event handler updates ChromeVox's range based on |evt|
510 * which updates mode, returns whether |evt| should be outputted. 524 * which updates mode, returns whether |evt| should be outputted.
511 * @return {boolean} 525 * @return {boolean}
512 */ 526 */
513 shouldOutput_: function(evt) { 527 shouldOutput_: function(evt) {
514 var mode = ChromeVoxState.instance.mode; 528 var mode = ChromeVoxState.instance.mode;
515 // Only output desktop rooted nodes or web nodes for next engine modes. 529 // Only output desktop rooted nodes or web nodes for next engine modes.
516 return evt.target.root.role == RoleType.desktop || 530 return evt.target.root.role == RoleType.DESKTOP ||
517 (mode == ChromeVoxMode.NEXT || 531 (mode == ChromeVoxMode.NEXT ||
518 mode == ChromeVoxMode.FORCE_NEXT || 532 mode == ChromeVoxMode.FORCE_NEXT ||
519 mode == ChromeVoxMode.CLASSIC_COMPAT); 533 mode == ChromeVoxMode.CLASSIC_COMPAT);
520 } 534 }
521 }; 535 };
522 536
523 /** 537 /**
524 * Initializes global state for DesktopAutomationHandler. 538 * Initializes global state for DesktopAutomationHandler.
525 * @private 539 * @private
526 */ 540 */
527 DesktopAutomationHandler.init_ = function() { 541 DesktopAutomationHandler.init_ = function() {
528 chrome.automation.getDesktop(function(desktop) { 542 chrome.automation.getDesktop(function(desktop) {
529 ChromeVoxState.desktopAutomationHandler = 543 ChromeVoxState.desktopAutomationHandler =
530 new DesktopAutomationHandler(desktop); 544 new DesktopAutomationHandler(desktop);
531 }); 545 });
532 }; 546 };
533 547
534 DesktopAutomationHandler.init_(); 548 DesktopAutomationHandler.init_();
535 549
536 }); // goog.scope 550 }); // goog.scope
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698