1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QtCore/QtConfig>
42 #ifndef QT_NO_ACCESSIBILITY
44 #include "iaccessible2.h"
45 #include "qwindowsaccessibility.h"
47 #include <QtGui/qaccessible2.h>
48 #include <QtWidgets/qapplication.h>
49 #include <QtCore/qdebug.h>
53 /**************************************************************\
54 * AccessibleApplication *
55 **************************************************************/
57 HRESULT STDMETHODCALLTYPE AccessibleApplication::QueryInterface(REFIID id, LPVOID *iface)
60 if (id == IID_IUnknown) {
61 accessibleDebug("AccessibleApplication::QI(): IID_IUnknown");
62 *iface = (IUnknown*)this;
63 } else if (id == IID_IAccessibleApplication) {
64 accessibleDebug("AccessibleApplication::QI(): IID_IAccessibleApplication");
65 *iface = static_cast<IAccessibleApplication*>(this);
75 ULONG STDMETHODCALLTYPE AccessibleApplication::AddRef()
80 ULONG STDMETHODCALLTYPE AccessibleApplication::Release()
89 /* IAccessibleApplication */
90 HRESULT STDMETHODCALLTYPE AccessibleApplication::get_appName(/* [retval][out] */ BSTR *name)
92 const QString appName = QGuiApplication::applicationName();
93 *name = QStringToBSTR(appName);
97 HRESULT STDMETHODCALLTYPE AccessibleApplication::get_appVersion(/* [retval][out] */ BSTR *version)
99 const QString appName = QGuiApplication::applicationVersion();
100 *version = QStringToBSTR(appName);
104 HRESULT STDMETHODCALLTYPE AccessibleApplication::get_toolkitName(/* [retval][out] */ BSTR *name)
106 *name = ::SysAllocString(L"Qt");
110 HRESULT STDMETHODCALLTYPE AccessibleApplication::get_toolkitVersion(/* [retval][out] */ BSTR *version)
112 *version = ::SysAllocString(QT_UNICODE_LITERAL(QT_VERSION_STR));
117 /**************************************************************\
118 * AccessibleRelation *
119 **************************************************************/
120 AccessibleRelation::AccessibleRelation(const QList<QAccessibleInterface *> &targets,
121 QAccessible::Relation relation)
122 : m_targets(targets), m_relation(relation), m_ref(1)
124 Q_ASSERT(m_targets.count());
128 HRESULT STDMETHODCALLTYPE AccessibleRelation::QueryInterface(REFIID id, LPVOID *iface)
131 if (id == IID_IUnknown)
132 *iface = (IUnknown*)this;
139 return E_NOINTERFACE;
142 ULONG STDMETHODCALLTYPE AccessibleRelation::AddRef()
147 ULONG STDMETHODCALLTYPE AccessibleRelation::Release()
156 /* IAccessibleRelation */
157 HRESULT STDMETHODCALLTYPE AccessibleRelation::get_relationType(
158 /* [retval][out] */ BSTR *relationType)
160 *relationType = relationToBSTR(m_relation);
164 HRESULT STDMETHODCALLTYPE AccessibleRelation::get_localizedRelationType(
165 /* [retval][out] */ BSTR *localizedRelationType)
167 // Who ever needs this???
168 *localizedRelationType = relationToBSTR(m_relation);
172 HRESULT STDMETHODCALLTYPE AccessibleRelation::get_nTargets(
173 /* [retval][out] */ long *nTargets)
175 // ### always one target
176 *nTargets = m_targets.count();
182 Client allocates and deallocates array
183 (see "Special Consideration when using Arrays", in Accessible2.idl)
185 HRESULT STDMETHODCALLTYPE AccessibleRelation::get_target(
186 /* [in] */ long targetIndex,
187 /* [retval][out] */ IUnknown **target)
189 if (targetIndex >= 0 && targetIndex < m_targets.count()) {
190 QAccessibleInterface *iface = m_targets.at(targetIndex);
191 *target = QWindowsAccessibility::wrap(iface);
201 Client allocates and deallocates \a targets array
202 (see "Special Consideration when using Arrays", in Accessible2.idl)
204 HRESULT STDMETHODCALLTYPE AccessibleRelation::get_targets(
205 /* [in] */ long maxTargets,
206 /* [length_is][size_is][out] */ IUnknown **targets,
207 /* [retval][out] */ long *nTargets)
210 const int numTargets = qMin((int)maxTargets, m_targets.count());
211 for (int i = 0; i < numTargets; ++i) {
212 QAccessibleInterface *iface = m_targets.at(i);
213 IAccessible *iacc = QWindowsAccessibility::wrap(iface);
219 *nTargets = numTargets;
220 // \a targets array is allocated by client.
221 return numTargets > 0 ? S_OK : S_FALSE;
225 /**************************************************************\
229 **************************************************************/
230 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryInterface(REFIID id, LPVOID *iface)
232 HRESULT hr = QWindowsMsaaAccessible::QueryInterface(id, iface);
233 if (!SUCCEEDED(hr)) {
234 if (id == IID_IServiceProvider) {
235 *iface = (IServiceProvider*)this;
236 } else if (id == IID_IAccessible2) {
237 *iface = (IAccessible2*)this;
238 } else if (id == IID_IAccessibleAction) {
239 if (accessible->actionInterface())
240 *iface = (IAccessibleAction*)this;
241 } else if (id == IID_IAccessibleComponent) {
242 *iface = (IAccessibleComponent*)this;
243 } else if (id == IID_IAccessibleEditableText) {
244 //if (accessible->editableTextInterface()) {
245 //*iface = (IAccessibleEditableText*)this;
247 } else if (id == IID_IAccessibleHyperlink) {
248 //*iface = (IAccessibleHyperlink*)this;
249 } else if (id == IID_IAccessibleHypertext) {
250 //*iface = (IAccessibleHypertext*)this;
251 } else if (id == IID_IAccessibleImage) {
252 //*iface = (IAccessibleImage*)this;
253 } else if (id == IID_IAccessibleRelation) {
254 *iface = (IAccessibleRelation*)this;
255 } else if (id == IID_IAccessibleTable) {
256 //*iface = (IAccessibleTable*)this; // not supported
257 } else if (id == IID_IAccessibleTable2) {
258 if (accessible->tableInterface())
259 *iface = (IAccessibleTable2*)this;
260 } else if (id == IID_IAccessibleTableCell) {
261 if (accessible->tableCellInterface())
262 *iface = (IAccessibleTableCell*)this;
263 } else if (id == IID_IAccessibleText) {
264 if (accessible->textInterface())
265 *iface = (IAccessibleText*)this;
266 } else if (id == IID_IAccessibleValue) {
267 if (accessible->valueInterface())
268 *iface = (IAccessibleValue*)this;
281 /* Note that IUnknown is inherited from several interfaces. Therefore we must reimplement all its
282 functions in the concrete class to avoid ambiguity.
284 ULONG STDMETHODCALLTYPE QWindowsIA2Accessible::AddRef()
286 return QWindowsMsaaAccessible::AddRef();
289 ULONG STDMETHODCALLTYPE QWindowsIA2Accessible::Release()
291 return QWindowsMsaaAccessible::Release();
294 /**************************************************************\
298 **************************************************************/
299 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRelations(long *nRelations)
301 accessibleDebugClientCalls(accessible);
304 if (!accessible->isValid())
307 return getRelationsHelper(0, 0, 0, nRelations);
310 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relation(long relationIndex, IAccessibleRelation **relation)
312 accessibleDebugClientCalls(accessible);
315 if (!accessible->isValid())
318 return getRelationsHelper(relation, relationIndex, 1);
323 Client allocates and deallocates array
324 (see "Special Consideration when using Arrays", in Accessible2.idl)
326 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relations(long maxRelations,
327 IAccessibleRelation **relations,
330 accessibleDebugClientCalls(accessible);
331 if (!accessible->isValid())
334 return getRelationsHelper(relations, 0, maxRelations, nRelations);
338 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::role(long *ia2role)
340 accessibleDebugClientCalls(accessible);
341 if (!accessible->isValid())
344 long r = accessible->role();
347 case QAccessible::LayeredPane: r = IA2_ROLE_LAYERED_PANE; break;
348 case QAccessible::Terminal: r = IA2_ROLE_TERMINAL; break;
349 case QAccessible::Desktop: r = IA2_ROLE_DESKTOP_PANE; break;
358 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollTo(enum IA2ScrollType /*scrollType*/)
365 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollToPoint(enum IA2CoordinateType /*coordinateType*/, long /*x*/, long /*y*/)
372 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_groupPosition(long *groupLevel,
373 long *similarItemsInGroup,
374 long *positionInGroup)
376 // ### Ignore for now. Not sure what this is used for.....
377 *groupLevel = 0; // Not applicable
378 *similarItemsInGroup = 0; // Not applicable
379 *positionInGroup = 0; // Not applicable
384 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_states(AccessibleStates *states)
386 accessibleDebugClientCalls(accessible);
387 if (!accessible->isValid())
391 QAccessible::State st = accessible->state();
392 AccessibleStates ia2states = 0;
394 ia2states |= IA2_STATE_ACTIVE;
396 ia2states |= IA2_STATE_DEFUNCT;
398 ia2states |= IA2_STATE_EDITABLE;
400 ia2states |= IA2_STATE_MULTI_LINE;
401 if (st.selectableText)
402 ia2states |= IA2_STATE_SELECTABLE_TEXT;
403 if (st.supportsAutoCompletion)
404 ia2states |= IA2_STATE_SUPPORTS_AUTOCOMPLETION;
411 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_extendedRole(BSTR *extendedRole)
415 return E_NOTIMPL; // mozilla does this
420 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedExtendedRole(BSTR *localizedExtendedRole)
423 *localizedExtendedRole = 0;
424 return E_NOTIMPL; // mozilla does this
429 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nExtendedStates(long *nExtendedStates)
431 // Who will ever intepret these values into something meaningful??
432 *nExtendedStates = 0;
433 return E_NOTIMPL; // mozilla does this
438 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_extendedStates(long /*maxExtendedStates*/,
439 BSTR **extendedStates,
440 long *nExtendedStates)
443 *nExtendedStates = 0;
444 return E_NOTIMPL; // mozilla does this
449 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedExtendedStates(long /*maxLocalizedExtendedStates*/,
450 BSTR **localizedExtendedStates,
451 long *nLocalizedExtendedStates)
453 *localizedExtendedStates = 0;
454 *nLocalizedExtendedStates = 0;
455 return E_NOTIMPL; // mozilla does this
460 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_uniqueID(long *outUniqueID)
462 accessibleDebugClientCalls(accessible);
463 if (!accessible->isValid())
465 // ### FIXME SERIOUSLY, NOT A STABLE SOLUTION IF NODES ARE DELETED ETC
466 // Return 0 if no object and no parent. This is really an error case.
467 uint uid = uniqueID();
468 accessibleDebug("uniqueID: %08x", uid);
470 *outUniqueID = (long)uid;
471 return uid ? S_OK : S_FALSE;
475 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_windowHandle(HWND *windowHandle)
477 accessibleDebugClientCalls(accessible);
478 if (!accessible->isValid())
480 return GetWindow(windowHandle);
484 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_indexInParent(long *indexInParent)
486 accessibleDebugClientCalls(accessible);
487 if (!accessible->isValid())
491 QAccessibleInterface *par = accessible->parent();
496 int indexOfChild = par->indexOfChild(accessible);
498 Q_ASSERT(indexOfChild >= 0);
499 *indexInParent = indexOfChild;
503 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locale(IA2Locale *locale)
505 accessibleDebugClientCalls(accessible);
506 if (!accessible->isValid())
510 res.country = QStringToBSTR(QLocale::countryToString(l.country()));
511 res.language = QStringToBSTR(QLocale::languageToString(l.language()));
517 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(BSTR *attributes)
519 accessibleDebugClientCalls(accessible);
520 if (!accessible->isValid())
522 *attributes = 0;//QStringToBSTR(QString());
526 /**************************************************************\
527 * IAccessibleAction *
528 **************************************************************/
529 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions)
531 accessibleDebugClientCalls(accessible);
532 if (!accessible->isValid())
536 if (QAccessibleActionInterface *actionIface = actionInterface())
537 *nActions = actionIface->actionNames().count();
541 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex)
543 accessibleDebugClientCalls(accessible);
544 if (!accessible->isValid())
546 if (QAccessibleActionInterface *actionIface = actionInterface()) {
547 const QStringList actionNames = actionIface->actionNames();
548 if (actionIndex < 0 || actionIndex >= actionNames.count())
550 const QString actionName = actionNames.at(actionIndex);
551 actionIface->doAction(actionName);
557 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionIndex, BSTR *description)
559 accessibleDebugClientCalls(accessible);
560 if (!accessible->isValid())
563 if (QAccessibleActionInterface *actionIface = actionInterface()) {
564 const QStringList actionNames = actionIface->actionNames();
565 if (actionIndex < 0 || actionIndex >= actionNames.count())
567 const QString actionName = actionNames.at(actionIndex);
568 *description = QStringToBSTR(actionIface->localizedActionDescription(actionName));
570 return *description ? S_OK : S_FALSE;
573 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_keyBinding(long actionIndex, long nMaxBindings, BSTR **keyBindings, long *nBindings)
575 accessibleDebugClientCalls(accessible);
576 if (!accessible->isValid())
578 Q_UNUSED(nMaxBindings);
579 BSTR *arrayOfBindingsToReturn = 0;
581 if (QAccessibleActionInterface *actionIface = actionInterface()) {
582 const QStringList actionNames = actionIface->actionNames();
583 if (actionIndex < 0 || actionIndex >= actionNames.count())
585 const QString actionName = actionNames.at(actionIndex);
586 const QStringList keyBindings = actionIface->keyBindingsForAction(actionName);
587 numBindings = keyBindings.count();
588 if (numBindings > 0) {
589 // The IDL documents that the client must free with CoTaskMemFree
590 arrayOfBindingsToReturn = (BSTR*)::CoTaskMemAlloc(sizeof(BSTR) * numBindings);
591 for (int i = 0; i < numBindings; ++i)
592 arrayOfBindingsToReturn[i] = QStringToBSTR(keyBindings.at(i));
595 *keyBindings = arrayOfBindingsToReturn;
596 *nBindings = numBindings;
598 return numBindings ? S_OK : S_FALSE;
601 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR *name)
603 accessibleDebugClientCalls(accessible);
604 if (!accessible->isValid())
607 if (QAccessibleActionInterface *actionIface = actionInterface()) {
608 const QStringList actionNames = actionIface->actionNames();
609 if (actionIndex < 0 || actionIndex >= actionNames.count())
611 const QString actionName = actionNames.at(actionIndex);
612 *name = QStringToBSTR(actionName);
614 return *name ? S_OK : S_FALSE;
617 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIndex, BSTR *localizedName)
619 accessibleDebugClientCalls(accessible);
620 if (!accessible->isValid())
623 if (QAccessibleActionInterface *actionIface = actionInterface()) {
624 const QStringList actionNames = actionIface->actionNames();
625 if (actionIndex < 0 || actionIndex >= actionNames.count())
628 const QString actionName = actionNames.at(actionIndex);
629 *localizedName = QStringToBSTR(actionIface->localizedActionName(actionName));
631 return *localizedName ? S_OK : S_FALSE;
634 /**************************************************************\
635 * IAccessibleComponent *
636 **************************************************************/
637 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locationInParent(long *x, long *y)
639 accessibleDebugClientCalls(accessible);
640 if (!accessible->isValid())
643 QPoint topLeft = accessible->rect().topLeft();
645 if (QAccessibleInterface *parentIface = accessible->parent())
646 topLeft -= parentIface->rect().topLeft();
653 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_foreground(IA2Color *foreground)
655 accessibleDebugClientCalls(accessible);
656 if (!accessible->isValid())
659 // IA2Color is a typedef for long
660 *foreground = (IA2Color)accessible->foregroundColor().rgb();
664 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_background(IA2Color *background)
666 accessibleDebugClientCalls(accessible);
667 if (!accessible->isValid())
670 // IA2Color is a typedef for long
671 *background = (IA2Color)accessible->backgroundColor().rgb();
675 /**************************************************************\
676 * IAccessibleTable2 *
677 **************************************************************/
678 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_cellAt( long row, long column, IUnknown **cell)
680 accessibleDebugClientCalls(accessible);
681 if (!accessible->isValid())
685 if (QAccessibleTableInterface *tableIface = tableInterface()) {
686 if (QAccessibleInterface *qtCell = tableIface->cellAt(row, column)) {
687 *cell = QWindowsAccessibility::wrap(qtCell);
690 accessibleDebug("found cell? %p", *cell);
691 return *cell ? S_OK : S_FALSE;
694 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caption( IUnknown **captionInterface)
696 accessibleDebugClientCalls(accessible);
697 if (!accessible->isValid())
700 *captionInterface = 0;
701 if (QAccessibleTableInterface *tableIface = tableInterface()) {
702 if (QAccessibleInterface *iface = tableIface->caption())
703 *captionInterface = QWindowsAccessibility::wrap(iface);
705 return *captionInterface ? S_OK : S_FALSE;
708 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnDescription( long column, BSTR *description)
710 accessibleDebugClientCalls(accessible);
711 if (!accessible->isValid())
715 if (QAccessibleTableInterface *tableIface = tableInterface()) {
716 const QString qtDesc = tableIface->columnDescription(column);
717 if (!qtDesc.isEmpty())
718 *description = QStringToBSTR(qtDesc);
720 return *description ? S_OK : S_FALSE;
723 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nColumns( long *columnCount)
725 accessibleDebugClientCalls(accessible);
726 if (!accessible->isValid())
729 if (QAccessibleTableInterface *tableIface = tableInterface()) {
730 *columnCount = tableIface->columnCount();
736 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRows(long *rowCount)
738 accessibleDebugClientCalls(accessible);
739 if (!accessible->isValid())
742 if (QAccessibleTableInterface *tableIface = tableInterface()) {
743 *rowCount = tableIface->rowCount();
749 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedCells(long *cellCount)
751 accessibleDebugClientCalls(accessible);
752 if (!accessible->isValid())
755 if (QAccessibleTableInterface *tableIface = tableInterface()) {
756 *cellCount = tableIface->selectedCellCount();
762 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedColumns(long *columnCount)
764 accessibleDebugClientCalls(accessible);
765 if (!accessible->isValid())
768 if (QAccessibleTableInterface *tableIface = tableInterface()) {
769 *columnCount = tableIface->selectedColumnCount();
775 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedRows(long *rowCount)
777 accessibleDebugClientCalls(accessible);
778 if (!accessible->isValid())
781 if (QAccessibleTableInterface *tableIface = tableInterface()) {
782 *rowCount = tableIface->selectedRowCount();
788 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowDescription(long row, BSTR *description)
790 accessibleDebugClientCalls(accessible);
791 if (!accessible->isValid())
795 if (QAccessibleTableInterface *tableIface = tableInterface()) {
796 const QString qtDesc = tableIface->columnDescription(row);
797 if (!qtDesc.isEmpty())
798 *description = QStringToBSTR(qtDesc);
800 return *description ? S_OK : S_FALSE;
803 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedCells(IUnknown ***cells, long *nSelectedCells)
805 accessibleDebugClientCalls(accessible);
807 Q_UNUSED(nSelectedCells);
808 if (!accessible->isValid())
811 QList<QAccessibleInterface*> selectedCells = tableInterface()->selectedCells();
812 return wrapListOfCells(selectedCells, cells, nSelectedCells);
815 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedColumns(long **selectedColumns, long *nColumns)
817 accessibleDebugClientCalls(accessible);
818 if (!accessible->isValid())
821 if (QAccessibleTableInterface *tableIface = tableInterface()) {
822 const QList<int> selectedIndices = tableIface->selectedColumns();
823 const int &count = selectedIndices.count();
824 long *selected = (count ? (long*)::CoTaskMemAlloc(sizeof(long) * count) : (long*)0);
825 for (int i = 0; i < count; ++i)
826 selected[i] = selectedIndices.at(i);
827 *selectedColumns = selected;
829 return count ? S_OK : S_FALSE;
835 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedRows(long **selectedRows, long *nRows)
837 accessibleDebugClientCalls(accessible);
838 if (!accessible->isValid())
841 if (QAccessibleTableInterface *tableIface = tableInterface()) {
842 const QList<int> selectedIndices = tableIface->selectedRows();
843 const int &count = selectedIndices.count();
844 long *selected = (count ? (long*)::CoTaskMemAlloc(sizeof(long) * count) : (long*)0);
845 for (int i = 0; i < count; ++i)
846 selected[i] = selectedIndices.at(i);
847 *selectedRows = selected;
849 return count ? S_OK : S_FALSE;
855 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_summary(IUnknown **summaryInterface)
857 accessibleDebugClientCalls(accessible);
858 if (!accessible->isValid())
861 *summaryInterface = 0;
862 if (QAccessibleTableInterface *tableIface = tableInterface()) {
863 if (QAccessibleInterface *iface = tableIface->summary())
864 *summaryInterface = QWindowsAccessibility::wrap(iface);
866 return *summaryInterface ? S_OK : S_FALSE;
869 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isColumnSelected(long column, boolean *isSelected)
871 accessibleDebugClientCalls(accessible);
872 if (!accessible->isValid())
875 if (QAccessibleTableInterface *tableIface = tableInterface()) {
876 *isSelected = tableIface->isColumnSelected(column);
882 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isRowSelected(long row, boolean *isSelected)
884 accessibleDebugClientCalls(accessible);
885 if (!accessible->isValid())
888 if (QAccessibleTableInterface *tableIface = tableInterface()) {
889 *isSelected = tableIface->isRowSelected(row);
895 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectRow(long row)
897 accessibleDebugClientCalls(accessible);
898 if (!accessible->isValid())
901 if (QAccessibleTableInterface *tableIface = tableInterface()) {
902 bool ok = tableIface->selectRow(row);
903 return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
908 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectColumn(long column)
910 accessibleDebugClientCalls(accessible);
911 if (!accessible->isValid())
914 if (QAccessibleTableInterface *tableIface = tableInterface()) {
915 bool ok = tableIface->selectColumn(column);
916 return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
921 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectRow(long row)
923 accessibleDebugClientCalls(accessible);
924 if (!accessible->isValid())
927 if (QAccessibleTableInterface *tableIface = tableInterface()) {
928 bool ok = tableIface->unselectRow(row);
929 return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
934 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectColumn(long column)
936 accessibleDebugClientCalls(accessible);
937 if (!accessible->isValid())
940 if (QAccessibleTableInterface *tableIface = tableInterface()) {
941 bool ok = tableIface->unselectColumn(column);
942 return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
947 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_modelChange( IA2TableModelChange * /*modelChange*/)
949 accessibleDebugClientCalls(accessible);
950 if (!accessible->isValid())
955 /**************************************************************\
956 * IAccessibleTableCell *
957 \**************************************************************/
958 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnExtent(long *nColumnsSpanned)
960 accessibleDebugClientCalls(accessible);
961 if (!accessible->isValid())
964 *nColumnsSpanned = tableCellInterface()->columnExtent();
968 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnHeaderCells(IUnknown ***cellAccessibles,
969 long *nColumnHeaderCells)
971 accessibleDebugClientCalls(accessible);
972 if (!accessible->isValid())
974 const QList<QAccessibleInterface*> headerCells = tableCellInterface()->columnHeaderCells();
975 return wrapListOfCells(headerCells, cellAccessibles, nColumnHeaderCells);
978 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnIndex(long *columnIndex)
980 accessibleDebugClientCalls(accessible);
981 if (!accessible->isValid())
983 *columnIndex = tableCellInterface()->columnIndex();
987 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowExtent(long *nRowsSpanned)
989 accessibleDebugClientCalls(accessible);
990 if (!accessible->isValid())
992 *nRowsSpanned = tableCellInterface()->rowExtent();
996 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowHeaderCells(IUnknown ***cellAccessibles,
997 long *nRowHeaderCells)
999 accessibleDebugClientCalls(accessible);
1000 if (!accessible->isValid())
1002 const QList<QAccessibleInterface*> headerCells = tableCellInterface()->rowHeaderCells();
1003 return wrapListOfCells(headerCells, cellAccessibles, nRowHeaderCells);
1006 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowIndex(long *rowIndex)
1008 accessibleDebugClientCalls(accessible);
1009 if (!accessible->isValid())
1011 *rowIndex = tableCellInterface()->rowIndex();
1015 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isSelected( boolean *isSelected)
1017 accessibleDebugClientCalls(accessible);
1018 if (!accessible->isValid())
1020 *isSelected = tableCellInterface()->isSelected();
1024 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowColumnExtents(long *row, long *column,
1025 long *rowExtents, long *columnExtents,
1026 boolean *isSelected)
1028 accessibleDebugClientCalls(accessible);
1029 if (!accessible->isValid())
1032 tableCellInterface()->rowColumnExtents((int*)row, (int*)column, (int*)rowExtents, (int*)columnExtents, (bool*)isSelected);
1036 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_table(IUnknown **table)
1038 accessibleDebugClientCalls(accessible);
1039 if (!accessible->isValid())
1042 QAccessibleInterface *tableIface = tableCellInterface()->table();
1044 *table = QWindowsAccessibility::wrap(tableIface);
1048 /**************************************************************\
1050 \**************************************************************/
1051 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::addSelection(long startOffset,
1054 accessibleDebugClientCalls(accessible);
1055 if (QAccessibleTextInterface *text = textInterface()) {
1056 text->addSelection(startOffset, endOffset);
1062 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(long offset,
1065 BSTR *textAttributes)
1067 accessibleDebugClientCalls(accessible);
1068 if (QAccessibleTextInterface *text = textInterface()) {
1069 const QString attrs = text->attributes(offset, (int*)startOffset, (int*)endOffset);
1070 *textAttributes = QStringToBSTR(attrs);
1076 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caretOffset(long *offset)
1078 accessibleDebugClientCalls(accessible);
1079 if (QAccessibleTextInterface *text = textInterface()) {
1080 *offset = text->cursorPosition();
1087 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_characterExtents(long offset,
1088 enum IA2CoordinateType coordType,
1094 accessibleDebugClientCalls(accessible);
1095 if (QAccessibleTextInterface *text = textInterface()) {
1096 QRect rect = text->characterRect(offset);
1097 mapFromScreenPos(coordType, rect.topLeft(), x, y);
1098 *width = rect.width();
1099 *height = rect.height();
1105 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelections(long *nSelections)
1107 accessibleDebugClientCalls(accessible);
1108 if (QAccessibleTextInterface *text = textInterface()) {
1109 *nSelections = text->selectionCount();
1115 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_offsetAtPoint(long x,
1117 enum IA2CoordinateType coordType,
1120 accessibleDebugClientCalls(accessible);
1121 if (QAccessibleTextInterface *text = textInterface()) {
1122 QPoint screenPos = mapToScreenPos(coordType, x, y);
1123 *offset = text->offsetAtPoint(screenPos);
1124 return (*offset >=0 ? S_OK : S_FALSE);
1130 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selection(long selectionIndex,
1134 accessibleDebugClientCalls(accessible);
1135 if (QAccessibleTextInterface *text = textInterface()) {
1136 text->selection(selectionIndex, (int*)startOffset, (int*)endOffset);
1142 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_text(long startOffset,
1146 accessibleDebugClientCalls(accessible);
1147 if (QAccessibleTextInterface *textif = textInterface()) {
1148 const QString t = textif->text(startOffset, endOffset);
1150 *text = QStringToBSTR(t);
1153 return E_INVALIDARG;
1158 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textBeforeOffset(long offset,
1159 enum IA2TextBoundaryType boundaryType,
1164 accessibleDebugClientCalls(accessible);
1165 if (QAccessibleTextInterface *textIface = textInterface()) {
1166 const QString txt = textIface->textBeforeOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
1167 if (!txt.isEmpty()) {
1168 *text = QStringToBSTR(txt);
1176 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAfterOffset(
1178 enum IA2TextBoundaryType boundaryType,
1183 accessibleDebugClientCalls(accessible);
1184 if (QAccessibleTextInterface *textIface = textInterface()) {
1185 const QString txt = textIface->textAfterOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
1186 if (!txt.isEmpty()) {
1187 *text = QStringToBSTR(txt);
1195 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAtOffset(long offset,
1196 enum IA2TextBoundaryType boundaryType,
1201 accessibleDebugClientCalls(accessible);
1202 if (QAccessibleTextInterface *textIface = textInterface()) {
1203 const QString txt = textIface->textAtOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
1204 if (!txt.isEmpty()) {
1205 *text = QStringToBSTR(txt);
1213 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::removeSelection(long selectionIndex)
1215 accessibleDebugClientCalls(accessible);
1216 if (QAccessibleTextInterface *textIface = textInterface()) {
1217 textIface->removeSelection(selectionIndex);
1223 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCaretOffset(long offset)
1225 accessibleDebugClientCalls(accessible);
1226 if (QAccessibleTextInterface *textIface = textInterface()) {
1227 textIface->setCursorPosition(offset);
1233 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setSelection(long selectionIndex,
1237 accessibleDebugClientCalls(accessible);
1238 if (QAccessibleTextInterface *textIface = textInterface()) {
1239 textIface->setSelection(selectionIndex, startOffset, endOffset);
1245 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nCharacters(long *nCharacters)
1247 accessibleDebugClientCalls(accessible);
1248 if (QAccessibleTextInterface *textIface = textInterface()) {
1249 *nCharacters = textIface->characterCount();
1255 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringTo(long startIndex,
1257 enum IA2ScrollType scrollType)
1259 accessibleDebugClientCalls(accessible);
1260 if (QAccessibleTextInterface *textIface = textInterface()) {
1261 Q_UNUSED(scrollType); //###
1262 textIface->scrollToSubstring(startIndex, endIndex);
1268 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringToPoint(long startIndex,
1270 enum IA2CoordinateType coordinateType,
1274 Q_UNUSED(startIndex);
1276 Q_UNUSED(coordinateType);
1283 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_newText(IA2TextSegment *newText)
1289 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_oldText(IA2TextSegment *oldText)
1295 /**************************************************************\
1296 * IAccessibleValue *
1297 **************************************************************/
1298 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_currentValue(VARIANT *currentValue)
1300 accessibleDebugClientCalls(accessible);
1301 if (!accessible->isValid())
1303 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1304 const QVariant var = valueIface->currentValue();
1305 if (QVariantToVARIANT(var, *currentValue, QByteArray(), false))
1309 currentValue->vt = VT_EMPTY;
1313 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCurrentValue(VARIANT value)
1315 accessibleDebugClientCalls(accessible);
1316 if (!accessible->isValid())
1318 HRESULT hr = S_FALSE;
1319 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1320 hr = VariantChangeType(&value, &value, 0, VT_R8);
1321 if (SUCCEEDED(hr)) {
1322 // ### works only for numbers (not date, strings, etc)
1323 valueIface->setCurrentValue(QVariant(value.dblVal));
1329 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_maximumValue(VARIANT *maximumValue)
1331 accessibleDebugClientCalls(accessible);
1332 if (!accessible->isValid())
1334 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1335 const QVariant var = valueIface->maximumValue();
1336 if (QVariantToVARIANT(var, *maximumValue, QByteArray(), false))
1339 maximumValue->vt = VT_EMPTY;
1343 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_minimumValue(VARIANT *minimumValue)
1345 accessibleDebugClientCalls(accessible);
1346 if (!accessible->isValid())
1348 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1349 const QVariant var = valueIface->minimumValue();
1350 if (QVariantToVARIANT(var, *minimumValue, QByteArray(), false))
1353 minimumValue->vt = VT_EMPTY;
1358 /**************************************************************\
1359 * IServiceProvider *
1360 **************************************************************/
1363 Reimplemented from IServiceProvider
1365 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryService(REFGUID guidService, REFIID riid, void **iface)
1369 Q_UNUSED(guidService);
1371 accessibleDebug("QWindowsIA2Accessible::QS(): %s", IIDToString(riid).constData());
1373 if (guidService == IID_IAccessible && riid == IID_IAccessible2) {
1374 // The conditions for entering here should be ok (from _dicoveringInterfaces in IAccessible2.idl)
1375 *iface = static_cast<IAccessible2*>(this);
1376 } else if (guidService == IID_IAccessible && (riid == IID_IAccessible || riid == IID_IUnknown || riid == IID_IDispatch)) {
1377 // The above conditions works with AccProbe and NVDA.
1378 *iface = static_cast<IAccessible*>(this);
1379 } else if (riid == IID_IAccessibleApplication) {
1380 *iface = new AccessibleApplication;
1388 return E_NOINTERFACE;
1395 \a maxRelations max number of relations to return in \a relations
1396 \a relations the array of relations matching
1397 \a startIndex Index to start to return from,
1398 it will return only that specific relation in \a relations
1400 If \a relations is null, \a startIndex and \a maxRelations are ignored, causing
1401 it to return the number of relations in \a nRelations
1403 HRESULT QWindowsIA2Accessible::getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations /* = 0*/)
1407 typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationEntry;
1408 QVector<RelationEntry> rels = accessible->relations();
1409 QMap<QAccessible::Relation, QAccessibleInterface *> relationMap;
1410 for (QVector<RelationEntry>::const_iterator it = rels.constBegin(); it != rels.constEnd(); ++it)
1412 RelationEntry e = *it;
1413 relationMap.insertMulti(e.second, e.first);
1416 QList<QAccessible::Relation> keys = relationMap.keys();
1417 const int numRelations = keys.count();
1419 for (int i = startIndex; i < qMin(startIndex + (int)maxRelations, numRelations); ++i) {
1420 QAccessible::Relation relation = keys.at(i);
1421 QList<QAccessibleInterface*> targets = relationMap.values(relation);
1422 AccessibleRelation *rel = new AccessibleRelation(targets, relation);
1428 *nRelations = numRelations;
1430 return numRelations > 0 ? S_OK : S_FALSE;
1438 helper to wrap a QList<QAccessibleInterface*> inside an array of IAccessible*
1439 The IAccessible* array is returned as a IUnknown*
1441 HRESULT QWindowsIA2Accessible::wrapListOfCells(const QList<QAccessibleInterface*> &inputCells, IUnknown ***outputAccessibles, long *nCellCount)
1443 const int count = inputCells.count();
1444 // Server allocates array
1445 IUnknown **outputCells = count ? (IUnknown**)::CoTaskMemAlloc(sizeof(IUnknown*) * count ) : (IUnknown**)0;
1446 for (int i = 0; i < count; ++i)
1447 outputCells[i] = QWindowsAccessibility::wrap(inputCells.at(i));
1449 *outputAccessibles = outputCells;
1450 *nCellCount = count;
1451 return count > 0 ? S_OK : S_FALSE;
1454 uint QWindowsIA2Accessible::uniqueID() const
1457 if (QObject *obj = accessible->object())
1461 QAccessibleInterface *acc = accessible;
1462 QVector<int> indexOfNodes;
1463 while (acc && !acc->object()) {
1464 QAccessibleInterface *par = acc->parent();
1465 indexOfNodes.append(par->indexOfChild(acc));
1466 if (acc != accessible)
1471 if (acc->object()) {
1472 uid = qHash(acc->object());
1473 for (int i = 0; i < indexOfNodes.count(); ++i)
1474 uid = qHash(uid + indexOfNodes.at(i));
1477 if (acc != accessible)
1485 #define IF_EQUAL_RETURN_IIDSTRING(id, iid) if (id == iid) return QByteArray(#iid)
1487 QByteArray QWindowsIA2Accessible::IIDToString(REFIID id)
1489 QByteArray strGuid = QWindowsMsaaAccessible::IIDToString(id);
1490 if (!strGuid.isEmpty())
1493 IF_EQUAL_RETURN_IIDSTRING(id, IID_IUnknown);
1494 IF_EQUAL_RETURN_IIDSTRING(id, IID_IDispatch);
1495 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible);
1496 IF_EQUAL_RETURN_IIDSTRING(id, IID_IOleWindow);
1497 IF_EQUAL_RETURN_IIDSTRING(id, IID_IServiceProvider);
1498 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible2);
1499 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleAction);
1500 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleApplication);
1501 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleComponent);
1502 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleEditableText);
1503 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHyperlink);
1504 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHypertext);
1505 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleImage);
1506 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleRelation);
1507 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable);
1508 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable2);
1509 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTableCell);
1510 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleText);
1511 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleValue);
1514 #if 0 // Can be useful for debugging, but normally we'd like to reduce the noise a bit...
1515 OLECHAR szGuid[39]={0};
1516 ::StringFromGUID2(id, szGuid, 39);
1517 strGuid.reserve(40);
1518 ::WideCharToMultiByte(CP_UTF8, 0, szGuid, 39, strGuid.data(), 39, NULL, NULL);
1527 #endif //QT_NO_ACCESSIBILITY