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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 35.8 KB
Line 
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 QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41#include "qaccessible.h"
42#ifndef QT_NO_ACCESSIBILITY
43
44#include "qapplication.h"
45#include <private/qsystemlibrary_p.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_WS_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_WS_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 QString soundName;
181 switch (reason) {
182 case PopupMenuStart:
183 soundName = QLatin1String("MenuPopup");
184 break;
185
186 case MenuCommand:
187 soundName = QLatin1String("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 = QLatin1String("SystemExclamation");
198 break;
199 case QMessageBox::Critical:
200 soundName = QLatin1String("SystemHand");
201 break;
202 case QMessageBox::Information:
203 soundName = QLatin1String("SystemAsterisk");
204 break;
205 default:
206 break;
207 }
208 } else
209#endif // QT_NO_MESSAGEBOX
210 {
211 soundName = QLatin1String("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\\") + soundName,
223 QSettings::NativeFormat);
224 QString file = settings.value(QLatin1String(".Current/.")).toString();
225#else
226 QString file;
227#endif
228 if (!file.isEmpty()) {
229 PlaySound(reinterpret_cast<const wchar_t *>(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT);
230 }
231 }
232
233 if (!isActive())
234 return;
235
236 typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
237
238#if defined(Q_WS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
239 // There is no user32.lib nor NotifyWinEvent for CE
240 return;
241#else
242 static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
243 static bool resolvedNWE = false;
244 if (!resolvedNWE) {
245 resolvedNWE = true;
246 ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
247 }
248 if (!ptrNotifyWinEvent)
249 return;
250
251 // An event has to be associated with a window,
252 // so find the first parent that is a widget.
253 QWidget *w = 0;
254 if (o->isWidgetType()) {
255 w = (QWidget*)o;
256 } else {
257 QObject *p = o;
258 while ((p = p->parent()) != 0) {
259 if (p->isWidgetType()) {
260 w = (QWidget*)p;
261 break;
262 }
263 }
264 }
265
266 if (!w) {
267 if (reason != QAccessible::ContextHelpStart &&
268 reason != QAccessible::ContextHelpEnd)
269 w = QApplication::focusWidget();
270 if (!w) {
271 w = QApplication::activeWindow();
272
273 if (!w)
274 return;
275
276// ### Fixme
277// if (!w) {
278// w = qApp->mainWidget();
279// if (!w)
280// return;
281// }
282 }
283 }
284
285 if (reason != MenuCommand) { // MenuCommand is faked
286 ptrNotifyWinEvent(reason, w->winId(), OBJID_CLIENT, who);
287 }
288#endif // Q_WS_WINCE
289}
290
291void QAccessible::setRootObject(QObject *o)
292{
293 if (rootObjectHandler) {
294 rootObjectHandler(o);
295 }
296}
297
298class QWindowsEnumerate : public IEnumVARIANT
299{
300public:
301 QWindowsEnumerate(const QVector<int> &a)
302 : ref(0), current(0),array(a)
303 {
304 }
305
306 virtual ~QWindowsEnumerate() {}
307
308 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
309 ULONG STDMETHODCALLTYPE AddRef();
310 ULONG STDMETHODCALLTYPE Release();
311
312 HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **ppEnum);
313 HRESULT STDMETHODCALLTYPE Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched);
314 HRESULT STDMETHODCALLTYPE Reset();
315 HRESULT STDMETHODCALLTYPE Skip(unsigned long celt);
316
317private:
318 ULONG ref;
319 ULONG current;
320 QVector<int> array;
321};
322
323HRESULT STDMETHODCALLTYPE QWindowsEnumerate::QueryInterface(REFIID id, LPVOID *iface)
324{
325 *iface = 0;
326 if (id == IID_IUnknown)
327 *iface = (IUnknown*)this;
328 else if (id == IID_IEnumVARIANT)
329 *iface = (IEnumVARIANT*)this;
330
331 if (*iface) {
332 AddRef();
333 return S_OK;
334 }
335
336 return E_NOINTERFACE;
337}
338
339ULONG STDMETHODCALLTYPE QWindowsEnumerate::AddRef()
340{
341 return ++ref;
342}
343
344ULONG STDMETHODCALLTYPE QWindowsEnumerate::Release()
345{
346 if (!--ref) {
347 delete this;
348 return 0;
349 }
350 return ref;
351}
352
353HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone(IEnumVARIANT **ppEnum)
354{
355 QWindowsEnumerate *penum = 0;
356 *ppEnum = 0;
357
358 penum = new QWindowsEnumerate(array);
359 if (!penum)
360 return E_OUTOFMEMORY;
361 penum->current = current;
362 penum->array = array;
363 penum->AddRef();
364 *ppEnum = penum;
365
366 return S_OK;
367}
368
369HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched)
370{
371 if (pCeltFetched)
372 *pCeltFetched = 0;
373
374 ULONG l;
375 for (l = 0; l < celt; l++) {
376 VariantInit(&rgVar[l]);
377 if ((current+1) > (ULONG)array.size()) {
378 *pCeltFetched = l;
379 return S_FALSE;
380 }
381
382 rgVar[l].vt = VT_I4;
383 rgVar[l].lVal = array[(int)current];
384 ++current;
385 }
386 *pCeltFetched = l;
387 return S_OK;
388}
389
390HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Reset()
391{
392 current = 0;
393 return S_OK;
394}
395
396HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt)
397{
398 current += celt;
399 if (current > (ULONG)array.size()) {
400 current = array.size();
401 return S_FALSE;
402 }
403 return S_OK;
404}
405
406/*
407*/
408class QWindowsAccessible : public IAccessible, IOleWindow, QAccessible
409{
410public:
411 QWindowsAccessible(QAccessibleInterface *a)
412 : ref(0), accessible(a)
413 {
414 }
415
416 virtual ~QWindowsAccessible()
417 {
418 delete accessible;
419 }
420
421 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
422 ULONG STDMETHODCALLTYPE AddRef();
423 ULONG STDMETHODCALLTYPE Release();
424
425 HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int *);
426 HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int, unsigned long, ITypeInfo **);
427 HRESULT STDMETHODCALLTYPE GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *);
428 HRESULT STDMETHODCALLTYPE Invoke(long, const _GUID &, unsigned long, unsigned short, tagDISPPARAMS *, tagVARIANT *, tagEXCEPINFO *, unsigned int *);
429
430 HRESULT STDMETHODCALLTYPE accHitTest(long xLeft, long yTop, VARIANT *pvarID);
431 HRESULT STDMETHODCALLTYPE accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID);
432 HRESULT STDMETHODCALLTYPE accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd);
433 HRESULT STDMETHODCALLTYPE get_accChild(VARIANT varChildID, IDispatch** ppdispChild);
434 HRESULT STDMETHODCALLTYPE get_accChildCount(long* pcountChildren);
435 HRESULT STDMETHODCALLTYPE get_accParent(IDispatch** ppdispParent);
436
437 HRESULT STDMETHODCALLTYPE accDoDefaultAction(VARIANT varID);
438 HRESULT STDMETHODCALLTYPE get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction);
439 HRESULT STDMETHODCALLTYPE get_accDescription(VARIANT varID, BSTR* pszDescription);
440 HRESULT STDMETHODCALLTYPE get_accHelp(VARIANT varID, BSTR *pszHelp);
441 HRESULT STDMETHODCALLTYPE get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic);
442 HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut);
443 HRESULT STDMETHODCALLTYPE get_accName(VARIANT varID, BSTR* pszName);
444 HRESULT STDMETHODCALLTYPE put_accName(VARIANT varChild, BSTR szName);
445 HRESULT STDMETHODCALLTYPE get_accRole(VARIANT varID, VARIANT *pvarRole);
446 HRESULT STDMETHODCALLTYPE get_accState(VARIANT varID, VARIANT *pvarState);
447 HRESULT STDMETHODCALLTYPE get_accValue(VARIANT varID, BSTR* pszValue);
448 HRESULT STDMETHODCALLTYPE put_accValue(VARIANT varChild, BSTR szValue);
449
450 HRESULT STDMETHODCALLTYPE accSelect(long flagsSelect, VARIANT varID);
451 HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT *pvarID);
452 HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT *pvarChildren);
453
454 HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
455 HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
456
457private:
458 ULONG ref;
459 QAccessibleInterface *accessible;
460};
461
462static inline BSTR QStringToBSTR(const QString &str)
463{
464 BSTR bstrVal;
465
466 int wlen = str.length()+1;
467 bstrVal = SysAllocStringByteLen(0, wlen*2);
468 memcpy(bstrVal, str.unicode(), sizeof(QChar)*(wlen));
469 bstrVal[wlen] = 0;
470
471 return bstrVal;
472}
473
474/*
475*/
476IAccessible *qt_createWindowsAccessible(QAccessibleInterface *access)
477{
478 QWindowsAccessible *acc = new QWindowsAccessible(access);
479 IAccessible *iface;
480 acc->QueryInterface(IID_IAccessible, (void**)&iface);
481
482 return iface;
483}
484
485/*
486 IUnknown
487*/
488HRESULT STDMETHODCALLTYPE QWindowsAccessible::QueryInterface(REFIID id, LPVOID *iface)
489{
490 *iface = 0;
491 if (id == IID_IUnknown)
492 *iface = (IUnknown*)(IDispatch*)this;
493 else if (id == IID_IDispatch)
494 *iface = (IDispatch*)this;
495 else if (id == IID_IAccessible)
496 *iface = (IAccessible*)this;
497 else if (id == IID_IOleWindow)
498 *iface = (IOleWindow*)this;
499 else
500 return E_NOINTERFACE;
501
502 AddRef();
503 return S_OK;
504}
505
506ULONG STDMETHODCALLTYPE QWindowsAccessible::AddRef()
507{
508 return ++ref;
509}
510
511ULONG STDMETHODCALLTYPE QWindowsAccessible::Release()
512{
513 if (!--ref) {
514 delete this;
515 return 0;
516 }
517 return ref;
518}
519
520/*
521 IDispatch
522*/
523
524HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfoCount(unsigned int * pctinfo)
525{
526 // We don't use a type library
527 *pctinfo = 0;
528 return S_OK;
529}
530
531HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfo(unsigned int, unsigned long, ITypeInfo **pptinfo)
532{
533 // We don't use a type library
534 *pptinfo = 0;
535 return S_OK;
536}
537
538HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetIDsOfNames(const _GUID &, wchar_t **rgszNames, unsigned int, unsigned long, long *rgdispid)
539{
540#if !defined(Q_CC_BOR) && !defined(Q_CC_GNU)
541 // PROPERTIES: Hierarchical
542 if (_bstr_t(rgszNames[0]) == _bstr_t(L"accParent"))
543 rgdispid[0] = DISPID_ACC_PARENT;
544 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount"))
545 rgdispid[0] = DISPID_ACC_CHILDCOUNT;
546 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChild"))
547 rgdispid[0] = DISPID_ACC_CHILD;
548
549 // PROPERTIES: Descriptional
550 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accName("))
551 rgdispid[0] = DISPID_ACC_NAME;
552 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accValue"))
553 rgdispid[0] = DISPID_ACC_VALUE;
554 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription"))
555 rgdispid[0] = DISPID_ACC_DESCRIPTION;
556 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accRole"))
557 rgdispid[0] = DISPID_ACC_ROLE;
558 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accState"))
559 rgdispid[0] = DISPID_ACC_STATE;
560 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp"))
561 rgdispid[0] = DISPID_ACC_HELP;
562 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic"))
563 rgdispid[0] = DISPID_ACC_HELPTOPIC;
564 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut"))
565 rgdispid[0] = DISPID_ACC_KEYBOARDSHORTCUT;
566 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus"))
567 rgdispid[0] = DISPID_ACC_FOCUS;
568 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection"))
569 rgdispid[0] = DISPID_ACC_SELECTION;
570 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction"))
571 rgdispid[0] = DISPID_ACC_DEFAULTACTION;
572
573 // METHODS
574 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect"))
575 rgdispid[0] = DISPID_ACC_SELECT;
576 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation"))
577 rgdispid[0] = DISPID_ACC_LOCATION;
578 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate"))
579 rgdispid[0] = DISPID_ACC_NAVIGATE;
580 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest"))
581 rgdispid[0] = DISPID_ACC_HITTEST;
582 else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction"))
583 rgdispid[0] = DISPID_ACC_DODEFAULTACTION;
584 else
585 return DISP_E_UNKNOWNINTERFACE;
586
587 return S_OK;
588#else
589 Q_UNUSED(rgszNames);
590 Q_UNUSED(rgdispid);
591
592 return DISP_E_MEMBERNOTFOUND;
593#endif
594}
595
596HRESULT STDMETHODCALLTYPE QWindowsAccessible::Invoke(long dispIdMember, const _GUID &, unsigned long, unsigned short wFlags, tagDISPPARAMS *pDispParams, tagVARIANT *pVarResult, tagEXCEPINFO *, unsigned int *)
597{
598 HRESULT hr = DISP_E_MEMBERNOTFOUND;
599
600 switch(dispIdMember)
601 {
602 case DISPID_ACC_PARENT:
603 if (wFlags == DISPATCH_PROPERTYGET) {
604 if (!pVarResult)
605 return E_INVALIDARG;
606 hr = get_accParent(&pVarResult->pdispVal);
607 } else {
608 hr = DISP_E_MEMBERNOTFOUND;
609 }
610 break;
611
612 case DISPID_ACC_CHILDCOUNT:
613 if (wFlags == DISPATCH_PROPERTYGET) {
614 if (!pVarResult)
615 return E_INVALIDARG;
616 hr = get_accChildCount(&pVarResult->lVal);
617 } else {
618 hr = DISP_E_MEMBERNOTFOUND;
619 }
620 break;
621
622 case DISPID_ACC_CHILD:
623 if (wFlags == DISPATCH_PROPERTYGET)
624 hr = get_accChild(pDispParams->rgvarg[0], &pVarResult->pdispVal);
625 else
626 hr = DISP_E_MEMBERNOTFOUND;
627 break;
628
629 case DISPID_ACC_NAME:
630 if (wFlags == DISPATCH_PROPERTYGET)
631 hr = get_accName(pDispParams->rgvarg[0], &pVarResult->bstrVal);
632 else if (wFlags == DISPATCH_PROPERTYPUT)
633 hr = put_accName(pDispParams->rgvarg[0], pVarResult->bstrVal);
634 else
635 hr = DISP_E_MEMBERNOTFOUND;
636 break;
637
638 case DISPID_ACC_VALUE:
639 if (wFlags == DISPATCH_PROPERTYGET)
640 hr = get_accValue(pDispParams->rgvarg[0], &pVarResult->bstrVal);
641 else if (wFlags == DISPATCH_PROPERTYPUT)
642 hr = put_accValue(pDispParams->rgvarg[0], pVarResult->bstrVal);
643 else
644 hr = DISP_E_MEMBERNOTFOUND;
645 break;
646
647 case DISPID_ACC_DESCRIPTION:
648 if (wFlags == DISPATCH_PROPERTYGET)
649 hr = get_accDescription(pDispParams->rgvarg[0], &pVarResult->bstrVal);
650 else
651 hr = DISP_E_MEMBERNOTFOUND;
652 break;
653
654 case DISPID_ACC_ROLE:
655 if (wFlags == DISPATCH_PROPERTYGET)
656 hr = get_accRole(pDispParams->rgvarg[0], pVarResult);
657 else
658 hr = DISP_E_MEMBERNOTFOUND;
659 break;
660
661 case DISPID_ACC_STATE:
662 if (wFlags == DISPATCH_PROPERTYGET)
663 hr = get_accState(pDispParams->rgvarg[0], pVarResult);
664 else
665 hr = DISP_E_MEMBERNOTFOUND;
666 break;
667
668 case DISPID_ACC_HELP:
669 if (wFlags == DISPATCH_PROPERTYGET)
670 hr = get_accHelp(pDispParams->rgvarg[0], &pVarResult->bstrVal);
671 else
672 hr = DISP_E_MEMBERNOTFOUND;
673 break;
674
675 case DISPID_ACC_HELPTOPIC:
676 if (wFlags == DISPATCH_PROPERTYGET)
677 hr = get_accHelpTopic(&pDispParams->rgvarg[2].bstrVal, pDispParams->rgvarg[1], &pDispParams->rgvarg[0].lVal);
678 else
679 hr = DISP_E_MEMBERNOTFOUND;
680 break;
681
682 case DISPID_ACC_KEYBOARDSHORTCUT:
683 if (wFlags == DISPATCH_PROPERTYGET)
684 hr = get_accKeyboardShortcut(pDispParams->rgvarg[0], &pVarResult->bstrVal);
685 else
686 hr = DISP_E_MEMBERNOTFOUND;
687 break;
688
689 case DISPID_ACC_FOCUS:
690 if (wFlags == DISPATCH_PROPERTYGET)
691 hr = get_accFocus(pVarResult);
692 else
693 hr = DISP_E_MEMBERNOTFOUND;
694 break;
695
696 case DISPID_ACC_SELECTION:
697 if (wFlags == DISPATCH_PROPERTYGET)
698 hr = get_accSelection(pVarResult);
699 else
700 hr = DISP_E_MEMBERNOTFOUND;
701 break;
702
703 case DISPID_ACC_DEFAULTACTION:
704 if (wFlags == DISPATCH_PROPERTYGET)
705 hr = get_accDefaultAction(pDispParams->rgvarg[0], &pVarResult->bstrVal);
706 else
707 hr = DISP_E_MEMBERNOTFOUND;
708 break;
709
710 case DISPID_ACC_SELECT:
711 if (wFlags == DISPATCH_METHOD)
712 hr = accSelect(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
713 else
714 hr = DISP_E_MEMBERNOTFOUND;
715 break;
716
717 case DISPID_ACC_LOCATION:
718 if (wFlags == DISPATCH_METHOD)
719 hr = accLocation(&pDispParams->rgvarg[4].lVal, &pDispParams->rgvarg[3].lVal, &pDispParams->rgvarg[2].lVal, &pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
720 else
721 hr = DISP_E_MEMBERNOTFOUND;
722 break;
723
724 case DISPID_ACC_NAVIGATE:
725 if (wFlags == DISPATCH_METHOD)
726 hr = accNavigate(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0], pVarResult);
727 else
728 hr = DISP_E_MEMBERNOTFOUND;
729 break;
730
731 case DISPID_ACC_HITTEST:
732 if (wFlags == DISPATCH_METHOD)
733 hr = accHitTest(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].lVal, pVarResult);
734 else
735 hr = DISP_E_MEMBERNOTFOUND;
736 break;
737
738 case DISPID_ACC_DODEFAULTACTION:
739 if (wFlags == DISPATCH_METHOD)
740 hr = accDoDefaultAction(pDispParams->rgvarg[0]);
741 else
742 hr = DISP_E_MEMBERNOTFOUND;
743 break;
744
745 default:
746 hr = DISP_E_MEMBERNOTFOUND;
747 break;
748 }
749
750 if (!SUCCEEDED(hr)) {
751 return hr;
752 }
753 return hr;
754}
755
756/*
757 IAccessible
758*/
759HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
760{
761 showDebug(__FUNCTION__, accessible);
762 if (!accessible->isValid())
763 return E_FAIL;
764
765 int control = accessible->childAt(xLeft, yTop);
766 if (control == -1) {
767 (*pvarID).vt = VT_EMPTY;
768 return S_FALSE;
769 }
770 QAccessibleInterface *acc = 0;
771 if (control)
772 accessible->navigate(Child, control, &acc);
773 if (!acc) {
774 (*pvarID).vt = VT_I4;
775 (*pvarID).lVal = control;
776 return S_OK;
777 }
778
779 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
780 IDispatch *iface = 0;
781 wacc->QueryInterface(IID_IDispatch, (void**)&iface);
782 if (iface) {
783 (*pvarID).vt = VT_DISPATCH;
784 (*pvarID).pdispVal = iface;
785 return S_OK;
786 } else {
787 delete wacc;
788 }
789
790 (*pvarID).vt = VT_EMPTY;
791 return S_FALSE;
792}
793
794HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
795{
796 showDebug(__FUNCTION__, accessible);
797 if (!accessible->isValid())
798 return E_FAIL;
799
800 QRect rect = accessible->rect(varID.lVal);
801 if (rect.isValid()) {
802 *pxLeft = rect.x();
803 *pyTop = rect.y();
804 *pcxWidth = rect.width();
805 *pcyHeight = rect.height();
806 } else {
807 *pxLeft = 0;
808 *pyTop = 0;
809 *pcxWidth = 0;
810 *pcyHeight = 0;
811 }
812 return S_OK;
813}
814
815HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
816{
817 showDebug(__FUNCTION__, accessible);
818 if (!accessible->isValid())
819 return E_FAIL;
820
821 QAccessibleInterface *acc = 0;
822 int control = -1;
823 switch(navDir) {
824 case NAVDIR_FIRSTCHILD:
825 control = accessible->navigate(Child, 1, &acc);
826 break;
827 case NAVDIR_LASTCHILD:
828 control = accessible->navigate(Child, accessible->childCount(), &acc);
829 break;
830 case NAVDIR_NEXT:
831 case NAVDIR_PREVIOUS:
832 if (!varStart.lVal){
833 QAccessibleInterface *parent = 0;
834 accessible->navigate(Ancestor, 1, &parent);
835 if (parent) {
836 int index = parent->indexOfChild(accessible);
837 index += (navDir == NAVDIR_NEXT) ? 1 : -1;
838 if (index > 0 && index <= parent->childCount())
839 control = parent->navigate(Child, index, &acc);
840 delete parent;
841 }
842 } else {
843 int index = varStart.lVal;
844 index += (navDir == NAVDIR_NEXT) ? 1 : -1;
845 if (index > 0 && index <= accessible->childCount())
846 control = accessible->navigate(Child, index, &acc);
847 }
848 break;
849 case NAVDIR_UP:
850 control = accessible->navigate(Up, varStart.lVal, &acc);
851 break;
852 case NAVDIR_DOWN:
853 control = accessible->navigate(Down, varStart.lVal, &acc);
854 break;
855 case NAVDIR_LEFT:
856 control = accessible->navigate(Left, varStart.lVal, &acc);
857 break;
858 case NAVDIR_RIGHT:
859 control = accessible->navigate(Right, varStart.lVal, &acc);
860 break;
861 default:
862 break;
863 }
864 if (control == -1) {
865 (*pvarEnd).vt = VT_EMPTY;
866 return S_FALSE;
867 }
868 if (!acc) {
869 (*pvarEnd).vt = VT_I4;
870 (*pvarEnd).lVal = control;
871 return S_OK;
872 }
873
874 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
875
876 IDispatch *iface = 0;
877 wacc->QueryInterface(IID_IDispatch, (void**)&iface);
878 if (iface) {
879 (*pvarEnd).vt = VT_DISPATCH;
880 (*pvarEnd).pdispVal = iface;
881 return S_OK;
882 } else {
883 delete wacc;
884 }
885
886 (*pvarEnd).vt = VT_EMPTY;
887 return S_FALSE;
888}
889
890HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
891{
892 showDebug(__FUNCTION__, accessible);
893 if (!accessible->isValid())
894 return E_FAIL;
895
896 if (varChildID.vt == VT_EMPTY)
897 return E_INVALIDARG;
898
899 QAccessibleInterface *acc = 0;
900 RelationFlag rel = varChildID.lVal ? Child : Self;
901 accessible->navigate(rel, varChildID.lVal, &acc);
902
903 if (acc) {
904 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
905 wacc->QueryInterface(IID_IDispatch, (void**)ppdispChild);
906 return S_OK;
907 }
908
909 *ppdispChild = 0;
910 return S_FALSE;
911}
912
913HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChildCount(long* pcountChildren)
914{
915 showDebug(__FUNCTION__, accessible);
916 if (!accessible->isValid())
917 return E_FAIL;
918
919 *pcountChildren = accessible->childCount();
920 return S_OK;
921}
922
923HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispParent)
924{
925 showDebug(__FUNCTION__, accessible);
926 if (!accessible->isValid())
927 return E_FAIL;
928
929 QAccessibleInterface *acc = 0;
930 accessible->navigate(Ancestor, 1, &acc);
931 if (acc) {
932 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
933 wacc->QueryInterface(IID_IDispatch, (void**)ppdispParent);
934
935 if (*ppdispParent)
936 return S_OK;
937 }
938
939 *ppdispParent = 0;
940 return S_FALSE;
941}
942
943/*
944 Properties and methods
945*/
946HRESULT STDMETHODCALLTYPE QWindowsAccessible::accDoDefaultAction(VARIANT varID)
947{
948 showDebug(__FUNCTION__, accessible);
949 if (!accessible->isValid())
950 return E_FAIL;
951
952 return accessible->doAction(DefaultAction, varID.lVal, QVariantList()) ? S_OK : S_FALSE;
953}
954
955HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction)
956{
957 showDebug(__FUNCTION__, accessible);
958 if (!accessible->isValid())
959 return E_FAIL;
960
961 QString def = accessible->actionText(DefaultAction, Name, varID.lVal);
962 if (def.isEmpty()) {
963 *pszDefaultAction = 0;
964 return S_FALSE;
965 }
966
967 *pszDefaultAction = QStringToBSTR(def);
968 return S_OK;
969}
970
971HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription)
972{
973 showDebug(__FUNCTION__, accessible);
974 if (!accessible->isValid())
975 return E_FAIL;
976
977 QString descr = accessible->text(Description, varID.lVal);
978 if (descr.size()) {
979 *pszDescription = QStringToBSTR(descr);
980 return S_OK;
981 }
982
983 *pszDescription = 0;
984 return S_FALSE;
985}
986
987HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp)
988{
989 showDebug(__FUNCTION__, accessible);
990 if (!accessible->isValid())
991 return E_FAIL;
992
993 QString help = accessible->text(Help, varID.lVal);
994 if (help.size()) {
995 *pszHelp = QStringToBSTR(help);
996 return S_OK;
997 }
998
999 *pszHelp = 0;
1000 return S_FALSE;
1001}
1002
1003HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
1004{
1005 return DISP_E_MEMBERNOTFOUND;
1006}
1007
1008HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut)
1009{
1010 showDebug(__FUNCTION__, accessible);
1011 if (!accessible->isValid())
1012 return E_FAIL;
1013
1014 QString sc = accessible->text(Accelerator, varID.lVal);
1015 if (sc.size()) {
1016 *pszKeyboardShortcut = QStringToBSTR(sc);
1017 return S_OK;
1018 }
1019
1020 *pszKeyboardShortcut = 0;
1021 return S_FALSE;
1022}
1023
1024HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* pszName)
1025{
1026 showDebug(__FUNCTION__, accessible);
1027 if (!accessible->isValid())
1028 return E_FAIL;
1029
1030 QString n = accessible->text(Name, varID.lVal);
1031 if (n.size()) {
1032 *pszName = QStringToBSTR(n);
1033 return S_OK;
1034 }
1035
1036 *pszName = 0;
1037 return S_FALSE;
1038}
1039
1040HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accName(VARIANT, BSTR)
1041{
1042 showDebug(__FUNCTION__, accessible);
1043 return DISP_E_MEMBERNOTFOUND;
1044}
1045
1046HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole)
1047{
1048 showDebug(__FUNCTION__, accessible);
1049 if (!accessible->isValid())
1050 return E_FAIL;
1051
1052 Role role = accessible->role(varID.lVal);
1053 if (role != NoRole) {
1054 if (role == LayeredPane)
1055 role = QAccessible::Pane;
1056 (*pvarRole).vt = VT_I4;
1057 (*pvarRole).lVal = role;
1058 } else {
1059 (*pvarRole).vt = VT_EMPTY;
1060 }
1061 return S_OK;
1062}
1063
1064HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accState(VARIANT varID, VARIANT *pvarState)
1065{
1066 showDebug(__FUNCTION__, accessible);
1067 if (!accessible->isValid())
1068 return E_FAIL;
1069
1070 (*pvarState).vt = VT_I4;
1071 (*pvarState).lVal = accessible->state(varID.lVal);
1072 return S_OK;
1073}
1074
1075HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accValue(VARIANT varID, BSTR* pszValue)
1076{
1077 showDebug(__FUNCTION__, accessible);
1078 if (!accessible->isValid())
1079 return E_FAIL;
1080
1081 QString value = accessible->text(Value, varID.lVal);
1082 if (!value.isNull()) {
1083 *pszValue = QStringToBSTR(value);
1084 return S_OK;
1085 }
1086
1087 *pszValue = 0;
1088 return S_FALSE;
1089}
1090
1091HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accValue(VARIANT, BSTR)
1092{
1093 showDebug(__FUNCTION__, accessible);
1094 return DISP_E_MEMBERNOTFOUND;
1095}
1096
1097HRESULT STDMETHODCALLTYPE QWindowsAccessible::accSelect(long flagsSelect, VARIANT varID)
1098{
1099 showDebug(__FUNCTION__, accessible);
1100 if (!accessible->isValid())
1101 return E_FAIL;
1102
1103 bool res = false;
1104
1105 if (flagsSelect & SELFLAG_TAKEFOCUS)
1106 res = accessible->doAction(SetFocus, varID.lVal, QVariantList());
1107 if (flagsSelect & SELFLAG_TAKESELECTION) {
1108 accessible->doAction(ClearSelection, 0, QVariantList());
1109 res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
1110 }
1111 if (flagsSelect & SELFLAG_EXTENDSELECTION)
1112 res = accessible->doAction(ExtendSelection, varID.lVal, QVariantList());
1113 if (flagsSelect & SELFLAG_ADDSELECTION)
1114 res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
1115 if (flagsSelect & SELFLAG_REMOVESELECTION)
1116 res = accessible->doAction(RemoveSelection, varID.lVal, QVariantList());
1117
1118 return res ? S_OK : S_FALSE;
1119}
1120
1121HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID)
1122{
1123 showDebug(__FUNCTION__, accessible);
1124 if (!accessible->isValid())
1125 return E_FAIL;
1126
1127 QAccessibleInterface *acc = 0;
1128 int control = accessible->navigate(FocusChild, 1, &acc);
1129 if (control == -1) {
1130 (*pvarID).vt = VT_EMPTY;
1131 return S_FALSE;
1132 }
1133 if (!acc || control == 0) {
1134 (*pvarID).vt = VT_I4;
1135 (*pvarID).lVal = control ? control : CHILDID_SELF;
1136 return S_OK;
1137 }
1138
1139 QWindowsAccessible* wacc = new QWindowsAccessible(acc);
1140 IDispatch *iface = 0;
1141 wacc->QueryInterface(IID_IDispatch, (void**)&iface);
1142 if (iface) {
1143 (*pvarID).vt = VT_DISPATCH;
1144 (*pvarID).pdispVal = iface;
1145 return S_OK;
1146 } else {
1147 delete wacc;
1148 }
1149
1150 (*pvarID).vt = VT_EMPTY;
1151 return S_FALSE;
1152}
1153
1154HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren)
1155{
1156 showDebug(__FUNCTION__, accessible);
1157 if (!accessible->isValid())
1158 return E_FAIL;
1159
1160 int cc = accessible->childCount();
1161 QVector<int> sel(cc);
1162 int selIndex = 0;
1163 for (int i = 1; i <= cc; ++i) {
1164 QAccessibleInterface *child = 0;
1165 int i2 = accessible->navigate(Child, i, &child);
1166 bool isSelected = false;
1167 if (child) {
1168 isSelected = child->state(0) & Selected;
1169 delete child;
1170 child = 0;
1171 } else {
1172 isSelected = accessible->state(i2) & Selected;
1173 }
1174 if (isSelected)
1175 sel[selIndex++] = i;
1176 }
1177 sel.resize(selIndex);
1178 if (sel.isEmpty()) {
1179 (*pvarChildren).vt = VT_EMPTY;
1180 return S_FALSE;
1181 }
1182 if (sel.size() == 1) {
1183 (*pvarChildren).vt = VT_I4;
1184 (*pvarChildren).lVal = sel[0];
1185 return S_OK;
1186 }
1187 IEnumVARIANT *iface = new QWindowsEnumerate(sel);
1188 IUnknown *uiface;
1189 iface->QueryInterface(IID_IUnknown, (void**)&uiface);
1190 (*pvarChildren).vt = VT_UNKNOWN;
1191 (*pvarChildren).punkVal = uiface;
1192
1193 return S_OK;
1194}
1195
1196HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetWindow(HWND *phwnd)
1197{
1198 *phwnd = 0;
1199 if (!accessible->isValid())
1200 return E_UNEXPECTED;
1201
1202 QObject *o = accessible->object();
1203 if (!o || !o->isWidgetType())
1204 return E_FAIL;
1205
1206 *phwnd = static_cast<QWidget*>(o)->winId();
1207 return S_OK;
1208}
1209
1210HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL)
1211{
1212 return S_OK;
1213}
1214
1215QT_END_NAMESPACE
1216
1217#endif // QT_NO_ACCESSIBILITY
Note: See TracBrowser for help on using the repository browser.