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 "AccessBridgeCalls.h"
  27 #include "AccessInfo.h"
  28 #include <stdio.h>
  29 #include <time.h>
  30 
  31 /*
  32  * returns formatted date and time
  33  */
  34 char *getTimeAndDate() {
  35     static char datebuf[64];
  36     struct tm *newtime;
  37     char am_pm[] = "AM";
  38     time_t long_time;
  39 
  40     time( &long_time );                /* Get time as long integer. */
  41     newtime = localtime( &long_time ); /* Convert to local time. */
  42 
  43     if( newtime->tm_hour > 12 )        /* Set up extension. */
  44         strcpy( am_pm, "PM" );
  45     if( newtime->tm_hour > 12 )        /* Convert from 24-hour */
  46                 newtime->tm_hour -= 12;    /*   to 12-hour clock.  */
  47     if( newtime->tm_hour == 0 )        /*Set hour to 12 if midnight. */
  48         newtime->tm_hour = 12;
  49 
  50     sprintf(datebuf, "%.19s %s\n", asctime( newtime ), am_pm );
  51     return (char *)datebuf;
  52 }
  53 
  54 
  55 /*
  56  * displays a message in a dialog and writes the message to a logfile
  57  */
  58 void displayAndLog(HWND hDlg, int nIDDlgItem, FILE *logfile, char *msg, ...) {
  59 
  60     if (hDlg == NULL || msg == NULL) {
  61         return;
  62     }
  63 
  64     char tmpbuf[HUGE_BUFSIZE];
  65     va_list argprt;
  66 
  67     va_start(argprt, msg);
  68     vsprintf(tmpbuf, msg, argprt);
  69 
  70     SetDlgItemText(hDlg, nIDDlgItem, tmpbuf);
  71 
  72     fprintf(logfile, "\n****************************************\n");
  73     fprintf(logfile, "%s\n", getTimeAndDate());
  74     fprintf(logfile, "%s\n", tmpbuf);
  75     fflush(logfile);
  76 }
  77 
  78 /*
  79  * writes a text string to a logfile
  80  */
  81 void logString(FILE *logfile, char *msg, ...) {
  82 
  83     if (logfile == NULL || msg == NULL) {
  84         return;
  85     }
  86 
  87     char tmpbuf[LINE_BUFSIZE];
  88     va_list argprt;
  89 
  90     va_start(argprt, msg);
  91     vsprintf(tmpbuf, msg, argprt);
  92 
  93     fprintf(logfile, tmpbuf);
  94     fprintf(logfile, "\n");
  95     fflush(logfile);
  96 }
  97 
  98 /*
  99  * safely appends a message to a buffer
 100  */
 101 BOOL appendToBuffer(char *buf, size_t buflen, char *msg, ...) {
 102 
 103     static char warning[] =
 104         "\nNot enough buffer space; remaining information truncated.\n";
 105     int warningLength = (int)strlen(warning) + 1;
 106 
 107     if (buf == NULL || msg == NULL) {
 108         return FALSE;
 109     }
 110 
 111     char tmpbuf[LARGE_BUFSIZE];
 112     va_list argprt;
 113 
 114     va_start(argprt, msg);
 115     vsprintf(tmpbuf, msg, argprt);
 116 
 117     // verify there's enough space in the buffer
 118     int spaceRemaining = buflen - (int)strlen(buf) - 1;
 119     if (spaceRemaining <= warningLength) {
 120         strncat(buf, warning, spaceRemaining);
 121         return FALSE;
 122     }
 123     strncat(buf, tmpbuf, spaceRemaining);
 124     return TRUE;
 125 }
 126 
 127 /**
 128  * returns accessibility information for an AccessibleContext
 129  */
 130 char *getAccessibleInfo(long vmID, AccessibleContext ac, char *buffer,
 131                         int bufsize) {
 132     return getAccessibleInfo(vmID, ac, 0, 0, buffer, bufsize);
 133 }
 134 
 135 /**
 136  * returns accessibility information at the specified coordinates in an
 137  * AccessibleContext
 138  */
 139 char *getAccessibleInfo(long vmID, AccessibleContext ac, int x, int y,
 140                         char *buffer, int bufsize) {
 141 
 142     wchar_t tmpBuf[LINE_BUFSIZE];
 143     wchar_t name[LINE_BUFSIZE];
 144     int i, j;
 145     long start;
 146     long end;
 147 
 148     if (buffer == NULL || bufsize <= 0) {
 149         return NULL;
 150     }
 151     buffer[0] = NULL;
 152 
 153     /* ===== AccessBridge / J2SE version information ===== */
 154 
 155     AccessBridgeVersionInfo versionInfo;
 156     BOOL result = GetVersionInfo(vmID, &versionInfo);
 157 
 158     if (result == FALSE) {
 159         appendToBuffer(buffer, bufsize, "\r\nERROR: cannot get version information", bufsize);
 160     } else {
 161         appendToBuffer(buffer, bufsize, "Version Information:");
 162         appendToBuffer(buffer, bufsize, "\r\n    Java virtual machine version: %ls",
 163                  versionInfo.VMversion);
 164         appendToBuffer(buffer, bufsize, "\r\n    Access Bridge Java class version: %ls",
 165                  versionInfo.bridgeJavaClassVersion);
 166         appendToBuffer(buffer, bufsize, "\r\n    Access Bridge Java DLL version: %ls",
 167                  versionInfo.bridgeJavaDLLVersion);
 168         appendToBuffer(buffer, bufsize, "\r\n    Access Bridge Windows DLL version: %ls",
 169                  versionInfo.bridgeWinDLLVersion);
 170     }
 171 
 172     if (ac == (AccessibleContext) 0) {
 173         return buffer;
 174     }
 175 
 176 
 177     /* ===== core AccessibleContext information ===== */
 178 
 179     AccessibleContextInfo info;
 180     if (GetAccessibleContextInfo(vmID, ac, &info) == FALSE) {
 181         appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed ", bufsize);
 182     } else {
 183 
 184         appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleContext information", bufsize);
 185         if (x >= 0 && y >= 0) {
 186             appendToBuffer(buffer, bufsize, " at mouse point [%d, %d]:", x, y);
 187         } else {
 188             appendToBuffer(buffer, bufsize, ":", bufsize);
 189         }
 190 
 191         if (getVirtualAccessibleName(vmID, ac, name, sizeof(name)) == FALSE) {
 192             appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize);
 193         } else {
 194             appendToBuffer(buffer, bufsize, "\r\n    Name:  %ls", name);
 195         }
 196         appendToBuffer(buffer, bufsize, "\r\n    Description:  %ls", info.description);
 197         appendToBuffer(buffer, bufsize, "\r\n    Role:  %ls", info.role);
 198         appendToBuffer(buffer, bufsize, "\r\n    Role in en_US locale:  %ls", info.role_en_US);
 199         appendToBuffer(buffer, bufsize, "\r\n    States:  %ls", info.states);
 200         appendToBuffer(buffer, bufsize, "\r\n    States in en_US locale:  %ls", info.states_en_US);
 201         appendToBuffer(buffer, bufsize, "\r\n    Index in parent:  %d", info.indexInParent);
 202         appendToBuffer(buffer, bufsize, "\r\n    Children count:  %d", info.childrenCount);
 203         appendToBuffer(buffer, bufsize, "\r\n    Bounding rectangle:  [%d, %d, %d, %d]",
 204                 info.x, info.y, info.x + info.width, info.y + info.height);
 205 
 206         /*  top-level window info */
 207         AccessibleContext topAC  = getTopLevelObject(vmID, ac);
 208         if (topAC == NULL) {
 209             appendToBuffer(buffer, bufsize, "\r\nERROR: getTopLevelObject failed", bufsize);
 210         } else {
 211             AccessibleContextInfo topInfo;
 212             if (GetAccessibleContextInfo(vmID, topAC, &topInfo) == FALSE) {
 213                 appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed for top-level window ", bufsize);
 214             } else {
 215                 if (getVirtualAccessibleName(vmID, topAC, name, sizeof(name)) == FALSE) {
 216                     appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize);
 217                 } else {
 218                     appendToBuffer(buffer, bufsize, "\r\n    Top-level window name:  %ls", name);
 219                 }
 220                 appendToBuffer(buffer, bufsize, "\r\n    Top-level window role:  %ls", topInfo.role);
 221             }
 222             ReleaseJavaObject(vmID, topAC);
 223 
 224         }
 225 
 226         /* ===== AccessibleParent information ===== */
 227 
 228         AccessibleContext parentAC = GetAccessibleParentFromContext(vmID, ac);
 229         if (parentAC == NULL) {
 230             appendToBuffer(buffer, bufsize, "\r\n    No parent", bufsize);
 231         } else {
 232             AccessibleContextInfo parentInfo;
 233             if (GetAccessibleContextInfo(vmID, parentAC, &parentInfo) == FALSE) {
 234                 appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed for parent", bufsize);
 235             } else {
 236                 if (getVirtualAccessibleName(vmID, parentAC, name, sizeof(name)) == FALSE) {
 237                     appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize);
 238                 } else {
 239                     appendToBuffer(buffer, bufsize, "\r\n    Parent name:  %ls", name);
 240                 }
 241                 appendToBuffer(buffer, bufsize, "\r\n    Parent role:  %ls", parentInfo.role);
 242             }
 243             ReleaseJavaObject(vmID, parentAC);
 244         }
 245 
 246 
 247         /* ====== visible children ===== */
 248         int nChildren = getVisibleChildrenCount(vmID, ac);
 249         if (nChildren == -1) {
 250             appendToBuffer(buffer, bufsize, "\r\nERROR: GetVisibleChildrenCount failed", bufsize);
 251         } else {
 252             appendToBuffer(buffer, bufsize, "\r\n    Visible descendents count:  %d", nChildren);
 253         }
 254 
 255         if (nChildren > 0) {
 256             VisibleChildrenInfo visibleChildrenInfo;
 257             if (getVisibleChildren(vmID, ac, 0, &visibleChildrenInfo) == FALSE) {
 258                 appendToBuffer(buffer, bufsize, "\r\nERROR: GetVisibleChildren failed", bufsize);
 259             } else {
 260                 AccessibleContextInfo childACInfo;
 261                 for (int child = 0; child < visibleChildrenInfo.returnedChildrenCount; child++) {
 262                     AccessibleContext childAC = visibleChildrenInfo.children[child];
 263                     if (GetAccessibleContextInfo(vmID, childAC, &childACInfo) == TRUE) {
 264                         if (getVirtualAccessibleName(vmID, childAC, name, sizeof(name)) == FALSE) {
 265                             appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize);
 266                         } else {
 267                             appendToBuffer(buffer, bufsize, "\r\n    Descendent %d name:  %ls", child, name);
 268                         }
 269                         appendToBuffer(buffer, bufsize, "\r\n    Descendent %d role:  %ls", child, childACInfo.role);
 270                     }
 271                     ReleaseJavaObject(vmID, childAC);
 272                 }
 273             }
 274         }
 275 
 276         /* ===== AccessibleSelection ===== */
 277 
 278         if (info.accessibleSelection == TRUE) {
 279 
 280             int selCount;
 281             AccessibleContext selectedAC;
 282 
 283             appendToBuffer(buffer, bufsize, "\r\n\r\nAccessible Selection information:", bufsize);
 284 
 285             if ((selCount = GetAccessibleSelectionCountFromContext(vmID, ac)) != -1) {
 286                 appendToBuffer(buffer, bufsize, "\r\n    Selection count:  %d", selCount);
 287 
 288                 for (i = 0; i < selCount; i++) {
 289                     if ((selectedAC = GetAccessibleSelectionFromContext(vmID, ac, i)) == NULL) {
 290                         appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleSelectionFromContext failed forselection %d", i);
 291                     } else {
 292                         if (GetAccessibleContextInfo(vmID, selectedAC, &info) == FALSE) {
 293                             appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed for selection %d", i);
 294                         } else {
 295                             if (getVirtualAccessibleName(vmID, selectedAC, name, sizeof(name)) == FALSE) {
 296                                 appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize);
 297                             } else {
 298                                 appendToBuffer(buffer, bufsize, "\r\n    Selection %d name: %ls", i, name);
 299                             }
 300                             appendToBuffer(buffer, bufsize, "\r\n    Selection %d role: %ls", i, info.role);
 301                             appendToBuffer(buffer, bufsize, "\r\n    Index in parent of selection %d: %d", i, info.indexInParent);
 302                         }
 303                         ReleaseJavaObject(vmID, selectedAC);
 304                     }
 305                 }
 306             }
 307         }
 308 
 309         // ====== Accessible KeyBindings, Icons and Actions ======
 310 
 311         AccessibleKeyBindings keyBindings;
 312         if (getAccessibleKeyBindings(vmID, ac, &keyBindings) == TRUE &&
 313             keyBindings.keyBindingsCount > 0) {
 314 
 315             appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleKeyBinding info:", bufsize);
 316             appendToBuffer(buffer, bufsize, "\r\n    Number of key bindings:  %d", keyBindings.keyBindingsCount);
 317 
 318             for (j = 0; j < keyBindings.keyBindingsCount; j++) {
 319 
 320                 appendToBuffer(buffer, bufsize, "\r\n    Key binding %d character: %c", j, keyBindings.keyBindingInfo[j].character);
 321                 appendToBuffer(buffer, bufsize, "\r\n    Key binding %d modifiers: %d", j, keyBindings.keyBindingInfo[j].modifiers);
 322             }
 323         }
 324 
 325         AccessibleIcons icons;
 326         if (getAccessibleIcons(vmID, ac, &icons) == TRUE &&
 327             icons.iconsCount > 0) {
 328 
 329             appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleIcons info:", bufsize);
 330             appendToBuffer(buffer, bufsize, "\r\n    Number of icons:  %d", icons.iconsCount);
 331 
 332             for (j = 0; j < icons.iconsCount; j++) {
 333 
 334                 appendToBuffer(buffer, bufsize, "\r\n    Icon %d description: %ls", j, icons.iconInfo[j].description);
 335                 appendToBuffer(buffer, bufsize, "\r\n    Icon %d height: %d", j, icons.iconInfo[j].height);
 336                 appendToBuffer(buffer, bufsize, "\r\n    Icon %d width: %d", j, icons.iconInfo[j].width);
 337             }
 338         }
 339 
 340         AccessibleActions actions;
 341         if (getAccessibleActions(vmID, ac, &actions) == TRUE &&
 342             actions.actionsCount > 0) {
 343 
 344             appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleActions info:", bufsize);
 345             appendToBuffer(buffer, bufsize, "\r\n    Number of actions:  %d", actions.actionsCount);
 346 
 347             for (j = 0; j < actions.actionsCount; j++) {
 348 
 349                 appendToBuffer(buffer, bufsize, "\r\n    Action %d name: %ls", j, actions.actionInfo[j].name);
 350             }
 351         }
 352 
 353         /* ===== AccessibleRelationSet ===== */
 354 
 355         AccessibleRelationSetInfo relationSetInfo;
 356         if (getAccessibleRelationSet(vmID, ac, &relationSetInfo) == FALSE) {
 357             appendToBuffer(buffer, bufsize, "\r\nGetAccessibleRelationSet failed.", bufsize);
 358         } else {
 359             int i;
 360             AccessibleContextInfo relInfo;
 361 
 362             if (relationSetInfo.relationCount > 0) {
 363                 appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleRelationSet information:", bufsize);
 364                 appendToBuffer(buffer, bufsize, "\r\n    Number of relations:  %d", relationSetInfo.relationCount);
 365             }
 366             for (i = 0; i < relationSetInfo.relationCount; i++) {
 367                 AccessibleRelationInfo relationInfo = relationSetInfo.relations[i];
 368 
 369                 appendToBuffer(buffer, bufsize, "\r\n    Relation %d key:  %ls", i, relationInfo.key);
 370                 appendToBuffer(buffer, bufsize, "\r\n    Relation %d target count:  %d", i, relationInfo.targetCount);
 371                 for (j = 0; j < relationInfo.targetCount; j++) {
 372                     if (GetAccessibleContextInfo(vmID, (AccessibleContext)relationInfo.targets[j], &relInfo) == FALSE) {
 373                         appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed.", bufsize);
 374                     } else {
 375 
 376                         // Core AccessibleContext information for relation target
 377                         if (getVirtualAccessibleName(vmID, (AccessibleContext)relationInfo.targets[j], name,
 378                                                      sizeof(name)) == FALSE) {
 379                             appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize);
 380                         } else {
 381                             appendToBuffer(buffer, bufsize, "\r\n        Target %d name:  %ls", j, name);
 382                         }
 383                         appendToBuffer(buffer, bufsize, "\r\n        Target %d role:  %ls", j, relInfo.role);
 384                     }
 385                     ReleaseJavaObject(vmID, (Java_Object)relationInfo.targets[j]);
 386 
 387                 }
 388             }
 389         }
 390 
 391         /* ===== AccessibleValue ===== */
 392 
 393         if (info.accessibleInterfaces & cAccessibleValueInterface) {
 394 
 395             appendToBuffer(buffer, bufsize, "\r\n\r\nAccessible Value information:", bufsize);
 396 
 397             if (GetCurrentAccessibleValueFromContext(vmID, ac, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) {
 398                 appendToBuffer(buffer, bufsize, "\r\n    Current Value:  %ls", tmpBuf);
 399             }
 400             if (GetMaximumAccessibleValueFromContext(vmID, ac, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) {
 401                 appendToBuffer(buffer, bufsize, "\r\n    Maximum Value:  %ls", tmpBuf);
 402             }
 403             if (GetMinimumAccessibleValueFromContext(vmID, ac, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) {
 404                 appendToBuffer(buffer, bufsize, "\r\n    Minimum Value:  %ls", tmpBuf);
 405             }
 406         }
 407 
 408 
 409         /* ===== AccessibleTable ===== */
 410 
 411         AccessibleTableInfo tableInfo;
 412 
 413         if ((info.accessibleInterfaces & cAccessibleTableInterface) == cAccessibleTableInterface) {
 414             if (getAccessibleTableInfo(vmID, ac, &tableInfo) != TRUE) {
 415                 appendToBuffer(buffer, bufsize, "\r\nERROR: getAccessibleTableInfo failed", bufsize);
 416             } else {
 417                 appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleTable info:", bufsize);
 418 
 419                 int trow = getAccessibleTableRow(vmID, tableInfo.accessibleTable, 3);
 420                 appendToBuffer(buffer, bufsize, "\r\n    getAccessibleTableRow:  %d", trow);
 421 
 422                 int tcol = getAccessibleTableColumn(vmID, tableInfo.accessibleTable, 2);
 423                 appendToBuffer(buffer, bufsize, "\r\n    getAccessibleTableColumn:  %d", tcol);
 424 
 425                 int tindex = getAccessibleTableIndex(vmID, tableInfo.accessibleTable, 2, 3);
 426                 appendToBuffer(buffer, bufsize, "\r\n    getAccessibleTableIndex:  %d", tindex);
 427 
 428                 // Core info
 429                 appendToBuffer(buffer, bufsize, "\r\n    table row count:  %d", tableInfo.rowCount);
 430                 appendToBuffer(buffer, bufsize, "\r\n    table column count:  %d", tableInfo.columnCount);
 431 
 432                 AccessibleTableCellInfo tableCellInfo;
 433                 for (int i = 0; i < tableInfo.rowCount; i++) {
 434                     for (int j = 0; j < tableInfo.columnCount; j++) {
 435 
 436                         if (getAccessibleTableCellInfo(vmID, tableInfo.accessibleTable, i, j,
 437                                                        &tableCellInfo) == FALSE) {
 438 
 439                             appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleTableCellInfo failed.", bufsize);
 440                         } else {
 441 
 442                             appendToBuffer(buffer, bufsize, "\r\n\r\n    AccessibleTable cell[%d,%d] info:", i, j);
 443                             appendToBuffer(buffer, bufsize, "\r\n    Index: %ld", tableCellInfo.index);
 444                             appendToBuffer(buffer, bufsize, "\r\n    Row extent: %ld", tableCellInfo.rowExtent);
 445                             appendToBuffer(buffer, bufsize, "\r\n    Column extent: %ld", tableCellInfo.columnExtent);
 446                             appendToBuffer(buffer, bufsize, "\r\n    Is selected?: %ld", tableCellInfo.isSelected);
 447 
 448                             AccessibleContextInfo cellACInfo;
 449                             if (GetAccessibleContextInfo(vmID, tableCellInfo.accessibleContext, &cellACInfo) == FALSE) {
 450                                 appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed for table cell [%d,%d].",
 451                                          i, j);
 452                             } else {
 453                                 if (getVirtualAccessibleName(vmID, tableCellInfo.accessibleContext, name,
 454                                                              sizeof(name)) == FALSE) {
 455                                     appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize);
 456                                 } else {
 457                                     appendToBuffer(buffer, bufsize, "\r\n    Name:  %ls", name);
 458                                 }
 459                                 appendToBuffer(buffer, bufsize, "\r\n    Role:  %ls", cellACInfo.role);
 460                             }
 461                             ReleaseJavaObject(vmID, tableCellInfo.accessibleContext);
 462                         }
 463                     }
 464                 }
 465 
 466                 // Get the column headers
 467                 AccessibleTableInfo columnInfo;
 468                 if (getAccessibleTableColumnHeader(vmID, ac, &columnInfo) == FALSE) {
 469                     appendToBuffer(buffer, bufsize, "\r\nERROR: getAccessibleTableColumnHeader failed.", bufsize);
 470                 } else {
 471                     appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleTable column header info:", bufsize);
 472 
 473                     // Core info
 474                     appendToBuffer(buffer, bufsize, "\r\n    Column header row count:  %d", columnInfo.rowCount);
 475                     appendToBuffer(buffer, bufsize, "\r\n    Column header column count:  %d", columnInfo.columnCount);
 476 
 477                 }
 478 
 479                 // Get the selected rows
 480                 int numSelections = getAccessibleTableRowSelectionCount(vmID,
 481                                                                         tableInfo.accessibleTable);
 482                 appendToBuffer(buffer, bufsize, "\r\n\r\nRow selection count:  %d", numSelections);
 483                 jint *selections = new jint[numSelections];
 484 
 485                 if (getAccessibleTableRowSelections(vmID, tableInfo.accessibleTable,
 486                                                     numSelections, selections) == FALSE) {
 487                     appendToBuffer(buffer, bufsize, "\r\nERROR: getAccessibleTableRowSelections failed.",
 488                             bufsize);
 489                 } else {
 490                     appendToBuffer(buffer, bufsize, "  \r\n  Row selections: ");
 491                     for (int j = 0; j < numSelections; j++) {
 492                         appendToBuffer(buffer, bufsize, " %d", selections[j]);
 493                     }
 494                 }
 495 
 496                 // Get column header info
 497                 for (int i = 0; i < columnInfo.columnCount; i++) {
 498                     if (getAccessibleTableCellInfo(vmID, columnInfo.accessibleTable, 0, i,
 499                                                    &tableCellInfo) == FALSE) {
 500 
 501                         appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleTableCellInfo failed.", bufsize);
 502                     } else {
 503                         appendToBuffer(buffer, bufsize, "\r\n\r\nColumn header [0,%d] cell info.", i);
 504                         appendToBuffer(buffer, bufsize, "\r\n    Index: %ld", tableCellInfo.index);
 505                         appendToBuffer(buffer, bufsize, "\r\n    Row extent: %ld", tableCellInfo.rowExtent);
 506                         appendToBuffer(buffer, bufsize, "\r\n    Column extent: %ld", tableCellInfo.columnExtent);
 507                         appendToBuffer(buffer, bufsize, "\r\n    Is selected: %ld", tableCellInfo.isSelected);
 508 
 509                         AccessibleContextInfo cellACInfo;
 510                         if (GetAccessibleContextInfo(vmID, tableCellInfo.accessibleContext, &cellACInfo) == FALSE) {
 511                             appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed.", bufsize);
 512                         } else {
 513                             if (getVirtualAccessibleName(vmID, tableCellInfo.accessibleContext, name,
 514                                                          sizeof(name)) == FALSE) {
 515                                 appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize);
 516                             } else {
 517                                 appendToBuffer(buffer, bufsize, "\r\n    Name:  %ls", name);
 518                             }
 519                             appendToBuffer(buffer, bufsize, "\r\n    Role:  %ls", cellACInfo.role);
 520                         }
 521                         ReleaseJavaObject(vmID, tableCellInfo.accessibleContext);
 522                     }
 523                 }
 524             }
 525         }
 526 
 527         /* ===== AccessibleText ===== */
 528 
 529         if (info.accessibleText == TRUE && x >= 0 && y >= 0) {
 530 
 531             AccessibleTextInfo textInfo;
 532             AccessibleTextItemsInfo textItems;
 533             AccessibleTextSelectionInfo textSelection;
 534             AccessibleTextRectInfo rectInfo;
 535             AccessibleTextAttributesInfo attributeInfo;
 536 
 537             appendToBuffer(buffer, bufsize, "\r\n\r\nAccessible Text information:", bufsize);
 538 
 539             if (GetAccessibleTextInfo(vmID, ac, &textInfo, x, y) == TRUE) {
 540 
 541                 appendToBuffer(buffer, bufsize, "\r\n    Mouse point at text index:  %d", textInfo.indexAtPoint);
 542                 appendToBuffer(buffer, bufsize, "\r\n    Caret at text index:  %d", textInfo.caretIndex);
 543                 appendToBuffer(buffer, bufsize, "\r\n    Char count:  %d", textInfo.charCount);
 544             }
 545             if (GetAccessibleTextSelectionInfo(vmID, ac, &textSelection) == TRUE) {
 546 
 547                 appendToBuffer(buffer, bufsize, "\r\n    Selection start index:  %d", textSelection.selectionStartIndex);
 548                 appendToBuffer(buffer, bufsize, "\r\n    Selection end index:  %d", textSelection.selectionEndIndex);
 549                 appendToBuffer(buffer, bufsize, "\r\n    Selected text:  %ls", textSelection.selectedText);
 550             }
 551 
 552             /* ===== AccessibleText information at the mouse point ===== */
 553 
 554             appendToBuffer(buffer, bufsize, "\r\n\r\n    At mouse point index: %d", textInfo.indexAtPoint);
 555 
 556             if (GetAccessibleTextRect(vmID, ac, &rectInfo, textInfo.indexAtPoint) == TRUE) {
 557 
 558                 appendToBuffer(buffer, bufsize, "\r\n        Character bounding rectangle: [%d, %d, %d, %d]",
 559                          rectInfo.x, rectInfo.y, rectInfo.width, rectInfo.height);
 560             }
 561 
 562             if (GetAccessibleTextLineBounds(vmID, ac, textInfo.indexAtPoint, &start, &end) == TRUE) {
 563                 if (GetAccessibleTextRange(vmID, ac, start, end, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) {
 564 
 565                     appendToBuffer(buffer, bufsize, "\r\n        Line bounds: [%d, %d]", start, end);
 566                 }
 567             }
 568             if (GetAccessibleTextItems(vmID, ac, &textItems, textInfo.indexAtPoint) == TRUE) {
 569 
 570                 appendToBuffer(buffer, bufsize, "\r\n        Character:  %lc", textItems.letter);
 571                 appendToBuffer(buffer, bufsize, "\r\n        Word:  %ls", textItems.word);
 572                 appendToBuffer(buffer, bufsize, "\r\n        Sentence:  %ls", textItems.sentence);
 573             }
 574 
 575             /* ===== AccessibleText attributes ===== */
 576 
 577             if (GetAccessibleTextAttributes(vmID, ac,
 578                                             textInfo.indexAtPoint,
 579                                             &attributeInfo)) {
 580 
 581                 appendToBuffer(buffer, bufsize, "\r\n        Core attributes: %s",
 582                         attributeInfo.bold == TRUE ? "bold" : "not bold");
 583                 appendToBuffer(buffer, bufsize, ", %s",
 584                         attributeInfo.italic == TRUE ? "italic" : "not italic");
 585                 appendToBuffer(buffer, bufsize, ", %s",
 586                         attributeInfo.underline == TRUE ? "underline" : "not underline");
 587                 appendToBuffer(buffer, bufsize, ", %s",
 588                         attributeInfo.strikethrough == TRUE ? "strikethrough" : "not strikethrough");
 589                 appendToBuffer(buffer, bufsize, ",  %s",
 590                         attributeInfo.superscript == TRUE ? "superscript" : "not superscript");
 591                 appendToBuffer(buffer, bufsize, ", %s",
 592                         attributeInfo.subscript == TRUE ? "subscript" : "not subscript");
 593 
 594                 appendToBuffer(buffer, bufsize, "\r\n        Background color:  %ls", attributeInfo.backgroundColor);
 595                 appendToBuffer(buffer, bufsize, "\r\n        Foreground color:  %ls", attributeInfo.foregroundColor);
 596                 appendToBuffer(buffer, bufsize, "\r\n        Font family:  %ls", attributeInfo.fontFamily);
 597                 appendToBuffer(buffer, bufsize,  "\r\n        Font size:  %d", attributeInfo.fontSize);
 598 
 599                 appendToBuffer(buffer, bufsize,  "\r\n        First line indent:  %f", attributeInfo.firstLineIndent);
 600                 appendToBuffer(buffer, bufsize,  "\r\n        Left indent:  %f", attributeInfo.leftIndent);
 601                 appendToBuffer(buffer, bufsize,  "\r\n        Right indent:  %f", attributeInfo.rightIndent);
 602                 appendToBuffer(buffer, bufsize,  "\r\n        Line spacing:  %f", attributeInfo.lineSpacing);
 603                 appendToBuffer(buffer, bufsize,  "\r\n        Space above:  %f", attributeInfo.spaceAbove);
 604                 appendToBuffer(buffer, bufsize,  "\r\n        Space below:  %f", attributeInfo.spaceBelow);
 605 
 606                 appendToBuffer(buffer, bufsize, "\r\n        Full attribute string:  %ls", attributeInfo.fullAttributesString);
 607 
 608                 // get the attribute run length
 609                 short runLength = -1;
 610                 if (getTextAttributesInRange(vmID, ac, textInfo.indexAtPoint, textInfo.indexAtPoint + 100,
 611                                              &attributeInfo, &runLength)) {
 612                     appendToBuffer(buffer, bufsize, "\r\n        Attribute run:  %d", runLength);
 613                 } else {
 614                     appendToBuffer(buffer, bufsize, "\r\n        getTextAttributesInRangeFailed");
 615                 }
 616             }
 617 
 618             /* ===== AccessibleText information at the caret index ===== */
 619 
 620             appendToBuffer(buffer, bufsize, "\r\n\r\n    At caret index: %d", textInfo.caretIndex);
 621 
 622             if (getCaretLocation(vmID, ac, &rectInfo, textInfo.caretIndex) == TRUE) {
 623 
 624                 appendToBuffer(buffer, bufsize, "\r\n        Caret bounding rectangle: [%d, %d, %d, %d]",
 625                          rectInfo.x, rectInfo.y, rectInfo.width, rectInfo.height);
 626             }
 627 
 628             if (GetAccessibleTextRect(vmID, ac, &rectInfo, textInfo.caretIndex) == TRUE) {
 629 
 630                 appendToBuffer(buffer, bufsize, "\r\n        Character bounding rectangle: [%d, %d, %d, %d]",
 631                          rectInfo.x, rectInfo.y, rectInfo.width, rectInfo.height);
 632             }
 633 
 634             if (GetAccessibleTextLineBounds(vmID, ac, textInfo.caretIndex, &start, &end) == TRUE) {
 635                 if (GetAccessibleTextRange(vmID, ac, start, end, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) {
 636 
 637                     appendToBuffer(buffer, bufsize, "\r\n        Line bounds: [%d, %d]", start, end);
 638                 }
 639             }
 640             if (GetAccessibleTextItems(vmID, ac, &textItems, textInfo.caretIndex) == TRUE) {
 641 
 642                 appendToBuffer(buffer, bufsize, "\r\n        Character:  %lc", textItems.letter);
 643                 appendToBuffer(buffer, bufsize, "\r\n        Word:  %ls", textItems.word);
 644                 appendToBuffer(buffer, bufsize, "\r\n        Sentence:  %ls", textItems.sentence);
 645             }
 646 
 647             /* ===== AccessibleText attributes ===== */
 648 
 649             if (GetAccessibleTextAttributes(vmID, ac, textInfo.caretIndex, &attributeInfo)) {
 650 
 651                 appendToBuffer(buffer, bufsize, "\r\n        Core attributes: %s",
 652                         attributeInfo.bold == TRUE ? "bold" : "not bold");
 653                 appendToBuffer(buffer, bufsize, ", %s",
 654                         attributeInfo.italic == TRUE ? "italic" : "not italic");
 655                 appendToBuffer(buffer, bufsize, ", %s",
 656                         attributeInfo.underline == TRUE ? "underline" : "not underline");
 657                 appendToBuffer(buffer, bufsize, ", %s",
 658                         attributeInfo.strikethrough == TRUE ? "strikethrough" : "not strikethrough");
 659                 appendToBuffer(buffer, bufsize, ",  %s",
 660                         attributeInfo.superscript == TRUE ? "superscript" : "not superscript");
 661                 appendToBuffer(buffer, bufsize, ", %s",
 662                         attributeInfo.subscript == TRUE ? "subscript" : "not subscript");
 663 
 664                 appendToBuffer(buffer, bufsize, "\r\n        Background color:  %ls", attributeInfo.backgroundColor);
 665                 appendToBuffer(buffer, bufsize, "\r\n        Foreground color:  %ls", attributeInfo.foregroundColor);
 666                 appendToBuffer(buffer, bufsize, "\r\n        Font family:  %ls", attributeInfo.fontFamily);
 667                 appendToBuffer(buffer, bufsize,  "\r\n        Font size:  %d", attributeInfo.fontSize);
 668 
 669 
 670                 appendToBuffer(buffer, bufsize,  "\r\n        First line indent:  %f", attributeInfo.firstLineIndent);
 671                 appendToBuffer(buffer, bufsize,  "\r\n        Left indent:  %f", attributeInfo.leftIndent);
 672                 appendToBuffer(buffer, bufsize,  "\r\n        Right indent:  %f", attributeInfo.rightIndent);
 673                 appendToBuffer(buffer, bufsize,  "\r\n        Line spacing:  %f", attributeInfo.lineSpacing);
 674                 appendToBuffer(buffer, bufsize,  "\r\n        Space above:  %f", attributeInfo.spaceAbove);
 675                 appendToBuffer(buffer, bufsize,  "\r\n        Space below:  %f", attributeInfo.spaceBelow);
 676 
 677                 appendToBuffer(buffer, bufsize, "\r\n        Full attribute string:  %ls", attributeInfo.fullAttributesString);
 678                 // get the attribute run length
 679                 short runLength = -1;
 680                 if (getTextAttributesInRange(vmID, ac, textInfo.caretIndex, textInfo.caretIndex + 100,
 681                                              &attributeInfo, &runLength)) {
 682                     appendToBuffer(buffer, bufsize, "\r\n        Attribute run:  %d", runLength);
 683                 } else {
 684                     appendToBuffer(buffer, bufsize, "\r\n        getTextAttributesInRangeFailed");
 685                 }
 686             }
 687         }
 688     }
 689     return buffer;
 690 }