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

Side by Side Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js

Issue 2387413002: Improve speech contextual announcements and startCallback synchronization (Closed)
Patch Set: Add output mods. Created 4 years, 2 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 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 Provides output services for ChromeVox. 6 * @fileoverview Provides output services for ChromeVox.
7 */ 7 */
8 8
9 goog.provide('Output'); 9 goog.provide('Output');
10 goog.provide('Output.EventType'); 10 goog.provide('Output.EventType');
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 * The speech queue mode for the generated speech utterance. 85 * The speech queue mode for the generated speech utterance.
86 * @type {cvox.QueueMode} 86 * @type {cvox.QueueMode}
87 * @private 87 * @private
88 */ 88 */
89 this.queueMode_ = cvox.QueueMode.QUEUE; 89 this.queueMode_ = cvox.QueueMode.QUEUE;
90 90
91 /** 91 /**
92 * @type {boolean} 92 * @type {boolean}
93 * @private 93 * @private
94 */ 94 */
95 this.outputContextFirst_ = localStorage['outputContextFirst'] == 'true'; 95 this.outputContextFirst_ = false;
96 }; 96 };
97 97
98 /** 98 /**
99 * Delimiter to use between output values. 99 * Delimiter to use between output values.
100 * @type {string} 100 * @type {string}
101 */ 101 */
102 Output.SPACE = ' '; 102 Output.SPACE = ' ';
103 103
104 /** 104 /**
105 * Metadata about supported automation roles. 105 * Metadata about supported automation roles.
106 * @const {Object<{msgId: string, 106 * @const {Object<{msgId: string,
107 * earconId: (string|undefined), 107 * earconId: (string|undefined),
108 * inherits: (string|undefined), 108 * inherits: (string|undefined),
109 * ignoreAncestry: (boolean|undefined)}>} 109 * outputContextFirst: (boolean|undefined)}>}
110 * msgId: the message id of the role. 110 * msgId: the message id of the role.
111 * earconId: an optional earcon to play when encountering the role. 111 * earconId: an optional earcon to play when encountering the role.
112 * inherits: inherits rules from this role. 112 * inherits: inherits rules from this role.
113 * ignoreAncestry: don't output ancestry changes when encountering this role. 113 * outputContextFirst: where to place the context output.
114 * @private 114 * @private
115 */ 115 */
116 Output.ROLE_INFO_ = { 116 Output.ROLE_INFO_ = {
117 alert: { 117 alert: {
118 msgId: 'role_alert', 118 msgId: 'role_alert',
119 earconId: 'ALERT_NONMODAL' 119 earconId: 'ALERT_NONMODAL'
120 }, 120 },
121 alertDialog: { 121 alertDialog: {
122 msgId: 'role_alertdialog' 122 msgId: 'role_alertdialog'
123 }, 123 },
(...skipping 18 matching lines...) Expand all
142 earconId: 'BUTTON' 142 earconId: 'BUTTON'
143 }, 143 },
144 checkBox: { 144 checkBox: {
145 msgId: 'role_checkbox' 145 msgId: 'role_checkbox'
146 }, 146 },
147 columnHeader: { 147 columnHeader: {
148 msgId: 'role_columnheader', 148 msgId: 'role_columnheader',
149 inherits: 'cell' 149 inherits: 'cell'
150 }, 150 },
151 comboBox: { 151 comboBox: {
152 msgId: 'role_combobox' 152 msgId: 'role_combobox',
153 earconId: 'LISTBOX'
153 }, 154 },
154 complementary: { 155 complementary: {
155 msgId: 'role_complementary', 156 msgId: 'role_complementary',
156 inherits: 'abstractContainer' 157 inherits: 'abstractContainer'
157 }, 158 },
158 contentInfo: { 159 contentInfo: {
159 msgId: 'role_contentinfo', 160 msgId: 'role_contentinfo',
160 inherits: 'abstractContainer' 161 inherits: 'abstractContainer'
161 }, 162 },
162 date: { 163 date: {
163 msgId: 'input_type_date', 164 msgId: 'input_type_date',
164 inherits: 'abstractContainer' 165 inherits: 'abstractContainer'
165 }, 166 },
166 definition: { 167 definition: {
167 msgId: 'role_definition', 168 msgId: 'role_definition',
168 inherits: 'abstractContainer' 169 inherits: 'abstractContainer'
169 }, 170 },
170 dialog: { 171 dialog: {
dmazzoni 2016/10/04 20:00:34 How about outputContextFirst for dialog, alertdial
171 msgId: 'role_dialog' 172 msgId: 'role_dialog'
172 }, 173 },
173 directory: { 174 directory: {
174 msgId: 'role_directory', 175 msgId: 'role_directory',
175 inherits: 'abstractContainer' 176 inherits: 'abstractContainer'
176 }, 177 },
177 document: { 178 document: {
178 msgId: 'role_document', 179 msgId: 'role_document',
179 inherits: 'abstractContainer' 180 inherits: 'abstractContainer'
180 }, 181 },
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 inherits: 'abstractContainer' 224 inherits: 'abstractContainer'
224 }, 225 },
225 marquee: { 226 marquee: {
226 msgId: 'role_marquee', 227 msgId: 'role_marquee',
227 }, 228 },
228 math: { 229 math: {
229 msgId: 'role_math', 230 msgId: 'role_math',
230 inherits: 'abstractContainer' 231 inherits: 'abstractContainer'
231 }, 232 },
232 menu: { 233 menu: {
233 msgId: 'role_menu' 234 msgId: 'role_menu',
235 outputContextFirst: true
234 }, 236 },
235 menuBar: { 237 menuBar: {
236 msgId: 'role_menubar', 238 msgId: 'role_menubar',
237 }, 239 },
238 menuItem: { 240 menuItem: {
239 msgId: 'role_menuitem' 241 msgId: 'role_menuitem'
240 }, 242 },
241 menuItemCheckBox: { 243 menuItemCheckBox: {
242 msgId: 'role_menuitemcheckbox' 244 msgId: 'role_menuitemcheckbox'
243 }, 245 },
(...skipping 17 matching lines...) Expand all
261 popUpButton: { 263 popUpButton: {
262 msgId: 'role_button', 264 msgId: 'role_button',
263 earconId: 'POP_UP_BUTTON' 265 earconId: 'POP_UP_BUTTON'
264 }, 266 },
265 radioButton: { 267 radioButton: {
266 msgId: 'role_radio' 268 msgId: 'role_radio'
267 }, 269 },
268 radioGroup: { 270 radioGroup: {
269 msgId: 'role_radiogroup', 271 msgId: 'role_radiogroup',
270 }, 272 },
273 rootWebArea: {
274 outputContextFirst: true
275 },
271 row: { 276 row: {
272 msgId: 'role_row', 277 msgId: 'role_row',
273 inherits: 'abstractContainer' 278 inherits: 'abstractContainer'
274 }, 279 },
275 rowHeader: { 280 rowHeader: {
276 msgId: 'role_rowheader', 281 msgId: 'role_rowheader',
277 inherits: 'cell' 282 inherits: 'cell'
278 }, 283 },
279 scrollBar: { 284 scrollBar: {
280 msgId: 'role_scrollbar', 285 msgId: 'role_scrollbar',
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 inherits: 'abstractContainer' 321 inherits: 'abstractContainer'
317 }, 322 },
318 timer: { 323 timer: {
319 msgId: 'role_timer' 324 msgId: 'role_timer'
320 }, 325 },
321 toolbar: { 326 toolbar: {
322 msgId: 'role_toolbar' 327 msgId: 'role_toolbar'
323 }, 328 },
324 toggleButton: { 329 toggleButton: {
325 msgId: 'role_button', 330 msgId: 'role_button',
326 inherits: 'checkBox' 331 inherits: 'checkBox',
332 earconId: 'BUTTON'
327 }, 333 },
328 tree: { 334 tree: {
329 msgId: 'role_tree' 335 msgId: 'role_tree'
330 }, 336 },
331 treeItem: { 337 treeItem: {
332 msgId: 'role_treeitem' 338 msgId: 'role_treeitem'
333 } 339 }
334 }; 340 };
335 341
336 /** 342 /**
(...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after
884 callback(); 890 callback();
885 }.bind(this); 891 }.bind(this);
886 return this; 892 return this;
887 }, 893 },
888 894
889 /** 895 /**
890 * Executes all specified output. 896 * Executes all specified output.
891 */ 897 */
892 go: function() { 898 go: function() {
893 // Speech. 899 // Speech.
894 var queueMode = this.queueMode_; 900 var queueMode = cvox.QueueMode.FLUSH;
895 this.speechBuffer_.forEach(function(buff, i, a) { 901 if (Output.forceModeForNextSpeechUtterance_ !== undefined)
896 if (Output.forceModeForNextSpeechUtterance_ !== undefined && 902 queueMode = Output.forceModeForNextSpeechUtterance_;
897 buff.length > 0) { 903 else if (this.queueMode_ !== undefined)
898 queueMode = Output.forceModeForNextSpeechUtterance_; 904 queueMode = this.queueMode_;
899 Output.forceModeForNextSpeechUtterance_ = undefined;
900 }
901 905
902 var speechProps = {}; 906 if (this.speechBuffer_.length > 0)
907 Output.forceModeForNextSpeechUtterance_ = undefined;
908
909 for (var i = 0; i < this.speechBuffer_.length; i++) {
910 var buff = this.speechBuffer_[i];
911 var speechProps = /** @type {Object} */(
912 buff.getSpanInstanceOf(Output.SpeechProperties)) || {};
913
914 speechProps.category = this.speechCategory_;
915
903 (function() { 916 (function() {
904 var scopedBuff = buff; 917 var scopedBuff = buff;
905 speechProps =
906 scopedBuff.getSpanInstanceOf(Output.SpeechProperties) || {};
907 speechProps.category = this.speechCategory_;
908
909 speechProps['startCallback'] = function() { 918 speechProps['startCallback'] = function() {
910 var actions = scopedBuff.getSpansInstanceOf(Output.Action); 919 var actions = scopedBuff.getSpansInstanceOf(Output.Action);
911 if (actions) { 920 if (actions) {
912 actions.forEach(function(a) { 921 actions.forEach(function(a) {
913 a.run(); 922 a.run();
914 }); 923 });
915 } 924 }
916 }; 925 };
917 }.bind(this)()); 926 }());
918 927
919 if (this.speechEndCallback_ && i == a.length - 1) 928 if (i == this.speechBuffer_.length - 1)
920 speechProps['endCallback'] = this.speechEndCallback_; 929 speechProps['endCallback'] = this.speechEndCallback_;
921 else 930
922 speechProps['endCallback'] = null;
923 cvox.ChromeVox.tts.speak( 931 cvox.ChromeVox.tts.speak(
924 buff.toString(), queueMode, speechProps); 932 buff.toString(), queueMode, speechProps);
925 queueMode = cvox.QueueMode.QUEUE; 933 queueMode = cvox.QueueMode.QUEUE;
926 }.bind(this)); 934 }
927 935
928 // Braille. 936 // Braille.
929 if (this.brailleBuffer_.length) { 937 if (this.brailleBuffer_.length) {
930 var buff = this.createBrailleOutput_(); 938 var buff = this.createBrailleOutput_();
931 var selSpan = 939 var selSpan =
932 buff.getSpanInstanceOf(Output.SelectionSpan); 940 buff.getSpanInstanceOf(Output.SelectionSpan);
933 var startIndex = -1, endIndex = -1; 941 var startIndex = -1, endIndex = -1;
934 if (selSpan) { 942 if (selSpan) {
935 var valueStart = buff.getSpanStart(selSpan); 943 var valueStart = buff.getSpanStart(selSpan);
936 var valueEnd = buff.getSpanEnd(selSpan); 944 var valueEnd = buff.getSpanEnd(selSpan);
(...skipping 23 matching lines...) Expand all
960 * @param {!cursors.Range} range 968 * @param {!cursors.Range} range
961 * @param {cursors.Range} prevRange 969 * @param {cursors.Range} prevRange
962 * @param {EventType|Output.EventType} type 970 * @param {EventType|Output.EventType} type
963 * @param {!Array<Spannable>} buff Buffer to receive rendered output. 971 * @param {!Array<Spannable>} buff Buffer to receive rendered output.
964 * @private 972 * @private
965 */ 973 */
966 render_: function(range, prevRange, type, buff) { 974 render_: function(range, prevRange, type, buff) {
967 if (prevRange && !prevRange.isValid()) 975 if (prevRange && !prevRange.isValid())
968 prevRange = null; 976 prevRange = null;
969 977
978 // Scan ancestors to get the value of |outputContextFirst|.
979 var parent = range.start.node;
980 while (parent) {
981 if (Output.ROLE_INFO_[parent.role] &&
982 Output.ROLE_INFO_[parent.role].outputContextFirst) {
983 this.outputContextFirst_ = true;
984 break;
985 }
986 parent = parent.parent;
987 }
988
970 if (range.isSubNode()) 989 if (range.isSubNode())
971 this.subNode_(range, prevRange, type, buff); 990 this.subNode_(range, prevRange, type, buff);
972 else 991 else
973 this.range_(range, prevRange, type, buff); 992 this.range_(range, prevRange, type, buff);
974 }, 993 },
975 994
976 /** 995 /**
977 * Format the node given the format specifier. 996 * Format the node given the format specifier.
978 * @param {AutomationNode} node 997 * @param {AutomationNode} node
979 * @param {string|!Object} format The output format either specified as an 998 * @param {string|!Object} format The output format either specified as an
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after
1357 }, 1376 },
1358 1377
1359 /** 1378 /**
1360 * @param {!AutomationNode} node 1379 * @param {!AutomationNode} node
1361 * @param {!AutomationNode} prevNode 1380 * @param {!AutomationNode} prevNode
1362 * @param {EventType|Output.EventType} type 1381 * @param {EventType|Output.EventType} type
1363 * @param {!Array<Spannable>} buff 1382 * @param {!Array<Spannable>} buff
1364 * @private 1383 * @private
1365 */ 1384 */
1366 ancestry_: function(node, prevNode, type, buff) { 1385 ancestry_: function(node, prevNode, type, buff) {
1367 // Check to see if ancestry output is ignored.
1368 if (Output.ROLE_INFO_[node.role] &&
1369 Output.ROLE_INFO_[node.role].ignoreAncestry)
1370 return;
1371
1372 var prevUniqueAncestors = 1386 var prevUniqueAncestors =
1373 AutomationUtil.getUniqueAncestors(node, prevNode); 1387 AutomationUtil.getUniqueAncestors(node, prevNode);
1374 var uniqueAncestors = AutomationUtil.getUniqueAncestors(prevNode, node); 1388 var uniqueAncestors = AutomationUtil.getUniqueAncestors(prevNode, node);
1375 1389
1376 // First, look up the event type's format block. 1390 // First, look up the event type's format block.
1377 // Navigate is the default event. 1391 // Navigate is the default event.
1378 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; 1392 var eventBlock = Output.RULES[type] || Output.RULES['navigate'];
1379 1393
1380 var getMergedRoleBlock = function(role) { 1394 var getMergedRoleBlock = function(role) {
1381 var parentRole = (Output.ROLE_INFO_[role] || {}).inherits; 1395 var parentRole = (Output.ROLE_INFO_[role] || {}).inherits;
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
1708 /** 1722 /**
1709 * Gets the output buffer for braille. 1723 * Gets the output buffer for braille.
1710 * @return {!Spannable} 1724 * @return {!Spannable}
1711 */ 1725 */
1712 get brailleOutputForTest() { 1726 get brailleOutputForTest() {
1713 return this.createBrailleOutput_(); 1727 return this.createBrailleOutput_();
1714 } 1728 }
1715 }; 1729 };
1716 1730
1717 }); // goog.scope 1731 }); // goog.scope
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698