summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorJan-Arve Saether <jan-arve.saether@nokia.com>2011-09-16 06:56:48 +0200
committerQt by Nokia <qt-info@nokia.com>2011-09-29 13:32:59 +0200
commit87ae97c11ab9b298c0ce6701873b45fc3992b385 (patch)
tree8f30a95f054b8bf2346a98e072ba864a7a974da5 /src/plugins
parent8ebd7d84fcdaeba152bd9812b45d5c49b1e03a23 (diff)
Refactor accessibility for Qt5
* Moved most stuff to gui\accessible * Moved widget-specific stuff to widgets\accessible * Moved platform-specific code to either the bridge plugin (this was already the case) or to the platform plugin. * Added several classes and functions. These have not yet gone through an API review. The plan is to do that in a later commit. Classes: - QPlatformAccessibility - QWindowsAccessibility Functions: - QWindow *QAccessibleInterface::window(); - QPlatformAccessibility *QPlatformIntegration::accessibility() * The bridge code can now either be a plugin or integrated into the platform plugin * Mac accessibility is left out for now. Unix "should still work" (tm). These platforms should be fixed soon. Change-Id: Ib49ffa73b647ee0af90864544c2769440157f562 Reviewed-on: http://codereview.qt-project.org/5330 Reviewed-by: Frederik Gladhorn <frederik.gladhorn@nokia.com> Reviewed-by: Jan-Arve Sæther <jan-arve.saether@nokia.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/accessible/widgets/complexwidgets.h2
-rw-r--r--src/plugins/accessible/widgets/itemviews.h4
-rw-r--r--src/plugins/accessible/widgets/main.cpp3
-rw-r--r--src/plugins/accessible/widgets/qaccessiblewidgets.h2
-rw-r--r--src/plugins/accessible/widgets/rangecontrols.h2
-rw-r--r--src/plugins/accessible/widgets/simplewidgets.h2
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsaccessibility.cpp1406
-rw-r--r--src/plugins/platforms/windows/qwindowsaccessibility.h61
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp7
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h1
-rw-r--r--src/plugins/platforms/windows/windows.pro8
13 files changed, 1495 insertions, 9 deletions
diff --git a/src/plugins/accessible/widgets/complexwidgets.h b/src/plugins/accessible/widgets/complexwidgets.h
index 8566fe6f0d..81f79fd235 100644
--- a/src/plugins/accessible/widgets/complexwidgets.h
+++ b/src/plugins/accessible/widgets/complexwidgets.h
@@ -45,7 +45,7 @@
#include <QtCore/qpointer.h>
#include <QtWidgets/qaccessiblewidget.h>
#include <QtWidgets/qabstractitemview.h>
-#include <QtWidgets/qaccessible2.h>
+#include <QtGui/qaccessible2.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/accessible/widgets/itemviews.h b/src/plugins/accessible/widgets/itemviews.h
index c2b255b424..41d2b6c4ef 100644
--- a/src/plugins/accessible/widgets/itemviews.h
+++ b/src/plugins/accessible/widgets/itemviews.h
@@ -44,8 +44,8 @@
#include <QtWidgets/qabstractitemview.h>
#include <QtWidgets/qheaderview.h>
-#include <QtWidgets/qaccessible.h>
-#include <QtWidgets/qaccessible2.h>
+#include <QtGui/qaccessible.h>
+#include <QtGui/qaccessible2.h>
#include <QtWidgets/qaccessiblewidget.h>
diff --git a/src/plugins/accessible/widgets/main.cpp b/src/plugins/accessible/widgets/main.cpp
index a7b3a95090..fb6bd1e95c 100644
--- a/src/plugins/accessible/widgets/main.cpp
+++ b/src/plugins/accessible/widgets/main.cpp
@@ -153,6 +153,7 @@ QStringList AccessibleFactory::keys() const
#ifndef QT_NO_DOCKWIDGET
list << QLatin1String("QDockWidget");
#endif
+ list << QLatin1String("QAccessibleWidget");
return list;
}
@@ -348,6 +349,8 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec
} else if (classname == QLatin1String("QDockWidget")) {
iface = new QAccessibleDockWidget(widget);
#endif
+ } else {
+ iface = new QAccessibleWidget(widget);
}
return iface;
diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.h b/src/plugins/accessible/widgets/qaccessiblewidgets.h
index bf3c769048..2a595d79dd 100644
--- a/src/plugins/accessible/widgets/qaccessiblewidgets.h
+++ b/src/plugins/accessible/widgets/qaccessiblewidgets.h
@@ -42,7 +42,7 @@
#ifndef QACCESSIBLEWIDGETS_H
#define QACCESSIBLEWIDGETS_H
-#include <QtWidgets/qaccessible2.h>
+#include <QtGui/qaccessible2.h>
#include <QtWidgets/qaccessiblewidget.h>
#ifndef QT_NO_ACCESSIBILITY
diff --git a/src/plugins/accessible/widgets/rangecontrols.h b/src/plugins/accessible/widgets/rangecontrols.h
index 30d8f0055b..39916a789a 100644
--- a/src/plugins/accessible/widgets/rangecontrols.h
+++ b/src/plugins/accessible/widgets/rangecontrols.h
@@ -43,7 +43,7 @@
#define RANGECONTROLS_H
#include <QtWidgets/qaccessiblewidget.h>
-#include <QtWidgets/qaccessible2.h>
+#include <QtGui/qaccessible2.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h
index aa68cf3626..122d086e74 100644
--- a/src/plugins/accessible/widgets/simplewidgets.h
+++ b/src/plugins/accessible/widgets/simplewidgets.h
@@ -43,7 +43,7 @@
#define SIMPLEWIDGETS_H
#include <QtCore/qcoreapplication.h>
-#include <QtWidgets/qaccessible2.h>
+#include <QtGui/qaccessible2.h>
#include <QtWidgets/qaccessiblewidget.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index 66d1858a6f..254463e445 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -88,6 +88,7 @@ enum WindowsEventType // Simplify event types
ClipboardEvent = ClipboardEventFlag + 1,
ActivateApplicationEvent = ApplicationEventFlag + 1,
DeactivateApplicationEvent = ApplicationEventFlag + 2,
+ AccessibleObjectFromWindowRequest = ApplicationEventFlag + 3,
InputMethodStartCompositionEvent = InputMethodEventFlag + 1,
InputMethodCompositionEvent = InputMethodEventFlag + 2,
InputMethodEndCompositionEvent = InputMethodEventFlag + 3,
@@ -166,6 +167,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
default:
break;
}
+ case WM_GETOBJECT:
+ return QtWindows::AccessibleObjectFromWindowRequest;
default:
break;
}
diff --git a/src/plugins/platforms/windows/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/qwindowsaccessibility.cpp
new file mode 100644
index 0000000000..fdc32730ad
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsaccessibility.cpp
@@ -0,0 +1,1406 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** 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 "qwindowsaccessibility.h"
+#include "qwindowscontext.h"
+
+#include <private/qsystemlibrary_p.h>
+
+#include <QtCore/qmap.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qpair.h>
+#include <QtWidgets/qapplication.h>
+#include <QtWidgets/qmessagebox.h>
+#include <QtWidgets/qgraphicsitem.h>
+#include <QtWidgets/qgraphicsview.h>
+#include <QtGui/qaccessible.h>
+#include <QtGui/qplatformnativeinterface_qpa.h>
+#include <QtGui/qwindow.h>
+#include "qt_windows.h"
+
+//#include <uiautomationcoreapi.h>
+#ifndef UiaRootObjectId
+#define UiaRootObjectId -25
+#endif
+
+#include <winuser.h>
+#if !defined(WINABLEAPI)
+# if defined(Q_WS_WINCE)
+# include <bldver.h>
+# endif
+# include <winable.h>
+#endif
+
+#include <oleacc.h>
+#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
+#include <comdef.h>
+#endif
+
+#ifdef Q_WS_WINCE
+#include "qguifunctions_wince.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//#define DEBUG_SHOW_ATCLIENT_COMMANDS
+#ifdef DEBUG_SHOW_ATCLIENT_COMMANDS
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <qdebug.h>
+QT_END_INCLUDE_NAMESPACE
+
+static const char *roleString(QAccessible::Role role)
+{
+ static const char *roles[] = {
+ "NoRole" /* = 0x00000000 */,
+ "TitleBar" /* = 0x00000001 */,
+ "MenuBar" /* = 0x00000002 */,
+ "ScrollBar" /* = 0x00000003 */,
+ "Grip" /* = 0x00000004 */,
+ "Sound" /* = 0x00000005 */,
+ "Cursor" /* = 0x00000006 */,
+ "Caret" /* = 0x00000007 */,
+ "AlertMessage" /* = 0x00000008 */,
+ "Window" /* = 0x00000009 */,
+ "Client" /* = 0x0000000A */,
+ "PopupMenu" /* = 0x0000000B */,
+ "MenuItem" /* = 0x0000000C */,
+ "ToolTip" /* = 0x0000000D */,
+ "Application" /* = 0x0000000E */,
+ "Document" /* = 0x0000000F */,
+ "Pane" /* = 0x00000010 */,
+ "Chart" /* = 0x00000011 */,
+ "Dialog" /* = 0x00000012 */,
+ "Border" /* = 0x00000013 */,
+ "Grouping" /* = 0x00000014 */,
+ "Separator" /* = 0x00000015 */,
+ "ToolBar" /* = 0x00000016 */,
+ "StatusBar" /* = 0x00000017 */,
+ "Table" /* = 0x00000018 */,
+ "ColumnHeader" /* = 0x00000019 */,
+ "RowHeader" /* = 0x0000001A */,
+ "Column" /* = 0x0000001B */,
+ "Row" /* = 0x0000001C */,
+ "Cell" /* = 0x0000001D */,
+ "Link" /* = 0x0000001E */,
+ "HelpBalloon" /* = 0x0000001F */,
+ "Assistant" /* = 0x00000020 */,
+ "List" /* = 0x00000021 */,
+ "ListItem" /* = 0x00000022 */,
+ "Tree" /* = 0x00000023 */,
+ "TreeItem" /* = 0x00000024 */,
+ "PageTab" /* = 0x00000025 */,
+ "PropertyPage" /* = 0x00000026 */,
+ "Indicator" /* = 0x00000027 */,
+ "Graphic" /* = 0x00000028 */,
+ "StaticText" /* = 0x00000029 */,
+ "EditableText" /* = 0x0000002A */, // Editable, selectable, etc.
+ "PushButton" /* = 0x0000002B */,
+ "CheckBox" /* = 0x0000002C */,
+ "RadioButton" /* = 0x0000002D */,
+ "ComboBox" /* = 0x0000002E */,
+ "DropList" /* = 0x0000002F */, // commented out
+ "ProgressBar" /* = 0x00000030 */,
+ "Dial" /* = 0x00000031 */,
+ "HotkeyField" /* = 0x00000032 */,
+ "Slider" /* = 0x00000033 */,
+ "SpinBox" /* = 0x00000034 */,
+ "Canvas" /* = 0x00000035 */,
+ "Animation" /* = 0x00000036 */,
+ "Equation" /* = 0x00000037 */,
+ "ButtonDropDown" /* = 0x00000038 */,
+ "ButtonMenu" /* = 0x00000039 */,
+ "ButtonDropGrid" /* = 0x0000003A */,
+ "Whitespace" /* = 0x0000003B */,
+ "PageTabList" /* = 0x0000003C */,
+ "Clock" /* = 0x0000003D */,
+ "Splitter" /* = 0x0000003E */,
+ "LayeredPane" /* = 0x0000003F */,
+ "UserRole" /* = 0x0000ffff*/
+ };
+
+ if (role >=0x40)
+ role = QAccessible::UserRole;
+ return roles[int(role)];
+}
+
+static const char *eventString(QAccessible::Event ev)
+{
+ static const char *events[] = {
+ "null", // 0
+ "SoundPlayed" /*= 0x0001*/,
+ "Alert" /*= 0x0002*/,
+ "ForegroundChanged" /*= 0x0003*/,
+ "MenuStart" /*= 0x0004*/,
+ "MenuEnd" /*= 0x0005*/,
+ "PopupMenuStart" /*= 0x0006*/,
+ "PopupMenuEnd" /*= 0x0007*/,
+ "ContextHelpStart" /*= 0x000C*/, // 8
+ "ContextHelpEnd" /*= 0x000D*/,
+ "DragDropStart" /*= 0x000E*/,
+ "DragDropEnd" /*= 0x000F*/,
+ "DialogStart" /*= 0x0010*/,
+ "DialogEnd" /*= 0x0011*/,
+ "ScrollingStart" /*= 0x0012*/,
+ "ScrollingEnd" /*= 0x0013*/,
+ "MenuCommand" /*= 0x0018*/, // 16
+
+ // Values from IAccessible2
+ "ActionChanged" /*= 0x0101*/, // 17
+ "ActiveDescendantChanged",
+ "AttributeChanged",
+ "DocumentContentChanged",
+ "DocumentLoadComplete",
+ "DocumentLoadStopped",
+ "DocumentReload",
+ "HyperlinkEndIndexChanged",
+ "HyperlinkNumberOfAnchorsChanged",
+ "HyperlinkSelectedLinkChanged",
+ "HypertextLinkActivated",
+ "HypertextLinkSelected",
+ "HyperlinkStartIndexChanged",
+ "HypertextChanged",
+ "HypertextNLinksChanged",
+ "ObjectAttributeChanged",
+ "PageChanged",
+ "SectionChanged",
+ "TableCaptionChanged",
+ "TableColumnDescriptionChanged",
+ "TableColumnHeaderChanged",
+ "TableModelChanged",
+ "TableRowDescriptionChanged",
+ "TableRowHeaderChanged",
+ "TableSummaryChanged",
+ "TextAttributeChanged",
+ "TextCaretMoved",
+ // TextChanged, deprecated, use TextUpdated
+ //TextColumnChanged = TextCaretMoved + 2,
+ "TextInserted",
+ "TextRemoved",
+ "TextUpdated",
+ "TextSelectionChanged",
+ "VisibleDataChanged", /*= 0x0101+32*/
+ "ObjectCreated" /*= 0x8000*/, // 49
+ "ObjectDestroyed" /*= 0x8001*/,
+ "ObjectShow" /*= 0x8002*/,
+ "ObjectHide" /*= 0x8003*/,
+ "ObjectReorder" /*= 0x8004*/,
+ "Focus" /*= 0x8005*/,
+ "Selection" /*= 0x8006*/,
+ "SelectionAdd" /*= 0x8007*/,
+ "SelectionRemove" /*= 0x8008*/,
+ "SelectionWithin" /*= 0x8009*/,
+ "StateChanged" /*= 0x800A*/,
+ "LocationChanged" /*= 0x800B*/,
+ "NameChanged" /*= 0x800C*/,
+ "DescriptionChanged" /*= 0x800D*/,
+ "ValueChanged" /*= 0x800E*/,
+ "ParentChanged" /*= 0x800F*/,
+ "HelpChanged" /*= 0x80A0*/,
+ "DefaultActionChanged" /*= 0x80B0*/,
+ "AcceleratorChanged" /*= 0x80C0*/
+ };
+ int e = int(ev);
+ if (e <= 0x80c0) {
+ const int last = sizeof(events)/sizeof(char*) - 1;
+
+ if (e <= 0x07)
+ return events[e];
+ else if (e <= 0x13)
+ return events[e - 0x0c + 8];
+ else if (e == 0x18)
+ return events[16];
+ else if (e <= 0x0101 + 32)
+ return events[e - 0x101 + 17];
+ else if (e <= 0x800f)
+ return events[e - 0x8000 + 49];
+ else if (e == 0x80a0)
+ return events[last - 2];
+ else if (e == 0x80b0)
+ return events[last - 1];
+ else if (e == 0x80c0)
+ return events[last];
+ }
+ return "unknown";
+};
+
+void showDebug(const char* funcName, const QAccessibleInterface *iface)
+{
+ qDebug() << "Role:" << roleString(iface->role(0))
+ << "Name:" << iface->text(QAccessible::Name, 0)
+ << "State:" << QString::number(int(iface->state(0)), 16)
+ << QLatin1String(funcName);
+}
+#else
+# define showDebug(f, iface)
+#endif
+
+// This stuff is used for widgets/items with no window handle:
+typedef QMap<int, QPair<QObject*,int> > NotifyMap;
+Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents)
+static int eventNum = 0;
+
+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;
+}
+
+/*
+*/
+class QWindowsAccessible : public IAccessible, IOleWindow, QAccessible
+{
+public:
+ QWindowsAccessible(QAccessibleInterface *a)
+ : ref(0), accessible(a)
+ {
+ }
+
+ virtual ~QWindowsAccessible()
+ {
+ delete accessible;
+ }
+
+ /* IUnknown */
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ /* 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);
+
+private:
+ ULONG ref;
+ QAccessibleInterface *accessible;
+};
+
+static inline BSTR QStringToBSTR(const QString &str)
+{
+ BSTR bstrVal;
+
+ int wlen = str.length()+1;
+ bstrVal = SysAllocStringByteLen(0, wlen*2);
+ memcpy(bstrVal, str.unicode(), sizeof(QChar)*(wlen));
+ bstrVal[wlen] = 0;
+
+ return bstrVal;
+}
+
+/*
+*/
+
+/*
+ IUnknown
+*/
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::QueryInterface(REFIID id, LPVOID *iface)
+{
+ *iface = 0;
+ 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
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsAccessible::AddRef()
+{
+ return ++ref;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsAccessible::Release()
+{
+ if (!--ref) {
+ delete this;
+ return 0;
+ }
+ return ref;
+}
+
+/*
+ IDispatch
+*/
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfoCount(unsigned int * pctinfo)
+{
+ // We don't use a type library
+ *pctinfo = 0;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfo(unsigned int, unsigned long, ITypeInfo **pptinfo)
+{
+ // We don't use a type library
+ *pptinfo = 0;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::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 QWindowsAccessible::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
+*/
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ int control = accessible->childAt(xLeft, yTop);
+ if (control == -1) {
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+ }
+ QAccessibleInterface *acc = 0;
+ if (control)
+ accessible->navigate(Child, control, &acc);
+ if (!acc) {
+ (*pvarID).vt = VT_I4;
+ (*pvarID).lVal = control;
+ return S_OK;
+ }
+
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+ IDispatch *iface = 0;
+ wacc->QueryInterface(IID_IDispatch, (void**)&iface);
+ if (iface) {
+ (*pvarID).vt = VT_DISPATCH;
+ (*pvarID).pdispVal = iface;
+ return S_OK;
+ } else {
+ delete wacc;
+ }
+
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QRect rect = accessible->rect(varID.lVal);
+ if (rect.isValid()) {
+ *pxLeft = rect.x();
+ *pyTop = rect.y();
+ *pcxWidth = rect.width();
+ *pcyHeight = rect.height();
+ } else {
+ *pxLeft = 0;
+ *pyTop = 0;
+ *pcxWidth = 0;
+ *pcyHeight = 0;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *acc = 0;
+ int control = -1;
+ switch (navDir) {
+ case NAVDIR_FIRSTCHILD:
+ control = accessible->navigate(Child, 1, &acc);
+ break;
+ case NAVDIR_LASTCHILD:
+ control = accessible->navigate(Child, accessible->childCount(), &acc);
+ break;
+ case NAVDIR_NEXT:
+ case NAVDIR_PREVIOUS:
+ if (!varStart.lVal){
+ QAccessibleInterface *parent = 0;
+ accessible->navigate(Ancestor, 1, &parent);
+ if (parent) {
+ int index = parent->indexOfChild(accessible);
+ index += (navDir == NAVDIR_NEXT) ? 1 : -1;
+ if (index > 0 && index <= parent->childCount())
+ control = parent->navigate(Child, index, &acc);
+ delete parent;
+ }
+ } else {
+ int index = varStart.lVal;
+ index += (navDir == NAVDIR_NEXT) ? 1 : -1;
+ if (index > 0 && index <= accessible->childCount())
+ control = accessible->navigate(Child, index, &acc);
+ }
+ break;
+ case NAVDIR_UP:
+ control = accessible->navigate(Up, varStart.lVal, &acc);
+ break;
+ case NAVDIR_DOWN:
+ control = accessible->navigate(Down, varStart.lVal, &acc);
+ break;
+ case NAVDIR_LEFT:
+ control = accessible->navigate(Left, varStart.lVal, &acc);
+ break;
+ case NAVDIR_RIGHT:
+ control = accessible->navigate(Right, varStart.lVal, &acc);
+ break;
+ default:
+ break;
+ }
+ if (control == -1) {
+ (*pvarEnd).vt = VT_EMPTY;
+ return S_FALSE;
+ }
+ if (!acc) {
+ (*pvarEnd).vt = VT_I4;
+ (*pvarEnd).lVal = control;
+ return S_OK;
+ }
+
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+
+ IDispatch *iface = 0;
+ wacc->QueryInterface(IID_IDispatch, (void**)&iface);
+ if (iface) {
+ (*pvarEnd).vt = VT_DISPATCH;
+ (*pvarEnd).pdispVal = iface;
+ return S_OK;
+ } else {
+ delete wacc;
+ }
+
+ (*pvarEnd).vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (varChildID.vt == VT_EMPTY)
+ return E_INVALIDARG;
+
+
+ int childIndex = varChildID.lVal;
+ QAccessibleInterface *acc = 0;
+
+ if (childIndex < 0) {
+ const int entry = childIndex;
+ QPair<QObject*, int> ref = qAccessibleRecentSentEvents()->value(entry);
+ if (ref.first) {
+ acc = queryAccessibleInterface(ref.first);
+ if (acc && ref.second) {
+ if (ref.second) {
+ QAccessibleInterface *res;
+ int index = acc->navigate(Child, ref.second, &res);
+ delete acc;
+ if (index == -1)
+ return E_INVALIDARG;
+ acc = res;
+ }
+ }
+ }
+ } else {
+ RelationFlag rel = childIndex ? Child : Self;
+ accessible->navigate(rel, childIndex, &acc);
+ }
+
+ if (acc) {
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+ wacc->QueryInterface(IID_IDispatch, (void**)ppdispChild);
+ return S_OK;
+ }
+
+ *ppdispChild = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChildCount(long* pcountChildren)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *pcountChildren = accessible->childCount();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispParent)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *acc = 0;
+ accessible->navigate(Ancestor, 1, &acc);
+ if (acc) {
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+ wacc->QueryInterface(IID_IDispatch, (void**)ppdispParent);
+
+ if (*ppdispParent)
+ return S_OK;
+ }
+
+ *ppdispParent = 0;
+ return S_FALSE;
+}
+
+/*
+ Properties and methods
+*/
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accDoDefaultAction(VARIANT varID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ return accessible->doAction(DefaultAction, varID.lVal, QVariantList()) ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString def = accessible->actionText(DefaultAction, Name, varID.lVal);
+ if (def.isEmpty()) {
+ *pszDefaultAction = 0;
+ return S_FALSE;
+ }
+
+ *pszDefaultAction = QStringToBSTR(def);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString descr = accessible->text(Description, varID.lVal);
+ if (descr.size()) {
+ *pszDescription = QStringToBSTR(descr);
+ return S_OK;
+ }
+
+ *pszDescription = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString help = accessible->text(Help, varID.lVal);
+ if (help.size()) {
+ *pszHelp = QStringToBSTR(help);
+ return S_OK;
+ }
+
+ *pszHelp = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
+{
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString sc = accessible->text(Accelerator, varID.lVal);
+ if (sc.size()) {
+ *pszKeyboardShortcut = QStringToBSTR(sc);
+ return S_OK;
+ }
+
+ *pszKeyboardShortcut = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* pszName)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString n = accessible->text(Name, varID.lVal);
+ if (n.size()) {
+ *pszName = QStringToBSTR(n);
+ return S_OK;
+ }
+
+ *pszName = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accName(VARIANT, BSTR)
+{
+ showDebug(__FUNCTION__, accessible);
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ Role role = accessible->role(varID.lVal);
+ if (role != NoRole) {
+ if (role == LayeredPane)
+ role = QAccessible::Pane;
+ (*pvarRole).vt = VT_I4;
+ (*pvarRole).lVal = role;
+ } else {
+ (*pvarRole).vt = VT_EMPTY;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accState(VARIANT varID, VARIANT *pvarState)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ (*pvarState).vt = VT_I4;
+ (*pvarState).lVal = accessible->state(varID.lVal);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accValue(VARIANT varID, BSTR* pszValue)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString value = accessible->text(Value, varID.lVal);
+ if (!value.isNull()) {
+ *pszValue = QStringToBSTR(value);
+ return S_OK;
+ }
+
+ *pszValue = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accValue(VARIANT, BSTR)
+{
+ showDebug(__FUNCTION__, accessible);
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accSelect(long flagsSelect, VARIANT varID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ bool res = false;
+
+ 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;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *acc = 0;
+ int control = accessible->navigate(FocusChild, 1, &acc);
+ if (control == -1) {
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+ }
+ if (!acc || control == 0) {
+ (*pvarID).vt = VT_I4;
+ (*pvarID).lVal = control ? control : CHILDID_SELF;
+ return S_OK;
+ }
+
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+ IDispatch *iface = 0;
+ wacc->QueryInterface(IID_IDispatch, (void**)&iface);
+ if (iface) {
+ (*pvarID).vt = VT_DISPATCH;
+ (*pvarID).pdispVal = iface;
+ return S_OK;
+ } else {
+ delete wacc;
+ }
+
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ int cc = accessible->childCount();
+ QVector<int> sel(cc);
+ int selIndex = 0;
+ for (int i = 1; i <= cc; ++i) {
+ QAccessibleInterface *child = 0;
+ int i2 = accessible->navigate(Child, i, &child);
+ bool isSelected = false;
+ if (child) {
+ isSelected = child->state(0) & Selected;
+ delete child;
+ child = 0;
+ } else {
+ isSelected = accessible->state(i2) & Selected;
+ }
+ if (isSelected)
+ sel[selIndex++] = i;
+ }
+ 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;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetWindow(HWND *phwnd)
+{
+ *phwnd = 0;
+ if (!accessible->isValid())
+ return E_UNEXPECTED;
+
+ QObject *o = accessible->object();
+ QWindow *window = qobject_cast<QWindow*>(o);
+ if (!window)
+ window = QGuiApplication::topLevelWindows().first();
+
+
+ Q_ASSERT(window);
+ if (!o || !window)
+ return E_FAIL;
+
+
+#ifdef Q_WS_QPA
+ //QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
+ //Q_ASSERT(platform);
+ //*phwnd = (HWND)platform->nativeResourceForWindow("handle", window);
+
+
+ return S_OK;
+#else
+ *phwnd = static_cast<QWidget*>(o)->effectiveWinId();
+ return S_OK;
+#endif
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL)
+{
+ return S_OK;
+}
+
+
+QWindowsAccessibility::QWindowsAccessibility()
+{
+}
+
+
+void QWindowsAccessibility::notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason)
+{
+ QString soundName;
+ switch (reason) {
+ 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_WS_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 = QAccessible::queryAccessibleInterface(o);
+ QWindow *window = iface->window();
+
+ if (!window) {
+ window = QGuiApplication::activeWindow();
+ if (!window)
+ return;
+ }
+
+ QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
+ HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window);
+
+ if (reason != 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(o, who));
+ ptrNotifyWinEvent(reason, hWnd, OBJID_CLIENT, eventId );
+
+ ++eventNum;
+ }
+#endif // Q_WS_WINCE
+
+}
+
+/*
+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 (QApplication::startingUp() || QApplication::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) {
+ QWindowsAccessible *winacc = new QWindowsAccessible(acc);
+ IAccessible *iface;
+ HRESULT hr = winacc->QueryInterface(IID_IAccessible, (void**)&iface);
+ if (SUCCEEDED(hr)) {
+ *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;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/plugins/platforms/windows/qwindowsaccessibility.h b/src/plugins/platforms/windows/qwindowsaccessibility.h
new file mode 100644
index 0000000000..d27b28cf48
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsaccessibility.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** 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 <QtGui/QPlatformAccessibility>
+#include <OleAcc.h>
+
+class QWindowsAccessibility : public QPlatformAccessibility
+{
+public:
+ QWindowsAccessibility();
+ static bool handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
+ virtual void notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason);
+ /*
+ virtual void setRootObject(QObject *o);
+ virtual void initialize();
+ virtual void cleanup();
+*/
+};
+
+#endif // QWINDOWSACCESSIBILITY_H
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 3dae732745..3da1281004 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -47,6 +47,7 @@
#include "qtwindowsglobal.h"
#include "qwindowsmime.h"
#include "qwindowsinputcontext.h"
+#include "qwindowsaccessibility.h"
#include <QtGui/QWindow>
#include <QtGui/QWindowSystemInterface>
@@ -623,6 +624,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::UnknownEvent:
return false;
+ case QtWindows::AccessibleObjectFromWindowRequest:
+ return QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(hwnd, wParam, lParam, result);
default:
break;
}
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 048ca13f6f..7bd4e2a0b4 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -50,6 +50,7 @@
#include "qwindowsclipboard.h"
#include "qwindowsdrag.h"
#include "qwindowsinputcontext.h"
+#include "qwindowsaccessibility.h"
#include <QtGui/QPlatformNativeInterface>
#include <QtGui/QWindowSystemInterface>
@@ -138,6 +139,7 @@ struct QWindowsIntegrationPrivate
QWindowsGuiEventDispatcher *m_eventDispatcher;
QOpenGLStaticContextPtr m_staticOpenGLContext;
QWindowsInputContext m_inputContext;
+ QWindowsAccessibility m_accessibility;
};
QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(bool openGL)
@@ -258,6 +260,11 @@ QPlatformInputContext * QWindowsIntegration::inputContext() const
return &d->m_inputContext;
}
+QPlatformAccessibility *QWindowsIntegration::accessibility() const
+{
+ return &d->m_accessibility;
+}
+
QWindowsIntegration *QWindowsIntegration::instance()
{
return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration());
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index 1fe2301175..8202e03106 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -66,6 +66,7 @@ public:
virtual QPlatformClipboard *clipboard() const;
virtual QPlatformDrag *drag() const;
virtual QPlatformInputContext *inputContext() const;
+ virtual QPlatformAccessibility *accessibility() const;
virtual QPlatformNativeInterface *nativeInterface() const;
virtual QPlatformFontDatabase *fontDatabase() const;
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
index e5627ae574..f188ef53b1 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -8,7 +8,7 @@ INCLUDEPATH += ../../../3rdparty/harfbuzz/src
QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
# Note: OpenGL32 must precede Gdi32 as it overwrites some functions.
-LIBS *= -lOpenGL32 -lGdi32 -lUser32 -lOle32 -lWinspool -lImm32
+LIBS *= -lOpenGL32 -lGdi32 -lUser32 -lOle32 -lWinspool -lImm32 -lWinmm
win32-g++: LIBS *= -luuid
contains(QT_CONFIG, directwrite) {
@@ -39,7 +39,8 @@ SOURCES += \
qwindowsdrag.cpp \
qwindowscursor.cpp \
pixmaputils.cpp \
- qwindowsinputcontext.cpp
+ qwindowsinputcontext.cpp \
+ qwindowsaccessibility.cpp
HEADERS += \
qwindowsnativeimage.h \
@@ -64,7 +65,8 @@ HEADERS += \
qwindowscursor.h \
pixmaputils.h \
array.h \
- qwindowsinputcontext.h
+ qwindowsinputcontext.h \
+ qwindowsaccessibility.h
target.path += $$[QT_INSTALL_PLUGINS]/platforms
INSTALLS += target