source: trunk/src/gui/accessible/qaccessible_win.cpp@ 122

Last change on this file since 122 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 35.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41#include "qaccessible.h"
42#ifndef QT_NO_ACCESSIBILITY
43
44#include "qapplication.h"
45#include "qlibrary.h"
46#include "qmessagebox.h" // ### dependency
47#include "qt_windows.h"
48#include "qwidget.h"
49#include "qsettings.h"
50
51#include <winuser.h>
52#if !defined(WINABLEAPI)
53# if defined(Q_OS_WINCE)
54# include <bldver.h>
55# endif
56# include <winable.h>
57#endif
58
59#include <oleacc.h>
60#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
61#include <comdef.h>
62#endif
63
64#ifdef Q_OS_WINCE
65#include "qguifunctions_wince.h"
66#endif
67
68QT_BEGIN_NAMESPACE
69
70//#define DEBUG_SHOW_ATCLIENT_COMMANDS
71#ifdef DEBUG_SHOW_ATCLIENT_COMMANDS
72QT_BEGIN_INCLUDE_NAMESPACE
73#include <qdebug.h>
74QT_END_INCLUDE_NAMESPACE
75
76static const char *roleString(QAccessible::Role role)
77{
78 static const char *roles[] = {
79 "NoRole" /*= 0x00000000*/,
80 "TitleBar" /*= 0x00000001*/,
81 "MenuBar" /*= 0x00000002*/,
82 "ScrollBar" /*= 0x00000003*/,
83 "Grip" /*= 0x00000004*/,
84 "Sound" /*= 0x00000005*/,
85 "Cursor" /*= 0x00000006*/,
86 "Caret" /*= 0x00000007*/,
87 "AlertMessage" /*= 0x00000008*/,
88 "Window" /*= 0x00000009*/,
89 "Client" /*= 0x0000000A*/,
90 "PopupMenu" /*= 0x0000000B*/,
91 "MenuItem" /*= 0x0000000C*/,
92 "ToolTip" /*= 0x0000000D*/,
93 "Application" /*= 0x0000000E*/,
94 "Document" /*= 0x0000000F*/,
95 "Pane" /*= 0x00000010*/,
96 "Chart" /*= 0x00000011*/,
97 "Dialog" /*= 0x00000012*/,
98 "Border" /*= 0x00000013*/,
99 "Grouping" /*= 0x00000014*/,
100 "Separator" /*= 0x00000015*/,
101 "ToolBar" /*= 0x00000016*/,
102 "StatusBar" /*= 0x00000017*/,
103 "Table" /*= 0x00000018*/,
104 "ColumnHeader" /*= 0x00000019*/,
105 "RowHeader" /*= 0x0000001A*/,
106 "Column" /*= 0x0000001B*/,
107 "Row" /*= 0x0000001C*/,
108 "Cell" /*= 0x0000001D*/,
109 "Link" /*= 0x0000001E*/,
110 "HelpBalloon" /*= 0x0000001F*/,
111 "Assistant" /*= 0x00000020*/,
112 "List" /*= 0x00000021*/,
113 "ListItem" /*= 0x00000022*/,
114 "Tree" /*= 0x00000023*/,
115 "TreeItem" /*= 0x00000024*/,
116 "PageTab" /*= 0x00000025*/,
117 "PropertyPage" /*= 0x00000026*/,
118 "Indicator" /*= 0x00000027*/,
119 "Graphic" /*= 0x00000028*/,
120 "StaticText" /*= 0x00000029*/,
121 "EditableText" /*= 0x0000002A*/, // Editable, selectable, etc.
122 "PushButton" /*= 0x0000002B*/,
123 "CheckBox" /*= 0x0000002C*/,
124 "RadioButton" /*= 0x0000002D*/,
125 "ComboBox" /*= 0x0000002E*/,
126 "DropList" /*= 0x0000002F*/, // commented out
127 "ProgressBar" /*= 0x00000030*/,
128 "Dial" /*= 0x00000031*/,
129 "HotkeyField" /*= 0x00000032*/,
130 "Slider" /*= 0x00000033*/,
131 "SpinBox" /*= 0x00000034*/,
132 "Canvas" /*= 0x00000035*/,
133 "Animation" /*= 0x00000036*/,
134 "Equation" /*= 0x00000037*/,
135 "ButtonDropDown" /*= 0x00000038*/,
136 "ButtonMenu" /*= 0x00000039*/,
137 "ButtonDropGrid" /*= 0x0000003A*/,
138 "Whitespace" /*= 0x0000003B*/,
139 "PageTabList" /*= 0x0000003C*/,
140 "Clock" /*= 0x0000003D*/,
141 "Splitter" /*= 0x0000003E*/,
142 "LayeredPane" /*= 0x0000003F*/,
143 "UserRole" /*= 0x0000ffff*/
144 };
145
146 if (role >=0x40)
147 role = QAccessible::UserRole;
148 return roles[int(role)];
149}
150
151void showDebug(const char* funcName, const QAccessibleInterface *iface)
152{
153 qDebug() << "Role:" << roleString(iface->role(0))
154 << "Name:" << iface->text(QAccessible::Name, 0)
155 << "State:" << QString::number(int(iface->state(0)), 16)
156 << QLatin1String(funcName);
157}
158#else
159# define showDebug(f, iface)
160#endif
161
162void QAccessible::initialize()
163{
164
165}
166void QAccessible::cleanup()
167{
168
169}
170
171void QAccessible::updateAccessibility(QObject *o, int who, Event reason)
172{
173 Q_ASSERT(o);
174
175 if (updateHandler) {
176 updateHandler(o, who, reason);
177 return;
178 }
179
180 QByteArray soundName;
181 switch (reason) {
182 case PopupMenuStart:
183 soundName = "MenuPopup";
184 break;
185
186 case MenuCommand:
187 soundName = "MenuCommand";
188 break;
189
190 case Alert:
191 {
192#ifndef QT_NO_MESSAGEBOX
193 QMessageBox *mb = qobject_cast<QMessageBox*>(o);
194 if (mb) {
195 switch (mb->icon()) {
196 case QMessageBox::Warning:
197 soundName = "SystemExclamation";
198 break;
199 case QMessageBox::Critical:
200 soundName = "SystemHand";
201 break;
202 case QMessageBox::Information:
203 soundName = "SystemAsterisk";
204 break;
205 default:
206 break;
207 }
208 } else
209#endif // QT_NO_MESSAGEBOX
210 {
211 soundName = "SystemAsterisk";
212 }
213
214 }
215 break;
216 default:
217 break;
218 }
219
220 if (soundName.size()) {
221#ifndef QT_NO_SETTINGS
222 QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") +
223 QString::fromLatin1(soundName.constData()), QSettings::NativeFormat);
224 QString file = settings.value(QLatin1String(".Current/.")).toString();
225#else
226 QString file;
227#endif
228 if (!file.isEmpty()) {
229 QT_WA({
230 PlaySoundW(reinterpret_cast<const wchar_t *> (QString::fromLatin1(soundName).utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT );
231 } , {
232 PlaySoundA(soundName.constData(), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT );
233 });
234 }
235 }
236
237 if (!isActive())
238 return;
239
240 typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
241
242#if defined(Q_OS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
243 // There is no user32.lib nor NotifyWinEvent for CE
244 return;
245#else
246 static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
247 static bool resolvedNWE = false;
248 if (!resolvedNWE) {
249 resolvedNWE = true;
250 ptrNotifyWinEvent = (PtrNotifyWinEvent)QLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
251 }
252 if (!ptrNotifyWinEvent)
253 return;
254
255 // An event has to be associated with a window,
256 // so find the first parent that is a widget.
257 QWidget *w = 0;
258 if (o->isWidgetType()) {
259 w = (QWidget*)o;
260 } else {
261 QObject *p = o;
262 while ((p = p->parent()) != 0) {
263 if (p->isWidgetType()) {
264 w = (QWidget*)p;
265 break;
266 }
267 }
268 }
269
270 if (!w) {
271 if (reason != QAccessible::ContextHelpStart &&
272 reason != QAccessible::ContextHelpEnd)
273 w = qApp->focusWidget();
274 if (!w) {
275 w = qApp->activeWindow();
276
277 if (!w)
278 return;
279
280// ### Fixme
281// if (!w) {
282// w = qApp->mainWidget();
283// if (!w)
284// return;
285// }
286 }
287 }
288
289 if (reason != MenuCommand) { // MenuCommand is faked
290 ptrNotifyWinEvent(reason, w->winId(), OBJID_CLIENT, who);
291 }
292#endif // Q_OS_WINCE
293}
294
295void QAccessible::setRootObject(QObject *o)
296{
297 if (rootObjectHandler) {
298 rootObjectHandler(o);
299 }
300}
301
302class QWindowsEnumerate : public IEnumVARIANT
303{
304public:
305 QWindowsEnumerate(const QVector<int> &a)
306 : ref(0), current(0),array(a)
307 {
308 }
309
310 virtual ~QWindowsEnumerate() {}
311
312 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
313 ULONG STDMETHODCALLTYPE AddRef();
314 ULONG STDMETHODCALLTYPE Release();
315
316 HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **ppEnum);
317 HRESULT STDMETHODCALLTYPE Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched);
318 HRESULT STDMETHODCALLTYPE Reset();
319 HRESULT STDMETHODCALLTYPE Skip(unsigned long celt);
320
321private:
322 ULONG ref;
323 ULONG current;
324 QVector<int> array;
325};
326
327HRESULT STDMETHODCALLTYPE QWindowsEnumerate::QueryInterface(REFIID id, LPVOID *iface)
328{
329 *iface = 0;
330 if (id == IID_IUnknown)
331 *iface = (IUnknown*)this;
332 else if (id == IID_IEnumVARIANT)
333 *iface = (IEnumVARIANT*)this;
334
335 if (*iface) {
336 AddRef();
337 return S_OK;
338 }
339
340 return E_NOINTERFACE;
341}
342
343ULONG STDMETHODCALLTYPE QWindowsEnumerate::AddRef()
344{
345 return ++ref;
346}
347
348ULONG STDMETHODCALLTYPE QWindowsEnumerate::Release()
349{
350 if (!--ref) {
351 delete this;
352 return 0;
353 }
354 return ref;
355}
356
357HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone(IEnumVARIANT **ppEnum)
358{
359 QWindowsEnumerate *penum = 0;
360 *ppEnum = 0;
361
362 penum = new QWindowsEnumerate(array);
363 if (!penum)
364 return E_OUTOFMEMORY;
365 penum->current = current;
366 penum->array = array;
367 penum->AddRef();
368 *ppEnum = penum;
369
370 return S_OK;
371}
372
373HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched)
374{
375 if (pCeltFetched)
376 *pCeltFetched = 0;
377
378 ULONG l;
379 for (l = 0; l < celt; l++) {
380 VariantInit(&rgVar[l]);
381 if ((current+1) > (ULONG)array.size()) {
382 *pCeltFetched = l;
383 return S_FALSE;
384 }
385
386 rgVar[l].vt = VT_I4;
387 rgVar[l].lVal = array[(int)current];
388 ++current;
389 }
390 *pCeltFetched = l;
391 return S_OK;
392}
393
394HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Reset()
395{
396 current = 0;
397 return S_OK;
398}
399
400HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt)
401{
402 current += celt;
403 if (current > (ULONG)array.size()) {
404 current = array.size();
405 return S_FALSE;
406 }
407 return S_OK;
408}
409
410/*
411*/
412class QWindowsAccessible : public IAccessible, IOleWindow, QAccessible
413{
414public:
415 QWindowsAccessible(QAccessibleInterface *a)
416 : ref(0), accessible(a)
417 {
418 }
419
420 virtual ~QWindowsAccessible()
421 {
422 delete accessible;
423 }
424
425 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
426 ULONG STDMETHODCALLTYPE AddRef();
427 ULONG STDMETHODCALLTYPE Release();
428
429 HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int *);
430 HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int, unsigned long, ITypeInfo **);
431 HRESULT STDMETHODCALLTYPE GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *);
432 HRESULT STDMETHODCALLTYPE Invoke(long, const _GUID &, unsigned long, unsigned short, tagDISPPARAMS *, tagVARIANT *, tagEXCEPINFO *, unsigned int *);
433
434 HRESULT STDMETHODCALLTYPE accHitTest(long xLeft, long yTop, VARIANT *pvarID);
435 HRESULT STDMETHODCALLTYPE accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID);
436 HRESULT STDMETHODCALLTYPE accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd);
437 HRESULT STDMETHODCALLTYPE get_accChild(VARIANT varChildID, IDispatch** ppdispChild);
438 HRESULT STDMETHODCALLTYPE get_accChildCount(long* pcountChildren);
439 HRESULT STDMETHODCALLTYPE get_accParent(IDispatch** ppdispParent);
440
441 HRESULT STDMETHODCALLTYPE accDoDefaultAction(VARIANT varID);
442 HRESULT STDMETHODCALLTYPE get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction);
443 HRESULT STDMETHODCALLTYPE get_accDescription(VARIANT varID, BSTR* pszDescription);
444 HRESULT STDMETHODCALLTYPE get_accHelp(VARIANT varID, BSTR *pszHelp);
445 HRESULT STDMETHODCALLTYPE get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic);
446 HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut);
447 HRESULT STDMETHODCALLTYPE get_accName(VARIANT varID, BSTR* pszName);
448 HRESULT STDMETHODCALLTYPE put_accName(VARIANT varChild, BSTR szName);
449 HRESULT STDMETHODCALLTYPE get_accRole(VARIANT varID, VARIANT *pvarRole);
450 HRESULT STDMETHODCALLTYPE get_accState(VARIANT varID, VARIANT *pvarState);
451 HRESULT STDMETHODCALLTYPE get_accValue(VARIANT varID, BSTR* pszValue);
452 HRESULT STDMETHODCALLTYPE put_accValue(VARIANT varChild, BSTR szValue);
453
454 HRESULT STDMETHODCALLTYPE accSelect(long flagsSelect, VARIANT varID);
455 HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT *pvarID);
456 HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT *pvarChildren);
457
458 HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
459 HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
460
461private:
462 ULONG ref;
463 QAccessibleInterface *accessible;
464};
465
466static inline BSTR QStringToBSTR(const QString &str)
467{
468 BSTR bstrVal;
469
470 int wlen = str.length()+1;
471 bstrVal = SysAllocStringByteLen(0, wlen*2);
472 memcpy(bstrVal, str.unicode(), sizeof(QChar)*(wlen));
473 bstrVal[wlen] = 0;
474
475 return bstrVal;
476}
477
478/*
479*/
480IAccessible *qt_createWindowsAccessible(QAccessibleInterface *access)
481{
482 QWindowsAccessible *acc = new QWindowsAccessible(access);
483 IAccessible *iface;
484 acc->QueryInterface(IID_IAccessible, (void**)&iface);
485
486 return iface;
487}
488
489/*
490 IUnknown
491*/
492HRESULT STDMETHODCALLTYPE QWindowsAccessible::QueryInterface(REFIID id, LPVOID *iface)
493{
494 *iface = 0;
495 if (id == IID_IUnknown)
496 *iface = (IUnknown*)(IDispatch*)this;
497 else if (id == IID_IDispatch)
498 *iface = (IDispatch*)this;
499 else if (id == IID_IAccessible)
500 *iface = (IAccessible*)this;
501 else if (id == IID_IOleWindow)
502 *iface = (IOleWindow*)this;
503 else
504 return E_NOINTERFACE;
505
506 AddRef();
507 return S_OK;
508}
509
510ULONG STDMETHODCALLTYPE QWindowsAccessible::AddRef()
511{
512 return ++ref;
513}
514
515ULONG STDMETHODCALLTYPE QWindowsAccessible::Release()
516{
517 if (!--ref) {
518 delete this;
519 return 0;
520 }
521 return ref;
522}
523
524/*
525 IDispatch
526*/
527
528HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfoCount(unsigned int * pctinfo)
529{
530 // We don't use a type library
531 *pctinfo = 0;
532 return S_OK;
533}
534
535HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfo(unsigned int, unsigned long, ITypeInfo **pptinfo)
536{
537 // We don't use a type library
538 *pptinfo = 0;
539 return S_OK;
540}
541
542HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetIDsOfNames(const _GUID &, wchar_t **rgszNames, unsigned int, unsigned long, long *rgdispid)
543{
544#if !defined(Q_CC_BOR) && !defined(Q_CC_GNU)
545 // PROPERTIES: Hierarchical
546 if (_bstr_t(rgszNames[0]) == _bstr_t(L"accParent"))
547 rgdispid[0] = DISPID_ACC_PARENT;
548 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount"))
549 rgdispid[0] = DISPID_ACC_CHILDCOUNT;
550 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChild"))
551 rgdispid[0] = DISPID_ACC_CHILD;
552
553 // PROPERTIES: Descriptional
554 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accName("))
555 rgdispid[0] = DISPID_ACC_NAME;
556 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accValue"))
557 rgdispid[0] = DISPID_ACC_VALUE;
558 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription"))
559 rgdispid[0] = DISPID_ACC_DESCRIPTION;
560 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accRole"))
561 rgdispid[0] = DISPID_ACC_ROLE;
562 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accState"))
563 rgdispid[0] = DISPID_ACC_STATE;
564 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp"))
565 rgdispid[0] = DISPID_ACC_HELP;
566 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic"))
567 rgdispid[0] = DISPID_ACC_HELPTOPIC;
568 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut"))
569 rgdispid[0] = DISPID_ACC_KEYBOARDSHORTCUT;
570 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus"))
571 rgdispid[0] = DISPID_ACC_FOCUS;
572 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection"))
573 rgdispid[0] = DISPID_ACC_SELECTION;
574 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction"))
575 rgdispid[0] = DISPID_ACC_DEFAULTACTION;
576
577 // METHODS
578 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect"))
579 rgdispid[0] = DISPID_ACC_SELECT;
580 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation"))
581 rgdispid[0] = DISPID_ACC_LOCATION;
582 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate"))
583 rgdispid[0] = DISPID_ACC_NAVIGATE;
584 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest"))
585 rgdispid[0] = DISPID_ACC_HITTEST;
586 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction"))
587 rgdispid[0] = DISPID_ACC_DODEFAULTACTION;
588 else
589 return DISP_E_UNKNOWNINTERFACE;
590
591 return S_OK;
592#else
593 Q_UNUSED(rgszNames);
594 Q_UNUSED(rgdispid);
595
596 return DISP_E_MEMBERNOTFOUND;
597#endif
598}
599
600HRESULT STDMETHODCALLTYPE QWindowsAccessible::Invoke(long dispIdMember, const _GUID &, unsigned long, unsigned short wFlags, tagDISPPARAMS *pDispParams, tagVARIANT *pVarResult, tagEXCEPINFO *, unsigned int *)
601{
602 HRESULT hr = DISP_E_MEMBERNOTFOUND;
603
604 switch(dispIdMember)
605 {
606 case DISPID_ACC_PARENT:
607 if (wFlags == DISPATCH_PROPERTYGET) {
608 if (!pVarResult)
609 return E_INVALIDARG;
610 hr = get_accParent(&pVarResult->pdispVal);
611 } else {
612 hr = DISP_E_MEMBERNOTFOUND;
613 }
614 break;
615
616 case DISPID_ACC_CHILDCOUNT:
617 if (wFlags == DISPATCH_PROPERTYGET) {
618 if (!pVarResult)
619 return E_INVALIDARG;
620 hr = get_accChildCount(&pVarResult->lVal);
621 } else {
622 hr = DISP_E_MEMBERNOTFOUND;
623 }
624 break;
625
626 case DISPID_ACC_CHILD:
627 if (wFlags == DISPATCH_PROPERTYGET)
628 hr = get_accChild(pDispParams->rgvarg[0], &pVarResult->pdispVal);
629 else
630 hr = DISP_E_MEMBERNOTFOUND;
631 break;
632
633 case DISPID_ACC_NAME:
634 if (wFlags == DISPATCH_PROPERTYGET)
635 hr = get_accName(pDispParams->rgvarg[0], &pVarResult->bstrVal);
636 else if (wFlags == DISPATCH_PROPERTYPUT)
637 hr = put_accName(pDispParams->rgvarg[0], pVarResult->bstrVal);
638 else
639 hr = DISP_E_MEMBERNOTFOUND;
640 break;
641
642 case DISPID_ACC_VALUE:
643 if (wFlags == DISPATCH_PROPERTYGET)
644 hr = get_accValue(pDispParams->rgvarg[0], &pVarResult->bstrVal);
645 else if (wFlags == DISPATCH_PROPERTYPUT)
646 hr = put_accValue(pDispParams->rgvarg[0], pVarResult->bstrVal);
647 else
648 hr = DISP_E_MEMBERNOTFOUND;
649 break;
650
651 case DISPID_ACC_DESCRIPTION:
652 if (wFlags == DISPATCH_PROPERTYGET)
653 hr = get_accDescription(pDispParams->rgvarg[0], &pVarResult->bstrVal);
654 else
655 hr = DISP_E_MEMBERNOTFOUND;
656 break;
657
658 case DISPID_ACC_ROLE:
659 if (wFlags == DISPATCH_PROPERTYGET)
660 hr = get_accRole(pDispParams->rgvarg[0], pVarResult);
661 else
662 hr = DISP_E_MEMBERNOTFOUND;
663 break;
664
665 case DISPID_ACC_STATE:
666 if (wFlags == DISPATCH_PROPERTYGET)
667 hr = get_accState(pDispParams->rgvarg[0], pVarResult);
668 else
669 hr = DISP_E_MEMBERNOTFOUND;
670 break;
671
672 case DISPID_ACC_HELP:
673 if (wFlags == DISPATCH_PROPERTYGET)
674 hr = get_accHelp(pDispParams->rgvarg[0], &pVarResult->bstrVal);
675 else
676 hr = DISP_E_MEMBERNOTFOUND;
677 break;
678
679 case DISPID_ACC_HELPTOPIC:
680 if (wFlags == DISPATCH_PROPERTYGET)
681 hr = get_accHelpTopic(&pDispParams->rgvarg[2].bstrVal, pDispParams->rgvarg[1], &pDispParams->rgvarg[0].lVal);
682 else
683 hr = DISP_E_MEMBERNOTFOUND;
684 break;
685
686 case DISPID_ACC_KEYBOARDSHORTCUT:
687 if (wFlags == DISPATCH_PROPERTYGET)
688 hr = get_accKeyboardShortcut(pDispParams->rgvarg[0], &pVarResult->bstrVal);
689 else
690 hr = DISP_E_MEMBERNOTFOUND;
691 break;
692
693 case DISPID_ACC_FOCUS:
694 if (wFlags == DISPATCH_PROPERTYGET)
695 hr = get_accFocus(pVarResult);
696 else
697 hr = DISP_E_MEMBERNOTFOUND;
698 break;
699
700 case DISPID_ACC_SELECTION:
701 if (wFlags == DISPATCH_PROPERTYGET)
702 hr = get_accSelection(pVarResult);
703 else
704 hr = DISP_E_MEMBERNOTFOUND;
705 break;
706
707 case DISPID_ACC_DEFAULTACTION:
708 if (wFlags == DISPATCH_PROPERTYGET)
709 hr = get_accDefaultAction(pDispParams->rgvarg[0], &pVarResult->bstrVal);
710 else
711 hr = DISP_E_MEMBERNOTFOUND;
712 break;
713
714 case DISPID_ACC_SELECT:
715 if (wFlags == DISPATCH_METHOD)
716 hr = accSelect(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
717 else
718 hr = DISP_E_MEMBERNOTFOUND;
719 break;
720
721 case DISPID_ACC_LOCATION:
722 if (wFlags == DISPATCH_METHOD)
723 hr = accLocation(&pDispParams->rgvarg[4].lVal, &pDispParams->rgvarg[3].lVal, &pDispParams->rgvarg[2].lVal, &pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
724 else
725 hr = DISP_E_MEMBERNOTFOUND;
726 break;
727
728 case DISPID_ACC_NAVIGATE:
729 if (wFlags == DISPATCH_METHOD)
730 hr = accNavigate(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0], pVarResult);
731 else
732 hr = DISP_E_MEMBERNOTFOUND;
733 break;
734
735 case DISPID_ACC_HITTEST:
736 if (wFlags == DISPATCH_METHOD)
737 hr = accHitTest(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].lVal, pVarResult);
738 else
739 hr = DISP_E_MEMBERNOTFOUND;
740 break;
741
742 case DISPID_ACC_DODEFAULTACTION:
743 if (wFlags == DISPATCH_METHOD)
744 hr = accDoDefaultAction(pDispParams->rgvarg[0]);
745 else
746 hr = DISP_E_MEMBERNOTFOUND;
747 break;
748
749 default:
750 hr = DISP_E_MEMBERNOTFOUND;
751 break;
752 }
753
754 if (!SUCCEEDED(hr)) {
755 return hr;
756 }
757 return hr;
758}
759
760/*
761 IAccessible
762*/
763HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
764{
765 showDebug(__FUNCTION__, accessible);
766 if (!accessible->isValid())
767 return E_FAIL;
768
769 int control = accessible->childAt(xLeft, yTop);
770 if (control == -1) {
771 (*pvarID).vt = VT_EMPTY;
772 return S_FALSE;
773 }
774 QAccessibleInterface *acc = 0;
775 if (control)
776 accessible->navigate(Child, control, &acc);
777 if (!acc) {
778 (*pvarID).vt = VT_I4;
779 (*pvarID).lVal = control;
780 return S_OK;
781 }
782
783 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
784 IDispatch *iface = 0;
785 wacc->QueryInterface(IID_IDispatch, (void**)&iface);
786 if (iface) {
787 (*pvarID).vt = VT_DISPATCH;
788 (*pvarID).pdispVal = iface;
789 return S_OK;
790 } else {
791 delete wacc;
792 }
793
794 (*pvarID).vt = VT_EMPTY;
795 return S_FALSE;
796}
797
798HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
799{
800 showDebug(__FUNCTION__, accessible);
801 if (!accessible->isValid())
802 return E_FAIL;
803
804 QRect rect = accessible->rect(varID.lVal);
805 if (rect.isValid()) {
806 *pxLeft = rect.x();
807 *pyTop = rect.y();
808 *pcxWidth = rect.width();
809 *pcyHeight = rect.height();
810 } else {
811 *pxLeft = 0;
812 *pyTop = 0;
813 *pcxWidth = 0;
814 *pcyHeight = 0;
815 }
816 return S_OK;
817}
818
819HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
820{
821 showDebug(__FUNCTION__, accessible);
822 if (!accessible->isValid())
823 return E_FAIL;
824
825 QAccessibleInterface *acc = 0;
826 int control = -1;
827 switch(navDir) {
828 case NAVDIR_FIRSTCHILD:
829 control = accessible->navigate(Child, 1, &acc);
830 break;
831 case NAVDIR_LASTCHILD:
832 control = accessible->navigate(Child, accessible->childCount(), &acc);
833 break;
834 case NAVDIR_NEXT:
835 case NAVDIR_PREVIOUS:
836 if (!varStart.lVal){
837 QAccessibleInterface *parent = 0;
838 accessible->navigate(Ancestor, 1, &parent);
839 if (parent) {
840 int index = parent->indexOfChild(accessible);
841 index += (navDir == NAVDIR_NEXT) ? 1 : -1;
842 if (index > 0 && index <= parent->childCount())
843 control = parent->navigate(Child, index, &acc);
844 delete parent;
845 }
846 } else {
847 int index = varStart.lVal;
848 index += (navDir == NAVDIR_NEXT) ? 1 : -1;
849 if (index > 0 && index <= accessible->childCount())
850 control = accessible->navigate(Child, index, &acc);
851 }
852 break;
853 case NAVDIR_UP:
854 control = accessible->navigate(Up, varStart.lVal, &acc);
855 break;
856 case NAVDIR_DOWN:
857 control = accessible->navigate(Down, varStart.lVal, &acc);
858 break;
859 case NAVDIR_LEFT:
860 control = accessible->navigate(Left, varStart.lVal, &acc);
861 break;
862 case NAVDIR_RIGHT:
863 control = accessible->navigate(Right, varStart.lVal, &acc);
864 break;
865 default:
866 break;
867 }
868 if (control == -1) {
869 (*pvarEnd).vt = VT_EMPTY;
870 return S_FALSE;
871 }
872 if (!acc) {
873 (*pvarEnd).vt = VT_I4;
874 (*pvarEnd).lVal = control;
875 return S_OK;
876 }
877
878 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
879
880 IDispatch *iface = 0;
881 wacc->QueryInterface(IID_IDispatch, (void**)&iface);
882 if (iface) {
883 (*pvarEnd).vt = VT_DISPATCH;
884 (*pvarEnd).pdispVal = iface;
885 return S_OK;
886 } else {
887 delete wacc;
888 }
889
890 (*pvarEnd).vt = VT_EMPTY;
891 return S_FALSE;
892}
893
894HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
895{
896 showDebug(__FUNCTION__, accessible);
897 if (!accessible->isValid())
898 return E_FAIL;
899
900 if (varChildID.vt == VT_EMPTY)
901 return E_INVALIDARG;
902
903 QAccessibleInterface *acc = 0;
904 RelationFlag rel = varChildID.lVal ? Child : Self;
905 accessible->navigate(rel, varChildID.lVal, &acc);
906
907 if (acc) {
908 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
909 wacc->QueryInterface(IID_IDispatch, (void**)ppdispChild);
910 return S_OK;
911 }
912
913 *ppdispChild = 0;
914 return S_FALSE;
915}
916
917HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChildCount(long* pcountChildren)
918{
919 showDebug(__FUNCTION__, accessible);
920 if (!accessible->isValid())
921 return E_FAIL;
922
923 *pcountChildren = accessible->childCount();
924 return S_OK;
925}
926
927HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispParent)
928{
929 showDebug(__FUNCTION__, accessible);
930 if (!accessible->isValid())
931 return E_FAIL;
932
933 QAccessibleInterface *acc = 0;
934 accessible->navigate(Ancestor, 1, &acc);
935 if (acc) {
936 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
937 wacc->QueryInterface(IID_IDispatch, (void**)ppdispParent);
938
939 if (*ppdispParent)
940 return S_OK;
941 }
942
943 *ppdispParent = 0;
944 return S_FALSE;
945}
946
947/*
948 Properties and methods
949*/
950HRESULT STDMETHODCALLTYPE QWindowsAccessible::accDoDefaultAction(VARIANT varID)
951{
952 showDebug(__FUNCTION__, accessible);
953 if (!accessible->isValid())
954 return E_FAIL;
955
956 return accessible->doAction(DefaultAction, varID.lVal, QVariantList()) ? S_OK : S_FALSE;
957}
958
959HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction)
960{
961 showDebug(__FUNCTION__, accessible);
962 if (!accessible->isValid())
963 return E_FAIL;
964
965 QString def = accessible->actionText(DefaultAction, Name, varID.lVal);
966 if (def.isEmpty()) {
967 *pszDefaultAction = 0;
968 return S_FALSE;
969 }
970
971 *pszDefaultAction = QStringToBSTR(def);
972 return S_OK;
973}
974
975HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription)
976{
977 showDebug(__FUNCTION__, accessible);
978 if (!accessible->isValid())
979 return E_FAIL;
980
981 QString descr = accessible->text(Description, varID.lVal);
982 if (descr.size()) {
983 *pszDescription = QStringToBSTR(descr);
984 return S_OK;
985 }
986
987 *pszDescription = 0;
988 return S_FALSE;
989}
990
991HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp)
992{
993 showDebug(__FUNCTION__, accessible);
994 if (!accessible->isValid())
995 return E_FAIL;
996
997 QString help = accessible->text(Help, varID.lVal);
998 if (help.size()) {
999 *pszHelp = QStringToBSTR(help);
1000 return S_OK;
1001 }
1002
1003 *pszHelp = 0;
1004 return S_FALSE;
1005}
1006
1007HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
1008{
1009 return DISP_E_MEMBERNOTFOUND;
1010}
1011
1012HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut)
1013{
1014 showDebug(__FUNCTION__, accessible);
1015 if (!accessible->isValid())
1016 return E_FAIL;
1017
1018 QString sc = accessible->text(Accelerator, varID.lVal);
1019 if (sc.size()) {
1020 *pszKeyboardShortcut = QStringToBSTR(sc);
1021 return S_OK;
1022 }
1023
1024 *pszKeyboardShortcut = 0;
1025 return S_FALSE;
1026}
1027
1028HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* pszName)
1029{
1030 showDebug(__FUNCTION__, accessible);
1031 if (!accessible->isValid())
1032 return E_FAIL;
1033
1034 QString n = accessible->text(Name, varID.lVal);
1035 if (n.size()) {
1036 *pszName = QStringToBSTR(n);
1037 return S_OK;
1038 }
1039
1040 *pszName = 0;
1041 return S_FALSE;
1042}
1043
1044HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accName(VARIANT, BSTR)
1045{
1046 showDebug(__FUNCTION__, accessible);
1047 return DISP_E_MEMBERNOTFOUND;
1048}
1049
1050HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole)
1051{
1052 showDebug(__FUNCTION__, accessible);
1053 if (!accessible->isValid())
1054 return E_FAIL;
1055
1056 Role role = accessible->role(varID.lVal);
1057 if (role != NoRole) {
1058 (*pvarRole).vt = VT_I4;
1059 (*pvarRole).lVal = role;
1060 } else {
1061 (*pvarRole).vt = VT_EMPTY;
1062 }
1063 return S_OK;
1064}
1065
1066HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accState(VARIANT varID, VARIANT *pvarState)
1067{
1068 showDebug(__FUNCTION__, accessible);
1069 if (!accessible->isValid())
1070 return E_FAIL;
1071
1072 (*pvarState).vt = VT_I4;
1073 (*pvarState).lVal = accessible->state(varID.lVal);
1074 return S_OK;
1075}
1076
1077HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accValue(VARIANT varID, BSTR* pszValue)
1078{
1079 showDebug(__FUNCTION__, accessible);
1080 if (!accessible->isValid())
1081 return E_FAIL;
1082
1083 QString value = accessible->text(Value, varID.lVal);
1084 if (!value.isNull()) {
1085 *pszValue = QStringToBSTR(value);
1086 return S_OK;
1087 }
1088
1089 *pszValue = 0;
1090 return S_FALSE;
1091}
1092
1093HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accValue(VARIANT, BSTR)
1094{
1095 showDebug(__FUNCTION__, accessible);
1096 return DISP_E_MEMBERNOTFOUND;
1097}
1098
1099HRESULT STDMETHODCALLTYPE QWindowsAccessible::accSelect(long flagsSelect, VARIANT varID)
1100{
1101 showDebug(__FUNCTION__, accessible);
1102 if (!accessible->isValid())
1103 return E_FAIL;
1104
1105 bool res = false;
1106
1107 if (flagsSelect & SELFLAG_TAKEFOCUS)
1108 res = accessible->doAction(SetFocus, varID.lVal, QVariantList());
1109 if (flagsSelect & SELFLAG_TAKESELECTION) {
1110 accessible->doAction(ClearSelection, 0, QVariantList());
1111 res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
1112 }
1113 if (flagsSelect & SELFLAG_EXTENDSELECTION)
1114 res = accessible->doAction(ExtendSelection, varID.lVal, QVariantList());
1115 if (flagsSelect & SELFLAG_ADDSELECTION)
1116 res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
1117 if (flagsSelect & SELFLAG_REMOVESELECTION)
1118 res = accessible->doAction(RemoveSelection, varID.lVal, QVariantList());
1119
1120 return res ? S_OK : S_FALSE;
1121}
1122
1123HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID)
1124{
1125 showDebug(__FUNCTION__, accessible);
1126 if (!accessible->isValid())
1127 return E_FAIL;
1128
1129 QAccessibleInterface *acc = 0;
1130 int control = accessible->navigate(FocusChild, 1, &acc);
1131 if (control == -1) {
1132 (*pvarID).vt = VT_EMPTY;
1133 return S_FALSE;
1134 }
1135 if (!acc || control == 0) {
1136 (*pvarID).vt = VT_I4;
1137 (*pvarID).lVal = control ? control : CHILDID_SELF;
1138 return S_OK;
1139 }
1140
1141 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
1142 IDispatch *iface = 0;
1143 wacc->QueryInterface(IID_IDispatch, (void**)&iface);
1144 if (iface) {
1145 (*pvarID).vt = VT_DISPATCH;
1146 (*pvarID).pdispVal = iface;
1147 return S_OK;
1148 } else {
1149 delete wacc;
1150 }
1151
1152 (*pvarID).vt = VT_EMPTY;
1153 return S_FALSE;
1154}
1155
1156HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren)
1157{
1158 showDebug(__FUNCTION__, accessible);
1159 if (!accessible->isValid())
1160 return E_FAIL;
1161
1162 int cc = accessible->childCount();
1163 QVector<int> sel(cc);
1164 int selIndex = 0;
1165 for (int i = 1; i <= cc; ++i) {
1166 QAccessibleInterface *child = 0;
1167 int i2 = accessible->navigate(Child, i, &child);
1168 bool isSelected = false;
1169 if (child) {
1170 isSelected = child->state(0) & Selected;
1171 delete child;
1172 child = 0;
1173 } else {
1174 isSelected = accessible->state(i2) & Selected;
1175 }
1176 if (isSelected)
1177 sel[selIndex++] = i;
1178 }
1179 sel.resize(selIndex);
1180 if (sel.isEmpty()) {
1181 (*pvarChildren).vt = VT_EMPTY;
1182 return S_FALSE;
1183 }
1184 if (sel.size() == 1) {
1185 (*pvarChildren).vt = VT_I4;
1186 (*pvarChildren).lVal = sel[0];
1187 return S_OK;
1188 }
1189 IEnumVARIANT *iface = new QWindowsEnumerate(sel);
1190 IUnknown *uiface;
1191 iface->QueryInterface(IID_IUnknown, (void**)&uiface);
1192 (*pvarChildren).vt = VT_UNKNOWN;
1193 (*pvarChildren).punkVal = uiface;
1194
1195 return S_OK;
1196}
1197
1198HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetWindow(HWND *phwnd)
1199{
1200 *phwnd = 0;
1201 if (!accessible->isValid())
1202 return E_UNEXPECTED;
1203
1204 QObject *o = accessible->object();
1205 if (!o || !o->isWidgetType())
1206 return E_FAIL;
1207
1208 *phwnd = static_cast<QWidget*>(o)->winId();
1209 return S_OK;
1210}
1211
1212HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL)
1213{
1214 return S_OK;
1215}
1216
1217QT_END_NAMESPACE
1218
1219#endif // QT_NO_ACCESSIBILITY
Note: See TracBrowser for help on using the repository browser.