From c9c3f578831ed6876fc98d08067ff410406df9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20de=20la=20Rocha?= Date: Wed, 6 Jul 2022 03:22:53 +0200 Subject: [PATCH] Windows QPA: Implement Selection UIA pattern for QTabBar Adding Selection pattern for tab bars and SelectionItem pattern for tab items, which are required for accessibility compliance. Fixes: QTBUG-104740 Change-Id: I0e3b1cfbf4838d8bc8b5bc2e2d7c9d372ac8b99d Reviewed-by: Oliver Wolff (cherry picked from commit 083ff27518a735e39563d1bae9c40ffbc7c1d527) Reviewed-by: Qt Cherry-pick Bot --- .../uiautomation/qwindowsuiamainprovider.cpp | 6 ++-- .../qwindowsuiaselectionitemprovider.cpp | 21 ++++++------ .../qwindowsuiaselectionprovider.cpp | 33 ++++++++++++------- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 1bcd1ad4a99..2d5d91a7ea4 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -295,14 +295,16 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow break; case UIA_SelectionPatternId: // Lists of items. - if (accessible->role() == QAccessible::List) { + if (accessible->role() == QAccessible::List + || accessible->role() == QAccessible::PageTabList) { *pRetVal = new QWindowsUiaSelectionProvider(id()); } break; case UIA_SelectionItemPatternId: // Items within a list and radio buttons. if ((accessible->role() == QAccessible::RadioButton) - || (accessible->role() == QAccessible::ListItem)) { + || (accessible->role() == QAccessible::ListItem) + || (accessible->role() == QAccessible::PageTab)) { *pRetVal = new QWindowsUiaSelectionItemProvider(id()); } break; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp index 14ec29c75b6..7e829b24a70 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp @@ -40,8 +40,8 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::Select() if (!actionInterface) return UIA_E_ELEMENTNOTAVAILABLE; - if (accessible->role() == QAccessible::RadioButton) { - // For radio buttons we just invoke the selection action; others are automatically deselected. + if (accessible->role() == QAccessible::RadioButton || accessible->role() == QAccessible::PageTab) { + // For radio buttons/tabs we just invoke the selection action; others are automatically deselected. actionInterface->doAction(QAccessibleActionInterface::pressAction()); } else { // Toggle list item if not already selected. It must be done first to support all selection modes. @@ -77,8 +77,8 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::AddToSelection() if (!actionInterface) return UIA_E_ELEMENTNOTAVAILABLE; - if (accessible->role() == QAccessible::RadioButton) { - // For radio buttons we invoke the selection action. + if (accessible->role() == QAccessible::RadioButton || accessible->role() == QAccessible::PageTab) { + // For radio buttons and tabs we invoke the selection action. actionInterface->doAction(QAccessibleActionInterface::pressAction()); } else { // Toggle list item if not already selected. @@ -102,7 +102,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::RemoveFromSelection( if (!actionInterface) return UIA_E_ELEMENTNOTAVAILABLE; - if (accessible->role() != QAccessible::RadioButton) { + if (accessible->role() != QAccessible::RadioButton && accessible->role() != QAccessible::PageTab) { if (accessible->state().selected) { actionInterface->doAction(QAccessibleActionInterface::toggleAction()); } @@ -126,6 +126,8 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_IsSelected(BOOL if (accessible->role() == QAccessible::RadioButton) *pRetVal = accessible->state().checked; + else if (accessible->role() == QAccessible::PageTab) + *pRetVal = accessible->state().focused; else *pRetVal = accessible->state().selected; return S_OK; @@ -149,11 +151,10 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_SelectionContain return UIA_E_ELEMENTNOTAVAILABLE; // Radio buttons do not require a container. - if (accessible->role() == QAccessible::ListItem) { - if (QAccessibleInterface *parent = accessible->parent()) { - if (parent->role() == QAccessible::List) { - *pRetVal = QWindowsUiaMainProvider::providerForAccessible(parent); - } + if (QAccessibleInterface *parent = accessible->parent()) { + if ((accessible->role() == QAccessible::ListItem && parent->role() == QAccessible::List) + || (accessible->role() == QAccessible::PageTab && parent->role() == QAccessible::PageTabList)) { + *pRetVal = QWindowsUiaMainProvider::providerForAccessible(parent); } } return S_OK; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp index 1d110a637ed..45f3b205529 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp @@ -45,8 +45,14 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::GetSelection(SAFEARRAY * QList selectedList; for (int i = 0; i < accessible->childCount(); ++i) { if (QAccessibleInterface *child = accessible->child(i)) { - if (child->state().selected) { - selectedList.append(child); + if (accessible->role() == QAccessible::PageTabList) { + if (child->role() == QAccessible::PageTab && child->state().focused) { + selectedList.append(child); + } + } else { + if (child->state().selected) { + selectedList.append(child); + } } } } @@ -90,18 +96,23 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_IsSelectionRequired( if (!accessible) return UIA_E_ELEMENTNOTAVAILABLE; - // Initially returns false if none are selected. After the first selection, it may be required. - bool anySelected = false; - for (int i = 0; i < accessible->childCount(); ++i) { - if (QAccessibleInterface *child = accessible->child(i)) { - if (child->state().selected) { - anySelected = true; - break; + if (accessible->role() == QAccessible::PageTabList) { + *pRetVal = TRUE; + } else { + + // Initially returns false if none are selected. After the first selection, it may be required. + bool anySelected = false; + for (int i = 0; i < accessible->childCount(); ++i) { + if (QAccessibleInterface *child = accessible->child(i)) { + if (child->state().selected) { + anySelected = true; + break; + } } } - } - *pRetVal = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable; + *pRetVal = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable; + } return S_OK; }