| 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('ChromeVoxAutomationEvent'); |
| 13 goog.require('ChromeVoxState'); | 14 goog.require('ChromeVoxState'); |
| 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; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 this.addListener_(e.textChanged, this.onTextChanged); | 66 this.addListener_(e.textChanged, this.onTextChanged); |
| 66 this.addListener_(e.textSelectionChanged, this.onTextSelectionChanged); | 67 this.addListener_(e.textSelectionChanged, this.onTextSelectionChanged); |
| 67 this.addListener_(e.valueChanged, this.onValueChanged); | 68 this.addListener_(e.valueChanged, this.onValueChanged); |
| 68 | 69 |
| 69 AutomationObjectConstructorInstaller.init(node, function() { | 70 AutomationObjectConstructorInstaller.init(node, function() { |
| 70 chrome.automation.getFocus((function(focus) { | 71 chrome.automation.getFocus((function(focus) { |
| 71 if (ChromeVoxState.instance.mode != ChromeVoxMode.FORCE_NEXT) | 72 if (ChromeVoxState.instance.mode != ChromeVoxMode.FORCE_NEXT) |
| 72 return; | 73 return; |
| 73 | 74 |
| 74 if (focus) { | 75 if (focus) { |
| 75 this.onFocus( | 76 this.onFocus(new ChromeVoxAutomationEvent( |
| 76 new chrome.automation.AutomationEvent( | 77 EventType.focus, focus, 'page')); |
| 77 EventType.focus, focus, 'page')); | |
| 78 } | 78 } |
| 79 }).bind(this)); | 79 }).bind(this)); |
| 80 }.bind(this)); | 80 }.bind(this)); |
| 81 }; | 81 }; |
| 82 | 82 |
| 83 /** | 83 /** |
| 84 * Time to wait until processing more value changed events. | 84 * Time to wait until processing more value changed events. |
| 85 * @const {number} | 85 * @const {number} |
| 86 */ | 86 */ |
| 87 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS = 500; | 87 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS = 500; |
| 88 | 88 |
| 89 /** | 89 /** |
| 90 * Controls announcement of non-user-initiated events. | 90 * Controls announcement of non-user-initiated events. |
| 91 * @type {boolean} | 91 * @type {boolean} |
| 92 */ | 92 */ |
| 93 DesktopAutomationHandler.announceActions = false; | 93 DesktopAutomationHandler.announceActions = false; |
| 94 | 94 |
| 95 DesktopAutomationHandler.prototype = { | 95 DesktopAutomationHandler.prototype = { |
| 96 __proto__: BaseAutomationHandler.prototype, | 96 __proto__: BaseAutomationHandler.prototype, |
| 97 | 97 |
| 98 /** @override */ | 98 /** @override */ |
| 99 willHandleEvent_: function(evt) { | 99 willHandleEvent_: function(evt) { |
| 100 return !cvox.ChromeVox.isActive; | 100 return !cvox.ChromeVox.isActive; |
| 101 }, | 101 }, |
| 102 | 102 |
| 103 /** | 103 /** |
| 104 * Provides all feedback once ChromeVox's focus changes. | 104 * Provides all feedback once ChromeVox's focus changes. |
| 105 * @param {!AutomationEvent} evt | 105 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 106 */ | 106 */ |
| 107 onEventDefault: function(evt) { | 107 onEventDefault: function(evt) { |
| 108 var node = evt.target; | 108 var node = evt.target; |
| 109 if (!node) | 109 if (!node) |
| 110 return; | 110 return; |
| 111 | 111 |
| 112 // Decide whether to announce and sync this event. | 112 // Decide whether to announce and sync this event. |
| 113 if (!DesktopAutomationHandler.announceActions && evt.eventFrom == 'action') | 113 if (!DesktopAutomationHandler.announceActions && evt.eventFrom == 'action') |
| 114 return; | 114 return; |
| 115 | 115 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 133 output.withBraille( | 133 output.withBraille( |
| 134 ChromeVoxState.instance.currentRange, prevRange, evt.type); | 134 ChromeVoxState.instance.currentRange, prevRange, evt.type); |
| 135 } else { | 135 } else { |
| 136 // Delegate event handling to the text edit handler for braille. | 136 // Delegate event handling to the text edit handler for braille. |
| 137 this.textEditHandler_.onEvent(evt); | 137 this.textEditHandler_.onEvent(evt); |
| 138 } | 138 } |
| 139 output.go(); | 139 output.go(); |
| 140 }, | 140 }, |
| 141 | 141 |
| 142 /** | 142 /** |
| 143 * @param {!AutomationEvent} evt | 143 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 144 */ | 144 */ |
| 145 onEventIfInRange: function(evt) { | 145 onEventIfInRange: function(evt) { |
| 146 if (!this.shouldOutput_(evt)) | 146 if (!this.shouldOutput_(evt)) |
| 147 return; | 147 return; |
| 148 | 148 |
| 149 var prev = ChromeVoxState.instance.currentRange; | 149 var prev = ChromeVoxState.instance.currentRange; |
| 150 if (prev.contentEquals(cursors.Range.fromNode(evt.target)) || | 150 if (prev.contentEquals(cursors.Range.fromNode(evt.target)) || |
| 151 evt.target.state.focused) { | 151 evt.target.state.focused) { |
| 152 // Category flush here since previous focus events via navigation can | 152 // Category flush here since previous focus events via navigation can |
| 153 // cause double speak. | 153 // cause double speak. |
| 154 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); | 154 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); |
| 155 | 155 |
| 156 // Intentionally skip setting range. | 156 // Intentionally skip setting range. |
| 157 new Output() | 157 new Output() |
| 158 .withRichSpeechAndBraille(cursors.Range.fromNode(evt.target), | 158 .withRichSpeechAndBraille(cursors.Range.fromNode(evt.target), |
| 159 prev, | 159 prev, |
| 160 Output.EventType.NAVIGATE) | 160 Output.EventType.NAVIGATE) |
| 161 .go(); | 161 .go(); |
| 162 } | 162 } |
| 163 }, | 163 }, |
| 164 | 164 |
| 165 /** | 165 /** |
| 166 * @param {!AutomationEvent} evt | 166 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 167 */ | 167 */ |
| 168 onEventIfSelected: function(evt) { | 168 onEventIfSelected: function(evt) { |
| 169 if (evt.target.state.selected) | 169 if (evt.target.state.selected) |
| 170 this.onEventDefault(evt); | 170 this.onEventDefault(evt); |
| 171 }, | 171 }, |
| 172 | 172 |
| 173 /** | 173 /** |
| 174 * @param {!AutomationEvent} evt | 174 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 175 */ | 175 */ |
| 176 onEventWithFlushedOutput: function(evt) { | 176 onEventWithFlushedOutput: function(evt) { |
| 177 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); | 177 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); |
| 178 this.onEventDefault(evt); | 178 this.onEventDefault(evt); |
| 179 }, | 179 }, |
| 180 | 180 |
| 181 /** | 181 /** |
| 182 * @param {!AutomationEvent} evt | 182 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 183 */ | 183 */ |
| 184 onAriaAttributeChanged: function(evt) { | 184 onAriaAttributeChanged: function(evt) { |
| 185 if (evt.target.state.editable) | 185 if (evt.target.state.editable) |
| 186 return; | 186 return; |
| 187 this.onEventIfInRange(evt); | 187 this.onEventIfInRange(evt); |
| 188 }, | 188 }, |
| 189 | 189 |
| 190 /** | 190 /** |
| 191 * @param {!AutomationEvent} evt | 191 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 192 */ | 192 */ |
| 193 onHover: function(evt) { | 193 onHover: function(evt) { |
| 194 if (ChromeVoxState.instance.currentRange && | 194 if (ChromeVoxState.instance.currentRange && |
| 195 evt.target == ChromeVoxState.instance.currentRange.start.node) | 195 evt.target == ChromeVoxState.instance.currentRange.start.node) |
| 196 return; | 196 return; |
| 197 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); | 197 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); |
| 198 this.onEventDefault(evt); | 198 this.onEventDefault(evt); |
| 199 }, | 199 }, |
| 200 | 200 |
| 201 /** | 201 /** |
| 202 * Makes an announcement without changing focus. | 202 * Makes an announcement without changing focus. |
| 203 * @param {!AutomationEvent} evt | 203 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 204 */ | 204 */ |
| 205 onActiveDescendantChanged: function(evt) { | 205 onActiveDescendantChanged: function(evt) { |
| 206 if (!evt.target.activeDescendant || !evt.target.state.focused) | 206 if (!evt.target.activeDescendant || !evt.target.state.focused) |
| 207 return; | 207 return; |
| 208 this.onEventDefault(new chrome.automation.AutomationEvent( | 208 this.onEventDefault(new ChromeVoxAutomationEvent( |
| 209 EventType.focus, evt.target.activeDescendant, evt.eventFrom)); | 209 EventType.focus, evt.target.activeDescendant, evt.eventFrom)); |
| 210 }, | 210 }, |
| 211 | 211 |
| 212 /** | 212 /** |
| 213 * Makes an announcement without changing focus. | 213 * Makes an announcement without changing focus. |
| 214 * @param {!AutomationEvent} evt | 214 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 215 */ | 215 */ |
| 216 onAlert: function(evt) { | 216 onAlert: function(evt) { |
| 217 var node = evt.target; | 217 var node = evt.target; |
| 218 if (!node || !this.shouldOutput_(evt)) | 218 if (!node || !this.shouldOutput_(evt)) |
| 219 return; | 219 return; |
| 220 | 220 |
| 221 var range = cursors.Range.fromNode(node); | 221 var range = cursors.Range.fromNode(node); |
| 222 | 222 |
| 223 new Output().withSpeechAndBraille(range, null, evt.type).go(); | 223 new Output().withSpeechAndBraille(range, null, evt.type).go(); |
| 224 }, | 224 }, |
| 225 | 225 |
| 226 /** | 226 /** |
| 227 * Provides all feedback once a checked state changed event fires. | 227 * Provides all feedback once a checked state changed event fires. |
| 228 * @param {!AutomationEvent} evt | 228 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 229 */ | 229 */ |
| 230 onCheckedStateChanged: function(evt) { | 230 onCheckedStateChanged: function(evt) { |
| 231 if (!AutomationPredicate.checkable(evt.target)) | 231 if (!AutomationPredicate.checkable(evt.target)) |
| 232 return; | 232 return; |
| 233 | 233 |
| 234 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); | 234 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.CATEGORY_FLUSH); |
| 235 this.onEventIfInRange( | 235 this.onEventIfInRange( |
| 236 new chrome.automation.AutomationEvent( | 236 new ChromeVoxAutomationEvent( |
| 237 EventType.checkedStateChanged, evt.target, evt.eventFrom)); | 237 EventType.checkedStateChanged, evt.target, evt.eventFrom)); |
| 238 }, | 238 }, |
| 239 | 239 |
| 240 /** | 240 /** |
| 241 * Provides all feedback once a focus event fires. | 241 * Provides all feedback once a focus event fires. |
| 242 * @param {!AutomationEvent} evt | 242 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 243 */ | 243 */ |
| 244 onFocus: function(evt) { | 244 onFocus: function(evt) { |
| 245 // Invalidate any previous editable text handler state. | 245 // Invalidate any previous editable text handler state. |
| 246 this.textEditHandler_ = null; | 246 this.textEditHandler_ = null; |
| 247 | 247 |
| 248 var node = evt.target; | 248 var node = evt.target; |
| 249 | 249 |
| 250 // Discard focus events on embeddedObject. | 250 // Discard focus events on embeddedObject. |
| 251 if (node.role == RoleType.embeddedObject) | 251 if (node.role == RoleType.embeddedObject) |
| 252 return; | 252 return; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 272 } | 272 } |
| 273 | 273 |
| 274 // If a previous node was saved for this focus, restore it. | 274 // If a previous node was saved for this focus, restore it. |
| 275 var savedRange = ChromeVoxState.instance.focusRecoveryMap.get(root); | 275 var savedRange = ChromeVoxState.instance.focusRecoveryMap.get(root); |
| 276 ChromeVoxState.instance.focusRecoveryMap.delete(root); | 276 ChromeVoxState.instance.focusRecoveryMap.delete(root); |
| 277 if (savedRange) { | 277 if (savedRange) { |
| 278 ChromeVoxState.instance.navigateToRange(savedRange, false); | 278 ChromeVoxState.instance.navigateToRange(savedRange, false); |
| 279 return; | 279 return; |
| 280 } | 280 } |
| 281 | 281 |
| 282 this.onEventDefault(new chrome.automation.AutomationEvent( | 282 this.onEventDefault(new ChromeVoxAutomationEvent( |
| 283 EventType.focus, node, evt.eventFrom)); | 283 EventType.focus, node, evt.eventFrom)); |
| 284 }, | 284 }, |
| 285 | 285 |
| 286 /** | 286 /** |
| 287 * Provides all feedback once a load complete event fires. | 287 * Provides all feedback once a load complete event fires. |
| 288 * @param {!AutomationEvent} evt | 288 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 289 */ | 289 */ |
| 290 onLoadComplete: function(evt) { | 290 onLoadComplete: function(evt) { |
| 291 chrome.automation.getFocus(function(focus) { | 291 chrome.automation.getFocus(function(focus) { |
| 292 if (!focus || !AutomationUtil.isDescendantOf(focus, evt.target)) | 292 if (!focus || !AutomationUtil.isDescendantOf(focus, evt.target)) |
| 293 return; | 293 return; |
| 294 | 294 |
| 295 // Create text edit handler, if needed, now in order not to miss initial | 295 // 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 | 296 // value change if text field has already been focused when initializing |
| 297 // ChromeVox. | 297 // ChromeVox. |
| 298 this.createTextEditHandlerIfNeeded_(focus); | 298 this.createTextEditHandlerIfNeeded_(focus); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 321 return; | 321 return; |
| 322 | 322 |
| 323 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); | 323 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); |
| 324 o.withRichSpeechAndBraille( | 324 o.withRichSpeechAndBraille( |
| 325 ChromeVoxState.instance.currentRange, null, evt.type).go(); | 325 ChromeVoxState.instance.currentRange, null, evt.type).go(); |
| 326 }.bind(this)); | 326 }.bind(this)); |
| 327 }, | 327 }, |
| 328 | 328 |
| 329 /** | 329 /** |
| 330 * Provides all feedback once a text changed event fires. | 330 * Provides all feedback once a text changed event fires. |
| 331 * @param {!AutomationEvent} evt | 331 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 332 */ | 332 */ |
| 333 onTextChanged: function(evt) { | 333 onTextChanged: function(evt) { |
| 334 if (evt.target.state.editable) | 334 if (evt.target.state.editable) |
| 335 this.onEditableChanged_(evt); | 335 this.onEditableChanged_(evt); |
| 336 }, | 336 }, |
| 337 | 337 |
| 338 /** | 338 /** |
| 339 * Provides all feedback once a text selection changed event fires. | 339 * Provides all feedback once a text selection changed event fires. |
| 340 * @param {!AutomationEvent} evt | 340 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 341 */ | 341 */ |
| 342 onTextSelectionChanged: function(evt) { | 342 onTextSelectionChanged: function(evt) { |
| 343 if (evt.target.state.editable) | 343 if (evt.target.state.editable) |
| 344 this.onEditableChanged_(evt); | 344 this.onEditableChanged_(evt); |
| 345 }, | 345 }, |
| 346 | 346 |
| 347 /** | 347 /** |
| 348 * Provides all feedback once a change event in a text field fires. | 348 * Provides all feedback once a change event in a text field fires. |
| 349 * @param {!AutomationEvent} evt | 349 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 350 * @private | 350 * @private |
| 351 */ | 351 */ |
| 352 onEditableChanged_: function(evt) { | 352 onEditableChanged_: function(evt) { |
| 353 var topRoot = AutomationUtil.getTopLevelRoot(evt.target); | 353 var topRoot = AutomationUtil.getTopLevelRoot(evt.target); |
| 354 if (!evt.target.state.focused || | 354 if (!evt.target.state.focused || |
| 355 (topRoot && | 355 (topRoot && |
| 356 topRoot.parent && | 356 topRoot.parent && |
| 357 !topRoot.parent.state.focused)) | 357 !topRoot.parent.state.focused)) |
| 358 return; | 358 return; |
| 359 | 359 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 380 } | 380 } |
| 381 | 381 |
| 382 // TODO(plundblad): This can currently be null for contenteditables. | 382 // TODO(plundblad): This can currently be null for contenteditables. |
| 383 // Clean up when it can't. | 383 // Clean up when it can't. |
| 384 if (this.textEditHandler_) | 384 if (this.textEditHandler_) |
| 385 this.textEditHandler_.onEvent(evt); | 385 this.textEditHandler_.onEvent(evt); |
| 386 }, | 386 }, |
| 387 | 387 |
| 388 /** | 388 /** |
| 389 * Provides all feedback once a value changed event fires. | 389 * Provides all feedback once a value changed event fires. |
| 390 * @param {!AutomationEvent} evt | 390 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 391 */ | 391 */ |
| 392 onValueChanged: function(evt) { | 392 onValueChanged: function(evt) { |
| 393 // Delegate to the edit text handler if this is an editable. | 393 // Delegate to the edit text handler if this is an editable. |
| 394 if (evt.target.state.editable) { | 394 if (evt.target.state.editable) { |
| 395 this.onEditableChanged_(evt); | 395 this.onEditableChanged_(evt); |
| 396 return; | 396 return; |
| 397 } | 397 } |
| 398 | 398 |
| 399 if (!this.shouldOutput_(evt)) | 399 if (!this.shouldOutput_(evt)) |
| 400 return; | 400 return; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 414 | 414 |
| 415 if (t.root.role == RoleType.desktop) | 415 if (t.root.role == RoleType.desktop) |
| 416 output.withQueueMode(cvox.QueueMode.FLUSH); | 416 output.withQueueMode(cvox.QueueMode.FLUSH); |
| 417 | 417 |
| 418 output.format('$value', evt.target).go(); | 418 output.format('$value', evt.target).go(); |
| 419 } | 419 } |
| 420 }, | 420 }, |
| 421 | 421 |
| 422 /** | 422 /** |
| 423 * Handle updating the active indicator when the document scrolls. | 423 * Handle updating the active indicator when the document scrolls. |
| 424 * @param {!AutomationEvent} evt | 424 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 425 */ | 425 */ |
| 426 onScrollPositionChanged: function(evt) { | 426 onScrollPositionChanged: function(evt) { |
| 427 var currentRange = ChromeVoxState.instance.currentRange; | 427 var currentRange = ChromeVoxState.instance.currentRange; |
| 428 if (currentRange && currentRange.isValid() && this.shouldOutput_(evt)) | 428 if (currentRange && currentRange.isValid() && this.shouldOutput_(evt)) |
| 429 new Output().withLocation(currentRange, null, evt.type).go(); | 429 new Output().withLocation(currentRange, null, evt.type).go(); |
| 430 }, | 430 }, |
| 431 | 431 |
| 432 /** | 432 /** |
| 433 * @param {!AutomationEvent} evt | 433 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 434 */ | 434 */ |
| 435 onSelection: function(evt) { | 435 onSelection: function(evt) { |
| 436 // Invalidate any previous editable text handler state since some nodes, | 436 // Invalidate any previous editable text handler state since some nodes, |
| 437 // like menuitems, can receive selection while focus remains on an editable | 437 // like menuitems, can receive selection while focus remains on an editable |
| 438 // leading to braille output routing to the editable. | 438 // leading to braille output routing to the editable. |
| 439 this.textEditHandler_ = null; | 439 this.textEditHandler_ = null; |
| 440 | 440 |
| 441 chrome.automation.getFocus(function(focus) { | 441 chrome.automation.getFocus(function(focus) { |
| 442 // Desktop tabs get "selection" when there's a focused webview during tab | 442 // Desktop tabs get "selection" when there's a focused webview during tab |
| 443 // switching. | 443 // switching. |
| 444 if (focus.role == RoleType.webView && evt.target.role == RoleType.tab) { | 444 if (focus.role == RoleType.webView && evt.target.role == RoleType.tab) { |
| 445 ChromeVoxState.instance.setCurrentRange( | 445 ChromeVoxState.instance.setCurrentRange( |
| 446 cursors.Range.fromNode(focus.firstChild)); | 446 cursors.Range.fromNode(focus.firstChild)); |
| 447 return; | 447 return; |
| 448 } | 448 } |
| 449 | 449 |
| 450 // Some cases (e.g. in overview mode), require overriding the assumption | 450 // Some cases (e.g. in overview mode), require overriding the assumption |
| 451 // that focus is an ancestor of a selection target. | 451 // that focus is an ancestor of a selection target. |
| 452 var override = evt.target.role == RoleType.menuItem || | 452 var override = evt.target.role == RoleType.menuItem || |
| 453 (evt.target.root == focus.root && | 453 (evt.target.root == focus.root && |
| 454 focus.root.role == RoleType.desktop); | 454 focus.root.role == RoleType.desktop); |
| 455 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); | 455 Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH); |
| 456 if (override || AutomationUtil.isDescendantOf(evt.target, focus)) | 456 if (override || AutomationUtil.isDescendantOf(evt.target, focus)) |
| 457 this.onEventDefault(evt); | 457 this.onEventDefault(evt); |
| 458 }.bind(this)); | 458 }.bind(this)); |
| 459 }, | 459 }, |
| 460 | 460 |
| 461 /** | 461 /** |
| 462 * Provides all feedback once a menu start event fires. | 462 * Provides all feedback once a menu start event fires. |
| 463 * @param {!AutomationEvent} evt | 463 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 464 */ | 464 */ |
| 465 onMenuStart: function(evt) { | 465 onMenuStart: function(evt) { |
| 466 ChromeVoxState.instance.markCurrentRange(); | 466 ChromeVoxState.instance.markCurrentRange(); |
| 467 this.onEventDefault(evt); | 467 this.onEventDefault(evt); |
| 468 }, | 468 }, |
| 469 | 469 |
| 470 /** | 470 /** |
| 471 * Provides all feedback once a menu end event fires. | 471 * Provides all feedback once a menu end event fires. |
| 472 * @param {!AutomationEvent} evt | 472 * @param {!AutomationEvent|!ChromeVoxAutomationEvent} evt |
| 473 */ | 473 */ |
| 474 onMenuEnd: function(evt) { | 474 onMenuEnd: function(evt) { |
| 475 this.onEventDefault(evt); | 475 this.onEventDefault(evt); |
| 476 | 476 |
| 477 // This is a work around for Chrome context menus not firing a focus event | 477 // This is a work around for Chrome context menus not firing a focus event |
| 478 // after you close them. | 478 // after you close them. |
| 479 chrome.automation.getFocus(function(focus) { | 479 chrome.automation.getFocus(function(focus) { |
| 480 if (focus) { | 480 if (focus) { |
| 481 this.onFocus( | 481 this.onFocus( |
| 482 new chrome.automation.AutomationEvent( | 482 new ChromeVoxAutomationEvent( |
| 483 EventType.focus, focus, 'page')); | 483 EventType.focus, focus, 'page')); |
| 484 } | 484 } |
| 485 }.bind(this)); | 485 }.bind(this)); |
| 486 }, | 486 }, |
| 487 | 487 |
| 488 /** | 488 /** |
| 489 * Create an editable text handler for the given node if needed. | 489 * Create an editable text handler for the given node if needed. |
| 490 * @param {!AutomationNode} node | 490 * @param {!AutomationNode} node |
| 491 */ | 491 */ |
| 492 createTextEditHandlerIfNeeded_: function(node) { | 492 createTextEditHandlerIfNeeded_: function(node) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 518 DesktopAutomationHandler.init_ = function() { | 518 DesktopAutomationHandler.init_ = function() { |
| 519 chrome.automation.getDesktop(function(desktop) { | 519 chrome.automation.getDesktop(function(desktop) { |
| 520 ChromeVoxState.desktopAutomationHandler = | 520 ChromeVoxState.desktopAutomationHandler = |
| 521 new DesktopAutomationHandler(desktop); | 521 new DesktopAutomationHandler(desktop); |
| 522 }); | 522 }); |
| 523 }; | 523 }; |
| 524 | 524 |
| 525 DesktopAutomationHandler.init_(); | 525 DesktopAutomationHandler.init_(); |
| 526 | 526 |
| 527 }); // goog.scope | 527 }); // goog.scope |
| OLD | NEW |