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));
120 Client allocates and deallocates array
121 (see "Special Consideration when using Arrays", in Accessible2.idl)
123 HRESULT STDMETHODCALLTYPE AccessibleRelation::get_target(
124 /* [in] */ long targetIndex,
125 /* [retval][out] */ IUnknown **target)
127 if (targetIndex >= 0 && targetIndex < m_targets.count()) {
128 QAccessibleInterface *iface = m_targets.at(targetIndex);
129 *target = QWindowsAccessibility::wrap(iface);
139 Client allocates and deallocates \a targets array
140 (see "Special Consideration when using Arrays", in Accessible2.idl)
142 HRESULT STDMETHODCALLTYPE AccessibleRelation::get_targets(
143 /* [in] */ long maxTargets, // Hmmm, ignore ???
144 /* [length_is][size_is][out] */ IUnknown **targets,
145 /* [retval][out] */ long *nTargets)
148 const int numTargets = qMin((int)maxTargets, m_targets.count());
149 for (int i = 0; i < numTargets; ++i) {
150 QAccessibleInterface *iface = m_targets.at(i);
151 IAccessible *iacc = QWindowsAccessibility::wrap(iface);
157 *nTargets = numTargets;
158 // \a targets array is allocated by client.
159 return numTargets > 0 ? S_OK : S_FALSE;
163 /**************************************************************\
167 **************************************************************/
168 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryInterface(REFIID id, LPVOID *iface)
172 QByteArray strIID = IIDToString(id);
173 if (!strIID.isEmpty()) {
174 QString ss; QDebug dbg(&ss); dbg << accessible;
175 accessibleDebug("QWindowsIA2Accessible::QI() - IID:%s, iface:%s ", strIID.constData(), qPrintable(ss));
177 if (id == IID_IUnknown) {
178 *iface = (IUnknown*)(IDispatch*)this;
179 } else if (id == IID_IDispatch) {
180 *iface = (IDispatch*)this;
181 } else if (id == IID_IAccessible) {
182 *iface = (IAccessible*)this;
183 } else if (id == IID_IOleWindow) {
184 *iface = (IOleWindow*)this;
185 } else if (id == IID_IServiceProvider) {
186 *iface = (IServiceProvider*)this;
187 } else if (id == IID_IAccessible2) {
188 *iface = (IAccessible2*)this;
189 } else if (id == IID_IAccessibleAction) {
190 if (accessible->actionInterface())
191 *iface = (IAccessibleAction*)this;
192 } else if (id == IID_IAccessibleComponent) {
193 *iface = (IAccessibleComponent*)this;
194 } else if (id == IID_IAccessibleEditableText) {
195 //if (accessible->editableTextInterface()) {
196 //*iface = (IAccessibleEditableText*)this;
198 } else if (id == IID_IAccessibleHyperlink) {
199 //*iface = (IAccessibleHyperlink*)this;
200 } else if (id == IID_IAccessibleHypertext) {
201 //*iface = (IAccessibleHypertext*)this;
202 } else if (id == IID_IAccessibleImage) {
203 //*iface = (IAccessibleImage*)this;
204 } else if (id == IID_IAccessibleRelation) {
205 *iface = (IAccessibleRelation*)this;
206 } else if (id == IID_IAccessibleTable) {
207 //*iface = (IAccessibleTable*)this; // not supported
208 } else if (id == IID_IAccessibleTable2) {
209 if (accessible->tableInterface())
210 *iface = (IAccessibleTable2*)this;
211 } else if (id == IID_IAccessibleTableCell) {
212 if (accessible->tableCellInterface())
213 *iface = (IAccessibleTableCell*)this;
214 } else if (id == IID_IAccessibleText) {
215 if (accessible->textInterface())
216 *iface = (IAccessibleText*)this;
217 } else if (id == IID_IAccessibleValue) {
218 if (accessible->valueInterface())
219 *iface = (IAccessibleValue*)this;
226 return E_NOINTERFACE;
229 ULONG STDMETHODCALLTYPE QWindowsIA2Accessible::AddRef()
234 ULONG STDMETHODCALLTYPE QWindowsIA2Accessible::Release()
245 /**************************************************************\
249 **************************************************************/
250 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRelations(long *nRelations)
252 accessibleDebugClientCalls(accessible);
255 if (!accessible->isValid())
258 return getRelationsHelper(0, 0, 0, nRelations);
261 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relation(long relationIndex, IAccessibleRelation **relation)
263 accessibleDebugClientCalls(accessible);
266 if (!accessible->isValid())
269 return getRelationsHelper(relation, relationIndex, 1);
274 Client allocates and deallocates array
275 (see "Special Consideration when using Arrays", in Accessible2.idl)
277 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relations(long maxRelations,
278 IAccessibleRelation **relations,
281 accessibleDebugClientCalls(accessible);
282 if (!accessible->isValid())
285 return getRelationsHelper(relations, 0, maxRelations, nRelations);
289 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::role(long *ia2role)
291 accessibleDebugClientCalls(accessible);
292 //### Change QAccessibleInterface::role() to return both MSAA and IA2 roles.
293 // When that is completed, we must patch the MSAA bridge not not return any
294 // IA2-specific roles from get_accRole().
295 if (!accessible->isValid())
298 *ia2role = accessible->role();
303 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollTo(enum IA2ScrollType /*scrollType*/)
310 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollToPoint(enum IA2CoordinateType /*coordinateType*/, long /*x*/, long /*y*/)
317 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_groupPosition(long *groupLevel,
318 long *similarItemsInGroup,
319 long *positionInGroup)
321 // ### Ignore for now. Not sure what this is used for.....
322 *groupLevel = 0; // Not applicable
323 *similarItemsInGroup = 0; // Not applicable
324 *positionInGroup = 0; // Not applicable
329 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_states(AccessibleStates *states)
331 accessibleDebugClientCalls(accessible);
332 if (!accessible->isValid())
336 QAccessible::State st = accessible->state();
337 AccessibleStates ia2states = 0;
339 ia2states |= IA2_STATE_ACTIVE;
341 ia2states |= IA2_STATE_DEFUNCT;
343 ia2states |= IA2_STATE_EDITABLE;
345 ia2states |= IA2_STATE_MULTI_LINE;
346 if (st.selectableText)
347 ia2states |= IA2_STATE_SELECTABLE_TEXT;
348 if (st.supportsAutoCompletion)
349 ia2states |= IA2_STATE_SUPPORTS_AUTOCOMPLETION;
356 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_extendedRole(BSTR *extendedRole)
360 return E_NOTIMPL; // mozilla does this
365 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedExtendedRole(BSTR *localizedExtendedRole)
368 *localizedExtendedRole = 0;
369 return E_NOTIMPL; // mozilla does this
374 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nExtendedStates(long *nExtendedStates)
376 // Who will ever intepret these values into something meaningful??
377 *nExtendedStates = 0;
378 return E_NOTIMPL; // mozilla does this
383 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_extendedStates(long /*maxExtendedStates*/,
384 BSTR **extendedStates,
385 long *nExtendedStates)
388 *nExtendedStates = 0;
389 return E_NOTIMPL; // mozilla does this
394 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedExtendedStates(long /*maxLocalizedExtendedStates*/,
395 BSTR **localizedExtendedStates,
396 long *nLocalizedExtendedStates)
398 *localizedExtendedStates = 0;
399 *nLocalizedExtendedStates = 0;
400 return E_NOTIMPL; // mozilla does this
405 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_uniqueID(long *outUniqueID)
407 accessibleDebugClientCalls(accessible);
408 if (!accessible->isValid())
410 // ### FIXME SERIOUSLY, NOT A STABLE SOLUTION IF NODES ARE DELETED ETC
411 // Return 0 if no object and no parent. This is really an error case.
412 uint uid = uniqueID();
413 accessibleDebug("uniqueID: %08x", uid);
415 *outUniqueID = (long)uid;
416 return uid ? S_OK : S_FALSE;
420 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_windowHandle(HWND *windowHandle)
422 accessibleDebugClientCalls(accessible);
423 if (!accessible->isValid())
425 return GetWindow(windowHandle);
429 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_indexInParent(long *indexInParent)
431 accessibleDebugClientCalls(accessible);
432 if (!accessible->isValid())
436 QAccessibleInterface *par = accessible->parent();
441 int indexOfChild = par->indexOfChild(accessible);
443 Q_ASSERT(indexOfChild >= 0);
444 *indexInParent = indexOfChild;
448 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locale(IA2Locale *locale)
450 accessibleDebugClientCalls(accessible);
451 if (!accessible->isValid())
455 res.country = QStringToBSTR(QLocale::countryToString(l.country()));
456 res.language = QStringToBSTR(QLocale::languageToString(l.language()));
462 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(BSTR *attributes)
464 accessibleDebugClientCalls(accessible);
465 if (!accessible->isValid())
467 *attributes = 0;//QStringToBSTR(QString());
471 /**************************************************************\
472 * IAccessibleAction *
473 **************************************************************/
474 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions)
476 accessibleDebugClientCalls(accessible);
477 if (!accessible->isValid())
481 if (QAccessibleActionInterface *actionIface = actionInterface())
482 *nActions = actionIface->actionNames().count();
486 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex)
488 accessibleDebugClientCalls(accessible);
489 if (!accessible->isValid())
491 if (QAccessibleActionInterface *actionIface = actionInterface()) {
492 const QStringList actionNames = actionIface->actionNames();
493 if (actionIndex < 0 || actionIndex >= actionNames.count())
495 const QString actionName = actionNames.at(actionIndex);
496 actionIface->doAction(actionName);
502 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionIndex, BSTR *description)
504 accessibleDebugClientCalls(accessible);
505 if (!accessible->isValid())
508 if (QAccessibleActionInterface *actionIface = actionInterface()) {
509 const QStringList actionNames = actionIface->actionNames();
510 if (actionIndex < 0 || actionIndex >= actionNames.count())
512 const QString actionName = actionNames.at(actionIndex);
513 *description = QStringToBSTR(actionIface->localizedActionDescription(actionName));
515 return *description ? S_OK : S_FALSE;
518 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_keyBinding(long actionIndex, long nMaxBindings, BSTR **keyBindings, long *nBindings)
520 accessibleDebugClientCalls(accessible);
521 if (!accessible->isValid())
523 Q_UNUSED(nMaxBindings);
524 BSTR *arrayOfBindingsToReturn = 0;
526 if (QAccessibleActionInterface *actionIface = actionInterface()) {
527 const QStringList actionNames = actionIface->actionNames();
528 if (actionIndex < 0 || actionIndex >= actionNames.count())
530 const QString actionName = actionNames.at(actionIndex);
531 const QStringList keyBindings = actionIface->keyBindingsForAction(actionName);
532 numBindings = keyBindings.count();
533 if (numBindings > 0) {
534 // The IDL documents that the client must free with CoTaskMemFree
535 arrayOfBindingsToReturn = (BSTR*)::CoTaskMemAlloc(sizeof(BSTR) * numBindings);
536 for (int i = 0; i < numBindings; ++i)
537 arrayOfBindingsToReturn[i] = QStringToBSTR(keyBindings.at(i));
540 *keyBindings = arrayOfBindingsToReturn;
541 *nBindings = numBindings;
543 return numBindings ? S_OK : S_FALSE;
546 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR *name)
548 accessibleDebugClientCalls(accessible);
549 if (!accessible->isValid())
552 if (QAccessibleActionInterface *actionIface = actionInterface()) {
553 const QStringList actionNames = actionIface->actionNames();
554 if (actionIndex < 0 || actionIndex >= actionNames.count())
556 const QString actionName = actionNames.at(actionIndex);
557 *name = QStringToBSTR(actionName);
559 return *name ? S_OK : S_FALSE;
562 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIndex, BSTR *localizedName)
564 accessibleDebugClientCalls(accessible);
565 if (!accessible->isValid())
568 if (QAccessibleActionInterface *actionIface = actionInterface()) {
569 const QStringList actionNames = actionIface->actionNames();
570 if (actionIndex < 0 || actionIndex >= actionNames.count())
573 const QString actionName = actionNames.at(actionIndex);
574 *localizedName = QStringToBSTR(actionIface->localizedActionName(actionName));
576 return *localizedName ? S_OK : S_FALSE;
579 /**************************************************************\
580 * IAccessibleComponent *
581 **************************************************************/
582 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locationInParent(long *x, long *y)
584 accessibleDebugClientCalls(accessible);
585 if (!accessible->isValid())
588 QPoint topLeft = accessible->rect().topLeft();
590 if (QAccessibleInterface *parentIface = accessible->parent())
591 topLeft -= parentIface->rect().topLeft();
598 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_foreground(IA2Color *foreground)
600 accessibleDebugClientCalls(accessible);
601 if (!accessible->isValid())
604 // IA2Color is a typedef for long
605 *foreground = (IA2Color)accessible->foregroundColor().rgb();
609 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_background(IA2Color *background)
611 accessibleDebugClientCalls(accessible);
612 if (!accessible->isValid())
615 // IA2Color is a typedef for long
616 *background = (IA2Color)accessible->backgroundColor().rgb();
620 /**************************************************************\
621 * IAccessibleTable2 *
622 **************************************************************/
623 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_cellAt( long row, long column, IUnknown **cell)
625 accessibleDebugClientCalls(accessible);
626 if (!accessible->isValid())
630 if (QAccessibleTableInterface *tableIface = tableInterface()) {
631 if (QAccessibleInterface *qtCell = tableIface->cellAt(row, column)) {
632 *cell = QWindowsAccessibility::wrap(qtCell);
635 accessibleDebug("found cell? %p", *cell);
636 return *cell ? S_OK : S_FALSE;
639 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caption( IUnknown **captionInterface)
641 accessibleDebugClientCalls(accessible);
642 if (!accessible->isValid())
645 *captionInterface = 0;
646 if (QAccessibleTableInterface *tableIface = tableInterface()) {
647 if (QAccessibleInterface *iface = tableIface->caption())
648 *captionInterface = QWindowsAccessibility::wrap(iface);
650 return *captionInterface ? S_OK : S_FALSE;
653 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnDescription( long column, BSTR *description)
655 accessibleDebugClientCalls(accessible);
656 if (!accessible->isValid())
660 if (QAccessibleTableInterface *tableIface = tableInterface()) {
661 const QString qtDesc = tableIface->columnDescription(column);
662 if (!qtDesc.isEmpty())
663 *description = QStringToBSTR(qtDesc);
665 return *description ? S_OK : S_FALSE;
668 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nColumns( long *columnCount)
670 accessibleDebugClientCalls(accessible);
671 if (!accessible->isValid())
674 if (QAccessibleTableInterface *tableIface = tableInterface()) {
675 *columnCount = tableIface->columnCount();
681 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRows(long *rowCount)
683 accessibleDebugClientCalls(accessible);
684 if (!accessible->isValid())
687 if (QAccessibleTableInterface *tableIface = tableInterface()) {
688 *rowCount = tableIface->rowCount();
694 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedCells(long *cellCount)
696 accessibleDebugClientCalls(accessible);
697 if (!accessible->isValid())
700 if (QAccessibleTableInterface *tableIface = tableInterface()) {
701 *cellCount = tableIface->selectedCellCount();
707 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedColumns(long *columnCount)
709 accessibleDebugClientCalls(accessible);
710 if (!accessible->isValid())
713 if (QAccessibleTableInterface *tableIface = tableInterface()) {
714 *columnCount = tableIface->selectedColumnCount();
720 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedRows(long *rowCount)
722 accessibleDebugClientCalls(accessible);
723 if (!accessible->isValid())
726 if (QAccessibleTableInterface *tableIface = tableInterface()) {
727 *rowCount = tableIface->selectedRowCount();
733 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowDescription(long row, BSTR *description)
735 accessibleDebugClientCalls(accessible);
736 if (!accessible->isValid())
740 if (QAccessibleTableInterface *tableIface = tableInterface()) {
741 const QString qtDesc = tableIface->columnDescription(row);
742 if (!qtDesc.isEmpty())
743 *description = QStringToBSTR(qtDesc);
745 return *description ? S_OK : S_FALSE;
748 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedCells(IUnknown ***cells, long *nSelectedCells)
750 accessibleDebugClientCalls(accessible);
752 Q_UNUSED(nSelectedCells);
753 if (!accessible->isValid())
756 QList<QAccessibleInterface*> selectedCells = tableInterface()->selectedCells();
757 return wrapListOfCells(selectedCells, cells, nSelectedCells);
760 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedColumns(long **selectedColumns, long *nColumns)
762 accessibleDebugClientCalls(accessible);
763 if (!accessible->isValid())
766 if (QAccessibleTableInterface *tableIface = tableInterface()) {
767 const QList<int> selectedIndices = tableIface->selectedColumns();
768 const int &count = selectedIndices.count();
769 long *selected = (count ? (long*)::CoTaskMemAlloc(sizeof(long) * count) : (long*)0);
770 for (int i = 0; i < count; ++i)
771 selected[i] = selectedIndices.at(i);
772 *selectedColumns = selected;
774 return count ? S_OK : S_FALSE;
780 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedRows(long **selectedRows, long *nRows)
782 accessibleDebugClientCalls(accessible);
783 if (!accessible->isValid())
786 if (QAccessibleTableInterface *tableIface = tableInterface()) {
787 const QList<int> selectedIndices = tableIface->selectedRows();
788 const int &count = selectedIndices.count();
789 long *selected = (count ? (long*)::CoTaskMemAlloc(sizeof(long) * count) : (long*)0);
790 for (int i = 0; i < count; ++i)
791 selected[i] = selectedIndices.at(i);
792 *selectedRows = selected;
794 return count ? S_OK : S_FALSE;
800 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_summary(IUnknown **summaryInterface)
802 accessibleDebugClientCalls(accessible);
803 if (!accessible->isValid())
806 *summaryInterface = 0;
807 if (QAccessibleTableInterface *tableIface = tableInterface()) {
808 if (QAccessibleInterface *iface = tableIface->summary())
809 *summaryInterface = QWindowsAccessibility::wrap(iface);
811 return *summaryInterface ? S_OK : S_FALSE;
814 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isColumnSelected(long column, boolean *isSelected)
816 accessibleDebugClientCalls(accessible);
817 if (!accessible->isValid())
820 if (QAccessibleTableInterface *tableIface = tableInterface()) {
821 *isSelected = tableIface->isColumnSelected(column);
827 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isRowSelected(long row, boolean *isSelected)
829 accessibleDebugClientCalls(accessible);
830 if (!accessible->isValid())
833 if (QAccessibleTableInterface *tableIface = tableInterface()) {
834 *isSelected = tableIface->isRowSelected(row);
840 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectRow(long row)
842 accessibleDebugClientCalls(accessible);
843 if (!accessible->isValid())
846 if (QAccessibleTableInterface *tableIface = tableInterface()) {
847 bool ok = tableIface->selectRow(row);
848 return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
853 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectColumn(long column)
855 accessibleDebugClientCalls(accessible);
856 if (!accessible->isValid())
859 if (QAccessibleTableInterface *tableIface = tableInterface()) {
860 bool ok = tableIface->selectColumn(column);
861 return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
866 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectRow(long row)
868 accessibleDebugClientCalls(accessible);
869 if (!accessible->isValid())
872 if (QAccessibleTableInterface *tableIface = tableInterface()) {
873 bool ok = tableIface->unselectRow(row);
874 return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
879 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectColumn(long column)
881 accessibleDebugClientCalls(accessible);
882 if (!accessible->isValid())
885 if (QAccessibleTableInterface *tableIface = tableInterface()) {
886 bool ok = tableIface->unselectColumn(column);
887 return ok ? S_OK : E_INVALIDARG; //### Not sure of the return value if it fails???
892 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_modelChange( IA2TableModelChange * /*modelChange*/)
894 accessibleDebugClientCalls(accessible);
895 if (!accessible->isValid())
900 /**************************************************************\
901 * IAccessibleTableCell *
902 \**************************************************************/
903 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnExtent(long *nColumnsSpanned)
905 accessibleDebugClientCalls(accessible);
906 if (!accessible->isValid())
909 *nColumnsSpanned = tableCellInterface()->columnExtent();
913 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnHeaderCells(IUnknown ***cellAccessibles,
914 long *nColumnHeaderCells)
916 accessibleDebugClientCalls(accessible);
917 if (!accessible->isValid())
919 const QList<QAccessibleInterface*> headerCells = tableCellInterface()->columnHeaderCells();
920 return wrapListOfCells(headerCells, cellAccessibles, nColumnHeaderCells);
923 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnIndex(long *columnIndex)
925 accessibleDebugClientCalls(accessible);
926 if (!accessible->isValid())
928 *columnIndex = tableCellInterface()->columnIndex();
932 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowExtent(long *nRowsSpanned)
934 accessibleDebugClientCalls(accessible);
935 if (!accessible->isValid())
937 *nRowsSpanned = tableCellInterface()->rowExtent();
941 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowHeaderCells(IUnknown ***cellAccessibles,
942 long *nRowHeaderCells)
944 accessibleDebugClientCalls(accessible);
945 if (!accessible->isValid())
947 const QList<QAccessibleInterface*> headerCells = tableCellInterface()->rowHeaderCells();
948 return wrapListOfCells(headerCells, cellAccessibles, nRowHeaderCells);
951 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowIndex(long *rowIndex)
953 accessibleDebugClientCalls(accessible);
954 if (!accessible->isValid())
956 *rowIndex = tableCellInterface()->rowIndex();
960 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isSelected( boolean *isSelected)
962 accessibleDebugClientCalls(accessible);
963 if (!accessible->isValid())
965 *isSelected = tableCellInterface()->isSelected();
969 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowColumnExtents(long *row, long *column,
970 long *rowExtents, long *columnExtents,
973 accessibleDebugClientCalls(accessible);
974 if (!accessible->isValid())
977 tableCellInterface()->rowColumnExtents((int*)row, (int*)column, (int*)rowExtents, (int*)columnExtents, (bool*)isSelected);
981 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_table(IUnknown **table)
983 accessibleDebugClientCalls(accessible);
984 if (!accessible->isValid())
987 QAccessibleInterface *tableIface = tableCellInterface()->table();
989 *table = QWindowsAccessibility::wrap(tableIface);
993 /**************************************************************\
995 \**************************************************************/
996 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::addSelection(long startOffset,
999 accessibleDebugClientCalls(accessible);
1000 if (QAccessibleTextInterface *text = textInterface()) {
1001 text->addSelection(startOffset, endOffset);
1007 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(long offset,
1010 BSTR *textAttributes)
1012 accessibleDebugClientCalls(accessible);
1013 if (QAccessibleTextInterface *text = textInterface()) {
1014 const QString attrs = text->attributes(offset, (int*)startOffset, (int*)endOffset);
1015 *textAttributes = QStringToBSTR(attrs);
1021 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caretOffset(long *offset)
1023 accessibleDebugClientCalls(accessible);
1024 if (QAccessibleTextInterface *text = textInterface()) {
1025 *offset = text->cursorPosition();
1031 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_characterExtents(long offset,
1032 enum IA2CoordinateType coordType,
1038 accessibleDebugClientCalls(accessible);
1039 if (QAccessibleTextInterface *text = textInterface()) {
1040 const QRect rect = text->characterRect(offset, (QAccessible2::CoordinateType)coordType);
1043 *width = rect.width();
1044 *height = rect.height();
1050 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelections(long *nSelections)
1052 accessibleDebugClientCalls(accessible);
1053 if (QAccessibleTextInterface *text = textInterface()) {
1054 *nSelections = text->selectionCount();
1060 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_offsetAtPoint(long x,
1062 enum IA2CoordinateType coordType,
1065 accessibleDebugClientCalls(accessible);
1066 if (QAccessibleTextInterface *text = textInterface()) {
1067 *offset = text->offsetAtPoint(QPoint(x,y), (QAccessible2::CoordinateType)coordType);
1068 return (*offset >=0 ? S_OK : S_FALSE);
1074 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selection(long selectionIndex,
1078 accessibleDebugClientCalls(accessible);
1079 if (QAccessibleTextInterface *text = textInterface()) {
1080 text->selection(selectionIndex, (int*)startOffset, (int*)endOffset);
1086 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_text(long startOffset,
1090 accessibleDebugClientCalls(accessible);
1091 if (QAccessibleTextInterface *textif = textInterface()) {
1092 const QString t = textif->text(startOffset, endOffset);
1094 *text = QStringToBSTR(t);
1097 return E_INVALIDARG;
1102 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textBeforeOffset(long offset,
1103 enum IA2TextBoundaryType boundaryType,
1108 accessibleDebugClientCalls(accessible);
1109 if (QAccessibleTextInterface *textIface = textInterface()) {
1110 const QString txt = textIface->textBeforeOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
1111 if (!txt.isEmpty()) {
1112 *text = QStringToBSTR(txt);
1120 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAfterOffset(
1122 enum IA2TextBoundaryType boundaryType,
1127 accessibleDebugClientCalls(accessible);
1128 if (QAccessibleTextInterface *textIface = textInterface()) {
1129 const QString txt = textIface->textAfterOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
1130 if (!txt.isEmpty()) {
1131 *text = QStringToBSTR(txt);
1139 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAtOffset(long offset,
1140 enum IA2TextBoundaryType boundaryType,
1145 accessibleDebugClientCalls(accessible);
1146 if (QAccessibleTextInterface *textIface = textInterface()) {
1147 const QString txt = textIface->textAtOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
1148 if (!txt.isEmpty()) {
1149 *text = QStringToBSTR(txt);
1157 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::removeSelection(long selectionIndex)
1159 accessibleDebugClientCalls(accessible);
1160 if (QAccessibleTextInterface *textIface = textInterface()) {
1161 textIface->removeSelection(selectionIndex);
1167 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCaretOffset(long offset)
1169 accessibleDebugClientCalls(accessible);
1170 if (QAccessibleTextInterface *textIface = textInterface()) {
1171 textIface->setCursorPosition(offset);
1177 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setSelection(long selectionIndex,
1181 accessibleDebugClientCalls(accessible);
1182 if (QAccessibleTextInterface *textIface = textInterface()) {
1183 textIface->setSelection(selectionIndex, startOffset, endOffset);
1189 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nCharacters(long *nCharacters)
1191 accessibleDebugClientCalls(accessible);
1192 if (QAccessibleTextInterface *textIface = textInterface()) {
1193 *nCharacters = textIface->characterCount();
1199 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringTo(long startIndex,
1201 enum IA2ScrollType scrollType)
1203 accessibleDebugClientCalls(accessible);
1204 if (QAccessibleTextInterface *textIface = textInterface()) {
1205 Q_UNUSED(scrollType); //###
1206 textIface->scrollToSubstring(startIndex, endIndex);
1212 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringToPoint(long startIndex,
1214 enum IA2CoordinateType coordinateType,
1218 Q_UNUSED(startIndex);
1220 Q_UNUSED(coordinateType);
1227 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_newText(IA2TextSegment *newText)
1233 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_oldText(IA2TextSegment *oldText)
1239 /**************************************************************\
1240 * IAccessibleValue *
1241 **************************************************************/
1242 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_currentValue(VARIANT *currentValue)
1244 accessibleDebugClientCalls(accessible);
1245 if (!accessible->isValid())
1247 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1248 const QVariant var = valueIface->currentValue();
1249 if (QVariantToVARIANT(var, *currentValue, QByteArray(), false))
1253 currentValue->vt = VT_EMPTY;
1257 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCurrentValue(VARIANT value)
1259 accessibleDebugClientCalls(accessible);
1260 if (!accessible->isValid())
1262 HRESULT hr = S_FALSE;
1263 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1264 hr = VariantChangeType(&value, &value, 0, VT_R8);
1265 if (SUCCEEDED(hr)) {
1266 // ### works only for numbers (not date, strings, etc)
1267 valueIface->setCurrentValue(QVariant(value.dblVal));
1273 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_maximumValue(VARIANT *maximumValue)
1275 accessibleDebugClientCalls(accessible);
1276 if (!accessible->isValid())
1278 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1279 const QVariant var = valueIface->maximumValue();
1280 if (QVariantToVARIANT(var, *maximumValue, QByteArray(), false))
1283 maximumValue->vt = VT_EMPTY;
1287 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_minimumValue(VARIANT *minimumValue)
1289 accessibleDebugClientCalls(accessible);
1290 if (!accessible->isValid())
1292 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1293 const QVariant var = valueIface->minimumValue();
1294 if (QVariantToVARIANT(var, *minimumValue, QByteArray(), false))
1297 minimumValue->vt = VT_EMPTY;
1302 /**************************************************************\
1303 * IServiceProvider *
1304 **************************************************************/
1307 Reimplemented from IServiceProvider
1309 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryService(REFGUID guidService, REFIID riid, void **iface)
1313 Q_UNUSED(guidService);
1315 accessibleDebug("QWindowsIA2Accessible::QS(): %s", IIDToString(riid).constData());
1316 if (riid == IID_IAccessible || riid == IID_IUnknown || riid == IID_IDispatch) {
1317 *iface = static_cast<IAccessible*>(this);
1318 } else if (/*guidService == IID_IAccessible && */riid == IID_IAccessible2) {
1319 *iface = static_cast<IAccessible2*>(this);
1320 } else if (riid == IID_IAccessibleApplication) {
1321 *iface = new AccessibleApplication;
1324 QueryInterface(riid, iface);
1331 return E_NOINTERFACE;
1338 \a maxRelations max number of relations to return in \a relations
1339 \a relations the array of relations matching
1340 \a startIndex Index to start to return from,
1341 it will return only that specific relation in \a relations
1343 If \a relations is null, \a startIndex and \a maxRelations are ignored, causing
1344 it to return the number of relations in \a nRelations
1346 HRESULT QWindowsIA2Accessible::getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations /* = 0*/)
1350 typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationEntry;
1351 QVector<RelationEntry> rels = accessible->relations();
1352 QMap<QAccessible::Relation, QAccessibleInterface *> relationMap;
1353 for (QVector<RelationEntry>::const_iterator it = rels.constBegin(); it != rels.constEnd(); ++it)
1355 RelationEntry e = *it;
1356 relationMap.insertMulti(e.second, e.first);
1359 QList<QAccessible::Relation> keys = relationMap.keys();
1360 const int numRelations = keys.count();
1362 for (int i = startIndex; i < qMin(startIndex + (int)maxRelations, numRelations); ++i) {
1363 QAccessible::Relation relation = keys.at(i);
1364 QList<QAccessibleInterface*> targets = relationMap.values(relation);
1365 AccessibleRelation *rel = new AccessibleRelation(targets, relation);
1371 *nRelations = numRelations;
1373 return numRelations > 0 ? S_OK : S_FALSE;
1381 helper to wrap a QList<QAccessibleInterface*> inside an array of IAccessible*
1382 The IAccessible* array is returned as a IUnknown*
1384 HRESULT QWindowsIA2Accessible::wrapListOfCells(const QList<QAccessibleInterface*> &inputCells, IUnknown ***outputAccessibles, long *nCellCount)
1386 const int count = inputCells.count();
1387 // Server allocates array
1388 IUnknown **outputCells = count ? (IUnknown**)::CoTaskMemAlloc(sizeof(IUnknown*) * count ) : (IUnknown**)0;
1389 for (int i = 0; i < count; ++i)
1390 outputCells[i] = QWindowsAccessibility::wrap(inputCells.at(i));
1392 *outputAccessibles = outputCells;
1393 *nCellCount = count;
1394 return count > 0 ? S_OK : S_FALSE;
1397 uint QWindowsIA2Accessible::uniqueID() const
1400 if (QObject *obj = accessible->object())
1404 QAccessibleInterface *acc = accessible;
1405 QVector<int> indexOfNodes;
1406 while (acc && !acc->object()) {
1407 QAccessibleInterface *par = acc->parent();
1408 indexOfNodes.append(par->indexOfChild(acc));
1409 if (acc != accessible)
1414 if (acc->object()) {
1415 uid = qHash(acc->object());
1416 for (int i = 0; i < indexOfNodes.count(); ++i)
1417 uid = qHash(uid + indexOfNodes.at(i));
1420 if (acc != accessible)
1428 #define IF_EQUAL_RETURN_IIDSTRING(id, iid) if (id == iid) return QByteArray(#iid)
1430 QByteArray QWindowsIA2Accessible::IIDToString(REFIID id)
1432 IF_EQUAL_RETURN_IIDSTRING(id, IID_IUnknown);
1433 IF_EQUAL_RETURN_IIDSTRING(id, IID_IDispatch);
1434 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible);
1435 IF_EQUAL_RETURN_IIDSTRING(id, IID_IOleWindow);
1436 IF_EQUAL_RETURN_IIDSTRING(id, IID_IServiceProvider);
1437 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible2);
1438 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleAction);
1439 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleApplication);
1440 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleComponent);
1441 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleEditableText);
1442 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHyperlink);
1443 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHypertext);
1444 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleImage);
1445 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleRelation);
1446 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable);
1447 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable2);
1448 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTableCell);
1449 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleText);
1450 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleValue);
1454 #if 0 // Can be useful for debugging, but normally we'd like to reduce the noise a bit...
1455 OLECHAR szGuid[39]={0};
1456 ::StringFromGUID2(id, szGuid, 39);
1457 strGuid.reserve(40);
1458 ::WideCharToMultiByte(CP_UTF8, 0, szGuid, 39, strGuid.data(), 39, NULL, NULL);
1467 #endif //QT_NO_ACCESSIBILITY