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();
1032 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_characterExtents(long offset,
1033 enum IA2CoordinateType coordType,
1039 accessibleDebugClientCalls(accessible);
1040 if (QAccessibleTextInterface *text = textInterface()) {
1041 QRect rect = text->characterRect(offset);
1042 mapFromScreenPos(coordType, rect.topLeft(), x, y);
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 QPoint screenPos = mapToScreenPos(coordType, x, y);
1068 *offset = text->offsetAtPoint(screenPos);
1069 return (*offset >=0 ? S_OK : S_FALSE);
1075 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selection(long selectionIndex,
1079 accessibleDebugClientCalls(accessible);
1080 if (QAccessibleTextInterface *text = textInterface()) {
1081 text->selection(selectionIndex, (int*)startOffset, (int*)endOffset);
1087 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_text(long startOffset,
1091 accessibleDebugClientCalls(accessible);
1092 if (QAccessibleTextInterface *textif = textInterface()) {
1093 const QString t = textif->text(startOffset, endOffset);
1095 *text = QStringToBSTR(t);
1098 return E_INVALIDARG;
1103 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textBeforeOffset(long offset,
1104 enum IA2TextBoundaryType boundaryType,
1109 accessibleDebugClientCalls(accessible);
1110 if (QAccessibleTextInterface *textIface = textInterface()) {
1111 const QString txt = textIface->textBeforeOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
1112 if (!txt.isEmpty()) {
1113 *text = QStringToBSTR(txt);
1121 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAfterOffset(
1123 enum IA2TextBoundaryType boundaryType,
1128 accessibleDebugClientCalls(accessible);
1129 if (QAccessibleTextInterface *textIface = textInterface()) {
1130 const QString txt = textIface->textAfterOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
1131 if (!txt.isEmpty()) {
1132 *text = QStringToBSTR(txt);
1140 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAtOffset(long offset,
1141 enum IA2TextBoundaryType boundaryType,
1146 accessibleDebugClientCalls(accessible);
1147 if (QAccessibleTextInterface *textIface = textInterface()) {
1148 const QString txt = textIface->textAtOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
1149 if (!txt.isEmpty()) {
1150 *text = QStringToBSTR(txt);
1158 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::removeSelection(long selectionIndex)
1160 accessibleDebugClientCalls(accessible);
1161 if (QAccessibleTextInterface *textIface = textInterface()) {
1162 textIface->removeSelection(selectionIndex);
1168 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCaretOffset(long offset)
1170 accessibleDebugClientCalls(accessible);
1171 if (QAccessibleTextInterface *textIface = textInterface()) {
1172 textIface->setCursorPosition(offset);
1178 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setSelection(long selectionIndex,
1182 accessibleDebugClientCalls(accessible);
1183 if (QAccessibleTextInterface *textIface = textInterface()) {
1184 textIface->setSelection(selectionIndex, startOffset, endOffset);
1190 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nCharacters(long *nCharacters)
1192 accessibleDebugClientCalls(accessible);
1193 if (QAccessibleTextInterface *textIface = textInterface()) {
1194 *nCharacters = textIface->characterCount();
1200 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringTo(long startIndex,
1202 enum IA2ScrollType scrollType)
1204 accessibleDebugClientCalls(accessible);
1205 if (QAccessibleTextInterface *textIface = textInterface()) {
1206 Q_UNUSED(scrollType); //###
1207 textIface->scrollToSubstring(startIndex, endIndex);
1213 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringToPoint(long startIndex,
1215 enum IA2CoordinateType coordinateType,
1219 Q_UNUSED(startIndex);
1221 Q_UNUSED(coordinateType);
1228 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_newText(IA2TextSegment *newText)
1234 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_oldText(IA2TextSegment *oldText)
1240 /**************************************************************\
1241 * IAccessibleValue *
1242 **************************************************************/
1243 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_currentValue(VARIANT *currentValue)
1245 accessibleDebugClientCalls(accessible);
1246 if (!accessible->isValid())
1248 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1249 const QVariant var = valueIface->currentValue();
1250 if (QVariantToVARIANT(var, *currentValue, QByteArray(), false))
1254 currentValue->vt = VT_EMPTY;
1258 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCurrentValue(VARIANT value)
1260 accessibleDebugClientCalls(accessible);
1261 if (!accessible->isValid())
1263 HRESULT hr = S_FALSE;
1264 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1265 hr = VariantChangeType(&value, &value, 0, VT_R8);
1266 if (SUCCEEDED(hr)) {
1267 // ### works only for numbers (not date, strings, etc)
1268 valueIface->setCurrentValue(QVariant(value.dblVal));
1274 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_maximumValue(VARIANT *maximumValue)
1276 accessibleDebugClientCalls(accessible);
1277 if (!accessible->isValid())
1279 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1280 const QVariant var = valueIface->maximumValue();
1281 if (QVariantToVARIANT(var, *maximumValue, QByteArray(), false))
1284 maximumValue->vt = VT_EMPTY;
1288 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_minimumValue(VARIANT *minimumValue)
1290 accessibleDebugClientCalls(accessible);
1291 if (!accessible->isValid())
1293 if (QAccessibleValueInterface *valueIface = valueInterface()) {
1294 const QVariant var = valueIface->minimumValue();
1295 if (QVariantToVARIANT(var, *minimumValue, QByteArray(), false))
1298 minimumValue->vt = VT_EMPTY;
1303 /**************************************************************\
1304 * IServiceProvider *
1305 **************************************************************/
1308 Reimplemented from IServiceProvider
1310 HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryService(REFGUID guidService, REFIID riid, void **iface)
1314 Q_UNUSED(guidService);
1316 accessibleDebug("QWindowsIA2Accessible::QS(): %s", IIDToString(riid).constData());
1317 if (riid == IID_IAccessible || riid == IID_IUnknown || riid == IID_IDispatch) {
1318 *iface = static_cast<IAccessible*>(this);
1319 } else if (/*guidService == IID_IAccessible && */riid == IID_IAccessible2) {
1320 *iface = static_cast<IAccessible2*>(this);
1321 } else if (riid == IID_IAccessibleApplication) {
1322 *iface = new AccessibleApplication;
1325 QueryInterface(riid, iface);
1332 return E_NOINTERFACE;
1339 \a maxRelations max number of relations to return in \a relations
1340 \a relations the array of relations matching
1341 \a startIndex Index to start to return from,
1342 it will return only that specific relation in \a relations
1344 If \a relations is null, \a startIndex and \a maxRelations are ignored, causing
1345 it to return the number of relations in \a nRelations
1347 HRESULT QWindowsIA2Accessible::getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations /* = 0*/)
1351 typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationEntry;
1352 QVector<RelationEntry> rels = accessible->relations();
1353 QMap<QAccessible::Relation, QAccessibleInterface *> relationMap;
1354 for (QVector<RelationEntry>::const_iterator it = rels.constBegin(); it != rels.constEnd(); ++it)
1356 RelationEntry e = *it;
1357 relationMap.insertMulti(e.second, e.first);
1360 QList<QAccessible::Relation> keys = relationMap.keys();
1361 const int numRelations = keys.count();
1363 for (int i = startIndex; i < qMin(startIndex + (int)maxRelations, numRelations); ++i) {
1364 QAccessible::Relation relation = keys.at(i);
1365 QList<QAccessibleInterface*> targets = relationMap.values(relation);
1366 AccessibleRelation *rel = new AccessibleRelation(targets, relation);
1372 *nRelations = numRelations;
1374 return numRelations > 0 ? S_OK : S_FALSE;
1382 helper to wrap a QList<QAccessibleInterface*> inside an array of IAccessible*
1383 The IAccessible* array is returned as a IUnknown*
1385 HRESULT QWindowsIA2Accessible::wrapListOfCells(const QList<QAccessibleInterface*> &inputCells, IUnknown ***outputAccessibles, long *nCellCount)
1387 const int count = inputCells.count();
1388 // Server allocates array
1389 IUnknown **outputCells = count ? (IUnknown**)::CoTaskMemAlloc(sizeof(IUnknown*) * count ) : (IUnknown**)0;
1390 for (int i = 0; i < count; ++i)
1391 outputCells[i] = QWindowsAccessibility::wrap(inputCells.at(i));
1393 *outputAccessibles = outputCells;
1394 *nCellCount = count;
1395 return count > 0 ? S_OK : S_FALSE;
1398 uint QWindowsIA2Accessible::uniqueID() const
1401 if (QObject *obj = accessible->object())
1405 QAccessibleInterface *acc = accessible;
1406 QVector<int> indexOfNodes;
1407 while (acc && !acc->object()) {
1408 QAccessibleInterface *par = acc->parent();
1409 indexOfNodes.append(par->indexOfChild(acc));
1410 if (acc != accessible)
1415 if (acc->object()) {
1416 uid = qHash(acc->object());
1417 for (int i = 0; i < indexOfNodes.count(); ++i)
1418 uid = qHash(uid + indexOfNodes.at(i));
1421 if (acc != accessible)
1429 #define IF_EQUAL_RETURN_IIDSTRING(id, iid) if (id == iid) return QByteArray(#iid)
1431 QByteArray QWindowsIA2Accessible::IIDToString(REFIID id)
1433 IF_EQUAL_RETURN_IIDSTRING(id, IID_IUnknown);
1434 IF_EQUAL_RETURN_IIDSTRING(id, IID_IDispatch);
1435 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible);
1436 IF_EQUAL_RETURN_IIDSTRING(id, IID_IOleWindow);
1437 IF_EQUAL_RETURN_IIDSTRING(id, IID_IServiceProvider);
1438 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible2);
1439 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleAction);
1440 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleApplication);
1441 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleComponent);
1442 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleEditableText);
1443 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHyperlink);
1444 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHypertext);
1445 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleImage);
1446 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleRelation);
1447 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable);
1448 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable2);
1449 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTableCell);
1450 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleText);
1451 IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleValue);
1455 #if 0 // Can be useful for debugging, but normally we'd like to reduce the noise a bit...
1456 OLECHAR szGuid[39]={0};
1457 ::StringFromGUID2(id, szGuid, 39);
1458 strGuid.reserve(40);
1459 ::WideCharToMultiByte(CP_UTF8, 0, szGuid, 39, strGuid.data(), 39, NULL, NULL);
1468 #endif //QT_NO_ACCESSIBILITY