| OLD | NEW |
| 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 Loading... |
| 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 console.log('updateFocusedNode calling GetFocus'); |
| 82 var focusedNodeInfo = GetFocus(DESKTOP_TREE_ID); |
| 83 console.log('updateFocusedNode calling GetFocus done:'); |
| 84 console.log(focusedNodeInfo); |
| 85 console.log(JSON.stringify(focusedNodeInfo)); |
| 86 if (!focusedNodeInfo) { |
| 87 console.log('updateFocusedNode return 1'); |
| 88 return; |
| 89 } |
| 90 var tree = AutomationRootNode.getOrCreate(focusedNodeInfo.treeId); |
| 91 if (tree) { |
| 92 console.log('updateFocusedNode return 2'); |
| 93 automationUtil.focusedNode = |
| 94 privates(tree).impl.get(focusedNodeInfo.nodeId); |
| 95 } else { |
| 96 console.log('updateFocusedNode return 3'); |
| 97 } |
| 98 |
| 99 console.log('updateFocusedNode returning: ' + automationUtil.focusedNode); |
| 100 }; |
| 101 |
| 69 automation.registerCustomHook(function(bindingsAPI) { | 102 automation.registerCustomHook(function(bindingsAPI) { |
| 70 var apiFunctions = bindingsAPI.apiFunctions; | 103 var apiFunctions = bindingsAPI.apiFunctions; |
| 71 | 104 |
| 72 // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj. | 105 // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj. |
| 73 apiFunctions.setHandleRequest('getTree', function getTree(tabID, callback) { | 106 apiFunctions.setHandleRequest('getTree', function getTree(tabID, callback) { |
| 74 var routingID = GetRoutingID(); | 107 var routingID = GetRoutingID(); |
| 75 StartCachingAccessibilityTrees(); | 108 StartCachingAccessibilityTrees(); |
| 76 | 109 |
| 77 // enableTab() ensures the renderer for the active or specified tab has | 110 // enableTab() ensures the renderer for the active or specified tab has |
| 78 // accessibility enabled, and fetches its ax tree id to use as | 111 // accessibility enabled, and fetches its ax tree id to use as |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 AutomationRootNode.destroy(DESKTOP_TREE_ID); | 144 AutomationRootNode.destroy(DESKTOP_TREE_ID); |
| 112 callback(); | 145 callback(); |
| 113 return; | 146 return; |
| 114 } | 147 } |
| 115 }); | 148 }); |
| 116 } else { | 149 } else { |
| 117 callback(desktopTree); | 150 callback(desktopTree); |
| 118 } | 151 } |
| 119 }); | 152 }); |
| 120 | 153 |
| 154 apiFunctions.setHandleRequest('getFocus', function() { |
| 155 console.log('automation_custom_bindings getFocus'); |
| 156 automationUtil.updateFocusedNode(); |
| 157 console.log('automation_custom_bindings getFocus 2'); |
| 158 console.log('automation_custom_bindings getFocus 2 returning: ' + |
| 159 automationUtil.focusedNode); |
| 160 return automationUtil.focusedNode; |
| 161 }); |
| 162 |
| 121 function removeTreeChangeObserver(observer) { | 163 function removeTreeChangeObserver(observer) { |
| 122 for (var id in automationUtil.treeChangeObserverMap) { | 164 for (var id in automationUtil.treeChangeObserverMap) { |
| 123 if (automationUtil.treeChangeObserverMap[id] == observer) { | 165 if (automationUtil.treeChangeObserverMap[id] == observer) { |
| 124 RemoveTreeChangeObserver(id); | 166 RemoveTreeChangeObserver(id); |
| 125 delete automationUtil.treeChangeObserverMap[id]; | 167 delete automationUtil.treeChangeObserverMap[id]; |
| 126 return; | 168 return; |
| 127 } | 169 } |
| 128 } | 170 } |
| 129 } | 171 } |
| 130 apiFunctions.setHandleRequest('removeTreeChangeObserver', function(observer) { | 172 apiFunctions.setHandleRequest('removeTreeChangeObserver', function(observer) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 automationInternal.onNodesRemoved.addListener(function(treeID, nodeIDs) { | 266 automationInternal.onNodesRemoved.addListener(function(treeID, nodeIDs) { |
| 225 var tree = AutomationRootNode.getOrCreate(treeID); | 267 var tree = AutomationRootNode.getOrCreate(treeID); |
| 226 if (!tree) | 268 if (!tree) |
| 227 return; | 269 return; |
| 228 | 270 |
| 229 for (var i = 0; i < nodeIDs.length; i++) { | 271 for (var i = 0; i < nodeIDs.length; i++) { |
| 230 privates(tree).impl.remove(nodeIDs[i]); | 272 privates(tree).impl.remove(nodeIDs[i]); |
| 231 } | 273 } |
| 232 }); | 274 }); |
| 233 | 275 |
| 234 // Listen to the automationInternal.onAccessibilityEvent event, which is | 276 /** |
| 235 // essentially a proxy for the AccessibilityHostMsg_Events IPC from the | 277 * Dispatch accessibility events fired on individual nodes to its |
| 236 // renderer. | 278 * corresponding AutomationNode. Handle focus events specially |
| 237 automationInternal.onAccessibilityEvent.addListener(function(data) { | 279 * (see below). |
| 238 var id = data.treeID; | 280 */ |
| 281 automationInternal.onAccessibilityEvent.addListener(function(eventParams) { |
| 282 var id = eventParams.treeID; |
| 239 var targetTree = AutomationRootNode.getOrCreate(id); | 283 var targetTree = AutomationRootNode.getOrCreate(id); |
| 240 | 284 |
| 241 if (!privates(targetTree).impl.onAccessibilityEvent(data)) | 285 // When we get a focus event, ignore the actual event target, and instead |
| 286 // check what node has focus globally. If that represents a focus change, |
| 287 // fire a focus event on the correct target. |
| 288 if (eventParams.eventType == schema.EventType.focus) { |
| 289 var previousFocusedNode = automationUtil.focusedNode; |
| 290 automationUtil.updateFocusedNode(); |
| 291 if (automationUtil.focusedNode && |
| 292 automationUtil.focusedNode == previousFocusedNode) { |
| 293 return; |
| 294 } |
| 295 |
| 296 if (automationUtil.focusedNode) { |
| 297 targetTree = automationUtil.focusedNode.root; |
| 298 eventParams.treeID = privates(targetTree).impl.treeID; |
| 299 eventParams.targetID = privates(automationUtil.focusedNode).impl.id; |
| 300 } |
| 301 } |
| 302 |
| 303 if (!privates(targetTree).impl.onAccessibilityEvent(eventParams)) |
| 242 return; | 304 return; |
| 243 | 305 |
| 244 // If we're not waiting on a callback to getTree(), we can early out here. | 306 // If we're not waiting on a callback to getTree(), we can early out here. |
| 245 if (!(id in idToCallback)) | 307 if (!(id in idToCallback)) |
| 246 return; | 308 return; |
| 247 | 309 |
| 248 // We usually get a 'placeholder' tree first, which doesn't have any url | 310 // 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 | 311 // attribute or child nodes. If we've got that, wait for the full tree before |
| 250 // calling the callback. | 312 // calling the callback. |
| 251 // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553) | 313 // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553) |
| (...skipping 26 matching lines...) Expand all Loading... |
| 278 }); | 340 }); |
| 279 | 341 |
| 280 exports.binding = automation.generate(); | 342 exports.binding = automation.generate(); |
| 281 | 343 |
| 282 // Add additional accessibility bindings not specified in the automation IDL. | 344 // Add additional accessibility bindings not specified in the automation IDL. |
| 283 // Accessibility and automation share some APIs (see | 345 // Accessibility and automation share some APIs (see |
| 284 // ui/accessibility/ax_enums.idl). | 346 // ui/accessibility/ax_enums.idl). |
| 285 forEach(schema, function(k, v) { | 347 forEach(schema, function(k, v) { |
| 286 exports.binding[k] = v; | 348 exports.binding[k] = v; |
| 287 }); | 349 }); |
| OLD | NEW |