summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows/accessible
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/windows/accessible')
-rw-r--r--src/plugins/platforms/windows/accessible/accessible.pri19
-rw-r--r--src/plugins/platforms/windows/accessible/comutils.cpp641
-rw-r--r--src/plugins/platforms/windows/accessible/comutils.h61
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.cpp1467
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.h379
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp319
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.h74
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp1213
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h139
9 files changed, 4312 insertions, 0 deletions
diff --git a/src/plugins/platforms/windows/accessible/accessible.pri b/src/plugins/platforms/windows/accessible/accessible.pri
new file mode 100644
index 0000000000..1671c67d17
--- /dev/null
+++ b/src/plugins/platforms/windows/accessible/accessible.pri
@@ -0,0 +1,19 @@
+SOURCES += \
+ $$PWD/qwindowsaccessibility.cpp
+
+HEADERS += \
+ $$PWD/qwindowsaccessibility.h
+
+!*g++* {
+ SOURCES += \
+ $$PWD/qwindowsmsaaaccessible.cpp \
+ $$PWD/iaccessible2.cpp \
+ $$PWD/comutils.cpp
+
+ HEADERS += \
+ $$PWD/qwindowsmsaaaccessible.h \
+ $$PWD/iaccessible2.h \
+ $$PWD/comutils.h
+
+ include(../../../../3rdparty/iaccessible2/iaccessible2.pri)
+} # !g++
diff --git a/src/plugins/platforms/windows/accessible/comutils.cpp b/src/plugins/platforms/windows/accessible/comutils.cpp
new file mode 100644
index 0000000000..9a0fce20b8
--- /dev/null
+++ b/src/plugins/platforms/windows/accessible/comutils.cpp
@@ -0,0 +1,641 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <ocidl.h>
+#include <olectl.h>
+
+#include "comutils.h"
+#include <QtCore/qdatetime.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qfont.h>
+
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qbytearray.h>
+#include <QtGui/qcolor.h>
+
+static DATE QDateTimeToDATE(const QDateTime &dt)
+{
+ if (!dt.isValid() || dt.isNull())
+ return 949998; // Special value for no date (01/01/4501)
+
+ SYSTEMTIME stime;
+ memset(&stime, 0, sizeof(stime));
+ QDate date = dt.date();
+ QTime time = dt.time();
+ if (date.isValid() && !date.isNull()) {
+ stime.wDay = date.day();
+ stime.wMonth = date.month();
+ stime.wYear = date.year();
+ }
+ if (time.isValid() && !time.isNull()) {
+ stime.wMilliseconds = time.msec();
+ stime.wSecond = time.second();
+ stime.wMinute = time.minute();
+ stime.wHour = time.hour();
+ }
+
+ double vtime;
+ SystemTimeToVariantTime(&stime, &vtime);
+
+ return vtime;
+}
+
+inline uint QColorToOLEColor(const QColor &col)
+{
+ return qRgba(col.blue(), col.green(), col.red(), 0x00);
+}
+
+bool QVariantToVARIANT(const QVariant &var, VARIANT &arg, const QByteArray &typeName, bool out)
+{
+ QVariant qvar = var;
+ // "type" is the expected type, so coerce if necessary
+ QVariant::Type proptype = typeName.isEmpty() ? QVariant::Invalid : QVariant::nameToType(typeName);
+ if (proptype == QVariant::UserType && !typeName.isEmpty()) {
+ if (typeName == "short" || typeName == "char")
+ proptype = QVariant::Int;
+ else if (typeName == "float")
+ proptype = QVariant::Double;
+ }
+ if (proptype != QVariant::Invalid && proptype != QVariant::UserType && proptype != qvar.type()) {
+ if (qvar.canConvert(proptype))
+ qvar.convert(proptype);
+ else
+ qvar = QVariant(proptype);
+ }
+
+ if (out && arg.vt == (VT_VARIANT|VT_BYREF) && arg.pvarVal) {
+ return QVariantToVARIANT(var, *arg.pvarVal, typeName, false);
+ }
+
+ if (out && proptype == QVariant::UserType && typeName == "QVariant") {
+ VARIANT *pVariant = new VARIANT;
+ QVariantToVARIANT(var, *pVariant, QByteArray(), false);
+ arg.vt = VT_VARIANT|VT_BYREF;
+ arg.pvarVal = pVariant;
+ return true;
+ }
+
+ switch ((int)qvar.type()) {
+ case QVariant::String:
+ if (out && arg.vt == (VT_BSTR|VT_BYREF)) {
+ if (*arg.pbstrVal)
+ SysFreeString(*arg.pbstrVal);
+ *arg.pbstrVal = QStringToBSTR(qvar.toString());
+ arg.vt = VT_BSTR|VT_BYREF;
+ } else {
+ arg.vt = VT_BSTR;
+ arg.bstrVal = QStringToBSTR(qvar.toString());
+ if (out) {
+ arg.pbstrVal = new BSTR(arg.bstrVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+
+ case QVariant::Int:
+ if (out && arg.vt == (VT_I4|VT_BYREF)) {
+ *arg.plVal = qvar.toInt();
+ } else {
+ arg.vt = VT_I4;
+ arg.lVal = qvar.toInt();
+ if (out) {
+ if (typeName == "short") {
+ arg.vt = VT_I2;
+ arg.piVal = new short(arg.lVal);
+ } else if (typeName == "char") {
+ arg.vt = VT_I1;
+ arg.pcVal= new char(arg.lVal);
+ } else {
+ arg.plVal = new long(arg.lVal);
+ }
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+
+ case QVariant::UInt:
+ if (out && (arg.vt == (VT_UINT|VT_BYREF) || arg.vt == (VT_I4|VT_BYREF))) {
+ *arg.puintVal = qvar.toUInt();
+ } else {
+ arg.vt = VT_UINT;
+ arg.uintVal = qvar.toUInt();
+ if (out) {
+ arg.puintVal = new uint(arg.uintVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+
+ case QVariant::LongLong:
+ if (out && arg.vt == (VT_CY|VT_BYREF)) {
+ arg.pcyVal->int64 = qvar.toLongLong();
+#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400
+ } else if (out && arg.vt == (VT_I8|VT_BYREF)) {
+ *arg.pllVal = qvar.toLongLong();
+ } else {
+ arg.vt = VT_I8;
+ arg.llVal = qvar.toLongLong();
+ if (out) {
+ arg.pllVal = new LONGLONG(arg.llVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+#else
+ } else {
+ arg.vt = VT_CY;
+ arg.cyVal.int64 = qvar.toLongLong();
+ if (out) {
+ arg.pcyVal = new CY(arg.cyVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+#endif
+ break;
+
+ case QVariant::ULongLong:
+ if (out && arg.vt == (VT_CY|VT_BYREF)) {
+ arg.pcyVal->int64 = qvar.toULongLong();
+#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400
+ } else if (out && arg.vt == (VT_UI8|VT_BYREF)) {
+ *arg.pullVal = qvar.toULongLong();
+ } else {
+ arg.vt = VT_UI8;
+ arg.ullVal = qvar.toULongLong();
+ if (out) {
+ arg.pullVal = new ULONGLONG(arg.ullVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+#else
+ } else {
+ arg.vt = VT_CY;
+ arg.cyVal.int64 = qvar.toULongLong();
+ if (out) {
+ arg.pcyVal = new CY(arg.cyVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+
+#endif
+
+ break;
+
+ case QVariant::Bool:
+ if (out && arg.vt == (VT_BOOL|VT_BYREF)) {
+ *arg.pboolVal = qvar.toBool() ? VARIANT_TRUE : VARIANT_FALSE;
+ } else {
+ arg.vt = VT_BOOL;
+ arg.boolVal = qvar.toBool() ? VARIANT_TRUE : VARIANT_FALSE;
+ if (out) {
+ arg.pboolVal = new short(arg.boolVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+ case QVariant::Double:
+ if (out && arg.vt == (VT_R8|VT_BYREF)) {
+ *arg.pdblVal = qvar.toDouble();
+ } else {
+ arg.vt = VT_R8;
+ arg.dblVal = qvar.toDouble();
+ if (out) {
+ if (typeName == "float") {
+ arg.vt = VT_R4;
+ arg.pfltVal = new float(arg.dblVal);
+ } else {
+ arg.pdblVal = new double(arg.dblVal);
+ }
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+ case QVariant::Color:
+ if (out && arg.vt == (VT_COLOR|VT_BYREF)) {
+
+ *arg.plVal = QColorToOLEColor(qvariant_cast<QColor>(qvar));
+ } else {
+ arg.vt = VT_COLOR;
+ arg.lVal = QColorToOLEColor(qvariant_cast<QColor>(qvar));
+ if (out) {
+ arg.plVal = new long(arg.lVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+
+ case QVariant::Date:
+ case QVariant::Time:
+ case QVariant::DateTime:
+ if (out && arg.vt == (VT_DATE|VT_BYREF)) {
+ *arg.pdate = QDateTimeToDATE(qvar.toDateTime());
+ } else {
+ arg.vt = VT_DATE;
+ arg.date = QDateTimeToDATE(qvar.toDateTime());
+ if (out) {
+ arg.pdate = new DATE(arg.date);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+#if 0 // not a value with min/max semantics
+ case QVariant::Font:
+ if (out && arg.vt == (VT_DISPATCH|VT_BYREF)) {
+ if (*arg.ppdispVal)
+ (*arg.ppdispVal)->Release();
+ *arg.ppdispVal = QFontToIFont(qvariant_cast<QFont>(qvar));
+ } else {
+ arg.vt = VT_DISPATCH;
+ arg.pdispVal = QFontToIFont(qvariant_cast<QFont>(qvar));
+ if (out) {
+ arg.ppdispVal = new IDispatch*(arg.pdispVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+ case QVariant::Pixmap:
+ if (out && arg.vt == (VT_DISPATCH|VT_BYREF)) {
+ if (*arg.ppdispVal)
+ (*arg.ppdispVal)->Release();
+ *arg.ppdispVal = QPixmapToIPicture(qvariant_cast<QPixmap>(qvar));
+ } else {
+ arg.vt = VT_DISPATCH;
+ arg.pdispVal = QPixmapToIPicture(qvariant_cast<QPixmap>(qvar));
+ if (out) {
+ arg.ppdispVal = new IDispatch*(arg.pdispVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+ case QVariant::Cursor:
+ {
+#ifndef QT_NO_CURSOR
+ int shape = qvariant_cast<QCursor>(qvar).shape();
+ if (out && (arg.vt & VT_BYREF)) {
+ switch (arg.vt & ~VT_BYREF) {
+ case VT_I4:
+ *arg.plVal = shape;
+ break;
+ case VT_I2:
+ *arg.piVal = shape;
+ break;
+ case VT_UI4:
+ *arg.pulVal = shape;
+ break;
+ case VT_UI2:
+ *arg.puiVal = shape;
+ break;
+ case VT_INT:
+ *arg.pintVal = shape;
+ break;
+ case VT_UINT:
+ *arg.puintVal = shape;
+ break;
+ }
+ } else {
+ arg.vt = VT_I4;
+ arg.lVal = shape;
+ if (out) {
+ arg.plVal = new long(arg.lVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+#endif
+ }
+ break;
+
+ case QVariant::List:
+ {
+ const QList<QVariant> list = qvar.toList();
+ const int count = list.count();
+ VARTYPE vt = VT_VARIANT;
+ QVariant::Type listType = QVariant::LastType; // == QVariant
+ if (!typeName.isEmpty() && typeName.startsWith("QList<")) {
+ const QByteArray listTypeName = typeName.mid(6, typeName.length() - 7); // QList<int> -> int
+ listType = QVariant::nameToType(listTypeName);
+ }
+
+ VARIANT variant;
+ void *pElement = &variant;
+ switch (listType) {
+ case QVariant::Int:
+ vt = VT_I4;
+ pElement = &variant.lVal;
+ break;
+ case QVariant::Double:
+ vt = VT_R8;
+ pElement = &variant.dblVal;
+ break;
+ case QVariant::DateTime:
+ vt = VT_DATE;
+ pElement = &variant.date;
+ break;
+ case QVariant::Bool:
+ vt = VT_BOOL;
+ pElement = &variant.boolVal;
+ break;
+ case QVariant::LongLong:
+#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400
+ vt = VT_I8;
+ pElement = &variant.llVal;
+#else
+ vt = VT_CY;
+ pElement = &variant.cyVal;
+#endif
+ break;
+ default:
+ break;
+ }
+ SAFEARRAY *array = 0;
+ bool is2D = false;
+ // If the first element in the array is a list the whole list is
+ // treated as a 2D array. The column count is taken from the 1st element.
+ if (count) {
+ QVariantList col = list.at(0).toList();
+ int maxColumns = col.count();
+ if (maxColumns) {
+ is2D = true;
+ SAFEARRAYBOUND rgsabound[2] = { {0} };
+ rgsabound[0].cElements = count;
+ rgsabound[1].cElements = maxColumns;
+ array = SafeArrayCreate(VT_VARIANT, 2, rgsabound);
+ LONG rgIndices[2];
+ for (LONG i = 0; i < count; ++i) {
+ rgIndices[0] = i;
+ QVariantList columns = list.at(i).toList();
+ int columnCount = qMin(maxColumns, columns.count());
+ for (LONG j = 0; j < columnCount; ++j) {
+ QVariant elem = columns.at(j);
+ VariantInit(&variant);
+ QVariantToVARIANT(elem, variant, elem.typeName());
+ rgIndices[1] = j;
+ SafeArrayPutElement(array, rgIndices, pElement);
+ clearVARIANT(&variant);
+ }
+ }
+
+ }
+ }
+ if (!is2D) {
+ array = SafeArrayCreateVector(vt, 0, count);
+ for (LONG index = 0; index < count; ++index) {
+ QVariant elem = list.at(index);
+ if (listType != QVariant::LastType)
+ elem.convert(listType);
+ VariantInit(&variant);
+ QVariantToVARIANT(elem, variant, elem.typeName());
+ SafeArrayPutElement(array, &index, pElement);
+ clearVARIANT(&variant);
+ }
+ }
+ if (out && arg.vt == (VT_ARRAY|vt|VT_BYREF)) {
+ if (*arg.pparray)
+ SafeArrayDestroy(*arg.pparray);
+ *arg.pparray = array;
+ } else {
+ arg.vt = VT_ARRAY|vt;
+ arg.parray = array;
+ if (out) {
+ arg.pparray = new SAFEARRAY*(arg.parray);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ }
+ break;
+
+ case QVariant::StringList:
+ {
+ const QStringList list = qvar.toStringList();
+ const int count = list.count();
+ SAFEARRAY *array = SafeArrayCreateVector(VT_BSTR, 0, count);
+ for (LONG index = 0; index < count; ++index) {
+ QString elem = list.at(index);
+ BSTR bstr = QStringToBSTR(elem);
+ SafeArrayPutElement(array, &index, bstr);
+ SysFreeString(bstr);
+ }
+
+ if (out && arg.vt == (VT_ARRAY|VT_BSTR|VT_BYREF)) {
+ if (*arg.pparray)
+ SafeArrayDestroy(*arg.pparray);
+ *arg.pparray = array;
+ } else {
+ arg.vt = VT_ARRAY|VT_BSTR;
+ arg.parray = array;
+ if (out) {
+ arg.pparray = new SAFEARRAY*(arg.parray);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ }
+ break;
+
+ case QVariant::ByteArray:
+ {
+ const QByteArray bytes = qvar.toByteArray();
+ const uint count = bytes.count();
+ SAFEARRAY *array = SafeArrayCreateVector(VT_UI1, 0, count);
+ if (count) {
+ const char *data = bytes.constData();
+ char *dest;
+ SafeArrayAccessData(array, (void **)&dest);
+ memcpy(dest, data, count);
+ SafeArrayUnaccessData(array);
+ }
+
+ if (out && arg.vt == (VT_ARRAY|VT_UI1|VT_BYREF)) {
+ if (*arg.pparray)
+ SafeArrayDestroy(*arg.pparray);
+ *arg.pparray = array;
+ } else {
+ arg.vt = VT_ARRAY|VT_UI1;
+ arg.parray = array;
+ if (out) {
+ arg.pparray = new SAFEARRAY*(arg.parray);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ }
+ break;
+
+#ifdef QAX_SERVER
+ case QVariant::Rect:
+ case QVariant::Size:
+ case QVariant::Point:
+ {
+ typedef HRESULT(WINAPI* PGetRecordInfoFromTypeInfo)(ITypeInfo *, IRecordInfo **);
+ static PGetRecordInfoFromTypeInfo pGetRecordInfoFromTypeInfo = 0;
+ static bool resolved = false;
+ if (!resolved) {
+ QSystemLibrary oleaut32(QLatin1String("oleaut32"));
+ pGetRecordInfoFromTypeInfo = (PGetRecordInfoFromTypeInfo)oleaut32.resolve("GetRecordInfoFromTypeInfo");
+ resolved = true;
+ }
+ if (!pGetRecordInfoFromTypeInfo)
+ break;
+
+ ITypeInfo *typeInfo = 0;
+ IRecordInfo *recordInfo = 0;
+ CLSID clsid = qvar.type() == QVariant::Rect ? CLSID_QRect
+ :qvar.type() == QVariant::Size ? CLSID_QSize
+ :CLSID_QPoint;
+ qAxTypeLibrary->GetTypeInfoOfGuid(clsid, &typeInfo);
+ if (!typeInfo)
+ break;
+ pGetRecordInfoFromTypeInfo(typeInfo, &recordInfo);
+ typeInfo->Release();
+ if (!recordInfo)
+ break;
+
+ void *record = 0;
+ switch (qvar.type()) {
+ case QVariant::Rect:
+ {
+ QRect qrect(qvar.toRect());
+ recordInfo->RecordCreateCopy(&qrect, &record);
+ }
+ break;
+ case QVariant::Size:
+ {
+ QSize qsize(qvar.toSize());
+ recordInfo->RecordCreateCopy(&qsize, &record);
+ }
+ break;
+ case QVariant::Point:
+ {
+ QPoint qpoint(qvar.toPoint());
+ recordInfo->RecordCreateCopy(&qpoint, &record);
+ }
+ break;
+ }
+
+ arg.vt = VT_RECORD;
+ arg.pRecInfo = recordInfo,
+ arg.pvRecord = record;
+ if (out) {
+ qWarning("QVariantToVARIANT: out-parameter not supported for records");
+ return false;
+ }
+ }
+ break;
+#endif // QAX_SERVER
+ case QVariant::UserType:
+ {
+ QByteArray subType = qvar.typeName();
+#ifdef QAX_SERVER
+ if (subType.endsWith('*'))
+ subType.truncate(subType.length() - 1);
+#endif
+ if (!qstrcmp(qvar.typeName(), "IDispatch*")) {
+ arg.vt = VT_DISPATCH;
+ arg.pdispVal = *(IDispatch**)qvar.data();
+ if (arg.pdispVal)
+ arg.pdispVal->AddRef();
+ if (out) {
+ qWarning("QVariantToVARIANT: out-parameter not supported for IDispatch");
+ return false;
+ }
+ } else if (!qstrcmp(qvar.typeName(), "IDispatch**")) {
+ arg.vt = VT_DISPATCH;
+ arg.ppdispVal = *(IDispatch***)qvar.data();
+ if (out)
+ arg.vt |= VT_BYREF;
+ } else if (!qstrcmp(qvar.typeName(), "IUnknown*")) {
+ arg.vt = VT_UNKNOWN;
+ arg.punkVal = *(IUnknown**)qvar.data();
+ if (arg.punkVal)
+ arg.punkVal->AddRef();
+ if (out) {
+ qWarning("QVariantToVARIANT: out-parameter not supported for IUnknown");
+ return false;
+ }
+#ifdef QAX_SERVER
+ } else if (qAxFactory()->metaObject(QString::fromLatin1(subType.constData()))) {
+ arg.vt = VT_DISPATCH;
+ void *user = *(void**)qvar.constData();
+// qVariantGet(qvar, user, qvar.typeName());
+ if (!user) {
+ arg.pdispVal = 0;
+ } else {
+ qAxFactory()->createObjectWrapper(static_cast<QObject*>(user), &arg.pdispVal);
+ }
+ if (out) {
+ qWarning("QVariantToVARIANT: out-parameter not supported for subtype");
+ return false;
+ }
+#else
+ } else if (QMetaType::type(subType)) {
+ QAxObject *object = *(QAxObject**)qvar.constData();
+// qVariantGet(qvar, object, subType);
+ arg.vt = VT_DISPATCH;
+ object->queryInterface(IID_IDispatch, (void**)&arg.pdispVal);
+ if (out) {
+ qWarning("QVariantToVARIANT: out-parameter not supported for subtype");
+ return false;
+ }
+#endif
+ } else {
+ return false;
+ }
+ }
+ break;
+#endif
+
+ case QVariant::Invalid: // default-parameters not set
+ if (out && arg.vt == (VT_ERROR|VT_BYREF)) {
+ *arg.plVal = DISP_E_PARAMNOTFOUND;
+ } else {
+ arg.vt = VT_ERROR;
+ arg.lVal = DISP_E_PARAMNOTFOUND;
+ if (out) {
+ arg.plVal = new long(arg.lVal);
+ arg.vt |= VT_BYREF;
+ }
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ Q_ASSERT(!out || (arg.vt & VT_BYREF));
+ return true;
+}
+
diff --git a/src/plugins/platforms/windows/accessible/comutils.h b/src/plugins/platforms/windows/accessible/comutils.h
new file mode 100644
index 0000000000..08420cc46c
--- /dev/null
+++ b/src/plugins/platforms/windows/accessible/comutils.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef COMUTILS_H
+#define COMUTILS_H
+
+#if !defined(_WINDOWS_) && !defined(_WINDOWS_H) && !defined(__WINDOWS__)
+#error Must include windows.h first!
+#endif
+
+#include <ocidl.h>
+#include <QtCore/qstring.h>
+
+class QVariant;
+
+bool QVariantToVARIANT(const QVariant &var, VARIANT &arg, const QByteArray &typeName, bool out);
+
+inline BSTR QStringToBSTR(const QString &str)
+{
+ return SysAllocStringLen((OLECHAR*)str.unicode(), str.length());
+}
+
+#endif // COMUTILS_H
+
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
new file mode 100644
index 0000000000..f22349714f
--- /dev/null
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
@@ -0,0 +1,1467 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QtConfig>
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "iaccessible2.h"
+#include "qwindowsaccessibility.h"
+
+#include <QtGui/qaccessible2.h>
+#include <QtWidgets/qapplication.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/**************************************************************\
+ * AccessibleApplication *
+ **************************************************************/
+// IUnknown
+HRESULT STDMETHODCALLTYPE AccessibleApplication::QueryInterface(REFIID id, LPVOID *iface)
+{
+ *iface = 0;
+ if (id == IID_IUnknown) {
+ accessibleDebug("AccessibleApplication::QI(): IID_IUnknown");
+ *iface = (IUnknown*)this;
+ } else if (id == IID_IAccessibleApplication) {
+ accessibleDebug("AccessibleApplication::QI(): IID_IAccessibleApplication");
+ *iface = static_cast<IAccessibleApplication*>(this);
+ }
+
+ if (*iface) {
+ AddRef();
+ return S_OK;
+ }
+ return E_NOINTERFACE;
+}
+
+ULONG STDMETHODCALLTYPE AccessibleApplication::AddRef()
+{
+ return ++m_ref;
+}
+
+ULONG STDMETHODCALLTYPE AccessibleApplication::Release()
+{
+ if (!--m_ref) {
+ delete this;
+ return 0;
+ }
+ return m_ref;
+}
+
+/* IAccessibleApplication */
+HRESULT STDMETHODCALLTYPE AccessibleApplication::get_appName(/* [retval][out] */ BSTR *name)
+{
+ const QString appName = QGuiApplication::applicationName();
+ *name = QStringToBSTR(appName);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleApplication::get_appVersion(/* [retval][out] */ BSTR *version)
+{
+ const QString appName = QGuiApplication::applicationVersion();
+ *version = QStringToBSTR(appName);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleApplication::get_toolkitName(/* [retval][out] */ BSTR *name)
+{
+ *name = ::SysAllocString(L"Qt");
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleApplication::get_toolkitVersion(/* [retval][out] */ BSTR *version)
+{
+ *version = ::SysAllocString(QT_UNICODE_LITERAL(QT_VERSION_STR));
+ return S_OK;
+}
+
+
+
+/*!
+ \internal
+ Client allocates and deallocates array
+ (see "Special Consideration when using Arrays", in Accessible2.idl)
+ */
+HRESULT STDMETHODCALLTYPE AccessibleRelation::get_target(
+ /* [in] */ long targetIndex,
+ /* [retval][out] */ IUnknown **target)
+{
+ if (targetIndex >= 0 && targetIndex < m_targets.count()) {
+ QAccessibleInterface *iface = m_targets.at(targetIndex);
+ *target = QWindowsAccessibility::wrap(iface);
+ if (*target)
+ return S_OK;
+ return E_FAIL;
+ }
+ return E_INVALIDARG;
+}
+
+/*!
+ \internal
+ Client allocates and deallocates \a targets array
+ (see "Special Consideration when using Arrays", in Accessible2.idl)
+ */
+HRESULT STDMETHODCALLTYPE AccessibleRelation::get_targets(
+ /* [in] */ long maxTargets, // Hmmm, ignore ???
+ /* [length_is][size_is][out] */ IUnknown **targets,
+ /* [retval][out] */ long *nTargets)
+{
+
+ const int numTargets = qMin((int)maxTargets, m_targets.count());
+ for (int i = 0; i < numTargets; ++i) {
+ QAccessibleInterface *iface = m_targets.at(i);
+ IAccessible *iacc = QWindowsAccessibility::wrap(iface);
+ if (!iacc)
+ return E_FAIL;
+ *targets = iacc;
+ ++targets;
+ }
+ *nTargets = numTargets;
+ // \a targets array is allocated by client.
+ return numTargets > 0 ? S_OK : S_FALSE;
+}
+
+
+/**************************************************************\
+ * *
+ * IUnknown *
+ * *
+ **************************************************************/
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryInterface(REFIID id, LPVOID *iface)
+{
+ *iface = 0;
+
+ QByteArray strIID = IIDToString(id);
+ if (!strIID.isEmpty()) {
+ QString ss; QDebug dbg(&ss); dbg << accessible;
+ accessibleDebug("QWindowsIA2Accessible::QI() - IID:%s, iface:%s ", strIID.constData(), qPrintable(ss));
+ }
+ if (id == IID_IUnknown) {
+ *iface = (IUnknown*)(IDispatch*)this;
+ } else if (id == IID_IDispatch) {
+ *iface = (IDispatch*)this;
+ } else if (id == IID_IAccessible) {
+ *iface = (IAccessible*)this;
+ } else if (id == IID_IOleWindow) {
+ *iface = (IOleWindow*)this;
+ } else if (id == IID_IServiceProvider) {
+ *iface = (IServiceProvider*)this;
+ } else if (id == IID_IAccessible2) {
+ *iface = (IAccessible2*)this;
+ } else if (id == IID_IAccessibleAction) {
+ if (accessible->actionInterface())
+ *iface = (IAccessibleAction*)this;
+ } else if (id == IID_IAccessibleComponent) {
+ *iface = (IAccessibleComponent*)this;
+ } else if (id == IID_IAccessibleEditableText) {
+ //if (accessible->editableTextInterface()) {
+ //*iface = (IAccessibleEditableText*)this;
+ //}
+ } else if (id == IID_IAccessibleHyperlink) {
+ //*iface = (IAccessibleHyperlink*)this;
+ } else if (id == IID_IAccessibleHypertext) {
+ //*iface = (IAccessibleHypertext*)this;
+ } else if (id == IID_IAccessibleImage) {
+ //*iface = (IAccessibleImage*)this;
+ } else if (id == IID_IAccessibleRelation) {
+ *iface = (IAccessibleRelation*)this;
+ } else if (id == IID_IAccessibleTable) {
+ //*iface = (IAccessibleTable*)this; // not supported
+ } else if (id == IID_IAccessibleTable2) {
+ if (accessible->tableInterface())
+ *iface = (IAccessibleTable2*)this;
+ } else if (id == IID_IAccessibleTableCell) {
+ if (accessible->tableCellInterface())
+ *iface = (IAccessibleTableCell*)this;
+ } else if (id == IID_IAccessibleText) {
+ if (accessible->textInterface())
+ *iface = (IAccessibleText*)this;
+ } else if (id == IID_IAccessibleValue) {
+ if (accessible->valueInterface())
+ *iface = (IAccessibleValue*)this;
+ }
+ if (*iface) {
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsIA2Accessible::AddRef()
+{
+ return ++ref;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsIA2Accessible::Release()
+{
+ if (!--ref) {
+ delete this;
+ return 0;
+ }
+ return ref;
+}
+
+
+
+/**************************************************************\
+ * *
+ * IAccessible2 *
+ * *
+ **************************************************************/
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRelations(long *nRelations)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!nRelations)
+ return E_INVALIDARG;
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ return getRelationsHelper(0, 0, 0, nRelations);
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relation(long relationIndex, IAccessibleRelation **relation)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!relation)
+ return E_INVALIDARG;
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ return getRelationsHelper(relation, relationIndex, 1);
+}
+
+/*!
+ \internal
+ Client allocates and deallocates array
+ (see "Special Consideration when using Arrays", in Accessible2.idl)
+ */
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relations(long maxRelations,
+ IAccessibleRelation **relations,
+ long *nRelations)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ return getRelationsHelper(relations, 0, maxRelations, nRelations);
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::role(long *ia2role)
+{
+ accessibleDebugClientCalls(accessible);
+ //### Change QAccessibleInterface::role() to return both MSAA and IA2 roles.
+ // When that is completed, we must patch the MSAA bridge not not return any
+ // IA2-specific roles from get_accRole().
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *ia2role = accessible->role();
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollTo(enum IA2ScrollType /*scrollType*/)
+{
+ //### Ignore for now
+ return E_NOTIMPL;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollToPoint(enum IA2CoordinateType /*coordinateType*/, long /*x*/, long /*y*/)
+{
+ //### Ignore for now
+ return E_NOTIMPL;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_groupPosition(long *groupLevel,
+ long *similarItemsInGroup,
+ long *positionInGroup)
+{
+ // ### Ignore for now. Not sure what this is used for.....
+ *groupLevel = 0; // Not applicable
+ *similarItemsInGroup = 0; // Not applicable
+ *positionInGroup = 0; // Not applicable
+ return S_FALSE;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_states(AccessibleStates *states)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ if (!states)
+ return E_POINTER;
+ QAccessible::State st = accessible->state();
+ AccessibleStates ia2states = 0;
+ if (st.active)
+ ia2states |= IA2_STATE_ACTIVE;
+ if (st.invalid)
+ ia2states |= IA2_STATE_DEFUNCT;
+ if (st.editable)
+ ia2states |= IA2_STATE_EDITABLE;
+ if (st.multiLine)
+ ia2states |= IA2_STATE_MULTI_LINE;
+ if (st.selectableText)
+ ia2states |= IA2_STATE_SELECTABLE_TEXT;
+ if (st.supportsAutoCompletion)
+ ia2states |= IA2_STATE_SUPPORTS_AUTOCOMPLETION;
+
+ *states = ia2states;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_extendedRole(BSTR *extendedRole)
+{
+ //###
+ *extendedRole = 0;
+ return E_NOTIMPL; // mozilla does this
+ //return S_FALSE;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedExtendedRole(BSTR *localizedExtendedRole)
+{
+ //###
+ *localizedExtendedRole = 0;
+ return E_NOTIMPL; // mozilla does this
+ //return S_FALSE;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nExtendedStates(long *nExtendedStates)
+{
+ // Who will ever intepret these values into something meaningful??
+ *nExtendedStates = 0;
+ return E_NOTIMPL; // mozilla does this
+ //return S_FALSE;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_extendedStates(long /*maxExtendedStates*/,
+ BSTR **extendedStates,
+ long *nExtendedStates)
+{
+ *extendedStates = 0;
+ *nExtendedStates = 0;
+ return E_NOTIMPL; // mozilla does this
+ //return S_FALSE;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedExtendedStates(long /*maxLocalizedExtendedStates*/,
+ BSTR **localizedExtendedStates,
+ long *nLocalizedExtendedStates)
+{
+ *localizedExtendedStates = 0;
+ *nLocalizedExtendedStates = 0;
+ return E_NOTIMPL; // mozilla does this
+ //return S_FALSE;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_uniqueID(long *outUniqueID)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ // ### FIXME SERIOUSLY, NOT A STABLE SOLUTION IF NODES ARE DELETED ETC
+ // Return 0 if no object and no parent. This is really an error case.
+ uint uid = uniqueID();
+ accessibleDebug("uniqueID: %08x", uid);
+
+ *outUniqueID = (long)uid;
+ return uid ? S_OK : S_FALSE;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_windowHandle(HWND *windowHandle)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ return GetWindow(windowHandle);
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_indexInParent(long *indexInParent)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ if (!indexInParent)
+ return E_INVALIDARG;
+ QAccessibleInterface *par = accessible->parent();
+ if (!par) {
+ *indexInParent = -1;
+ return S_FALSE;
+ }
+ int indexOfChild = par->indexOfChild(accessible);
+ delete par;
+ Q_ASSERT(indexOfChild >= 0);
+ *indexInParent = indexOfChild;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locale(IA2Locale *locale)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ IA2Locale res;
+ QLocale l;
+ res.country = QStringToBSTR(QLocale::countryToString(l.country()));
+ res.language = QStringToBSTR(QLocale::languageToString(l.language()));
+ *locale = res;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(BSTR *attributes)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ *attributes = 0;//QStringToBSTR(QString());
+ return S_FALSE;
+}
+
+/**************************************************************\
+ * IAccessibleAction *
+ **************************************************************/
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ *nActions = 0;
+
+ if (QAccessibleActionInterface *actionIface = actionInterface())
+ *nActions = actionIface->actionNames().count();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ if (QAccessibleActionInterface *actionIface = actionInterface()) {
+ const QStringList actionNames = actionIface->actionNames();
+ if (actionIndex < 0 || actionIndex >= actionNames.count())
+ return E_INVALIDARG;
+ const QString actionName = actionNames.at(actionIndex);
+ actionIface->doAction(actionName);
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionIndex, BSTR *description)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ *description = 0;
+ if (QAccessibleActionInterface *actionIface = actionInterface()) {
+ const QStringList actionNames = actionIface->actionNames();
+ if (actionIndex < 0 || actionIndex >= actionNames.count())
+ return E_INVALIDARG;
+ const QString actionName = actionNames.at(actionIndex);
+ *description = QStringToBSTR(actionIface->localizedActionDescription(actionName));
+ }
+ return *description ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_keyBinding(long actionIndex, long nMaxBindings, BSTR **keyBindings, long *nBindings)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ Q_UNUSED(nMaxBindings);
+ BSTR *arrayOfBindingsToReturn = 0;
+ int numBindings = 0;
+ if (QAccessibleActionInterface *actionIface = actionInterface()) {
+ const QStringList actionNames = actionIface->actionNames();
+ if (actionIndex < 0 || actionIndex >= actionNames.count())
+ return E_INVALIDARG;
+ const QString actionName = actionNames.at(actionIndex);
+ const QStringList keyBindings = actionIface->keyBindingsForAction(actionName);
+ numBindings = keyBindings.count();
+ if (numBindings > 0) {
+ // The IDL documents that the client must free with CoTaskMemFree
+ arrayOfBindingsToReturn = (BSTR*)::CoTaskMemAlloc(sizeof(BSTR) * numBindings);
+ for (int i = 0; i < numBindings; ++i)
+ arrayOfBindingsToReturn[i] = QStringToBSTR(keyBindings.at(i));
+ }
+ }
+ *keyBindings = arrayOfBindingsToReturn;
+ *nBindings = numBindings;
+
+ return numBindings ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR *name)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ *name = 0;
+ if (QAccessibleActionInterface *actionIface = actionInterface()) {
+ const QStringList actionNames = actionIface->actionNames();
+ if (actionIndex < 0 || actionIndex >= actionNames.count())
+ return E_INVALIDARG;
+ const QString actionName = actionNames.at(actionIndex);
+ *name = QStringToBSTR(actionName);
+ }
+ return *name ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIndex, BSTR *localizedName)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ *localizedName = 0;
+ if (QAccessibleActionInterface *actionIface = actionInterface()) {
+ const QStringList actionNames = actionIface->actionNames();
+ if (actionIndex < 0 || actionIndex >= actionNames.count())
+ return E_INVALIDARG;
+
+ const QString actionName = actionNames.at(actionIndex);
+ *localizedName = QStringToBSTR(actionIface->localizedActionName(actionName));
+ }
+ return *localizedName ? S_OK : S_FALSE;
+}
+
+/**************************************************************\
+ * IAccessibleComponent *
+ **************************************************************/
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locationInParent(long *x, long *y)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QPoint topLeft = accessible->rect().topLeft();
+
+ if (QAccessibleInterface *parentIface = accessible->parent())
+ topLeft -= parentIface->rect().topLeft();
+
+ *x = topLeft.x();
+ *y = topLeft.y();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_foreground(IA2Color *foreground)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ // IA2Color is a typedef for long
+ *foreground = (IA2Color)accessible->foregroundColor().rgb();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_background(IA2Color *background)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ // IA2Color is a typedef for long
+ *background = (IA2Color)accessible->backgroundColor().rgb();
+ return S_OK;
+}
+
+/**************************************************************\
+ * IAccessibleTable2 *
+ **************************************************************/
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_cellAt( long row, long column, IUnknown **cell)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *cell = 0;
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ if (QAccessibleInterface *qtCell = tableIface->cellAt(row, column)) {
+ *cell = QWindowsAccessibility::wrap(qtCell);
+ }
+ }
+ accessibleDebug("found cell? %p", *cell);
+ return *cell ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caption( IUnknown **captionInterface)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *captionInterface = 0;
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ if (QAccessibleInterface *iface = tableIface->caption())
+ *captionInterface = QWindowsAccessibility::wrap(iface);
+ }
+ return *captionInterface ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnDescription( long column, BSTR *description)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *description = 0;
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ const QString qtDesc = tableIface->columnDescription(column);
+ if (!qtDesc.isEmpty())
+ *description = QStringToBSTR(qtDesc);
+ }
+ return *description ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nColumns( long *columnCount)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ *columnCount = tableIface->columnCount();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRows(long *rowCount)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ *rowCount = tableIface->rowCount();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedCells(long *cellCount)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ *cellCount = tableIface->selectedCellCount();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedColumns(long *columnCount)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ *columnCount = tableIface->selectedColumnCount();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedRows(long *rowCount)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ *rowCount = tableIface->selectedRowCount();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowDescription(long row, BSTR *description)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *description = 0;
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ const QString qtDesc = tableIface->columnDescription(row);
+ if (!qtDesc.isEmpty())
+ *description = QStringToBSTR(qtDesc);
+ }
+ return *description ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedCells(IUnknown ***cells, long *nSelectedCells)
+{
+ accessibleDebugClientCalls(accessible);
+ Q_UNUSED(cells);
+ Q_UNUSED(nSelectedCells);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QList<QAccessibleInterface*> selectedCells = tableInterface()->selectedCells();
+ return wrapListOfCells(selectedCells, cells, nSelectedCells);
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedColumns(long **selectedColumns, long *nColumns)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ const QList<int> selectedIndices = tableIface->selectedColumns();
+ const int &count = selectedIndices.count();
+ long *selected = (count ? (long*)::CoTaskMemAlloc(sizeof(long) * count) : (long*)0);
+ for (int i = 0; i < count; ++i)
+ selected[i] = selectedIndices.at(i);
+ *selectedColumns = selected;
+ *nColumns = count;
+ return count ? S_OK : S_FALSE;
+ }
+ return E_FAIL;
+
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedRows(long **selectedRows, long *nRows)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ const QList<int> selectedIndices = tableIface->selectedRows();
+ const int &count = selectedIndices.count();
+ long *selected = (count ? (long*)::CoTaskMemAlloc(sizeof(long) * count) : (long*)0);
+ for (int i = 0; i < count; ++i)
+ selected[i] = selectedIndices.at(i);
+ *selectedRows = selected;
+ *nRows = count;
+ return count ? S_OK : S_FALSE;
+ }
+ return E_FAIL;
+
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_summary(IUnknown **summaryInterface)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *summaryInterface = 0;
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ if (QAccessibleInterface *iface = tableIface->summary())
+ *summaryInterface = QWindowsAccessibility::wrap(iface);
+ }
+ return *summaryInterface ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isColumnSelected(long column, boolean *isSelected)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ *isSelected = tableIface->isColumnSelected(column);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isRowSelected(long row, boolean *isSelected)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ *isSelected = tableIface->isRowSelected(row);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectRow(long row)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ bool ok = tableIface->selectRow(row);
+ return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectColumn(long column)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ bool ok = tableIface->selectColumn(column);
+ return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectRow(long row)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ bool ok = tableIface->unselectRow(row);
+ return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectColumn(long column)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleTableInterface *tableIface = tableInterface()) {
+ bool ok = tableIface->unselectColumn(column);
+ return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_modelChange( IA2TableModelChange * /*modelChange*/)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************\
+ * IAccessibleTableCell *
+\**************************************************************/
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnExtent(long *nColumnsSpanned)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *nColumnsSpanned = tableCellInterface()->columnExtent();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnHeaderCells(IUnknown ***cellAccessibles,
+ long *nColumnHeaderCells)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ const QList<QAccessibleInterface*> headerCells = tableCellInterface()->columnHeaderCells();
+ return wrapListOfCells(headerCells, cellAccessibles, nColumnHeaderCells);
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnIndex(long *columnIndex)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ *columnIndex = tableCellInterface()->columnIndex();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowExtent(long *nRowsSpanned)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ *nRowsSpanned = tableCellInterface()->rowExtent();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowHeaderCells(IUnknown ***cellAccessibles,
+ long *nRowHeaderCells)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ const QList<QAccessibleInterface*> headerCells = tableCellInterface()->rowHeaderCells();
+ return wrapListOfCells(headerCells, cellAccessibles, nRowHeaderCells);
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowIndex(long *rowIndex)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ *rowIndex = tableCellInterface()->rowIndex();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isSelected( boolean *isSelected)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ *isSelected = tableCellInterface()->isSelected();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowColumnExtents(long *row, long *column,
+ long *rowExtents, long *columnExtents,
+ boolean *isSelected)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ tableCellInterface()->rowColumnExtents((int*)row, (int*)column, (int*)rowExtents, (int*)columnExtents, (bool*)isSelected);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_table(IUnknown **table)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *tableIface = tableCellInterface()->table();
+
+ *table = QWindowsAccessibility::wrap(tableIface);
+ return S_OK;
+}
+
+/**************************************************************\
+ * IAccessibleText *
+\**************************************************************/
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::addSelection(long startOffset,
+ long endOffset)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *text = textInterface()) {
+ text->addSelection(startOffset, endOffset);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(long offset,
+ long *startOffset,
+ long *endOffset,
+ BSTR *textAttributes)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *text = textInterface()) {
+ const QString attrs = text->attributes(offset, (int*)startOffset, (int*)endOffset);
+ *textAttributes = QStringToBSTR(attrs);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caretOffset(long *offset)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *text = textInterface()) {
+ *offset = text->cursorPosition();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_characterExtents(long offset,
+ enum IA2CoordinateType coordType,
+ long *x,
+ long *y,
+ long *width,
+ long *height)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *text = textInterface()) {
+ const QRect rect = text->characterRect(offset, (QAccessible2::CoordinateType)coordType);
+ *x = rect.x();
+ *y = rect.y();
+ *width = rect.width();
+ *height = rect.height();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelections(long *nSelections)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *text = textInterface()) {
+ *nSelections = text->selectionCount();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_offsetAtPoint(long x,
+ long y,
+ enum IA2CoordinateType coordType,
+ long *offset)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *text = textInterface()) {
+ *offset = text->offsetAtPoint(QPoint(x,y), (QAccessible2::CoordinateType)coordType);
+ return (*offset >=0 ? S_OK : S_FALSE);
+ }
+ return E_FAIL;
+
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selection(long selectionIndex,
+ long *startOffset,
+ long *endOffset)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *text = textInterface()) {
+ text->selection(selectionIndex, (int*)startOffset, (int*)endOffset);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_text(long startOffset,
+ long endOffset,
+ BSTR *text)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *textif = textInterface()) {
+ const QString t = textif->text(startOffset, endOffset);
+ if (!t.isEmpty()) {
+ *text = QStringToBSTR(t);
+ return S_OK;
+ }
+ return E_INVALIDARG;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textBeforeOffset(long offset,
+ enum IA2TextBoundaryType boundaryType,
+ long *startOffset,
+ long *endOffset,
+ BSTR *text)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *textIface = textInterface()) {
+ const QString txt = textIface->textBeforeOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
+ if (!txt.isEmpty()) {
+ *text = QStringToBSTR(txt);
+ return S_OK;
+ }
+ return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAfterOffset(
+ long offset,
+ enum IA2TextBoundaryType boundaryType,
+ long *startOffset,
+ long *endOffset,
+ BSTR *text)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *textIface = textInterface()) {
+ const QString txt = textIface->textAfterOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
+ if (!txt.isEmpty()) {
+ *text = QStringToBSTR(txt);
+ return S_OK;
+ }
+ return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAtOffset(long offset,
+ enum IA2TextBoundaryType boundaryType,
+ long *startOffset,
+ long *endOffset,
+ BSTR *text)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *textIface = textInterface()) {
+ const QString txt = textIface->textAtOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
+ if (!txt.isEmpty()) {
+ *text = QStringToBSTR(txt);
+ return S_OK;
+ }
+ return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::removeSelection(long selectionIndex)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *textIface = textInterface()) {
+ textIface->removeSelection(selectionIndex);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCaretOffset(long offset)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *textIface = textInterface()) {
+ textIface->setCursorPosition(offset);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setSelection(long selectionIndex,
+ long startOffset,
+ long endOffset)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *textIface = textInterface()) {
+ textIface->setSelection(selectionIndex, startOffset, endOffset);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nCharacters(long *nCharacters)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *textIface = textInterface()) {
+ *nCharacters = textIface->characterCount();
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringTo(long startIndex,
+ long endIndex,
+ enum IA2ScrollType scrollType)
+{
+ accessibleDebugClientCalls(accessible);
+ if (QAccessibleTextInterface *textIface = textInterface()) {
+ Q_UNUSED(scrollType); //###
+ textIface->scrollToSubstring(startIndex, endIndex);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringToPoint(long startIndex,
+ long endIndex,
+ enum IA2CoordinateType coordinateType,
+ long x,
+ long y)
+{
+ Q_UNUSED(startIndex);
+ Q_UNUSED(endIndex);
+ Q_UNUSED(coordinateType);
+ Q_UNUSED(x);
+ Q_UNUSED(y);
+
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_newText(IA2TextSegment *newText)
+{
+ Q_UNUSED(newText);
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_oldText(IA2TextSegment *oldText)
+{
+ Q_UNUSED(oldText);
+ return E_NOTIMPL;
+}
+
+/**************************************************************\
+ * IAccessibleValue *
+ **************************************************************/
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_currentValue(VARIANT *currentValue)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ if (QAccessibleValueInterface *valueIface = valueInterface()) {
+ const QVariant var = valueIface->currentValue();
+ if (QVariantToVARIANT(var, *currentValue, QByteArray(), false))
+ return S_OK;
+
+ }
+ currentValue->vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCurrentValue(VARIANT value)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ HRESULT hr = S_FALSE;
+ if (QAccessibleValueInterface *valueIface = valueInterface()) {
+ hr = VariantChangeType(&value, &value, 0, VT_R8);
+ if (SUCCEEDED(hr)) {
+ // ### works only for numbers (not date, strings, etc)
+ valueIface->setCurrentValue(QVariant(value.dblVal));
+ }
+ }
+ return hr;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_maximumValue(VARIANT *maximumValue)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ if (QAccessibleValueInterface *valueIface = valueInterface()) {
+ const QVariant var = valueIface->maximumValue();
+ if (QVariantToVARIANT(var, *maximumValue, QByteArray(), false))
+ return S_OK;
+ }
+ maximumValue->vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_minimumValue(VARIANT *minimumValue)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ if (QAccessibleValueInterface *valueIface = valueInterface()) {
+ const QVariant var = valueIface->minimumValue();
+ if (QVariantToVARIANT(var, *minimumValue, QByteArray(), false))
+ return S_OK;
+ }
+ minimumValue->vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+
+/**************************************************************\
+ * IServiceProvider *
+ **************************************************************/
+/*!
+ \internal
+ Reimplemented from IServiceProvider
+*/
+HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryService(REFGUID guidService, REFIID riid, void **iface)
+{
+ if (!iface)
+ return E_POINTER;
+ Q_UNUSED(guidService);
+ *iface = 0;
+ accessibleDebug("QWindowsIA2Accessible::QS(): %s", IIDToString(riid).constData());
+ if (riid == IID_IAccessible || riid == IID_IUnknown || riid == IID_IDispatch) {
+ *iface = static_cast<IAccessible*>(this);
+ } else if (/*guidService == IID_IAccessible && */riid == IID_IAccessible2) {
+ *iface = static_cast<IAccessible2*>(this);
+ } else if (riid == IID_IAccessibleApplication) {
+ *iface = new AccessibleApplication;
+ return S_OK;
+ } else {
+ QueryInterface(riid, iface);
+ }
+ if (*iface) {
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+
+/*!
+ \internal
+ private function..
+ \a maxRelations max number of relations to return in \a relations
+ \a relations the array of relations matching
+ \a startIndex Index to start to return from,
+ it will return only that specific relation in \a relations
+
+ If \a relations is null, \a startIndex and \a maxRelations are ignored, causing
+ it to return the number of relations in \a nRelations
+*/
+HRESULT QWindowsIA2Accessible::getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations /* = 0*/)
+{
+ if (nRelations)
+ *nRelations = 0;
+ typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationEntry;
+ QVector<RelationEntry> rels = accessible->relations();
+ QMap<QAccessible::Relation, QAccessibleInterface *> relationMap;
+ for (QVector<RelationEntry>::const_iterator it = rels.constBegin(); it != rels.constEnd(); ++it)
+ {
+ RelationEntry e = *it;
+ relationMap.insertMulti(e.second, e.first);
+ }
+
+ QList<QAccessible::Relation> keys = relationMap.keys();
+ const int numRelations = keys.count();
+ if (relations) {
+ for (int i = startIndex; i < qMin(startIndex + (int)maxRelations, numRelations); ++i) {
+ QAccessible::Relation relation = keys.at(i);
+ QList<QAccessibleInterface*> targets = relationMap.values(relation);
+ AccessibleRelation *rel = new AccessibleRelation(targets, relation);
+ *relations = rel;
+ ++relations;
+ }
+ }
+ if (nRelations)
+ *nRelations = numRelations;
+
+ return numRelations > 0 ? S_OK : S_FALSE;
+}
+
+
+
+
+/*!
+ \internal
+ helper to wrap a QList<QAccessibleInterface*> inside an array of IAccessible*
+ The IAccessible* array is returned as a IUnknown*
+*/
+HRESULT QWindowsIA2Accessible::wrapListOfCells(const QList<QAccessibleInterface*> &inputCells, IUnknown ***outputAccessibles, long *nCellCount)
+{
+ const int count = inputCells.count();
+ // Server allocates array
+ IUnknown **outputCells = count ? (IUnknown**)::CoTaskMemAlloc(sizeof(IUnknown*) * count ) : (IUnknown**)0;
+ for (int i = 0; i < count; ++i)
+ outputCells[i] = QWindowsAccessibility::wrap(inputCells.at(i));
+
+ *outputAccessibles = outputCells;
+ *nCellCount = count;
+ return count > 0 ? S_OK : S_FALSE;
+}
+
+uint QWindowsIA2Accessible::uniqueID() const
+{
+ uint uid = 0;
+ if (QObject *obj = accessible->object())
+ uid = qHash(obj);
+
+ if (!uid) {
+ QAccessibleInterface *acc = accessible;
+ QVector<int> indexOfNodes;
+ while (acc && !acc->object()) {
+ QAccessibleInterface *par = acc->parent();
+ indexOfNodes.append(par->indexOfChild(acc));
+ if (acc != accessible)
+ delete acc;
+ acc = par;
+ }
+ if (acc) {
+ if (acc->object()) {
+ uid = qHash(acc->object());
+ for (int i = 0; i < indexOfNodes.count(); ++i)
+ uid = qHash(uid + indexOfNodes.at(i));
+
+ }
+ if (acc != accessible)
+ delete acc;
+ }
+ }
+ return uid;
+}
+
+
+#define IF_EQUAL_RETURN_IIDSTRING(id, iid) if (id == iid) return QByteArray(#iid)
+
+QByteArray QWindowsIA2Accessible::IIDToString(REFIID id)
+{
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IUnknown);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IDispatch);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IOleWindow);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IServiceProvider);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible2);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleAction);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleApplication);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleComponent);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleEditableText);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHyperlink);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHypertext);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleImage);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleRelation);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable2);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTableCell);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleText);
+ IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleValue);
+
+ // else...
+ QByteArray strGuid;
+#if 0 // Can be useful for debugging, but normally we'd like to reduce the noise a bit...
+ OLECHAR szGuid[39]={0};
+ ::StringFromGUID2(id, szGuid, 39);
+ strGuid.reserve(40);
+ ::WideCharToMultiByte(CP_UTF8, 0, szGuid, 39, strGuid.data(), 39, NULL, NULL);
+ strGuid[38] = '\0';
+#endif
+ return strGuid;
+}
+
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.h b/src/plugins/platforms/windows/accessible/iaccessible2.h
new file mode 100644
index 0000000000..a59263fba1
--- /dev/null
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.h
@@ -0,0 +1,379 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef IACCESSIBLE2_H
+#define IACCESSIBLE2_H
+
+#include <QtCore/QtConfig>
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "qwindowsmsaaaccessible.h"
+#include "comutils.h"
+
+#include "Accessible2.h"
+#include "AccessibleAction.h"
+#include "AccessibleApplication.h"
+#include "AccessibleComponent.h"
+#include "AccessibleEditableText.h"
+#include "AccessibleHyperlink.h"
+#include "AccessibleHypertext.h"
+#include "AccessibleImage.h"
+#include "AccessibleRelation.h"
+#include "AccessibleTable.h"
+#include "AccessibleTable2.h"
+#include "AccessibleTableCell.h"
+#include "AccessibleText.h"
+#include "AccessibleValue.h"
+
+#include "AccessibleEventID.h"
+#include "AccessibleRole.h"
+#include "AccessibleStates.h"
+
+#ifdef Q_CC_MINGW
+# include <servprov.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsIA2Accessible : public QWindowsMsaaAccessible,
+ public IAccessibleAction,
+ public IAccessibleComponent,
+ /*public IAccessibleEditableText,*/
+ public IAccessibleTable2,
+ public IAccessibleTableCell,
+ public IAccessibleText,
+ public IAccessibleValue,
+ public IServiceProvider
+{
+public:
+ QWindowsIA2Accessible(QAccessibleInterface *a) : QWindowsMsaaAccessible(a) {}
+
+ /* IUnknown */
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ /* IAccessible2 */
+ HRESULT STDMETHODCALLTYPE get_nRelations(long *nRelations);
+ HRESULT STDMETHODCALLTYPE get_relation(long relationIndex, IAccessibleRelation **relation);
+ HRESULT STDMETHODCALLTYPE get_relations(long maxRelations, IAccessibleRelation **relations, long *nRelations);
+ HRESULT STDMETHODCALLTYPE role(long *role);
+ HRESULT STDMETHODCALLTYPE scrollTo(enum IA2ScrollType scrollType);
+ HRESULT STDMETHODCALLTYPE scrollToPoint(enum IA2CoordinateType coordinateType, long x, long y);
+ HRESULT STDMETHODCALLTYPE get_groupPosition(long *groupLevel, long *similarItemsInGroup, long *positionInGroup);
+ HRESULT STDMETHODCALLTYPE get_states(AccessibleStates *states);
+ HRESULT STDMETHODCALLTYPE get_extendedRole(BSTR *extendedRole);
+ HRESULT STDMETHODCALLTYPE get_localizedExtendedRole(BSTR *localizedExtendedRole);
+ HRESULT STDMETHODCALLTYPE get_nExtendedStates(long *nExtendedStates);
+ HRESULT STDMETHODCALLTYPE get_extendedStates(long maxExtendedStates, BSTR **extendedStates, long *nExtendedStates);
+ HRESULT STDMETHODCALLTYPE get_localizedExtendedStates(long maxLocalizedExtendedStates, BSTR **localizedExtendedStates, long *nLocalizedExtendedStates);
+ HRESULT STDMETHODCALLTYPE get_uniqueID(long *uniqueID);
+ HRESULT STDMETHODCALLTYPE get_windowHandle(HWND *windowHandle);
+ HRESULT STDMETHODCALLTYPE get_indexInParent(long *indexInParent);
+ HRESULT STDMETHODCALLTYPE get_locale(IA2Locale *locale);
+ HRESULT STDMETHODCALLTYPE get_attributes(BSTR *attributes);
+
+ /* IAccessibleAction */
+ HRESULT STDMETHODCALLTYPE nActions(long *nActions);
+ HRESULT STDMETHODCALLTYPE doAction(long actionIndex);
+ HRESULT STDMETHODCALLTYPE get_description(long actionIndex, BSTR *description);
+ HRESULT STDMETHODCALLTYPE get_keyBinding(long actionIndex, long nMaxBindings, BSTR **keyBindings, long *nBindings);
+ HRESULT STDMETHODCALLTYPE get_name(long actionIndex, BSTR *name);
+ HRESULT STDMETHODCALLTYPE get_localizedName(long actionIndex, BSTR *localizedName);
+
+ /* IAccessibleComponent */
+ HRESULT STDMETHODCALLTYPE get_locationInParent(long *x,long *y);
+ HRESULT STDMETHODCALLTYPE get_foreground(IA2Color *foreground);
+ HRESULT STDMETHODCALLTYPE get_background(IA2Color *background);
+
+ /* IAccessibleEditableText */
+ /*
+ HRESULT STDMETHODCALLTYPE copyText(long startOffset, long endOffset);
+ HRESULT STDMETHODCALLTYPE deleteText(long startOffset, long endOffset);
+ HRESULT STDMETHODCALLTYPE insertText(long offset, BSTR *text);
+ HRESULT STDMETHODCALLTYPE cutText(long startOffset, long endOffset);
+ HRESULT STDMETHODCALLTYPE pasteText(long offset);
+ HRESULT STDMETHODCALLTYPE replaceText(long startOffset, long endOffset, BSTR *text);
+ HRESULT STDMETHODCALLTYPE setAttributes(long startOffset, long endOffset, BSTR *attributes);
+ */
+
+ /* IAccessibleTable2 */
+ HRESULT STDMETHODCALLTYPE get_cellAt( long row, long column, IUnknown **cell);
+ HRESULT STDMETHODCALLTYPE get_caption( IUnknown **accessible);
+ HRESULT STDMETHODCALLTYPE get_columnDescription( long column, BSTR *description);
+ HRESULT STDMETHODCALLTYPE get_nColumns( long *columnCount);
+ HRESULT STDMETHODCALLTYPE get_nRows( long *rowCount);
+ HRESULT STDMETHODCALLTYPE get_nSelectedCells( long *cellCount);
+ HRESULT STDMETHODCALLTYPE get_nSelectedColumns( long *columnCount);
+ HRESULT STDMETHODCALLTYPE get_nSelectedRows( long *rowCount);
+ HRESULT STDMETHODCALLTYPE get_rowDescription( long row, BSTR *description);
+ HRESULT STDMETHODCALLTYPE get_selectedCells( IUnknown ***cells, long *nSelectedCells);
+ HRESULT STDMETHODCALLTYPE get_selectedColumns( long **selectedColumns, long *nColumns);
+ HRESULT STDMETHODCALLTYPE get_selectedRows( long **selectedRows, long *nRows);
+ HRESULT STDMETHODCALLTYPE get_summary( IUnknown **accessible);
+ HRESULT STDMETHODCALLTYPE get_isColumnSelected( long column, boolean *isSelected);
+ HRESULT STDMETHODCALLTYPE get_isRowSelected( long row, boolean *isSelected);
+ HRESULT STDMETHODCALLTYPE selectRow( long row);
+ HRESULT STDMETHODCALLTYPE selectColumn( long column);
+ HRESULT STDMETHODCALLTYPE unselectRow( long row);
+ HRESULT STDMETHODCALLTYPE unselectColumn( long column);
+ HRESULT STDMETHODCALLTYPE get_modelChange( IA2TableModelChange *modelChange);
+
+ /* IAccessibleTableCell */
+ HRESULT STDMETHODCALLTYPE get_columnExtent(long *nColumnsSpanned);
+ HRESULT STDMETHODCALLTYPE get_columnHeaderCells(IUnknown ***cellAccessibles, long *nColumnHeaderCells);
+ HRESULT STDMETHODCALLTYPE get_columnIndex(long *columnIndex);
+ HRESULT STDMETHODCALLTYPE get_rowExtent(long *nRowsSpanned);
+ HRESULT STDMETHODCALLTYPE get_rowHeaderCells(IUnknown ***cellAccessibles, long *nRowHeaderCells);
+ HRESULT STDMETHODCALLTYPE get_rowIndex(long *rowIndex);
+ HRESULT STDMETHODCALLTYPE get_isSelected( boolean *isSelected);
+ HRESULT STDMETHODCALLTYPE get_rowColumnExtents(long *row, long *column,
+ long *rowExtents, long *columnExtents,
+ boolean *isSelected);
+ HRESULT STDMETHODCALLTYPE get_table(IUnknown **table);
+
+
+ /* IAccessibleText */
+ HRESULT STDMETHODCALLTYPE addSelection(long startOffset, long endOffset);
+ HRESULT STDMETHODCALLTYPE get_attributes(long offset, long *startOffset,
+ long *endOffset, BSTR *textAttributes);
+ HRESULT STDMETHODCALLTYPE get_caretOffset(long *offset);
+ HRESULT STDMETHODCALLTYPE get_characterExtents(long offset, enum IA2CoordinateType coordType,
+ long *x, long *y,
+ long *width, long *height);
+ HRESULT STDMETHODCALLTYPE get_nSelections(long *nSelections);
+ HRESULT STDMETHODCALLTYPE get_offsetAtPoint(long x, long y, enum IA2CoordinateType coordType, long *offset);
+ HRESULT STDMETHODCALLTYPE get_selection(long selectionIndex, long *startOffset, long *endOffset);
+ HRESULT STDMETHODCALLTYPE get_text(long startOffset, long endOffset, BSTR *text);
+ HRESULT STDMETHODCALLTYPE get_textBeforeOffset(long offset, enum IA2TextBoundaryType boundaryType,
+ long *startOffset, long *endOffset, BSTR *text);
+ HRESULT STDMETHODCALLTYPE get_textAfterOffset(long offset, enum IA2TextBoundaryType boundaryType,
+ long *startOffset, long *endOffset, BSTR *text);
+ HRESULT STDMETHODCALLTYPE get_textAtOffset(long offset, enum IA2TextBoundaryType boundaryType,
+ long *startOffset, long *endOffset, BSTR *text);
+ HRESULT STDMETHODCALLTYPE removeSelection(long selectionIndex);
+ HRESULT STDMETHODCALLTYPE setCaretOffset(long offset);
+ HRESULT STDMETHODCALLTYPE setSelection(long selectionIndex, long startOffset, long endOffset);
+ HRESULT STDMETHODCALLTYPE get_nCharacters(long *nCharacters);
+ HRESULT STDMETHODCALLTYPE scrollSubstringTo(long startIndex, long endIndex, enum IA2ScrollType scrollType);
+ HRESULT STDMETHODCALLTYPE scrollSubstringToPoint(long startIndex, long endIndex,
+ enum IA2CoordinateType coordinateType, long x, long y);
+ HRESULT STDMETHODCALLTYPE get_newText(IA2TextSegment *newText);
+ HRESULT STDMETHODCALLTYPE get_oldText(IA2TextSegment *oldText);
+
+ /* IAccessibleValue */
+ HRESULT STDMETHODCALLTYPE get_currentValue(VARIANT *currentValue);
+ HRESULT STDMETHODCALLTYPE setCurrentValue(VARIANT value);
+ HRESULT STDMETHODCALLTYPE get_maximumValue(VARIANT *maximumValue);
+ HRESULT STDMETHODCALLTYPE get_minimumValue(VARIANT *minimumValue);
+
+ /* IServiceProvider */
+ HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppv);
+
+ /* private helper functions */
+private:
+ inline QAccessibleTextInterface *textInterface() const {
+ return accessible->isValid() ? accessible->textInterface() : static_cast<QAccessibleTextInterface *>(0);
+ }
+
+ inline QAccessibleActionInterface *actionInterface() const {
+ return accessible->actionInterface();
+ }
+
+ inline QAccessibleValueInterface *valueInterface() const {
+ return accessible->valueInterface();
+ }
+
+ inline QAccessibleTableInterface *tableInterface() const {
+ return accessible->tableInterface();
+ }
+
+ inline QAccessibleTableCellInterface *tableCellInterface() const {
+ return accessible->tableCellInterface();
+ }
+
+ HRESULT getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations = 0);
+ HRESULT wrapListOfCells(const QList<QAccessibleInterface*> &inputCells, IUnknown ***outputAccessibles, long *nCellCount);
+ uint uniqueID() const;
+ QByteArray IIDToString(REFIID id);
+
+private:
+ ULONG ref;
+
+};
+
+/**************************************************************\
+ * AccessibleApplication *
+ **************************************************************/
+class AccessibleApplication : public IAccessibleApplication
+{
+public:
+ AccessibleApplication() : m_ref(1)
+ {
+
+ }
+
+ virtual ~AccessibleApplication() {}
+
+ /* IUnknown */
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ /* IAccessibleApplication */
+ HRESULT STDMETHODCALLTYPE get_appName(/* [retval][out] */ BSTR *name);
+ HRESULT STDMETHODCALLTYPE get_appVersion(/* [retval][out] */ BSTR *version);
+ HRESULT STDMETHODCALLTYPE get_toolkitName(/* [retval][out] */ BSTR *name);
+ HRESULT STDMETHODCALLTYPE get_toolkitVersion(/* [retval][out] */ BSTR *version);
+private:
+ ULONG m_ref;
+};
+
+
+
+/**************************************************************\
+ * IAccessibleRelation *
+ **************************************************************/
+struct AccessibleRelation : public IAccessibleRelation
+{
+ AccessibleRelation(const QList<QAccessibleInterface *> &targets,
+ QAccessible::Relation relation)
+ : m_targets(targets), m_relation(relation), m_ref(1)
+ {
+ Q_ASSERT(m_targets.count());
+ }
+
+
+ /* IUnknown */
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface)
+ {
+ *iface = 0;
+ if (id == IID_IUnknown)
+ *iface = (IUnknown*)this;
+
+ if (*iface) {
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return ++m_ref;
+ }
+
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ if (!--m_ref) {
+ delete this;
+ return 0;
+ }
+ return m_ref;
+ }
+
+ /* IAccessibleRelation */
+ HRESULT STDMETHODCALLTYPE get_relationType(
+ /* [retval][out] */ BSTR *relationType)
+ {
+ *relationType = relationToBSTR(m_relation);
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE get_localizedRelationType(
+ /* [retval][out] */ BSTR *localizedRelationType)
+ {
+ // Who ever needs this???
+ *localizedRelationType = relationToBSTR(m_relation);
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE get_nTargets(
+ /* [retval][out] */ long *nTargets)
+ {
+ // ### always one target
+ *nTargets = m_targets.count();
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE get_target(long targetIndex, IUnknown **target);
+
+
+ /*!
+ \internal
+ Client allocates and deallocates \a targets array
+ (see "Special Consideration when using Arrays", in Accessible2.idl)
+ */
+ HRESULT STDMETHODCALLTYPE get_targets(
+ /* [in] */ long maxTargets, // Hmmm, ignore ???
+ /* [length_is][size_is][out] */ IUnknown **targets,
+ /* [retval][out] */ long *nTargets);
+
+private:
+ static BSTR relationToBSTR(QAccessible::Relation relation)
+ {
+ wchar_t *constRelationString = 0;
+ switch (relation) {
+ case QAccessible::Controlled:
+ constRelationString = IA2_RELATION_CONTROLLED_BY;
+ break;
+ }
+
+ if (constRelationString) {
+ BSTR bstrVal;
+ const UINT wlen = (UINT)wcslen(constRelationString);
+ bstrVal = ::SysAllocStringLen(constRelationString, wlen);
+ return bstrVal;
+ }
+ return 0;
+ }
+
+
+ QList<QAccessibleInterface *> m_targets;
+ QAccessible::Relation m_relation;
+ ULONG m_ref;
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY
+
+#endif // IACCESSIBLE2_H
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
new file mode 100644
index 0000000000..4f92b910b2
--- /dev/null
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
@@ -0,0 +1,319 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QtConfig>
+#ifndef QT_NO_ACCESSIBILITY
+
+
+#include <private/qsystemlibrary_p.h>
+
+#include <QtCore/qlocale.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qsettings.h>
+#include <QtGui/qaccessible.h>
+#include <QtGui/qaccessible2.h>
+#include <QtGui/qplatformnativeinterface_qpa.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qguiapplication.h>
+
+#include "qwindowsaccessibility.h"
+
+#ifndef Q_CC_MINGW
+# include "iaccessible2.h"
+#endif // !Q_CC_MINGW
+
+#include "comutils.h"
+
+#include <oleacc.h>
+
+//#include <uiautomationcoreapi.h>
+#ifndef UiaRootObjectId
+#define UiaRootObjectId -25
+#endif
+
+#include <winuser.h>
+#if !defined(WINABLEAPI)
+# if defined(Q_OS_WINCE)
+# include <bldver.h>
+# endif
+# include <winable.h>
+#endif
+
+#include <oleacc.h>
+#include <servprov.h>
+#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
+#include <comdef.h>
+#endif
+
+#ifdef Q_OS_WINCE
+#include "../qguifunctions_wince.h"
+#endif
+
+#include "../qtwindows_additional.h"
+
+
+// This stuff is used for widgets/items with no window handle:
+typedef QMap<int, QPair<QObject*,int> > NotifyMap;
+Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents)
+
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \!internal
+ \class QWindowsAccessibility
+
+ Implements QPlatformAccessibility
+
+*/
+QWindowsAccessibility::QWindowsAccessibility()
+{
+}
+
+void QWindowsAccessibility::notifyAccessibilityUpdate(const QAccessibleEvent &event)
+{
+ QString soundName;
+ switch (event.type()) {
+ case QAccessible::PopupMenuStart:
+ soundName = QLatin1String("MenuPopup");
+ break;
+
+ case QAccessible::MenuCommand:
+ soundName = QLatin1String("MenuCommand");
+ break;
+
+ case QAccessible::Alert:
+ {
+ /* ### FIXME
+#ifndef QT_NO_MESSAGEBOX
+ QMessageBox *mb = qobject_cast<QMessageBox*>(o);
+ if (mb) {
+ switch (mb->icon()) {
+ case QMessageBox::Warning:
+ soundName = QLatin1String("SystemExclamation");
+ break;
+ case QMessageBox::Critical:
+ soundName = QLatin1String("SystemHand");
+ break;
+ case QMessageBox::Information:
+ soundName = QLatin1String("SystemAsterisk");
+ break;
+ default:
+ break;
+ }
+ } else
+#endif // QT_NO_MESSAGEBOX
+*/
+ {
+ soundName = QLatin1String("SystemAsterisk");
+ }
+
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!soundName.isEmpty()) {
+#ifndef QT_NO_SETTINGS
+ QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + soundName,
+ QSettings::NativeFormat);
+ QString file = settings.value(QLatin1String(".Current/.")).toString();
+#else
+ QString file;
+#endif
+ if (!file.isEmpty()) {
+ PlaySound(reinterpret_cast<const wchar_t *>(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT);
+ }
+ }
+
+ typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
+
+#if defined(Q_OS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
+ // There is no user32.lib nor NotifyWinEvent for CE
+ return;
+#else
+ static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
+ static bool resolvedNWE = false;
+ if (!resolvedNWE) {
+ resolvedNWE = true;
+ ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
+ }
+ if (!ptrNotifyWinEvent)
+ return;
+
+ // An event has to be associated with a window,
+ // so find the first parent that is a widget and that has a WId
+ QAccessibleInterface *iface = event.accessibleInterface();
+ QWindow *window = iface ? QWindowsAccessibility::windowHelper(iface) : 0;
+ delete iface;
+
+ if (!window) {
+ window = QGuiApplication::activeWindow();
+ if (!window)
+ return;
+ }
+
+ QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
+ HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window);
+
+ static int eventNum = 0;
+ if (event.type() != QAccessible::MenuCommand) { // MenuCommand is faked
+ // See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE"
+ eventNum %= 50; //[0..49]
+ int eventId = - (eventNum - 1);
+
+ qAccessibleRecentSentEvents()->insert(eventId, qMakePair(event.object(), event.child()));
+ ptrNotifyWinEvent(event.type(), hWnd, OBJID_CLIENT, eventId );
+
+ ++eventNum;
+ }
+#endif // Q_OS_WINCE
+}
+
+QWindow *QWindowsAccessibility::windowHelper(const QAccessibleInterface *iface)
+{
+ QWindow *window = iface->window();
+ if (!window) {
+ QAccessibleInterface *acc = iface->parent();
+ while (acc && !window) {
+ window = acc->window();
+ QAccessibleInterface *par = acc->parent();
+ delete acc;
+ acc = par;
+ }
+ }
+ return window;
+}
+
+/*!
+ \internal
+ helper to wrap a QAccessibleInterface inside a IAccessible*
+*/
+IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc)
+{
+#ifdef Q_CC_MINGW
+ return 0;
+#else
+ if (!acc)
+ return 0;
+ QWindowsIA2Accessible *wacc = new QWindowsIA2Accessible(acc);
+ IAccessible *iacc = 0;
+ wacc->QueryInterface(IID_IAccessible, (void**)&iacc);
+ return iacc;
+#endif
+}
+
+/*!
+ \internal
+*/
+QPair<QObject*, int> QWindowsAccessibility::getCachedObject(int entryId)
+{
+ return qAccessibleRecentSentEvents()->value(entryId);
+}
+
+/*
+void QWindowsAccessibility::setRootObject(QObject *o)
+{
+
+}
+
+void QWindowsAccessibility::initialize()
+{
+
+}
+
+void QWindowsAccessibility::cleanup()
+{
+
+}
+
+*/
+
+bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
+{
+ if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) {
+ /* For UI Automation */
+ } else if ((DWORD)lParam == OBJID_CLIENT) {
+#if 1
+ // Ignoring all requests while starting up
+ // ### Maybe QPA takes care of this???
+ if (QCoreApplication::startingUp() || QCoreApplication::closingDown())
+ return false;
+#endif
+
+ typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN);
+ static PtrLresultFromObject ptrLresultFromObject = 0;
+ static bool oleaccChecked = false;
+
+ if (!oleaccChecked) {
+ oleaccChecked = true;
+#if !defined(Q_OS_WINCE)
+ ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject");
+#endif
+ }
+
+ if (ptrLresultFromObject) {
+ QWindow *window = QWindowsContext::instance()->findWindow(hwnd);
+ if (window) {
+ QAccessibleInterface *acc = window->accessibleRoot();
+ if (acc) {
+ if (IAccessible *iface = wrap(acc)) {
+ *lResult = ptrLresultFromObject(IID_IAccessible, wParam, iface); // ref == 2
+ if (*lResult) {
+ iface->Release(); // the client will release the object again, and then it will destroy itself
+ }
+ return true;
+ } else {
+ delete acc;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
new file mode 100644
index 0000000000..0c3aca0a03
--- /dev/null
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSACCESSIBILITY_H
+#define QWINDOWSACCESSIBILITY_H
+
+#include "../qtwindowsglobal.h"
+#include "../qwindowscontext.h"
+#include <QtGui/QPlatformAccessibility>
+
+#include <oleacc.h>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QWindowsAccessibility : public QPlatformAccessibility
+{
+public:
+ QWindowsAccessibility();
+ static bool handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
+ virtual void notifyAccessibilityUpdate(const QAccessibleEvent &event);
+ /*
+ virtual void setRootObject(QObject *o);
+ virtual void initialize();
+ virtual void cleanup();
+ */
+ static IAccessible *wrap(QAccessibleInterface *acc);
+ static QWindow *windowHelper(const QAccessibleInterface *iface);
+
+ static QPair<QObject*, int> getCachedObject(int entryId);
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // QWINDOWSACCESSIBILITY_H
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
new file mode 100644
index 0000000000..8791bbdcfb
--- /dev/null
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
@@ -0,0 +1,1213 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QtConfig>
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "qwindowsmsaaaccessible.h"
+#include "qwindowsaccessibility.h"
+#include <oleacc.h>
+#include <servprov.h>
+#include <winuser.h>
+#include "comutils.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qsettings.h>
+#include <QtGui/qaccessible.h>
+#include <QtGui/qaccessible2.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qplatformnativeinterface_qpa.h>
+#include <QtGui/qwindow.h>
+#include <QtWidgets/qapplication.h>
+#include <QtWidgets/qgraphicsitem.h>
+#include <QtWidgets/qgraphicsview.h>
+#include <QtWidgets/qmessagebox.h>
+
+//#include <uiautomationcoreapi.h>
+#ifndef UiaRootObjectId
+#define UiaRootObjectId -25
+#endif
+
+#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
+#include <comdef.h>
+#endif
+
+#ifdef Q_OS_WINCE
+#include "../qguifunctions_wince.h"
+#endif
+
+#include "../qtwindows_additional.h"
+
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsEnumerate : public IEnumVARIANT
+{
+public:
+ QWindowsEnumerate(const QVector<int> &a)
+ : ref(0), current(0),array(a)
+ {
+ }
+
+ virtual ~QWindowsEnumerate() {}
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **ppEnum);
+ HRESULT STDMETHODCALLTYPE Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched);
+ HRESULT STDMETHODCALLTYPE Reset();
+ HRESULT STDMETHODCALLTYPE Skip(unsigned long celt);
+
+private:
+ ULONG ref;
+ ULONG current;
+ QVector<int> array;
+};
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::QueryInterface(REFIID id, LPVOID *iface)
+{
+ *iface = 0;
+ if (id == IID_IUnknown)
+ *iface = (IUnknown*)this;
+ else if (id == IID_IEnumVARIANT)
+ *iface = (IEnumVARIANT*)this;
+
+ if (*iface) {
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsEnumerate::AddRef()
+{
+ return ++ref;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsEnumerate::Release()
+{
+ if (!--ref) {
+ delete this;
+ return 0;
+ }
+ return ref;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone(IEnumVARIANT **ppEnum)
+{
+ QWindowsEnumerate *penum = 0;
+ *ppEnum = 0;
+
+ penum = new QWindowsEnumerate(array);
+ if (!penum)
+ return E_OUTOFMEMORY;
+ penum->current = current;
+ penum->array = array;
+ penum->AddRef();
+ *ppEnum = penum;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched)
+{
+ if (pCeltFetched)
+ *pCeltFetched = 0;
+
+ ULONG l;
+ for (l = 0; l < celt; l++) {
+ VariantInit(&rgVar[l]);
+ if ((current+1) > (ULONG)array.size()) {
+ *pCeltFetched = l;
+ return S_FALSE;
+ }
+
+ rgVar[l].vt = VT_I4;
+ rgVar[l].lVal = array[(int)current];
+ ++current;
+ }
+ *pCeltFetched = l;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Reset()
+{
+ current = 0;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt)
+{
+ current += celt;
+ if (current > (ULONG)array.size()) {
+ current = array.size();
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+static bool compareAccessible(QAccessibleInterface *one, QAccessibleInterface *other)
+{
+ if (one == other) return true;
+ if (!one || !other) return false;
+
+ if (one->object() && other->object() && (one->object() == other->object()))
+ return true;
+ QAIPointer onePar(one->parent());
+ QAIPointer otherPar(other->parent());
+
+ if (compareAccessible(onePar.data(), otherPar.data()))
+ return onePar->indexOfChild(one) == otherPar->indexOfChild(other);
+ return false;
+}
+
+#ifndef QT_NO_DEBUG
+bool debug_accessibility()
+{
+ static int debugging = -1;
+ if (debugging == -1)
+ debugging = qgetenv("QT_DEBUG_ACCESSIBILITY").toInt();
+ return !!debugging;
+}
+#endif
+
+#if defined(DEBUG_SHOW_ATCLIENT_COMMANDS)
+void accessibleDebugClientCalls_helper(const char* funcName, const QAccessibleInterface *iface)
+{
+ QString str;
+ QDebug dbg(&str);
+ dbg << iface << QLatin1String(funcName);
+ accessibleDebug("%s", qPrintable(str));
+}
+#endif
+
+/*
+ IDispatch
+*/
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::GetTypeInfoCount(unsigned int * pctinfo)
+{
+ // We don't use a type library
+ *pctinfo = 0;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::GetTypeInfo(unsigned int, unsigned long, ITypeInfo **pptinfo)
+{
+ // We don't use a type library
+ *pptinfo = 0;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::GetIDsOfNames(const _GUID &, wchar_t **rgszNames, unsigned int, unsigned long, long *rgdispid)
+{
+#if !defined(Q_CC_BOR) && !defined(Q_CC_GNU)
+ // PROPERTIES: Hierarchical
+ if (_bstr_t(rgszNames[0]) == _bstr_t(L"accParent"))
+ rgdispid[0] = DISPID_ACC_PARENT;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount"))
+ rgdispid[0] = DISPID_ACC_CHILDCOUNT;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accChild"))
+ rgdispid[0] = DISPID_ACC_CHILD;
+
+ // PROPERTIES: Descriptional
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accName("))
+ rgdispid[0] = DISPID_ACC_NAME;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accValue"))
+ rgdispid[0] = DISPID_ACC_VALUE;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription"))
+ rgdispid[0] = DISPID_ACC_DESCRIPTION;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accRole"))
+ rgdispid[0] = DISPID_ACC_ROLE;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accState"))
+ rgdispid[0] = DISPID_ACC_STATE;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp"))
+ rgdispid[0] = DISPID_ACC_HELP;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic"))
+ rgdispid[0] = DISPID_ACC_HELPTOPIC;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut"))
+ rgdispid[0] = DISPID_ACC_KEYBOARDSHORTCUT;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus"))
+ rgdispid[0] = DISPID_ACC_FOCUS;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection"))
+ rgdispid[0] = DISPID_ACC_SELECTION;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction"))
+ rgdispid[0] = DISPID_ACC_DEFAULTACTION;
+
+ // METHODS
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect"))
+ rgdispid[0] = DISPID_ACC_SELECT;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation"))
+ rgdispid[0] = DISPID_ACC_LOCATION;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate"))
+ rgdispid[0] = DISPID_ACC_NAVIGATE;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest"))
+ rgdispid[0] = DISPID_ACC_HITTEST;
+ else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction"))
+ rgdispid[0] = DISPID_ACC_DODEFAULTACTION;
+ else
+ return DISP_E_UNKNOWNINTERFACE;
+
+ return S_OK;
+#else
+ Q_UNUSED(rgszNames);
+ Q_UNUSED(rgdispid);
+
+ return DISP_E_MEMBERNOTFOUND;
+#endif
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::Invoke(long dispIdMember,
+ const _GUID &,
+ unsigned long,
+ unsigned short wFlags,
+ tagDISPPARAMS *pDispParams,
+ tagVARIANT *pVarResult,
+ tagEXCEPINFO *, unsigned int *)
+{
+ HRESULT hr = DISP_E_MEMBERNOTFOUND;
+
+ switch (dispIdMember)
+ {
+ case DISPID_ACC_PARENT:
+ if (wFlags == DISPATCH_PROPERTYGET) {
+ if (!pVarResult)
+ return E_INVALIDARG;
+ hr = get_accParent(&pVarResult->pdispVal);
+ } else {
+ hr = DISP_E_MEMBERNOTFOUND;
+ }
+ break;
+
+ case DISPID_ACC_CHILDCOUNT:
+ if (wFlags == DISPATCH_PROPERTYGET) {
+ if (!pVarResult)
+ return E_INVALIDARG;
+ hr = get_accChildCount(&pVarResult->lVal);
+ } else {
+ hr = DISP_E_MEMBERNOTFOUND;
+ }
+ break;
+
+ case DISPID_ACC_CHILD:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accChild(pDispParams->rgvarg[0], &pVarResult->pdispVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_NAME:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accName(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else if (wFlags == DISPATCH_PROPERTYPUT)
+ hr = put_accName(pDispParams->rgvarg[0], pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_VALUE:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accValue(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else if (wFlags == DISPATCH_PROPERTYPUT)
+ hr = put_accValue(pDispParams->rgvarg[0], pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_DESCRIPTION:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accDescription(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_ROLE:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accRole(pDispParams->rgvarg[0], pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_STATE:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accState(pDispParams->rgvarg[0], pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_HELP:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accHelp(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_HELPTOPIC:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accHelpTopic(&pDispParams->rgvarg[2].bstrVal, pDispParams->rgvarg[1], &pDispParams->rgvarg[0].lVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_KEYBOARDSHORTCUT:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accKeyboardShortcut(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_FOCUS:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accFocus(pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_SELECTION:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accSelection(pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_DEFAULTACTION:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accDefaultAction(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_SELECT:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accSelect(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_LOCATION:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accLocation(&pDispParams->rgvarg[4].lVal, &pDispParams->rgvarg[3].lVal, &pDispParams->rgvarg[2].lVal, &pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_NAVIGATE:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accNavigate(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0], pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_HITTEST:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accHitTest(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].lVal, pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_DODEFAULTACTION:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accDoDefaultAction(pDispParams->rgvarg[0]);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ default:
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+ }
+
+ if (!SUCCEEDED(hr)) {
+ return hr;
+ }
+ return hr;
+}
+
+/*
+ IAccessible
+
+IAccessible::accHitTest documents the value returned in pvarID like this:
+
+| *Point location* | *vt member* | *Value member* |
++========================================================+=============+=========================+
+| Outside of the object's boundaries, and either inside | VT_EMPTY | None. |
+| or outside of the object's bounding rectangle. | | |
++--------------------------------------------------------+-------------+-------------------------+
+| Within the object but not within a child element or a | VT_I4 | lVal is CHILDID_SELF |
+| child object. | | |
++--------------------------------------------------------+-------------+-------------------------+
+| Within a child element. | VT_I4 | lVal contains |
+| | | the child ID. |
++--------------------------------------------------------+-------------+-------------------------+
+| Within a child object. | VT_DISPATCH | pdispVal is set to the |
+| | | child object's IDispatch|
+| | | interface pointer |
++--------------------------------------------------------+-------------+-------------------------+
+*/
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *child = accessible->childAt(xLeft, yTop);
+ if (child == 0) {
+ // no child found, return this item if it contains the coordinates
+ if (accessible->rect().contains(xLeft, yTop)) {
+ (*pvarID).vt = VT_I4;
+ (*pvarID).lVal = CHILDID_SELF;
+ return S_OK;
+ }
+ } else {
+ IAccessible *iface = QWindowsAccessibility::wrap(child);
+ if (iface) {
+ (*pvarID).vt = VT_DISPATCH;
+ (*pvarID).pdispVal = iface;
+ return S_OK;
+ }
+ }
+
+ // Did not find anything
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+/*
+ It is recommended to read
+ "Implementing a Microsoft Active Accessibility (MSAA) Server.
+ Practical Tips for Developers and How Mozilla Does It"
+ (https://developer.mozilla.org/En/Accessibility/Implementing_an_MSAA_Server)
+
+ to get an overview of what's important to implement and what parts of MSAA
+ can be ignored. All stuff prefixed with "moz" are information from that page.
+*/
+// moz: [important]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QRect rect;
+ if (varID.lVal) {
+ QAIPointer child = QAIPointer(accessible->child(varID.lVal - 1));
+ if (child->isValid())
+ rect = child->rect();
+ } else {
+ rect = accessible->rect();
+ }
+
+ *pxLeft = rect.x();
+ *pyTop = rect.y();
+ *pcxWidth = rect.width();
+ *pcyHeight = rect.height();
+
+ return S_OK;
+}
+
+// moz: [important, but no need to implement up/down/left/right]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *acc = 0;
+ switch (navDir) {
+ case NAVDIR_FIRSTCHILD:
+ acc = accessible->child(0);
+ break;
+ case NAVDIR_LASTCHILD:
+ acc = accessible->child(accessible->childCount() - 1);
+ break;
+ case NAVDIR_NEXT:
+ case NAVDIR_PREVIOUS:
+ if (!varStart.lVal){
+ QAccessibleInterface *parent = accessible->parent();
+ if (parent) {
+ int index = parent->indexOfChild(accessible);
+ index += (navDir == NAVDIR_NEXT) ? 1 : -1;
+ if (index >= 0 && index < parent->childCount())
+ acc = parent->child(index);
+ delete parent;
+ }
+ } else {
+ int index = varStart.lVal;
+ index += (navDir == NAVDIR_NEXT) ? 1 : -1;
+ if (index > 0 && index <= accessible->childCount())
+ acc = accessible->child(index - 1);
+ }
+ break;
+
+ // Geometrical
+ case NAVDIR_UP:
+ case NAVDIR_DOWN:
+ case NAVDIR_LEFT:
+ case NAVDIR_RIGHT:
+ if (QAccessibleInterface *pIface = accessible->parent()) {
+ const int indexOfOurself = pIface->indexOfChild(accessible);
+ QRect startg = accessible->rect();
+ QPoint startc = startg.center();
+ QAccessibleInterface *candidate = 0;
+ unsigned mindist = UINT_MAX; // will work on screen sizes at least up to 46340x46340
+ const int sibCount = pIface->childCount();
+ for (int i = 0; i < sibCount; ++i) {
+ QAccessibleInterface *sibling = 0;
+ sibling = pIface->child(i);
+ Q_ASSERT(sibling);
+ if (i == indexOfOurself || sibling->state().invisible) {
+ //ignore ourself and invisible siblings
+ delete sibling;
+ continue;
+ }
+
+ QRect sibg = sibling->rect();
+ QPoint sibc = sibg.center();
+ QPoint sibp;
+ QPoint startp;
+ QPoint distp;
+ switch (navDir) {
+ case NAVDIR_LEFT:
+ startp = QPoint(startg.left(), startg.top() + startg.height() / 2);
+ sibp = QPoint(sibg.right(), sibg.top() + sibg.height() / 2);
+ if (QPoint(sibc - startc).x() >= 0) {
+ delete sibling;
+ continue;
+ }
+ distp = sibp - startp;
+ break;
+ case NAVDIR_RIGHT:
+ startp = QPoint(startg.right(), startg.top() + startg.height() / 2);
+ sibp = QPoint(sibg.left(), sibg.top() + sibg.height() / 2);
+ if (QPoint(sibc - startc).x() <= 0) {
+ delete sibling;
+ continue;
+ }
+ distp = sibp - startp;
+ break;
+ case NAVDIR_UP:
+ startp = QPoint(startg.left() + startg.width() / 2, startg.top());
+ sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.bottom());
+ if (QPoint(sibc - startc).y() >= 0) {
+ delete sibling;
+ continue;
+ }
+ distp = sibp - startp;
+ break;
+ case NAVDIR_DOWN:
+ startp = QPoint(startg.left() + startg.width() / 2, startg.bottom());
+ sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.top());
+ if (QPoint(sibc - startc).y() <= 0) {
+ delete sibling;
+ continue;
+ }
+ distp = sibp - startp;
+ break;
+ default:
+ break;
+ }
+
+ // Since we're *comparing* (and not measuring) distances, we can compare the
+ // squared distance, (thus, no need to take the sqrt()).
+ unsigned dist = distp.x() * distp.x() + distp.y() * distp.y();
+ if (dist < mindist) {
+ delete candidate;
+ candidate = sibling;
+ mindist = dist;
+ } else {
+ delete sibling;
+ }
+ }
+ delete pIface;
+ acc = candidate;
+ }
+ break;
+ default:
+ break;
+ }
+ if (!acc) {
+ (*pvarEnd).vt = VT_EMPTY;
+ return S_FALSE;
+ }
+
+ if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) {
+ (*pvarEnd).vt = VT_DISPATCH;
+ (*pvarEnd).pdispVal = iface;
+ return S_OK;
+ } else {
+ if (acc != accessible)
+ delete acc;
+ }
+
+ (*pvarEnd).vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+// moz: [important]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (varChildID.vt != VT_I4)
+ return E_INVALIDARG;
+
+
+ int childIndex = varChildID.lVal;
+ QAccessibleInterface *acc = 0;
+
+ if (childIndex < 0) {
+ const int entry = childIndex;
+ QPair<QObject*, int> ref = QWindowsAccessibility::getCachedObject(entry);
+ if (ref.first) {
+ acc = QAccessible::queryAccessibleInterface(ref.first);
+ if (acc && ref.second >= 0) {
+ QAccessibleInterface *res = acc->child(ref.second);
+ delete acc;
+ if (!res)
+ return E_INVALIDARG;
+ acc = res;
+ }
+ } else {
+ qWarning("get_accChild got a negative varChildID, but did not find it in cache");
+ }
+ } else {
+ if (childIndex) {
+ acc = accessible->child(childIndex - 1);
+ } else {
+ // Yes, some AT clients (Active Accessibility Object Inspector)
+ // actually ask for the same object. As a consequence, we need to clone ourselves:
+ if (QAccessibleInterface *par = accessible->parent()) {
+ const int indexOf = par->indexOfChild(accessible);
+ QAccessibleInterface *clone = par->child(indexOf);
+ delete par;
+ acc = clone;
+ }
+ }
+ }
+
+ if (acc) {
+ *ppdispChild = QWindowsAccessibility::wrap(acc);
+ return S_OK;
+ }
+
+ return E_FAIL;
+}
+
+// moz: [important]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChildCount(long* pcountChildren)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *pcountChildren = accessible->childCount();
+ return S_OK;
+}
+
+// moz: [important]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accParent(IDispatch** ppdispParent)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *acc = accessible->parent();
+ if (acc) {
+ if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) {
+ *ppdispParent = iface;
+ return S_OK;
+ } else {
+ delete acc;
+ }
+ }
+
+ *ppdispParent = 0;
+ return S_FALSE;
+}
+
+/*
+ Properties and methods
+*/
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accDoDefaultAction(VARIANT varID)
+{
+ Q_UNUSED(varID);
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
+ const QString def = actionIface->actionNames().value(0);
+ if (!def.isEmpty()) {
+ actionIface->doAction(def);
+ return S_OK;
+ }
+ }
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction)
+{
+ Q_UNUSED(varID);
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *pszDefaultAction = 0;
+ if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
+ const QString def = actionIface->actionNames().value(0);
+ if (!def.isEmpty())
+ *pszDefaultAction = QStringToBSTR(def);
+ }
+ return *pszDefaultAction ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+
+ QString descr;
+ if (varID.lVal) {
+ QAIPointer child = childPointer(varID);
+ if (!child)
+ return E_FAIL;
+ descr = child->text(QAccessible::Description);
+ } else {
+ descr = accessible->text(QAccessible::Description);
+ }
+ if (descr.size()) {
+ *pszDescription = QStringToBSTR(descr);
+ return S_OK;
+ }
+
+ *pszDescription = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString help;
+ if (varID.lVal) {
+ QAIPointer child = childPointer(varID);
+ if (!child)
+ return E_FAIL;
+ help = child->text(QAccessible::Help);
+ } else {
+ help = accessible->text(QAccessible::Help);
+ }
+ if (help.size()) {
+ *pszHelp = QStringToBSTR(help);
+ return S_OK;
+ }
+
+ *pszHelp = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
+{
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut)
+{
+ Q_UNUSED(varID);
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *pszKeyboardShortcut = 0;
+ if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
+ const QString def = actionIface->actionNames().value(0);
+ if (!def.isEmpty()) {
+ const QString keyBoardShortCut = actionIface->keyBindingsForAction(def).value(0);
+ if (!keyBoardShortCut.isEmpty())
+ *pszKeyboardShortcut = QStringToBSTR(keyBoardShortCut);
+ }
+ }
+ return *pszKeyboardShortcut ? S_OK : S_FALSE;
+}
+
+static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAccessible::RelationFlag flag)
+{
+ typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationPair;
+ QVector<RelationPair> rels = iface->relations(flag);
+
+ for (int i = 1; i < rels.count(); ++i)
+ delete rels.at(i).first;
+
+ return rels.value(0).first;
+}
+
+// moz: [important]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BSTR* pszName)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString name;
+ if (varID.lVal) {
+ QAIPointer child = childPointer(varID);
+ if (!child)
+ return E_FAIL;
+ name = child->text(QAccessible::Name);
+ if (name.isEmpty()) {
+ if (QAccessibleInterface *labelInterface = relatedInterface(child.data(), QAccessible::Label)) {
+ name = labelInterface->text(QAccessible::Name);
+ delete labelInterface;
+ }
+ }
+ } else {
+ name = accessible->text(QAccessible::Name);
+ if (name.isEmpty()) {
+ if (QAccessibleInterface *labelInterface = relatedInterface(accessible, QAccessible::Label)) {
+ name = labelInterface->text(QAccessible::Name);
+ delete labelInterface;
+ }
+ }
+ }
+ if (name.size()) {
+ *pszName = QStringToBSTR(name);
+ return S_OK;
+ }
+
+ *pszName = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accName(VARIANT, BSTR)
+{
+ accessibleDebugClientCalls(accessible);
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+// moz: [important]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessible::Role role;
+ if (varID.lVal) {
+ QAIPointer child = childPointer(varID);
+ if (!child)
+ return E_FAIL;
+ role = child->role();
+ } else {
+ role = accessible->role();
+ }
+
+ if (role != QAccessible::NoRole) {
+ if (role == QAccessible::LayeredPane)
+ role = QAccessible::Pane;
+ (*pvarRole).vt = VT_I4;
+ (*pvarRole).lVal = role;
+ } else {
+ (*pvarRole).vt = VT_EMPTY;
+ }
+ return S_OK;
+}
+
+// moz: [important]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accState(VARIANT varID, VARIANT *pvarState)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessible::State state;
+ if (varID.lVal) {
+ QAIPointer child = childPointer(varID);
+ if (!child.data())
+ return E_FAIL;
+ state = child->state();
+ } else {
+ state = accessible->state();
+ }
+
+ LONG st = 0;
+ if (state.animated)
+ st |= STATE_SYSTEM_ANIMATED;
+ if (state.busy)
+ st |= STATE_SYSTEM_BUSY;
+ if (state.checked)
+ st |= STATE_SYSTEM_CHECKED;
+ if (state.collapsed)
+ st |= STATE_SYSTEM_COLLAPSED;
+ if (state.defaultButton)
+ st |= STATE_SYSTEM_DEFAULT;
+ if (state.expanded)
+ st |= STATE_SYSTEM_EXPANDED;
+ if (state.extSelectable)
+ st |= STATE_SYSTEM_EXTSELECTABLE;
+ if (state.focusable)
+ st |= STATE_SYSTEM_FOCUSABLE;
+ if (state.focused)
+ st |= STATE_SYSTEM_FOCUSED;
+ if (state.hasPopup)
+ st |= STATE_SYSTEM_HASPOPUP;
+ if (state.hotTracked)
+ st |= STATE_SYSTEM_HOTTRACKED;
+ if (state.invisible)
+ st |= STATE_SYSTEM_INVISIBLE;
+ if (state.linked)
+ st |= STATE_SYSTEM_LINKED;
+ if (state.marqueed)
+ st |= STATE_SYSTEM_MARQUEED;
+ if (state.checkStateMixed)
+ st |= STATE_SYSTEM_MIXED;
+ if (state.movable)
+ st |= STATE_SYSTEM_MOVEABLE;
+ if (state.multiSelectable)
+ st |= STATE_SYSTEM_MULTISELECTABLE;
+ if (state.offscreen)
+ st |= STATE_SYSTEM_OFFSCREEN;
+ if (state.pressed)
+ st |= STATE_SYSTEM_PRESSED;
+ if (state.passwordEdit)
+ st |= STATE_SYSTEM_PROTECTED;
+ if (state.readOnly)
+ st |= STATE_SYSTEM_READONLY;
+ if (state.selectable)
+ st |= STATE_SYSTEM_SELECTABLE;
+ if (state.selected)
+ st |= STATE_SYSTEM_SELECTED;
+ if (state.selfVoicing)
+ st |= STATE_SYSTEM_SELFVOICING;
+ if (state.sizeable)
+ st |= STATE_SYSTEM_SIZEABLE;
+ if (state.traversed)
+ st |= STATE_SYSTEM_TRAVERSED;
+
+ (*pvarState).vt = VT_I4;
+ (*pvarState).lVal = st;
+ return S_OK;
+}
+
+// moz: [important]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BSTR* pszValue)
+{
+ accessibleDebugClientCalls(accessible);
+ if (varID.vt != VT_I4)
+ return E_INVALIDARG;
+
+ if (!accessible->isValid() || varID.lVal) {
+ return E_FAIL;
+ }
+
+ QString value;
+ if (accessible->valueInterface()) {
+ value = QString::number(accessible->valueInterface()->currentValue().toDouble());
+ } else {
+ value = accessible->text(QAccessible::Value);
+ }
+ if (!value.isNull()) {
+ *pszValue = QStringToBSTR(value);
+ return S_OK;
+ }
+
+ *pszValue = 0;
+ accessibleDebug("return S_FALSE");
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accValue(VARIANT, BSTR)
+{
+ accessibleDebugClientCalls(accessible);
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+// moz: [important]
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accSelect(long flagsSelect, VARIANT varID)
+{
+ Q_UNUSED(flagsSelect);
+ Q_UNUSED(varID);
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ bool res = false;
+
+/*
+ ### Check for accessibleTableInterface() or accessibleTextInterface()
+
+ ### and if there are no ia2 interfaces we should do nothing??
+ if (flagsSelect & SELFLAG_TAKEFOCUS)
+ res = accessible->doAction(SetFocus, varID.lVal, QVariantList());
+ if (flagsSelect & SELFLAG_TAKESELECTION) {
+ accessible->doAction(ClearSelection, 0, QVariantList());
+ res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
+ }
+ if (flagsSelect & SELFLAG_EXTENDSELECTION)
+ res = accessible->doAction(ExtendSelection, varID.lVal, QVariantList());
+ if (flagsSelect & SELFLAG_ADDSELECTION)
+ res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
+ if (flagsSelect & SELFLAG_REMOVESELECTION)
+ res = accessible->doAction(RemoveSelection, varID.lVal, QVariantList());
+*/
+ return res ? S_OK : S_FALSE;
+}
+
+/*!
+ \internal
+ Can return:
+
+ +-------------+------------------------------------------------------------------------------+
+ | VT_EMPTY | None. Neither this object nor any of its children has the keyboard focus. |
+ +-------------+------------------------------------------------------------------------------+
+ | VT_I4 | lVal is CHILDID_SELF. The object itself has the keyboard focus. |
+ +-------------+------------------------------------------------------------------------------+
+ | VT_I4 | lVal contains the child ID of the child element that has the keyboard focus. |
+ +-------------+------------------------------------------------------------------------------+
+ | VT_DISPATCH | pdispVal member is the address of the IDispatch interface for the child |
+ | | object that has the keyboard focus. |
+ +-------------+------------------------------------------------------------------------------+
+ moz: [important]
+*/
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accFocus(VARIANT *pvarID)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (QAccessibleInterface *acc = accessible->focusChild()) {
+ if (compareAccessible(acc, accessible)) {
+ (*pvarID).vt = VT_I4;
+ (*pvarID).lVal = CHILDID_SELF;
+ delete acc;
+ return S_OK;
+ } else {
+ if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) {
+ (*pvarID).vt = VT_DISPATCH;
+ (*pvarID).pdispVal = iface;
+ return S_OK;
+ }
+ }
+ delete acc;
+ }
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accSelection(VARIANT *pvarChildren)
+{
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ int cc = accessible->childCount();
+ QVector<int> sel(cc);
+ int selIndex = 0;
+ for (int i = 0; i < cc; ++i) {
+ bool isSelected = false;
+ QAccessibleInterface *child = accessible->child(i);
+ if (child) {
+ isSelected = child->state().selected;
+ delete child;
+ }
+ if (isSelected)
+ sel[selIndex++] = i+1;
+ }
+ sel.resize(selIndex);
+ if (sel.isEmpty()) {
+ (*pvarChildren).vt = VT_EMPTY;
+ return S_FALSE;
+ }
+ if (sel.size() == 1) {
+ (*pvarChildren).vt = VT_I4;
+ (*pvarChildren).lVal = sel[0];
+ return S_OK;
+ }
+ IEnumVARIANT *iface = new QWindowsEnumerate(sel);
+ IUnknown *uiface;
+ iface->QueryInterface(IID_IUnknown, (void**)&uiface);
+ (*pvarChildren).vt = VT_UNKNOWN;
+ (*pvarChildren).punkVal = uiface;
+
+ return S_OK;
+}
+
+/**************************************************************\
+ * IOleWindow *
+ **************************************************************/
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::GetWindow(HWND *phwnd)
+{
+ *phwnd = 0;
+ accessibleDebugClientCalls(accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+ if (!accessible->isValid())
+ return E_UNEXPECTED;
+
+ QWindow *window = QWindowsAccessibility::windowHelper(accessible);
+ if (!window)
+ return E_FAIL;
+
+ QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
+ Q_ASSERT(platform);
+ *phwnd = (HWND)platform->nativeResourceForWindow("handle", window);
+ accessibleDebug("QWindowsAccessible::GetWindow(): %p", *phwnd);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::ContextSensitiveHelp(BOOL)
+{
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
new file mode 100644
index 0000000000..9cb56c954c
--- /dev/null
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QWINDOWSMSAAACCESSIBLE_H
+#define QWINDOWSMSAAACCESSIBLE_H
+
+#include <QtCore/QtConfig>
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "../qtwindows_additional.h"
+#include <oleacc.h>
+#include "Accessible2.h"
+#include <QtCore/qsharedpointer.h>
+#include <QtGui/qaccessible.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_DEBUG
+bool debug_accessibility();
+# define accessibleDebug !debug_accessibility() ? (void)0 : qDebug
+#else
+# define accessibleDebug
+#endif
+
+#define DEBUG_SHOW_ATCLIENT_COMMANDS
+#if defined(DEBUG_SHOW_ATCLIENT_COMMANDS)
+void accessibleDebugClientCalls_helper(const char* funcName, const QAccessibleInterface *iface);
+# define accessibleDebugClientCalls(iface) accessibleDebugClientCalls_helper(Q_FUNC_INFO, iface)
+#else
+# define accessibleDebugClientCalls(iface)
+#endif
+
+typedef QSharedPointer<QAccessibleInterface> QAIPointer;
+
+QWindow *window_helper(const QAccessibleInterface *iface);
+
+/**************************************************************\
+ * QWindowsAccessible *
+ **************************************************************/
+class QWindowsMsaaAccessible : public IAccessible2, public IOleWindow
+{
+public:
+ QWindowsMsaaAccessible(QAccessibleInterface *a)
+ : accessible(a)
+ {
+ }
+
+ virtual ~QWindowsMsaaAccessible()
+ {
+ delete accessible;
+ }
+
+
+ /* IDispatch */
+ HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int *);
+ HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int, unsigned long, ITypeInfo **);
+ HRESULT STDMETHODCALLTYPE GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *);
+ HRESULT STDMETHODCALLTYPE Invoke(long, const _GUID &, unsigned long, unsigned short, tagDISPPARAMS *, tagVARIANT *, tagEXCEPINFO *, unsigned int *);
+
+ /* IAccessible */
+ HRESULT STDMETHODCALLTYPE accHitTest(long xLeft, long yTop, VARIANT *pvarID);
+ HRESULT STDMETHODCALLTYPE accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID);
+ HRESULT STDMETHODCALLTYPE accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd);
+ HRESULT STDMETHODCALLTYPE get_accChild(VARIANT varChildID, IDispatch** ppdispChild);
+ HRESULT STDMETHODCALLTYPE get_accChildCount(long* pcountChildren);
+ HRESULT STDMETHODCALLTYPE get_accParent(IDispatch** ppdispParent);
+
+ HRESULT STDMETHODCALLTYPE accDoDefaultAction(VARIANT varID);
+ HRESULT STDMETHODCALLTYPE get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction);
+ HRESULT STDMETHODCALLTYPE get_accDescription(VARIANT varID, BSTR* pszDescription);
+ HRESULT STDMETHODCALLTYPE get_accHelp(VARIANT varID, BSTR *pszHelp);
+ HRESULT STDMETHODCALLTYPE get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic);
+ HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut);
+ HRESULT STDMETHODCALLTYPE get_accName(VARIANT varID, BSTR* pszName);
+ HRESULT STDMETHODCALLTYPE put_accName(VARIANT varChild, BSTR szName);
+ HRESULT STDMETHODCALLTYPE get_accRole(VARIANT varID, VARIANT *pvarRole);
+ HRESULT STDMETHODCALLTYPE get_accState(VARIANT varID, VARIANT *pvarState);
+ HRESULT STDMETHODCALLTYPE get_accValue(VARIANT varID, BSTR* pszValue);
+ HRESULT STDMETHODCALLTYPE put_accValue(VARIANT varChild, BSTR szValue);
+
+ HRESULT STDMETHODCALLTYPE accSelect(long flagsSelect, VARIANT varID);
+ HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT *pvarID);
+ HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT *pvarChildren);
+
+ /* IOleWindow */
+ HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
+ HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
+
+protected:
+ QAccessibleInterface *accessible;
+
+ QAIPointer childPointer(VARIANT varID)
+ {
+ return QAIPointer(accessible->child(varID.lVal - 1));
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY
+
+#endif // QWINDOWSMSAAACCESSIBLE_H