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

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

Issue 2883283003: Revert of Refactor Select-to-speak so that mouse events are forwarded to the extension. (Closed)
Patch Set: Created 3 years, 7 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
« no previous file with comments | « chrome/browser/chromeos/accessibility/select_to_speak_event_handler_unittest.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 } 46 }
47 47
48 /** 48 /**
49 * @constructor 49 * @constructor
50 */ 50 */
51 var SelectToSpeak = function() { 51 var SelectToSpeak = function() {
52 /** @private { AutomationNode } */ 52 /** @private { AutomationNode } */
53 this.node_ = null; 53 this.node_ = null;
54 54
55 /** @private { boolean } */ 55 /** @private { boolean } */
56 this.trackingMouse_ = false; 56 this.down_ = false;
57
58 /** @private { boolean } */
59 this.didTrackMouse_ = false;
60
61 /** @private { boolean } */
62 this.isSearchKeyDown_ = false;
63
64 /** @private { !Set<number> } */
65 this.keysCurrentlyDown_ = new Set();
66
67 /** @private { !Set<number> } */
68 this.keysPressedTogether_ = new Set();
69 57
70 /** @private {{x: number, y: number}} */ 58 /** @private {{x: number, y: number}} */
71 this.mouseStart_ = {x: 0, y: 0}; 59 this.mouseStart_ = {x: 0, y: 0};
72 60
73 /** @private {{x: number, y: number}} */
74 this.mouseEnd_ = {x: 0, y: 0};
75
76 /** @private {AutomationRootNode} */
77 chrome.automation.getDesktop(function(desktop) { 61 chrome.automation.getDesktop(function(desktop) {
78 this.desktop_ = desktop;
79
80 // After the user selects a region of the screen, we do a hit test at
81 // the center of that box using the automation API. The result of the
82 // hit test is a MOUSE_RELEASED accessibility event.
83 desktop.addEventListener( 62 desktop.addEventListener(
84 EventType.MOUSE_RELEASED, this.onAutomationHitTest_.bind(this), 63 EventType.MOUSE_PRESSED, this.onMousePressed_.bind(this), true);
85 true); 64 desktop.addEventListener(
65 EventType.MOUSE_DRAGGED, this.onMouseDragged_.bind(this), true);
66 desktop.addEventListener(
67 EventType.MOUSE_RELEASED, this.onMouseReleased_.bind(this), true);
68 desktop.addEventListener(
69 EventType.MOUSE_CANCELED, this.onMouseCanceled_.bind(this), true);
86 }.bind(this)); 70 }.bind(this));
87 71
88 /** @private { ?string } */ 72 /** @private { ?string } */
89 this.voiceNameFromPrefs_ = null; 73 this.voiceNameFromPrefs_ = null;
90 74
91 /** @private { ?string } */ 75 /** @private { ?string } */
92 this.voiceNameFromLocale_ = null; 76 this.voiceNameFromLocale_ = null;
93 77
94 /** @private { Set<string> } */ 78 /** @private { Set<string> } */
95 this.validVoiceNames_ = new Set(); 79 this.validVoiceNames_ = new Set();
96 80
97 /** @private { number } */ 81 /** @private { number } */
98 this.speechRate_ = 1.0; 82 this.speechRate_ = 1.0;
99 83
100 /** @const { string } */ 84 /** @const { string } */
101 this.color_ = "#f73a98"; 85 this.color_ = "#f73a98";
102 86
103 this.initPreferences_(); 87 this.initPreferences_();
104
105 this.setUpEventListeners_();
106 }; 88 };
107 89
108 /** @const {number} */
109 SelectToSpeak.SEARCH_KEY_CODE = 91;
110
111 /** @const {number} */
112 SelectToSpeak.CONTROL_KEY_CODE = 17;
113
114 SelectToSpeak.prototype = { 90 SelectToSpeak.prototype = {
115 /** 91 /**
116 * Called when the mouse is pressed and the user is in a mode where 92 * Called when the mouse is pressed and the user is in a mode where
117 * select-to-speak is capturing mouse events (for example holding down 93 * select-to-speak is capturing mouse events (for example holding down
118 * Search). 94 * Search).
119 * 95 *
120 * @param {!Event} evt The DOM event 96 * @param {!AutomationEvent} evt
121 * @return {boolean} True if the default action should be performed;
122 * we always return false because we don't want any other event
123 * handlers to run.
124 */ 97 */
125 onMouseDown_: function(evt) { 98 onMousePressed_: function(evt) {
126 if (!this.isSearchKeyDown_) 99 this.down_ = true;
127 return false; 100 this.mouseStart_ = {x: evt.mouseX, y: evt.mouseY};
128 101 this.startNode_ = evt.target;
129 this.trackingMouse_ = true;
130 this.didTrackMouse_ = true;
131 this.mouseStart_ = {x: evt.screenX, y: evt.screenY};
132 chrome.tts.stop(); 102 chrome.tts.stop();
133 103 this.onMouseDragged_(evt);
134 // Fire a hit test event on click to warm up the cache.
135 this.desktop_.hitTest(evt.screenX, evt.screenY, EventType.MOUSE_PRESSED);
136
137 this.onMouseMove_(evt);
138 return false;
139 }, 104 },
140 105
141 /** 106 /**
142 * Called when the mouse is moved or dragged and the user is in a 107 * Called when the mouse is moved or dragged and the user is in a
143 * mode where select-to-speak is capturing mouse events (for example 108 * mode where select-to-speak is capturing mouse events (for example
144 * holding down Search). 109 * holding down Search).
145 * 110 *
146 * @param {!Event} evt The DOM event 111 * @param {!AutomationEvent} evt
147 * @return {boolean} True if the default action should be performed.
148 */ 112 */
149 onMouseMove_: function(evt) { 113 onMouseDragged_: function(evt) {
150 if (!this.trackingMouse_) 114 if (!this.down_)
151 return false; 115 return;
152 116
153 var rect = rectFromPoints( 117 var rect = rectFromPoints(
154 this.mouseStart_.x, this.mouseStart_.y, 118 this.mouseStart_.x, this.mouseStart_.y,
155 evt.screenX, evt.screenY); 119 evt.mouseX, evt.mouseY);
156 chrome.accessibilityPrivate.setFocusRing([rect], this.color_); 120 chrome.accessibilityPrivate.setFocusRing([rect], this.color_);
157 return false;
158 }, 121 },
159 122
160 /** 123 /**
161 * Called when the mouse is released and the user is in a 124 * Called when the mouse is released and the user is in a
162 * mode where select-to-speak is capturing mouse events (for example 125 * mode where select-to-speak is capturing mouse events (for example
163 * holding down Search). 126 * holding down Search).
164 * 127 *
165 * @param {!Event} evt 128 * @param {!AutomationEvent} evt
166 * @return {boolean} True if the default action should be performed.
167 */ 129 */
168 onMouseUp_: function(evt) { 130 onMouseReleased_: function(evt) {
169 this.onMouseMove_(evt); 131 this.onMouseDragged_(evt);
170 this.trackingMouse_ = false; 132 this.down_ = false;
171 133
172 chrome.accessibilityPrivate.setFocusRing([]); 134 chrome.accessibilityPrivate.setFocusRing([]);
173 135
174 this.mouseEnd_ = {x: evt.screenX, y: evt.screenY}; 136 // Walk up to the nearest window, web area, or dialog that the
175 var ctrX = Math.floor((this.mouseStart_.x + this.mouseEnd_.x) / 2);
176 var ctrY = Math.floor((this.mouseStart_.y + this.mouseEnd_.y) / 2);
177
178 // Do a hit test at the center of the area the user dragged over.
179 // This will give us some context when searching the accessibility tree.
180 // The hit test will result in a EventType.MOUSE_RELEASED event being
181 // fired on the result of that hit test, which will trigger
182 // onAutomationHitTest_.
183 this.desktop_.hitTest(ctrX, ctrY, EventType.MOUSE_RELEASED);
184 return false;
185 },
186
187 /**
188 * Called in response to our hit test after the mouse is released,
189 * when the user is in a mode where select-to-speak is capturing
190 * mouse events (for example holding down Search).
191 *
192 * @param {!AutomationEvent} evt The automation event.
193 */
194 onAutomationHitTest_: function(evt) {
195 // Walk up to the nearest window, web area, toolbar, or dialog that the
196 // hit node is contained inside. Only speak objects within that 137 // hit node is contained inside. Only speak objects within that
197 // container. In the future we might include other container-like 138 // container. In the future we might include other container-like
198 // roles here. 139 // roles here.
199 var root = evt.target; 140 var root = this.startNode_;
200 while (root.parent && 141 while (root.parent &&
201 root.role != RoleType.WINDOW && 142 root.role != RoleType.WINDOW &&
202 root.role != RoleType.ROOT_WEB_AREA && 143 root.role != RoleType.ROOT_WEB_AREA &&
203 root.role != RoleType.DESKTOP && 144 root.role != RoleType.DESKTOP &&
204 root.role != RoleType.DIALOG && 145 root.role != RoleType.DIALOG) {
205 root.role != RoleType.ALERT_DIALOG &&
206 root.role != RoleType.TOOLBAR) {
207 root = root.parent; 146 root = root.parent;
208 } 147 }
209 148
210 var rect = rectFromPoints( 149 var rect = rectFromPoints(
211 this.mouseStart_.x, this.mouseStart_.y, 150 this.mouseStart_.x, this.mouseStart_.y,
212 this.mouseEnd_.x, this.mouseEnd_.y); 151 evt.mouseX, evt.mouseY);
213 var nodes = []; 152 var nodes = [];
214 this.findAllMatching_(root, rect, nodes); 153 this.findAllMatching_(root, rect, nodes);
215 this.startSpeechQueue_(nodes); 154 this.startSpeechQueue_(nodes);
216 }, 155 },
217 156
218 /** 157 /**
219 * @param {!Event} evt 158 * Called when the user cancels select-to-speak's capturing of mouse
159 * events (for example by releasing Search while the mouse is still down).
160 *
161 * @param {!AutomationEvent} evt
220 */ 162 */
221 onKeyDown_: function(evt) { 163 onMouseCanceled_: function(evt) {
222 if (this.keysPressedTogether_.size == 0 && 164 this.down_ = false;
223 evt.keyCode == SelectToSpeak.SEARCH_KEY_CODE) { 165 chrome.accessibilityPrivate.setFocusRing([]);
224 this.isSearchKeyDown_ = true; 166 chrome.tts.stop();
225 } else if (!this.trackingMouse_) {
226 this.isSearchKeyDown_ = false;
227 }
228
229 this.keysCurrentlyDown_.add(evt.keyCode);
230 this.keysPressedTogether_.add(evt.keyCode);
231 }, 167 },
232 168
233 /** 169 /**
234 * @param {!Event} evt
235 */
236 onKeyUp_: function(evt) {
237 if (evt.keyCode == SelectToSpeak.SEARCH_KEY_CODE) {
238 this.isSearchKeyDown_ = false;
239
240 // If we were in the middle of tracking the mouse, cancel it.
241 if (this.trackingMouse_) {
242 this.trackingMouse_ = false;
243 chrome.accessibilityPrivate.setFocusRing([]);
244 chrome.tts.stop();
245 }
246 }
247
248 // Stop speech when the user taps and releases Control or Search
249 // without using the mouse or pressing any other keys along the way.
250 if (!this.didTrackMouse_ &&
251 (evt.keyCode == SelectToSpeak.SEARCH_KEY_CODE ||
252 evt.keyCode == SelectToSpeak.CONTROL_KEY_CODE) &&
253 this.keysPressedTogether_.has(evt.keyCode) &&
254 this.keysPressedTogether_.size == 1) {
255 this.trackingMouse_ = false;
256 chrome.accessibilityPrivate.setFocusRing([]);
257 chrome.tts.stop();
258 }
259
260 this.keysCurrentlyDown_.delete(evt.keyCode);
261 if (this.keysCurrentlyDown_.size == 0) {
262 this.keysPressedTogether_.clear();
263 this.didTrackMouse_ = false;
264 }
265 },
266
267 /**
268 * Set up event listeners for mouse and keyboard events. These are
269 * forwarded to us from the SelectToSpeakEventHandler so they should
270 * be interpreted as global events on the whole screen, not local to
271 * any particular window.
272 */
273 setUpEventListeners_: function() {
274 document.addEventListener('keydown', this.onKeyDown_.bind(this));
275 document.addEventListener('keyup', this.onKeyUp_.bind(this));
276 document.addEventListener('mousedown', this.onMouseDown_.bind(this));
277 document.addEventListener('mousemove', this.onMouseMove_.bind(this));
278 document.addEventListener('mouseup', this.onMouseUp_.bind(this));
279 },
280
281 /**
282 * Finds all nodes within the subtree rooted at |node| that overlap 170 * Finds all nodes within the subtree rooted at |node| that overlap
283 * a given rectangle. 171 * a given rectangle.
284 * @param {AutomationNode} node The starting node. 172 * @param {AutomationNode} node The starting node.
285 * @param {{left: number, top: number, width: number, height: number}} rect 173 * @param {{left: number, top: number, width: number, height: number}} rect
286 * The bounding box to search. 174 * The bounding box to search.
287 * @param {Array<AutomationNode>} nodes The matching node array to be 175 * @param {Array<AutomationNode>} nodes The matching node array to be
288 * populated. 176 * populated.
289 * @return {boolean} True if any matches are found. 177 * @return {boolean} True if any matches are found.
290 */ 178 */
291 findAllMatching_: function(node, rect, nodes) { 179 findAllMatching_: function(node, rect, nodes) {
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 this.updateDefaultVoice_(); 276 this.updateDefaultVoice_();
389 window.speechSynthesis.onvoiceschanged = (function() { 277 window.speechSynthesis.onvoiceschanged = (function() {
390 this.updateDefaultVoice_(); 278 this.updateDefaultVoice_();
391 }).bind(this); 279 }).bind(this);
392 }, 280 },
393 281
394 /** 282 /**
395 * Get the list of TTS voices, and set the default voice if not already set. 283 * Get the list of TTS voices, and set the default voice if not already set.
396 */ 284 */
397 updateDefaultVoice_: function() { 285 updateDefaultVoice_: function() {
286 console.log('updateDefaultVoice_ ' + this.down_);
398 var uiLocale = chrome.i18n.getMessage('@@ui_locale'); 287 var uiLocale = chrome.i18n.getMessage('@@ui_locale');
399 uiLocale = uiLocale.replace('_', '-').toLowerCase(); 288 uiLocale = uiLocale.replace('_', '-').toLowerCase();
400 289
401 chrome.tts.getVoices((function(voices) { 290 chrome.tts.getVoices((function(voices) {
402 console.log('updateDefaultVoice_ voices: ' + voices.length); 291 console.log('updateDefaultVoice_ voices: ' + voices.length);
403 this.validVoiceNames_ = new Set(); 292 this.validVoiceNames_ = new Set();
404 293
405 if (voices.length == 0) 294 if (voices.length == 0)
406 return; 295 return;
407 296
(...skipping 17 matching lines...) Expand all
425 this.voiceNameFromLocale_ = voices[0].voiceName; 314 this.voiceNameFromLocale_ = voices[0].voiceName;
426 315
427 chrome.storage.sync.get(['voice'], (function(prefs) { 316 chrome.storage.sync.get(['voice'], (function(prefs) {
428 if (!prefs['voice']) { 317 if (!prefs['voice']) {
429 chrome.storage.sync.set({'voice': voices[0].voiceName}); 318 chrome.storage.sync.set({'voice': voices[0].voiceName});
430 } 319 }
431 }).bind(this)); 320 }).bind(this));
432 }).bind(this)); 321 }).bind(this));
433 } 322 }
434 }; 323 };
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/accessibility/select_to_speak_event_handler_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698