1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the plugins of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtCore/QtConfig>
43 #ifndef QT_NO_ACCESSIBILITY
46 #include "qwindowsaccessibility.h"
47 #include "qwindowscontext.h"
49 #include <private/qsystemlibrary_p.h>
51 #include <QtCore/qmap.h>
52 #include <QtCore/qsettings.h>
53 #include <QtCore/qsharedpointer.h>
54 #include <QtCore/qpair.h>
55 #include <QtWidgets/qapplication.h>
56 #include <QtWidgets/qmessagebox.h>
57 #include <QtWidgets/qgraphicsitem.h>
58 #include <QtWidgets/qgraphicsview.h>
59 #include <QtGui/qaccessible.h>
60 #include <QtGui/qplatformnativeinterface_qpa.h>
61 #include <QtGui/qwindow.h>
62 #include <QtGui/qaccessible2.h>
65 //#include <uiautomationcoreapi.h>
66 #ifndef UiaRootObjectId
67 #define UiaRootObjectId -25
71 #if !defined(WINABLEAPI)
72 # if defined(Q_WS_WINCE)
79 #if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
84 #include "qguifunctions_wince.h"
89 //#define DEBUG_SHOW_ATCLIENT_COMMANDS
90 #ifdef DEBUG_SHOW_ATCLIENT_COMMANDS
91 QT_BEGIN_INCLUDE_NAMESPACE
93 QT_END_INCLUDE_NAMESPACE
95 static const char *roleString(QAccessible::Role role)
97 static const char *roles[] = {
98 "NoRole" /* = 0x00000000 */,
99 "TitleBar" /* = 0x00000001 */,
100 "MenuBar" /* = 0x00000002 */,
101 "ScrollBar" /* = 0x00000003 */,
102 "Grip" /* = 0x00000004 */,
103 "Sound" /* = 0x00000005 */,
104 "Cursor" /* = 0x00000006 */,
105 "Caret" /* = 0x00000007 */,
106 "AlertMessage" /* = 0x00000008 */,
107 "Window" /* = 0x00000009 */,
108 "Client" /* = 0x0000000A */,
109 "PopupMenu" /* = 0x0000000B */,
110 "MenuItem" /* = 0x0000000C */,
111 "ToolTip" /* = 0x0000000D */,
112 "Application" /* = 0x0000000E */,
113 "Document" /* = 0x0000000F */,
114 "Pane" /* = 0x00000010 */,
115 "Chart" /* = 0x00000011 */,
116 "Dialog" /* = 0x00000012 */,
117 "Border" /* = 0x00000013 */,
118 "Grouping" /* = 0x00000014 */,
119 "Separator" /* = 0x00000015 */,
120 "ToolBar" /* = 0x00000016 */,
121 "StatusBar" /* = 0x00000017 */,
122 "Table" /* = 0x00000018 */,
123 "ColumnHeader" /* = 0x00000019 */,
124 "RowHeader" /* = 0x0000001A */,
125 "Column" /* = 0x0000001B */,
126 "Row" /* = 0x0000001C */,
127 "Cell" /* = 0x0000001D */,
128 "Link" /* = 0x0000001E */,
129 "HelpBalloon" /* = 0x0000001F */,
130 "Assistant" /* = 0x00000020 */,
131 "List" /* = 0x00000021 */,
132 "ListItem" /* = 0x00000022 */,
133 "Tree" /* = 0x00000023 */,
134 "TreeItem" /* = 0x00000024 */,
135 "PageTab" /* = 0x00000025 */,
136 "PropertyPage" /* = 0x00000026 */,
137 "Indicator" /* = 0x00000027 */,
138 "Graphic" /* = 0x00000028 */,
139 "StaticText" /* = 0x00000029 */,
140 "EditableText" /* = 0x0000002A */, // Editable, selectable, etc.
141 "PushButton" /* = 0x0000002B */,
142 "CheckBox" /* = 0x0000002C */,
143 "RadioButton" /* = 0x0000002D */,
144 "ComboBox" /* = 0x0000002E */,
145 "DropList" /* = 0x0000002F */, // commented out
146 "ProgressBar" /* = 0x00000030 */,
147 "Dial" /* = 0x00000031 */,
148 "HotkeyField" /* = 0x00000032 */,
149 "Slider" /* = 0x00000033 */,
150 "SpinBox" /* = 0x00000034 */,
151 "Canvas" /* = 0x00000035 */,
152 "Animation" /* = 0x00000036 */,
153 "Equation" /* = 0x00000037 */,
154 "ButtonDropDown" /* = 0x00000038 */,
155 "ButtonMenu" /* = 0x00000039 */,
156 "ButtonDropGrid" /* = 0x0000003A */,
157 "Whitespace" /* = 0x0000003B */,
158 "PageTabList" /* = 0x0000003C */,
159 "Clock" /* = 0x0000003D */,
160 "Splitter" /* = 0x0000003E */,
161 "LayeredPane" /* = 0x0000003F */,
162 "UserRole" /* = 0x0000ffff*/
166 role = QAccessible::UserRole;
167 return roles[int(role)];
170 static const char *eventString(QAccessible::Event ev)
172 static const char *events[] = {
174 "SoundPlayed" /*= 0x0001*/,
175 "Alert" /*= 0x0002*/,
176 "ForegroundChanged" /*= 0x0003*/,
177 "MenuStart" /*= 0x0004*/,
178 "MenuEnd" /*= 0x0005*/,
179 "PopupMenuStart" /*= 0x0006*/,
180 "PopupMenuEnd" /*= 0x0007*/,
181 "ContextHelpStart" /*= 0x000C*/, // 8
182 "ContextHelpEnd" /*= 0x000D*/,
183 "DragDropStart" /*= 0x000E*/,
184 "DragDropEnd" /*= 0x000F*/,
185 "DialogStart" /*= 0x0010*/,
186 "DialogEnd" /*= 0x0011*/,
187 "ScrollingStart" /*= 0x0012*/,
188 "ScrollingEnd" /*= 0x0013*/,
189 "MenuCommand" /*= 0x0018*/, // 16
191 // Values from IAccessible2
192 "ActionChanged" /*= 0x0101*/, // 17
193 "ActiveDescendantChanged",
195 "DocumentContentChanged",
196 "DocumentLoadComplete",
197 "DocumentLoadStopped",
199 "HyperlinkEndIndexChanged",
200 "HyperlinkNumberOfAnchorsChanged",
201 "HyperlinkSelectedLinkChanged",
202 "HypertextLinkActivated",
203 "HypertextLinkSelected",
204 "HyperlinkStartIndexChanged",
206 "HypertextNLinksChanged",
207 "ObjectAttributeChanged",
210 "TableCaptionChanged",
211 "TableColumnDescriptionChanged",
212 "TableColumnHeaderChanged",
214 "TableRowDescriptionChanged",
215 "TableRowHeaderChanged",
216 "TableSummaryChanged",
217 "TextAttributeChanged",
219 // TextChanged, deprecated, use TextUpdated
220 //TextColumnChanged = TextCaretMoved + 2,
224 "TextSelectionChanged",
225 "VisibleDataChanged", /*= 0x0101+32*/
226 "ObjectCreated" /*= 0x8000*/, // 49
227 "ObjectDestroyed" /*= 0x8001*/,
228 "ObjectShow" /*= 0x8002*/,
229 "ObjectHide" /*= 0x8003*/,
230 "ObjectReorder" /*= 0x8004*/,
231 "Focus" /*= 0x8005*/,
232 "Selection" /*= 0x8006*/,
233 "SelectionAdd" /*= 0x8007*/,
234 "SelectionRemove" /*= 0x8008*/,
235 "SelectionWithin" /*= 0x8009*/,
236 "StateChanged" /*= 0x800A*/,
237 "LocationChanged" /*= 0x800B*/,
238 "NameChanged" /*= 0x800C*/,
239 "DescriptionChanged" /*= 0x800D*/,
240 "ValueChanged" /*= 0x800E*/,
241 "ParentChanged" /*= 0x800F*/,
242 "HelpChanged" /*= 0x80A0*/,
243 "DefaultActionChanged" /*= 0x80B0*/,
244 "AcceleratorChanged" /*= 0x80C0*/
248 const int last = sizeof(events)/sizeof(char*) - 1;
253 return events[e - 0x0c + 8];
256 else if (e <= 0x0101 + 32)
257 return events[e - 0x101 + 17];
258 else if (e <= 0x800f)
259 return events[e - 0x8000 + 49];
260 else if (e == 0x80a0)
261 return events[last - 2];
262 else if (e == 0x80b0)
263 return events[last - 1];
264 else if (e == 0x80c0)
270 void showDebug(const char* funcName, const QAccessibleInterface *iface)
272 qDebug() << "Role:" << roleString(iface->role(0))
273 << "Name:" << iface->text(QAccessible::Name, 0)
274 << "State:" << QString::number(int(iface->state(0)), 16)
275 << QLatin1String(funcName);
278 # define showDebug(f, iface)
281 typedef QSharedPointer<QAccessibleInterface> QAIPointer;
283 // This stuff is used for widgets/items with no window handle:
284 typedef QMap<int, QPair<QObject*,int> > NotifyMap;
285 Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents)
286 static int eventNum = 0;
288 class QWindowsEnumerate : public IEnumVARIANT
291 QWindowsEnumerate(const QVector<int> &a)
292 : ref(0), current(0),array(a)
296 virtual ~QWindowsEnumerate() {}
298 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
299 ULONG STDMETHODCALLTYPE AddRef();
300 ULONG STDMETHODCALLTYPE Release();
302 HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **ppEnum);
303 HRESULT STDMETHODCALLTYPE Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched);
304 HRESULT STDMETHODCALLTYPE Reset();
305 HRESULT STDMETHODCALLTYPE Skip(unsigned long celt);
313 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::QueryInterface(REFIID id, LPVOID *iface)
316 if (id == IID_IUnknown)
317 *iface = (IUnknown*)this;
318 else if (id == IID_IEnumVARIANT)
319 *iface = (IEnumVARIANT*)this;
326 return E_NOINTERFACE;
329 ULONG STDMETHODCALLTYPE QWindowsEnumerate::AddRef()
334 ULONG STDMETHODCALLTYPE QWindowsEnumerate::Release()
343 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone(IEnumVARIANT **ppEnum)
345 QWindowsEnumerate *penum = 0;
348 penum = new QWindowsEnumerate(array);
350 return E_OUTOFMEMORY;
351 penum->current = current;
352 penum->array = array;
359 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched)
365 for (l = 0; l < celt; l++) {
366 VariantInit(&rgVar[l]);
367 if ((current+1) > (ULONG)array.size()) {
373 rgVar[l].lVal = array[(int)current];
380 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Reset()
386 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt)
389 if (current > (ULONG)array.size()) {
390 current = array.size();
398 class QWindowsAccessible : public IAccessible, IOleWindow
401 QWindowsAccessible(QAccessibleInterface *a)
402 : ref(0), accessible(a)
406 virtual ~QWindowsAccessible()
412 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
413 ULONG STDMETHODCALLTYPE AddRef();
414 ULONG STDMETHODCALLTYPE Release();
417 HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int *);
418 HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int, unsigned long, ITypeInfo **);
419 HRESULT STDMETHODCALLTYPE GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *);
420 HRESULT STDMETHODCALLTYPE Invoke(long, const _GUID &, unsigned long, unsigned short, tagDISPPARAMS *, tagVARIANT *, tagEXCEPINFO *, unsigned int *);
423 HRESULT STDMETHODCALLTYPE accHitTest(long xLeft, long yTop, VARIANT *pvarID);
424 HRESULT STDMETHODCALLTYPE accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID);
425 HRESULT STDMETHODCALLTYPE accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd);
426 HRESULT STDMETHODCALLTYPE get_accChild(VARIANT varChildID, IDispatch** ppdispChild);
427 HRESULT STDMETHODCALLTYPE get_accChildCount(long* pcountChildren);
428 HRESULT STDMETHODCALLTYPE get_accParent(IDispatch** ppdispParent);
430 HRESULT STDMETHODCALLTYPE accDoDefaultAction(VARIANT varID);
431 HRESULT STDMETHODCALLTYPE get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction);
432 HRESULT STDMETHODCALLTYPE get_accDescription(VARIANT varID, BSTR* pszDescription);
433 HRESULT STDMETHODCALLTYPE get_accHelp(VARIANT varID, BSTR *pszHelp);
434 HRESULT STDMETHODCALLTYPE get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic);
435 HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut);
436 HRESULT STDMETHODCALLTYPE get_accName(VARIANT varID, BSTR* pszName);
437 HRESULT STDMETHODCALLTYPE put_accName(VARIANT varChild, BSTR szName);
438 HRESULT STDMETHODCALLTYPE get_accRole(VARIANT varID, VARIANT *pvarRole);
439 HRESULT STDMETHODCALLTYPE get_accState(VARIANT varID, VARIANT *pvarState);
440 HRESULT STDMETHODCALLTYPE get_accValue(VARIANT varID, BSTR* pszValue);
441 HRESULT STDMETHODCALLTYPE put_accValue(VARIANT varChild, BSTR szValue);
443 HRESULT STDMETHODCALLTYPE accSelect(long flagsSelect, VARIANT varID);
444 HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT *pvarID);
445 HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT *pvarChildren);
448 HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
449 HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
453 QAccessibleInterface *accessible;
455 QAIPointer childPointer(VARIANT varID)
457 return QAIPointer(accessible->child(varID.lVal - 1));
461 static inline BSTR QStringToBSTR(const QString &str)
465 int wlen = str.length()+1;
466 bstrVal = SysAllocStringByteLen(0, wlen*2);
467 memcpy(bstrVal, str.unicode(), sizeof(QChar)*(wlen));
479 HRESULT STDMETHODCALLTYPE QWindowsAccessible::QueryInterface(REFIID id, LPVOID *iface)
482 if (id == IID_IUnknown)
483 *iface = (IUnknown*)(IDispatch*)this;
484 else if (id == IID_IDispatch)
485 *iface = (IDispatch*)this;
486 else if (id == IID_IAccessible)
487 *iface = (IAccessible*)this;
488 else if (id == IID_IOleWindow)
489 *iface = (IOleWindow*)this;
491 return E_NOINTERFACE;
497 ULONG STDMETHODCALLTYPE QWindowsAccessible::AddRef()
502 ULONG STDMETHODCALLTYPE QWindowsAccessible::Release()
515 HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfoCount(unsigned int * pctinfo)
517 // We don't use a type library
522 HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfo(unsigned int, unsigned long, ITypeInfo **pptinfo)
524 // We don't use a type library
529 HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetIDsOfNames(const _GUID &, wchar_t **rgszNames, unsigned int, unsigned long, long *rgdispid)
531 #if !defined(Q_CC_BOR) && !defined(Q_CC_GNU)
532 // PROPERTIES: Hierarchical
533 if (_bstr_t(rgszNames[0]) == _bstr_t(L"accParent"))
534 rgdispid[0] = DISPID_ACC_PARENT;
535 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount"))
536 rgdispid[0] = DISPID_ACC_CHILDCOUNT;
537 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accChild"))
538 rgdispid[0] = DISPID_ACC_CHILD;
540 // PROPERTIES: Descriptional
541 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accName("))
542 rgdispid[0] = DISPID_ACC_NAME;
543 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accValue"))
544 rgdispid[0] = DISPID_ACC_VALUE;
545 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription"))
546 rgdispid[0] = DISPID_ACC_DESCRIPTION;
547 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accRole"))
548 rgdispid[0] = DISPID_ACC_ROLE;
549 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accState"))
550 rgdispid[0] = DISPID_ACC_STATE;
551 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp"))
552 rgdispid[0] = DISPID_ACC_HELP;
553 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic"))
554 rgdispid[0] = DISPID_ACC_HELPTOPIC;
555 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut"))
556 rgdispid[0] = DISPID_ACC_KEYBOARDSHORTCUT;
557 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus"))
558 rgdispid[0] = DISPID_ACC_FOCUS;
559 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection"))
560 rgdispid[0] = DISPID_ACC_SELECTION;
561 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction"))
562 rgdispid[0] = DISPID_ACC_DEFAULTACTION;
565 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect"))
566 rgdispid[0] = DISPID_ACC_SELECT;
567 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation"))
568 rgdispid[0] = DISPID_ACC_LOCATION;
569 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate"))
570 rgdispid[0] = DISPID_ACC_NAVIGATE;
571 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest"))
572 rgdispid[0] = DISPID_ACC_HITTEST;
573 else if (_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction"))
574 rgdispid[0] = DISPID_ACC_DODEFAULTACTION;
576 return DISP_E_UNKNOWNINTERFACE;
583 return DISP_E_MEMBERNOTFOUND;
587 HRESULT STDMETHODCALLTYPE QWindowsAccessible::Invoke(long dispIdMember, const _GUID &, unsigned long, unsigned short wFlags, tagDISPPARAMS *pDispParams, tagVARIANT *pVarResult, tagEXCEPINFO *, unsigned int *)
589 HRESULT hr = DISP_E_MEMBERNOTFOUND;
591 switch (dispIdMember)
593 case DISPID_ACC_PARENT:
594 if (wFlags == DISPATCH_PROPERTYGET) {
597 hr = get_accParent(&pVarResult->pdispVal);
599 hr = DISP_E_MEMBERNOTFOUND;
603 case DISPID_ACC_CHILDCOUNT:
604 if (wFlags == DISPATCH_PROPERTYGET) {
607 hr = get_accChildCount(&pVarResult->lVal);
609 hr = DISP_E_MEMBERNOTFOUND;
613 case DISPID_ACC_CHILD:
614 if (wFlags == DISPATCH_PROPERTYGET)
615 hr = get_accChild(pDispParams->rgvarg[0], &pVarResult->pdispVal);
617 hr = DISP_E_MEMBERNOTFOUND;
620 case DISPID_ACC_NAME:
621 if (wFlags == DISPATCH_PROPERTYGET)
622 hr = get_accName(pDispParams->rgvarg[0], &pVarResult->bstrVal);
623 else if (wFlags == DISPATCH_PROPERTYPUT)
624 hr = put_accName(pDispParams->rgvarg[0], pVarResult->bstrVal);
626 hr = DISP_E_MEMBERNOTFOUND;
629 case DISPID_ACC_VALUE:
630 if (wFlags == DISPATCH_PROPERTYGET)
631 hr = get_accValue(pDispParams->rgvarg[0], &pVarResult->bstrVal);
632 else if (wFlags == DISPATCH_PROPERTYPUT)
633 hr = put_accValue(pDispParams->rgvarg[0], pVarResult->bstrVal);
635 hr = DISP_E_MEMBERNOTFOUND;
638 case DISPID_ACC_DESCRIPTION:
639 if (wFlags == DISPATCH_PROPERTYGET)
640 hr = get_accDescription(pDispParams->rgvarg[0], &pVarResult->bstrVal);
642 hr = DISP_E_MEMBERNOTFOUND;
645 case DISPID_ACC_ROLE:
646 if (wFlags == DISPATCH_PROPERTYGET)
647 hr = get_accRole(pDispParams->rgvarg[0], pVarResult);
649 hr = DISP_E_MEMBERNOTFOUND;
652 case DISPID_ACC_STATE:
653 if (wFlags == DISPATCH_PROPERTYGET)
654 hr = get_accState(pDispParams->rgvarg[0], pVarResult);
656 hr = DISP_E_MEMBERNOTFOUND;
659 case DISPID_ACC_HELP:
660 if (wFlags == DISPATCH_PROPERTYGET)
661 hr = get_accHelp(pDispParams->rgvarg[0], &pVarResult->bstrVal);
663 hr = DISP_E_MEMBERNOTFOUND;
666 case DISPID_ACC_HELPTOPIC:
667 if (wFlags == DISPATCH_PROPERTYGET)
668 hr = get_accHelpTopic(&pDispParams->rgvarg[2].bstrVal, pDispParams->rgvarg[1], &pDispParams->rgvarg[0].lVal);
670 hr = DISP_E_MEMBERNOTFOUND;
673 case DISPID_ACC_KEYBOARDSHORTCUT:
674 if (wFlags == DISPATCH_PROPERTYGET)
675 hr = get_accKeyboardShortcut(pDispParams->rgvarg[0], &pVarResult->bstrVal);
677 hr = DISP_E_MEMBERNOTFOUND;
680 case DISPID_ACC_FOCUS:
681 if (wFlags == DISPATCH_PROPERTYGET)
682 hr = get_accFocus(pVarResult);
684 hr = DISP_E_MEMBERNOTFOUND;
687 case DISPID_ACC_SELECTION:
688 if (wFlags == DISPATCH_PROPERTYGET)
689 hr = get_accSelection(pVarResult);
691 hr = DISP_E_MEMBERNOTFOUND;
694 case DISPID_ACC_DEFAULTACTION:
695 if (wFlags == DISPATCH_PROPERTYGET)
696 hr = get_accDefaultAction(pDispParams->rgvarg[0], &pVarResult->bstrVal);
698 hr = DISP_E_MEMBERNOTFOUND;
701 case DISPID_ACC_SELECT:
702 if (wFlags == DISPATCH_METHOD)
703 hr = accSelect(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
705 hr = DISP_E_MEMBERNOTFOUND;
708 case DISPID_ACC_LOCATION:
709 if (wFlags == DISPATCH_METHOD)
710 hr = accLocation(&pDispParams->rgvarg[4].lVal, &pDispParams->rgvarg[3].lVal, &pDispParams->rgvarg[2].lVal, &pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
712 hr = DISP_E_MEMBERNOTFOUND;
715 case DISPID_ACC_NAVIGATE:
716 if (wFlags == DISPATCH_METHOD)
717 hr = accNavigate(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0], pVarResult);
719 hr = DISP_E_MEMBERNOTFOUND;
722 case DISPID_ACC_HITTEST:
723 if (wFlags == DISPATCH_METHOD)
724 hr = accHitTest(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].lVal, pVarResult);
726 hr = DISP_E_MEMBERNOTFOUND;
729 case DISPID_ACC_DODEFAULTACTION:
730 if (wFlags == DISPATCH_METHOD)
731 hr = accDoDefaultAction(pDispParams->rgvarg[0]);
733 hr = DISP_E_MEMBERNOTFOUND;
737 hr = DISP_E_MEMBERNOTFOUND;
741 if (!SUCCEEDED(hr)) {
750 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
752 showDebug(__FUNCTION__, accessible);
753 if (!accessible->isValid())
756 QAccessibleInterface *child = accessible->childAt(xLeft, yTop);
758 // no child found, return this item if it contains the coordinates
759 if (accessible->rect().contains(xLeft, yTop)) {
760 IDispatch *iface = 0;
761 QueryInterface(IID_IDispatch, (void**)&iface);
763 (*pvarID).vt = VT_DISPATCH;
764 (*pvarID).pdispVal = iface;
768 (*pvarID).vt = VT_EMPTY;
772 QWindowsAccessible* wacc = new QWindowsAccessible(child);
773 IDispatch *iface = 0;
774 wacc->QueryInterface(IID_IDispatch, (void**)&iface);
776 (*pvarID).vt = VT_DISPATCH;
777 (*pvarID).pdispVal = iface;
783 (*pvarID).vt = VT_EMPTY;
788 It is recommended to read
789 "Implementing a Microsoft Active Accessibility (MSAA) Server.
790 Practical Tips for Developers and How Mozilla Does It"
791 (https://developer.mozilla.org/En/Accessibility/Implementing_an_MSAA_Server)
793 to get an overview of what's important to implement and what parts of MSAA
794 can be ignored. All stuff prefixed with "moz" are information from that page.
797 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
799 showDebug(__FUNCTION__, accessible);
800 if (!accessible->isValid())
805 QAIPointer child = QAIPointer(accessible->child(varID.lVal - 1));
806 if (child->isValid())
807 rect = child->rect();
809 rect = accessible->rect();
814 *pcxWidth = rect.width();
815 *pcyHeight = rect.height();
820 // moz: [important, but no need to implement up/down/left/right]
821 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
823 showDebug(__FUNCTION__, accessible);
824 if (!accessible->isValid())
827 QAccessibleInterface *acc = 0;
830 case NAVDIR_FIRSTCHILD:
831 control = accessible->navigate(QAccessible::Child, 1, &acc);
833 case NAVDIR_LASTCHILD:
834 control = accessible->navigate(QAccessible::Child, accessible->childCount(), &acc);
837 case NAVDIR_PREVIOUS:
839 QAccessibleInterface *parent = accessible->parent();
841 int index = parent->indexOfChild(accessible);
842 index += (navDir == NAVDIR_NEXT) ? 1 : -1;
843 if (index > 0 && index <= parent->childCount())
844 control = parent->navigate(QAccessible::Child, index, &acc);
848 int index = varStart.lVal;
849 index += (navDir == NAVDIR_NEXT) ? 1 : -1;
850 if (index > 0 && index <= accessible->childCount())
851 control = accessible->navigate(QAccessible::Child, index, &acc);
855 control = accessible->navigate(QAccessible::Up, varStart.lVal, &acc);
858 control = accessible->navigate(QAccessible::Down, varStart.lVal, &acc);
861 control = accessible->navigate(QAccessible::Left, varStart.lVal, &acc);
864 control = accessible->navigate(QAccessible::Right, varStart.lVal, &acc);
870 (*pvarEnd).vt = VT_EMPTY;
874 (*pvarEnd).vt = VT_I4;
875 (*pvarEnd).lVal = control;
879 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
881 IDispatch *iface = 0;
882 wacc->QueryInterface(IID_IDispatch, (void**)&iface);
884 (*pvarEnd).vt = VT_DISPATCH;
885 (*pvarEnd).pdispVal = iface;
891 (*pvarEnd).vt = VT_EMPTY;
896 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
898 showDebug(__FUNCTION__, accessible);
899 if (!accessible->isValid())
902 if (varChildID.vt == VT_EMPTY)
906 int childIndex = varChildID.lVal;
907 QAccessibleInterface *acc = 0;
909 if (childIndex < 0) {
910 const int entry = childIndex;
911 QPair<QObject*, int> ref = qAccessibleRecentSentEvents()->value(entry);
913 acc = QAccessible::queryAccessibleInterface(ref.first);
914 if (acc && ref.second) {
916 QAccessibleInterface *res;
917 int index = acc->navigate(QAccessible::Child, ref.second, &res);
926 QAccessible::RelationFlag rel = childIndex ? QAccessible::Child : QAccessible::Self;
927 accessible->navigate(rel, childIndex, &acc);
931 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
932 wacc->QueryInterface(IID_IDispatch, (void**)ppdispChild);
941 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChildCount(long* pcountChildren)
943 showDebug(__FUNCTION__, accessible);
944 if (!accessible->isValid())
947 *pcountChildren = accessible->childCount();
952 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispParent)
954 showDebug(__FUNCTION__, accessible);
955 if (!accessible->isValid())
958 QAccessibleInterface *acc = accessible->parent();
960 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
961 wacc->QueryInterface(IID_IDispatch, (void**)ppdispParent);
972 Properties and methods
974 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accDoDefaultAction(VARIANT varID)
977 showDebug(__FUNCTION__, accessible);
978 if (!accessible->isValid())
981 if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
982 const QString def = actionIface->actionNames().value(0);
983 if (!def.isEmpty()) {
984 actionIface->doAction(def);
991 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction)
994 showDebug(__FUNCTION__, accessible);
995 if (!accessible->isValid())
998 *pszDefaultAction = 0;
999 if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
1000 const QString def = actionIface->actionNames().value(0);
1002 *pszDefaultAction = QStringToBSTR(def);
1004 return *pszDefaultAction ? S_OK : S_FALSE;
1007 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription)
1009 showDebug(__FUNCTION__, accessible);
1010 if (!accessible->isValid())
1016 QAIPointer child = childPointer(varID);
1019 descr = child->text(QAccessible::Description);
1021 descr = accessible->text(QAccessible::Description);
1024 *pszDescription = QStringToBSTR(descr);
1028 *pszDescription = 0;
1032 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp)
1034 showDebug(__FUNCTION__, accessible);
1035 if (!accessible->isValid())
1040 QAIPointer child = childPointer(varID);
1043 help = child->text(QAccessible::Help);
1045 help = accessible->text(QAccessible::Help);
1048 *pszHelp = QStringToBSTR(help);
1056 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
1058 return DISP_E_MEMBERNOTFOUND;
1061 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut)
1064 showDebug(__FUNCTION__, accessible);
1065 if (!accessible->isValid())
1068 *pszKeyboardShortcut = 0;
1069 if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
1070 const QString def = actionIface->actionNames().value(0);
1071 if (!def.isEmpty()) {
1072 const QString keyBoardShortCut = actionIface->keyBindingsForAction(def).value(0);
1073 if (!keyBoardShortCut.isEmpty())
1074 *pszKeyboardShortcut = QStringToBSTR(keyBoardShortCut);
1077 return *pszKeyboardShortcut ? S_OK : S_FALSE;
1081 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* pszName)
1083 showDebug(__FUNCTION__, accessible);
1084 if (!accessible->isValid())
1089 QAIPointer child = childPointer(varID);
1092 name = child->text(QAccessible::Name);
1094 name = accessible->text(QAccessible::Name);
1097 *pszName = QStringToBSTR(name);
1105 HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accName(VARIANT, BSTR)
1107 showDebug(__FUNCTION__, accessible);
1108 return DISP_E_MEMBERNOTFOUND;
1112 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole)
1114 showDebug(__FUNCTION__, accessible);
1115 if (!accessible->isValid())
1118 QAccessible::Role role;
1120 QAIPointer child = childPointer(varID);
1123 role = child->role();
1125 role = accessible->role();
1128 if (role != QAccessible::NoRole) {
1129 if (role == QAccessible::LayeredPane)
1130 role = QAccessible::Pane;
1131 (*pvarRole).vt = VT_I4;
1132 (*pvarRole).lVal = role;
1134 (*pvarRole).vt = VT_EMPTY;
1140 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accState(VARIANT varID, VARIANT *pvarState)
1142 showDebug(__FUNCTION__, accessible);
1143 if (!accessible->isValid())
1146 QAccessible::State state;
1148 QAIPointer child = childPointer(varID);
1151 state = child->state();
1153 state = accessible->state();
1156 (*pvarState).vt = VT_I4;
1157 (*pvarState).lVal = state;
1162 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accValue(VARIANT varID, BSTR* pszValue)
1164 showDebug(__FUNCTION__, accessible);
1165 if (!accessible->isValid() || varID.lVal)
1169 if (accessible->valueInterface()) {
1170 value = QString::number(accessible->valueInterface()->currentValue().toDouble());
1172 value = accessible->text(QAccessible::Value);
1174 if (!value.isNull()) {
1175 *pszValue = QStringToBSTR(value);
1183 HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accValue(VARIANT, BSTR)
1185 showDebug(__FUNCTION__, accessible);
1186 return DISP_E_MEMBERNOTFOUND;
1190 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accSelect(long flagsSelect, VARIANT varID)
1192 showDebug(__FUNCTION__, accessible);
1193 if (!accessible->isValid())
1199 ### Check for accessibleTableInterface() or accessibleTextInterface()
1201 ### and if there are no ia2 interfaces we should do nothing??
1202 if (flagsSelect & SELFLAG_TAKEFOCUS)
1203 res = accessible->doAction(SetFocus, varID.lVal, QVariantList());
1204 if (flagsSelect & SELFLAG_TAKESELECTION) {
1205 accessible->doAction(ClearSelection, 0, QVariantList());
1206 res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
1208 if (flagsSelect & SELFLAG_EXTENDSELECTION)
1209 res = accessible->doAction(ExtendSelection, varID.lVal, QVariantList());
1210 if (flagsSelect & SELFLAG_ADDSELECTION)
1211 res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
1212 if (flagsSelect & SELFLAG_REMOVESELECTION)
1213 res = accessible->doAction(RemoveSelection, varID.lVal, QVariantList());
1215 return res ? S_OK : S_FALSE;
1219 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID)
1221 showDebug(__FUNCTION__, accessible);
1222 if (!accessible->isValid())
1225 QAccessibleInterface *acc = 0;
1226 int control = accessible->navigate(QAccessible::FocusChild, 1, &acc);
1227 if (control == -1) {
1228 (*pvarID).vt = VT_EMPTY;
1231 if (!acc || control == 0) {
1232 (*pvarID).vt = VT_I4;
1233 (*pvarID).lVal = control ? control : CHILDID_SELF;
1237 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
1238 IDispatch *iface = 0;
1239 wacc->QueryInterface(IID_IDispatch, (void**)&iface);
1241 (*pvarID).vt = VT_DISPATCH;
1242 (*pvarID).pdispVal = iface;
1248 (*pvarID).vt = VT_EMPTY;
1252 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren)
1254 showDebug(__FUNCTION__, accessible);
1255 if (!accessible->isValid())
1258 int cc = accessible->childCount();
1259 QVector<int> sel(cc);
1261 for (int i = 0; i < cc; ++i) {
1262 bool isSelected = false;
1263 QAccessibleInterface *child = accessible->child(i);
1265 isSelected = child->state() & QAccessible::Selected;
1269 sel[selIndex++] = i+1;
1271 sel.resize(selIndex);
1272 if (sel.isEmpty()) {
1273 (*pvarChildren).vt = VT_EMPTY;
1276 if (sel.size() == 1) {
1277 (*pvarChildren).vt = VT_I4;
1278 (*pvarChildren).lVal = sel[0];
1281 IEnumVARIANT *iface = new QWindowsEnumerate(sel);
1283 iface->QueryInterface(IID_IUnknown, (void**)&uiface);
1284 (*pvarChildren).vt = VT_UNKNOWN;
1285 (*pvarChildren).punkVal = uiface;
1290 static QWindow *window_helper(const QAccessibleInterface *iface)
1292 QWindow *window = iface->window();
1294 QAccessibleInterface *acc = iface->parent();
1295 while (acc && !window) {
1296 window = acc->window();
1297 QAccessibleInterface *par = acc->parent();
1305 HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetWindow(HWND *phwnd)
1308 if (!accessible->isValid())
1309 return E_UNEXPECTED;
1311 QWindow *window = window_helper(accessible);
1315 QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
1317 *phwnd = (HWND)platform->nativeResourceForWindow("handle", window);
1321 HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL)
1327 QWindowsAccessibility::QWindowsAccessibility()
1332 void QWindowsAccessibility::notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason)
1336 case QAccessible::PopupMenuStart:
1337 soundName = QLatin1String("MenuPopup");
1340 case QAccessible::MenuCommand:
1341 soundName = QLatin1String("MenuCommand");
1344 case QAccessible::Alert:
1347 #ifndef QT_NO_MESSAGEBOX
1348 QMessageBox *mb = qobject_cast<QMessageBox*>(o);
1350 switch (mb->icon()) {
1351 case QMessageBox::Warning:
1352 soundName = QLatin1String("SystemExclamation");
1354 case QMessageBox::Critical:
1355 soundName = QLatin1String("SystemHand");
1357 case QMessageBox::Information:
1358 soundName = QLatin1String("SystemAsterisk");
1364 #endif // QT_NO_MESSAGEBOX
1367 soundName = QLatin1String("SystemAsterisk");
1376 if (!soundName.isEmpty()) {
1377 #ifndef QT_NO_SETTINGS
1378 QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + soundName,
1379 QSettings::NativeFormat);
1380 QString file = settings.value(QLatin1String(".Current/.")).toString();
1384 if (!file.isEmpty()) {
1385 PlaySound(reinterpret_cast<const wchar_t *>(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT);
1389 typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1391 #if defined(Q_WS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
1392 // There is no user32.lib nor NotifyWinEvent for CE
1395 static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
1396 static bool resolvedNWE = false;
1399 ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
1401 if (!ptrNotifyWinEvent)
1404 // An event has to be associated with a window,
1405 // so find the first parent that is a widget and that has a WId
1406 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(o);
1407 QWindow *window = iface ? window_helper(iface) : 0;
1410 window = QGuiApplication::activeWindow();
1415 QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
1416 HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window);
1418 if (reason != QAccessible::MenuCommand) { // MenuCommand is faked
1419 // See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE"
1420 eventNum %= 50; //[0..49]
1421 int eventId = - eventNum - 1;
1423 qAccessibleRecentSentEvents()->insert(eventId, qMakePair(o, who));
1424 ptrNotifyWinEvent(reason, hWnd, OBJID_CLIENT, eventId );
1428 #endif // Q_WS_WINCE
1433 void QWindowsAccessibility::setRootObject(QObject *o)
1438 void QWindowsAccessibility::initialize()
1443 void QWindowsAccessibility::cleanup()
1450 bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
1452 if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) {
1453 /* For UI Automation
1455 } else if ((DWORD)lParam == OBJID_CLIENT) {
1457 // Ignoring all requests while starting up
1458 // ### Maybe QPA takes care of this???
1459 if (QApplication::startingUp() || QApplication::closingDown())
1463 typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN);
1464 static PtrLresultFromObject ptrLresultFromObject = 0;
1465 static bool oleaccChecked = false;
1467 if (!oleaccChecked) {
1468 oleaccChecked = true;
1469 #if !defined(Q_OS_WINCE)
1470 ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject");
1474 if (ptrLresultFromObject) {
1475 QWindow *window = QWindowsContext::instance()->findWindow(hwnd);
1477 QAccessibleInterface *acc = window->accessibleRoot();
1479 QWindowsAccessible *winacc = new QWindowsAccessible(acc);
1481 HRESULT hr = winacc->QueryInterface(IID_IAccessible, (void**)&iface);
1482 if (SUCCEEDED(hr)) {
1483 *lResult = ptrLresultFromObject(IID_IAccessible, wParam, iface); // ref == 2
1485 iface->Release(); // the client will release the object again, and then it will destroy itself
1498 #endif //QT_NO_ACCESSIBILITY