Do not crash in the windows accessibility bridge
[profile/ivi/qtbase.git] / src / plugins / platforms / windows / qwindowsaccessibility.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtCore/QtConfig>
43 #ifndef QT_NO_ACCESSIBILITY
44
45
46 #include "qwindowsaccessibility.h"
47 #include "qwindowscontext.h"
48
49 #include <private/qsystemlibrary_p.h>
50
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>
63 #include <OleAcc.h>
64
65 //#include <uiautomationcoreapi.h>
66 #ifndef UiaRootObjectId
67 #define UiaRootObjectId        -25
68 #endif
69
70 #include <winuser.h>
71 #if !defined(WINABLEAPI)
72 #  if defined(Q_WS_WINCE)
73 #    include <bldver.h>
74 #  endif
75 #  include <winable.h>
76 #endif
77
78 #include <oleacc.h>
79 #if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
80 #include <comdef.h>
81 #endif
82
83 #ifdef Q_WS_WINCE
84 #include "qguifunctions_wince.h"
85 #endif
86
87 QT_BEGIN_NAMESPACE
88
89 //#define DEBUG_SHOW_ATCLIENT_COMMANDS
90 #ifdef DEBUG_SHOW_ATCLIENT_COMMANDS
91 QT_BEGIN_INCLUDE_NAMESPACE
92 #include <qdebug.h>
93 QT_END_INCLUDE_NAMESPACE
94
95 static const char *roleString(QAccessible::Role role)
96 {
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*/
163    };
164
165    if (role >=0x40)
166         role = QAccessible::UserRole;
167    return roles[int(role)];
168 }
169
170 static const char *eventString(QAccessible::Event ev)
171 {
172     static const char *events[] = {
173         "null",                                 // 0
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
190
191         // Values from IAccessible2
192         "ActionChanged"        /*= 0x0101*/,    // 17
193         "ActiveDescendantChanged",
194         "AttributeChanged",
195         "DocumentContentChanged",
196         "DocumentLoadComplete",
197         "DocumentLoadStopped",
198         "DocumentReload",
199         "HyperlinkEndIndexChanged",
200         "HyperlinkNumberOfAnchorsChanged",
201         "HyperlinkSelectedLinkChanged",
202         "HypertextLinkActivated",
203         "HypertextLinkSelected",
204         "HyperlinkStartIndexChanged",
205         "HypertextChanged",
206         "HypertextNLinksChanged",
207         "ObjectAttributeChanged",
208         "PageChanged",
209         "SectionChanged",
210         "TableCaptionChanged",
211         "TableColumnDescriptionChanged",
212         "TableColumnHeaderChanged",
213         "TableModelChanged",
214         "TableRowDescriptionChanged",
215         "TableRowHeaderChanged",
216         "TableSummaryChanged",
217         "TextAttributeChanged",
218         "TextCaretMoved",
219         // TextChanged, deprecated, use TextUpdated
220         //TextColumnChanged = TextCaretMoved + 2,
221         "TextInserted",
222         "TextRemoved",
223         "TextUpdated",
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*/
245     };
246     int e = int(ev);
247     if (e <= 0x80c0) {
248         const int last = sizeof(events)/sizeof(char*) - 1;
249
250         if (e <= 0x07)
251             return events[e];
252         else if (e <= 0x13)
253             return events[e - 0x0c + 8];
254         else if (e == 0x18)
255             return events[16];
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)
265             return events[last];
266     }
267     return "unknown";
268 };
269
270 void showDebug(const char* funcName, const QAccessibleInterface *iface)
271 {
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);
276 }
277 #else
278 # define showDebug(f, iface)
279 #endif
280
281 typedef QSharedPointer<QAccessibleInterface> QAIPointer;
282
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;
287
288 class QWindowsEnumerate : public IEnumVARIANT
289 {
290 public:
291     QWindowsEnumerate(const QVector<int> &a)
292         : ref(0), current(0),array(a)
293     {
294     }
295
296     virtual ~QWindowsEnumerate() {}
297
298     HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
299     ULONG STDMETHODCALLTYPE AddRef();
300     ULONG STDMETHODCALLTYPE Release();
301
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);
306
307 private:
308     ULONG ref;
309     ULONG current;
310     QVector<int> array;
311 };
312
313 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::QueryInterface(REFIID id, LPVOID *iface)
314 {
315     *iface = 0;
316     if (id == IID_IUnknown)
317         *iface = (IUnknown*)this;
318     else if (id == IID_IEnumVARIANT)
319         *iface = (IEnumVARIANT*)this;
320
321     if (*iface) {
322         AddRef();
323         return S_OK;
324     }
325
326     return E_NOINTERFACE;
327 }
328
329 ULONG STDMETHODCALLTYPE QWindowsEnumerate::AddRef()
330 {
331     return ++ref;
332 }
333
334 ULONG STDMETHODCALLTYPE QWindowsEnumerate::Release()
335 {
336     if (!--ref) {
337         delete this;
338         return 0;
339     }
340     return ref;
341 }
342
343 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone(IEnumVARIANT **ppEnum)
344 {
345     QWindowsEnumerate *penum = 0;
346     *ppEnum = 0;
347
348     penum = new QWindowsEnumerate(array);
349     if (!penum)
350         return E_OUTOFMEMORY;
351     penum->current = current;
352     penum->array = array;
353     penum->AddRef();
354     *ppEnum = penum;
355
356     return S_OK;
357 }
358
359 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Next(unsigned long  celt, VARIANT FAR*  rgVar, unsigned long FAR*  pCeltFetched)
360 {
361     if (pCeltFetched)
362         *pCeltFetched = 0;
363
364     ULONG l;
365     for (l = 0; l < celt; l++) {
366         VariantInit(&rgVar[l]);
367         if ((current+1) > (ULONG)array.size()) {
368             *pCeltFetched = l;
369             return S_FALSE;
370         }
371
372         rgVar[l].vt = VT_I4;
373         rgVar[l].lVal = array[(int)current];
374         ++current;
375     }
376     *pCeltFetched = l;
377     return S_OK;
378 }
379
380 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Reset()
381 {
382     current = 0;
383     return S_OK;
384 }
385
386 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt)
387 {
388     current += celt;
389     if (current > (ULONG)array.size()) {
390         current = array.size();
391         return S_FALSE;
392     }
393     return S_OK;
394 }
395
396 /*
397 */
398 class QWindowsAccessible : public IAccessible, IOleWindow
399 {
400 public:
401     QWindowsAccessible(QAccessibleInterface *a)
402         : ref(0), accessible(a)
403     {
404     }
405
406     virtual ~QWindowsAccessible()
407     {
408         delete accessible;
409     }
410
411     /* IUnknown */
412     HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
413     ULONG STDMETHODCALLTYPE AddRef();
414     ULONG STDMETHODCALLTYPE Release();
415
416     /* IDispatch */
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 *);
421
422     /* IAccessible */
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);
429
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);
442
443     HRESULT STDMETHODCALLTYPE accSelect(long flagsSelect, VARIANT varID);
444     HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT *pvarID);
445     HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT *pvarChildren);
446
447     /* IOleWindow */
448     HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
449     HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
450
451 private:
452     ULONG ref;
453     QAccessibleInterface *accessible;
454
455     QAIPointer childPointer(VARIANT varID)
456     {
457         return QAIPointer(accessible->child(varID.lVal - 1));
458     }
459 };
460
461 static inline BSTR QStringToBSTR(const QString &str)
462 {
463     BSTR bstrVal;
464
465     int wlen = str.length()+1;
466     bstrVal = SysAllocStringByteLen(0, wlen*2);
467     memcpy(bstrVal, str.unicode(), sizeof(QChar)*(wlen));
468     bstrVal[wlen] = 0;
469
470     return bstrVal;
471 }
472
473 /*
474 */
475
476 /*
477   IUnknown
478 */
479 HRESULT STDMETHODCALLTYPE QWindowsAccessible::QueryInterface(REFIID id, LPVOID *iface)
480 {
481     *iface = 0;
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;
490     else
491         return E_NOINTERFACE;
492
493     AddRef();
494     return S_OK;
495 }
496
497 ULONG STDMETHODCALLTYPE QWindowsAccessible::AddRef()
498 {
499     return ++ref;
500 }
501
502 ULONG STDMETHODCALLTYPE QWindowsAccessible::Release()
503 {
504     if (!--ref) {
505         delete this;
506         return 0;
507     }
508     return ref;
509 }
510
511 /*
512   IDispatch
513 */
514
515 HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfoCount(unsigned int * pctinfo)
516 {
517     // We don't use a type library
518     *pctinfo = 0;
519     return S_OK;
520 }
521
522 HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfo(unsigned int, unsigned long, ITypeInfo **pptinfo)
523 {
524     // We don't use a type library
525     *pptinfo = 0;
526     return S_OK;
527 }
528
529 HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetIDsOfNames(const _GUID &, wchar_t **rgszNames, unsigned int, unsigned long, long *rgdispid)
530 {
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;
539
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;
563
564     // METHODS
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;
575     else
576         return DISP_E_UNKNOWNINTERFACE;
577
578     return S_OK;
579 #else
580     Q_UNUSED(rgszNames);
581     Q_UNUSED(rgdispid);
582
583     return DISP_E_MEMBERNOTFOUND;
584 #endif
585 }
586
587 HRESULT STDMETHODCALLTYPE QWindowsAccessible::Invoke(long dispIdMember, const _GUID &, unsigned long, unsigned short wFlags, tagDISPPARAMS *pDispParams, tagVARIANT *pVarResult, tagEXCEPINFO *, unsigned int *)
588 {
589     HRESULT hr = DISP_E_MEMBERNOTFOUND;
590
591     switch (dispIdMember)
592     {
593         case DISPID_ACC_PARENT:
594             if (wFlags == DISPATCH_PROPERTYGET) {
595                 if (!pVarResult)
596                     return E_INVALIDARG;
597                 hr = get_accParent(&pVarResult->pdispVal);
598             } else {
599                 hr = DISP_E_MEMBERNOTFOUND;
600             }
601             break;
602
603         case DISPID_ACC_CHILDCOUNT:
604             if (wFlags == DISPATCH_PROPERTYGET) {
605                 if (!pVarResult)
606                     return E_INVALIDARG;
607                 hr = get_accChildCount(&pVarResult->lVal);
608             } else {
609                 hr = DISP_E_MEMBERNOTFOUND;
610             }
611             break;
612
613         case DISPID_ACC_CHILD:
614             if (wFlags == DISPATCH_PROPERTYGET)
615                 hr = get_accChild(pDispParams->rgvarg[0], &pVarResult->pdispVal);
616             else
617                 hr = DISP_E_MEMBERNOTFOUND;
618             break;
619
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);
625             else
626                 hr = DISP_E_MEMBERNOTFOUND;
627             break;
628
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);
634             else
635                 hr = DISP_E_MEMBERNOTFOUND;
636             break;
637
638         case DISPID_ACC_DESCRIPTION:
639             if (wFlags == DISPATCH_PROPERTYGET)
640                 hr = get_accDescription(pDispParams->rgvarg[0], &pVarResult->bstrVal);
641             else
642                 hr = DISP_E_MEMBERNOTFOUND;
643             break;
644
645         case DISPID_ACC_ROLE:
646             if (wFlags == DISPATCH_PROPERTYGET)
647                 hr = get_accRole(pDispParams->rgvarg[0], pVarResult);
648             else
649                 hr = DISP_E_MEMBERNOTFOUND;
650             break;
651
652         case DISPID_ACC_STATE:
653             if (wFlags == DISPATCH_PROPERTYGET)
654                 hr = get_accState(pDispParams->rgvarg[0], pVarResult);
655             else
656                 hr = DISP_E_MEMBERNOTFOUND;
657             break;
658
659         case DISPID_ACC_HELP:
660             if (wFlags == DISPATCH_PROPERTYGET)
661                 hr = get_accHelp(pDispParams->rgvarg[0], &pVarResult->bstrVal);
662             else
663                 hr = DISP_E_MEMBERNOTFOUND;
664             break;
665
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);
669             else
670                 hr = DISP_E_MEMBERNOTFOUND;
671             break;
672
673         case DISPID_ACC_KEYBOARDSHORTCUT:
674             if (wFlags == DISPATCH_PROPERTYGET)
675                 hr = get_accKeyboardShortcut(pDispParams->rgvarg[0], &pVarResult->bstrVal);
676             else
677                 hr = DISP_E_MEMBERNOTFOUND;
678             break;
679
680         case DISPID_ACC_FOCUS:
681             if (wFlags == DISPATCH_PROPERTYGET)
682                 hr = get_accFocus(pVarResult);
683             else
684                 hr = DISP_E_MEMBERNOTFOUND;
685             break;
686
687         case DISPID_ACC_SELECTION:
688             if (wFlags == DISPATCH_PROPERTYGET)
689                 hr = get_accSelection(pVarResult);
690             else
691                 hr = DISP_E_MEMBERNOTFOUND;
692             break;
693
694         case DISPID_ACC_DEFAULTACTION:
695             if (wFlags == DISPATCH_PROPERTYGET)
696                 hr = get_accDefaultAction(pDispParams->rgvarg[0], &pVarResult->bstrVal);
697             else
698                 hr = DISP_E_MEMBERNOTFOUND;
699             break;
700
701         case DISPID_ACC_SELECT:
702             if (wFlags == DISPATCH_METHOD)
703                 hr = accSelect(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
704             else
705                 hr = DISP_E_MEMBERNOTFOUND;
706             break;
707
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]);
711             else
712                 hr = DISP_E_MEMBERNOTFOUND;
713             break;
714
715         case DISPID_ACC_NAVIGATE:
716             if (wFlags == DISPATCH_METHOD)
717                 hr = accNavigate(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0], pVarResult);
718             else
719                 hr = DISP_E_MEMBERNOTFOUND;
720             break;
721
722         case DISPID_ACC_HITTEST:
723             if (wFlags == DISPATCH_METHOD)
724                 hr = accHitTest(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].lVal, pVarResult);
725             else
726                 hr = DISP_E_MEMBERNOTFOUND;
727             break;
728
729         case DISPID_ACC_DODEFAULTACTION:
730             if (wFlags == DISPATCH_METHOD)
731                 hr = accDoDefaultAction(pDispParams->rgvarg[0]);
732             else
733                 hr = DISP_E_MEMBERNOTFOUND;
734             break;
735
736         default:
737             hr = DISP_E_MEMBERNOTFOUND;
738             break;
739     }
740
741     if (!SUCCEEDED(hr)) {
742         return hr;
743     }
744     return hr;
745 }
746
747 /*
748   IAccessible
749 */
750 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
751 {
752     showDebug(__FUNCTION__, accessible);
753     if (!accessible->isValid())
754         return E_FAIL;
755
756     QAccessibleInterface *child = accessible->childAt(xLeft, yTop);
757     if (child == 0) {
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);
762             if (iface) {
763                 (*pvarID).vt = VT_DISPATCH;
764                 (*pvarID).pdispVal = iface;
765                 return S_OK;
766             }
767         }
768         (*pvarID).vt = VT_EMPTY;
769         return S_FALSE;
770     }
771
772     QWindowsAccessible* wacc = new QWindowsAccessible(child);
773     IDispatch *iface = 0;
774     wacc->QueryInterface(IID_IDispatch, (void**)&iface);
775     if (iface) {
776         (*pvarID).vt = VT_DISPATCH;
777         (*pvarID).pdispVal = iface;
778         return S_OK;
779     } else {
780         delete wacc;
781     }
782
783     (*pvarID).vt = VT_EMPTY;
784     return S_FALSE;
785 }
786
787 /*
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)
792
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.
795 */
796 // moz: [important]
797 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
798 {
799     showDebug(__FUNCTION__, accessible);
800     if (!accessible->isValid())
801         return E_FAIL;
802
803     QRect rect;
804     if (varID.lVal) {
805         QAIPointer child = QAIPointer(accessible->child(varID.lVal - 1));
806         if (child->isValid())
807             rect = child->rect();
808     } else {
809         rect = accessible->rect();
810     }
811
812     *pxLeft = rect.x();
813     *pyTop = rect.y();
814     *pcxWidth = rect.width();
815     *pcyHeight = rect.height();
816
817     return S_OK;
818 }
819
820 // moz: [important, but no need to implement up/down/left/right]
821 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
822 {
823     showDebug(__FUNCTION__, accessible);
824     if (!accessible->isValid())
825         return E_FAIL;
826
827     QAccessibleInterface *acc = 0;
828     int control = -1;
829     switch (navDir) {
830     case NAVDIR_FIRSTCHILD:
831         control = accessible->navigate(QAccessible::Child, 1, &acc);
832         break;
833     case NAVDIR_LASTCHILD:
834         control = accessible->navigate(QAccessible::Child, accessible->childCount(), &acc);
835         break;
836     case NAVDIR_NEXT:
837     case NAVDIR_PREVIOUS:
838         if (!varStart.lVal){
839             QAccessibleInterface *parent = accessible->parent();
840             if (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);
845                 delete parent;
846             }
847         } else {
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);
852         }
853         break;
854     case NAVDIR_UP:
855         control = accessible->navigate(QAccessible::Up, varStart.lVal, &acc);
856         break;
857     case NAVDIR_DOWN:
858         control = accessible->navigate(QAccessible::Down, varStart.lVal, &acc);
859         break;
860     case NAVDIR_LEFT:
861         control = accessible->navigate(QAccessible::Left, varStart.lVal, &acc);
862         break;
863     case NAVDIR_RIGHT:
864         control = accessible->navigate(QAccessible::Right, varStart.lVal, &acc);
865         break;
866     default:
867         break;
868     }
869     if (control == -1) {
870         (*pvarEnd).vt = VT_EMPTY;
871         return S_FALSE;
872     }
873     if (!acc) {
874         (*pvarEnd).vt = VT_I4;
875         (*pvarEnd).lVal = control;
876         return S_OK;
877     }
878
879     QWindowsAccessible* wacc = new QWindowsAccessible(acc);
880
881     IDispatch *iface = 0;
882     wacc->QueryInterface(IID_IDispatch, (void**)&iface);
883     if (iface) {
884         (*pvarEnd).vt = VT_DISPATCH;
885         (*pvarEnd).pdispVal = iface;
886         return S_OK;
887     } else {
888         delete wacc;
889     }
890
891     (*pvarEnd).vt = VT_EMPTY;
892     return S_FALSE;
893 }
894
895 // moz: [important]
896 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
897 {
898     showDebug(__FUNCTION__, accessible);
899     if (!accessible->isValid())
900         return E_FAIL;
901
902     if (varChildID.vt == VT_EMPTY)
903         return E_INVALIDARG;
904
905
906     int childIndex = varChildID.lVal;
907     QAccessibleInterface *acc = 0;
908
909     if (childIndex < 0) {
910         const int entry = childIndex;
911         QPair<QObject*, int> ref = qAccessibleRecentSentEvents()->value(entry);
912         if (ref.first) {
913             acc = QAccessible::queryAccessibleInterface(ref.first);
914             if (acc && ref.second) {
915                 if (ref.second) {
916                     QAccessibleInterface *res;
917                     int index = acc->navigate(QAccessible::Child, ref.second, &res);
918                     delete acc;
919                     if (index == -1)
920                         return E_INVALIDARG;
921                     acc = res;
922                 }
923             }
924         }
925     } else {
926         QAccessible::RelationFlag rel = childIndex ? QAccessible::Child : QAccessible::Self;
927         accessible->navigate(rel, childIndex, &acc);
928     }
929
930     if (acc) {
931         QWindowsAccessible* wacc = new QWindowsAccessible(acc);
932         wacc->QueryInterface(IID_IDispatch, (void**)ppdispChild);
933         return S_OK;
934     }
935
936     *ppdispChild = 0;
937     return S_FALSE;
938 }
939
940 // moz: [important]
941 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChildCount(long* pcountChildren)
942 {
943     showDebug(__FUNCTION__, accessible);
944     if (!accessible->isValid())
945         return E_FAIL;
946
947     *pcountChildren = accessible->childCount();
948     return S_OK;
949 }
950
951 // moz: [important]
952 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispParent)
953 {
954     showDebug(__FUNCTION__, accessible);
955     if (!accessible->isValid())
956         return E_FAIL;
957
958     QAccessibleInterface *acc = accessible->parent();
959     if (acc) {
960         QWindowsAccessible* wacc = new QWindowsAccessible(acc);
961         wacc->QueryInterface(IID_IDispatch, (void**)ppdispParent);
962
963         if (*ppdispParent)
964             return S_OK;
965     }
966
967     *ppdispParent = 0;
968     return S_FALSE;
969 }
970
971 /*
972   Properties and methods
973 */
974 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accDoDefaultAction(VARIANT varID)
975 {
976     Q_UNUSED(varID);
977     showDebug(__FUNCTION__, accessible);
978     if (!accessible->isValid())
979         return E_FAIL;
980
981     if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
982         const QString def = actionIface->actionNames().value(0);
983         if (!def.isEmpty()) {
984             actionIface->doAction(def);
985             return S_OK;
986         }
987     }
988     return S_FALSE;
989 }
990
991 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction)
992 {
993     Q_UNUSED(varID);
994     showDebug(__FUNCTION__, accessible);
995     if (!accessible->isValid())
996         return E_FAIL;
997
998     *pszDefaultAction = 0;
999     if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
1000         const QString def = actionIface->actionNames().value(0);
1001         if (!def.isEmpty())
1002             *pszDefaultAction = QStringToBSTR(def);
1003     }
1004     return *pszDefaultAction ? S_OK : S_FALSE;
1005 }
1006
1007 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription)
1008 {
1009     showDebug(__FUNCTION__, accessible);
1010     if (!accessible->isValid())
1011         return E_FAIL;
1012
1013
1014     QString descr;
1015     if (varID.lVal) {
1016         QAIPointer child = childPointer(varID);
1017         if (!child)
1018             return E_FAIL;
1019         descr = child->text(QAccessible::Description);
1020     } else {
1021         descr = accessible->text(QAccessible::Description);
1022     }
1023     if (descr.size()) {
1024         *pszDescription = QStringToBSTR(descr);
1025         return S_OK;
1026     }
1027
1028     *pszDescription = 0;
1029     return S_FALSE;
1030 }
1031
1032 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp)
1033 {
1034     showDebug(__FUNCTION__, accessible);
1035     if (!accessible->isValid())
1036         return E_FAIL;
1037
1038     QString help;
1039     if (varID.lVal) {
1040         QAIPointer child = childPointer(varID);
1041         if (!child)
1042             return E_FAIL;
1043         help = child->text(QAccessible::Help);
1044     } else {
1045         help = accessible->text(QAccessible::Help);
1046     }
1047     if (help.size()) {
1048         *pszHelp = QStringToBSTR(help);
1049         return S_OK;
1050     }
1051
1052     *pszHelp = 0;
1053     return S_FALSE;
1054 }
1055
1056 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
1057 {
1058     return DISP_E_MEMBERNOTFOUND;
1059 }
1060
1061 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut)
1062 {
1063     Q_UNUSED(varID);
1064     showDebug(__FUNCTION__, accessible);
1065     if (!accessible->isValid())
1066         return E_FAIL;
1067
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);
1075         }
1076     }
1077     return *pszKeyboardShortcut ? S_OK : S_FALSE;
1078 }
1079
1080 // moz: [important]
1081 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* pszName)
1082 {
1083     showDebug(__FUNCTION__, accessible);
1084     if (!accessible->isValid())
1085         return E_FAIL;
1086
1087     QString name;
1088     if (varID.lVal) {
1089         QAIPointer child = childPointer(varID);
1090         if (!child)
1091             return E_FAIL;
1092         name = child->text(QAccessible::Name);
1093     } else {
1094         name = accessible->text(QAccessible::Name);
1095     }
1096     if (name.size()) {
1097         *pszName = QStringToBSTR(name);
1098         return S_OK;
1099     }
1100
1101     *pszName = 0;
1102     return S_FALSE;
1103 }
1104
1105 HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accName(VARIANT, BSTR)
1106 {
1107     showDebug(__FUNCTION__, accessible);
1108     return DISP_E_MEMBERNOTFOUND;
1109 }
1110
1111 // moz: [important]
1112 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole)
1113 {
1114     showDebug(__FUNCTION__, accessible);
1115     if (!accessible->isValid())
1116         return E_FAIL;
1117
1118     QAccessible::Role role;
1119     if (varID.lVal) {
1120         QAIPointer child = childPointer(varID);
1121         if (!child)
1122             return E_FAIL;
1123         role = child->role();
1124     } else {
1125         role = accessible->role();
1126     }
1127
1128     if (role != QAccessible::NoRole) {
1129         if (role == QAccessible::LayeredPane)
1130             role = QAccessible::Pane;
1131         (*pvarRole).vt = VT_I4;
1132         (*pvarRole).lVal = role;
1133     } else {
1134         (*pvarRole).vt = VT_EMPTY;
1135     }
1136     return S_OK;
1137 }
1138
1139 // moz: [important]
1140 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accState(VARIANT varID, VARIANT *pvarState)
1141 {
1142     showDebug(__FUNCTION__, accessible);
1143     if (!accessible->isValid())
1144         return E_FAIL;
1145
1146     QAccessible::State state;
1147     if (varID.lVal) {
1148         QAIPointer child = childPointer(varID);
1149         if (!child.data())
1150             return E_FAIL;
1151         state = child->state();
1152     } else {
1153         state = accessible->state();
1154     }
1155
1156     (*pvarState).vt = VT_I4;
1157     (*pvarState).lVal = state;
1158     return S_OK;
1159 }
1160
1161 // moz: [important]
1162 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accValue(VARIANT varID, BSTR* pszValue)
1163 {
1164     showDebug(__FUNCTION__, accessible);
1165     if (!accessible->isValid() || varID.lVal)
1166         return E_FAIL;
1167
1168     QString value;
1169     if (accessible->valueInterface()) {
1170         value = QString::number(accessible->valueInterface()->currentValue().toDouble());
1171     } else {
1172         value = accessible->text(QAccessible::Value);
1173     }
1174     if (!value.isNull()) {
1175         *pszValue = QStringToBSTR(value);
1176         return S_OK;
1177     }
1178
1179     *pszValue = 0;
1180     return S_FALSE;
1181 }
1182
1183 HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accValue(VARIANT, BSTR)
1184 {
1185     showDebug(__FUNCTION__, accessible);
1186     return DISP_E_MEMBERNOTFOUND;
1187 }
1188
1189 // moz: [important]
1190 HRESULT STDMETHODCALLTYPE QWindowsAccessible::accSelect(long flagsSelect, VARIANT varID)
1191 {
1192     showDebug(__FUNCTION__, accessible);
1193     if (!accessible->isValid())
1194         return E_FAIL;
1195
1196     bool res = false;
1197
1198 /*
1199   ### Check for accessibleTableInterface() or accessibleTextInterface()
1200
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());
1207     }
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());
1214 */
1215     return res ? S_OK : S_FALSE;
1216 }
1217
1218 // moz: [important]
1219 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID)
1220 {
1221     showDebug(__FUNCTION__, accessible);
1222     if (!accessible->isValid())
1223         return E_FAIL;
1224
1225     QAccessibleInterface *acc = 0;
1226     int control = accessible->navigate(QAccessible::FocusChild, 1, &acc);
1227     if (control == -1) {
1228         (*pvarID).vt = VT_EMPTY;
1229         return S_FALSE;
1230     }
1231     if (!acc || control == 0) {
1232         (*pvarID).vt = VT_I4;
1233         (*pvarID).lVal = control ? control : CHILDID_SELF;
1234         return S_OK;
1235     }
1236
1237     QWindowsAccessible* wacc = new QWindowsAccessible(acc);
1238     IDispatch *iface = 0;
1239     wacc->QueryInterface(IID_IDispatch, (void**)&iface);
1240     if (iface) {
1241         (*pvarID).vt = VT_DISPATCH;
1242         (*pvarID).pdispVal = iface;
1243         return S_OK;
1244     } else {
1245         delete wacc;
1246     }
1247
1248     (*pvarID).vt = VT_EMPTY;
1249     return S_FALSE;
1250 }
1251
1252 HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren)
1253 {
1254     showDebug(__FUNCTION__, accessible);
1255     if (!accessible->isValid())
1256         return E_FAIL;
1257
1258     int cc = accessible->childCount();
1259     QVector<int> sel(cc);
1260     int selIndex = 0;
1261     for (int i = 0; i < cc; ++i) {
1262         bool isSelected = false;
1263         QAccessibleInterface *child = accessible->child(i);
1264         if (child) {
1265             isSelected = child->state() & QAccessible::Selected;
1266             delete child;
1267         }
1268         if (isSelected)
1269             sel[selIndex++] = i+1;
1270     }
1271     sel.resize(selIndex);
1272     if (sel.isEmpty()) {
1273         (*pvarChildren).vt = VT_EMPTY;
1274         return S_FALSE;
1275     }
1276     if (sel.size() == 1) {
1277         (*pvarChildren).vt = VT_I4;
1278         (*pvarChildren).lVal = sel[0];
1279         return S_OK;
1280     }
1281     IEnumVARIANT *iface = new QWindowsEnumerate(sel);
1282     IUnknown *uiface;
1283     iface->QueryInterface(IID_IUnknown, (void**)&uiface);
1284     (*pvarChildren).vt = VT_UNKNOWN;
1285     (*pvarChildren).punkVal = uiface;
1286
1287     return S_OK;
1288 }
1289
1290 static QWindow *window_helper(const QAccessibleInterface *iface)
1291 {
1292     QWindow *window = iface->window();
1293     if (!window) {
1294         QAccessibleInterface *acc = iface->parent();
1295         while (acc && !window) {
1296             window = acc->window();
1297             QAccessibleInterface *par = acc->parent();
1298             delete acc;
1299             acc = par;
1300         }
1301     }
1302     return window;
1303 }
1304
1305 HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetWindow(HWND *phwnd)
1306 {
1307     *phwnd = 0;
1308     if (!accessible->isValid())
1309         return E_UNEXPECTED;
1310
1311     QWindow *window = window_helper(accessible);
1312     if (!window)
1313         return E_FAIL;
1314
1315     QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
1316     Q_ASSERT(platform);
1317     *phwnd = (HWND)platform->nativeResourceForWindow("handle", window);
1318     return S_OK;
1319 }
1320
1321 HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL)
1322 {
1323     return S_OK;
1324 }
1325
1326
1327 QWindowsAccessibility::QWindowsAccessibility()
1328 {
1329 }
1330
1331
1332 void QWindowsAccessibility::notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason)
1333 {
1334     QString soundName;
1335     switch (reason) {
1336     case QAccessible::PopupMenuStart:
1337         soundName = QLatin1String("MenuPopup");
1338         break;
1339
1340     case QAccessible::MenuCommand:
1341         soundName = QLatin1String("MenuCommand");
1342         break;
1343
1344     case QAccessible::Alert:
1345         {
1346         /*      ### FIXME
1347 #ifndef QT_NO_MESSAGEBOX
1348             QMessageBox *mb = qobject_cast<QMessageBox*>(o);
1349             if (mb) {
1350                 switch (mb->icon()) {
1351                 case QMessageBox::Warning:
1352                     soundName = QLatin1String("SystemExclamation");
1353                     break;
1354                 case QMessageBox::Critical:
1355                     soundName = QLatin1String("SystemHand");
1356                     break;
1357                 case QMessageBox::Information:
1358                     soundName = QLatin1String("SystemAsterisk");
1359                     break;
1360                 default:
1361                     break;
1362                 }
1363             } else
1364 #endif // QT_NO_MESSAGEBOX
1365 */
1366             {
1367                 soundName = QLatin1String("SystemAsterisk");
1368             }
1369
1370         }
1371         break;
1372     default:
1373         break;
1374     }
1375
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();
1381 #else
1382         QString file;
1383 #endif
1384         if (!file.isEmpty()) {
1385             PlaySound(reinterpret_cast<const wchar_t *>(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT);
1386         }
1387     }
1388
1389     typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1390
1391 #if defined(Q_WS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
1392     // There is no user32.lib nor NotifyWinEvent for CE
1393     return;
1394 #else
1395     static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
1396     static bool resolvedNWE = false;
1397     if (!resolvedNWE) {
1398         resolvedNWE = true;
1399         ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
1400     }
1401     if (!ptrNotifyWinEvent)
1402         return;
1403
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;
1408
1409     if (!window) {
1410         window = QGuiApplication::activeWindow();
1411         if (!window)
1412             return;
1413     }
1414
1415     QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
1416     HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window);
1417
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;
1422
1423         qAccessibleRecentSentEvents()->insert(eventId, qMakePair(o, who));
1424         ptrNotifyWinEvent(reason, hWnd, OBJID_CLIENT, eventId );
1425
1426         ++eventNum;
1427     }
1428 #endif // Q_WS_WINCE
1429
1430 }
1431
1432 /*
1433 void QWindowsAccessibility::setRootObject(QObject *o)
1434 {
1435
1436 }
1437
1438 void QWindowsAccessibility::initialize()
1439 {
1440
1441 }
1442
1443 void QWindowsAccessibility::cleanup()
1444 {
1445
1446 }
1447
1448 */
1449
1450 bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
1451 {
1452     if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) {
1453         /* For UI Automation
1454       */
1455     } else if ((DWORD)lParam == OBJID_CLIENT) {
1456 #if 1
1457         // Ignoring all requests while starting up
1458         // ### Maybe QPA takes care of this???
1459         if (QApplication::startingUp() || QApplication::closingDown())
1460             return false;
1461 #endif
1462
1463         typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN);
1464         static PtrLresultFromObject ptrLresultFromObject = 0;
1465         static bool oleaccChecked = false;
1466
1467         if (!oleaccChecked) {
1468             oleaccChecked = true;
1469 #if !defined(Q_OS_WINCE)
1470             ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject");
1471 #endif
1472         }
1473
1474         if (ptrLresultFromObject) {
1475             QWindow *window = QWindowsContext::instance()->findWindow(hwnd);
1476             if (window) {
1477                 QAccessibleInterface *acc = window->accessibleRoot();
1478                 if (acc) {
1479                     QWindowsAccessible *winacc = new QWindowsAccessible(acc);
1480                     IAccessible *iface;
1481                     HRESULT hr = winacc->QueryInterface(IID_IAccessible, (void**)&iface);
1482                     if (SUCCEEDED(hr)) {
1483                         *lResult = ptrLresultFromObject(IID_IAccessible, wParam, iface);  // ref == 2
1484                         if (*lResult) {
1485                             iface->Release(); // the client will release the object again, and then it will destroy itself
1486                         }
1487                         return true;
1488                     }
1489                 }
1490             }
1491         }
1492     }
1493     return false;
1494 }
1495
1496 QT_END_NAMESPACE
1497
1498 #endif //QT_NO_ACCESSIBILITY