Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js

Issue 2782993002: Add an options page to Select-to-Speak and allow setting voice name, rate (Closed)
Patch Set: fix unit tests Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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.voiceNameFromPrefs_ = null;
74
75 /** @private { ?string } */
76 this.voiceNameFromLocale_ = null;
77
78 /** @private { Set<string> } */
79 this.validVoiceNames_ = new Set();
80
81 /** @private { number } */
82 this.speechRate_ = 1.0;
83
84 this.initPreferences_();
71 }; 85 };
72 86
73 SelectToSpeak.prototype = { 87 SelectToSpeak.prototype = {
74 /** 88 /**
75 * Called when the mouse is pressed and the user is in a mode where 89 * 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 90 * select-to-speak is capturing mouse events (for example holding down
77 * Search). 91 * Search).
78 * 92 *
79 * @param {!AutomationEvent} evt 93 * @param {!AutomationEvent} evt
80 */ 94 */
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 196
183 /** 197 /**
184 * Enqueue speech commands for all of the given nodes. 198 * Enqueue speech commands for all of the given nodes.
185 * @param {Array<AutomationNode>} nodes The nodes to speak. 199 * @param {Array<AutomationNode>} nodes The nodes to speak.
186 */ 200 */
187 startSpeechQueue_: function(nodes) { 201 startSpeechQueue_: function(nodes) {
188 chrome.tts.stop(); 202 chrome.tts.stop();
189 for (var i = 0; i < nodes.length; i++) { 203 for (var i = 0; i < nodes.length; i++) {
190 var node = nodes[i]; 204 var node = nodes[i];
191 var isLast = (i == nodes.length - 1); 205 var isLast = (i == nodes.length - 1);
192 chrome.tts.speak(node.name || '', { 206
193 lang: 'en-US', 207 var options = {
208 rate: this.rate_,
194 'enqueue': true, 209 'enqueue': true,
195 onEvent: (function(node, isLast, event) { 210 onEvent: (function(node, isLast, event) {
196 if (event.type == 'start') { 211 if (event.type == 'start') {
197 chrome.accessibilityPrivate.setFocusRing([node.location]); 212 chrome.accessibilityPrivate.setFocusRing([node.location]);
198 } else if (event.type == 'interrupted' || 213 } else if (event.type == 'interrupted' ||
199 event.type == 'cancelled') { 214 event.type == 'cancelled') {
200 chrome.accessibilityPrivate.setFocusRing([]); 215 chrome.accessibilityPrivate.setFocusRing([]);
201 } else if (event.type == 'end') { 216 } else if (event.type == 'end') {
202 if (isLast) { 217 if (isLast) {
203 chrome.accessibilityPrivate.setFocusRing([]); 218 chrome.accessibilityPrivate.setFocusRing([]);
204 } 219 }
205 } 220 }
206 }).bind(this, node, isLast) 221 }).bind(this, node, isLast)
222 };
223
224 // Pick the voice name from prefs first, or the one that matches
225 // the locale next, but don't pick a voice that isn't currently
226 // loaded. If no voices are found, leave the voiceName option
227 // unset to let the browser try to route the speech request
228 // anyway if possible.
229 console.log('Pref: ' + this.voiceNameFromPrefs_);
230 console.log('Locale: ' + this.voiceNameFromLocale_);
231 var valid = '';
232 this.validVoiceNames_.forEach(function(voiceName) {
233 if (valid)
234 valid += ',';
235 valid += voiceName;
207 }); 236 });
237 console.log('Valid: ' + valid);
238 if (this.voiceNameFromPrefs_ &&
239 this.validVoiceNames_.has(this.voiceNameFromPrefs_)) {
240 options['voiceName'] = this.voiceNameFromPrefs_;
241 } else if (this.voiceNameFromLocale_ &&
242 this.validVoiceNames_.has(this.voiceNameFromLocale_)) {
243 options['voiceName'] = this.voiceNameFromLocale_;
244 }
245
246 chrome.tts.speak(node.name || '', options);
208 } 247 }
248 },
249
250 /**
251 * Loads preferences from chrome.storage, sets default values if
252 * necessary, and registers a listener to update prefs when they
253 * change.
254 */
255 initPreferences_: function() {
256 var updatePrefs = (function() {
257 chrome.storage.sync.get(['voice', 'rate'], (function(prefs) {
258 if (prefs['voice']) {
259 this.voiceNameFromPrefs_ = prefs['voice'];
260 }
261 if (prefs['rate']) {
262 this.rate_ = parseFloat(prefs['rate']);
263 } else {
264 chrome.storage.sync.set({'rate': this.rate_});
265 }
266 }).bind(this));
267 }).bind(this);
268
269 updatePrefs();
270 chrome.storage.onChanged.addListener(updatePrefs);
271
272 this.updateDefaultVoice_();
273 window.speechSynthesis.onvoiceschanged = (function() {
274 this.updateDefaultVoice_();
275 }).bind(this);
276 },
277
278 /**
279 * Get the list of TTS voices, and set the default voice if not already set.
280 */
281 updateDefaultVoice_: function() {
282 console.log('updateDefaultVoice_ ' + this.down_);
283 var uiLocale = chrome.i18n.getMessage('@@ui_locale');
284 uiLocale = uiLocale.replace('_', '-').toLowerCase();
285
286 chrome.tts.getVoices((function(voices) {
287 console.log('updateDefaultVoice_ voices: ' + voices.length);
288 this.validVoiceNames_ = new Set();
289
290 if (voices.length == 0)
291 return;
292
293 voices.forEach((function(voice) {
294 this.validVoiceNames_.add(voice.voiceName);
295 }).bind(this));
296
297 voices.sort(function(a, b) {
298 function score(voice) {
299 var lang = voice.lang.toLowerCase();
300 var s = 0;
301 if (lang == uiLocale)
302 s += 2;
303 if (lang.substr(0, 2) == uiLocale.substr(0, 2))
304 s += 1;
305 return s;
306 }
307 return score(b) - score(a);
308 });
309
310 this.voiceNameFromLocale_ = voices[0].voiceName;
311
312 chrome.storage.sync.get(['voice'], (function(prefs) {
313 if (!prefs['voice']) {
314 chrome.storage.sync.set({'voice': voices[0].voiceName});
315 }
316 }).bind(this));
317 }).bind(this));
209 } 318 }
210 }; 319 };
211
212 new SelectToSpeak();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698