Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 The entry point for all ChromeVox2 related code for the | 6 * @fileoverview The entry point for all ChromeVox2 related code for the |
| 7 * background page. | 7 * background page. |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 goog.provide('Background'); | 10 goog.provide('Background'); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 63 * @private | 63 * @private |
| 64 */ | 64 */ |
| 65 this.currentRange_ = null; | 65 this.currentRange_ = null; |
| 66 | 66 |
| 67 /** | 67 /** |
| 68 * @type {cursors.Range} | 68 * @type {cursors.Range} |
| 69 * @private | 69 * @private |
| 70 */ | 70 */ |
| 71 this.savedRange_ = null; | 71 this.savedRange_ = null; |
| 72 | 72 |
| 73 /** | |
| 74 * Which variant of ChromeVox is active. | |
| 75 * @type {ChromeVoxMode} | |
| 76 * @private | |
| 77 */ | |
| 78 this.mode_ = ChromeVoxMode.COMPAT; | |
| 79 | |
| 80 // Manually bind all functions to |this|. | 73 // Manually bind all functions to |this|. |
| 81 for (var func in this) { | 74 for (var func in this) { |
| 82 if (typeof(this[func]) == 'function') | 75 if (typeof(this[func]) == 'function') |
| 83 this[func] = this[func].bind(this); | 76 this[func] = this[func].bind(this); |
| 84 } | 77 } |
| 85 | 78 |
| 86 /** @type {!cvox.AbstractEarcons} @private */ | 79 /** @type {!cvox.AbstractEarcons} @private */ |
| 87 this.classicEarcons_ = cvox.ChromeVox.earcons || new cvox.ClassicEarcons(); | 80 this.classicEarcons_ = cvox.ChromeVox.earcons || new cvox.ClassicEarcons(); |
| 88 | 81 |
| 89 /** @type {!cvox.AbstractEarcons} @private */ | 82 /** @type {!cvox.AbstractEarcons} @private */ |
| 90 this.nextEarcons_ = new NextEarcons(); | 83 this.nextEarcons_ = new NextEarcons(); |
| 91 | 84 |
| 92 // Turn cvox.ChromeVox.earcons into a getter that returns either the | 85 // Turn cvox.ChromeVox.earcons into a getter that returns either the |
| 93 // Next earcons or the Classic earcons depending on the current mode. | 86 // Next earcons or the Classic earcons depending on the current mode. |
| 94 Object.defineProperty(cvox.ChromeVox, 'earcons', { | 87 Object.defineProperty(cvox.ChromeVox, 'earcons', { |
| 95 get: (function() { | 88 get: (function() { |
| 96 if (this.mode_ === ChromeVoxMode.FORCE_NEXT || | 89 if (this.mode === ChromeVoxMode.FORCE_NEXT || |
| 97 this.mode_ === ChromeVoxMode.NEXT) { | 90 this.mode === ChromeVoxMode.NEXT) { |
| 98 return this.nextEarcons_; | 91 return this.nextEarcons_; |
| 99 } else { | 92 } else { |
| 100 return this.classicEarcons_; | 93 return this.classicEarcons_; |
| 101 } | 94 } |
| 102 }).bind(this) | 95 }).bind(this) |
| 103 }); | 96 }); |
| 104 | 97 |
| 105 if (cvox.ChromeVox.isChromeOS) { | 98 if (cvox.ChromeVox.isChromeOS) { |
| 106 Object.defineProperty(cvox.ChromeVox, 'modKeyStr', { | 99 Object.defineProperty(cvox.ChromeVox, 'modKeyStr', { |
| 107 get: function() { | 100 get: function() { |
| 108 return (this.mode_ == ChromeVoxMode.CLASSIC || this.mode_ == | 101 return (this.mode == ChromeVoxMode.CLASSIC || this.mode == |
| 109 ChromeVoxMode.COMPAT) ? | 102 ChromeVoxMode.COMPAT) ? |
| 110 'Search+Shift' : 'Search'; | 103 'Search+Shift' : 'Search'; |
| 111 }.bind(this) | 104 }.bind(this) |
| 112 }); | 105 }); |
| 113 } | 106 } |
| 114 | 107 |
| 115 Object.defineProperty(cvox.ChromeVox, 'isActive', { | 108 Object.defineProperty(cvox.ChromeVox, 'isActive', { |
| 116 get: function() { | 109 get: function() { |
| 117 return localStorage['active'] !== 'false'; | 110 return localStorage['active'] !== 'false'; |
| 118 }, | 111 }, |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 132 | 125 |
| 133 // Live region handler. | 126 // Live region handler. |
| 134 this.liveRegions_ = new LiveRegions(this); | 127 this.liveRegions_ = new LiveRegions(this); |
| 135 | 128 |
| 136 /** @type {number} @private */ | 129 /** @type {number} @private */ |
| 137 this.passThroughKeyUpCount_ = 0; | 130 this.passThroughKeyUpCount_ = 0; |
| 138 | 131 |
| 139 /** @type {boolean} @private */ | 132 /** @type {boolean} @private */ |
| 140 this.inExcursion_ = false; | 133 this.inExcursion_ = false; |
| 141 | 134 |
| 135 /** | |
| 136 * Stores the mode as computed the last time a current range was set. | |
| 137 */ | |
| 138 this.mode_ = ChromeVoxMode.COMPAT; | |
|
dmazzoni
2016/06/21 21:21:02
Can you use getMode() here?
David Tseng
2016/06/21 22:41:32
No, because we always need to perform the basic se
| |
| 139 | |
| 142 if (!chrome.accessibilityPrivate.setKeyboardListener) | 140 if (!chrome.accessibilityPrivate.setKeyboardListener) |
| 143 chrome.accessibilityPrivate.setKeyboardListener = function() {}; | 141 chrome.accessibilityPrivate.setKeyboardListener = function() {}; |
| 144 | 142 |
| 145 if (cvox.ChromeVox.isChromeOS) { | 143 if (cvox.ChromeVox.isChromeOS) { |
| 146 chrome.accessibilityPrivate.onAccessibilityGesture.addListener( | 144 chrome.accessibilityPrivate.onAccessibilityGesture.addListener( |
| 147 this.onAccessibilityGesture_); | 145 this.onAccessibilityGesture_); |
| 148 | 146 |
| 147 if (localStorage['useNext'] == 'true') | |
| 148 this.forceChromeVoxNextActive(); | |
| 149 else | |
| 150 this.onModeChanged_(ChromeVoxMode.COMPAT, ChromeVoxMode.CLASSIC); | |
|
dmazzoni
2016/06/21 21:21:02
It'd be nice if you could just call refreshMode()
David Tseng
2016/06/21 22:41:32
new mode and call onModeChanged automatically base
| |
| 151 | |
| 149 Notifications.onStartup(); | 152 Notifications.onStartup(); |
| 150 }}; | 153 }}; |
| 151 | 154 |
| 152 /** | 155 /** |
| 153 * @const {string} | 156 * @const {string} |
| 154 */ | 157 */ |
| 155 Background.ISSUE_URL = 'https://code.google.com/p/chromium/issues/entry?' + | 158 Background.ISSUE_URL = 'https://code.google.com/p/chromium/issues/entry?' + |
| 156 'labels=Type-Bug,Pri-2,cvox2,OS-Chrome&' + | 159 'labels=Type-Bug,Pri-2,cvox2,OS-Chrome&' + |
| 157 'components=UI>accessibility&' + | 160 'components=UI>accessibility&' + |
| 158 'description='; | 161 'description='; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 189 'swipeDown2': 'readFromHere', | 192 'swipeDown2': 'readFromHere', |
| 190 }; | 193 }; |
| 191 | 194 |
| 192 Background.prototype = { | 195 Background.prototype = { |
| 193 __proto__: ChromeVoxState.prototype, | 196 __proto__: ChromeVoxState.prototype, |
| 194 | 197 |
| 195 /** | 198 /** |
| 196 * @override | 199 * @override |
| 197 */ | 200 */ |
| 198 getMode: function() { | 201 getMode: function() { |
| 199 return this.mode_; | 202 if (localStorage['useNext'] == 'true') |
| 203 return ChromeVoxMode.FORCE_NEXT; | |
| 204 | |
| 205 var target; | |
| 206 if (!this.getCurrentRange()) { | |
| 207 chrome.automation.getFocus(function(focus) { | |
| 208 target = focus; | |
| 209 }); | |
| 210 } else { | |
| 211 target = this.getCurrentRange().start.node; | |
| 212 } | |
| 213 | |
| 214 if (!target) | |
| 215 return ChromeVoxMode.CLASSIC; | |
| 216 | |
| 217 // Closure complains, but clearly, |target| is not null. | |
| 218 var root = | |
| 219 AutomationUtil.getTopLevelRoot(/** @type {!AutomationNode} */(target)); | |
| 220 if (!root) | |
| 221 return ChromeVoxMode.COMPAT; | |
|
dmazzoni
2016/06/21 21:21:02
nit: wrong indent
David Tseng
2016/06/21 22:41:32
Done.
| |
| 222 if (this.isWhitelistedForCompat_(root.docUrl)) | |
| 223 return ChromeVoxMode.COMPAT; | |
| 224 else if (this.isWhitelistedForNext_(root.docUrl)) | |
| 225 return ChromeVoxMode.NEXT; | |
| 226 else | |
| 227 return ChromeVoxMode.CLASSIC; | |
| 200 }, | 228 }, |
| 201 | 229 |
| 202 /** | 230 /** |
| 203 * @override | 231 * Handles a mode change. |
| 232 * @param {ChromeVoxMode} newMode | |
| 233 * @param {ChromeVoxMode} oldMode | |
| 234 * @private | |
| 204 */ | 235 */ |
| 205 setMode: function(mode, opt_injectClassic) { | 236 onModeChanged_: function(newMode, oldMode) { |
| 206 // Switching key maps potentially affects the key codes that involve | 237 // Switching key maps potentially affects the key codes that involve |
| 207 // sequencing. Without resetting this list, potentially stale key codes | 238 // sequencing. Without resetting this list, potentially stale key codes |
| 208 // remain. The key codes themselves get pushed in | 239 // remain. The key codes themselves get pushed in |
| 209 // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. | 240 // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. |
| 210 cvox.ChromeVox.sequenceSwitchKeyCodes = []; | 241 cvox.ChromeVox.sequenceSwitchKeyCodes = []; |
| 211 if (mode === ChromeVoxMode.CLASSIC || mode === ChromeVoxMode.COMPAT) | 242 if (window['prefs']) { |
| 212 window['prefs'].switchToKeyMap('keymap_classic'); | 243 if (newMode === ChromeVoxMode.CLASSIC || newMode === ChromeVoxMode.COMPAT) |
| 213 else | 244 window['prefs'].switchToKeyMap('keymap_classic'); |
| 214 window['prefs'].switchToKeyMap('keymap_next'); | 245 else |
| 246 window['prefs'].switchToKeyMap('keymap_next'); | |
| 247 } | |
| 215 | 248 |
| 216 if (mode == ChromeVoxMode.CLASSIC) { | 249 if (newMode == ChromeVoxMode.CLASSIC) { |
| 217 if (chrome.commands && | 250 if (chrome.commands && |
| 218 chrome.commands.onCommand.hasListener(this.onGotCommand)) | 251 chrome.commands.onCommand.hasListener(this.onGotCommand)) |
| 219 chrome.commands.onCommand.removeListener(this.onGotCommand); | 252 chrome.commands.onCommand.removeListener(this.onGotCommand); |
| 220 chrome.accessibilityPrivate.setKeyboardListener(false, false); | 253 chrome.accessibilityPrivate.setKeyboardListener(false, false); |
| 254 | |
| 255 if (cvox.ChromeVox.isChromeOS) | |
| 256 chrome.accessibilityPrivate.setFocusRing([]); | |
| 221 } else { | 257 } else { |
| 222 if (chrome.commands && | 258 if (chrome.commands && |
| 223 !chrome.commands.onCommand.hasListener(this.onGotCommand)) | 259 !chrome.commands.onCommand.hasListener(this.onGotCommand)) |
| 224 chrome.commands.onCommand.addListener(this.onGotCommand); | 260 chrome.commands.onCommand.addListener(this.onGotCommand); |
| 225 chrome.accessibilityPrivate.setKeyboardListener( | 261 chrome.accessibilityPrivate.setKeyboardListener( |
| 226 true, cvox.ChromeVox.isStickyPrefOn); | 262 true, cvox.ChromeVox.isStickyPrefOn); |
| 227 } | 263 } |
| 228 | 264 |
| 229 // note that |this.currentRange_| can *change* because the request is | 265 // note that |this.currentRange_| can *change* because the request is |
| 230 // async. Save it to ensure we're looking at the currentRange at this moment | 266 // async. Save it to ensure we're looking at the currentRange at this moment |
| 231 // in time. | 267 // in time. |
| 232 var cur = this.currentRange_; | 268 var cur = this.currentRange_; |
| 233 chrome.tabs.query({active: true}, function(tabs) { | 269 chrome.tabs.query({active: true}, function(tabs) { |
| 234 if (mode === ChromeVoxMode.CLASSIC) { | 270 if (newMode === ChromeVoxMode.CLASSIC) { |
| 235 // Generally, we don't want to inject classic content scripts as it is | 271 // Generally, we don't want to inject classic content scripts as it is |
| 236 // done by the extension system at document load. The exception is when | 272 // done by the extension system at document load. The exception is when |
| 237 // we toggle classic on manually as part of a user command. | 273 // we toggle classic on manually as part of a user command. |
| 238 if (opt_injectClassic) | 274 if (oldMode == ChromeVoxMode.FORCE_NEXT) |
| 239 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); | 275 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); |
| 240 } else { | 276 } else { |
| 241 // When in compat mode, if the focus is within the desktop tree proper, | 277 // When in compat mode, if the focus is within the desktop tree proper, |
| 242 // then do not disable content scripts. | 278 // then do not disable content scripts. |
| 243 if (cur && !cur.isWebRange()) | 279 if (cur && !cur.isWebRange()) |
| 244 return; | 280 return; |
| 245 | 281 |
| 246 this.disableClassicChromeVox_(); | 282 this.disableClassicChromeVox_(); |
| 247 } | 283 } |
| 248 }.bind(this)); | 284 }.bind(this)); |
| 249 | 285 |
| 250 // If switching out of a ChromeVox Next mode, make sure we cancel | 286 // If switching out of a ChromeVox Next mode, make sure we cancel |
| 251 // the progress loading sound just in case. | 287 // the progress loading sound just in case. |
| 252 if ((this.mode_ === ChromeVoxMode.NEXT || | 288 if (oldMode === ChromeVoxMode.NEXT || |
| 253 this.mode_ === ChromeVoxMode.FORCE_NEXT) && | 289 oldMode === ChromeVoxMode.FORCE_NEXT) |
| 254 this.mode_ != mode) { | |
| 255 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); | 290 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); |
| 256 } | |
| 257 | 291 |
| 258 if (mode === ChromeVoxMode.NEXT || | 292 if (newMode === ChromeVoxMode.NEXT || |
| 259 mode === ChromeVoxMode.FORCE_NEXT) { | 293 newMode === ChromeVoxMode.FORCE_NEXT) { |
| 260 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send(); | 294 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send(); |
| 261 if (cvox.TabsApiHandler) | 295 if (cvox.TabsApiHandler) |
| 262 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = false; | 296 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = false; |
| 263 } else { | 297 } else { |
| 264 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); | 298 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); |
| 265 if (cvox.TabsApiHandler) | 299 if (cvox.TabsApiHandler) |
| 266 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = true; | 300 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = true; |
| 267 } | 301 } |
| 268 | |
| 269 // If switching to Classic from any automation-API-based mode, | |
| 270 // clear the focus ring. | |
| 271 if (mode === ChromeVoxMode.CLASSIC && mode != this.mode_) { | |
| 272 if (cvox.ChromeVox.isChromeOS) | |
| 273 chrome.accessibilityPrivate.setFocusRing([]); | |
| 274 } | |
| 275 | |
| 276 // If switching away from Classic to any automation-API-based mode, | |
| 277 // update the range based on what's focused. | |
| 278 if (this.mode_ === ChromeVoxMode.CLASSIC && mode != this.mode_) { | |
| 279 chrome.automation.getFocus((function(focus) { | |
| 280 if (focus) | |
| 281 this.setCurrentRange(cursors.Range.fromNode(focus)); | |
| 282 }).bind(this)); | |
| 283 } | |
| 284 | |
| 285 this.mode_ = mode; | |
| 286 }, | 302 }, |
| 287 | 303 |
| 288 /** | 304 /** |
| 289 * Mode refreshes takes into account both |url| and the current ChromeVox | 305 * Toggles between force next and classic/compat modes. |
| 290 * range. The latter gets used to decide if the user is or isn't in web | 306 * This toggle automatically handles deciding between classic/compat based on |
| 291 * content. The focused state also needs to be set for this info to be | 307 * the start of the current range. |
| 292 * reliable. | 308 * @param {boolean=} opt_setValue Directly set to force next (true) or |
| 293 * @override | 309 * classic/compat (false). |
| 310 * @return {boolean} True to announce current position. | |
| 294 */ | 311 */ |
| 295 refreshMode: function(node) { | 312 toggleNext: function(opt_setValue) { |
| 296 // Mode changes are based upon the top level web root. | 313 var useNext; |
| 297 var root = node.root; | 314 if (opt_setValue !== undefined) |
| 298 while (root && | 315 useNext = opt_setValue; |
| 299 root.parent && | 316 else |
| 300 root.parent.root && | 317 useNext = localStorage['useNext'] != 'true'; |
| 301 root.parent.root.role != RoleType.desktop) { | |
| 302 root = root.parent.root; | |
| 303 } | |
| 304 | 318 |
| 305 var url = ''; | 319 localStorage['useNext'] = useNext; |
| 306 if (root && root.role == RoleType.rootWebArea) | 320 if (useNext) |
| 307 url = root.docUrl; | 321 this.forceChromeVoxNextActive(); |
| 322 else | |
| 323 this.setCurrentRange(null); | |
| 308 | 324 |
| 309 var mode = this.mode_; | 325 var announce = Msgs.getMsg(useNext ? |
| 310 if (mode != ChromeVoxMode.FORCE_NEXT) { | 326 'switch_to_next' : 'switch_to_classic'); |
| 311 if (this.isWhitelistedForNext_(url)) { | 327 cvox.ChromeVox.tts.speak( |
| 312 mode = ChromeVoxMode.NEXT; | 328 announce, cvox.QueueMode.FLUSH, {doNotInterrupt: true}); |
| 313 } else if (this.isBlacklistedForClassic_(url) || (this.currentRange_ && | 329 Notifications.onModeChange(); |
| 314 !this.currentRange_.isWebRange() && | |
| 315 this.currentRange_.start.node.state.focused)) { | |
| 316 mode = ChromeVoxMode.COMPAT; | |
| 317 } else { | |
| 318 mode = ChromeVoxMode.CLASSIC; | |
| 319 } | |
| 320 } | |
| 321 | 330 |
| 322 this.setMode(mode); | 331 // If the new mode is Classic, return false now so we don't announce |
| 332 // anything more. | |
| 333 return useNext; | |
| 323 }, | 334 }, |
| 324 | 335 |
| 325 /** | 336 /** |
| 326 * @override | 337 * @override |
| 327 */ | 338 */ |
| 328 getCurrentRange: function() { | 339 getCurrentRange: function() { |
| 329 if (this.currentRange_ && this.currentRange_.isValid()) | 340 if (this.currentRange_ && this.currentRange_.isValid()) |
| 330 return this.currentRange_; | 341 return this.currentRange_; |
| 331 return null; | 342 return null; |
| 332 }, | 343 }, |
| 333 | 344 |
| 334 /** | 345 /** |
| 335 * @override | 346 * @override |
| 336 */ | 347 */ |
| 337 setCurrentRange: function(newRange) { | 348 setCurrentRange: function(newRange) { |
| 338 if (!newRange) | 349 if (!this.inExcursion_ && newRange) |
| 339 return; | |
| 340 | |
| 341 // Is the range invalid? | |
| 342 if (newRange.start.node.role === undefined || | |
| 343 newRange.end.node.role === undefined) { | |
| 344 // Restore range to the focused location. | |
| 345 chrome.automation.getFocus(function(f) { | |
| 346 newRange = cursors.Range.fromNode(f); | |
| 347 }); | |
| 348 } | |
| 349 | |
| 350 if (!this.inExcursion_) | |
| 351 this.savedRange_ = new cursors.Range(newRange.start, newRange.end); | 350 this.savedRange_ = new cursors.Range(newRange.start, newRange.end); |
| 352 | 351 |
| 353 this.currentRange_ = newRange; | 352 this.currentRange_ = newRange; |
| 353 var oldMode = this.mode_; | |
|
dmazzoni
2016/06/21 21:21:02
Could these 5 lines be refreshMode()?
Then any ca
David Tseng
2016/06/21 22:41:32
I'd like to limit the number of methods exposed by
| |
| 354 var newMode = this.getMode(); | |
| 355 if (oldMode != newMode) { | |
| 356 this.onModeChanged_(newMode, oldMode); | |
| 357 this.mode_ = newMode; | |
| 358 } | |
| 354 | 359 |
| 355 if (this.currentRange_) { | 360 if (this.currentRange_) { |
| 356 var start = this.currentRange_.start.node; | 361 var start = this.currentRange_.start.node; |
| 357 start.makeVisible(); | 362 start.makeVisible(); |
| 358 | 363 |
| 359 var root = start.root; | 364 var root = start.root; |
| 360 | |
| 361 if (!root || root.role == RoleType.desktop) | 365 if (!root || root.role == RoleType.desktop) |
| 362 return; | 366 return; |
| 363 | 367 |
| 364 var position = {}; | 368 var position = {}; |
| 365 var loc = start.location; | 369 var loc = start.location; |
| 366 position.x = loc.left + loc.width / 2; | 370 position.x = loc.left + loc.width / 2; |
| 367 position.y = loc.top + loc.height / 2; | 371 position.y = loc.top + loc.height / 2; |
| 368 var url = root.docUrl; | 372 var url = root.docUrl; |
| 369 url = url.substring(0, url.indexOf('#')) || url; | 373 url = url.substring(0, url.indexOf('#')) || url; |
| 370 cvox.ChromeVox.position[url] = position; | 374 cvox.ChromeVox.position[url] = position; |
| 371 } | 375 } |
| 372 }, | 376 }, |
| 373 | 377 |
| 374 /** Forces ChromeVox Next to be active for all tabs. */ | 378 /** Forces ChromeVox Next to be active for all tabs. */ |
| 375 forceChromeVoxNextActive: function() { | 379 forceChromeVoxNextActive: function() { |
|
dmazzoni
2016/06/21 21:21:02
This doesn't actually force it active, it assumes
David Tseng
2016/06/21 22:41:32
Yup; removed and in-lined since there are no exter
| |
| 376 this.setMode(ChromeVoxMode.FORCE_NEXT); | 380 this.onModeChanged_(ChromeVoxMode.FORCE_NEXT, ChromeVoxMode.CLASSIC); |
| 377 }, | 381 }, |
| 378 | 382 |
| 379 /** | 383 /** |
| 380 * Handles ChromeVox Next commands. | 384 * Handles ChromeVox Next commands. |
| 381 * @param {string} command | 385 * @param {string} command |
| 382 * @param {boolean=} opt_bypassModeCheck Always tries to execute the command | 386 * @param {boolean=} opt_bypassModeCheck Always tries to execute the command |
| 383 * regardless of mode. | 387 * regardless of mode. |
| 384 * @return {boolean} True if the command should propagate. | 388 * @return {boolean} True if the command should propagate. |
| 385 */ | 389 */ |
| 386 onGotCommand: function(command, opt_bypassModeCheck) { | 390 onGotCommand: function(command, opt_bypassModeCheck) { |
| 387 // Check for loss of focus which results in us invalidating our current | 391 // Check for loss of focus which results in us invalidating our current |
| 388 // range. Note this call is synchronis. | 392 // range. Note this call is synchronis. |
| 389 chrome.automation.getFocus(function(focusedNode) { | 393 chrome.automation.getFocus(function(focusedNode) { |
| 390 if (this.currentRange_ && !this.currentRange_.isValid()) | 394 if (this.currentRange_ && !this.currentRange_.isValid()) |
| 391 this.currentRange_ = cursors.Range.fromNode(focusedNode); | 395 this.currentRange_ = cursors.Range.fromNode(focusedNode); |
| 392 if (!focusedNode) | 396 if (!focusedNode) |
| 393 this.currentRange_ = null; | 397 this.currentRange_ = null; |
| 394 }.bind(this)); | 398 }.bind(this)); |
| 395 | 399 |
| 396 if (!this.currentRange_) | 400 if (!this.currentRange_) |
| 397 return true; | 401 return true; |
| 398 | 402 |
| 399 if (this.mode_ == ChromeVoxMode.CLASSIC && !opt_bypassModeCheck) | 403 if (this.mode == ChromeVoxMode.CLASSIC && !opt_bypassModeCheck) |
| 400 return true; | 404 return true; |
| 401 | 405 |
| 402 var current = this.currentRange_; | 406 var current = this.currentRange_; |
| 403 var dir = Dir.FORWARD; | 407 var dir = Dir.FORWARD; |
| 404 var pred = null; | 408 var pred = null; |
| 405 var predErrorMsg = undefined; | 409 var predErrorMsg = undefined; |
| 406 var speechProps = {}; | 410 var speechProps = {}; |
| 407 switch (command) { | 411 switch (command) { |
| 408 case 'nextCharacter': | 412 case 'nextCharacter': |
| 409 speechProps['phoneticCharacters'] = true; | 413 speechProps['phoneticCharacters'] = true; |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 return false; | 604 return false; |
| 601 | 605 |
| 602 cvox.ChromeVox.isActive = !cvox.ChromeVox.isActive; | 606 cvox.ChromeVox.isActive = !cvox.ChromeVox.isActive; |
| 603 if (!cvox.ChromeVox.isActive) { | 607 if (!cvox.ChromeVox.isActive) { |
| 604 var msg = Msgs.getMsg('chromevox_inactive'); | 608 var msg = Msgs.getMsg('chromevox_inactive'); |
| 605 cvox.ChromeVox.tts.speak(msg, cvox.QueueMode.FLUSH); | 609 cvox.ChromeVox.tts.speak(msg, cvox.QueueMode.FLUSH); |
| 606 return false; | 610 return false; |
| 607 } | 611 } |
| 608 break; | 612 break; |
| 609 case 'toggleChromeVoxVersion': | 613 case 'toggleChromeVoxVersion': |
| 610 var newMode; | 614 if (!this.toggleNext()) |
| 611 if (this.mode_ == ChromeVoxMode.FORCE_NEXT) { | 615 return false; |
| 612 var inWeb = current.isWebRange(); | |
| 613 newMode = inWeb ? ChromeVoxMode.CLASSIC : ChromeVoxMode.COMPAT; | |
| 614 } else { | |
| 615 newMode = ChromeVoxMode.FORCE_NEXT; | |
| 616 } | |
| 617 this.setMode(newMode, true); | |
| 618 | |
| 619 var isClassic = | |
| 620 newMode == ChromeVoxMode.CLASSIC || newMode == ChromeVoxMode.COMPAT; | |
| 621 | |
| 622 // Leaving unlocalized as 'next' isn't an official name. | |
| 623 cvox.ChromeVox.tts.speak(isClassic ? | |
| 624 'classic' : 'next', cvox.QueueMode.FLUSH, {doNotInterrupt: true}); | |
| 625 | |
| 626 // If the new mode is Classic, return now so we don't announce | |
| 627 // anything more. | |
| 628 if (newMode == ChromeVoxMode.CLASSIC) | |
| 629 return false; | |
| 630 break; | 616 break; |
| 631 case 'toggleStickyMode': | 617 case 'toggleStickyMode': |
| 632 cvox.ChromeVoxBackground.setPref('sticky', | 618 cvox.ChromeVoxBackground.setPref('sticky', |
| 633 !cvox.ChromeVox.isStickyPrefOn, | 619 !cvox.ChromeVox.isStickyPrefOn, |
| 634 true); | 620 true); |
| 635 | 621 |
| 636 if (cvox.ChromeVox.isStickyPrefOn) | 622 if (cvox.ChromeVox.isStickyPrefOn) |
| 637 chrome.accessibilityPrivate.setKeyboardListener(true, true); | 623 chrome.accessibilityPrivate.setKeyboardListener(true, true); |
| 638 else | 624 else |
| 639 chrome.accessibilityPrivate.setKeyboardListener(true, false); | 625 chrome.accessibilityPrivate.setKeyboardListener(true, false); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 780 output.go(); | 766 output.go(); |
| 781 return false; | 767 return false; |
| 782 case 'readCurrentURL': | 768 case 'readCurrentURL': |
| 783 var output = new Output(); | 769 var output = new Output(); |
| 784 var target = this.currentRange_.start.node.root; | 770 var target = this.currentRange_.start.node.root; |
| 785 output.withString(target.docUrl || '').go(); | 771 output.withString(target.docUrl || '').go(); |
| 786 return false; | 772 return false; |
| 787 case 'reportIssue': | 773 case 'reportIssue': |
| 788 var url = Background.ISSUE_URL; | 774 var url = Background.ISSUE_URL; |
| 789 var description = {}; | 775 var description = {}; |
| 790 description['Mode'] = this.mode_; | 776 description['Mode'] = this.mode; |
| 791 description['Version'] = chrome.app.getDetails().version; | 777 description['Version'] = chrome.app.getDetails().version; |
| 792 description['Reproduction Steps'] = '%0a1.%0a2.%0a3.'; | 778 description['Reproduction Steps'] = '%0a1.%0a2.%0a3.'; |
| 793 for (var key in description) | 779 for (var key in description) |
| 794 url += key + ':%20' + description[key] + '%0a'; | 780 url += key + ':%20' + description[key] + '%0a'; |
| 795 chrome.tabs.create({url: url}); | 781 chrome.tabs.create({url: url}); |
| 796 return false; | 782 return false; |
| 797 case 'toggleBrailleCaptions': | 783 case 'toggleBrailleCaptions': |
| 798 cvox.BrailleCaptionsBackground.setActive( | 784 cvox.BrailleCaptionsBackground.setActive( |
| 799 !cvox.BrailleCaptionsBackground.isEnabled()); | 785 !cvox.BrailleCaptionsBackground.isEnabled()); |
| 800 return false; | 786 return false; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 901 /** | 887 /** |
| 902 * Handles key down events. | 888 * Handles key down events. |
| 903 * @param {Event} evt The key down event to process. | 889 * @param {Event} evt The key down event to process. |
| 904 * @return {boolean} True if the default action should be performed. | 890 * @return {boolean} True if the default action should be performed. |
| 905 */ | 891 */ |
| 906 onKeyDown: function(evt) { | 892 onKeyDown: function(evt) { |
| 907 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive; | 893 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive; |
| 908 if (cvox.ChromeVox.passThroughMode) | 894 if (cvox.ChromeVox.passThroughMode) |
| 909 return false; | 895 return false; |
| 910 | 896 |
| 911 if (this.mode_ != ChromeVoxMode.CLASSIC && | 897 if (this.mode != ChromeVoxMode.CLASSIC && |
| 912 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) { | 898 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) { |
| 913 evt.preventDefault(); | 899 evt.preventDefault(); |
| 914 evt.stopPropagation(); | 900 evt.stopPropagation(); |
| 915 } | 901 } |
| 916 Output.flushNextSpeechUtterance(); | 902 Output.flushNextSpeechUtterance(); |
| 917 return false; | 903 return false; |
| 918 }, | 904 }, |
| 919 | 905 |
| 920 /** | 906 /** |
| 921 * Handles key up events. | 907 * Handles key up events. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 944 chrome.tabs.create(optionsPage); | 930 chrome.tabs.create(optionsPage); |
| 945 }, | 931 }, |
| 946 | 932 |
| 947 /** | 933 /** |
| 948 * Handles a braille command. | 934 * Handles a braille command. |
| 949 * @param {!cvox.BrailleKeyEvent} evt | 935 * @param {!cvox.BrailleKeyEvent} evt |
| 950 * @param {!cvox.NavBraille} content | 936 * @param {!cvox.NavBraille} content |
| 951 * @return {boolean} True if evt was processed. | 937 * @return {boolean} True if evt was processed. |
| 952 */ | 938 */ |
| 953 onBrailleKeyEvent: function(evt, content) { | 939 onBrailleKeyEvent: function(evt, content) { |
| 954 if (this.mode_ === ChromeVoxMode.CLASSIC) | 940 if (this.mode === ChromeVoxMode.CLASSIC) |
| 955 return false; | 941 return false; |
| 956 | 942 |
| 957 switch (evt.command) { | 943 switch (evt.command) { |
| 958 case cvox.BrailleKeyCommand.PAN_LEFT: | 944 case cvox.BrailleKeyCommand.PAN_LEFT: |
| 959 this.onGotCommand('previousObject'); | 945 this.onGotCommand('previousObject'); |
| 960 break; | 946 break; |
| 961 case cvox.BrailleKeyCommand.PAN_RIGHT: | 947 case cvox.BrailleKeyCommand.PAN_RIGHT: |
| 962 this.onGotCommand('nextObject'); | 948 this.onGotCommand('nextObject'); |
| 963 break; | 949 break; |
| 964 case cvox.BrailleKeyCommand.LINE_UP: | 950 case cvox.BrailleKeyCommand.LINE_UP: |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 984 } | 970 } |
| 985 return true; | 971 return true; |
| 986 }, | 972 }, |
| 987 | 973 |
| 988 /** | 974 /** |
| 989 * Returns true if the url should have Classic running. | 975 * Returns true if the url should have Classic running. |
| 990 * @return {boolean} | 976 * @return {boolean} |
| 991 * @private | 977 * @private |
| 992 */ | 978 */ |
| 993 shouldEnableClassicForUrl_: function(url) { | 979 shouldEnableClassicForUrl_: function(url) { |
| 994 return this.mode_ != ChromeVoxMode.FORCE_NEXT && | 980 return this.mode != ChromeVoxMode.FORCE_NEXT && |
| 995 !this.isBlacklistedForClassic_(url) && | 981 !this.isBlacklistedForClassic_(url) && |
| 996 !this.isWhitelistedForNext_(url); | 982 !this.isWhitelistedForNext_(url); |
| 997 }, | 983 }, |
| 998 | 984 |
| 999 /** | 985 /** |
| 986 * Compat mode is on if any of the following are true: | |
| 987 * 1. a url is blacklisted for Classic. | |
| 988 * 2. the current range is not within web content. | |
| 989 * @param {string} url | |
| 990 */ | |
| 991 isWhitelistedForCompat_: function(url) { | |
| 992 return this.isBlacklistedForClassic_(url) || (this.getCurrentRange() && | |
| 993 !this.getCurrentRange().isWebRange() && | |
| 994 this.getCurrentRange().start.node.state.focused); | |
| 995 }, | |
| 996 | |
| 997 /** | |
| 1000 * @param {string} url | 998 * @param {string} url |
| 1001 * @return {boolean} | 999 * @return {boolean} |
| 1002 * @private | 1000 * @private |
| 1003 */ | 1001 */ |
| 1004 isBlacklistedForClassic_: function(url) { | 1002 isBlacklistedForClassic_: function(url) { |
| 1005 return this.classicBlacklistRegExp_.test(url); | 1003 return this.classicBlacklistRegExp_.test(url); |
| 1006 }, | 1004 }, |
| 1007 | 1005 |
| 1008 /** | 1006 /** |
| 1009 * @param {string} url | 1007 * @param {string} url |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1143 /** | 1141 /** |
| 1144 * Handles accessibility gestures from the touch screen. | 1142 * Handles accessibility gestures from the touch screen. |
| 1145 * @param {string} gesture The gesture to handle, based on the AXGesture enum | 1143 * @param {string} gesture The gesture to handle, based on the AXGesture enum |
| 1146 * defined in ui/accessibility/ax_enums.idl | 1144 * defined in ui/accessibility/ax_enums.idl |
| 1147 * @private | 1145 * @private |
| 1148 */ | 1146 */ |
| 1149 onAccessibilityGesture_: function(gesture) { | 1147 onAccessibilityGesture_: function(gesture) { |
| 1150 // If we're in classic mode, some gestures need to be handled by the | 1148 // If we're in classic mode, some gestures need to be handled by the |
| 1151 // content script. Other gestures are universal and will be handled in | 1149 // content script. Other gestures are universal and will be handled in |
| 1152 // this function. | 1150 // this function. |
| 1153 if (this.mode_ == ChromeVoxMode.CLASSIC) { | 1151 if (this.mode == ChromeVoxMode.CLASSIC) { |
| 1154 if (this.handleClassicGesture_(gesture)) | 1152 if (this.handleClassicGesture_(gesture)) |
| 1155 return; | 1153 return; |
| 1156 } | 1154 } |
| 1157 | 1155 |
| 1158 var command = Background.GESTURE_NEXT_COMMAND_MAP[gesture]; | 1156 var command = Background.GESTURE_NEXT_COMMAND_MAP[gesture]; |
| 1159 if (command) | 1157 if (command) |
| 1160 this.onGotCommand(command); | 1158 this.onGotCommand(command); |
| 1161 }, | 1159 }, |
| 1162 | 1160 |
| 1163 /** | 1161 /** |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1194 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') | 1192 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') |
| 1195 .replace(/\*/g, '.*') | 1193 .replace(/\*/g, '.*') |
| 1196 .replace(/\?/g, '.'); | 1194 .replace(/\?/g, '.'); |
| 1197 }).join('|') + ')$'); | 1195 }).join('|') + ')$'); |
| 1198 }; | 1196 }; |
| 1199 | 1197 |
| 1200 /** @type {Background} */ | 1198 /** @type {Background} */ |
| 1201 global.backgroundObj = new Background(); | 1199 global.backgroundObj = new Background(); |
| 1202 | 1200 |
| 1203 }); // goog.scope | 1201 }); // goog.scope |
| OLD | NEW |