diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/accessible/qaccessible_win.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/accessible/qaccessible_win.cpp')
-rw-r--r-- | src/gui/accessible/qaccessible_win.cpp | 1219 |
1 files changed, 1219 insertions, 0 deletions
diff --git a/src/gui/accessible/qaccessible_win.cpp b/src/gui/accessible/qaccessible_win.cpp new file mode 100644 index 0000000..99cc272 --- /dev/null +++ b/src/gui/accessible/qaccessible_win.cpp @@ -0,0 +1,1219 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qaccessible.h" +#ifndef QT_NO_ACCESSIBILITY + +#include "qapplication.h" +#include "qlibrary.h" +#include "qmessagebox.h" // ### dependency +#include "qt_windows.h" +#include "qwidget.h" +#include "qsettings.h" + +#include <winuser.h> +#if !defined(WINABLEAPI) +# if defined(Q_OS_WINCE) +# include <bldver.h> +# endif +# include <winable.h> +#endif + +#include <oleacc.h> +#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU) +#include <comdef.h> +#endif + +#ifdef Q_OS_WINCE +#include "qguifunctions_wince.h" +#endif + +QT_BEGIN_NAMESPACE + +//#define DEBUG_SHOW_ATCLIENT_COMMANDS +#ifdef DEBUG_SHOW_ATCLIENT_COMMANDS +QT_BEGIN_INCLUDE_NAMESPACE +#include <qdebug.h> +QT_END_INCLUDE_NAMESPACE + +static const char *roleString(QAccessible::Role role) +{ + static const char *roles[] = { + "NoRole" /*= 0x00000000*/, + "TitleBar" /*= 0x00000001*/, + "MenuBar" /*= 0x00000002*/, + "ScrollBar" /*= 0x00000003*/, + "Grip" /*= 0x00000004*/, + "Sound" /*= 0x00000005*/, + "Cursor" /*= 0x00000006*/, + "Caret" /*= 0x00000007*/, + "AlertMessage" /*= 0x00000008*/, + "Window" /*= 0x00000009*/, + "Client" /*= 0x0000000A*/, + "PopupMenu" /*= 0x0000000B*/, + "MenuItem" /*= 0x0000000C*/, + "ToolTip" /*= 0x0000000D*/, + "Application" /*= 0x0000000E*/, + "Document" /*= 0x0000000F*/, + "Pane" /*= 0x00000010*/, + "Chart" /*= 0x00000011*/, + "Dialog" /*= 0x00000012*/, + "Border" /*= 0x00000013*/, + "Grouping" /*= 0x00000014*/, + "Separator" /*= 0x00000015*/, + "ToolBar" /*= 0x00000016*/, + "StatusBar" /*= 0x00000017*/, + "Table" /*= 0x00000018*/, + "ColumnHeader" /*= 0x00000019*/, + "RowHeader" /*= 0x0000001A*/, + "Column" /*= 0x0000001B*/, + "Row" /*= 0x0000001C*/, + "Cell" /*= 0x0000001D*/, + "Link" /*= 0x0000001E*/, + "HelpBalloon" /*= 0x0000001F*/, + "Assistant" /*= 0x00000020*/, + "List" /*= 0x00000021*/, + "ListItem" /*= 0x00000022*/, + "Tree" /*= 0x00000023*/, + "TreeItem" /*= 0x00000024*/, + "PageTab" /*= 0x00000025*/, + "PropertyPage" /*= 0x00000026*/, + "Indicator" /*= 0x00000027*/, + "Graphic" /*= 0x00000028*/, + "StaticText" /*= 0x00000029*/, + "EditableText" /*= 0x0000002A*/, // Editable, selectable, etc. + "PushButton" /*= 0x0000002B*/, + "CheckBox" /*= 0x0000002C*/, + "RadioButton" /*= 0x0000002D*/, + "ComboBox" /*= 0x0000002E*/, + "DropList" /*= 0x0000002F*/, // commented out + "ProgressBar" /*= 0x00000030*/, + "Dial" /*= 0x00000031*/, + "HotkeyField" /*= 0x00000032*/, + "Slider" /*= 0x00000033*/, + "SpinBox" /*= 0x00000034*/, + "Canvas" /*= 0x00000035*/, + "Animation" /*= 0x00000036*/, + "Equation" /*= 0x00000037*/, + "ButtonDropDown" /*= 0x00000038*/, + "ButtonMenu" /*= 0x00000039*/, + "ButtonDropGrid" /*= 0x0000003A*/, + "Whitespace" /*= 0x0000003B*/, + "PageTabList" /*= 0x0000003C*/, + "Clock" /*= 0x0000003D*/, + "Splitter" /*= 0x0000003E*/, + "LayeredPane" /*= 0x0000003F*/, + "UserRole" /*= 0x0000ffff*/ + }; + + if (role >=0x40) + role = QAccessible::UserRole; + return roles[int(role)]; +} + +void showDebug(const char* funcName, const QAccessibleInterface *iface) +{ + qDebug() << "Role:" << roleString(iface->role(0)) + << "Name:" << iface->text(QAccessible::Name, 0) + << "State:" << QString::number(int(iface->state(0)), 16) + << QLatin1String(funcName); +} +#else +# define showDebug(f, iface) +#endif + +void QAccessible::initialize() +{ + +} +void QAccessible::cleanup() +{ + +} + +void QAccessible::updateAccessibility(QObject *o, int who, Event reason) +{ + Q_ASSERT(o); + + if (updateHandler) { + updateHandler(o, who, reason); + return; + } + + QByteArray soundName; + switch (reason) { + case PopupMenuStart: + soundName = "MenuPopup"; + break; + + case MenuCommand: + soundName = "MenuCommand"; + break; + + case Alert: + { +#ifndef QT_NO_MESSAGEBOX + QMessageBox *mb = qobject_cast<QMessageBox*>(o); + if (mb) { + switch (mb->icon()) { + case QMessageBox::Warning: + soundName = "SystemExclamation"; + break; + case QMessageBox::Critical: + soundName = "SystemHand"; + break; + case QMessageBox::Information: + soundName = "SystemAsterisk"; + break; + default: + break; + } + } else +#endif // QT_NO_MESSAGEBOX + { + soundName = "SystemAsterisk"; + } + + } + break; + default: + break; + } + + if (soundName.size()) { +#ifndef QT_NO_SETTINGS + QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + + QString::fromLatin1(soundName.constData()), QSettings::NativeFormat); + QString file = settings.value(QLatin1String(".Current/.")).toString(); +#else + QString file; +#endif + if (!file.isEmpty()) { + QT_WA({ + PlaySoundW(reinterpret_cast<const wchar_t *> (QString::fromLatin1(soundName).utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT ); + } , { + PlaySoundA(soundName.constData(), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT ); + }); + } + } + + if (!isActive()) + return; + + typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG); + +#if defined(Q_OS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0 + // There is no user32.lib nor NotifyWinEvent for CE + return; +#else + static PtrNotifyWinEvent ptrNotifyWinEvent = 0; + static bool resolvedNWE = false; + if (!resolvedNWE) { + resolvedNWE = true; + ptrNotifyWinEvent = (PtrNotifyWinEvent)QLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent"); + } + if (!ptrNotifyWinEvent) + return; + + // An event has to be associated with a window, + // so find the first parent that is a widget. + QWidget *w = 0; + if (o->isWidgetType()) { + w = (QWidget*)o; + } else { + QObject *p = o; + while ((p = p->parent()) != 0) { + if (p->isWidgetType()) { + w = (QWidget*)p; + break; + } + } + } + + if (!w) { + if (reason != QAccessible::ContextHelpStart && + reason != QAccessible::ContextHelpEnd) + w = qApp->focusWidget(); + if (!w) { + w = qApp->activeWindow(); + + if (!w) + return; + +// ### Fixme +// if (!w) { +// w = qApp->mainWidget(); +// if (!w) +// return; +// } + } + } + + if (reason != MenuCommand) { // MenuCommand is faked + ptrNotifyWinEvent(reason, w->winId(), OBJID_CLIENT, who); + } +#endif // Q_OS_WINCE +} + +void QAccessible::setRootObject(QObject *o) +{ + if (rootObjectHandler) { + rootObjectHandler(o); + } +} + +class QWindowsEnumerate : public IEnumVARIANT +{ +public: + QWindowsEnumerate(const QVector<int> &a) + : ref(0), current(0),array(a) + { + } + + virtual ~QWindowsEnumerate() {} + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **ppEnum); + HRESULT STDMETHODCALLTYPE Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched); + HRESULT STDMETHODCALLTYPE Reset(); + HRESULT STDMETHODCALLTYPE Skip(unsigned long celt); + +private: + ULONG ref; + ULONG current; + QVector<int> array; +}; + +HRESULT STDMETHODCALLTYPE QWindowsEnumerate::QueryInterface(REFIID id, LPVOID *iface) +{ + *iface = 0; + if (id == IID_IUnknown) + *iface = (IUnknown*)this; + else if (id == IID_IEnumVARIANT) + *iface = (IEnumVARIANT*)this; + + if (*iface) { + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE QWindowsEnumerate::AddRef() +{ + return ++ref; +} + +ULONG STDMETHODCALLTYPE QWindowsEnumerate::Release() +{ + if (!--ref) { + delete this; + return 0; + } + return ref; +} + +HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone(IEnumVARIANT **ppEnum) +{ + QWindowsEnumerate *penum = 0; + *ppEnum = 0; + + penum = new QWindowsEnumerate(array); + if (!penum) + return E_OUTOFMEMORY; + penum->current = current; + penum->array = array; + penum->AddRef(); + *ppEnum = penum; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched) +{ + if (pCeltFetched) + *pCeltFetched = 0; + + ULONG l; + for (l = 0; l < celt; l++) { + VariantInit(&rgVar[l]); + if ((current+1) > (ULONG)array.size()) { + *pCeltFetched = l; + return S_FALSE; + } + + rgVar[l].vt = VT_I4; + rgVar[l].lVal = array[(int)current]; + ++current; + } + *pCeltFetched = l; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Reset() +{ + current = 0; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt) +{ + current += celt; + if (current > (ULONG)array.size()) { + current = array.size(); + return S_FALSE; + } + return S_OK; +} + +/* +*/ +class QWindowsAccessible : public IAccessible, IOleWindow, QAccessible +{ +public: + QWindowsAccessible(QAccessibleInterface *a) + : ref(0), accessible(a) + { + } + + virtual ~QWindowsAccessible() + { + delete accessible; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int *); + HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int, unsigned long, ITypeInfo **); + HRESULT STDMETHODCALLTYPE GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *); + HRESULT STDMETHODCALLTYPE Invoke(long, const _GUID &, unsigned long, unsigned short, tagDISPPARAMS *, tagVARIANT *, tagEXCEPINFO *, unsigned int *); + + HRESULT STDMETHODCALLTYPE accHitTest(long xLeft, long yTop, VARIANT *pvarID); + HRESULT STDMETHODCALLTYPE accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID); + HRESULT STDMETHODCALLTYPE accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd); + HRESULT STDMETHODCALLTYPE get_accChild(VARIANT varChildID, IDispatch** ppdispChild); + HRESULT STDMETHODCALLTYPE get_accChildCount(long* pcountChildren); + HRESULT STDMETHODCALLTYPE get_accParent(IDispatch** ppdispParent); + + HRESULT STDMETHODCALLTYPE accDoDefaultAction(VARIANT varID); + HRESULT STDMETHODCALLTYPE get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction); + HRESULT STDMETHODCALLTYPE get_accDescription(VARIANT varID, BSTR* pszDescription); + HRESULT STDMETHODCALLTYPE get_accHelp(VARIANT varID, BSTR *pszHelp); + HRESULT STDMETHODCALLTYPE get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic); + HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut); + HRESULT STDMETHODCALLTYPE get_accName(VARIANT varID, BSTR* pszName); + HRESULT STDMETHODCALLTYPE put_accName(VARIANT varChild, BSTR szName); + HRESULT STDMETHODCALLTYPE get_accRole(VARIANT varID, VARIANT *pvarRole); + HRESULT STDMETHODCALLTYPE get_accState(VARIANT varID, VARIANT *pvarState); + HRESULT STDMETHODCALLTYPE get_accValue(VARIANT varID, BSTR* pszValue); + HRESULT STDMETHODCALLTYPE put_accValue(VARIANT varChild, BSTR szValue); + + HRESULT STDMETHODCALLTYPE accSelect(long flagsSelect, VARIANT varID); + HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT *pvarID); + HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT *pvarChildren); + + HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); + HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + +private: + ULONG ref; + QAccessibleInterface *accessible; +}; + +static inline BSTR QStringToBSTR(const QString &str) +{ + BSTR bstrVal; + + int wlen = str.length()+1; + bstrVal = SysAllocStringByteLen(0, wlen*2); + memcpy(bstrVal, str.unicode(), sizeof(QChar)*(wlen)); + bstrVal[wlen] = 0; + + return bstrVal; +} + +/* +*/ +IAccessible *qt_createWindowsAccessible(QAccessibleInterface *access) +{ + QWindowsAccessible *acc = new QWindowsAccessible(access); + IAccessible *iface; + acc->QueryInterface(IID_IAccessible, (void**)&iface); + + return iface; +} + +/* + IUnknown +*/ +HRESULT STDMETHODCALLTYPE QWindowsAccessible::QueryInterface(REFIID id, LPVOID *iface) +{ + *iface = 0; + if (id == IID_IUnknown) + *iface = (IUnknown*)(IDispatch*)this; + else if (id == IID_IDispatch) + *iface = (IDispatch*)this; + else if (id == IID_IAccessible) + *iface = (IAccessible*)this; + else if (id == IID_IOleWindow) + *iface = (IOleWindow*)this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +ULONG STDMETHODCALLTYPE QWindowsAccessible::AddRef() +{ + return ++ref; +} + +ULONG STDMETHODCALLTYPE QWindowsAccessible::Release() +{ + if (!--ref) { + delete this; + return 0; + } + return ref; +} + +/* + IDispatch +*/ + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfoCount(unsigned int * pctinfo) +{ + // We don't use a type library + *pctinfo = 0; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfo(unsigned int, unsigned long, ITypeInfo **pptinfo) +{ + // We don't use a type library + *pptinfo = 0; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetIDsOfNames(const _GUID &, wchar_t **rgszNames, unsigned int, unsigned long, long *rgdispid) +{ +#if !defined(Q_CC_BOR) && !defined(Q_CC_GNU) + // PROPERTIES: Hierarchical + if (_bstr_t(rgszNames[0]) == _bstr_t(L"accParent")) + rgdispid[0] = DISPID_ACC_PARENT; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount")) + rgdispid[0] = DISPID_ACC_CHILDCOUNT; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChild")) + rgdispid[0] = DISPID_ACC_CHILD; + + // PROPERTIES: Descriptional + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accName(")) + rgdispid[0] = DISPID_ACC_NAME; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accValue")) + rgdispid[0] = DISPID_ACC_VALUE; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription")) + rgdispid[0] = DISPID_ACC_DESCRIPTION; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accRole")) + rgdispid[0] = DISPID_ACC_ROLE; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accState")) + rgdispid[0] = DISPID_ACC_STATE; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp")) + rgdispid[0] = DISPID_ACC_HELP; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic")) + rgdispid[0] = DISPID_ACC_HELPTOPIC; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut")) + rgdispid[0] = DISPID_ACC_KEYBOARDSHORTCUT; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus")) + rgdispid[0] = DISPID_ACC_FOCUS; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection")) + rgdispid[0] = DISPID_ACC_SELECTION; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction")) + rgdispid[0] = DISPID_ACC_DEFAULTACTION; + + // METHODS + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect")) + rgdispid[0] = DISPID_ACC_SELECT; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation")) + rgdispid[0] = DISPID_ACC_LOCATION; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate")) + rgdispid[0] = DISPID_ACC_NAVIGATE; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest")) + rgdispid[0] = DISPID_ACC_HITTEST; + else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction")) + rgdispid[0] = DISPID_ACC_DODEFAULTACTION; + else + return DISP_E_UNKNOWNINTERFACE; + + return S_OK; +#else + Q_UNUSED(rgszNames); + Q_UNUSED(rgdispid); + + return DISP_E_MEMBERNOTFOUND; +#endif +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::Invoke(long dispIdMember, const _GUID &, unsigned long, unsigned short wFlags, tagDISPPARAMS *pDispParams, tagVARIANT *pVarResult, tagEXCEPINFO *, unsigned int *) +{ + HRESULT hr = DISP_E_MEMBERNOTFOUND; + + switch(dispIdMember) + { + case DISPID_ACC_PARENT: + if (wFlags == DISPATCH_PROPERTYGET) { + if (!pVarResult) + return E_INVALIDARG; + hr = get_accParent(&pVarResult->pdispVal); + } else { + hr = DISP_E_MEMBERNOTFOUND; + } + break; + + case DISPID_ACC_CHILDCOUNT: + if (wFlags == DISPATCH_PROPERTYGET) { + if (!pVarResult) + return E_INVALIDARG; + hr = get_accChildCount(&pVarResult->lVal); + } else { + hr = DISP_E_MEMBERNOTFOUND; + } + break; + + case DISPID_ACC_CHILD: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accChild(pDispParams->rgvarg[0], &pVarResult->pdispVal); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_NAME: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accName(pDispParams->rgvarg[0], &pVarResult->bstrVal); + else if (wFlags == DISPATCH_PROPERTYPUT) + hr = put_accName(pDispParams->rgvarg[0], pVarResult->bstrVal); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_VALUE: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accValue(pDispParams->rgvarg[0], &pVarResult->bstrVal); + else if (wFlags == DISPATCH_PROPERTYPUT) + hr = put_accValue(pDispParams->rgvarg[0], pVarResult->bstrVal); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_DESCRIPTION: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accDescription(pDispParams->rgvarg[0], &pVarResult->bstrVal); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_ROLE: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accRole(pDispParams->rgvarg[0], pVarResult); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_STATE: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accState(pDispParams->rgvarg[0], pVarResult); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_HELP: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accHelp(pDispParams->rgvarg[0], &pVarResult->bstrVal); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_HELPTOPIC: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accHelpTopic(&pDispParams->rgvarg[2].bstrVal, pDispParams->rgvarg[1], &pDispParams->rgvarg[0].lVal); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_KEYBOARDSHORTCUT: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accKeyboardShortcut(pDispParams->rgvarg[0], &pVarResult->bstrVal); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_FOCUS: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accFocus(pVarResult); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_SELECTION: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accSelection(pVarResult); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_DEFAULTACTION: + if (wFlags == DISPATCH_PROPERTYGET) + hr = get_accDefaultAction(pDispParams->rgvarg[0], &pVarResult->bstrVal); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_SELECT: + if (wFlags == DISPATCH_METHOD) + hr = accSelect(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_LOCATION: + if (wFlags == DISPATCH_METHOD) + hr = accLocation(&pDispParams->rgvarg[4].lVal, &pDispParams->rgvarg[3].lVal, &pDispParams->rgvarg[2].lVal, &pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_NAVIGATE: + if (wFlags == DISPATCH_METHOD) + hr = accNavigate(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0], pVarResult); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_HITTEST: + if (wFlags == DISPATCH_METHOD) + hr = accHitTest(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].lVal, pVarResult); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + case DISPID_ACC_DODEFAULTACTION: + if (wFlags == DISPATCH_METHOD) + hr = accDoDefaultAction(pDispParams->rgvarg[0]); + else + hr = DISP_E_MEMBERNOTFOUND; + break; + + default: + hr = DISP_E_MEMBERNOTFOUND; + break; + } + + if (!SUCCEEDED(hr)) { + return hr; + } + return hr; +} + +/* + IAccessible +*/ +HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + int control = accessible->childAt(xLeft, yTop); + if (control == -1) { + (*pvarID).vt = VT_EMPTY; + return S_FALSE; + } + QAccessibleInterface *acc = 0; + if (control) + accessible->navigate(Child, control, &acc); + if (!acc) { + (*pvarID).vt = VT_I4; + (*pvarID).lVal = control; + return S_OK; + } + + QWindowsAccessible* wacc = new QWindowsAccessible(acc); + IDispatch *iface = 0; + wacc->QueryInterface(IID_IDispatch, (void**)&iface); + if (iface) { + (*pvarID).vt = VT_DISPATCH; + (*pvarID).pdispVal = iface; + return S_OK; + } else { + delete wacc; + } + + (*pvarID).vt = VT_EMPTY; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QRect rect = accessible->rect(varID.lVal); + if (rect.isValid()) { + *pxLeft = rect.x(); + *pyTop = rect.y(); + *pcxWidth = rect.width(); + *pcyHeight = rect.height(); + } else { + *pxLeft = 0; + *pyTop = 0; + *pcxWidth = 0; + *pcyHeight = 0; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QAccessibleInterface *acc = 0; + int control = -1; + switch(navDir) { + case NAVDIR_FIRSTCHILD: + control = accessible->navigate(Child, 1, &acc); + break; + case NAVDIR_LASTCHILD: + control = accessible->navigate(Child, accessible->childCount(), &acc); + break; + case NAVDIR_NEXT: + case NAVDIR_PREVIOUS: + if (!varStart.lVal){ + QAccessibleInterface *parent = 0; + accessible->navigate(Ancestor, 1, &parent); + if (parent) { + int index = parent->indexOfChild(accessible); + index += (navDir == NAVDIR_NEXT) ? 1 : -1; + if (index > 0 && index <= parent->childCount()) + control = parent->navigate(Child, index, &acc); + delete parent; + } + } else { + int index = varStart.lVal; + index += (navDir == NAVDIR_NEXT) ? 1 : -1; + if (index > 0 && index <= accessible->childCount()) + control = accessible->navigate(Child, index, &acc); + } + break; + case NAVDIR_UP: + control = accessible->navigate(Up, varStart.lVal, &acc); + break; + case NAVDIR_DOWN: + control = accessible->navigate(Down, varStart.lVal, &acc); + break; + case NAVDIR_LEFT: + control = accessible->navigate(Left, varStart.lVal, &acc); + break; + case NAVDIR_RIGHT: + control = accessible->navigate(Right, varStart.lVal, &acc); + break; + default: + break; + } + if (control == -1) { + (*pvarEnd).vt = VT_EMPTY; + return S_FALSE; + } + if (!acc) { + (*pvarEnd).vt = VT_I4; + (*pvarEnd).lVal = control; + return S_OK; + } + + QWindowsAccessible* wacc = new QWindowsAccessible(acc); + + IDispatch *iface = 0; + wacc->QueryInterface(IID_IDispatch, (void**)&iface); + if (iface) { + (*pvarEnd).vt = VT_DISPATCH; + (*pvarEnd).pdispVal = iface; + return S_OK; + } else { + delete wacc; + } + + (*pvarEnd).vt = VT_EMPTY; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + if (varChildID.vt == VT_EMPTY) + return E_INVALIDARG; + + QAccessibleInterface *acc = 0; + RelationFlag rel = varChildID.lVal ? Child : Self; + accessible->navigate(rel, varChildID.lVal, &acc); + + if (acc) { + QWindowsAccessible* wacc = new QWindowsAccessible(acc); + wacc->QueryInterface(IID_IDispatch, (void**)ppdispChild); + return S_OK; + } + + *ppdispChild = 0; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChildCount(long* pcountChildren) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + *pcountChildren = accessible->childCount(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispParent) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QAccessibleInterface *acc = 0; + accessible->navigate(Ancestor, 1, &acc); + if (acc) { + QWindowsAccessible* wacc = new QWindowsAccessible(acc); + wacc->QueryInterface(IID_IDispatch, (void**)ppdispParent); + + if (*ppdispParent) + return S_OK; + } + + *ppdispParent = 0; + return S_FALSE; +} + +/* + Properties and methods +*/ +HRESULT STDMETHODCALLTYPE QWindowsAccessible::accDoDefaultAction(VARIANT varID) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + return accessible->doAction(DefaultAction, varID.lVal, QVariantList()) ? S_OK : S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QString def = accessible->actionText(DefaultAction, Name, varID.lVal); + if (def.isEmpty()) { + *pszDefaultAction = 0; + return S_FALSE; + } + + *pszDefaultAction = QStringToBSTR(def); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QString descr = accessible->text(Description, varID.lVal); + if (descr.size()) { + *pszDescription = QStringToBSTR(descr); + return S_OK; + } + + *pszDescription = 0; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QString help = accessible->text(Help, varID.lVal); + if (help.size()) { + *pszHelp = QStringToBSTR(help); + return S_OK; + } + + *pszHelp = 0; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelpTopic(BSTR *, VARIANT, long *) +{ + return DISP_E_MEMBERNOTFOUND; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QString sc = accessible->text(Accelerator, varID.lVal); + if (sc.size()) { + *pszKeyboardShortcut = QStringToBSTR(sc); + return S_OK; + } + + *pszKeyboardShortcut = 0; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* pszName) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QString n = accessible->text(Name, varID.lVal); + if (n.size()) { + *pszName = QStringToBSTR(n); + return S_OK; + } + + *pszName = 0; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accName(VARIANT, BSTR) +{ + showDebug(__FUNCTION__, accessible); + return DISP_E_MEMBERNOTFOUND; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + Role role = accessible->role(varID.lVal); + if (role != NoRole) { + (*pvarRole).vt = VT_I4; + (*pvarRole).lVal = role; + } else { + (*pvarRole).vt = VT_EMPTY; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accState(VARIANT varID, VARIANT *pvarState) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + (*pvarState).vt = VT_I4; + (*pvarState).lVal = accessible->state(varID.lVal); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accValue(VARIANT varID, BSTR* pszValue) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QString value = accessible->text(Value, varID.lVal); + if (!value.isNull()) { + *pszValue = QStringToBSTR(value); + return S_OK; + } + + *pszValue = 0; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accValue(VARIANT, BSTR) +{ + showDebug(__FUNCTION__, accessible); + return DISP_E_MEMBERNOTFOUND; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::accSelect(long flagsSelect, VARIANT varID) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + bool res = false; + + if (flagsSelect & SELFLAG_TAKEFOCUS) + res = accessible->doAction(SetFocus, varID.lVal, QVariantList()); + if (flagsSelect & SELFLAG_TAKESELECTION) { + accessible->doAction(ClearSelection, 0, QVariantList()); + res = accessible->doAction(AddToSelection, varID.lVal, QVariantList()); + } + if (flagsSelect & SELFLAG_EXTENDSELECTION) + res = accessible->doAction(ExtendSelection, varID.lVal, QVariantList()); + if (flagsSelect & SELFLAG_ADDSELECTION) + res = accessible->doAction(AddToSelection, varID.lVal, QVariantList()); + if (flagsSelect & SELFLAG_REMOVESELECTION) + res = accessible->doAction(RemoveSelection, varID.lVal, QVariantList()); + + return res ? S_OK : S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + QAccessibleInterface *acc = 0; + int control = accessible->navigate(FocusChild, 1, &acc); + if (control == -1) { + (*pvarID).vt = VT_EMPTY; + return S_FALSE; + } + if (!acc || control == 0) { + (*pvarID).vt = VT_I4; + (*pvarID).lVal = control ? control : CHILDID_SELF; + return S_OK; + } + + QWindowsAccessible* wacc = new QWindowsAccessible(acc); + IDispatch *iface = 0; + wacc->QueryInterface(IID_IDispatch, (void**)&iface); + if (iface) { + (*pvarID).vt = VT_DISPATCH; + (*pvarID).pdispVal = iface; + return S_OK; + } else { + delete wacc; + } + + (*pvarID).vt = VT_EMPTY; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren) +{ + showDebug(__FUNCTION__, accessible); + if (!accessible->isValid()) + return E_FAIL; + + int cc = accessible->childCount(); + QVector<int> sel(cc); + int selIndex = 0; + for (int i = 1; i <= cc; ++i) { + QAccessibleInterface *child = 0; + int i2 = accessible->navigate(Child, i, &child); + bool isSelected = false; + if (child) { + isSelected = child->state(0) & Selected; + delete child; + child = 0; + } else { + isSelected = accessible->state(i2) & Selected; + } + if (isSelected) + sel[selIndex++] = i; + } + sel.resize(selIndex); + if (sel.isEmpty()) { + (*pvarChildren).vt = VT_EMPTY; + return S_FALSE; + } + if (sel.size() == 1) { + (*pvarChildren).vt = VT_I4; + (*pvarChildren).lVal = sel[0]; + return S_OK; + } + IEnumVARIANT *iface = new QWindowsEnumerate(sel); + IUnknown *uiface; + iface->QueryInterface(IID_IUnknown, (void**)&uiface); + (*pvarChildren).vt = VT_UNKNOWN; + (*pvarChildren).punkVal = uiface; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetWindow(HWND *phwnd) +{ + *phwnd = 0; + if (!accessible->isValid()) + return E_UNEXPECTED; + + QObject *o = accessible->object(); + if (!o || !o->isWidgetType()) + return E_FAIL; + + *phwnd = static_cast<QWidget*>(o)->winId(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL) +{ + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY |