Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 var AutomationEvent = chrome.automation.AutomationEvent; | 5 var AutomationEvent = chrome.automation.AutomationEvent; |
| 6 var AutomationNode = chrome.automation.AutomationNode; | 6 var AutomationNode = chrome.automation.AutomationNode; |
| 7 var EventType = chrome.automation.EventType; | 7 var EventType = chrome.automation.EventType; |
| 8 var RoleType = chrome.automation.RoleType; | 8 var RoleType = chrome.automation.RoleType; |
| 9 | 9 |
| 10 /** | 10 /** |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 61 chrome.automation.getDesktop(function(desktop) { | 61 chrome.automation.getDesktop(function(desktop) { |
| 62 desktop.addEventListener( | 62 desktop.addEventListener( |
| 63 EventType.MOUSE_PRESSED, this.onMousePressed_.bind(this), true); | 63 EventType.MOUSE_PRESSED, this.onMousePressed_.bind(this), true); |
| 64 desktop.addEventListener( | 64 desktop.addEventListener( |
| 65 EventType.MOUSE_DRAGGED, this.onMouseDragged_.bind(this), true); | 65 EventType.MOUSE_DRAGGED, this.onMouseDragged_.bind(this), true); |
| 66 desktop.addEventListener( | 66 desktop.addEventListener( |
| 67 EventType.MOUSE_RELEASED, this.onMouseReleased_.bind(this), true); | 67 EventType.MOUSE_RELEASED, this.onMouseReleased_.bind(this), true); |
| 68 desktop.addEventListener( | 68 desktop.addEventListener( |
| 69 EventType.MOUSE_CANCELED, this.onMouseCanceled_.bind(this), true); | 69 EventType.MOUSE_CANCELED, this.onMouseCanceled_.bind(this), true); |
| 70 }.bind(this)); | 70 }.bind(this)); |
| 71 | |
| 72 /** @private { ?string } */ | |
| 73 this.voiceName_ = null; | |
| 74 | |
| 75 /** @private { number } */ | |
| 76 this.speechRate_ = 1.0; | |
| 77 | |
| 78 this.initPreferences_(); | |
| 71 }; | 79 }; |
| 72 | 80 |
| 73 SelectToSpeak.prototype = { | 81 SelectToSpeak.prototype = { |
| 74 /** | 82 /** |
| 75 * Called when the mouse is pressed and the user is in a mode where | 83 * Called when the mouse is pressed and the user is in a mode where |
| 76 * select-to-speak is capturing mouse events (for example holding down | 84 * select-to-speak is capturing mouse events (for example holding down |
| 77 * Search). | 85 * Search). |
| 78 * | 86 * |
| 79 * @param {!AutomationEvent} evt | 87 * @param {!AutomationEvent} evt |
| 80 */ | 88 */ |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 | 190 |
| 183 /** | 191 /** |
| 184 * Enqueue speech commands for all of the given nodes. | 192 * Enqueue speech commands for all of the given nodes. |
| 185 * @param {Array<AutomationNode>} nodes The nodes to speak. | 193 * @param {Array<AutomationNode>} nodes The nodes to speak. |
| 186 */ | 194 */ |
| 187 startSpeechQueue_: function(nodes) { | 195 startSpeechQueue_: function(nodes) { |
| 188 chrome.tts.stop(); | 196 chrome.tts.stop(); |
| 189 for (var i = 0; i < nodes.length; i++) { | 197 for (var i = 0; i < nodes.length; i++) { |
| 190 var node = nodes[i]; | 198 var node = nodes[i]; |
| 191 var isLast = (i == nodes.length - 1); | 199 var isLast = (i == nodes.length - 1); |
| 192 chrome.tts.speak(node.name || '', { | 200 |
| 201 var options = { | |
| 193 lang: 'en-US', | 202 lang: 'en-US', |
| 203 rate: this.rate_, | |
| 194 'enqueue': true, | 204 'enqueue': true, |
| 195 onEvent: (function(node, isLast, event) { | 205 onEvent: (function(node, isLast, event) { |
| 196 if (event.type == 'start') { | 206 if (event.type == 'start') { |
| 197 chrome.accessibilityPrivate.setFocusRing([node.location]); | 207 chrome.accessibilityPrivate.setFocusRing([node.location]); |
| 198 } else if (event.type == 'interrupted' || | 208 } else if (event.type == 'interrupted' || |
| 199 event.type == 'cancelled') { | 209 event.type == 'cancelled') { |
| 200 chrome.accessibilityPrivate.setFocusRing([]); | 210 chrome.accessibilityPrivate.setFocusRing([]); |
| 201 } else if (event.type == 'end') { | 211 } else if (event.type == 'end') { |
| 202 if (isLast) { | 212 if (isLast) { |
| 203 chrome.accessibilityPrivate.setFocusRing([]); | 213 chrome.accessibilityPrivate.setFocusRing([]); |
| 204 } | 214 } |
| 205 } | 215 } |
| 206 }).bind(this, node, isLast) | 216 }).bind(this, node, isLast) |
| 217 }; | |
| 218 if (this.voiceName_) { | |
| 219 options['voiceName'] = this.voiceName_; | |
| 220 } | |
| 221 chrome.tts.speak(node.name || '', options); | |
| 222 } | |
| 223 }, | |
| 224 | |
| 225 /** | |
| 226 * Loads preferences from chrome.storage, sets default values if | |
| 227 * necessary, and registers a listener to update prefs when they | |
| 228 * change. | |
| 229 */ | |
| 230 initPreferences_: function() { | |
| 231 var updatePrefs = (function() { | |
| 232 chrome.storage.sync.get(['voice', 'rate'], (function(prefs) { | |
| 233 if (prefs['voice']) { | |
|
David Tseng
2017/03/29 22:24:46
Just a warning, a voice synced in this way might b
dmazzoni
2017/03/30 20:19:17
Good catch.
I made this more robust by tracking t
| |
| 234 this.voiceName_ = prefs['voice']; | |
| 235 } | |
| 236 if (prefs['rate']) { | |
| 237 this.rate_ = parseFloat(prefs['rate']); | |
| 238 } else { | |
| 239 chrome.storage.sync.set({'rate': this.rate_}); | |
| 240 } | |
| 241 }).bind(this)); | |
| 242 }).bind(this); | |
| 243 | |
| 244 updatePrefs(); | |
| 245 chrome.storage.onChanged.addListener(updatePrefs); | |
| 246 | |
| 247 this.updateDefaultVoice_(); | |
| 248 window.speechSynthesis.onvoiceschanged = | |
| 249 this.updateDefaultVoice_.bind(this); | |
| 250 }, | |
| 251 | |
| 252 /** | |
| 253 * Get the list of TTS voices, and set the default voice if not already set. | |
| 254 */ | |
| 255 updateDefaultVoice_: function() { | |
| 256 var uiLocale = chrome.i18n.getMessage('@@ui_locale'); | |
| 257 uiLocale = uiLocale.replace('_', '-').toLowerCase(); | |
| 258 | |
| 259 chrome.tts.getVoices(function(voices) { | |
| 260 if (voices.length == 0) | |
| 261 return; | |
| 262 | |
| 263 voices.sort(function(a, b) { | |
| 264 function score(voice) { | |
| 265 var lang = voice.lang.toLowerCase(); | |
| 266 var s = 0; | |
| 267 if (lang == uiLocale) | |
| 268 s += 2; | |
| 269 if (lang.substr(0, 2) == uiLocale.substr(0, 2)) | |
| 270 s += 1; | |
| 271 return s; | |
| 272 } | |
| 273 return score(b) - score(a); | |
| 207 }); | 274 }); |
| 208 } | 275 |
| 276 chrome.storage.sync.get(['voice'], (function(prefs) { | |
| 277 if (!prefs['voice']) { | |
| 278 chrome.storage.sync.set({'voice': voices[0].voiceName}); | |
| 279 } | |
| 280 }).bind(this)); | |
| 281 }); | |
| 209 } | 282 } |
| 210 }; | 283 }; |
| 211 | 284 |
| 212 new SelectToSpeak(); | 285 new SelectToSpeak(); |
| OLD | NEW |