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 }