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

Side by Side Diff: chrome/renderer/resources/extensions/automation_custom_bindings.js

Issue 1589623002: Keep track of accessibility focus across windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Final suggestions Created 4 years, 10 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 // Custom bindings for the automation API. 5 // Custom bindings for the automation API.
6 var AutomationNode = require('automationNode').AutomationNode; 6 var AutomationNode = require('automationNode').AutomationNode;
7 var AutomationRootNode = require('automationNode').AutomationRootNode; 7 var AutomationRootNode = require('automationNode').AutomationRootNode;
8 var automation = require('binding').Binding.create('automation'); 8 var automation = require('binding').Binding.create('automation');
9 var automationInternal = 9 var automationInternal =
10 require('binding').Binding.create('automationInternal').generate(); 10 require('binding').Binding.create('automationInternal').generate();
11 var eventBindings = require('event_bindings'); 11 var eventBindings = require('event_bindings');
12 var Event = eventBindings.Event; 12 var Event = eventBindings.Event;
13 var exceptionHandler = require('uncaught_exception_handler'); 13 var exceptionHandler = require('uncaught_exception_handler');
14 var forEach = require('utils').forEach; 14 var forEach = require('utils').forEach;
15 var lastError = require('lastError'); 15 var lastError = require('lastError');
16 var logging = requireNative('logging'); 16 var logging = requireNative('logging');
17 var nativeAutomationInternal = requireNative('automationInternal'); 17 var nativeAutomationInternal = requireNative('automationInternal');
18 var GetRoutingID = nativeAutomationInternal.GetRoutingID; 18 var GetRoutingID = nativeAutomationInternal.GetRoutingID;
19 var GetSchemaAdditions = nativeAutomationInternal.GetSchemaAdditions; 19 var GetSchemaAdditions = nativeAutomationInternal.GetSchemaAdditions;
20 var DestroyAccessibilityTree = 20 var DestroyAccessibilityTree =
21 nativeAutomationInternal.DestroyAccessibilityTree; 21 nativeAutomationInternal.DestroyAccessibilityTree;
22 var GetIntAttribute = nativeAutomationInternal.GetIntAttribute; 22 var GetIntAttribute = nativeAutomationInternal.GetIntAttribute;
23 var StartCachingAccessibilityTrees = 23 var StartCachingAccessibilityTrees =
24 nativeAutomationInternal.StartCachingAccessibilityTrees; 24 nativeAutomationInternal.StartCachingAccessibilityTrees;
25 var AddTreeChangeObserver = nativeAutomationInternal.AddTreeChangeObserver; 25 var AddTreeChangeObserver = nativeAutomationInternal.AddTreeChangeObserver;
26 var RemoveTreeChangeObserver = 26 var RemoveTreeChangeObserver =
27 nativeAutomationInternal.RemoveTreeChangeObserver; 27 nativeAutomationInternal.RemoveTreeChangeObserver;
28 var GetFocus = nativeAutomationInternal.GetFocus;
28 var schema = GetSchemaAdditions(); 29 var schema = GetSchemaAdditions();
29 30
30 /** 31 /**
31 * A namespace to export utility functions to other files in automation. 32 * A namespace to export utility functions to other files in automation.
32 */ 33 */
33 window.automationUtil = function() {}; 34 window.automationUtil = function() {};
34 35
35 // TODO(aboxhall): Look into using WeakMap 36 // TODO(aboxhall): Look into using WeakMap
36 var idToCallback = {}; 37 var idToCallback = {};
37 38
(...skipping 21 matching lines...) Expand all
59 * @type {Object<number, TreeChangeObserver>} 60 * @type {Object<number, TreeChangeObserver>}
60 */ 61 */
61 automationUtil.treeChangeObserverMap = {}; 62 automationUtil.treeChangeObserverMap = {};
62 63
63 /** 64 /**
64 * The id of the next tree change observer. 65 * The id of the next tree change observer.
65 * @type {number} 66 * @type {number}
66 */ 67 */
67 automationUtil.nextTreeChangeObserverId = 1; 68 automationUtil.nextTreeChangeObserverId = 1;
68 69
70 /**
71 * @type {AutomationNode} The current focused node. This is only updated
72 * when calling automationUtil.updateFocusedNode.
73 */
74 automationUtil.focusedNode = null;
75
76 /**
77 * Update automationUtil.focusedNode to be the node that currently has focus.
78 */
79 automationUtil.updateFocusedNode = function() {
80 automationUtil.focusedNode = null;
81 var focusedNodeInfo = GetFocus(DESKTOP_TREE_ID);
82 if (!focusedNodeInfo)
83 return;
84 var tree = AutomationRootNode.getOrCreate(focusedNodeInfo.treeId);
85 if (tree) {
86 automationUtil.focusedNode =
87 privates(tree).impl.get(focusedNodeInfo.nodeId);
88 }
89 };
90
69 automation.registerCustomHook(function(bindingsAPI) { 91 automation.registerCustomHook(function(bindingsAPI) {
70 var apiFunctions = bindingsAPI.apiFunctions; 92 var apiFunctions = bindingsAPI.apiFunctions;
71 93
72 // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj. 94 // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj.
73 apiFunctions.setHandleRequest('getTree', function getTree(tabID, callback) { 95 apiFunctions.setHandleRequest('getTree', function getTree(tabID, callback) {
74 var routingID = GetRoutingID(); 96 var routingID = GetRoutingID();
75 StartCachingAccessibilityTrees(); 97 StartCachingAccessibilityTrees();
76 98
77 // enableTab() ensures the renderer for the active or specified tab has 99 // enableTab() ensures the renderer for the active or specified tab has
78 // accessibility enabled, and fetches its ax tree id to use as 100 // accessibility enabled, and fetches its ax tree id to use as
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 AutomationRootNode.destroy(DESKTOP_TREE_ID); 133 AutomationRootNode.destroy(DESKTOP_TREE_ID);
112 callback(); 134 callback();
113 return; 135 return;
114 } 136 }
115 }); 137 });
116 } else { 138 } else {
117 callback(desktopTree); 139 callback(desktopTree);
118 } 140 }
119 }); 141 });
120 142
143 apiFunctions.setHandleRequest('getFocus', function(callback) {
144 automationUtil.updateFocusedNode();
145 callback(automationUtil.focusedNode);
146 });
147
121 function removeTreeChangeObserver(observer) { 148 function removeTreeChangeObserver(observer) {
122 for (var id in automationUtil.treeChangeObserverMap) { 149 for (var id in automationUtil.treeChangeObserverMap) {
123 if (automationUtil.treeChangeObserverMap[id] == observer) { 150 if (automationUtil.treeChangeObserverMap[id] == observer) {
124 RemoveTreeChangeObserver(id); 151 RemoveTreeChangeObserver(id);
125 delete automationUtil.treeChangeObserverMap[id]; 152 delete automationUtil.treeChangeObserverMap[id];
126 return; 153 return;
127 } 154 }
128 } 155 }
129 } 156 }
130 apiFunctions.setHandleRequest('removeTreeChangeObserver', function(observer) { 157 apiFunctions.setHandleRequest('removeTreeChangeObserver', function(observer) {
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 automationInternal.onNodesRemoved.addListener(function(treeID, nodeIDs) { 251 automationInternal.onNodesRemoved.addListener(function(treeID, nodeIDs) {
225 var tree = AutomationRootNode.getOrCreate(treeID); 252 var tree = AutomationRootNode.getOrCreate(treeID);
226 if (!tree) 253 if (!tree)
227 return; 254 return;
228 255
229 for (var i = 0; i < nodeIDs.length; i++) { 256 for (var i = 0; i < nodeIDs.length; i++) {
230 privates(tree).impl.remove(nodeIDs[i]); 257 privates(tree).impl.remove(nodeIDs[i]);
231 } 258 }
232 }); 259 });
233 260
234 // Listen to the automationInternal.onAccessibilityEvent event, which is 261 /**
235 // essentially a proxy for the AccessibilityHostMsg_Events IPC from the 262 * Dispatch accessibility events fired on individual nodes to its
236 // renderer. 263 * corresponding AutomationNode. Handle focus events specially
237 automationInternal.onAccessibilityEvent.addListener(function(data) { 264 * (see below).
238 var id = data.treeID; 265 */
266 automationInternal.onAccessibilityEvent.addListener(function(eventParams) {
267 var id = eventParams.treeID;
239 var targetTree = AutomationRootNode.getOrCreate(id); 268 var targetTree = AutomationRootNode.getOrCreate(id);
240 269
241 if (!privates(targetTree).impl.onAccessibilityEvent(data)) 270 // When we get a focus event, ignore the actual event target, and instead
271 // check what node has focus globally. If that represents a focus change,
272 // fire a focus event on the correct target.
273 if (eventParams.eventType == schema.EventType.focus) {
274 var previousFocusedNode = automationUtil.focusedNode;
275 automationUtil.updateFocusedNode();
276 if (automationUtil.focusedNode &&
277 automationUtil.focusedNode == previousFocusedNode) {
278 return;
279 }
280
281 if (automationUtil.focusedNode) {
282 targetTree = automationUtil.focusedNode.root;
283 eventParams.treeID = privates(targetTree).impl.treeID;
284 eventParams.targetID = privates(automationUtil.focusedNode).impl.id;
285 }
286 }
287
288 if (!privates(targetTree).impl.onAccessibilityEvent(eventParams))
242 return; 289 return;
243 290
244 // If we're not waiting on a callback to getTree(), we can early out here. 291 // If we're not waiting on a callback to getTree(), we can early out here.
245 if (!(id in idToCallback)) 292 if (!(id in idToCallback))
246 return; 293 return;
247 294
248 // We usually get a 'placeholder' tree first, which doesn't have any url 295 // We usually get a 'placeholder' tree first, which doesn't have any url
249 // attribute or child nodes. If we've got that, wait for the full tree before 296 // attribute or child nodes. If we've got that, wait for the full tree before
250 // calling the callback. 297 // calling the callback.
251 // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553) 298 // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553)
(...skipping 26 matching lines...) Expand all
278 }); 325 });
279 326
280 exports.binding = automation.generate(); 327 exports.binding = automation.generate();
281 328
282 // Add additional accessibility bindings not specified in the automation IDL. 329 // Add additional accessibility bindings not specified in the automation IDL.
283 // Accessibility and automation share some APIs (see 330 // Accessibility and automation share some APIs (see
284 // ui/accessibility/ax_enums.idl). 331 // ui/accessibility/ax_enums.idl).
285 forEach(schema, function(k, v) { 332 forEach(schema, function(k, v) {
286 exports.binding[k] = v; 333 exports.binding[k] = v;
287 }); 334 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698