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

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

Issue 2509883002: Select-to-speak extension code (Closed)
Patch Set: Created 4 years, 1 month 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 | « no previous file | chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2 » ('j') | 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
5 var RoleType = chrome.automation.RoleType;
6
7 /**
8 * @constructor
David Tseng 2016/11/22 19:01:09 Are you planning on compiling this file (at least
dmazzoni 2016/11/28 18:51:12 Yes. I finished adding that to this change now. To
9 */
10 SelectToSpeak = function() {
11 this.node_ = null;
12 this.down_ = false;
13
14 chrome.automation.getDesktop(function(d) {
15 d.addEventListener('mousePressed', this.onMousePressed_.bind(this), true);
David Tseng 2016/11/22 19:01:10 chrome.automation.EventType
dmazzoni 2016/11/28 18:51:12 Done.
16 d.addEventListener('mouseDragged', this.onMouseDragged_.bind(this), true);
17 d.addEventListener('mouseMoved', this.onMouseDragged_.bind(this), true);
David Tseng 2016/11/22 19:01:09 onMouseDraggedOrMoved? (or were these supposed to
dmazzoni 2016/11/28 18:51:13 Actually we don't need to handle mouseMoved. Fixed
18 d.addEventListener('mouseReleased', this.onMouseReleased_.bind(this), true);
19 d.addEventListener('mouseCanceled', this.onMouseCanceled_.bind(this), true);
20 }.bind(this));
21 };
22
23 SelectToSpeak.prototype = {
24 /**
25 * Called when the mouse is pressed and the user is in a mode where
26 * select-to-speak is capturing mouse events (for example holding down
27 * Search).
28 *
29 * @param {!AutomationEvent} evt
30 */
31 onMousePressed_: function(evt) {
32 this.down_ = true;
33 this.mouseStart_ = {x: evt.mouseX, y: evt.mouseY};
34 this.startNode_ = evt.target;
35 this.speechQueue_ = [];
36 chrome.tts.stop();
37 this.onMouseDragged_(evt);
38 },
39
40 /**
41 * Called when the mouse is moved or dragged and the user is in a
42 * mode where select-to-speak is capturing mouse events (for example
David Tseng 2016/11/22 19:01:10 Select to speak only captures if search is down, r
dmazzoni 2016/11/28 18:51:13 Currently yes but I wanted to write the comment in
43 * holding down Search).
44 *
45 * @param {!AutomationEvent} evt
46 */
47 onMouseDragged_: function(evt) {
48 if (!this.down_)
David Tseng 2016/11/22 19:01:10 Doesn't a mouse drag already mean a mouse down? I
dmazzoni 2016/11/28 18:51:12 This is still needed to handle a race condition wh
49 return;
50
51 var rect = {left: Math.floor(this.mouseStart_.x),
52 top: Math.floor(this.mouseStart_.y),
David Tseng 2016/11/22 19:01:10 How does this work if I drag up or to the left? Do
dmazzoni 2016/11/28 18:51:12 Good point. Fixed.
53 width: Math.floor(evt.mouseX - this.mouseStart_.x),
54 height: Math.floor(evt.mouseY - this.mouseStart_.y)};
55 chrome.accessibilityPrivate.setFocusRing([rect]);
56 },
57
58 /**
59 * Called when the mouse is moved or dragged and the user is in a
60 * mode where select-to-speak is capturing mouse events (for example
David Tseng 2016/11/22 19:01:10 Update the comment
dmazzoni 2016/11/28 18:51:12 Done.
61 * holding down Search).
62 *
63 * @param {!AutomationEvent} evt
64 */
65 onMouseReleased_: function(evt) {
66 this.onMouseDragged_(evt);
67 this.down_ = false;
68
69 chrome.accessibilityPrivate.setFocusRing([]);
David Tseng 2016/11/22 19:01:10 I would have expected this to happen when s2s goes
dmazzoni 2016/11/28 18:51:12 That's handled in onMouseCanceled. For onMouseRel
70
71 // Walk up to the nearest window, web area, or dialog that the
72 // hit node is contained inside. Only speak objects within that
73 // container. In the future we might include other container-like
74 // roles here.
75 var root = this.startNode_;
76 while (root.parent &&
77 root.role != RoleType.window &&
78 root.role != RoleType.rootWebArea &&
79 root.role != RoleType.desktop &&
80 root.role != RoleType.dialog) {
81 root = root.parent;
82 }
83
84 var rect = {left: Math.floor(this.mouseStart_.x),
85 top: Math.floor(this.mouseStart_.y),
86 width: Math.floor(evt.mouseX - this.mouseStart_.x),
87 height: Math.floor(evt.mouseY - this.mouseStart_.y)};
88 var nodes = [];
89 this.findAllMatching_(root, rect, nodes);
90
91 this.speechQueue_ = nodes;
92 this.speakNextInQueue_();
93 },
94
95 /**
96 * Called when the user cancels select-to-speak's capturing of mouse
97 * events (for example by releasing Search while the mouse is still down).
98 *
99 * @param {!AutomationEvent} evt
100 */
101 onMouseCanceled_: function(evt) {
102 this.down_ = false;
103 chrome.accessibilityPrivate.setFocusRing([]);
104 this.speechQueue_ = [];
105 chrome.tts.stop();
106 },
107
108 /**
109 * Returns true if |rect1| and |rect2| overlap. The rects must define
110 * left, top, width, and height.
111 * @param {Object} rect1
112 * @param {Object} rect2
113 * @return {boolean} True if the rects overlap.
114 */
115 overlaps_: function(rect1, rect2) {
David Tseng 2016/11/22 19:01:09 No need to define this function in this class; mak
dmazzoni 2016/11/28 18:51:12 Done.
116 var l1 = rect1.left;
117 var r1 = rect1.left + rect1.width;
118 var t1 = rect1.top;
119 var b1 = rect1.top + rect1.height;
120 var l2 = rect2.left;
121 var r2 = rect2.left + rect2.width;
122 var t2 = rect2.top;
123 var b2 = rect2.top + rect2.height;
124 return (l1 < r2 && r1 > l2 && t1 < b2 && b1 > t2);
David Tseng 2016/11/22 19:01:09 Doesn't look right. What happens if the two rects
dmazzoni 2016/11/28 18:51:13 Both of those cases work as long as the rects have
125 },
126
127 /**
128 * Finds all nodes within the subtree rooted at |node| that overlap
129 * a given rectangle.
130 * @param {AutomationNode} The starting node.
131 * @param {Object} rect The bounding box to search.
132 * @param {Array<AutomationNode>} nodes The matching node array to be
133 * populated.
134 * @return {boolean} True if any matches are found.
135 */
136 findAllMatching_: function(node, rect, nodes) {
137 var found = false;
138 for (var c = node.firstChild; c; c = c.nextSibling) {
139 if (this.findAllMatching_(c, rect, nodes))
140 found = true;
141 }
142
143 if (found)
144 return true;
145
146 if (!node.name)
David Tseng 2016/11/22 19:01:10 This is going to give some strange results I think
dmazzoni 2016/11/28 18:51:13 I think it's actually useful that it reads the alt
147 return false;
148
149 if (this.overlaps_(node.location, rect)) {
150 nodes.push(node);
151 return true;
152 }
153
154 return false;
155 },
156
157 /**
158 * Pop the next matching node from the queue and speak and highlight it.
159 */
160 speakNextInQueue_: function() {
161 if (!this.speechQueue_ || this.speechQueue_.length == 0) {
David Tseng 2016/11/22 19:01:10 Looks like type checking would help here. Set this
dmazzoni 2016/11/28 18:51:12 Done.
162 chrome.accessibilityPrivate.setFocusRing([]);
163 return;
164 }
165
166 var node = this.speechQueue_.shift();
167 chrome.accessibilityPrivate.setFocusRing([node.location]);
168 chrome.tts.speak(node.name, {
169 lang: 'en-US',
David Tseng 2016/11/22 19:01:10 Maybe we should think about starting some code sha
dmazzoni 2016/11/28 18:51:13 Agreed, perhaps some common utility libraries.
170 'enqueue': false,
David Tseng 2016/11/22 19:01:09 Can we let the native tts queue handle things?
dmazzoni 2016/11/28 18:51:12 Done, it just means slightly trickier logic inside
171 onEvent: (function(event) {
172 if (event.type == 'end') {
173 this.speakNextInQueue_();
174 } else if (event.type == 'interrupted' ||
175 event.type == 'cancelled') {
176 chrome.accessibilityPrivate.setFocusRing([]);
177 }
178 }).bind(this)
179 });
180 }
181 };
182
183 new SelectToSpeak();
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2 » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698