1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 package org.openoffice.accessibility; 24 25 import com.sun.star.accessibility.AccessibleRole; 26 import com.sun.star.accessibility.XAccessible; 27 import com.sun.star.accessibility.XAccessibleContext; 28 import com.sun.star.java.XJavaVM; 29 import com.sun.star.uno.*; 30 31 import org.openoffice.java.accessibility.*; 32 33 import java.lang.reflect.InvocationTargetException; 34 import java.lang.reflect.Method; 35 36 import javax.accessibility.*; 37 38 39 public class WindowsAccessBridgeAdapter { 40 private static Method registerVirtualFrame; 41 private static Method revokeVirtualFrame; 42 private static java.util.Hashtable frameMap; 43 getProcessID()44 protected static native byte[] getProcessID(); 45 createMapping(long jvmaccess)46 protected static native boolean createMapping(long jvmaccess); 47 48 // On Windows all native frames must be registered to the access bridge. 49 // Therefor the bridge exports two methods that we try to find here. attach(XComponentContext xComponentContext)50 protected static void attach(XComponentContext xComponentContext) { 51 try { 52 Class bridge = Class.forName( 53 "com.sun.java.accessibility.AccessBridge"); 54 Class[] parameterTypes = { 55 javax.accessibility.Accessible.class, Integer.class 56 }; 57 58 if (bridge != null) { 59 registerVirtualFrame = bridge.getMethod("registerVirtualFrame", 60 parameterTypes); 61 revokeVirtualFrame = bridge.getMethod("revokeVirtualFrame", 62 parameterTypes); 63 64 // load the native dll 65 System.loadLibrary("java_uno_accessbridge"); 66 67 Object any = xComponentContext.getValueByName( 68 "/singletons/com.sun.star.java.theJavaVirtualMachine"); 69 70 if (AnyConverter.isObject(any)) { 71 XJavaVM xJavaVM = (XJavaVM) UnoRuntime.queryInterface(XJavaVM.class, 72 AnyConverter.toObject(new Type(XJavaVM.class), any)); 73 74 if (xJavaVM != null) { 75 any = xJavaVM.getJavaVM(getProcessID()); 76 77 if (AnyConverter.isLong(any)) { 78 createMapping(AnyConverter.toLong(any)); 79 frameMap = new java.util.Hashtable(); 80 } 81 } 82 } 83 } 84 } catch (NoSuchMethodException e) { 85 System.err.println("ERROR: incompatible AccessBridge found: " + 86 e.getMessage()); 87 88 // Forward this exception to UNO to indicate that the service will 89 // not work correctly. 90 throw new com.sun.star.uno.RuntimeException( 91 "incompatible AccessBridge class: " + e.getMessage()); 92 } catch (java.lang.SecurityException e) { 93 System.err.println("ERROR: no access to AccessBridge: " + 94 e.getMessage()); 95 96 // Forward this exception to UNO to indicate that the service will not work correctly. 97 throw new com.sun.star.uno.RuntimeException( 98 "Security exception caught: " + e.getMessage()); 99 } catch (ClassNotFoundException e) { 100 // Forward this exception to UNO to indicate that the service will not work correctly. 101 throw new com.sun.star.uno.RuntimeException( 102 "ClassNotFound exception caught: " + e.getMessage()); 103 } catch (IllegalArgumentException e) { 104 System.err.println("IllegalArgumentException caught: " + 105 e.getMessage()); 106 107 // Forward this exception to UNO to indicate that the service will not work correctly. 108 throw new com.sun.star.uno.RuntimeException( 109 "IllegalArgumentException caught: " + e.getMessage()); 110 } catch (com.sun.star.lang.IllegalArgumentException e) { 111 System.err.println("UNO IllegalArgumentException caught: " + 112 e.getMessage()); 113 114 // Forward this exception to UNO to indicate that the service will not work correctly. 115 throw new com.sun.star.uno.RuntimeException( 116 "UNO IllegalArgumentException caught: " + e.getMessage()); 117 } 118 } 119 isAttached()120 protected static boolean isAttached() { 121 return frameMap != null; 122 } 123 getAccessibleWrapper(XAccessible xAccessible)124 protected static Accessible getAccessibleWrapper(XAccessible xAccessible) { 125 Accessible a = null; 126 127 try { 128 XAccessibleContext xAccessibleContext = xAccessible.getAccessibleContext(); 129 130 if (xAccessibleContext != null) { 131 switch (xAccessibleContext.getAccessibleRole()) { 132 case AccessibleRole.LIST: 133 a = (Accessible) AccessibleObjectFactory.getAccessibleComponent(xAccessible); 134 if (a != null) { 135 a = new ListProxy(a.getAccessibleContext()); 136 } 137 break; 138 139 case AccessibleRole.MENU: 140 141 Accessible tmp = (Accessible) AccessibleObjectFactory.getAccessibleComponent(xAccessible); 142 if (tmp != null) { 143 AccessibleContext ac = tmp.getAccessibleContext(); 144 145 if (ac != null) { 146 a = new PopupMenuProxy(ac); 147 } 148 } 149 150 break; 151 152 case AccessibleRole.TOOL_TIP: 153 a = PopupWindow.create(xAccessible); 154 break; 155 156 default: 157 a = (Accessible) AccessBridge.getTopWindow(xAccessible); 158 break; 159 } 160 } 161 } catch (com.sun.star.uno.RuntimeException e) { 162 } 163 164 return a; 165 } 166 167 /** Registers a native frame at the Java AccessBridge for Windows */ registerTopWindow(int handle, XAccessible xAccessible)168 public static void registerTopWindow(int handle, XAccessible xAccessible) { 169 Integer hwnd = new Integer(handle); 170 171 if (!frameMap.contains(hwnd)) { 172 if (Build.DEBUG) { 173 System.err.println("Native frame " + hwnd + " of role " + 174 AccessibleRoleAdapter.getAccessibleRole(xAccessible) + 175 " has been opened"); 176 } 177 178 Accessible a = getAccessibleWrapper(xAccessible); 179 180 if (a != null) { 181 Object[] args = { a, hwnd }; 182 183 frameMap.put(hwnd, a); 184 185 if (Build.DEBUG) { 186 System.err.println("registering native frame " + hwnd); 187 } 188 189 try { 190 registerVirtualFrame.invoke(null, args); 191 } catch (IllegalAccessException e) { 192 System.err.println("IllegalAccessException caught: " + 193 e.getMessage()); 194 } catch (IllegalArgumentException e) { 195 System.err.println("IllegalArgumentException caught: " + 196 e.getMessage()); 197 } catch (InvocationTargetException e) { 198 System.err.println("InvokationTargetException caught: " + 199 e.getMessage()); 200 } 201 } 202 } 203 } 204 205 /** Revokes a native frame at the Java AccessBridge for Windows */ revokeTopWindow(int handle, XAccessible xAccessible)206 public static void revokeTopWindow(int handle, XAccessible xAccessible) { 207 Integer hwnd = new Integer(handle); 208 209 Accessible a = (Accessible) frameMap.remove(hwnd); 210 211 if (a != null) { 212 Object[] args = { a, hwnd }; 213 214 if (Build.DEBUG) { 215 System.err.println("revoking native frame " + hwnd); 216 } 217 218 try { 219 revokeVirtualFrame.invoke(null, args); 220 } catch (IllegalAccessException e) { 221 System.err.println("IllegalAccessException caught: " + 222 e.getMessage()); 223 } catch (IllegalArgumentException e) { 224 System.err.println("IllegalArgumentException caught: " + 225 e.getMessage()); 226 } catch (InvocationTargetException e) { 227 System.err.println("InvokationTargetException caught: " + 228 e.getMessage()); 229 } 230 } 231 232 if (a instanceof PopupWindow) { 233 PopupWindow toolTipWindow = (PopupWindow) a; 234 toolTipWindow.removeAll(); 235 toolTipWindow.dispose(); 236 } 237 } 238 239 protected static class PopupMenuProxy extends AccessibleContext 240 implements Accessible, AccessibleComponent { 241 AccessibleContext menu; 242 AccessibleComponent menuComponent; 243 int x = 0; int y = 0; int width = 0; int height = 0; 244 PopupMenuProxy(AccessibleContext ac)245 PopupMenuProxy(AccessibleContext ac) { 246 menu = ac; 247 menuComponent = menu.getAccessibleComponent(); 248 249 /** calculate the bounding rectangle by iterating over the 250 * the children. 251 */ 252 int x2 = 0; int y2 = 0; 253 int count = ac.getAccessibleChildrenCount(); 254 for (int i = 0; i < count; i++) { 255 Accessible a = menu.getAccessibleChild(i); 256 257 if (a != null) { 258 AccessibleContext childAC = a.getAccessibleContext(); 259 260 if (childAC != null) { 261 AccessibleComponent comp = ac.getAccessibleComponent(); 262 263 if (comp != null) { 264 java.awt.Point p = comp.getLocationOnScreen(); 265 java.awt.Dimension d = comp.getSize(); 266 267 if (p != null && d != null) { 268 if (p.x < x) { 269 x = p.x; 270 } 271 if (p.y < y) { 272 y = p.y; 273 } 274 if (p.x + d.width > x2) { 275 x2 = p.x + d.width; 276 } 277 if (p.y + d.height > y2) { 278 y2 = p.y + d.height; 279 } 280 } 281 } 282 } 283 } 284 } 285 286 width = x2 - x; 287 height = y2 - y; 288 } 289 290 /** Returns the AccessibleContext associated with this object */ getAccessibleContext()291 public javax.accessibility.AccessibleContext getAccessibleContext() { 292 return this; 293 } 294 295 /** Returns the AccessibleContext associated with this object */ getAccessibleComponent()296 public javax.accessibility.AccessibleComponent getAccessibleComponent() { 297 return this; 298 } 299 300 /** Returns the AccessibleText associated with this object */ getAccessibleText()301 public javax.accessibility.AccessibleText getAccessibleText() { 302 return menu.getAccessibleText(); 303 } 304 305 /** Returns the AccessibleContext associated with this object */ getAccessibleStateSet()306 public javax.accessibility.AccessibleStateSet getAccessibleStateSet() { 307 return menu.getAccessibleStateSet(); 308 } 309 getLocale()310 public java.util.Locale getLocale() { 311 return menu.getLocale(); 312 } 313 getAccessibleIndexInParent()314 public int getAccessibleIndexInParent() { 315 return -1; 316 } 317 getAccessibleChildrenCount()318 public int getAccessibleChildrenCount() { 319 return menu.getAccessibleChildrenCount(); 320 } 321 getAccessibleChild(int i)322 public javax.accessibility.Accessible getAccessibleChild(int i) { 323 return menu.getAccessibleChild(i); 324 } 325 getAccessibleRole()326 public javax.accessibility.AccessibleRole getAccessibleRole() { 327 return javax.accessibility.AccessibleRole.POPUP_MENU; 328 } 329 330 /* 331 * AccessibleComponent 332 */ addFocusListener(java.awt.event.FocusListener fl)333 public void addFocusListener(java.awt.event.FocusListener fl) { 334 menuComponent.addFocusListener(fl); 335 } 336 removeFocusListener(java.awt.event.FocusListener fl)337 public void removeFocusListener(java.awt.event.FocusListener fl) { 338 menuComponent.removeFocusListener(fl); 339 } 340 341 /** Returns the background color of the object */ getBackground()342 public java.awt.Color getBackground() { 343 return menuComponent.getBackground(); 344 } 345 setBackground(java.awt.Color c)346 public void setBackground(java.awt.Color c) { 347 // Not supported by UNO accessibility API 348 } 349 350 /** Returns the foreground color of the object */ getForeground()351 public java.awt.Color getForeground() { 352 return menuComponent.getForeground(); 353 } 354 setForeground(java.awt.Color c)355 public void setForeground(java.awt.Color c) { 356 menuComponent.setForeground(c); 357 } 358 getCursor()359 public java.awt.Cursor getCursor() { 360 return menuComponent.getCursor(); 361 } 362 setCursor(java.awt.Cursor cursor)363 public void setCursor(java.awt.Cursor cursor) { 364 menuComponent.setCursor(cursor); 365 } 366 getFont()367 public java.awt.Font getFont() { 368 return menuComponent.getFont(); 369 } 370 setFont(java.awt.Font f)371 public void setFont(java.awt.Font f) { 372 menuComponent.setFont(f); 373 } 374 getFontMetrics(java.awt.Font f)375 public java.awt.FontMetrics getFontMetrics(java.awt.Font f) { 376 return menuComponent.getFontMetrics(f); 377 } 378 isEnabled()379 public boolean isEnabled() { 380 return menuComponent.isEnabled(); 381 } 382 setEnabled(boolean b)383 public void setEnabled(boolean b) { 384 menuComponent.setEnabled(b); 385 } 386 isVisible()387 public boolean isVisible() { 388 return menuComponent.isVisible(); 389 } 390 setVisible(boolean b)391 public void setVisible(boolean b) { 392 menuComponent.setVisible(b); 393 } 394 isShowing()395 public boolean isShowing() { 396 return menuComponent.isShowing(); 397 } 398 contains(java.awt.Point p)399 public boolean contains(java.awt.Point p) { 400 java.awt.Dimension d = getSize(); 401 402 if (Build.DEBUG) { 403 System.err.println("PopupMenuProxy.containsPoint(" + p.x + "," + 404 p.y + ") returns " + 405 (((d.width >= 0) && (p.x < d.width) && (d.height >= 0) && 406 (p.y < d.height)) ? "true" : "false")); 407 } 408 409 if ((d.width >= 0) && (p.x < d.width) && (d.height >= 0) && 410 (p.y < d.height)) { 411 return true; 412 } 413 414 return false; 415 } 416 417 /** Returns the location of the object on the screen. */ getLocationOnScreen()418 public java.awt.Point getLocationOnScreen() { 419 return new java.awt.Point(x,y); 420 } 421 422 /** Gets the location of this component in the form of a point specifying the component's top-left corner */ getLocation()423 public java.awt.Point getLocation() { 424 // This object represents a toplevel, so this is the same as getLocationOnScreen() 425 return getLocationOnScreen(); 426 } 427 428 /** Moves this component to a new location */ setLocation(java.awt.Point p)429 public void setLocation(java.awt.Point p) { 430 // Not supported by UNO accessibility API 431 } 432 433 /** Gets the bounds of this component in the form of a Rectangle object */ getBounds()434 public java.awt.Rectangle getBounds() { 435 return new java.awt.Rectangle(x, y, width, height); 436 } 437 438 /** Moves and resizes this component to conform to the new bounding rectangle r */ setBounds(java.awt.Rectangle r)439 public void setBounds(java.awt.Rectangle r) { 440 // Not supported by UNO accessibility API 441 } 442 443 /** Returns the size of this component in the form of a Dimension object */ getSize()444 public java.awt.Dimension getSize() { 445 return new java.awt.Dimension(width, height); 446 } 447 448 /** Resizes this component so that it has width d.width and height d.height */ setSize(java.awt.Dimension d)449 public void setSize(java.awt.Dimension d) { 450 // Not supported by UNO accessibility API 451 } 452 453 /** Returns the Accessible child, if one exists, contained at the local 454 * coordinate Point 455 */ getAccessibleAt(java.awt.Point p)456 public javax.accessibility.Accessible getAccessibleAt(java.awt.Point p) { 457 java.awt.Point p2 = menuComponent.getLocationOnScreen(); 458 return menuComponent.getAccessibleAt( 459 new java.awt.Point(p.x + x - p2.x, p.y + y - p2.y)); 460 } 461 isFocusTraversable()462 public boolean isFocusTraversable() { 463 return menuComponent.isFocusTraversable(); 464 } 465 requestFocus()466 public void requestFocus() { 467 menuComponent.requestFocus(); 468 } 469 } 470 471 protected static class ListProxy extends AccessibleContext 472 implements Accessible, AccessibleComponent { 473 AccessibleContext list; 474 AccessibleComponent listComponent; 475 ListProxy(AccessibleContext ac)476 ListProxy(AccessibleContext ac) { 477 list = ac; 478 listComponent = list.getAccessibleComponent(); 479 } 480 481 /** Returns the AccessibleContext associated with this object */ getAccessibleContext()482 public javax.accessibility.AccessibleContext getAccessibleContext() { 483 return this; 484 } 485 486 /** Returns the AccessibleContext associated with this object */ getAccessibleComponent()487 public javax.accessibility.AccessibleComponent getAccessibleComponent() { 488 return this; 489 } 490 491 /** Returns the AccessibleSelection associated with this object */ getAccessibleSelection()492 public javax.accessibility.AccessibleSelection getAccessibleSelection() { 493 return list.getAccessibleSelection(); 494 } 495 496 /** Returns the AccessibleContext associated with this object */ getAccessibleStateSet()497 public javax.accessibility.AccessibleStateSet getAccessibleStateSet() { 498 return list.getAccessibleStateSet(); 499 } 500 getLocale()501 public java.util.Locale getLocale() { 502 return list.getLocale(); 503 } 504 getAccessibleIndexInParent()505 public int getAccessibleIndexInParent() { 506 return -1; 507 } 508 getAccessibleChildrenCount()509 public int getAccessibleChildrenCount() { 510 return list.getAccessibleChildrenCount(); 511 } 512 getAccessibleChild(int i)513 public javax.accessibility.Accessible getAccessibleChild(int i) { 514 return list.getAccessibleChild(i); 515 } 516 getAccessibleRole()517 public javax.accessibility.AccessibleRole getAccessibleRole() { 518 return javax.accessibility.AccessibleRole.LIST; 519 } 520 521 /* 522 * AccessibleComponent 523 */ addFocusListener(java.awt.event.FocusListener fl)524 public void addFocusListener(java.awt.event.FocusListener fl) { 525 listComponent.addFocusListener(fl); 526 } 527 removeFocusListener(java.awt.event.FocusListener fl)528 public void removeFocusListener(java.awt.event.FocusListener fl) { 529 listComponent.removeFocusListener(fl); 530 } 531 532 /** Returns the background color of the object */ getBackground()533 public java.awt.Color getBackground() { 534 return listComponent.getBackground(); 535 } 536 setBackground(java.awt.Color c)537 public void setBackground(java.awt.Color c) { 538 // Not supported by UNO accessibility API 539 } 540 541 /** Returns the foreground color of the object */ getForeground()542 public java.awt.Color getForeground() { 543 return listComponent.getForeground(); 544 } 545 setForeground(java.awt.Color c)546 public void setForeground(java.awt.Color c) { 547 listComponent.setForeground(c); 548 } 549 getCursor()550 public java.awt.Cursor getCursor() { 551 return listComponent.getCursor(); 552 } 553 setCursor(java.awt.Cursor cursor)554 public void setCursor(java.awt.Cursor cursor) { 555 listComponent.setCursor(cursor); 556 } 557 getFont()558 public java.awt.Font getFont() { 559 return listComponent.getFont(); 560 } 561 setFont(java.awt.Font f)562 public void setFont(java.awt.Font f) { 563 listComponent.setFont(f); 564 } 565 getFontMetrics(java.awt.Font f)566 public java.awt.FontMetrics getFontMetrics(java.awt.Font f) { 567 return listComponent.getFontMetrics(f); 568 } 569 isEnabled()570 public boolean isEnabled() { 571 return listComponent.isEnabled(); 572 } 573 setEnabled(boolean b)574 public void setEnabled(boolean b) { 575 listComponent.setEnabled(b); 576 } 577 isVisible()578 public boolean isVisible() { 579 return listComponent.isVisible(); 580 } 581 setVisible(boolean b)582 public void setVisible(boolean b) { 583 listComponent.setVisible(b); 584 } 585 isShowing()586 public boolean isShowing() { 587 return listComponent.isShowing(); 588 } 589 contains(java.awt.Point p)590 public boolean contains(java.awt.Point p) { 591 return listComponent.contains(p); 592 } 593 594 /** Returns the location of the object on the screen. */ getLocationOnScreen()595 public java.awt.Point getLocationOnScreen() { 596 return listComponent.getLocationOnScreen(); 597 } 598 599 /** Gets the location of this component in the form of a point specifying 600 * the component's top-left corner 601 */ getLocation()602 public java.awt.Point getLocation() { 603 // This object represents a toplevel object, so getLocation() should 604 // return the same as getLocationOnScreen(). 605 return getLocationOnScreen(); 606 } 607 608 /** Moves this component to a new location */ setLocation(java.awt.Point p)609 public void setLocation(java.awt.Point p) { 610 // Not supported by UNO accessibility API 611 } 612 613 /** Gets the bounds of this component in the form of a Rectangle object */ getBounds()614 public java.awt.Rectangle getBounds() { 615 java.awt.Point p = getLocationOnScreen(); 616 java.awt.Dimension d = getSize(); 617 return new java.awt.Rectangle(p.x, p.y, d.width, d.height); 618 } 619 620 /** Moves and resizes this component to conform to the new bounding rectangle r */ setBounds(java.awt.Rectangle r)621 public void setBounds(java.awt.Rectangle r) { 622 // Not supported by UNO accessibility API 623 } 624 625 /** Returns the size of this component in the form of a Dimension object */ getSize()626 public java.awt.Dimension getSize() { 627 return listComponent.getSize(); 628 } 629 630 /** Resizes this component so that it has width d.width and height d.height */ setSize(java.awt.Dimension d)631 public void setSize(java.awt.Dimension d) { 632 // Not supported by UNO accessibility API 633 } 634 635 /** Returns the Accessible child, if one exists, contained at the local 636 * coordinate Point 637 */ getAccessibleAt(java.awt.Point p)638 public javax.accessibility.Accessible getAccessibleAt(java.awt.Point p) { 639 return listComponent.getAccessibleAt(p); 640 } 641 isFocusTraversable()642 public boolean isFocusTraversable() { 643 return listComponent.isFocusTraversable(); 644 } 645 requestFocus()646 public void requestFocus() { 647 listComponent.requestFocus(); 648 } 649 } 650 } 651