OLD | NEW |
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 Loading... |
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. |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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} 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} 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} 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} 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} 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; |
(...skipping 13 matching lines...) Expand all Loading... |
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 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 if (!ChromeVoxState.instance.currentRange) { | 384 if (!ChromeVoxState.instance.currentRange) { |
370 this.onEventDefault(evt); | 385 this.onEventDefault(evt); |
371 ChromeVoxState.instance.setCurrentRange( | 386 ChromeVoxState.instance.setCurrentRange( |
372 cursors.Range.fromNode(evt.target)); | 387 cursors.Range.fromNode(evt.target)); |
373 } | 388 } |
374 | 389 |
375 this.createTextEditHandlerIfNeeded_(evt.target); | 390 this.createTextEditHandlerIfNeeded_(evt.target); |
376 | 391 |
377 // Sync the ChromeVox range to the editable, if a selection exists. | 392 // Sync the ChromeVox range to the editable, if a selection exists. |
378 var anchorObject = evt.target.root.anchorObject; | 393 var anchorObject = evt.target.root.anchorObject; |
379 var anchorOffset = evt.target.root.anchorOffset; | 394 var anchorOffset = evt.target.root.anchorOffset || 0; |
380 var focusObject = evt.target.root.focusObject; | 395 var focusObject = evt.target.root.focusObject; |
381 var focusOffset = evt.target.root.focusOffset; | 396 var focusOffset = evt.target.root.focusOffset || 0; |
382 if (anchorObject && focusObject) { | 397 if (anchorObject && focusObject) { |
383 var selectedRange = new cursors.Range( | 398 var selectedRange = new cursors.Range( |
384 new cursors.WrappingCursor(anchorObject, anchorOffset), | 399 new cursors.WrappingCursor(anchorObject, anchorOffset), |
385 new cursors.WrappingCursor(focusObject, focusOffset)); | 400 new cursors.WrappingCursor(focusObject, focusOffset)); |
386 | 401 |
387 // Sync ChromeVox range with selection. | 402 // Sync ChromeVox range with selection. |
388 ChromeVoxState.instance.setCurrentRange(selectedRange); | 403 ChromeVoxState.instance.setCurrentRange(selectedRange); |
389 } | 404 } |
390 | 405 |
391 // TODO(plundblad): This can currently be null for contenteditables. | 406 // TODO(plundblad): This can currently be null for contenteditables. |
(...skipping 11 matching lines...) Expand all Loading... |
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} 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} 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} 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} 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 |
OLD | NEW |