--- /dev/null 2015-03-20 22:55:49.000000000 -0500 +++ new/jdk/src/jdk.accessibility/windows/native/libaccessbridge/AccessInfo.cpp 2015-03-20 22:55:48.912090000 -0500 @@ -0,0 +1,690 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "AccessBridgeCalls.h" +#include "AccessInfo.h" +#include +#include + +/* + * returns formatted date and time + */ +char *getTimeAndDate() { + static char datebuf[64]; + struct tm *newtime; + char am_pm[] = "AM"; + time_t long_time; + + time( &long_time ); /* Get time as long integer. */ + newtime = localtime( &long_time ); /* Convert to local time. */ + + if( newtime->tm_hour > 12 ) /* Set up extension. */ + strcpy( am_pm, "PM" ); + if( newtime->tm_hour > 12 ) /* Convert from 24-hour */ + newtime->tm_hour -= 12; /* to 12-hour clock. */ + if( newtime->tm_hour == 0 ) /*Set hour to 12 if midnight. */ + newtime->tm_hour = 12; + + sprintf(datebuf, "%.19s %s\n", asctime( newtime ), am_pm ); + return (char *)datebuf; +} + + +/* + * displays a message in a dialog and writes the message to a logfile + */ +void displayAndLog(HWND hDlg, int nIDDlgItem, FILE *logfile, char *msg, ...) { + + if (hDlg == NULL || msg == NULL) { + return; + } + + char tmpbuf[HUGE_BUFSIZE]; + va_list argprt; + + va_start(argprt, msg); + vsprintf(tmpbuf, msg, argprt); + + SetDlgItemText(hDlg, nIDDlgItem, tmpbuf); + + fprintf(logfile, "\n****************************************\n"); + fprintf(logfile, "%s\n", getTimeAndDate()); + fprintf(logfile, "%s\n", tmpbuf); + fflush(logfile); +} + +/* + * writes a text string to a logfile + */ +void logString(FILE *logfile, char *msg, ...) { + + if (logfile == NULL || msg == NULL) { + return; + } + + char tmpbuf[LINE_BUFSIZE]; + va_list argprt; + + va_start(argprt, msg); + vsprintf(tmpbuf, msg, argprt); + + fprintf(logfile, tmpbuf); + fprintf(logfile, "\n"); + fflush(logfile); +} + +/* + * safely appends a message to a buffer + */ +BOOL appendToBuffer(char *buf, size_t buflen, char *msg, ...) { + + static char warning[] = + "\nNot enough buffer space; remaining information truncated.\n"; + int warningLength = (int)strlen(warning) + 1; + + if (buf == NULL || msg == NULL) { + return FALSE; + } + + char tmpbuf[LARGE_BUFSIZE]; + va_list argprt; + + va_start(argprt, msg); + vsprintf(tmpbuf, msg, argprt); + + // verify there's enough space in the buffer + int spaceRemaining = buflen - (int)strlen(buf) - 1; + if (spaceRemaining <= warningLength) { + strncat(buf, warning, spaceRemaining); + return FALSE; + } + strncat(buf, tmpbuf, spaceRemaining); + return TRUE; +} + +/** + * returns accessibility information for an AccessibleContext + */ +char *getAccessibleInfo(long vmID, AccessibleContext ac, char *buffer, + int bufsize) { + return getAccessibleInfo(vmID, ac, 0, 0, buffer, bufsize); +} + +/** + * returns accessibility information at the specified coordinates in an + * AccessibleContext + */ +char *getAccessibleInfo(long vmID, AccessibleContext ac, int x, int y, + char *buffer, int bufsize) { + + wchar_t tmpBuf[LINE_BUFSIZE]; + wchar_t name[LINE_BUFSIZE]; + int i, j; + long start; + long end; + + if (buffer == NULL || bufsize <= 0) { + return NULL; + } + buffer[0] = NULL; + + /* ===== AccessBridge / J2SE version information ===== */ + + AccessBridgeVersionInfo versionInfo; + BOOL result = GetVersionInfo(vmID, &versionInfo); + + if (result == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: cannot get version information", bufsize); + } else { + appendToBuffer(buffer, bufsize, "Version Information:"); + appendToBuffer(buffer, bufsize, "\r\n Java virtual machine version: %ls", + versionInfo.VMversion); + appendToBuffer(buffer, bufsize, "\r\n Access Bridge Java class version: %ls", + versionInfo.bridgeJavaClassVersion); + appendToBuffer(buffer, bufsize, "\r\n Access Bridge Java DLL version: %ls", + versionInfo.bridgeJavaDLLVersion); + appendToBuffer(buffer, bufsize, "\r\n Access Bridge Windows DLL version: %ls", + versionInfo.bridgeWinDLLVersion); + } + + if (ac == (AccessibleContext) 0) { + return buffer; + } + + + /* ===== core AccessibleContext information ===== */ + + AccessibleContextInfo info; + if (GetAccessibleContextInfo(vmID, ac, &info) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed ", bufsize); + } else { + + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleContext information", bufsize); + if (x >= 0 && y >= 0) { + appendToBuffer(buffer, bufsize, " at mouse point [%d, %d]:", x, y); + } else { + appendToBuffer(buffer, bufsize, ":", bufsize); + } + + if (getVirtualAccessibleName(vmID, ac, name, sizeof(name)) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n Name: %ls", name); + } + appendToBuffer(buffer, bufsize, "\r\n Description: %ls", info.description); + appendToBuffer(buffer, bufsize, "\r\n Role: %ls", info.role); + appendToBuffer(buffer, bufsize, "\r\n Role in en_US locale: %ls", info.role_en_US); + appendToBuffer(buffer, bufsize, "\r\n States: %ls", info.states); + appendToBuffer(buffer, bufsize, "\r\n States in en_US locale: %ls", info.states_en_US); + appendToBuffer(buffer, bufsize, "\r\n Index in parent: %d", info.indexInParent); + appendToBuffer(buffer, bufsize, "\r\n Children count: %d", info.childrenCount); + appendToBuffer(buffer, bufsize, "\r\n Bounding rectangle: [%d, %d, %d, %d]", + info.x, info.y, info.x + info.width, info.y + info.height); + + /* top-level window info */ + AccessibleContext topAC = getTopLevelObject(vmID, ac); + if (topAC == NULL) { + appendToBuffer(buffer, bufsize, "\r\nERROR: getTopLevelObject failed", bufsize); + } else { + AccessibleContextInfo topInfo; + if (GetAccessibleContextInfo(vmID, topAC, &topInfo) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed for top-level window ", bufsize); + } else { + if (getVirtualAccessibleName(vmID, topAC, name, sizeof(name)) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n Top-level window name: %ls", name); + } + appendToBuffer(buffer, bufsize, "\r\n Top-level window role: %ls", topInfo.role); + } + ReleaseJavaObject(vmID, topAC); + + } + + /* ===== AccessibleParent information ===== */ + + AccessibleContext parentAC = GetAccessibleParentFromContext(vmID, ac); + if (parentAC == NULL) { + appendToBuffer(buffer, bufsize, "\r\n No parent", bufsize); + } else { + AccessibleContextInfo parentInfo; + if (GetAccessibleContextInfo(vmID, parentAC, &parentInfo) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed for parent", bufsize); + } else { + if (getVirtualAccessibleName(vmID, parentAC, name, sizeof(name)) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n Parent name: %ls", name); + } + appendToBuffer(buffer, bufsize, "\r\n Parent role: %ls", parentInfo.role); + } + ReleaseJavaObject(vmID, parentAC); + } + + + /* ====== visible children ===== */ + int nChildren = getVisibleChildrenCount(vmID, ac); + if (nChildren == -1) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetVisibleChildrenCount failed", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n Visible descendents count: %d", nChildren); + } + + if (nChildren > 0) { + VisibleChildrenInfo visibleChildrenInfo; + if (getVisibleChildren(vmID, ac, 0, &visibleChildrenInfo) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetVisibleChildren failed", bufsize); + } else { + AccessibleContextInfo childACInfo; + for (int child = 0; child < visibleChildrenInfo.returnedChildrenCount; child++) { + AccessibleContext childAC = visibleChildrenInfo.children[child]; + if (GetAccessibleContextInfo(vmID, childAC, &childACInfo) == TRUE) { + if (getVirtualAccessibleName(vmID, childAC, name, sizeof(name)) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n Descendent %d name: %ls", child, name); + } + appendToBuffer(buffer, bufsize, "\r\n Descendent %d role: %ls", child, childACInfo.role); + } + ReleaseJavaObject(vmID, childAC); + } + } + } + + /* ===== AccessibleSelection ===== */ + + if (info.accessibleSelection == TRUE) { + + int selCount; + AccessibleContext selectedAC; + + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessible Selection information:", bufsize); + + if ((selCount = GetAccessibleSelectionCountFromContext(vmID, ac)) != -1) { + appendToBuffer(buffer, bufsize, "\r\n Selection count: %d", selCount); + + for (i = 0; i < selCount; i++) { + if ((selectedAC = GetAccessibleSelectionFromContext(vmID, ac, i)) == NULL) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleSelectionFromContext failed forselection %d", i); + } else { + if (GetAccessibleContextInfo(vmID, selectedAC, &info) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed for selection %d", i); + } else { + if (getVirtualAccessibleName(vmID, selectedAC, name, sizeof(name)) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n Selection %d name: %ls", i, name); + } + appendToBuffer(buffer, bufsize, "\r\n Selection %d role: %ls", i, info.role); + appendToBuffer(buffer, bufsize, "\r\n Index in parent of selection %d: %d", i, info.indexInParent); + } + ReleaseJavaObject(vmID, selectedAC); + } + } + } + } + + // ====== Accessible KeyBindings, Icons and Actions ====== + + AccessibleKeyBindings keyBindings; + if (getAccessibleKeyBindings(vmID, ac, &keyBindings) == TRUE && + keyBindings.keyBindingsCount > 0) { + + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleKeyBinding info:", bufsize); + appendToBuffer(buffer, bufsize, "\r\n Number of key bindings: %d", keyBindings.keyBindingsCount); + + for (j = 0; j < keyBindings.keyBindingsCount; j++) { + + appendToBuffer(buffer, bufsize, "\r\n Key binding %d character: %c", j, keyBindings.keyBindingInfo[j].character); + appendToBuffer(buffer, bufsize, "\r\n Key binding %d modifiers: %d", j, keyBindings.keyBindingInfo[j].modifiers); + } + } + + AccessibleIcons icons; + if (getAccessibleIcons(vmID, ac, &icons) == TRUE && + icons.iconsCount > 0) { + + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleIcons info:", bufsize); + appendToBuffer(buffer, bufsize, "\r\n Number of icons: %d", icons.iconsCount); + + for (j = 0; j < icons.iconsCount; j++) { + + appendToBuffer(buffer, bufsize, "\r\n Icon %d description: %ls", j, icons.iconInfo[j].description); + appendToBuffer(buffer, bufsize, "\r\n Icon %d height: %d", j, icons.iconInfo[j].height); + appendToBuffer(buffer, bufsize, "\r\n Icon %d width: %d", j, icons.iconInfo[j].width); + } + } + + AccessibleActions actions; + if (getAccessibleActions(vmID, ac, &actions) == TRUE && + actions.actionsCount > 0) { + + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleActions info:", bufsize); + appendToBuffer(buffer, bufsize, "\r\n Number of actions: %d", actions.actionsCount); + + for (j = 0; j < actions.actionsCount; j++) { + + appendToBuffer(buffer, bufsize, "\r\n Action %d name: %ls", j, actions.actionInfo[j].name); + } + } + + /* ===== AccessibleRelationSet ===== */ + + AccessibleRelationSetInfo relationSetInfo; + if (getAccessibleRelationSet(vmID, ac, &relationSetInfo) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nGetAccessibleRelationSet failed.", bufsize); + } else { + int i; + AccessibleContextInfo relInfo; + + if (relationSetInfo.relationCount > 0) { + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleRelationSet information:", bufsize); + appendToBuffer(buffer, bufsize, "\r\n Number of relations: %d", relationSetInfo.relationCount); + } + for (i = 0; i < relationSetInfo.relationCount; i++) { + AccessibleRelationInfo relationInfo = relationSetInfo.relations[i]; + + appendToBuffer(buffer, bufsize, "\r\n Relation %d key: %ls", i, relationInfo.key); + appendToBuffer(buffer, bufsize, "\r\n Relation %d target count: %d", i, relationInfo.targetCount); + for (j = 0; j < relationInfo.targetCount; j++) { + if (GetAccessibleContextInfo(vmID, (AccessibleContext)relationInfo.targets[j], &relInfo) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed.", bufsize); + } else { + + // Core AccessibleContext information for relation target + if (getVirtualAccessibleName(vmID, (AccessibleContext)relationInfo.targets[j], name, + sizeof(name)) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n Target %d name: %ls", j, name); + } + appendToBuffer(buffer, bufsize, "\r\n Target %d role: %ls", j, relInfo.role); + } + ReleaseJavaObject(vmID, (Java_Object)relationInfo.targets[j]); + + } + } + } + + /* ===== AccessibleValue ===== */ + + if (info.accessibleInterfaces & cAccessibleValueInterface) { + + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessible Value information:", bufsize); + + if (GetCurrentAccessibleValueFromContext(vmID, ac, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) { + appendToBuffer(buffer, bufsize, "\r\n Current Value: %ls", tmpBuf); + } + if (GetMaximumAccessibleValueFromContext(vmID, ac, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) { + appendToBuffer(buffer, bufsize, "\r\n Maximum Value: %ls", tmpBuf); + } + if (GetMinimumAccessibleValueFromContext(vmID, ac, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) { + appendToBuffer(buffer, bufsize, "\r\n Minimum Value: %ls", tmpBuf); + } + } + + + /* ===== AccessibleTable ===== */ + + AccessibleTableInfo tableInfo; + + if ((info.accessibleInterfaces & cAccessibleTableInterface) == cAccessibleTableInterface) { + if (getAccessibleTableInfo(vmID, ac, &tableInfo) != TRUE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: getAccessibleTableInfo failed", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleTable info:", bufsize); + + int trow = getAccessibleTableRow(vmID, tableInfo.accessibleTable, 3); + appendToBuffer(buffer, bufsize, "\r\n getAccessibleTableRow: %d", trow); + + int tcol = getAccessibleTableColumn(vmID, tableInfo.accessibleTable, 2); + appendToBuffer(buffer, bufsize, "\r\n getAccessibleTableColumn: %d", tcol); + + int tindex = getAccessibleTableIndex(vmID, tableInfo.accessibleTable, 2, 3); + appendToBuffer(buffer, bufsize, "\r\n getAccessibleTableIndex: %d", tindex); + + // Core info + appendToBuffer(buffer, bufsize, "\r\n table row count: %d", tableInfo.rowCount); + appendToBuffer(buffer, bufsize, "\r\n table column count: %d", tableInfo.columnCount); + + AccessibleTableCellInfo tableCellInfo; + for (int i = 0; i < tableInfo.rowCount; i++) { + for (int j = 0; j < tableInfo.columnCount; j++) { + + if (getAccessibleTableCellInfo(vmID, tableInfo.accessibleTable, i, j, + &tableCellInfo) == FALSE) { + + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleTableCellInfo failed.", bufsize); + } else { + + appendToBuffer(buffer, bufsize, "\r\n\r\n AccessibleTable cell[%d,%d] info:", i, j); + appendToBuffer(buffer, bufsize, "\r\n Index: %ld", tableCellInfo.index); + appendToBuffer(buffer, bufsize, "\r\n Row extent: %ld", tableCellInfo.rowExtent); + appendToBuffer(buffer, bufsize, "\r\n Column extent: %ld", tableCellInfo.columnExtent); + appendToBuffer(buffer, bufsize, "\r\n Is selected?: %ld", tableCellInfo.isSelected); + + AccessibleContextInfo cellACInfo; + if (GetAccessibleContextInfo(vmID, tableCellInfo.accessibleContext, &cellACInfo) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed for table cell [%d,%d].", + i, j); + } else { + if (getVirtualAccessibleName(vmID, tableCellInfo.accessibleContext, name, + sizeof(name)) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n Name: %ls", name); + } + appendToBuffer(buffer, bufsize, "\r\n Role: %ls", cellACInfo.role); + } + ReleaseJavaObject(vmID, tableCellInfo.accessibleContext); + } + } + } + + // Get the column headers + AccessibleTableInfo columnInfo; + if (getAccessibleTableColumnHeader(vmID, ac, &columnInfo) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: getAccessibleTableColumnHeader failed.", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessibleTable column header info:", bufsize); + + // Core info + appendToBuffer(buffer, bufsize, "\r\n Column header row count: %d", columnInfo.rowCount); + appendToBuffer(buffer, bufsize, "\r\n Column header column count: %d", columnInfo.columnCount); + + } + + // Get the selected rows + int numSelections = getAccessibleTableRowSelectionCount(vmID, + tableInfo.accessibleTable); + appendToBuffer(buffer, bufsize, "\r\n\r\nRow selection count: %d", numSelections); + jint *selections = new jint[numSelections]; + + if (getAccessibleTableRowSelections(vmID, tableInfo.accessibleTable, + numSelections, selections) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: getAccessibleTableRowSelections failed.", + bufsize); + } else { + appendToBuffer(buffer, bufsize, " \r\n Row selections: "); + for (int j = 0; j < numSelections; j++) { + appendToBuffer(buffer, bufsize, " %d", selections[j]); + } + } + + // Get column header info + for (int i = 0; i < columnInfo.columnCount; i++) { + if (getAccessibleTableCellInfo(vmID, columnInfo.accessibleTable, 0, i, + &tableCellInfo) == FALSE) { + + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleTableCellInfo failed.", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n\r\nColumn header [0,%d] cell info.", i); + appendToBuffer(buffer, bufsize, "\r\n Index: %ld", tableCellInfo.index); + appendToBuffer(buffer, bufsize, "\r\n Row extent: %ld", tableCellInfo.rowExtent); + appendToBuffer(buffer, bufsize, "\r\n Column extent: %ld", tableCellInfo.columnExtent); + appendToBuffer(buffer, bufsize, "\r\n Is selected: %ld", tableCellInfo.isSelected); + + AccessibleContextInfo cellACInfo; + if (GetAccessibleContextInfo(vmID, tableCellInfo.accessibleContext, &cellACInfo) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\nERROR: GetAccessibleContextInfo failed.", bufsize); + } else { + if (getVirtualAccessibleName(vmID, tableCellInfo.accessibleContext, name, + sizeof(name)) == FALSE) { + appendToBuffer(buffer, bufsize, "\r\n\r\nERROR: getVirtualAccessibleName", bufsize); + } else { + appendToBuffer(buffer, bufsize, "\r\n Name: %ls", name); + } + appendToBuffer(buffer, bufsize, "\r\n Role: %ls", cellACInfo.role); + } + ReleaseJavaObject(vmID, tableCellInfo.accessibleContext); + } + } + } + } + + /* ===== AccessibleText ===== */ + + if (info.accessibleText == TRUE && x >= 0 && y >= 0) { + + AccessibleTextInfo textInfo; + AccessibleTextItemsInfo textItems; + AccessibleTextSelectionInfo textSelection; + AccessibleTextRectInfo rectInfo; + AccessibleTextAttributesInfo attributeInfo; + + appendToBuffer(buffer, bufsize, "\r\n\r\nAccessible Text information:", bufsize); + + if (GetAccessibleTextInfo(vmID, ac, &textInfo, x, y) == TRUE) { + + appendToBuffer(buffer, bufsize, "\r\n Mouse point at text index: %d", textInfo.indexAtPoint); + appendToBuffer(buffer, bufsize, "\r\n Caret at text index: %d", textInfo.caretIndex); + appendToBuffer(buffer, bufsize, "\r\n Char count: %d", textInfo.charCount); + } + if (GetAccessibleTextSelectionInfo(vmID, ac, &textSelection) == TRUE) { + + appendToBuffer(buffer, bufsize, "\r\n Selection start index: %d", textSelection.selectionStartIndex); + appendToBuffer(buffer, bufsize, "\r\n Selection end index: %d", textSelection.selectionEndIndex); + appendToBuffer(buffer, bufsize, "\r\n Selected text: %ls", textSelection.selectedText); + } + + /* ===== AccessibleText information at the mouse point ===== */ + + appendToBuffer(buffer, bufsize, "\r\n\r\n At mouse point index: %d", textInfo.indexAtPoint); + + if (GetAccessibleTextRect(vmID, ac, &rectInfo, textInfo.indexAtPoint) == TRUE) { + + appendToBuffer(buffer, bufsize, "\r\n Character bounding rectangle: [%d, %d, %d, %d]", + rectInfo.x, rectInfo.y, rectInfo.width, rectInfo.height); + } + + if (GetAccessibleTextLineBounds(vmID, ac, textInfo.indexAtPoint, &start, &end) == TRUE) { + if (GetAccessibleTextRange(vmID, ac, start, end, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) { + + appendToBuffer(buffer, bufsize, "\r\n Line bounds: [%d, %d]", start, end); + } + } + if (GetAccessibleTextItems(vmID, ac, &textItems, textInfo.indexAtPoint) == TRUE) { + + appendToBuffer(buffer, bufsize, "\r\n Character: %lc", textItems.letter); + appendToBuffer(buffer, bufsize, "\r\n Word: %ls", textItems.word); + appendToBuffer(buffer, bufsize, "\r\n Sentence: %ls", textItems.sentence); + } + + /* ===== AccessibleText attributes ===== */ + + if (GetAccessibleTextAttributes(vmID, ac, + textInfo.indexAtPoint, + &attributeInfo)) { + + appendToBuffer(buffer, bufsize, "\r\n Core attributes: %s", + attributeInfo.bold == TRUE ? "bold" : "not bold"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.italic == TRUE ? "italic" : "not italic"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.underline == TRUE ? "underline" : "not underline"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.strikethrough == TRUE ? "strikethrough" : "not strikethrough"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.superscript == TRUE ? "superscript" : "not superscript"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.subscript == TRUE ? "subscript" : "not subscript"); + + appendToBuffer(buffer, bufsize, "\r\n Background color: %ls", attributeInfo.backgroundColor); + appendToBuffer(buffer, bufsize, "\r\n Foreground color: %ls", attributeInfo.foregroundColor); + appendToBuffer(buffer, bufsize, "\r\n Font family: %ls", attributeInfo.fontFamily); + appendToBuffer(buffer, bufsize, "\r\n Font size: %d", attributeInfo.fontSize); + + appendToBuffer(buffer, bufsize, "\r\n First line indent: %f", attributeInfo.firstLineIndent); + appendToBuffer(buffer, bufsize, "\r\n Left indent: %f", attributeInfo.leftIndent); + appendToBuffer(buffer, bufsize, "\r\n Right indent: %f", attributeInfo.rightIndent); + appendToBuffer(buffer, bufsize, "\r\n Line spacing: %f", attributeInfo.lineSpacing); + appendToBuffer(buffer, bufsize, "\r\n Space above: %f", attributeInfo.spaceAbove); + appendToBuffer(buffer, bufsize, "\r\n Space below: %f", attributeInfo.spaceBelow); + + appendToBuffer(buffer, bufsize, "\r\n Full attribute string: %ls", attributeInfo.fullAttributesString); + + // get the attribute run length + short runLength = -1; + if (getTextAttributesInRange(vmID, ac, textInfo.indexAtPoint, textInfo.indexAtPoint + 100, + &attributeInfo, &runLength)) { + appendToBuffer(buffer, bufsize, "\r\n Attribute run: %d", runLength); + } else { + appendToBuffer(buffer, bufsize, "\r\n getTextAttributesInRangeFailed"); + } + } + + /* ===== AccessibleText information at the caret index ===== */ + + appendToBuffer(buffer, bufsize, "\r\n\r\n At caret index: %d", textInfo.caretIndex); + + if (getCaretLocation(vmID, ac, &rectInfo, textInfo.caretIndex) == TRUE) { + + appendToBuffer(buffer, bufsize, "\r\n Caret bounding rectangle: [%d, %d, %d, %d]", + rectInfo.x, rectInfo.y, rectInfo.width, rectInfo.height); + } + + if (GetAccessibleTextRect(vmID, ac, &rectInfo, textInfo.caretIndex) == TRUE) { + + appendToBuffer(buffer, bufsize, "\r\n Character bounding rectangle: [%d, %d, %d, %d]", + rectInfo.x, rectInfo.y, rectInfo.width, rectInfo.height); + } + + if (GetAccessibleTextLineBounds(vmID, ac, textInfo.caretIndex, &start, &end) == TRUE) { + if (GetAccessibleTextRange(vmID, ac, start, end, tmpBuf, (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE) { + + appendToBuffer(buffer, bufsize, "\r\n Line bounds: [%d, %d]", start, end); + } + } + if (GetAccessibleTextItems(vmID, ac, &textItems, textInfo.caretIndex) == TRUE) { + + appendToBuffer(buffer, bufsize, "\r\n Character: %lc", textItems.letter); + appendToBuffer(buffer, bufsize, "\r\n Word: %ls", textItems.word); + appendToBuffer(buffer, bufsize, "\r\n Sentence: %ls", textItems.sentence); + } + + /* ===== AccessibleText attributes ===== */ + + if (GetAccessibleTextAttributes(vmID, ac, textInfo.caretIndex, &attributeInfo)) { + + appendToBuffer(buffer, bufsize, "\r\n Core attributes: %s", + attributeInfo.bold == TRUE ? "bold" : "not bold"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.italic == TRUE ? "italic" : "not italic"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.underline == TRUE ? "underline" : "not underline"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.strikethrough == TRUE ? "strikethrough" : "not strikethrough"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.superscript == TRUE ? "superscript" : "not superscript"); + appendToBuffer(buffer, bufsize, ", %s", + attributeInfo.subscript == TRUE ? "subscript" : "not subscript"); + + appendToBuffer(buffer, bufsize, "\r\n Background color: %ls", attributeInfo.backgroundColor); + appendToBuffer(buffer, bufsize, "\r\n Foreground color: %ls", attributeInfo.foregroundColor); + appendToBuffer(buffer, bufsize, "\r\n Font family: %ls", attributeInfo.fontFamily); + appendToBuffer(buffer, bufsize, "\r\n Font size: %d", attributeInfo.fontSize); + + + appendToBuffer(buffer, bufsize, "\r\n First line indent: %f", attributeInfo.firstLineIndent); + appendToBuffer(buffer, bufsize, "\r\n Left indent: %f", attributeInfo.leftIndent); + appendToBuffer(buffer, bufsize, "\r\n Right indent: %f", attributeInfo.rightIndent); + appendToBuffer(buffer, bufsize, "\r\n Line spacing: %f", attributeInfo.lineSpacing); + appendToBuffer(buffer, bufsize, "\r\n Space above: %f", attributeInfo.spaceAbove); + appendToBuffer(buffer, bufsize, "\r\n Space below: %f", attributeInfo.spaceBelow); + + appendToBuffer(buffer, bufsize, "\r\n Full attribute string: %ls", attributeInfo.fullAttributesString); + // get the attribute run length + short runLength = -1; + if (getTextAttributesInRange(vmID, ac, textInfo.caretIndex, textInfo.caretIndex + 100, + &attributeInfo, &runLength)) { + appendToBuffer(buffer, bufsize, "\r\n Attribute run: %d", runLength); + } else { + appendToBuffer(buffer, bufsize, "\r\n getTextAttributesInRangeFailed"); + } + } + } + } + return buffer; +}