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'); | 11 goog.require('AutomationObjectConstructorInstaller'); |
12 goog.require('BaseAutomationHandler'); | 12 goog.require('BaseAutomationHandler'); |
13 goog.require('ChromeVoxState'); | 13 goog.require('ChromeVoxState'); |
| 14 goog.require('CustomAutomationEvent'); |
14 goog.require('Stubs'); | 15 goog.require('Stubs'); |
15 goog.require('editing.TextEditHandler'); | 16 goog.require('editing.TextEditHandler'); |
16 | 17 |
17 goog.scope(function() { | 18 goog.scope(function() { |
18 var AutomationEvent = chrome.automation.AutomationEvent; | 19 var AutomationEvent = chrome.automation.AutomationEvent; |
19 var AutomationNode = chrome.automation.AutomationNode; | 20 var AutomationNode = chrome.automation.AutomationNode; |
20 var Dir = constants.Dir; | 21 var Dir = constants.Dir; |
21 var EventType = chrome.automation.EventType; | 22 var EventType = chrome.automation.EventType; |
22 var RoleType = chrome.automation.RoleType; | 23 var RoleType = chrome.automation.RoleType; |
23 | 24 |
(...skipping 12 matching lines...) Expand all Loading... |
36 */ | 37 */ |
37 this.textEditHandler_ = null; | 38 this.textEditHandler_ = null; |
38 | 39 |
39 /** | 40 /** |
40 * The last time we handled a value changed event. | 41 * The last time we handled a value changed event. |
41 * @type {!Date} | 42 * @type {!Date} |
42 * @private | 43 * @private |
43 */ | 44 */ |
44 this.lastValueChanged_ = new Date(0); | 45 this.lastValueChanged_ = new Date(0); |
45 | 46 |
46 var e = EventType; | 47 this.addListener_(EventType.ACTIVEDESCENDANTCHANGED, |
47 this.addListener_(e.activedescendantchanged, this.onActiveDescendantChanged); | 48 this.onActiveDescendantChanged); |
48 this.addListener_(e.alert, this.onAlert); | 49 this.addListener_(EventType.ALERT, |
49 this.addListener_(e.ariaAttributeChanged, this.onAriaAttributeChanged); | 50 this.onAlert); |
50 this.addListener_(e.autocorrectionOccured, this.onEventIfInRange); | 51 this.addListener_(EventType.ARIA_ATTRIBUTE_CHANGED, |
51 this.addListener_(e.checkedStateChanged, this.onCheckedStateChanged); | 52 this.onAriaAttributeChanged); |
52 this.addListener_(e.childrenChanged, this.onActiveDescendantChanged); | 53 this.addListener_(EventType.AUTOCORRECTION_OCCURED, |
53 this.addListener_(e.expandedChanged, this.onEventIfInRange); | 54 this.onEventIfInRange); |
54 this.addListener_(e.focus, this.onFocus); | 55 this.addListener_(EventType.CHECKED_STATE_CHANGED, |
55 this.addListener_(e.hover, this.onHover); | 56 this.onCheckedStateChanged); |
56 this.addListener_(e.invalidStatusChanged, this.onEventIfInRange); | 57 this.addListener_(EventType.CHILDREN_CHANGED, |
57 this.addListener_(e.loadComplete, this.onLoadComplete); | 58 this.onActiveDescendantChanged); |
58 this.addListener_(e.menuEnd, this.onMenuEnd); | 59 this.addListener_(EventType.EXPANDED_CHANGED, |
59 this.addListener_(e.menuListItemSelected, this.onEventIfSelected); | 60 this.onEventIfInRange); |
60 this.addListener_(e.menuStart, this.onMenuStart); | 61 this.addListener_(EventType.FOCUS, |
61 this.addListener_(e.rowCollapsed, this.onEventIfInRange); | 62 this.onFocus); |
62 this.addListener_(e.rowExpanded, this.onEventIfInRange); | 63 this.addListener_(EventType.HOVER, |
63 this.addListener_(e.scrollPositionChanged, this.onScrollPositionChanged); | 64 this.onHover); |
64 this.addListener_(e.selection, this.onSelection); | 65 this.addListener_(EventType.INVALID_STATUS_CHANGED, |
65 this.addListener_(e.textChanged, this.onTextChanged); | 66 this.onEventIfInRange); |
66 this.addListener_(e.textSelectionChanged, this.onTextSelectionChanged); | 67 this.addListener_(EventType.LOAD_COMPLETE, |
67 this.addListener_(e.valueChanged, this.onValueChanged); | 68 this.onLoadComplete); |
| 69 this.addListener_(EventType.MENU_END, |
| 70 this.onMenuEnd); |
| 71 this.addListener_(EventType.MENU_LIST_ITEM_SELECTED, |
| 72 this.onEventIfSelected); |
| 73 this.addListener_(EventType.MENU_START, |
| 74 this.onMenuStart); |
| 75 this.addListener_(EventType.ROW_COLLAPSED, |
| 76 this.onEventIfInRange); |
| 77 this.addListener_(EventType.ROW_EXPANDED, |
| 78 this.onEventIfInRange); |
| 79 this.addListener_(EventType.SCROLL_POSITION_CHANGED, |
| 80 this.onScrollPositionChanged); |
| 81 this.addListener_(EventType.SELECTION, |
| 82 this.onSelection); |
| 83 this.addListener_(EventType.TEXT_CHANGED, |
| 84 this.onTextChanged); |
| 85 this.addListener_(EventType.TEXT_SELECTION_CHANGED, |
| 86 this.onTextSelectionChanged); |
| 87 this.addListener_(EventType.VALUE_CHANGED, |
| 88 this.onValueChanged); |
68 | 89 |
69 AutomationObjectConstructorInstaller.init(node, function() { | 90 AutomationObjectConstructorInstaller.init(node, function() { |
70 chrome.automation.getFocus((function(focus) { | 91 chrome.automation.getFocus((function(focus) { |
71 if (ChromeVoxState.instance.mode != ChromeVoxMode.FORCE_NEXT) | 92 if (ChromeVoxState.instance.mode != ChromeVoxMode.FORCE_NEXT) |
72 return; | 93 return; |
73 | 94 |
74 if (focus) { | 95 if (focus) { |
75 this.onFocus( | 96 var event = new CustomAutomationEvent(EventType.FOCUS, focus, 'page'); |
76 new chrome.automation.AutomationEvent( | 97 this.onFocus(event); |
77 EventType.focus, focus, 'page')); | |
78 } | 98 } |
79 }).bind(this)); | 99 }).bind(this)); |
80 }.bind(this)); | 100 }.bind(this)); |
81 }; | 101 }; |
82 | 102 |
83 /** | 103 /** |
84 * Time to wait until processing more value changed events. | 104 * Time to wait until processing more value changed events. |
85 * @const {number} | 105 * @const {number} |
86 */ | 106 */ |
87 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS = 500; | 107 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS = 500; |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 this.onEventDefault(evt); | 218 this.onEventDefault(evt); |
199 }, | 219 }, |
200 | 220 |
201 /** | 221 /** |
202 * Makes an announcement without changing focus. | 222 * Makes an announcement without changing focus. |
203 * @param {!AutomationEvent} evt | 223 * @param {!AutomationEvent} evt |
204 */ | 224 */ |
205 onActiveDescendantChanged: function(evt) { | 225 onActiveDescendantChanged: function(evt) { |
206 if (!evt.target.activeDescendant || !evt.target.state.focused) | 226 if (!evt.target.activeDescendant || !evt.target.state.focused) |
207 return; | 227 return; |
208 this.onEventDefault(new chrome.automation.AutomationEvent( | 228 var event = new CustomAutomationEvent( |
209 EventType.focus, evt.target.activeDescendant, evt.eventFrom)); | 229 EventType.FOCUS, evt.target.activeDescendant, evt.eventFrom); |
| 230 this.onEventDefault(event); |
210 }, | 231 }, |
211 | 232 |
212 /** | 233 /** |
213 * Makes an announcement without changing focus. | 234 * Makes an announcement without changing focus. |
214 * @param {!AutomationEvent} evt | 235 * @param {!AutomationEvent} evt |
215 */ | 236 */ |
216 onAlert: function(evt) { | 237 onAlert: function(evt) { |
217 var node = evt.target; | 238 var node = evt.target; |
218 if (!node || !this.shouldOutput_(evt)) | 239 if (!node || !this.shouldOutput_(evt)) |
219 return; | 240 return; |
220 | 241 |
221 var range = cursors.Range.fromNode(node); | 242 var range = cursors.Range.fromNode(node); |
222 | 243 |
223 new Output().withSpeechAndBraille(range, null, evt.type).go(); | 244 new Output().withSpeechAndBraille(range, null, evt.type).go(); |
224 }, | 245 }, |
225 | 246 |
226 /** | 247 /** |
227 * Provides all feedback once a checked state changed event fires. | 248 * Provides all feedback once a checked state changed event fires. |
228 * @param {!AutomationEvent} evt | 249 * @param {!AutomationEvent} evt |
229 */ | 250 */ |
230 onCheckedStateChanged: function(evt) { | 251 onCheckedStateChanged: function(evt) { |
231 if (!AutomationPredicate.checkable(evt.target)) | 252 if (!AutomationPredicate.checkable(evt.target)) |
232 return; | 253 return; |
233 | 254 |
234 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); | 255 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); |
235 this.onEventIfInRange( | 256 var event = new CustomAutomationEvent( |
236 new chrome.automation.AutomationEvent( | 257 EventType.CHECKED_STATE_CHANGED, evt.target, evt.eventFrom); |
237 EventType.checkedStateChanged, evt.target, evt.eventFrom)); | 258 this.onEventIfInRange(event); |
238 }, | 259 }, |
239 | 260 |
240 /** | 261 /** |
241 * Provides all feedback once a focus event fires. | 262 * Provides all feedback once a focus event fires. |
242 * @param {!AutomationEvent} evt | 263 * @param {!AutomationEvent} evt |
243 */ | 264 */ |
244 onFocus: function(evt) { | 265 onFocus: function(evt) { |
245 // Invalidate any previous editable text handler state. | 266 // Invalidate any previous editable text handler state. |
246 this.textEditHandler_ = null; | 267 this.textEditHandler_ = null; |
247 | 268 |
248 var node = evt.target; | 269 var node = evt.target; |
249 | 270 |
250 // Discard focus events on embeddedObject. | 271 // Discard focus events on embeddedObject. |
251 if (node.role == RoleType.embeddedObject) | 272 if (node.role == RoleType.EMBEDDED_OBJECT) |
252 return; | 273 return; |
253 | 274 |
254 this.createTextEditHandlerIfNeeded_(evt.target); | 275 this.createTextEditHandlerIfNeeded_(evt.target); |
255 | 276 |
256 // Category flush speech triggered by events with no source. This includes | 277 // Category flush speech triggered by events with no source. This includes |
257 // views. | 278 // views. |
258 if (evt.eventFrom == '') | 279 if (evt.eventFrom == '') |
259 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); | 280 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); |
260 if (!node.root) | 281 if (!node.root) |
261 return; | 282 return; |
262 | 283 |
263 var root = AutomationUtil.getTopLevelRoot(node.root); | 284 var root = AutomationUtil.getTopLevelRoot(node.root); |
264 | |
265 // If we're crossing out of a root, save it in case it needs recovering. | 285 // If we're crossing out of a root, save it in case it needs recovering. |
266 var prevRange = ChromeVoxState.instance.currentRange; | 286 var prevRange = ChromeVoxState.instance.currentRange; |
267 var prevNode = prevRange ? prevRange.start.node : null; | 287 var prevNode = prevRange ? prevRange.start.node : null; |
268 if (prevNode) { | 288 if (prevNode) { |
269 var prevRoot = AutomationUtil.getTopLevelRoot(prevNode); | 289 var prevRoot = AutomationUtil.getTopLevelRoot(prevNode); |
270 if (prevRoot && prevRoot !== root) | 290 if (prevRoot && prevRoot !== root) |
271 ChromeVoxState.instance.focusRecoveryMap.set(prevRoot, prevRange); | 291 ChromeVoxState.instance.focusRecoveryMap.set(prevRoot, prevRange); |
272 } | 292 } |
273 | |
274 // If a previous node was saved for this focus, restore it. | 293 // If a previous node was saved for this focus, restore it. |
275 var savedRange = ChromeVoxState.instance.focusRecoveryMap.get(root); | 294 var savedRange = ChromeVoxState.instance.focusRecoveryMap.get(root); |
276 ChromeVoxState.instance.focusRecoveryMap.delete(root); | 295 ChromeVoxState.instance.focusRecoveryMap.delete(root); |
277 if (savedRange) { | 296 if (savedRange) { |
278 ChromeVoxState.instance.navigateToRange(savedRange, false); | 297 ChromeVoxState.instance.navigateToRange(savedRange, false); |
279 return; | 298 return; |
280 } | 299 } |
281 | 300 var event = new CustomAutomationEvent(EventType.FOCUS, node, evt.eventFrom); |
282 this.onEventDefault(new chrome.automation.AutomationEvent( | 301 this.onEventDefault(event); |
283 EventType.focus, node, evt.eventFrom)); | |
284 }, | 302 }, |
285 | 303 |
286 /** | 304 /** |
287 * Provides all feedback once a load complete event fires. | 305 * Provides all feedback once a load complete event fires. |
288 * @param {!AutomationEvent} evt | 306 * @param {!AutomationEvent} evt |
289 */ | 307 */ |
290 onLoadComplete: function(evt) { | 308 onLoadComplete: function(evt) { |
291 chrome.automation.getFocus(function(focus) { | 309 chrome.automation.getFocus(function(focus) { |
292 if (!focus || !AutomationUtil.isDescendantOf(focus, evt.target)) | 310 if (!focus || !AutomationUtil.isDescendantOf(focus, evt.target)) |
293 return; | 311 return; |
(...skipping 13 matching lines...) Expand all Loading... |
307 } | 325 } |
308 | 326 |
309 // If initial focus was already placed on this page (e.g. if a user starts | 327 // 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 | 328 // tabbing before load complete), then don't move ChromeVox's position on |
311 // the page. | 329 // the page. |
312 if (ChromeVoxState.instance.currentRange && | 330 if (ChromeVoxState.instance.currentRange && |
313 ChromeVoxState.instance.currentRange.start.node.root == focus.root) | 331 ChromeVoxState.instance.currentRange.start.node.root == focus.root) |
314 return; | 332 return; |
315 | 333 |
316 var o = new Output(); | 334 var o = new Output(); |
317 if (focus.role == RoleType.rootWebArea) { | 335 if (focus.role == RoleType.ROOT_WEB_AREA) { |
318 // Restore to previous position. | 336 // Restore to previous position. |
319 var url = focus.docUrl; | 337 var url = focus.docUrl; |
320 url = url.substring(0, url.indexOf('#')) || url; | 338 url = url.substring(0, url.indexOf('#')) || url; |
321 var pos = cvox.ChromeVox.position[url]; | 339 var pos = cvox.ChromeVox.position[url]; |
322 if (pos) { | 340 if (pos) { |
323 focus = AutomationUtil.hitTest(focus.root, pos) || focus; | 341 focus = AutomationUtil.hitTest(focus.root, pos) || focus; |
324 if (focus != focus.root) | 342 if (focus != focus.root) |
325 o.format('$name', focus.root); | 343 o.format('$name', focus.root); |
326 } | 344 } |
327 } | 345 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 if (!ChromeVoxState.instance.currentRange) { | 387 if (!ChromeVoxState.instance.currentRange) { |
370 this.onEventDefault(evt); | 388 this.onEventDefault(evt); |
371 ChromeVoxState.instance.setCurrentRange( | 389 ChromeVoxState.instance.setCurrentRange( |
372 cursors.Range.fromNode(evt.target)); | 390 cursors.Range.fromNode(evt.target)); |
373 } | 391 } |
374 | 392 |
375 this.createTextEditHandlerIfNeeded_(evt.target); | 393 this.createTextEditHandlerIfNeeded_(evt.target); |
376 | 394 |
377 // Sync the ChromeVox range to the editable, if a selection exists. | 395 // Sync the ChromeVox range to the editable, if a selection exists. |
378 var anchorObject = evt.target.root.anchorObject; | 396 var anchorObject = evt.target.root.anchorObject; |
379 var anchorOffset = evt.target.root.anchorOffset; | 397 var anchorOffset = evt.target.root.anchorOffset || 0; |
380 var focusObject = evt.target.root.focusObject; | 398 var focusObject = evt.target.root.focusObject; |
381 var focusOffset = evt.target.root.focusOffset; | 399 var focusOffset = evt.target.root.focusOffset || 0; |
382 if (anchorObject && focusObject) { | 400 if (anchorObject && focusObject) { |
383 var selectedRange = new cursors.Range( | 401 var selectedRange = new cursors.Range( |
384 new cursors.WrappingCursor(anchorObject, anchorOffset), | 402 new cursors.WrappingCursor(anchorObject, anchorOffset), |
385 new cursors.WrappingCursor(focusObject, focusOffset)); | 403 new cursors.WrappingCursor(focusObject, focusOffset)); |
386 | 404 |
387 // Sync ChromeVox range with selection. | 405 // Sync ChromeVox range with selection. |
388 ChromeVoxState.instance.setCurrentRange(selectedRange); | 406 ChromeVoxState.instance.setCurrentRange(selectedRange); |
389 } | 407 } |
390 | 408 |
391 // TODO(plundblad): This can currently be null for contenteditables. | 409 // TODO(plundblad): This can currently be null for contenteditables. |
(...skipping 11 matching lines...) Expand all Loading... |
403 if (evt.target.state.editable) { | 421 if (evt.target.state.editable) { |
404 this.onEditableChanged_(evt); | 422 this.onEditableChanged_(evt); |
405 return; | 423 return; |
406 } | 424 } |
407 | 425 |
408 if (!this.shouldOutput_(evt)) | 426 if (!this.shouldOutput_(evt)) |
409 return; | 427 return; |
410 | 428 |
411 var t = evt.target; | 429 var t = evt.target; |
412 if (t.state.focused || | 430 if (t.state.focused || |
413 t.root.role == RoleType.desktop || | 431 t.root.role == RoleType.DESKTOP || |
414 AutomationUtil.isDescendantOf( | 432 AutomationUtil.isDescendantOf( |
415 ChromeVoxState.instance.currentRange.start.node, t)) { | 433 ChromeVoxState.instance.currentRange.start.node, t)) { |
416 if (new Date() - this.lastValueChanged_ <= | 434 if (new Date() - this.lastValueChanged_ <= |
417 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS) | 435 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS) |
418 return; | 436 return; |
419 | 437 |
420 this.lastValueChanged_ = new Date(); | 438 this.lastValueChanged_ = new Date(); |
421 | 439 |
422 var output = new Output(); | 440 var output = new Output(); |
423 | 441 |
424 if (t.root.role == RoleType.desktop) | 442 if (t.root.role == RoleType.DESKTOP) |
425 output.withQueueMode(cvox.QueueMode.FLUSH); | 443 output.withQueueMode(cvox.QueueMode.FLUSH); |
426 | 444 |
427 output.format('$value', evt.target).go(); | 445 output.format('$value', evt.target).go(); |
428 } | 446 } |
429 }, | 447 }, |
430 | 448 |
431 /** | 449 /** |
432 * Handle updating the active indicator when the document scrolls. | 450 * Handle updating the active indicator when the document scrolls. |
433 * @param {!AutomationEvent} evt | 451 * @param {!AutomationEvent} evt |
434 */ | 452 */ |
435 onScrollPositionChanged: function(evt) { | 453 onScrollPositionChanged: function(evt) { |
436 var currentRange = ChromeVoxState.instance.currentRange; | 454 var currentRange = ChromeVoxState.instance.currentRange; |
437 if (currentRange && currentRange.isValid() && this.shouldOutput_(evt)) | 455 if (currentRange && currentRange.isValid() && this.shouldOutput_(evt)) |
438 new Output().withLocation(currentRange, null, evt.type).go(); | 456 new Output().withLocation(currentRange, null, evt.type).go(); |
439 }, | 457 }, |
440 | 458 |
441 /** | 459 /** |
442 * @param {!AutomationEvent} evt | 460 * @param {!AutomationEvent} evt |
443 */ | 461 */ |
444 onSelection: function(evt) { | 462 onSelection: function(evt) { |
445 // Invalidate any previous editable text handler state since some nodes, | 463 // Invalidate any previous editable text handler state since some nodes, |
446 // like menuitems, can receive selection while focus remains on an editable | 464 // like menuitems, can receive selection while focus remains on an editable |
447 // leading to braille output routing to the editable. | 465 // leading to braille output routing to the editable. |
448 this.textEditHandler_ = null; | 466 this.textEditHandler_ = null; |
449 | 467 |
450 chrome.automation.getFocus(function(focus) { | 468 chrome.automation.getFocus(function(focus) { |
451 // Desktop tabs get "selection" when there's a focused webview during tab | 469 // Desktop tabs get "selection" when there's a focused webview during tab |
452 // switching. | 470 // switching. |
453 if (focus.role == RoleType.webView && evt.target.role == RoleType.tab) { | 471 if (focus.role == RoleType.WEB_VIEW && evt.target.role == RoleType.TAB) { |
454 ChromeVoxState.instance.setCurrentRange( | 472 ChromeVoxState.instance.setCurrentRange( |
455 cursors.Range.fromNode(focus.firstChild)); | 473 cursors.Range.fromNode(focus.firstChild)); |
456 return; | 474 return; |
457 } | 475 } |
458 | 476 |
459 // Some cases (e.g. in overview mode), require overriding the assumption | 477 // Some cases (e.g. in overview mode), require overriding the assumption |
460 // that focus is an ancestor of a selection target. | 478 // that focus is an ancestor of a selection target. |
461 var override = evt.target.role == RoleType.menuItem || | 479 var override = evt.target.role == RoleType.MENU_ITEM || |
462 (evt.target.root == focus.root && | 480 (evt.target.root == focus.root && |
463 focus.root.role == RoleType.desktop); | 481 focus.root.role == RoleType.DESKTOP); |
464 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); | 482 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); |
465 if (override || AutomationUtil.isDescendantOf(evt.target, focus)) | 483 if (override || AutomationUtil.isDescendantOf(evt.target, focus)) |
466 this.onEventDefault(evt); | 484 this.onEventDefault(evt); |
467 }.bind(this)); | 485 }.bind(this)); |
468 }, | 486 }, |
469 | 487 |
470 /** | 488 /** |
471 * Provides all feedback once a menu start event fires. | 489 * Provides all feedback once a menu start event fires. |
472 * @param {!AutomationEvent} evt | 490 * @param {!AutomationEvent} evt |
473 */ | 491 */ |
474 onMenuStart: function(evt) { | 492 onMenuStart: function(evt) { |
475 ChromeVoxState.instance.markCurrentRange(); | 493 ChromeVoxState.instance.markCurrentRange(); |
476 this.onEventDefault(evt); | 494 this.onEventDefault(evt); |
477 }, | 495 }, |
478 | 496 |
479 /** | 497 /** |
480 * Provides all feedback once a menu end event fires. | 498 * Provides all feedback once a menu end event fires. |
481 * @param {!AutomationEvent} evt | 499 * @param {!AutomationEvent} evt |
482 */ | 500 */ |
483 onMenuEnd: function(evt) { | 501 onMenuEnd: function(evt) { |
484 this.onEventDefault(evt); | 502 this.onEventDefault(evt); |
485 | 503 |
486 // This is a work around for Chrome context menus not firing a focus event | 504 // This is a work around for Chrome context menus not firing a focus event |
487 // after you close them. | 505 // after you close them. |
488 chrome.automation.getFocus(function(focus) { | 506 chrome.automation.getFocus(function(focus) { |
489 if (focus) { | 507 if (focus) { |
490 this.onFocus( | 508 var event = new CustomAutomationEvent(EventType.FOCUS, focus, 'page'); |
491 new chrome.automation.AutomationEvent( | 509 this.onFocus(event); |
492 EventType.focus, focus, 'page')); | |
493 } | 510 } |
494 }.bind(this)); | 511 }.bind(this)); |
495 }, | 512 }, |
496 | 513 |
497 /** | 514 /** |
498 * Create an editable text handler for the given node if needed. | 515 * Create an editable text handler for the given node if needed. |
499 * @param {!AutomationNode} node | 516 * @param {!AutomationNode} node |
500 */ | 517 */ |
501 createTextEditHandlerIfNeeded_: function(node) { | 518 createTextEditHandlerIfNeeded_: function(node) { |
502 if (!this.textEditHandler_ || | 519 if (!this.textEditHandler_ || |
503 this.textEditHandler_.node !== node) { | 520 this.textEditHandler_.node !== node) { |
504 this.textEditHandler_ = editing.TextEditHandler.createForNode(node); | 521 this.textEditHandler_ = editing.TextEditHandler.createForNode(node); |
505 } | 522 } |
506 }, | 523 }, |
507 | 524 |
508 /** | 525 /** |
509 * Once an event handler updates ChromeVox's range based on |evt| | 526 * Once an event handler updates ChromeVox's range based on |evt| |
510 * which updates mode, returns whether |evt| should be outputted. | 527 * which updates mode, returns whether |evt| should be outputted. |
511 * @return {boolean} | 528 * @return {boolean} |
512 */ | 529 */ |
513 shouldOutput_: function(evt) { | 530 shouldOutput_: function(evt) { |
514 var mode = ChromeVoxState.instance.mode; | 531 var mode = ChromeVoxState.instance.mode; |
515 // Only output desktop rooted nodes or web nodes for next engine modes. | 532 // Only output desktop rooted nodes or web nodes for next engine modes. |
516 return evt.target.root.role == RoleType.desktop || | 533 return evt.target.root.role == RoleType.DESKTOP || |
517 (mode == ChromeVoxMode.NEXT || | 534 (mode == ChromeVoxMode.NEXT || |
518 mode == ChromeVoxMode.FORCE_NEXT || | 535 mode == ChromeVoxMode.FORCE_NEXT || |
519 mode == ChromeVoxMode.CLASSIC_COMPAT); | 536 mode == ChromeVoxMode.CLASSIC_COMPAT); |
520 } | 537 } |
521 }; | 538 }; |
522 | 539 |
523 /** | 540 /** |
524 * Initializes global state for DesktopAutomationHandler. | 541 * Initializes global state for DesktopAutomationHandler. |
525 * @private | 542 * @private |
526 */ | 543 */ |
527 DesktopAutomationHandler.init_ = function() { | 544 DesktopAutomationHandler.init_ = function() { |
528 chrome.automation.getDesktop(function(desktop) { | 545 chrome.automation.getDesktop(function(desktop) { |
529 ChromeVoxState.desktopAutomationHandler = | 546 ChromeVoxState.desktopAutomationHandler = |
530 new DesktopAutomationHandler(desktop); | 547 new DesktopAutomationHandler(desktop); |
531 }); | 548 }); |
532 }; | 549 }; |
533 | 550 |
534 DesktopAutomationHandler.init_(); | 551 DesktopAutomationHandler.init_(); |
535 | 552 |
536 }); // goog.scope | 553 }); // goog.scope |
OLD | NEW |