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

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

Issue 2777203006: Added auto-scan, made some small changes to how prefs are stored, refactored. (Closed)
Patch Set: 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 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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 let AutomationNode = chrome.automation.AutomationNode;
6
7 let debuggingEnabled = true;
8
9 /** 5 /**
6 * Class to manage SwitchAccess and interact with other controllers.
7 *
10 * @constructor 8 * @constructor
9 * @implements {SwitchAccessInterface}
dmazzoni 2017/03/29 05:52:20 This worked out well!
elichtenberg 2017/03/29 19:15:11 Thanks!
11 */ 10 */
12 let SwitchAccess = function() { 11 let SwitchAccess = function() {
13 console.log('Switch access is enabled'); 12 console.log('Switch access is enabled');
14 13
15 /** 14 /**
16 * User preferences. 15 * User preferences.
17 * 16 *
18 * @type {SwitchAccessPrefs} 17 * @type {SwitchAccessPrefs}
19 */ 18 */
20 this.switchAccessPrefs = null; 19 this.switchAccessPrefs = null;
21 20
22 /** 21 /**
22 * Handles changes to auto-scan.
23 *
24 * @private {AutoScanManager}
25 */
26 this.autoScanManager_ = null;
27
28 /**
29 * Handles keyboard input.
30 *
31 * @private {KeyboardHandler}
32 */
33 this.keyboardHandler_ = null;
34
35 /**
36 * Moves to the appropriate node in the accessibility tree.
37 *
38 * @private {AutomationTreeWalker}
39 */
40 this.treeWalker_ = null;
41
42 /**
23 * Currently selected node. 43 * Currently selected node.
24 * 44 *
25 * @private {AutomationNode} 45 * @private {AutomationNode}
26 */ 46 */
27 this.node_ = null; 47 this.node_ = null;
28 48
29 /** 49 /**
30 * Root node (i.e., the desktop). 50 * Root node (i.e., the desktop).
31 * 51 *
32 * @private {AutomationNode} 52 * @private {AutomationNode}
33 */ 53 */
34 this.root_ = null; 54 this.root_ = null;
35 55
36 this.init_(); 56 this.init_();
37 }; 57 };
38 58
39 SwitchAccess.prototype = { 59 SwitchAccess.prototype = {
40 /** 60 /**
41 * Set this.node_ and this.root_ to the desktop node, and set up preferences 61 * Set this.node_ and this.root_ to the desktop node, and set up preferences,
42 * and event listeners. 62 * controllers, and event listeners.
43 * 63 *
44 * @private 64 * @private
45 */ 65 */
46 init_: function() { 66 init_: function() {
47 this.switchAccessPrefs = new SwitchAccessPrefs(); 67 this.switchAccessPrefs = new SwitchAccessPrefs();
68 this.autoScanManager_ = new AutoScanManager(this);
69 this.keyboardHandler_ = new KeyboardHandler(this);
70 this.treeWalker_ = new AutomationTreeWalker();
48 71
49 chrome.automation.getDesktop(function(desktop) { 72 chrome.automation.getDesktop(function(desktop) {
50 this.node_ = desktop; 73 this.node_ = desktop;
51 this.root_ = desktop; 74 this.root_ = desktop;
52 console.log('AutomationNode for desktop is loaded'); 75 console.log('AutomationNode for desktop is loaded');
53 this.printNode_(this.node_); 76 this.printNode_(this.node_);
54
55 document.addEventListener('keyup', function(event) {
56 switch (event.key) {
57 case '1':
58 console.log('1 = go to previous element');
59 this.moveToPrevious_();
60 break;
61 case '2':
62 console.log('2 = go to next element');
63 this.moveToNext_();
64 break;
65 case '3':
66 console.log('3 = do default on element');
67 this.doDefault_();
68 break;
69 case '4':
70 this.showOptionsPage_();
71 break;
72 }
73 if (debuggingEnabled) {
74 switch (event.key) {
75 case '6':
76 console.log('6 = go to previous element (debug mode)');
77 this.debugMoveToPrevious_();
78 break;
79 case '7':
80 console.log('7 = go to next element (debug mode)');
81 this.debugMoveToNext_();
82 break;
83 case '8':
84 console.log('8 = go to child element (debug mode)');
85 this.debugMoveToFirstChild_();
86 break;
87 case '9':
88 console.log('9 = go to parent element (debug mode)');
89 this.debugMoveToParent_();
90 break;
91 }
92 }
93 if (this.node_)
94 chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
95 }.bind(this));
96 }.bind(this)); 77 }.bind(this));
97 78
98 document.addEventListener('prefsUpdate', this.handlePrefsUpdate_); 79 document.addEventListener(
80 'prefsUpdate', this.handlePrefsUpdate_.bind(this));
81 },
82
83 /**
84 * Set this.node_ to the next interesting node. If no interesting node comes
85 * after this.node_, set this.node_ to the first interesting node.
86 *
87 * @override
88 */
89 moveToNext: function() {
90 let next = this.treeWalker_.moveToNext(this.node_, this.root_);
91 if (next) {
92 this.node_ = next;
93 this.printNode_(this.node_);
94 chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
95 }
99 }, 96 },
100 97
101 /** 98 /**
102 * Set this.node_ to the previous interesting node. If no interesting node 99 * Set this.node_ to the previous interesting node. If no interesting node
103 * comes before this.node_, set this.node_ to the last interesting node. 100 * comes before this.node_, set this.node_ to the last interesting node.
104 * 101 *
105 * @private 102 * @override
106 */ 103 */
107 moveToPrevious_: function() { 104 moveToPrevious: function() {
108 if (this.node_) { 105 let prev = this.treeWalker_.moveToPrevious(this.node_, this.root_);
109 let prev = this.getPreviousNode_(this.node_); 106 if (prev) {
110 while (prev && !this.isInteresting_(prev)) { 107 this.node_ = prev;
111 prev = this.getPreviousNode_(prev); 108 this.printNode_(this.node_);
112 } 109 chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
113 if (prev) {
114 this.node_ = prev;
115 this.printNode_(this.node_);
116 return;
117 }
118 } 110 }
119
120 if (this.root_) {
121 console.log('Reached the first interesting node. Restarting with last.')
122 let prev = this.getYoungestDescendant_(this.root_);
123 while (prev && !this.isInteresting_(prev)) {
124 prev = this.getPreviousNode_(prev);
125 }
126 if (prev) {
127 this.node_ = prev;
128 this.printNode_(this.node_);
129 return;
130 }
131 }
132
133 console.log('Found no interesting nodes to visit.')
134 }, 111 },
135 112
136 /** 113 /**
137 * Set this.node_ to the next interesting node. If no interesting node comes
138 * after this.node_, set this.node_ to the first interesting node.
139 *
140 * @private
141 */
142 moveToNext_: function() {
143 if (this.node_) {
144 let next = this.getNextNode_(this.node_);
145 while (next && !this.isInteresting_(next))
146 next = this.getNextNode_(next);
147 if (next) {
148 this.node_ = next;
149 this.printNode_(this.node_);
150 return;
151 }
152 }
153
154 if (this.root_) {
155 console.log('Reached the last interesting node. Restarting with first.');
156 let next = this.root_.firstChild;
157 while (next && !this.isInteresting_(next))
158 next = this.getNextNode_(next);
159 if (next) {
160 this.node_ = next;
161 this.printNode_(this.node_);
162 return;
163 }
164 }
165
166 console.log('Found no interesting nodes to visit.');
167 },
168
169 /**
170 * Given a flat list of nodes in pre-order, get the node that comes after
171 * |node|.
172 *
173 * @param {!AutomationNode} node
174 * @return {AutomationNode}
175 * @private
176 */
177 getNextNode_: function(node) {
178 // Check for child.
179 let child = node.firstChild;
180 if (child)
181 return child;
182
183 // No child. Check for right-sibling.
184 let sibling = node.nextSibling;
185 if (sibling)
186 return sibling;
187
188 // No right-sibling. Get right-sibling of closest ancestor.
189 let ancestor = node.parent;
190 while (ancestor) {
191 let aunt = ancestor.nextSibling;
192 if (aunt)
193 return aunt;
194 ancestor = ancestor.parent;
195 }
196
197 // No node found after |node|, so return null.
198 return null;
199 },
200
201 /**
202 * Given a flat list of nodes in pre-order, get the node that comes before
203 * |node|.
204 *
205 * @param {!AutomationNode} node
206 * @return {AutomationNode}
207 * @private
208 */
209 getPreviousNode_: function(node) {
210 // Check for left-sibling. Return its youngest descendant if it has one.
211 // Otherwise, return the sibling.
212 let sibling = node.previousSibling;
213 if (sibling) {
214 let descendant = this.getYoungestDescendant_(sibling);
215 if (descendant)
216 return descendant;
217 return sibling;
218 }
219
220 // No left-sibling. Check for parent.
221 let parent = node.parent;
222 if (parent)
223 return parent;
224
225 // No node found before |node|, so return null.
226 return null;
227 },
228
229 /**
230 * Get the youngest descendant of |node| if it has one.
231 *
232 * @param {!AutomationNode} node
233 * @return {AutomationNode}
234 * @private
235 */
236 getYoungestDescendant_: function(node) {
237 if (!node.lastChild)
238 return null;
239
240 while (node.lastChild)
241 node = node.lastChild;
242
243 return node;
244 },
245
246 /**
247 * Returns true if |node| is interesting.
248 *
249 * @param {!AutomationNode} node
250 * @return {boolean}
251 * @private
252 */
253 isInteresting_: function(node) {
254 return node.state && node.state.focusable;
255 },
256
257
258 /**
259 * Perform the default action on the currently selected node. 114 * Perform the default action on the currently selected node.
260 * 115 *
261 * @private 116 * @override
262 */ 117 */
263 doDefault_: function() { 118 doDefault: function() {
119 if (!this.node_)
120 return;
121
264 let state = this.node_.state; 122 let state = this.node_.state;
265 if (state && state.focusable) 123 if (state && state.focusable)
266 console.log('Node was focusable, doing default on it') 124 console.log('Node was focusable, doing default on it')
267 else if (state) 125 else if (state)
268 console.log('Node was not focusable, but still doing default'); 126 console.log('Node was not focusable, but still doing default');
269 else 127 else
270 console.log('Node has no state, still doing default'); 128 console.log('Node has no state, still doing default');
271 console.log('\n'); 129 console.log('\n');
272 this.node_.doDefault(); 130 this.node_.doDefault();
273 }, 131 },
274 132
275 /** 133 /**
276 * Open the options page in a new tab. 134 * Open the options page in a new tab.
277 * 135 *
278 * @private 136 * @override
279 */ 137 */
280 showOptionsPage_: function() { 138 showOptionsPage: function() {
281 let optionsPage = {url: 'options.html'}; 139 let optionsPage = {url: 'options.html'};
282 chrome.tabs.create(optionsPage); 140 chrome.tabs.create(optionsPage);
283 }, 141 },
284 142
285 /** 143 /**
144 * Perform actions as the result of actions by the user. Currently, restarts
145 * auto-scan if it is enabled.
146 *
147 * @override
148 */
149 performedUserAction: function() {
150 if (this.autoScanManager_.isRunning())
151 this.autoScanManager_.restart();
152 },
153
154 /**
286 * Handle a change in user preferences. 155 * Handle a change in user preferences.
287 * 156 *
288 * @param {!Event} event 157 * @param {!Event} event
289 * @private 158 * @private
290 */ 159 */
291 handlePrefsUpdate_: function(event) { 160 handlePrefsUpdate_: function(event) {
292 let updatedPrefs = event.detail; 161 let updatedPrefs = event.detail;
293 for (let key of Object.keys(updatedPrefs)) { 162 for (let key of Object.keys(updatedPrefs)) {
294 switch (key) { 163 switch (key) {
295 case 'enableAutoScan': 164 case 'enableAutoScan':
296 console.log('Auto-scan enabled set to: ' + updatedPrefs[key]); 165 this.autoScanManager_.setEnabled(updatedPrefs[key]);
297 break; 166 break;
298 case 'autoScanTime': 167 case 'autoScanTime':
299 console.log( 168 this.autoScanManager_.setScanTime(updatedPrefs[key]);
300 'Auto-scan time set to: ' + updatedPrefs[key] + " seconds");
301 break; 169 break;
302 } 170 }
303 } 171 }
304 }, 172 },
305 173
306 // TODO(elichtenberg): Move print functions to a custom logger class. Only 174 // TODO(elichtenberg): Move print functions to a custom logger class. Only
307 // log when debuggingEnabled is true. 175 // log when debuggingEnabled is true.
308 /** 176 /**
309 * Print out details about a node. 177 * Print out details about a node.
310 * 178 *
(...skipping 14 matching lines...) Expand all
325 } 193 }
326 console.log('Has ' + node.children.length + ' children'); 194 console.log('Has ' + node.children.length + ' children');
327 } else { 195 } else {
328 console.log('Node is null'); 196 console.log('Node is null');
329 } 197 }
330 console.log(node); 198 console.log(node);
331 console.log('\n'); 199 console.log('\n');
332 }, 200 },
333 201
334 /** 202 /**
203 * Move to the next sibling of this.node_ if it has one.
204 *
205 * @override
206 */
207 debugMoveToNext: function() {
208 let next = this.treeWalker_.debugMoveToNext(this.node_);
209 if (next) {
210 this.node_ = next;
211 this.printNode_(this.node_);
212 chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
213 }
214 },
215
216 /**
335 * Move to the previous sibling of this.node_ if it has one. 217 * Move to the previous sibling of this.node_ if it has one.
336 * 218 *
337 * @private 219 * @override
338 */ 220 */
339 debugMoveToPrevious_: function() { 221 debugMoveToPrevious: function() {
340 let previous = this.node_.previousSibling; 222 let prev = this.treeWalker_.debugMoveToPrevious(this.node_);
341 if (previous) { 223 if (prev) {
342 this.node_ = previous; 224 this.node_ = prev;
343 this.printNode_(this.node_); 225 this.printNode_(this.node_);
344 } else { 226 chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
345 console.log('Node is first of siblings');
346 console.log('\n');
347 }
348 },
349
350 /**
351 * Move to the next sibling of this.node_ if it has one.
352 *
353 * @private
354 */
355 debugMoveToNext_: function() {
356 let next = this.node_.nextSibling;
357 if (next) {
358 this.node_ = next;
359 this.printNode_(this.node_);
360 } else {
361 console.log('Node is last of siblings');
362 console.log('\n');
363 } 227 }
364 }, 228 },
365 229
366 /** 230 /**
367 * Move to the first child of this.node_ if it has one. 231 * Move to the first child of this.node_ if it has one.
368 * 232 *
369 * @private 233 * @override
370 */ 234 */
371 debugMoveToFirstChild_: function() { 235 debugMoveToFirstChild: function() {
372 let child = this.node_.firstChild; 236 let child = this.treeWalker_.debugMoveToFirstChild(this.node_);
373 if (child) { 237 if (child) {
374 this.node_ = child; 238 this.node_ = child;
375 this.printNode_(this.node_); 239 this.printNode_(this.node_);
376 } else { 240 chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
377 console.log('Node has no children');
378 console.log('\n');
379 } 241 }
380 }, 242 },
381 243
382 /** 244 /**
383 * Move to the parent of this.node_ if it has one. 245 * Move to the parent of this.node_ if it has one.
384 * 246 *
385 * @private 247 * @override
386 */ 248 */
387 debugMoveToParent_: function() { 249 debugMoveToParent: function() {
388 let parent = this.node_.parent; 250 let parent = this.treeWalker_.debugMoveToParent(this.node_);
389 if (parent) { 251 if (parent) {
390 this.node_ = parent; 252 this.node_ = parent;
391 this.printNode_(this.node_); 253 this.printNode_(this.node_);
392 } else { 254 chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
393 console.log('Node has no parent');
394 console.log('\n');
395 } 255 }
396 } 256 }
397 }; 257 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698