PageRenderTime 70ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 2ms

/src/windows/classes/com/sun/java/accessibility/AccessBridge.java

https://bitbucket.org/screenconnect/openjdk8-jdk
Java | 7272 lines | 5033 code | 542 blank | 1697 comment | 1558 complexity | 5abad8fd491d1ea5c2f6e8dec052be8b MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4. *
  5. * This code is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 only, as
  7. * published by the Free Software Foundation. Oracle designates this
  8. * particular file as subject to the "Classpath" exception as provided
  9. * by Oracle in the LICENSE file that accompanied this code.
  10. *
  11. * This code is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * version 2 for more details (a copy is included in the LICENSE file that
  15. * accompanied this code).
  16. *
  17. * You should have received a copy of the GNU General Public License version
  18. * 2 along with this work; if not, write to the Free Software Foundation,
  19. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22. * or visit www.oracle.com if you need additional information or have any
  23. * questions.
  24. */
  25. package com.sun.java.accessibility;
  26. import java.awt.*;
  27. import java.awt.event.*;
  28. import java.util.*;
  29. import java.lang.*;
  30. import java.lang.reflect.*;
  31. import java.beans.*;
  32. import javax.swing.*;
  33. import javax.swing.event.*;
  34. import javax.swing.text.*;
  35. import javax.swing.tree.*;
  36. import javax.swing.table.*;
  37. import javax.swing.plaf.TreeUI;
  38. import javax.accessibility.*;
  39. import com.sun.java.accessibility.util.*;
  40. import sun.awt.AWTAccessor;
  41. import sun.awt.AppContext;
  42. import sun.awt.SunToolkit;
  43. import java.util.concurrent.Callable;
  44. import java.util.concurrent.ConcurrentHashMap;
  45. import java.util.concurrent.CountDownLatch;
  46. /*
  47. * Note: This class has to be public. It's loaded from the VM like this:
  48. * Class.forName(atName).newInstance();
  49. */
  50. @jdk.Exported(false)
  51. final public class AccessBridge extends AccessBridgeLoader {
  52. private final String AccessBridgeVersion =
  53. "AccessBridge 2.0.4";
  54. private static AccessBridge theAccessBridge;
  55. private ObjectReferences references;
  56. private EventHandler eventHandler;
  57. private boolean runningOnJDK1_4 = false;
  58. private boolean runningOnJDK1_5 = false;
  59. // Maps AccessibleRoles strings to AccessibleRoles.
  60. private ConcurrentHashMap<String,AccessibleRole> accessibleRoleMap = new ConcurrentHashMap<>();
  61. /**
  62. If the object's role is in the following array getVirtualAccessibleName
  63. will use the extended search algorithm.
  64. */
  65. private ArrayList<AccessibleRole> extendedVirtualNameSearchRoles = new ArrayList<>();
  66. /**
  67. If the role of the object's parent is in the following array
  68. getVirtualAccessibleName will NOT use the extended search
  69. algorithm even if the object's role is in the
  70. extendedVirtualNameSearchRoles array.
  71. */
  72. private ArrayList<AccessibleRole> noExtendedVirtualNameSearchParentRoles = new ArrayList<>();
  73. /**
  74. * AccessBridge constructor
  75. *
  76. * Note: This constructor has to be public. It's called from the VM like this:
  77. * Class.forName(atName).newInstance();
  78. */
  79. public AccessBridge() {
  80. super();
  81. theAccessBridge = this;
  82. references = new ObjectReferences();
  83. // initialize shutdown hook
  84. Runtime runTime = Runtime.getRuntime();
  85. shutdownHook hook = new shutdownHook();
  86. runTime.addShutdownHook(new Thread(hook));
  87. // initialize AccessibleRole map
  88. initAccessibleRoleMap();
  89. // determine which version of the JDK is running
  90. String version = getJavaVersionProperty();
  91. debugString("JDK version = "+version);
  92. runningOnJDK1_4 = (version.compareTo("1.4") >= 0);
  93. runningOnJDK1_5 = (version.compareTo("1.5") >= 0);
  94. // initialize the methods that map HWNDs and Java top-level
  95. // windows
  96. if (initHWNDcalls() == true) {
  97. // is this a JVM we can use?
  98. // install JDK 1.2 and later Swing ToolKit listener
  99. EventQueueMonitor.isGUIInitialized();
  100. // start the Java event handler
  101. eventHandler = new EventHandler(this);
  102. // register for menu selection events
  103. if (runningOnJDK1_4) {
  104. MenuSelectionManager.defaultManager().addChangeListener(eventHandler);
  105. }
  106. // register as a NativeWindowHandler
  107. addNativeWindowHandler(new DefaultNativeWindowHandler());
  108. // start in a new thread
  109. Thread abthread = new Thread(new dllRunner());
  110. abthread.setDaemon(true);
  111. abthread.start();
  112. debugString("AccessBridge started");
  113. }
  114. }
  115. /*
  116. * adaptor to run the AccessBridge DLL
  117. */
  118. private class dllRunner implements Runnable {
  119. public void run() {
  120. runDLL();
  121. }
  122. }
  123. /*
  124. * shutdown hook
  125. */
  126. private class shutdownHook implements Runnable {
  127. public void run() {
  128. debugString("***** shutdownHook: shutting down...");
  129. javaShutdown();
  130. }
  131. }
  132. /*
  133. * Initialize the hashtable that maps Strings to AccessibleRoles.
  134. */
  135. private void initAccessibleRoleMap() {
  136. /*
  137. * Initialize the AccessibleRoles map. This code uses methods in
  138. * java.lang.reflect.* to build the map.
  139. */
  140. try {
  141. Class<?> clAccessibleRole = Class.forName ("javax.accessibility.AccessibleRole");
  142. if (null != clAccessibleRole) {
  143. AccessibleRole roleUnknown = AccessibleRole.UNKNOWN;
  144. Field [] fields = clAccessibleRole.getFields ();
  145. int i = 0;
  146. for (i = 0; i < fields.length; i ++) {
  147. Field f = fields [i];
  148. if (javax.accessibility.AccessibleRole.class == f.getType ()) {
  149. AccessibleRole nextRole = (AccessibleRole) (f.get (roleUnknown));
  150. String nextRoleString = nextRole.toDisplayString (Locale.US);
  151. accessibleRoleMap.put (nextRoleString, nextRole);
  152. }
  153. }
  154. }
  155. } catch (Exception e) {}
  156. /*
  157. Build the extendedVirtualNameSearchRoles array list. I chose this method
  158. because some of the Accessible Roles that need to be added to it are not
  159. available in all versions of the J2SE that we want to support.
  160. */
  161. extendedVirtualNameSearchRoles.add (AccessibleRole.COMBO_BOX);
  162. try {
  163. /*
  164. Added in J2SE 1.4
  165. */
  166. extendedVirtualNameSearchRoles.add (AccessibleRole.DATE_EDITOR);
  167. } catch (NoSuchFieldError e) {}
  168. extendedVirtualNameSearchRoles.add (AccessibleRole.LIST);
  169. extendedVirtualNameSearchRoles.add (AccessibleRole.PASSWORD_TEXT);
  170. extendedVirtualNameSearchRoles.add (AccessibleRole.SLIDER);
  171. try {
  172. /*
  173. Added in J2SE 1.3
  174. */
  175. extendedVirtualNameSearchRoles.add (AccessibleRole.SPIN_BOX);
  176. } catch (NoSuchFieldError e) {}
  177. extendedVirtualNameSearchRoles.add (AccessibleRole.TABLE);
  178. extendedVirtualNameSearchRoles.add (AccessibleRole.TEXT);
  179. extendedVirtualNameSearchRoles.add (AccessibleRole.UNKNOWN);
  180. noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TABLE);
  181. noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TOOL_BAR);
  182. }
  183. /**
  184. * start the AccessBridge DLL running in its own thread
  185. */
  186. private native void runDLL();
  187. /**
  188. * debugging output (goes to OutputDebugStr())
  189. */
  190. private native void sendDebugString(String debugStr);
  191. /**
  192. * debugging output (goes to OutputDebugStr())
  193. */
  194. private void debugString(String debugStr) {
  195. sendDebugString(debugStr);
  196. }
  197. /* ===== utility methods ===== */
  198. /**
  199. * decrement the reference to the object (called by native code)
  200. */
  201. private void decrementReference(Object o) {
  202. references.decrement(o);
  203. }
  204. /**
  205. * get the java.version property from the JVM
  206. */
  207. private String getJavaVersionProperty() {
  208. String s = System.getProperty("java.version");
  209. if (s != null) {
  210. references.increment(s);
  211. return s;
  212. }
  213. return null;
  214. }
  215. /**
  216. * get the java.version property from the JVM
  217. */
  218. private String getAccessBridgeVersion() {
  219. String s = new String(AccessBridgeVersion);
  220. references.increment(s);
  221. return s;
  222. }
  223. /* ===== HWND/Java window mapping methods ===== */
  224. // Java toolkit methods for mapping HWNDs to Java components
  225. private Method javaGetComponentFromNativeWindowHandleMethod;
  226. private Method javaGetNativeWindowHandleFromComponentMethod;
  227. // native jawt methods for mapping HWNDs to Java components
  228. private native int isJAWTInstalled();
  229. private native int jawtGetNativeWindowHandleFromComponent(Component comp);
  230. private native Component jawtGetComponentFromNativeWindowHandle(int handle);
  231. Toolkit toolkit;
  232. /**
  233. * map an HWND to an AWT Component
  234. */
  235. private boolean initHWNDcalls() {
  236. Class<?> integerParemter[] = new Class<?>[1];
  237. integerParemter[0] = Integer.TYPE;
  238. Class<?> componentParemter[] = new Class<?>[1];
  239. try {
  240. componentParemter[0] = Class.forName("java.awt.Component");
  241. } catch (ClassNotFoundException e) {
  242. debugString("Exception: " + e.toString());
  243. }
  244. Object[] args = new Object[1];
  245. Component c;
  246. boolean returnVal = false;
  247. toolkit = Toolkit.getDefaultToolkit();
  248. if (useJAWT_DLL) {
  249. returnVal = true;
  250. } else {
  251. // verify javaGetComponentFromNativeWindowHandle() method
  252. // is present if JAWT.DLL is not installed
  253. try {
  254. javaGetComponentFromNativeWindowHandleMethod =
  255. toolkit.getClass().getMethod(
  256. "getComponentFromNativeWindowHandle", integerParemter);
  257. if (javaGetComponentFromNativeWindowHandleMethod != null) {
  258. try {
  259. args[0] = new Integer(1);
  260. c = (Component) javaGetComponentFromNativeWindowHandleMethod.invoke(toolkit, args);
  261. returnVal = true;
  262. } catch (InvocationTargetException e) {
  263. debugString("Exception: " + e.toString());
  264. } catch (IllegalAccessException e) {
  265. debugString("Exception: " + e.toString());
  266. }
  267. }
  268. } catch (NoSuchMethodException e) {
  269. debugString("Exception: " + e.toString());
  270. } catch (SecurityException e) {
  271. debugString("Exception: " + e.toString());
  272. }
  273. // verify getComponentFromNativeWindowHandle() method
  274. // is present if JAWT.DLL is not installed
  275. try {
  276. javaGetNativeWindowHandleFromComponentMethod =
  277. toolkit.getClass().getMethod(
  278. "getNativeWindowHandleFromComponent", componentParemter);
  279. if (javaGetNativeWindowHandleFromComponentMethod != null) {
  280. try {
  281. args[0] = new Button("OK"); // need some Component...
  282. Integer i = (Integer) javaGetNativeWindowHandleFromComponentMethod.invoke(toolkit, args);
  283. returnVal = true;
  284. } catch (InvocationTargetException e) {
  285. debugString("Exception: " + e.toString());
  286. } catch (IllegalAccessException e) {
  287. debugString("Exception: " + e.toString());
  288. } catch (Exception e) {
  289. debugString("Exception: " + e.toString());
  290. }
  291. }
  292. } catch (NoSuchMethodException e) {
  293. debugString("Exception: " + e.toString());
  294. } catch (SecurityException e) {
  295. debugString("Exception: " + e.toString());
  296. }
  297. }
  298. return returnVal;
  299. }
  300. // native window handler interface
  301. private interface NativeWindowHandler {
  302. public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle);
  303. }
  304. // hash table of native window handle to AccessibleContext mappings
  305. static private ConcurrentHashMap<Integer,AccessibleContext> windowHandleToContextMap = new ConcurrentHashMap<>();
  306. // hash table of AccessibleContext to native window handle mappings
  307. static private ConcurrentHashMap<AccessibleContext,Integer> contextToWindowHandleMap = new ConcurrentHashMap<>();
  308. /*
  309. * adds a virtual window handler to our hash tables
  310. */
  311. static private void registerVirtualFrame(final Accessible a,
  312. Integer nativeWindowHandle ) {
  313. if (a != null) {
  314. AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  315. @Override
  316. public AccessibleContext call() throws Exception {
  317. return a.getAccessibleContext();
  318. }
  319. }, a);
  320. windowHandleToContextMap.put(nativeWindowHandle, ac);
  321. contextToWindowHandleMap.put(ac, nativeWindowHandle);
  322. }
  323. }
  324. /*
  325. * removes a virtual window handler to our hash tables
  326. */
  327. static private void revokeVirtualFrame(final Accessible a,
  328. Integer nativeWindowHandle ) {
  329. AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  330. @Override
  331. public AccessibleContext call() throws Exception {
  332. return a.getAccessibleContext();
  333. }
  334. }, a);
  335. windowHandleToContextMap.remove(nativeWindowHandle);
  336. contextToWindowHandleMap.remove(ac);
  337. }
  338. // vector of native window handlers
  339. private static Vector<NativeWindowHandler> nativeWindowHandlers = new Vector<>();
  340. /*
  341. * adds a native window handler to our list
  342. */
  343. private static void addNativeWindowHandler(NativeWindowHandler handler) {
  344. if (handler == null) {
  345. throw new IllegalArgumentException();
  346. }
  347. nativeWindowHandlers.addElement(handler);
  348. }
  349. /*
  350. * removes a native window handler to our list
  351. */
  352. private static boolean removeNativeWindowHandler(NativeWindowHandler handler) {
  353. if (handler == null) {
  354. throw new IllegalArgumentException();
  355. }
  356. return nativeWindowHandlers.removeElement(handler);
  357. }
  358. /**
  359. * verifies that a native window handle is a Java window
  360. */
  361. private boolean isJavaWindow(int nativeHandle) {
  362. AccessibleContext ac = getContextFromNativeWindowHandle(nativeHandle);
  363. if (ac != null) {
  364. saveContextToWindowHandleMapping(ac, nativeHandle);
  365. return true;
  366. }
  367. return false;
  368. }
  369. /*
  370. * saves the mapping between an AccessibleContext and a window handle
  371. */
  372. private void saveContextToWindowHandleMapping(AccessibleContext ac,
  373. int nativeHandle) {
  374. debugString("saveContextToWindowHandleMapping...");
  375. if (ac == null) {
  376. return;
  377. }
  378. if (! contextToWindowHandleMap.containsKey(ac)) {
  379. debugString("saveContextToWindowHandleMapping: ac = "+ac+"; handle = "+nativeHandle);
  380. contextToWindowHandleMap.put(ac, nativeHandle);
  381. }
  382. }
  383. /**
  384. * maps a native window handle to an Accessible Context
  385. */
  386. private AccessibleContext getContextFromNativeWindowHandle(int nativeHandle) {
  387. // First, look for the Accessible in our hash table of
  388. // virtual window handles.
  389. AccessibleContext ac = windowHandleToContextMap.get(nativeHandle);
  390. if(ac!=null) {
  391. saveContextToWindowHandleMapping(ac, nativeHandle);
  392. return ac;
  393. }
  394. // Next, look for the native window handle in our vector
  395. // of native window handles.
  396. int numHandlers = nativeWindowHandlers.size();
  397. for (int i = 0; i < numHandlers; i++) {
  398. NativeWindowHandler nextHandler = nativeWindowHandlers.elementAt(i);
  399. final Accessible a = nextHandler.getAccessibleFromNativeWindowHandle(nativeHandle);
  400. if (a != null) {
  401. ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  402. @Override
  403. public AccessibleContext call() throws Exception {
  404. return a.getAccessibleContext();
  405. }
  406. }, a);
  407. saveContextToWindowHandleMapping(ac, nativeHandle);
  408. return ac;
  409. }
  410. }
  411. // Not found.
  412. return null;
  413. }
  414. /**
  415. * maps an AccessibleContext to a native window handle
  416. * returns 0 on error
  417. */
  418. private int getNativeWindowHandleFromContext(AccessibleContext ac) {
  419. debugString("getNativeWindowHandleFromContext: ac = "+ac);
  420. try {
  421. return contextToWindowHandleMap.get(ac);
  422. } catch (Exception ex) {
  423. return 0;
  424. }
  425. }
  426. private class DefaultNativeWindowHandler implements NativeWindowHandler {
  427. /*
  428. * returns the Accessible associated with a native window
  429. */
  430. public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle) {
  431. final Component c = getComponentFromNativeWindowHandle(nativeHandle);
  432. if (c instanceof Accessible) {
  433. AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  434. @Override
  435. public AccessibleContext call() throws Exception {
  436. return c.getAccessibleContext();
  437. }
  438. }, c);
  439. saveContextToWindowHandleMapping(ac, nativeHandle);
  440. return (Accessible)c;
  441. } else {
  442. return null;
  443. }
  444. }
  445. /**
  446. * map an HWND to an AWT Component
  447. */
  448. private Component getComponentFromNativeWindowHandle(int nativeHandle) {
  449. if (useJAWT_DLL) {
  450. debugString("*** calling jawtGetComponentFromNativeWindowHandle");
  451. return jawtGetComponentFromNativeWindowHandle(nativeHandle);
  452. } else {
  453. debugString("*** calling javaGetComponentFromNativeWindowHandle");
  454. Object[] args = new Object[1];
  455. if (javaGetComponentFromNativeWindowHandleMethod != null) {
  456. try {
  457. args[0] = nativeHandle;
  458. Object o = javaGetComponentFromNativeWindowHandleMethod.invoke(toolkit, args);
  459. if (o instanceof Accessible) {
  460. final Accessible acc=(Accessible)o;
  461. AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  462. @Override
  463. public AccessibleContext call() throws Exception {
  464. return acc.getAccessibleContext();
  465. }
  466. }, (Component)o);
  467. saveContextToWindowHandleMapping(ac,nativeHandle);
  468. }
  469. return (Component)o;
  470. } catch (InvocationTargetException | IllegalAccessException e) {
  471. debugString("Exception: " + e.toString());
  472. }
  473. }
  474. }
  475. return null;
  476. }
  477. }
  478. /**
  479. * map an AWT Component to an HWND
  480. */
  481. private int getNativeWindowHandleFromComponent(final Component target) {
  482. if (useJAWT_DLL) {
  483. debugString("*** calling jawtGetNativeWindowHandleFromComponent");
  484. return jawtGetNativeWindowHandleFromComponent(target);
  485. } else {
  486. Object[] args = new Object[1];
  487. debugString("*** calling javaGetNativeWindowHandleFromComponent");
  488. if (javaGetNativeWindowHandleFromComponentMethod != null) {
  489. try {
  490. args[0] = target;
  491. Integer i = (Integer) javaGetNativeWindowHandleFromComponentMethod.invoke(toolkit, args);
  492. // cache the mapping
  493. AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  494. @Override
  495. public AccessibleContext call() throws Exception {
  496. return target.getAccessibleContext();
  497. }
  498. }, target);
  499. contextToWindowHandleMap.put(ac, i);
  500. return i.intValue();
  501. } catch (InvocationTargetException e) {
  502. debugString("Exception: " + e.toString());
  503. } catch (IllegalAccessException e) {
  504. debugString("Exception: " + e.toString());
  505. }
  506. }
  507. }
  508. return -1;
  509. }
  510. /* ===== AccessibleContext methods =====*/
  511. /*
  512. * returns the inner-most AccessibleContext in parent at Point(x, y)
  513. */
  514. private AccessibleContext getAccessibleContextAt(int x, int y,
  515. AccessibleContext parent) {
  516. if (parent == null) {
  517. return null;
  518. }
  519. if (windowHandleToContextMap != null &&
  520. windowHandleToContextMap.containsValue(getRootAccessibleContext(parent))) {
  521. // Path for applications that register their top-level
  522. // windows with the AccessBridge (e.g., StarOffice 6.1)
  523. return getAccessibleContextAt_1(x, y, parent);
  524. } else {
  525. // Path for applications that do not register
  526. // their top-level windows with the AccessBridge
  527. // (e.g., Swing/AWT applications)
  528. return getAccessibleContextAt_2(x, y, parent);
  529. }
  530. }
  531. /*
  532. * returns the root accessible context
  533. */
  534. private AccessibleContext getRootAccessibleContext(final AccessibleContext ac) {
  535. if (ac == null) {
  536. return null;
  537. }
  538. return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  539. @Override
  540. public AccessibleContext call() throws Exception {
  541. Accessible parent = ac.getAccessibleParent();
  542. if (parent == null) {
  543. return ac;
  544. }
  545. Accessible tmp = parent.getAccessibleContext().getAccessibleParent();
  546. while (tmp != null) {
  547. parent = tmp;
  548. tmp = parent.getAccessibleContext().getAccessibleParent();
  549. }
  550. return parent.getAccessibleContext();
  551. }
  552. }, ac);
  553. }
  554. /*
  555. * StarOffice version that does not use the EventQueueMonitor
  556. */
  557. private AccessibleContext getAccessibleContextAt_1(final int x, final int y,
  558. final AccessibleContext parent) {
  559. debugString(" : getAccessibleContextAt_1 called");
  560. debugString(" -> x = " + x + " y = " + y + " parent = " + parent);
  561. if (parent == null) return null;
  562. final AccessibleComponent acmp = InvocationUtils.invokeAndWait(new Callable<AccessibleComponent>() {
  563. @Override
  564. public AccessibleComponent call() throws Exception {
  565. return parent.getAccessibleComponent();
  566. }
  567. }, parent);
  568. if (acmp!=null) {
  569. final Point loc = InvocationUtils.invokeAndWait(new Callable<Point>() {
  570. @Override
  571. public Point call() throws Exception {
  572. return acmp.getLocation();
  573. }
  574. }, parent);
  575. final Accessible a = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
  576. @Override
  577. public Accessible call() throws Exception {
  578. return acmp.getAccessibleAt(new Point(x - loc.x, y - loc.y));
  579. }
  580. }, parent);
  581. if (a != null) {
  582. AccessibleContext foundAC = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  583. @Override
  584. public AccessibleContext call() throws Exception {
  585. return a.getAccessibleContext();
  586. }
  587. }, parent);
  588. if (foundAC != null) {
  589. if (foundAC != parent) {
  590. // recurse down into the child
  591. return getAccessibleContextAt_1(x - loc.x, y - loc.y,
  592. foundAC);
  593. } else
  594. return foundAC;
  595. }
  596. }
  597. }
  598. return parent;
  599. }
  600. /*
  601. * AWT/Swing version
  602. */
  603. private AccessibleContext getAccessibleContextAt_2(final int x, final int y,
  604. AccessibleContext parent) {
  605. debugString("getAccessibleContextAt_2 called");
  606. debugString(" -> x = " + x + " y = " + y + " parent = " + parent);
  607. return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  608. @Override
  609. public AccessibleContext call() throws Exception {
  610. Accessible a = EventQueueMonitor.getAccessibleAt(new Point(x, y));
  611. if (a != null) {
  612. AccessibleContext childAC = a.getAccessibleContext();
  613. if (childAC != null) {
  614. debugString(" returning childAC = " + childAC);
  615. return childAC;
  616. }
  617. }
  618. return null;
  619. }
  620. }, parent);
  621. }
  622. /**
  623. * returns the Accessible that has focus
  624. */
  625. private AccessibleContext getAccessibleContextWithFocus() {
  626. Component c = AWTEventMonitor.getComponentWithFocus();
  627. if (c != null) {
  628. final Accessible a = Translator.getAccessible(c);
  629. if (a != null) {
  630. AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
  631. @Override
  632. public AccessibleContext call() throws Exception {
  633. return a.getAccessibleContext();
  634. }
  635. }, c);
  636. if (ac != null) {
  637. return ac;
  638. }
  639. }
  640. }
  641. return null;
  642. }
  643. /**
  644. * returns the AccessibleName from an AccessibleContext
  645. */
  646. private String getAccessibleNameFromContext(final AccessibleContext ac) {
  647. debugString("***** ac = "+ac.getClass());
  648. if (ac != null) {
  649. String s = InvocationUtils.invokeAndWait(new Callable<String>() {
  650. @Override
  651. public String call() throws Exception {
  652. return ac.getAccessibleName();
  653. }
  654. }, ac);
  655. if (s != null) {
  656. references.increment(s);
  657. debugString("Returning AccessibleName from Context: " + s);
  658. return s;
  659. } else {
  660. return null;
  661. }
  662. } else {
  663. debugString("getAccessibleNameFromContext; ac = null!");
  664. return null;
  665. }
  666. }
  667. /**
  668. * Returns an AccessibleName for a component using an algorithm optimized
  669. * for the JAWS screen reader. This method is only intended for JAWS. All
  670. * other uses are entirely optional.
  671. */
  672. private String getVirtualAccessibleNameFromContext(final AccessibleContext ac) {
  673. if (null != ac) {
  674. /*
  675. Step 1:
  676. =======
  677. Determine if we can obtain the Virtual Accessible Name from the
  678. Accessible Name or Accessible Description of the object.
  679. */
  680. String nameString = InvocationUtils.invokeAndWait(new Callable<String>() {
  681. @Override
  682. public String call() throws Exception {
  683. return ac.getAccessibleName();
  684. }
  685. }, ac);
  686. if ( ( null != nameString ) && ( 0 != nameString.length () ) ) {
  687. debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleName.");
  688. references.increment (nameString);
  689. return nameString;
  690. }
  691. String descriptionString = InvocationUtils.invokeAndWait(new Callable<String>() {
  692. @Override
  693. public String call() throws Exception {
  694. return ac.getAccessibleDescription();
  695. }
  696. }, ac);
  697. if ( ( null != descriptionString ) && ( 0 != descriptionString.length () ) ) {
  698. debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleDescription.");
  699. references.increment (descriptionString);
  700. return descriptionString;
  701. }
  702. debugString ("The Virtual Accessible Name was not found using AccessibleContext::getAccessibleDescription. or getAccessibleName");
  703. /*
  704. Step 2:
  705. =======
  706. Decide whether the extended name search algorithm should be
  707. used for this object.
  708. */
  709. boolean bExtendedSearch = false;
  710. AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
  711. @Override
  712. public AccessibleRole call() throws Exception {
  713. return ac.getAccessibleRole();
  714. }
  715. }, ac);
  716. AccessibleContext parentContext = null;
  717. AccessibleRole parentRole = AccessibleRole.UNKNOWN;
  718. if ( extendedVirtualNameSearchRoles.contains (role) ) {
  719. parentContext = getAccessibleParentFromContext (ac);
  720. if ( null != parentContext ) {
  721. final AccessibleContext parentContextInnerTemp = parentContext;
  722. parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
  723. @Override
  724. public AccessibleRole call() throws Exception {
  725. return parentContextInnerTemp.getAccessibleRole();
  726. }
  727. }, ac);
  728. if ( AccessibleRole.UNKNOWN != parentRole ) {
  729. bExtendedSearch = true;
  730. if ( noExtendedVirtualNameSearchParentRoles.contains (parentRole) ) {
  731. bExtendedSearch = false;
  732. }
  733. }
  734. }
  735. }
  736. if (false == bExtendedSearch) {
  737. debugString ("bk -- getVirtualAccessibleNameFromContext will not use the extended name search algorithm. role = " + role.toDisplayString (Locale.US) );
  738. /*
  739. Step 3:
  740. =======
  741. We have determined that we should not use the extended name
  742. search algorithm for this object (we must obtain the name of
  743. the object from the object itself and not from neighboring
  744. objects). However the object name cannot be obtained from
  745. the Accessible Name or Accessible Description of the object.
  746. Handle several special cases here that might yield a value for
  747. the Virtual Accessible Name. Return null if the object does
  748. not match the criteria for any of these special cases.
  749. */
  750. if (AccessibleRole.LABEL == role) {
  751. /*
  752. Does the label support the Accessible Text Interface?
  753. */
  754. final AccessibleText at = InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {
  755. @Override
  756. public AccessibleText call() throws Exception {
  757. return ac.getAccessibleText();
  758. }
  759. }, ac);
  760. if (null != at) {
  761. int charCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {
  762. @Override
  763. public Integer call() throws Exception {
  764. return at.getCharCount();
  765. }
  766. }, ac);
  767. String text = getAccessibleTextRangeFromContext (ac, 0, charCount);
  768. if (null != text) {
  769. debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Text of the LABEL object.");
  770. references.increment (text);
  771. return text;
  772. }
  773. }
  774. /*
  775. Does the label support the Accessible Icon Interface?
  776. */
  777. debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");
  778. final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
  779. @Override
  780. public AccessibleIcon[] call() throws Exception {
  781. return ac.getAccessibleIcon();
  782. }
  783. }, ac);
  784. if ( (null != ai) && (ai.length > 0) ) {
  785. String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
  786. @Override
  787. public String call() throws Exception {
  788. return ai[0].getAccessibleIconDescription();
  789. }
  790. }, ac);
  791. if (iconDescription != null){
  792. debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the LABEL object.");
  793. references.increment (iconDescription);
  794. return iconDescription;
  795. }
  796. } else {
  797. parentContext = getAccessibleParentFromContext (ac);
  798. if ( null != parentContext ) {
  799. final AccessibleContext parentContextInnerTemp = parentContext;
  800. parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
  801. @Override
  802. public AccessibleRole call() throws Exception {
  803. return parentContextInnerTemp.getAccessibleRole();
  804. }
  805. }, ac);
  806. if ( AccessibleRole.TABLE == parentRole ) {
  807. int indexInParent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
  808. @Override
  809. public Integer call() throws Exception {
  810. return ac.getAccessibleIndexInParent();
  811. }
  812. }, ac);
  813. final AccessibleContext acTableCell = getAccessibleChildFromContext (parentContext, indexInParent);
  814. debugString ("bk -- Making a second attempt to obtain the Virtual Accessible Name from the Accessible Icon information for the Table Cell.");
  815. if (acTableCell != null) {
  816. final AccessibleIcon [] aiRet =InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
  817. @Override
  818. public AccessibleIcon[] call() throws Exception {
  819. return acTableCell.getAccessibleIcon();
  820. }
  821. }, ac);
  822. if ( (null != aiRet) && (aiRet.length > 0) ) {
  823. String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
  824. public String call() {
  825. return aiRet[0].getAccessibleIconDescription ();
  826. }
  827. }, ac);
  828. if (iconDescription != null){
  829. debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the Table Cell object.");
  830. references.increment (iconDescription);
  831. return iconDescription;
  832. }
  833. }
  834. }
  835. }
  836. }
  837. }
  838. } else if ( (AccessibleRole.TOGGLE_BUTTON == role) ||
  839. (AccessibleRole.PUSH_BUTTON == role) ) {
  840. /*
  841. Does the button support the Accessible Icon Interface?
  842. */
  843. debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");
  844. final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon []>() {
  845. public AccessibleIcon [] call() {
  846. return ac.getAccessibleIcon ();
  847. }
  848. }, ac);
  849. if ( (null != ai) && (ai.length > 0) ) {
  850. String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
  851. public String call() {
  852. return ai[0].getAccessibleIconDescription ();
  853. }
  854. }, ac);
  855. if (iconDescription != null){
  856. debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the TOGGLE_BUTTON or PUSH_BUTTON object.");
  857. references.increment (iconDescription);
  858. return iconDescription;
  859. }
  860. }
  861. } else if ( AccessibleRole.CHECK_BOX == role ) {
  862. /*
  863. NOTE: The only case I know of in which a check box does not
  864. have a name is when that check box is contained in a table.
  865. In this case it would be appropriate to use the display string
  866. of the check box object as the name (in US English the display
  867. string is typically either "true" or "false").
  868. I am using the AccessibleValue interface to obtain the display
  869. string of the check box. If the Accessible Value is 1, I am
  870. returning Boolean.TRUE.toString (), If the Accessible Value is
  871. 0, I am returning Boolean.FALSE.toString (). If the Accessible
  872. Value is some other number, I will return the display string of
  873. the current numerical value of the check box.
  874. */
  875. final AccessibleValue av = InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {
  876. @Override
  877. public AccessibleValue call() throws Exception {
  878. return ac.getAccessibleValue();
  879. }
  880. }, ac);
  881. if ( null != av ) {
  882. nameString = null;
  883. Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
  884. @Override
  885. public Number call() throws Exception {
  886. return av.getCurrentAccessibleValue();
  887. }
  888. }, ac);
  889. if ( null != value ) {
  890. if ( 1 == value.intValue () ) {
  891. nameString = Boolean.TRUE.toString ();
  892. } else if ( 0 == value.intValue () ) {
  893. nameString = Boolean.FALSE.toString ();
  894. } else {
  895. nameString = value.toString ();
  896. }
  897. if ( null != nameString ) {
  898. references.increment (nameString);
  899. return nameString;
  900. }
  901. }
  902. }
  903. }
  904. return null;
  905. }
  906. /*
  907. +
  908. Beginning of the extended name search
  909. +
  910. */
  911. final AccessibleContext parentContextOuterTemp = parentContext;
  912. String parentName = InvocationUtils.invokeAndWait(new Callable<String>() {
  913. @Override
  914. public String call() throws Exception {
  915. return parentContextOuterTemp.getAccessibleName();
  916. }
  917. }, ac);
  918. String parentDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
  919. @Override
  920. public String call() throws Exception {
  921. return parentContextOuterTemp.getAccessibleDescription();
  922. }
  923. }, ac);
  924. /*
  925. Step 4:
  926. =======
  927. Special case for Slider Bar objects.
  928. */
  929. if ( (AccessibleRole.SLIDER == role) &&
  930. (AccessibleRole.PANEL == parentRole) &&
  931. (null != parentName) ) {
  932. debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Name of the SLIDER object's parent object.");
  933. references.increment (parentName);
  934. return parentName;
  935. }
  936. boolean bIsEditCombo = false;
  937. AccessibleContext testContext = ac;
  938. /*
  939. Step 5:
  940. =======
  941. Special case for Edit Combo Boxes
  942. */
  943. if ( (AccessibleRole.TEXT == role) &&
  944. (AccessibleRole.COMBO_BOX == parentRole) ) {
  945. bIsEditCombo = true;
  946. if (null != parentName) {
  947. debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Name of the object's parent object.");
  948. references.increment (parentName);
  949. return parentName;
  950. } else if (null != parentDescription) {
  951. debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Description of the object's parent object.");
  952. references.increment (parentDescription);
  953. return parentDescription;
  954. }
  955. testContext = parentContext;
  956. parentRole = AccessibleRole.UNKNOWN;
  957. parentContext = getAccessibleParentFromContext (testContext);
  958. if ( null != parentContext ) {
  959. final AccessibleContext parentContextInnerTemp = parentContext;
  960. parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
  961. @Override
  962. public AccessibleRole call() throws Exception {
  963. return parentContextInnerTemp.getAccessibleRole();
  964. }
  965. }, ac);
  966. }
  967. }
  968. /*
  969. Step 6:
  970. =======
  971. Attempt to get the Virtual Accessible Name of the object using the
  972. Accessible Relation Set Info (the LABELED_BY Accessible Relation).
  973. */
  974. String version = getJavaVersionProperty ();
  975. if ( (null != version) && (version.compareTo ("1.3") >= 0) ) {
  976. final AccessibleContext parentContextTempInner = parentContext;
  977. AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {
  978. @Override
  979. public AccessibleRelationSet call() throws Exception {
  980. return parentContextTempInner.getAccessibleRelationSet();
  981. }
  982. }, ac);
  983. if ( ars != null && (ars.size () > 0) && (ars.contains (AccessibleRelation.LABELED_BY)) ) {
  984. AccessibleRelation labeledByRelation = ars.get (AccessibleRelation.LABELED_BY);
  985. if (labeledByRelation != null) {
  986. Object [] targets = labeledByRelation.getTarget ();
  987. Object o = targets [0];
  988. if (o instanceof Accessible) {
  989. AccessibleContext labelContext = ((Accessible)o).getAccessibleContext ();
  990. if (labelContext != null) {
  991. String labelName = labelContext.getAccessibleName ();
  992. String labelDescription = labelContext.getAccessibleDescription ();
  993. if (null != labelName) {
  994. debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Name Case.");
  995. references.increment (labelName);
  996. return labelName;
  997. } else if (null != labelDescription) {
  998. debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Description Case.");
  999. references.increment (labelDescription);
  1000. return labelDescription;
  1001. }
  1002. }
  1003. }
  1004. }
  1005. }
  1006. } else {
  1007. debugString ("bk -- This version of Java does not support AccessibleContext::getAccessibleRelationSet.");
  1008. }
  1009. //Note: add AccessibleContext to use InvocationUtils.invokeAndWait
  1010. /*
  1011. Step 7:
  1012. =======
  1013. Search for a label object that is positioned either just to the left
  1014. or just above the object and get the Accessible Name of the Label
  1015. object.
  1016. */
  1017. int testIndexMax = 0;
  1018. int testX = 0;
  1019. int testY = 0;
  1020. int testWidth = 0;
  1021. int testHeight = 0;
  1022. int targetX = 0;
  1023. int targetY = 0;
  1024. final AccessibleContext tempContext = testContext;
  1025. int testIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {
  1026. @Override
  1027. public Integer call() throws Exception {
  1028. return tempContext.getAccessibleIndexInParent();
  1029. }
  1030. }, ac);
  1031. if ( null != parentContext ) {
  1032. final AccessibleContext parentContextInnerTemp = parentContext;
  1033. testIndexMax = InvocationUtils.invokeAndWait(new Callable<Integer>() {
  1034. @Override
  1035. public Integer call() throws Exception {
  1036. return parentContextInnerTemp.getAccessibleChildrenCount() - 1;
  1037. }
  1038. }, ac);
  1039. }
  1040. testX = getAccessibleXcoordFromContext (testContext);
  1041. testY = getAccessibleYcoordFromContext (testContext);
  1042. testWidth = getAccessibleWidthFromContext (testContext);
  1043. testHeight = getAccessibleHeightFromContext (testContext);
  1044. targetX = testX + 2;
  1045. targetY = testY + 2;
  1046. int childIndex = testIndex - 1;
  1047. /*Accessible child = null;
  1048. AccessibleContext childContext = null;
  1049. AccessibleRole childRole = AccessibleRole.UNKNOWN;*/
  1050. int childX = 0;
  1051. int childY = 0;
  1052. int childWidth = 0;
  1053. int childHeight = 0;
  1054. String childName = null;
  1055. String childDescription = null;
  1056. while (childIndex >= 0) {
  1057. final int childIndexTemp = childIndex;
  1058. final AccessibleContext parentContextInnerTemp = parentContext;
  1059. final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
  1060. @Override
  1061. public Accessible call() throws Exception {
  1062. return parentContextInnerTemp.getAccessibleChild(childIndexTemp);
  1063. }
  1064. }, ac);
  1065. if ( null != child ) {
  1066. final AccessibleContext childContext = InvocationUt

Large files files are truncated, but you can click here to view the full file