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 26 #include "JavaMonkey.h" 27 #include "AccessInfo.h" 28 29 HWND ourHwnd; 30 HWND topLevelWindow; 31 int depth = -1; 32 FILE *logfile; 33 HMENU popupMenu; 34 35 char theMonkeyClassName[] = "MonkeyWin"; 36 char theAccessInfoClassName[] = "AccessInfoWin"; 37 38 HWND theMonkeyWindow; 39 HWND theTreeControlWindow; 40 HINSTANCE theInstance; 41 JavaMonkey *theMonkey; 42 AccessibleNode *theSelectedNode; 43 AccessibleNode *thePopupNode; 44 AccessibleContext theSelectedAccessibleContext; 45 HWND hwndTV; // handle of tree-view control 46 47 int APIENTRY WinMain(HINSTANCE hInstance, 48 HINSTANCE hPrevInstance, 49 LPSTR lpCmdLine, 50 int nCmdShow) 51 { 52 53 if (logfile == null) { 54 logfile = fopen(JAVA_MONKEY_LOG, "w"); // overwrite existing log file 55 logString(logfile, "Starting JavaMonkey.exe %s\n", getTimeAndDate()); 56 } 57 58 theInstance = hInstance; 59 60 // start JavaMonkey 61 theMonkey = new JavaMonkey(nCmdShow); 62 63 return 0; 64 } 65 66 JavaMonkey::JavaMonkey(int nCmdShow) { 67 68 HWND hwnd; 69 static char szAppName[] = "JavaMonkey"; 70 static char szMenuName[] = "MONKEYMENU"; 71 MSG msg; 72 WNDCLASSEX wc; 73 74 // JavaMonkey window 75 wc.cbSize = sizeof(wc); 76 wc.style = CS_HREDRAW | CS_VREDRAW; 77 wc.lpfnWndProc = WinProc; 78 wc.cbClsExtra = 0; 79 wc.cbWndExtra = 0; 80 wc.hInstance = theInstance; 81 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 82 wc.hCursor = LoadCursor(NULL, IDI_APPLICATION); 83 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 84 wc.lpszMenuName = szMenuName; 85 wc.lpszClassName = szAppName; 86 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 87 88 RegisterClassEx(&wc); 89 90 // AccessInfo Window 91 wc.cbSize = sizeof(WNDCLASSEX); 92 93 wc.hInstance = theInstance; 94 wc.lpszClassName = theAccessInfoClassName; 95 wc.lpfnWndProc = (WNDPROC)AccessInfoWindowProc; 96 wc.style = 0; 97 98 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 99 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 100 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 101 102 wc.lpszMenuName = ""; 103 wc.cbClsExtra = 0; 104 wc.cbWndExtra = 0; 105 106 wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 107 108 RegisterClassEx(&wc); 109 110 // create the JavaMonkey window 111 hwnd = CreateWindow(szAppName, 112 szAppName, 113 WS_OVERLAPPEDWINDOW, 114 CW_USEDEFAULT, 115 CW_USEDEFAULT, 116 CW_USEDEFAULT, 117 CW_USEDEFAULT, 118 NULL, 119 NULL, 120 theInstance, 121 NULL); 122 123 ourHwnd = hwnd; 124 125 /* Initialize the common controls. */ 126 INITCOMMONCONTROLSEX cc; 127 cc.dwSize = sizeof(INITCOMMONCONTROLSEX); 128 cc.dwICC = ICC_TREEVIEW_CLASSES; 129 InitCommonControlsEx(&cc); 130 131 ShowWindow(hwnd, nCmdShow); 132 133 UpdateWindow(hwnd); 134 135 BOOL result = initializeAccessBridge(); 136 if (result != FALSE) { 137 while (GetMessage(&msg, NULL, 0, 0)) { 138 TranslateMessage(&msg); 139 DispatchMessage(&msg); 140 } 141 shutdownAccessBridge(); 142 } 143 } 144 145 /* 146 * the Monkey window proc 147 */ 148 LRESULT CALLBACK WinProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { 149 150 int command; 151 short width, height; 152 153 switch(iMsg) { 154 155 case WM_CREATE: 156 // create the accessibility tree view 157 theTreeControlWindow = CreateATreeView(hwnd); 158 159 // load the popup menu 160 popupMenu = LoadMenu(theInstance, "PopupMenu"); 161 popupMenu = GetSubMenu(popupMenu, 0); 162 break; 163 164 case WM_CLOSE: 165 EndDialog(hwnd, TRUE); 166 PostQuitMessage (0); 167 break; 168 169 case WM_SIZE: 170 width = LOWORD(lParam); 171 height = HIWORD(lParam); 172 SetWindowPos(theTreeControlWindow, NULL, 0, 0, width, height, 0); 173 return(FALSE); // let windows finish handling this 174 175 case WM_COMMAND: 176 command = LOWORD(wParam); 177 switch(command) { 178 179 case cExitMenuItem: 180 EndDialog(hwnd, TRUE); 181 PostQuitMessage (0); 182 break; 183 184 case cRefreshTreeItem: 185 // update the accessibility tree 186 theMonkey->buildAccessibilityTree(); 187 break; 188 189 case cAPIMenuItem: 190 // open a new window with the Accessibility API in it for the 191 // selected element in the tree 192 if (theSelectedNode != (AccessibleNode *) 0) { 193 theSelectedNode->displayAPIWindow(); 194 } 195 break; 196 197 case cAPIPopupItem: 198 // open a new window with the Accessibility API in it for the 199 // element in the tree adjacent to the popup menu 200 if (thePopupNode != (AccessibleNode *) 0) { 201 thePopupNode->displayAPIWindow(); 202 } 203 break; 204 205 } 206 break; 207 208 case WM_NOTIFY: // receive tree messages 209 210 NMTREEVIEW *nmptr = (LPNMTREEVIEW) lParam; 211 switch (nmptr->hdr.code) { 212 213 case TVN_SELCHANGED: 214 // get the selected tree node 215 theSelectedNode = (AccessibleNode *) nmptr->itemNew.lParam; 216 break; 217 218 case NM_RCLICK: 219 220 // display a popup menu over the tree node 221 POINT p; 222 GetCursorPos(&p); 223 TrackPopupMenu(popupMenu, 0, p.x, p.y, 0, hwnd, NULL); 224 225 // get the tree node under the popup menu 226 TVHITTESTINFO hitinfo; 227 ScreenToClient(theTreeControlWindow, &p); 228 hitinfo.pt = p; 229 HTREEITEM node = TreeView_HitTest(theTreeControlWindow, &hitinfo); 230 231 if (node != null) { 232 TVITEMEX tvItem; 233 tvItem.hItem = node; 234 if (TreeView_GetItem(hwndTV, &tvItem) == TRUE) { 235 thePopupNode = (AccessibleNode *)tvItem.lParam; 236 } 237 } 238 break; 239 } 240 } 241 return DefWindowProc(hwnd, iMsg, wParam, lParam); 242 } 243 244 /* 245 * Accessibility information window proc 246 */ 247 LRESULT CALLBACK AccessInfoWindowProc(HWND hWnd, UINT message, 248 UINT wParam, LONG lParam) { 249 short width, height; 250 HWND dlgItem; 251 252 switch (message) { 253 case WM_CREATE: 254 RECT rcClient; // dimensions of client area 255 HWND hwndEdit; // handle of tree-view control 256 257 // Get the dimensions of the parent window's client area, 258 // and create the edit control. 259 GetClientRect(hWnd, &rcClient); 260 hwndEdit = CreateWindow("Edit", 261 "", 262 WS_VISIBLE | WS_TABSTOP | WS_CHILD | 263 ES_MULTILINE | ES_AUTOVSCROLL | 264 ES_READONLY | WS_VSCROLL, 265 0, 0, rcClient.right, rcClient.bottom, 266 hWnd, 267 (HMENU) cAccessInfoText, 268 theInstance, 269 NULL); 270 break; 271 272 case WM_CLOSE: 273 DestroyWindow(hWnd); 274 break; 275 276 case WM_SIZE: 277 width = LOWORD(lParam); 278 height = HIWORD(lParam); 279 dlgItem = GetDlgItem(hWnd, cAccessInfoText); 280 SetWindowPos(dlgItem, NULL, 0, 0, width, height, 0); 281 return(FALSE); // let windows finish handling this 282 break; 283 284 default: 285 return DefWindowProc(hWnd, message, wParam, lParam); 286 } 287 288 return 0; 289 } 290 291 /** 292 * Build a tree (and the treeview control) of all accessible Java components 293 * 294 */ 295 void JavaMonkey::buildAccessibilityTree() { 296 // have MS-Windows call EnumWndProc() with all of the top-level windows 297 EnumWindows((WNDENUMPROC) EnumWndProc, NULL); 298 } 299 300 /** 301 * Create (and display) the accessible component nodes of a parent AccessibleContext 302 * 303 */ 304 BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam) { 305 if (IsJavaWindow(hwnd)) { 306 long vmID; 307 AccessibleContext ac; 308 if (GetAccessibleContextFromHWND(hwnd, &vmID, &ac) == TRUE) { 309 theMonkey->addComponentNodes(vmID, ac, (AccessibleNode *) NULL, 310 hwnd, TVI_ROOT, theTreeControlWindow); 311 } 312 topLevelWindow = hwnd; 313 } 314 return(TRUE); 315 } 316 317 // CreateATreeView - creates a tree-view control. 318 // Returns the handle of the new control if successful or NULL 319 // otherwise. 320 // hwndParent - handle of the control's parent window 321 HWND CreateATreeView(HWND hwndParent) { 322 RECT rcClient; // dimensions of client area 323 324 // Get the dimensions of the parent window's client area, and create 325 // the tree-view control. 326 GetClientRect(hwndParent, &rcClient); 327 hwndTV = CreateWindow(WC_TREEVIEW, 328 "", 329 WS_VISIBLE | WS_TABSTOP | WS_CHILD | 330 TVS_HASLINES | TVS_HASBUTTONS | 331 TVS_LINESATROOT, 332 0, 0, rcClient.right, rcClient.bottom, 333 hwndParent, 334 (HMENU) cTreeControl, 335 theInstance, 336 NULL); 337 338 return hwndTV; 339 } 340 341 /** 342 * Create (and display) the accessible component nodes of a parent AccessibleContext 343 * 344 */ 345 void JavaMonkey::addComponentNodes(long vmID, AccessibleContext context, 346 AccessibleNode *parent, HWND hwnd, 347 HTREEITEM treeNodeParent, HWND treeWnd) { 348 349 AccessibleNode *newNode = new AccessibleNode(vmID, context, parent, hwnd, treeNodeParent); 350 351 AccessibleContextInfo info; 352 if (GetAccessibleContextInfo(vmID, context, &info) != FALSE) { 353 char s[LINE_BUFSIZE]; 354 355 wsprintf(s, "%ls", info.name); 356 newNode->setAccessibleName(s); 357 wsprintf(s, "%ls", info.role); 358 newNode->setAccessibleRole(s); 359 360 wsprintf(s, "%ls [%ls]", info.name, info.role); 361 362 TVITEM tvi; 363 tvi.mask = TVIF_PARAM | TVIF_TEXT; 364 tvi.pszText = (char *) s; // Accessible name and role 365 tvi.cchTextMax = (int)strlen(s); 366 tvi.lParam = (long) newNode; // Accessibility information 367 368 TVINSERTSTRUCT tvis; 369 tvis.hParent = treeNodeParent; 370 tvis.hInsertAfter = TVI_LAST; 371 tvis.item = tvi; 372 373 HTREEITEM treeNodeItem = TreeView_InsertItem(treeWnd, &tvis); 374 375 for (int i = 0; i < info.childrenCount; i++) { 376 addComponentNodes(vmID, GetAccessibleChildFromContext(vmID, context, i), 377 newNode, hwnd, treeNodeItem, treeWnd); 378 } 379 } else { 380 char s[LINE_BUFSIZE]; 381 sprintf(s, "ERROR calling GetAccessibleContextInfo; vmID = %X, context = %X", vmID, context); 382 383 TVITEM tvi; 384 tvi.mask = TVIF_PARAM | TVIF_TEXT; // text and lParam are only valid parts 385 tvi.pszText = (char *) s; 386 tvi.cchTextMax = (int)strlen(s); 387 tvi.lParam = (long) newNode; 388 389 TVINSERTSTRUCT tvis; 390 tvis.hParent = treeNodeParent; 391 tvis.hInsertAfter = TVI_LAST; // make tree in order given 392 tvis.item = tvi; 393 394 HTREEITEM treeNodeItem = TreeView_InsertItem(treeWnd, &tvis); 395 } 396 } 397 398 // ----------------------------- 399 400 /** 401 * Create an AccessibleNode 402 * 403 */ 404 AccessibleNode::AccessibleNode(long JavaVMID, AccessibleContext context, 405 AccessibleNode *parent, HWND hwnd, 406 HTREEITEM parentTreeNodeItem) { 407 vmID = JavaVMID; 408 ac = context; 409 parentNode = parent; 410 baseHWND = hwnd; 411 treeNodeParent = parentTreeNodeItem; 412 413 // setting accessibleName and accessibleRole not done here, 414 // in order to minimize calls to the AccessBridge 415 // (since such a call is needed to enumerate children) 416 } 417 418 /** 419 * Destroy an AccessibleNode 420 * 421 */ 422 AccessibleNode::~AccessibleNode() { 423 ReleaseJavaObject(vmID, ac); 424 } 425 426 /** 427 * Set the accessibleName string 428 * 429 */ 430 void AccessibleNode::setAccessibleName(char *name) { 431 strncpy(accessibleName, name, MAX_STRING_SIZE); 432 } 433 434 /** 435 * Set the accessibleRole string 436 * 437 */ 438 void AccessibleNode::setAccessibleRole(char *role) { 439 strncpy(accessibleRole, role, SHORT_STRING_SIZE); 440 } 441 442 443 444 445 446 447 448 /** 449 * Create an API window to show off the info for this AccessibleContext 450 */ 451 BOOL AccessibleNode::displayAPIWindow() { 452 453 HWND apiWindow = CreateWindow(theAccessInfoClassName, 454 "Java Accessibility API view", 455 WS_OVERLAPPEDWINDOW, 456 CW_USEDEFAULT, 457 CW_USEDEFAULT, 458 600, 459 750, 460 HWND_DESKTOP, 461 NULL, 462 theInstance, 463 (void *) NULL); 464 465 if (!apiWindow) { 466 printError("cannot create API window"); 467 return (FALSE); 468 } 469 470 char buffer[HUGE_BUFSIZE]; 471 buffer[0] = '\0'; 472 getAccessibleInfo(vmID, ac, buffer, sizeof(buffer)); 473 displayAndLog(apiWindow, cAccessInfoText, logfile, buffer); 474 475 ShowWindow(apiWindow, SW_SHOWNORMAL); 476 UpdateWindow(apiWindow); 477 478 return (TRUE); 479 }