From 0cf6297c15be45d852be98c862bd0211e6de1aa2 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Fri, 8 Sep 2017 18:00:05 +0200 Subject: Add support for Windows UI Automation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the Qt Accessibility Windows back end, formerly based on legacy MSAA, with a new implementation based on UI Automation. Fixes issues with accessibility tools like screen readers and magnifiers, and with the automatic showing and hiding of the virtual keyboard in touchscreen-based Windows computers. [ChangeLog][Windows] The Windows Accessibility back end, formerly based on Microsoft Active Accessibility, was replaced with a new implementation based on Microsoft UI Automation. Task-number: QTPM-487 Task-number: QTBUG-53024 Task-number: QTBUG-43190 Task-number: QTBUG-61926 Task-number: QTBUG-38499 Task-number: QTBUG-38337 Task-number: QTBUG-38501 Task-number: QTBUG-38502 Task-number: QTBUG-38504 Task-number: QTBUG-38505 Task-number: QTBUG-38507 Change-Id: I20b4f8f5e938fef791c6e9c577fcd919140999bd Reviewed-by: Jan Arve Sæther --- .../uiautomation/qwindowsuiaaccessibility.cpp | 140 +++++ .../uiautomation/qwindowsuiaaccessibility.h | 65 +++ .../uiautomation/qwindowsuiabaseprovider.cpp | 81 +++ .../windows/uiautomation/qwindowsuiabaseprovider.h | 78 +++ .../uiautomation/qwindowsuiagriditemprovider.cpp | 176 ++++++ .../uiautomation/qwindowsuiagriditemprovider.h | 71 +++ .../uiautomation/qwindowsuiagridprovider.cpp | 136 +++++ .../windows/uiautomation/qwindowsuiagridprovider.h | 69 +++ .../uiautomation/qwindowsuiainvokeprovider.cpp | 84 +++ .../uiautomation/qwindowsuiainvokeprovider.h | 67 +++ .../uiautomation/qwindowsuiamainprovider.cpp | 638 +++++++++++++++++++++ .../windows/uiautomation/qwindowsuiamainprovider.h | 105 ++++ .../uiautomation/qwindowsuiaprovidercache.cpp | 106 ++++ .../uiautomation/qwindowsuiaprovidercache.h | 77 +++ .../uiautomation/qwindowsuiarangevalueprovider.cpp | 190 ++++++ .../uiautomation/qwindowsuiarangevalueprovider.h | 73 +++ .../qwindowsuiaselectionitemprovider.cpp | 201 +++++++ .../qwindowsuiaselectionitemprovider.h | 71 +++ .../uiautomation/qwindowsuiaselectionprovider.cpp | 147 +++++ .../uiautomation/qwindowsuiaselectionprovider.h | 69 +++ .../uiautomation/qwindowsuiatableitemprovider.cpp | 129 +++++ .../uiautomation/qwindowsuiatableitemprovider.h | 68 +++ .../uiautomation/qwindowsuiatableprovider.cpp | 154 +++++ .../uiautomation/qwindowsuiatableprovider.h | 69 +++ .../uiautomation/qwindowsuiatextprovider.cpp | 261 +++++++++ .../windows/uiautomation/qwindowsuiatextprovider.h | 80 +++ .../uiautomation/qwindowsuiatextrangeprovider.cpp | 554 ++++++++++++++++++ .../uiautomation/qwindowsuiatextrangeprovider.h | 88 +++ .../uiautomation/qwindowsuiatoggleprovider.cpp | 105 ++++ .../uiautomation/qwindowsuiatoggleprovider.h | 68 +++ .../windows/uiautomation/qwindowsuiautils.cpp | 221 +++++++ .../windows/uiautomation/qwindowsuiautils.h | 89 +++ .../uiautomation/qwindowsuiavalueprovider.cpp | 132 +++++ .../uiautomation/qwindowsuiavalueprovider.h | 70 +++ .../windows/uiautomation/uiautomation.pri | 43 ++ 35 files changed, 4775 insertions(+) create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp create mode 100644 src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h create mode 100644 src/plugins/platforms/windows/uiautomation/uiautomation.pri (limited to 'src/plugins/platforms/windows/uiautomation') diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp new file mode 100644 index 0000000000..907883bf5b --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiaaccessibility.h" +#include "qwindowsuiamainprovider.h" +#include "qwindowsuiautils.h" + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaAccessibility::QWindowsUiaAccessibility() +{ +} + +QWindowsUiaAccessibility::~QWindowsUiaAccessibility() +{ +} + +// Handles UI Automation window messages. +bool QWindowsUiaAccessibility::handleWmGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult) +{ + if (lParam == LPARAM(UiaRootObjectId)) { + + // Start handling accessibility internally + QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true); + + // Ignoring all requests while starting up / shutting down + if (QCoreApplication::startingUp() || QCoreApplication::closingDown()) + return false; + + if (QWindow *window = QWindowsContext::instance()->findWindow(hwnd)) { + if (QAccessibleInterface *accessible = window->accessibleRoot()) { + QWindowsUiaMainProvider *provider = QWindowsUiaMainProvider::providerForAccessible(accessible); + *lResult = QWindowsUiaWrapper::instance()->returnRawElementProvider(hwnd, wParam, lParam, provider); + return true; + } + } + } + return false; +} + +// Handles accessibility update notifications. +void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) +{ + if (!event) + return; + + QAccessibleInterface *accessible = event->accessibleInterface(); + if (!isActive() || !accessible || !accessible->isValid()) + return; + + // Ensures QWindowsUiaWrapper is properly initialized. + if (!QWindowsUiaWrapper::instance()->ready()) + return; + + // No need to do anything when nobody is listening. + if (!QWindowsUiaWrapper::instance()->clientsAreListening()) + return; + + switch (event->type()) { + + case QAccessible::Focus: + QWindowsUiaMainProvider::notifyFocusChange(event); + break; + + case QAccessible::StateChanged: + QWindowsUiaMainProvider::notifyStateChange(static_cast(event)); + break; + + case QAccessible::ValueChanged: + QWindowsUiaMainProvider::notifyValueChange(static_cast(event)); + break; + + case QAccessible::TextAttributeChanged: + case QAccessible::TextColumnChanged: + case QAccessible::TextInserted: + case QAccessible::TextRemoved: + case QAccessible::TextUpdated: + case QAccessible::TextSelectionChanged: + case QAccessible::TextCaretMoved: + QWindowsUiaMainProvider::notifyTextChange(event); + break; + + default: + break; + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h new file mode 100644 index 0000000000..bbb81d596b --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAACCESSIBILITY_H +#define QWINDOWSUIAACCESSIBILITY_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowscontext.h" +#include + +QT_BEGIN_NAMESPACE + +// Windows plataform accessibility implemented over UI Automation. +class QWindowsUiaAccessibility : public QPlatformAccessibility +{ +public: + explicit QWindowsUiaAccessibility(); + virtual ~QWindowsUiaAccessibility(); + static bool handleWmGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult); + void notifyAccessibilityUpdate(QAccessibleEvent *event) override; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIAACCESSIBILITY_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp new file mode 100644 index 0000000000..1e1fc49c0f --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaBaseProvider::QWindowsUiaBaseProvider(QAccessible::Id id) : + m_id(id) +{ +} + +QWindowsUiaBaseProvider::~QWindowsUiaBaseProvider() +{ +} + +QAccessibleInterface *QWindowsUiaBaseProvider::accessibleInterface() const +{ + QAccessibleInterface *accessible = QAccessible::accessibleInterface(m_id); + if (accessible && accessible->isValid()) + return accessible; + return nullptr; +} + +QAccessible::Id QWindowsUiaBaseProvider::id() const +{ + return m_id; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h new file mode 100644 index 0000000000..3ae403e8c5 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIABASEPROVIDER_H +#define QWINDOWSUIABASEPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QAccessibleInterface; +class QDebug; + +// Base class for UI Automation providers. +class QWindowsUiaBaseProvider : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(QWindowsUiaBaseProvider) +public: + explicit QWindowsUiaBaseProvider(QAccessible::Id id); + virtual ~QWindowsUiaBaseProvider(); + + QAccessibleInterface *accessibleInterface() const; + QAccessible::Id id() const; + +private: + QAccessible::Id m_id; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIABASEPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp new file mode 100644 index 0000000000..e0502c00f3 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiagriditemprovider.h" +#include "qwindowsuiamainprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaGridItemProvider::QWindowsUiaGridItemProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaGridItemProvider::~QWindowsUiaGridItemProvider() +{ +} + +// Returns the row index of the item. +HRESULT STDMETHODCALLTYPE QWindowsUiaGridItemProvider::get_Row(int *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = 0; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface(); + if (!tableCellInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = tableCellInterface->rowIndex(); + return S_OK; +} + +// Returns the column index of the item. +HRESULT STDMETHODCALLTYPE QWindowsUiaGridItemProvider::get_Column(int *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = 0; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface(); + if (!tableCellInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = tableCellInterface->columnIndex(); + return S_OK; +} + +// Returns the number of rows occupied by the item. +HRESULT STDMETHODCALLTYPE QWindowsUiaGridItemProvider::get_RowSpan(int *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = 0; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface(); + if (!tableCellInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = tableCellInterface->rowExtent(); + return S_OK; +} + +// Returns the number of columns occupied by the item. +HRESULT STDMETHODCALLTYPE QWindowsUiaGridItemProvider::get_ColumnSpan(int *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = 0; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface(); + if (!tableCellInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = tableCellInterface->columnExtent(); + return S_OK; +} + +// Returns the provider for the cointaining table/tree. +HRESULT STDMETHODCALLTYPE QWindowsUiaGridItemProvider::get_ContainingGrid(IRawElementProviderSimple **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface(); + if (!tableCellInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (QAccessibleInterface *table = tableCellInterface->table()) { + *pRetVal = QWindowsUiaMainProvider::providerForAccessible(table); + } + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h new file mode 100644 index 0000000000..a93b50ef97 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAGRIDITEMPROVIDER_H +#define QWINDOWSUIAGRIDITEMPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Grid Item control pattern provider. Used by items within a table/tree. +class QWindowsUiaGridItemProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaGridItemProvider) +public: + explicit QWindowsUiaGridItemProvider(QAccessible::Id id); + virtual ~QWindowsUiaGridItemProvider(); + + // IGridItemProvider + HRESULT STDMETHODCALLTYPE get_Row(int *pRetVal); + HRESULT STDMETHODCALLTYPE get_Column(int *pRetVal); + HRESULT STDMETHODCALLTYPE get_RowSpan(int *pRetVal); + HRESULT STDMETHODCALLTYPE get_ColumnSpan(int *pRetVal); + HRESULT STDMETHODCALLTYPE get_ContainingGrid(IRawElementProviderSimple **pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIAGRIDITEMPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp new file mode 100644 index 0000000000..65c2df703b --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiagridprovider.h" +#include "qwindowsuiamainprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaGridProvider::QWindowsUiaGridProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaGridProvider::~QWindowsUiaGridProvider() +{ +} + +// Returns the provider for an item within a table/tree. +HRESULT STDMETHODCALLTYPE QWindowsUiaGridProvider::GetItem(int row, int column, IRawElementProviderSimple **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableInterface *tableInterface = accessible->tableInterface(); + if (!tableInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + if ((row >= 0) && (row < tableInterface->rowCount()) && (column >= 0) && (column < tableInterface->columnCount())) { + if (QAccessibleInterface *cell = tableInterface->cellAt(row, column)) { + *pRetVal = QWindowsUiaMainProvider::providerForAccessible(cell); + } + } + return S_OK; +} + +// Returns the number of rows. +HRESULT STDMETHODCALLTYPE QWindowsUiaGridProvider::get_RowCount(int *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = 0; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableInterface *tableInterface = accessible->tableInterface(); + if (!tableInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = tableInterface->rowCount(); + return S_OK; +} + +// Returns the number of columns. +HRESULT STDMETHODCALLTYPE QWindowsUiaGridProvider::get_ColumnCount(int *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = 0; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableInterface *tableInterface = accessible->tableInterface(); + if (!tableInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = tableInterface->columnCount(); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h new file mode 100644 index 0000000000..15521f98b3 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAGRIDPROVIDER_H +#define QWINDOWSUIAGRIDPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Grid control pattern provider. Used by tables/trees. +class QWindowsUiaGridProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaGridProvider) +public: + explicit QWindowsUiaGridProvider(QAccessible::Id id); + virtual ~QWindowsUiaGridProvider(); + + // IGridProvider + HRESULT STDMETHODCALLTYPE GetItem(int row, int column, IRawElementProviderSimple **pRetVal); + HRESULT STDMETHODCALLTYPE get_RowCount(int *pRetVal); + HRESULT STDMETHODCALLTYPE get_ColumnCount(int *pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIAGRIDPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp new file mode 100644 index 0000000000..2af883c4f6 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiainvokeprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaInvokeProvider::QWindowsUiaInvokeProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaInvokeProvider::~QWindowsUiaInvokeProvider() +{ +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaInvokeProvider::Invoke() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + actionInterface->doAction(QAccessibleActionInterface::pressAction()); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h new file mode 100644 index 0000000000..2b8a646983 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAINVOKEPROVIDER_H +#define QWINDOWSUIAINVOKEPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Invoke control pattern provider. +class QWindowsUiaInvokeProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaInvokeProvider) +public: + explicit QWindowsUiaInvokeProvider(QAccessible::Id id); + virtual ~QWindowsUiaInvokeProvider(); + + // IInvokeProvider + HRESULT STDMETHODCALLTYPE Invoke(); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIAINVOKEPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp new file mode 100644 index 0000000000..46f73f81a0 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -0,0 +1,638 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiamainprovider.h" +#include "qwindowsuiavalueprovider.h" +#include "qwindowsuiarangevalueprovider.h" +#include "qwindowsuiatextprovider.h" +#include "qwindowsuiatoggleprovider.h" +#include "qwindowsuiainvokeprovider.h" +#include "qwindowsuiaselectionprovider.h" +#include "qwindowsuiaselectionitemprovider.h" +#include "qwindowsuiatableprovider.h" +#include "qwindowsuiatableitemprovider.h" +#include "qwindowsuiagridprovider.h" +#include "qwindowsuiagriditemprovider.h" +#include "qwindowscombase.h" +#include "qwindowscontext.h" +#include "qwindowsuiautils.h" +#include "qwindowsuiaprovidercache.h" + +#include +#include +#include +#include + +#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU) +#include +#endif + +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +// Returns a cached instance of the provider for a specific acessible interface. +QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessibleInterface *accessible) +{ + if (!accessible) + return nullptr; + + QAccessible::Id id = QAccessible::uniqueId(accessible); + QWindowsUiaProviderCache *providerCache = QWindowsUiaProviderCache::instance(); + QWindowsUiaMainProvider *provider = qobject_cast(providerCache->providerForId(id)); + + if (provider) { + provider->AddRef(); + } else { + provider = new QWindowsUiaMainProvider(accessible); + providerCache->insert(id, provider); + } + return provider; +} + +QWindowsUiaMainProvider::QWindowsUiaMainProvider(QAccessibleInterface *a, int initialRefCount) + : QWindowsUiaBaseProvider(QAccessible::uniqueId(a)), + m_ref(initialRefCount) +{ +} + +QWindowsUiaMainProvider::~QWindowsUiaMainProvider() +{ +} + +void QWindowsUiaMainProvider::notifyFocusChange(QAccessibleEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_AutomationFocusChangedEventId); + } + } +} + +void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + if (event->changedStates().checked || event->changedStates().checkStateMixed) { + // Notifies states changes in checkboxes. + if (accessible->role() == QAccessible::CheckBox) { + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + VARIANT oldVal, newVal; + clearVariant(&oldVal); + int toggleState = ToggleState_Off; + if (accessible->state().checked) + toggleState = accessible->state().checkStateMixed ? ToggleState_Indeterminate : ToggleState_On; + setVariantI4(toggleState, &newVal); + QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ToggleToggleStatePropertyId, oldVal, newVal); + } + } + } + if (event->changedStates().active) { + if (accessible->role() == QAccessible::Window) { + // Notifies window opened/closed. + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + if (accessible->state().active) { + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Window_WindowOpenedEventId); + } else { + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Window_WindowClosedEventId); + } + } + } + } + } +} + +void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { + // Notifies changes in values of controls supporting the value interface. + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + VARIANT oldVal, newVal; + clearVariant(&oldVal); + setVariantDouble(valueInterface->currentValue().toDouble(), &newVal); + QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_RangeValueValuePropertyId, oldVal, newVal); + } + } + } +} + +// Notifies changes in text content and selection state of text controls. +void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + if (accessible->textInterface()) { + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + if (event->type() == QAccessible::TextSelectionChanged) { + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId); + } else if (event->type() == QAccessible::TextCaretMoved) { + if (!accessible->state().readOnly) { + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId); + } + } else { + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextChangedEventId); + } + } + } + } +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface) +{ + if (!iface) + return E_INVALIDARG; + *iface = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + + const bool result = qWindowsComQueryUnknownInterfaceMulti(this, iid, iface) + || qWindowsComQueryInterface(this, iid, iface) + || qWindowsComQueryInterface(this, iid, iface) + || (accessible && hwndForAccessible(accessible) && qWindowsComQueryInterface(this, iid, iface)); + return result ? S_OK : E_NOINTERFACE; +} + +ULONG QWindowsUiaMainProvider::AddRef() +{ + return ++m_ref; +} + +ULONG STDMETHODCALLTYPE QWindowsUiaMainProvider::Release() +{ + if (!--m_ref) { + delete this; + return 0; + } + return m_ref; +} + +HRESULT QWindowsUiaMainProvider::get_ProviderOptions(ProviderOptions *pRetVal) +{ + if (!pRetVal) + return E_INVALIDARG; + // We are STA, (OleInitialize()). + *pRetVal = static_cast(ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading); + return S_OK; +} + +// Return providers for specific control patterns +HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknown **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idPattern; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + switch (idPattern) { + case UIA_TextPatternId: + case UIA_TextPattern2Id: + // All text controls. + if (accessible->textInterface()) { + *pRetVal = new QWindowsUiaTextProvider(id()); + } + break; + case UIA_ValuePatternId: + // All accessible controls return text(QAccessible::Value) (which may be empty). + *pRetVal = new QWindowsUiaValueProvider(id()); + break; + case UIA_RangeValuePatternId: + // Controls providing a numeric value within a range (e.g., sliders, scroll bars, dials). + if (accessible->valueInterface()) { + *pRetVal = new QWindowsUiaRangeValueProvider(id()); + } + break; + case UIA_TogglePatternId: + // Checkbox controls. + if (accessible->role() == QAccessible::CheckBox) { + *pRetVal = new QWindowsUiaToggleProvider(id()); + } + break; + case UIA_SelectionPatternId: + // Lists of items. + if (accessible->role() == QAccessible::List) { + *pRetVal = new QWindowsUiaSelectionProvider(id()); + } + break; + case UIA_SelectionItemPatternId: + // Items within a list and radio buttons. + if ((accessible->role() == QAccessible::RadioButton) + || (accessible->role() == QAccessible::ListItem)) { + *pRetVal = new QWindowsUiaSelectionItemProvider(id()); + } + break; + case UIA_TablePatternId: + // Table/tree. + if (accessible->tableInterface() + && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) { + *pRetVal = new QWindowsUiaTableProvider(id()); + } + break; + case UIA_TableItemPatternId: + // Item within a table/tree. + if (accessible->tableCellInterface() + && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) { + *pRetVal = new QWindowsUiaTableItemProvider(id()); + } + break; + case UIA_GridPatternId: + // Table/tree. + if (accessible->tableInterface() + && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) { + *pRetVal = new QWindowsUiaGridProvider(id()); + } + break; + case UIA_GridItemPatternId: + // Item within a table/tree. + if (accessible->tableCellInterface() + && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) { + *pRetVal = new QWindowsUiaGridItemProvider(id()); + } + break; + case UIA_InvokePatternId: + // Things that have an invokable action (e.g., simple buttons). + if (accessible->actionInterface()) { + *pRetVal = new QWindowsUiaInvokeProvider(id()); + } + break; + default: + break; + } + + return S_OK; +} + +HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idProp; + + if (!pRetVal) + return E_INVALIDARG; + clearVariant(pRetVal); + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + bool clientTopLevel = (accessible->role() == QAccessible::Client) + && accessible->parent() && (accessible->parent()->role() == QAccessible::Application); + + switch (idProp) { + case UIA_ProcessIdPropertyId: + // PID + setVariantI4(int(GetCurrentProcessId()), pRetVal); + break; + case UIA_AccessKeyPropertyId: + // Accelerator key. + setVariantString(accessible->text(QAccessible::Accelerator), pRetVal); + break; + case UIA_AutomationIdPropertyId: + // Automation ID, which can be used by tools to select a specific control in the UI. + setVariantString(automationIdForAccessible(accessible), pRetVal); + break; + case UIA_ClassNamePropertyId: + // Class name. + if (QObject *o = accessible->object()) { + QString className = QLatin1String(o->metaObject()->className()); + setVariantString(className, pRetVal); + } + break; + case UIA_FrameworkIdPropertyId: + setVariantString(QStringLiteral("Qt"), pRetVal); + break; + case UIA_ControlTypePropertyId: + if (clientTopLevel) { + // Reports a top-level widget as a window, instead of "custom". + setVariantI4(UIA_WindowControlTypeId, pRetVal); + } else { + // Control type converted from role. + setVariantI4(roleToControlTypeId(accessible->role()), pRetVal); + } + break; + case UIA_HelpTextPropertyId: + setVariantString(accessible->text(QAccessible::Help), pRetVal); + break; + case UIA_HasKeyboardFocusPropertyId: + setVariantBool(accessible->state().focused, pRetVal); + break; + case UIA_IsKeyboardFocusablePropertyId: + setVariantBool(accessible->state().focusable, pRetVal); + break; + case UIA_IsOffscreenPropertyId: + setVariantBool(false, pRetVal); + break; + case UIA_IsContentElementPropertyId: + setVariantBool(true, pRetVal); + break; + case UIA_IsControlElementPropertyId: + setVariantBool(true, pRetVal); + break; + case UIA_IsEnabledPropertyId: + setVariantBool(!accessible->state().disabled, pRetVal); + break; + case UIA_IsPasswordPropertyId: + setVariantBool(accessible->role() == QAccessible::EditableText + && accessible->state().passwordEdit, pRetVal); + break; + case UIA_IsPeripheralPropertyId: + // True for peripheral UIs. + if (QWindow *window = windowForAccessible(accessible)) { + const Qt::WindowType wt = window->type(); + setVariantBool(wt == Qt::Popup || wt == Qt::ToolTip || wt == Qt::SplashScreen, pRetVal); + } + break; + case UIA_FullDescriptionPropertyId: + setVariantString(accessible->text(QAccessible::Description), pRetVal); + break; + case UIA_NamePropertyId: { + QString name = accessible->text(QAccessible::Name); + if (name.isEmpty() && clientTopLevel) { + name = QCoreApplication::applicationName(); + } + setVariantString(name, pRetVal); + break; + } + default: + break; + } + return S_OK; +} + +// Generates an ID based on the name of the controls and their parents. +QString QWindowsUiaMainProvider::automationIdForAccessible(const QAccessibleInterface *accessible) +{ + QString result; + if (accessible) { + QObject *obj = accessible->object(); + while (obj) { + QString name = obj->objectName(); + if (name.isEmpty()) + return QString(); + if (!result.isEmpty()) + result.prepend(QLatin1Char('.')); + result.prepend(name); + obj = obj->parent(); + } + } + return result; +} + +HRESULT QWindowsUiaMainProvider::get_HostRawElementProvider(IRawElementProviderSimple **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + // Returns a host provider only for controls associated with a native window handle. Others should return NULL. + if (QAccessibleInterface *accessible = accessibleInterface()) { + if (HWND hwnd = hwndForAccessible(accessible)) { + return QWindowsUiaWrapper::instance()->hostProviderFromHwnd(hwnd, pRetVal); + } + } + return S_OK; +} + +// Navigates within the tree of accessible controls. +HRESULT QWindowsUiaMainProvider::Navigate(NavigateDirection direction, IRawElementProviderFragment **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << direction << " this: " << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleInterface *targetacc = nullptr; + + switch (direction) { + case NavigateDirection_Parent: + targetacc = accessible->parent(); + if (targetacc && (targetacc->role() == QAccessible::Application)) { + targetacc = nullptr; // The app's children are considered top level objects. + } + break; + case NavigateDirection_FirstChild: + targetacc = accessible->child(0); + break; + case NavigateDirection_LastChild: + targetacc = accessible->child(accessible->childCount() - 1); + break; + case NavigateDirection_NextSibling: + case NavigateDirection_PreviousSibling: + if (QAccessibleInterface *parent = accessible->parent()) { + if (parent->isValid()) { + int index = parent->indexOfChild(accessible); + index += (direction == NavigateDirection_NextSibling) ? 1 : -1; + if (index >= 0 && index < parent->childCount()) + targetacc = parent->child(index); + } + } + break; + } + + if (targetacc) + *pRetVal = providerForAccessible(targetacc); + return S_OK; +} + +// Returns a unique id assigned to the UI element, used as key by the UI Automation framework. +HRESULT QWindowsUiaMainProvider::GetRuntimeId(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + // The UiaAppendRuntimeId constant is used to make then ID unique + // among multiple instances running on the system. + int rtId[] = { UiaAppendRuntimeId, int(id()) }; + + if ((*pRetVal = SafeArrayCreateVector(VT_I4, 0, 2))) { + for (LONG i = 0; i < 2; ++i) + SafeArrayPutElement(*pRetVal, &i, &rtId[i]); + } + return S_OK; +} + +// Returns the bounding rectangle for the accessible control. +HRESULT QWindowsUiaMainProvider::get_BoundingRectangle(UiaRect *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QWindow *window = windowForAccessible(accessible); + if (!window) + return UIA_E_ELEMENTNOTAVAILABLE; + + rectToNativeUiaRect(accessible->rect(), window, pRetVal); + return S_OK; +} + +HRESULT QWindowsUiaMainProvider::GetEmbeddedFragmentRoots(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + // No embedded roots. + return S_OK; +} + +// Sets focus to the control. +HRESULT QWindowsUiaMainProvider::SetFocus() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + actionInterface->doAction(QAccessibleActionInterface::setFocusAction()); + return S_OK; +} + +HRESULT QWindowsUiaMainProvider::get_FragmentRoot(IRawElementProviderFragmentRoot **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + // Our UI Automation implementation considers the window as the root for + // non-native controls/fragments. + if (QAccessibleInterface *accessible = accessibleInterface()) { + if (QWindow *window = windowForAccessible(accessible)) { + if (QAccessibleInterface *rootacc = window->accessibleRoot()) { + *pRetVal = providerForAccessible(rootacc); + } + } + } + return S_OK; +} + +// Returns a provider for the UI element present at the specified screen coordinates. +HRESULT QWindowsUiaMainProvider::ElementProviderFromPoint(double x, double y, IRawElementProviderFragment **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << x << y; + + if (!pRetVal) { + return E_INVALIDARG; + } + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QWindow *window = windowForAccessible(accessible); + if (!window) + return UIA_E_ELEMENTNOTAVAILABLE; + + // Scales coordinates from High DPI screens. + UiaPoint uiaPoint = {x, y}; + QPoint point; + nativeUiaPointToPoint(uiaPoint, window, &point); + + QAccessibleInterface *targetacc = accessible->childAt(point.x(), point.y()); + + if (targetacc) { + QAccessibleInterface *acc = targetacc; + // Controls can be embedded within grouping elements. By default returns the innermost control. + while (acc) { + targetacc = acc; + // For accessibility tools it may be better to return the text element instead of its subcomponents. + if (targetacc->textInterface()) break; + acc = acc->childAt(point.x(), point.y()); + } + *pRetVal = providerForAccessible(targetacc); + } + return S_OK; +} + +// Returns the fragment with focus. +HRESULT QWindowsUiaMainProvider::GetFocus(IRawElementProviderFragment **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + if (QAccessibleInterface *accessible = accessibleInterface()) { + if (QAccessibleInterface *focusacc = accessible->focusChild()) { + *pRetVal = providerForAccessible(focusacc); + } + } + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h new file mode 100644 index 0000000000..893cbf7f8a --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAMAINPROVIDER_H +#define QWINDOWSUIAMAINPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// The main UI Automation class. +class QWindowsUiaMainProvider : + public QWindowsUiaBaseProvider, + public IRawElementProviderSimple, + public IRawElementProviderFragment, + public IRawElementProviderFragmentRoot +{ + Q_OBJECT + Q_DISABLE_COPY(QWindowsUiaMainProvider) +public: + static QWindowsUiaMainProvider *providerForAccessible(QAccessibleInterface *accessible); + explicit QWindowsUiaMainProvider(QAccessibleInterface *a, int initialRefCount = 1); + virtual ~QWindowsUiaMainProvider(); + static void notifyFocusChange(QAccessibleEvent *event); + static void notifyStateChange(QAccessibleStateChangeEvent *event); + static void notifyValueChange(QAccessibleValueChangeEvent *event); + static void notifyTextChange(QAccessibleEvent *event); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IRawElementProviderSimple methods + HRESULT STDMETHODCALLTYPE get_ProviderOptions(ProviderOptions *pRetVal); + HRESULT STDMETHODCALLTYPE GetPatternProvider(PATTERNID idPattern, IUnknown **pRetVal); + HRESULT STDMETHODCALLTYPE GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal); + HRESULT STDMETHODCALLTYPE get_HostRawElementProvider(IRawElementProviderSimple **pRetVal); + + // IRawElementProviderFragment methods + HRESULT STDMETHODCALLTYPE Navigate(NavigateDirection direction, IRawElementProviderFragment **pRetVal); + HRESULT STDMETHODCALLTYPE GetRuntimeId(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE get_BoundingRectangle(UiaRect *pRetVal); + HRESULT STDMETHODCALLTYPE GetEmbeddedFragmentRoots(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE SetFocus(); + HRESULT STDMETHODCALLTYPE get_FragmentRoot(IRawElementProviderFragmentRoot **pRetVal); + + // IRawElementProviderFragmentRoot methods + HRESULT STDMETHODCALLTYPE ElementProviderFromPoint(double x, double y, IRawElementProviderFragment **pRetVal); + HRESULT STDMETHODCALLTYPE GetFocus(IRawElementProviderFragment **pRetVal); + +private: + QString automationIdForAccessible(const QAccessibleInterface *accessible); + ULONG m_ref; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIAMAINPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp new file mode 100644 index 0000000000..9f0a1e126f --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiaprovidercache.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +// Private constructor +QWindowsUiaProviderCache::QWindowsUiaProviderCache() +{ +} + +// shared instance +QWindowsUiaProviderCache *QWindowsUiaProviderCache::instance() +{ + static QWindowsUiaProviderCache providerCache; + return &providerCache; +} + +// Returns the provider instance associated with the ID, or nullptr. +QWindowsUiaBaseProvider *QWindowsUiaProviderCache::providerForId(QAccessible::Id id) const +{ + return providerTable.value(id); +} + +// Inserts a provider in the cache and associates it with an accessibility ID. +void QWindowsUiaProviderCache::insert(QAccessible::Id id, QWindowsUiaBaseProvider *provider) +{ + remove(id); + if (provider) { + providerTable[id] = provider; + inverseTable[provider] = id; + // Connects the destroyed signal to our slot, to remove deleted objects from the cache. + QObject::connect(provider, &QObject::destroyed, this, &QWindowsUiaProviderCache::objectDestroyed); + } +} + +// Removes deleted provider objects from the cache. +void QWindowsUiaProviderCache::objectDestroyed(QObject *obj) +{ + // We have to use the inverse table to map the object address back to its ID, + // since at this point (called from QObject destructor), it has already been + // partially destroyed and we cannot treat it as a provider. + auto it = inverseTable.find(obj); + if (it != inverseTable.end()) { + providerTable.remove(*it); + inverseTable.remove(obj); + } +} + +// Removes a provider with a given id from the cache. +void QWindowsUiaProviderCache::remove(QAccessible::Id id) +{ + inverseTable.remove(providerTable.value(id)); + providerTable.remove(id); +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h new file mode 100644 index 0000000000..7ad30ac39c --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAPROVIDERCACHE_H +#define QWINDOWSUIAPROVIDERCACHE_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// Singleton used to cache provider instances using the accessibility ID as the key. +class QWindowsUiaProviderCache : public QObject +{ + QWindowsUiaProviderCache(); + Q_OBJECT +public: + static QWindowsUiaProviderCache *instance(); + QWindowsUiaBaseProvider *providerForId(QAccessible::Id id) const; + void insert(QAccessible::Id id, QWindowsUiaBaseProvider *provider); + void remove(QAccessible::Id id); + +private Q_SLOTS: + void objectDestroyed(QObject *obj); + +private: + QHash providerTable; + QHash inverseTable; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIAPROVIDERCACHE_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp new file mode 100644 index 0000000000..0cd09c3f0a --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiarangevalueprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaRangeValueProvider::QWindowsUiaRangeValueProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaRangeValueProvider::~QWindowsUiaRangeValueProvider() +{ +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaRangeValueProvider::SetValue(double val) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleValueInterface *valueInterface = accessible->valueInterface(); + if (!valueInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + double minimum = valueInterface->minimumValue().toDouble(); + double maximum = valueInterface->maximumValue().toDouble(); + if ((val < minimum) || (val > maximum)) + return E_INVALIDARG; + + valueInterface->setCurrentValue(QVariant(val)); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaRangeValueProvider::get_Value(double *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleValueInterface *valueInterface = accessible->valueInterface(); + if (!valueInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QVariant varValue = valueInterface->currentValue(); + *pRetVal = varValue.toDouble(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaRangeValueProvider::get_IsReadOnly(BOOL *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = accessible->state().readOnly; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaRangeValueProvider::get_Maximum(double *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleValueInterface *valueInterface = accessible->valueInterface(); + if (!valueInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QVariant varValue = valueInterface->maximumValue(); + *pRetVal = varValue.toDouble(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaRangeValueProvider::get_Minimum(double *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleValueInterface *valueInterface = accessible->valueInterface(); + if (!valueInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QVariant varValue = valueInterface->minimumValue(); + *pRetVal = varValue.toDouble(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaRangeValueProvider::get_LargeChange(double *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + return get_SmallChange(pRetVal); +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaRangeValueProvider::get_SmallChange(double *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleValueInterface *valueInterface = accessible->valueInterface(); + if (!valueInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QVariant varValue = valueInterface->minimumStepSize(); + *pRetVal = varValue.toDouble(); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h new file mode 100644 index 0000000000..f742ef99c2 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIARANGEVALUEPROVIDER_H +#define QWINDOWSUIARANGEVALUEPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Range Value control pattern provider. +class QWindowsUiaRangeValueProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaRangeValueProvider) +public: + explicit QWindowsUiaRangeValueProvider(QAccessible::Id id); + virtual ~QWindowsUiaRangeValueProvider(); + + // IRangeValueProvider + HRESULT STDMETHODCALLTYPE SetValue(double val); + HRESULT STDMETHODCALLTYPE get_Value(double *pRetVal); + HRESULT STDMETHODCALLTYPE get_IsReadOnly(BOOL *pRetVal); + HRESULT STDMETHODCALLTYPE get_Maximum(double *pRetVal); + HRESULT STDMETHODCALLTYPE get_Minimum(double *pRetVal); + HRESULT STDMETHODCALLTYPE get_LargeChange(double *pRetVal); + HRESULT STDMETHODCALLTYPE get_SmallChange(double *pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIARANGEVALUEPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp new file mode 100644 index 0000000000..45216a6d1c --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiaselectionitemprovider.h" +#include "qwindowsuiamainprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaSelectionItemProvider::QWindowsUiaSelectionItemProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaSelectionItemProvider::~QWindowsUiaSelectionItemProvider() +{ +} + +// Selects the element (deselecting all others). +HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::Select() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->role() == QAccessible::RadioButton) { + // For radio buttons 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. + if (!accessible->state().selected) { + actionInterface->doAction(QAccessibleActionInterface::toggleAction()); + } + // Toggle selected siblings. + if (QAccessibleInterface *parent = accessible->parent()) { + for (int i = 0; i < parent->childCount(); ++i) { + if (QAccessibleInterface *sibling = parent->child(i)) { + if ((sibling != accessible) && (sibling->state().selected)) { + if (QAccessibleActionInterface *siblingAction = sibling->actionInterface()) { + siblingAction->doAction(QAccessibleActionInterface::toggleAction()); + } + } + } + } + } + } + return S_OK; +} + +// Adds the element to the list of selected elements. +HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::AddToSelection() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->role() == QAccessible::RadioButton) { + // For radio buttons we invoke the selection action. + actionInterface->doAction(QAccessibleActionInterface::pressAction()); + } else { + // Toggle list item if not already selected. + if (!accessible->state().selected) { + actionInterface->doAction(QAccessibleActionInterface::toggleAction()); + } + } + return S_OK; +} + +// Removes a list item from selection. +HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::RemoveFromSelection() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->role() != QAccessible::RadioButton) { + if (accessible->state().selected) { + actionInterface->doAction(QAccessibleActionInterface::toggleAction()); + } + } + + return S_OK; +} + +// Returns true if element is currently selected. +HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_IsSelected(BOOL *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = FALSE; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->role() == QAccessible::RadioButton) + *pRetVal = accessible->state().checked; + else + *pRetVal = accessible->state().selected; + return S_OK; +} + +// Returns the provider for the container element (e.g., the list for the list item). +HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_SelectionContainer(IRawElementProviderSimple **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + 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); + } + } + } + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h new file mode 100644 index 0000000000..6a9b5b1e4b --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIASELECTIONITEMPROVIDER_H +#define QWINDOWSUIASELECTIONITEMPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Selection Item control pattern provider. Used for List items and radio buttons. +class QWindowsUiaSelectionItemProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaSelectionItemProvider) +public: + explicit QWindowsUiaSelectionItemProvider(QAccessible::Id id); + virtual ~QWindowsUiaSelectionItemProvider(); + + // ISelectionItemProvider + HRESULT STDMETHODCALLTYPE Select(); + HRESULT STDMETHODCALLTYPE AddToSelection(); + HRESULT STDMETHODCALLTYPE RemoveFromSelection(); + HRESULT STDMETHODCALLTYPE get_IsSelected(BOOL *pRetVal); + HRESULT STDMETHODCALLTYPE get_SelectionContainer(IRawElementProviderSimple **pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIASELECTIONITEMPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp new file mode 100644 index 0000000000..1c06503bfc --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiaselectionprovider.h" +#include "qwindowsuiamainprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaSelectionProvider::QWindowsUiaSelectionProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaSelectionProvider::~QWindowsUiaSelectionProvider() +{ +} + +// Returns an array of providers with the selected items. +HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::GetSelection(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + // First put selected items in a list, then build a safe array with the right size. + QList selectedList; + for (int i = 0; i < accessible->childCount(); ++i) { + if (QAccessibleInterface *child = accessible->child(i)) { + if (child->state().selected) { + selectedList.append(child); + } + } + } + + if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, selectedList.size()))) { + for (LONG i = 0; i < selectedList.size(); ++i) { + if (QWindowsUiaMainProvider *childProvider = QWindowsUiaMainProvider::providerForAccessible(selectedList.at(i))) { + SafeArrayPutElement(*pRetVal, &i, static_cast(childProvider)); + childProvider->Release(); + } + } + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_CanSelectMultiple(BOOL *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = FALSE; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = accessible->state().multiSelectable; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_IsSelectionRequired(BOOL *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = FALSE; + + QAccessibleInterface *accessible = accessibleInterface(); + 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; + } + } + } + + *pRetVal = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable; + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h new file mode 100644 index 0000000000..5a07a82ac8 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIASELECTIONPROVIDER_H +#define QWINDOWSUIASELECTIONPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Selection control pattern provider. Used for Lists. +class QWindowsUiaSelectionProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaSelectionProvider) +public: + explicit QWindowsUiaSelectionProvider(QAccessible::Id id); + virtual ~QWindowsUiaSelectionProvider(); + + // ISelectionProvider + HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(BOOL *pRetVal); + HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(BOOL *pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIASELECTIONPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp new file mode 100644 index 0000000000..3ea29fc86c --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiatableitemprovider.h" +#include "qwindowsuiamainprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaTableItemProvider::QWindowsUiaTableItemProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaTableItemProvider::~QWindowsUiaTableItemProvider() +{ +} + +// Returns the providers for the row headers associated with the item. +HRESULT STDMETHODCALLTYPE QWindowsUiaTableItemProvider::GetRowHeaderItems(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface(); + if (!tableCellInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QList headers = tableCellInterface->rowHeaderCells(); + + if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, headers.size()))) { + for (LONG i = 0; i < headers.size(); ++i) { + if (QWindowsUiaMainProvider *headerProvider = QWindowsUiaMainProvider::providerForAccessible(headers.at(i))) { + SafeArrayPutElement(*pRetVal, &i, static_cast(headerProvider)); + headerProvider->Release(); + } + } + } + return S_OK; +} + +// Returns the providers for the column headers associated with the item. +HRESULT STDMETHODCALLTYPE QWindowsUiaTableItemProvider::GetColumnHeaderItems(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface(); + if (!tableCellInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QList headers = tableCellInterface->columnHeaderCells(); + + if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, headers.size()))) { + for (LONG i = 0; i < headers.size(); ++i) { + if (QWindowsUiaMainProvider *headerProvider = QWindowsUiaMainProvider::providerForAccessible(headers.at(i))) { + SafeArrayPutElement(*pRetVal, &i, static_cast(headerProvider)); + headerProvider->Release(); + } + } + } + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h new file mode 100644 index 0000000000..277884c980 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIATABLEITEMPROVIDER_H +#define QWINDOWSUIATABLEITEMPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Table Item control pattern provider. Used by items within a table/tree. +class QWindowsUiaTableItemProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaTableItemProvider) +public: + explicit QWindowsUiaTableItemProvider(QAccessible::Id id); + virtual ~QWindowsUiaTableItemProvider(); + + // ITableItemProvider + HRESULT STDMETHODCALLTYPE GetRowHeaderItems(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE GetColumnHeaderItems(SAFEARRAY **pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIATABLEITEMPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp new file mode 100644 index 0000000000..f79a24536b --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiatableprovider.h" +#include "qwindowsuiamainprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaTableProvider::QWindowsUiaTableProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaTableProvider::~QWindowsUiaTableProvider() +{ +} + +// Gets the providers for all the row headers in the table. +HRESULT STDMETHODCALLTYPE QWindowsUiaTableProvider::GetRowHeaders(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableInterface *tableInterface = accessible->tableInterface(); + if (!tableInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QList headers; + + for (int i = 0; i < tableInterface->rowCount(); ++i) { + if (QAccessibleInterface *cell = tableInterface->cellAt(i, 0)) { + if (QAccessibleTableCellInterface *tableCellInterface = cell->tableCellInterface()) { + headers.append(tableCellInterface->rowHeaderCells()); + } + } + } + if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, headers.size()))) { + for (LONG i = 0; i < headers.size(); ++i) { + if (QWindowsUiaMainProvider *headerProvider = QWindowsUiaMainProvider::providerForAccessible(headers.at(i))) { + SafeArrayPutElement(*pRetVal, &i, static_cast(headerProvider)); + headerProvider->Release(); + } + } + } + return S_OK; +} + +// Gets the providers for all the column headers in the table. +HRESULT STDMETHODCALLTYPE QWindowsUiaTableProvider::GetColumnHeaders(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTableInterface *tableInterface = accessible->tableInterface(); + if (!tableInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QList headers; + + for (int i = 0; i < tableInterface->columnCount(); ++i) { + if (QAccessibleInterface *cell = tableInterface->cellAt(0, i)) { + if (QAccessibleTableCellInterface *tableCellInterface = cell->tableCellInterface()) { + headers.append(tableCellInterface->columnHeaderCells()); + } + } + } + if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, headers.size()))) { + for (LONG i = 0; i < headers.size(); ++i) { + if (QWindowsUiaMainProvider *headerProvider = QWindowsUiaMainProvider::providerForAccessible(headers.at(i))) { + SafeArrayPutElement(*pRetVal, &i, static_cast(headerProvider)); + headerProvider->Release(); + } + } + } + return S_OK; +} + +// Returns the primary direction of traversal for the table. +HRESULT STDMETHODCALLTYPE QWindowsUiaTableProvider::get_RowOrColumnMajor(enum RowOrColumnMajor *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = RowOrColumnMajor_Indeterminate; + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h new file mode 100644 index 0000000000..8cd0acda03 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIATABLEPROVIDER_H +#define QWINDOWSUIATABLEPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Table control pattern provider. Used by tables/trees. +class QWindowsUiaTableProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaTableProvider) +public: + explicit QWindowsUiaTableProvider(QAccessible::Id id); + virtual ~QWindowsUiaTableProvider(); + + // ITableProvider + HRESULT STDMETHODCALLTYPE GetRowHeaders(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE GetColumnHeaders(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE get_RowOrColumnMajor(enum RowOrColumnMajor *pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIATABLEPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp new file mode 100644 index 0000000000..e1622933af --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiatextprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaTextProvider::QWindowsUiaTextProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaTextProvider::~QWindowsUiaTextProvider() +{ +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::QueryInterface(REFIID iid, LPVOID *iface) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!iface) + return E_INVALIDARG; + *iface = nullptr; + + const bool result = qWindowsComQueryUnknownInterfaceMulti(this, iid, iface) + || qWindowsComQueryInterface(this, iid, iface) + || qWindowsComQueryInterface(this, iid, iface); + return result ? S_OK : E_NOINTERFACE; +} + +// Returns an array of providers for the selected text ranges. +HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetSelection(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + int selCount = textInterface->selectionCount(); + if (selCount > 0) { + // Build a safe array with the text range providers. + if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, selCount))) { + for (LONG i = 0; i < selCount; ++i) { + int startOffset = 0, endOffset = 0; + textInterface->selection((int)i, &startOffset, &endOffset); + QWindowsUiaTextRangeProvider *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), startOffset, endOffset); + SafeArrayPutElement(*pRetVal, &i, static_cast(textRangeProvider)); + textRangeProvider->Release(); + } + } + } else { + // If there is no selection, we return an array with a single degenerate (empty) text range at the cursor position. + if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, 1))) { + LONG i = 0; + int cursorPosition = textInterface->cursorPosition(); + QWindowsUiaTextRangeProvider *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), cursorPosition, cursorPosition); + SafeArrayPutElement(*pRetVal, &i, static_cast(textRangeProvider)); + textRangeProvider->Release(); + } + } + return S_OK; +} + +// Returns an array of providers for the visible text ranges. +HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetVisibleRanges(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + // Considering the entire text as visible. + if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, 1))) { + LONG i = 0; + QWindowsUiaTextRangeProvider *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), 0, textInterface->characterCount()); + SafeArrayPutElement(*pRetVal, &i, static_cast(textRangeProvider)); + textRangeProvider->Release(); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::RangeFromChild(IRawElementProviderSimple * /*childElement*/, + ITextRangeProvider **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + // No children supported. + return S_OK; +} + +// Returns a degenerate text range at the specified point. +HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::RangeFromPoint(UiaPoint point, ITextRangeProvider **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QWindow *window = windowForAccessible(accessible); + if (!window) + return UIA_E_ELEMENTNOTAVAILABLE; + + QPoint pt; + nativeUiaPointToPoint(point, window, &pt); + + int offset = textInterface->offsetAtPoint(pt); + if ((offset >= 0) && (offset < textInterface->characterCount())) { + *pRetVal = new QWindowsUiaTextRangeProvider(id(), offset, offset); + } + return S_OK; +} + +// Returns a text range provider for the entire text. +HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::get_DocumentRange(ITextRangeProvider **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = new QWindowsUiaTextRangeProvider(id(), 0, textInterface->characterCount()); + return S_OK; +} + +// Currently supporting single selection. +HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::get_SupportedTextSelection(SupportedTextSelection *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = SupportedTextSelection_Single; + return S_OK; +} + +// Not supporting annotations. +HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::RangeFromAnnotation(IRawElementProviderSimple * /*annotationElement*/, ITextRangeProvider **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetCaretRange(BOOL *isActive, ITextRangeProvider **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!isActive || !pRetVal) + return E_INVALIDARG; + *isActive = FALSE; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + *isActive = accessible->state().focused; + + int cursorPosition = textInterface->cursorPosition(); + *pRetVal = new QWindowsUiaTextRangeProvider(id(), cursorPosition, cursorPosition); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h new file mode 100644 index 0000000000..a6d10027fa --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIATEXTPROVIDER_H +#define QWINDOWSUIATEXTPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" +#include "qwindowsuiatextrangeprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Text control pattern provider. Used for text controls. +class QWindowsUiaTextProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaTextProvider) +public: + explicit QWindowsUiaTextProvider(QAccessible::Id id); + ~QWindowsUiaTextProvider(); + + // IUnknown overrides + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface); + + // ITextProvider + HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE GetVisibleRanges(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE RangeFromChild(IRawElementProviderSimple *childElement, ITextRangeProvider **pRetVal); + HRESULT STDMETHODCALLTYPE RangeFromPoint(UiaPoint point, ITextRangeProvider **pRetVal); + HRESULT STDMETHODCALLTYPE get_DocumentRange(ITextRangeProvider **pRetVal); + HRESULT STDMETHODCALLTYPE get_SupportedTextSelection(SupportedTextSelection *pRetVal); + + // ITextProvider2 + HRESULT STDMETHODCALLTYPE RangeFromAnnotation(IRawElementProviderSimple *annotationElement, ITextRangeProvider **pRetVal); + HRESULT STDMETHODCALLTYPE GetCaretRange(BOOL *isActive, ITextRangeProvider **pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIATEXTPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp new file mode 100644 index 0000000000..dae7cbdd5f --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp @@ -0,0 +1,554 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiatextrangeprovider.h" +#include "qwindowsuiamainprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaTextRangeProvider::QWindowsUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset) : + QWindowsUiaBaseProvider(id), + m_startOffset(startOffset), + m_endOffset(endOffset) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this << startOffset << endOffset; +} + +QWindowsUiaTextRangeProvider::~QWindowsUiaTextRangeProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; +} + +HRESULT QWindowsUiaTextRangeProvider::AddToSelection() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + return Select(); +} + +HRESULT QWindowsUiaTextRangeProvider::Clone(ITextRangeProvider **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + + *pRetVal = new QWindowsUiaTextRangeProvider(id(), m_startOffset, m_endOffset); + return S_OK; +} + +// Two ranges are considered equal if their start/end points are the same. +HRESULT QWindowsUiaTextRangeProvider::Compare(ITextRangeProvider *range, BOOL *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!range || !pRetVal) + return E_INVALIDARG; + + QWindowsUiaTextRangeProvider *targetProvider = static_cast(range); + *pRetVal = ((targetProvider->m_startOffset == m_startOffset) && (targetProvider->m_endOffset == m_endOffset)); + return S_OK; +} + +// Compare different endpoinds between two providers. +HRESULT QWindowsUiaTextRangeProvider::CompareEndpoints(TextPatternRangeEndpoint endpoint, + ITextRangeProvider *targetRange, + TextPatternRangeEndpoint targetEndpoint, + int *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ + << "endpoint=" << endpoint << "targetRange=" << targetRange + << "targetEndpoint=" << targetEndpoint << "this: " << this; + + if (!targetRange || !pRetVal) + return E_INVALIDARG; + + QWindowsUiaTextRangeProvider *targetProvider = static_cast(targetRange); + + int point = (endpoint == TextPatternRangeEndpoint_Start) ? m_startOffset : m_endOffset; + int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ? + targetProvider->m_startOffset : targetProvider->m_endOffset; + *pRetVal = point - targetPoint; + return S_OK; +} + +// Expands/normalizes the range for a given text unit. +HRESULT QWindowsUiaTextRangeProvider::ExpandToEnclosingUnit(TextUnit unit) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "unit=" << unit << "this: " << this; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + int len = textInterface->characterCount(); + if (len < 1) { + m_startOffset = 0; + m_endOffset = 0; + } else { + if (unit == TextUnit_Character) { + m_startOffset = qBound(0, m_startOffset, len - 1); + m_endOffset = m_startOffset + 1; + } else { + QString text = textInterface->text(0, len); + for (int t = m_startOffset; t >= 0; --t) { + if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) { + m_startOffset = t; + break; + } + } + for (int t = m_startOffset; t < len; ++t) { + if ((t == len - 1) || (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1])))) { + m_endOffset = t + 1; + break; + } + } + } + } + return S_OK; +} + +// Not supported. +HRESULT QWindowsUiaTextRangeProvider::FindAttribute(TEXTATTRIBUTEID /* attributeId */, + VARIANT /* val */, BOOL /* backward */, + ITextRangeProvider **pRetVal) +{ + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + return S_OK; +} + +// Returns the value of a given attribute. +HRESULT STDMETHODCALLTYPE QWindowsUiaTextRangeProvider::GetAttributeValue(TEXTATTRIBUTEID attributeId, + VARIANT *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "attributeId=" << attributeId << "this: " << this; + + if (!pRetVal) + return E_INVALIDARG; + clearVariant(pRetVal); + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + switch (attributeId) { + case UIA_IsReadOnlyAttributeId: + setVariantBool(accessible->state().readOnly, pRetVal); + break; + case UIA_CaretPositionAttributeId: + if (textInterface->cursorPosition() == 0) + setVariantI4(CaretPosition_BeginningOfLine, pRetVal); + else if (textInterface->cursorPosition() == textInterface->characterCount()) + setVariantI4(CaretPosition_EndOfLine, pRetVal); + else + setVariantI4(CaretPosition_Unknown, pRetVal); + break; + default: + break; + } + return S_OK; +} + +// Returns an array of bounding rectangles for text lines within the range. +HRESULT QWindowsUiaTextRangeProvider::GetBoundingRectangles(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + QWindow *window = windowForAccessible(accessible); + if (!window) + return UIA_E_ELEMENTNOTAVAILABLE; + + int len = textInterface->characterCount(); + QList rectList; + + if ((m_startOffset >= 0) && (m_endOffset <= len) && (m_startOffset < m_endOffset)) { + int start, end; + textInterface->textAtOffset(m_startOffset, QAccessible::LineBoundary, &start, &end); + while ((start >= 0) && (end >= 0)) { + int startRange = qMax(start, m_startOffset); + int endRange = qMin(end, m_endOffset); + if (startRange < endRange) { + // Calculates a bounding rectangle for the line and adds it to the list. + QRect startRect = textInterface->characterRect(startRange); + QRect endRect = textInterface->characterRect(endRange - 1); + QRect lineRect(qMin(startRect.x(), endRect.x()), + qMin(startRect.y(), endRect.y()), + qMax(startRect.x() + startRect.width(), endRect.x() + endRect.width()) - qMin(startRect.x(), endRect.x()), + qMax(startRect.y() + startRect.height(), endRect.y() + endRect.height()) - qMin(startRect.y(), endRect.y())); + rectList.append(lineRect); + } + if (end >= len) break; + textInterface->textAfterOffset(end + 1, QAccessible::LineBoundary, &start, &end); + } + } + + if ((*pRetVal = SafeArrayCreateVector(VT_R8, 0, 4 * rectList.size()))) { + for (int i = 0; i < rectList.size(); ++i) { + // Scale rect for high DPI screens. + UiaRect uiaRect; + rectToNativeUiaRect(rectList[i], window, &uiaRect); + double coords[4] = { uiaRect.left, uiaRect.top, uiaRect.width, uiaRect.height }; + for (int j = 0; j < 4; ++j) { + LONG idx = 4 * i + j; + SafeArrayPutElement(*pRetVal, &idx, &coords[j]); + } + } + } + return S_OK; +} + +// Returns an array of children elements embedded within the range. +HRESULT QWindowsUiaTextRangeProvider::GetChildren(SAFEARRAY **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + // Not supporting any children. + *pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, 0); + return S_OK; +} + +// Returns a provider for the enclosing element (text to which the range belongs). +HRESULT QWindowsUiaTextRangeProvider::GetEnclosingElement(IRawElementProviderSimple **pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + if (!pRetVal) + return E_INVALIDARG; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = QWindowsUiaMainProvider::providerForAccessible(accessible); + return S_OK; +} + +// Gets the text within the range. +HRESULT QWindowsUiaTextRangeProvider::GetText(int maxLength, BSTR *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << maxLength << "this: " << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + int len = textInterface->characterCount(); + QString rangeText; + if ((m_startOffset >= 0) && (m_endOffset <= len) && (m_startOffset < m_endOffset)) + rangeText = textInterface->text(m_startOffset, m_endOffset); + + if ((maxLength > -1) && (rangeText.size() > maxLength)) + rangeText.truncate(maxLength); + *pRetVal = bStrFromQString(rangeText); + return S_OK; +} + +// Moves the range a specified number of units (and normalizes it). +HRESULT QWindowsUiaTextRangeProvider::Move(TextUnit unit, int count, int *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "unit=" << unit << "count=" << count << "this: " << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = 0; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + int len = textInterface->characterCount(); + + if (len < 1) + return S_OK; + + if (unit == TextUnit_Character) { + // Moves the start point, ensuring it lies within the bounds. + int start = qBound(0, m_startOffset + count, len - 1); + // If range was initially empty, leaves it as is; otherwise, normalizes it to one char. + m_endOffset = (m_endOffset > m_startOffset) ? start + 1 : start; + *pRetVal = start - m_startOffset; // Returns the actually moved distance. + m_startOffset = start; + } else { + if (count > 0) { + MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, pRetVal); + MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, pRetVal); + } else { + MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, pRetVal); + MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, pRetVal); + } + } + return S_OK; +} + +// Copies the value of an end point from one range to another. +HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByRange(TextPatternRangeEndpoint endpoint, + ITextRangeProvider *targetRange, + TextPatternRangeEndpoint targetEndpoint) +{ + if (!targetRange) + return E_INVALIDARG; + + qCDebug(lcQpaUiAutomation) << __FUNCTION__ + << "endpoint=" << endpoint << "targetRange=" << targetRange << "targetEndpoint=" << targetEndpoint << "this: " << this; + + QWindowsUiaTextRangeProvider *targetProvider = static_cast(targetRange); + + int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ? + targetProvider->m_startOffset : targetProvider->m_endOffset; + + // If the moved endpoint crosses the other endpoint, that one is moved too. + if (endpoint == TextPatternRangeEndpoint_Start) { + m_startOffset = targetPoint; + if (m_endOffset < m_startOffset) + m_endOffset = m_startOffset; + } else { + m_endOffset = targetPoint; + if (m_endOffset < m_startOffset) + m_startOffset = m_endOffset; + } + return S_OK; +} + +// Moves an endpoint an specific number of units. +HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, + TextUnit unit, int count, + int *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ + << "endpoint=" << endpoint << "unit=" << unit << "count=" << count << "this: " << this; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = 0; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + int len = textInterface->characterCount(); + + if (len < 1) + return S_OK; + + if (unit == TextUnit_Character) { + if (endpoint == TextPatternRangeEndpoint_Start) { + int boundedValue = qBound(0, m_startOffset + count, len - 1); + *pRetVal = boundedValue - m_startOffset; + m_startOffset = boundedValue; + m_endOffset = qBound(m_startOffset, m_endOffset, len); + } else { + int boundedValue = qBound(0, m_endOffset + count, len); + *pRetVal = boundedValue - m_endOffset; + m_endOffset = boundedValue; + m_startOffset = qBound(0, m_startOffset, m_endOffset); + } + } else { + QString text = textInterface->text(0, len); + int moved = 0; + + if (endpoint == TextPatternRangeEndpoint_Start) { + if (count > 0) { + for (int t = m_startOffset; (t < len - 1) && (moved < count); ++t) { + if (isTextUnitSeparator(unit, text[t]) && !isTextUnitSeparator(unit, text[t + 1])) { + m_startOffset = t + 1; + ++moved; + } + } + m_endOffset = qBound(m_startOffset, m_endOffset, len); + } else { + for (int t = m_startOffset - 1; (t >= 0) && (moved > count); --t) { + if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) { + m_startOffset = t; + --moved; + } + } + } + } else { + if (count > 0) { + for (int t = m_endOffset; (t < len) && (moved < count); ++t) { + if ((t == len - 1) || (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1])))) { + m_endOffset = t + 1; + ++moved; + } + } + } else { + int end = 0; + for (int t = m_endOffset - 2; (t > 0) && (moved > count); --t) { + if (isTextUnitSeparator(unit, text[t]) && ((unit == TextUnit_Word) || !isTextUnitSeparator(unit, text[t + 1]))) { + end = t + 1; + --moved; + } + } + m_endOffset = end; + m_startOffset = qBound(0, m_startOffset, m_endOffset); + } + } + *pRetVal = moved; + } + return S_OK; +} + +HRESULT QWindowsUiaTextRangeProvider::RemoveFromSelection() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + // unselects all + return unselect(); +} + +// Scrolls the range into view. +HRESULT QWindowsUiaTextRangeProvider::ScrollIntoView(BOOL alignToTop) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "alignToTop=" << alignToTop << "this: " << this; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + textInterface->scrollToSubstring(m_startOffset, m_endOffset); + return S_OK; +} + +// Selects the range. +HRESULT QWindowsUiaTextRangeProvider::Select() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + // unselects all and adds a new selection + unselect(); + textInterface->addSelection(m_startOffset, m_endOffset); + return S_OK; +} + +// Not supported. +HRESULT QWindowsUiaTextRangeProvider::FindTextW(BSTR /* text */, BOOL /* backward */, + BOOL /* ignoreCase */, + ITextRangeProvider **pRetVal) +{ + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + return S_OK; +} + +// Removes all selected ranges from the text element. +HRESULT QWindowsUiaTextRangeProvider::unselect() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleTextInterface *textInterface = accessible->textInterface(); + if (!textInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + int selCount = textInterface->selectionCount(); + + for (int i = selCount - 1; i >= 0; --i) + textInterface->removeSelection(i); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h new file mode 100644 index 0000000000..6fe6502c41 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIATEXTRANGEPROVIDER_H +#define QWINDOWSUIATEXTRANGEPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Text Range control pattern provider. Used for text controls. +class QWindowsUiaTextRangeProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaTextRangeProvider) +public: + explicit QWindowsUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset); + virtual ~QWindowsUiaTextRangeProvider(); + + HRESULT STDMETHODCALLTYPE AddToSelection(); + HRESULT STDMETHODCALLTYPE Clone(ITextRangeProvider **pRetVal); + HRESULT STDMETHODCALLTYPE Compare(ITextRangeProvider *range, BOOL *pRetVal); + HRESULT STDMETHODCALLTYPE CompareEndpoints(TextPatternRangeEndpoint endpoint, ITextRangeProvider *targetRange, TextPatternRangeEndpoint targetEndpoint, int *pRetVal); + HRESULT STDMETHODCALLTYPE ExpandToEnclosingUnit(TextUnit unit); + HRESULT STDMETHODCALLTYPE FindAttribute(TEXTATTRIBUTEID attributeId, VARIANT val, BOOL backward, ITextRangeProvider **pRetVal); + HRESULT STDMETHODCALLTYPE FindText(BSTR text, BOOL backward, BOOL ignoreCase, ITextRangeProvider **pRetVal); + HRESULT STDMETHODCALLTYPE GetAttributeValue(TEXTATTRIBUTEID attributeId, VARIANT *pRetVal); + HRESULT STDMETHODCALLTYPE GetBoundingRectangles(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE GetChildren(SAFEARRAY **pRetVal); + HRESULT STDMETHODCALLTYPE GetEnclosingElement(IRawElementProviderSimple **pRetVal); + HRESULT STDMETHODCALLTYPE GetText(int maxLength, BSTR *pRetVal); + HRESULT STDMETHODCALLTYPE Move(TextUnit unit, int count, int *pRetVal); + HRESULT STDMETHODCALLTYPE MoveEndpointByRange(TextPatternRangeEndpoint endpoint, ITextRangeProvider *targetRange, TextPatternRangeEndpoint targetEndpoint); + HRESULT STDMETHODCALLTYPE MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, int count, int *pRetVal); + HRESULT STDMETHODCALLTYPE RemoveFromSelection(); + HRESULT STDMETHODCALLTYPE ScrollIntoView(BOOL alignToTop); + HRESULT STDMETHODCALLTYPE Select(); + +private: + HRESULT unselect(); + int m_startOffset; + int m_endOffset; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIATEXTRANGEPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp new file mode 100644 index 0000000000..01cdfd7e91 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiatoggleprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaToggleProvider::QWindowsUiaToggleProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaToggleProvider::~QWindowsUiaToggleProvider() +{ +} + +// toggles the state by invoking the toggle action +HRESULT STDMETHODCALLTYPE QWindowsUiaToggleProvider::Toggle() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + actionInterface->doAction(QAccessibleActionInterface::toggleAction()); + return S_OK; +} + +// Gets the current toggle state. +HRESULT STDMETHODCALLTYPE QWindowsUiaToggleProvider::get_ToggleState(ToggleState *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = ToggleState_Off; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->state().checked) + *pRetVal = accessible->state().checkStateMixed ? ToggleState_Indeterminate : ToggleState_On; + else + *pRetVal = ToggleState_Off; + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h new file mode 100644 index 0000000000..a0df983e40 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIATOGGLEPROVIDER_H +#define QWINDOWSUIATOGGLEPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Toggle control pattern provider. Used for checkboxes. +class QWindowsUiaToggleProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaToggleProvider) +public: + explicit QWindowsUiaToggleProvider(QAccessible::Id id); + virtual ~QWindowsUiaToggleProvider(); + + // IToggleProvider + HRESULT STDMETHODCALLTYPE Toggle(); + HRESULT STDMETHODCALLTYPE get_ToggleState(ToggleState *pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIATOGGLEPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp new file mode 100644 index 0000000000..89e5075dcb --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" +#include "qwindowswindow.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QWindowsUiAutomation { + +// Returns the window containing the element (usually the top window), +QWindow *windowForAccessible(const QAccessibleInterface *accessible) +{ + QWindow *window = accessible->window(); + if (!window) { + QAccessibleInterface *acc = accessible->parent(); + while (acc && acc->isValid() && !window) { + window = acc->window(); + QAccessibleInterface *par = acc->parent(); + acc = par; + } + } + return window; +} + +// Returns the native window handle associated with the element, if any. +// Usually it will be NULL, as Qt5 by default uses alien widgets with no native windows. +HWND hwndForAccessible(const QAccessibleInterface *accessible) +{ + if (QWindow *window = accessible->window()) { + if (!accessible->parent() || (accessible->parent()->window() != window)) { + return QWindowsBaseWindow::handleOf(window); + } + } + return NULL; +} + +void clearVariant(VARIANT *variant) +{ + variant->vt = VT_EMPTY; + variant->punkVal = nullptr; +} + +void setVariantI4(int value, VARIANT *variant) +{ + variant->vt = VT_I4; + variant->lVal = value; +} + +void setVariantBool(bool value, VARIANT *variant) +{ + variant->vt = VT_BOOL; + variant->boolVal = value ? -1 : 0; +} + +void setVariantDouble(double value, VARIANT *variant) +{ + variant->vt = VT_R8; + variant->boolVal = value; +} + +BSTR bStrFromQString(const QString &value) +{ + return SysAllocString(reinterpret_cast(value.utf16())); +} + +void setVariantString(const QString &value, VARIANT *variant) +{ + variant->vt = VT_BSTR; + variant->bstrVal = bStrFromQString(value); +} + +// Scales a rect to native coordinates, according to high dpi settings. +void rectToNativeUiaRect(const QRect &rect, const QWindow *w, UiaRect *uiaRect) +{ + if (w && uiaRect) { + const qreal factor = QHighDpiScaling::factor(w); + uiaRect->left = qreal(rect.x()) * factor; + uiaRect->top = qreal(rect.y()) * factor; + uiaRect->width = qreal(rect.width()) * factor; + uiaRect->height = qreal(rect.height()) * factor; + } +} + +// Scales a point from native coordinates, according to high dpi settings. +void nativeUiaPointToPoint(const UiaPoint &uiaPoint, const QWindow *w, QPoint *point) +{ + if (w && point) { + const qreal factor = QHighDpiScaling::factor(w); + point->setX(int(std::lround(uiaPoint.x / factor))); + point->setY(int(std::lround(uiaPoint.y / factor))); + } +} + +// Maps an accessibility role ID to an UI Automation control type ID. +long roleToControlTypeId(QAccessible::Role role) +{ + static const QHash mapping { + {QAccessible::TitleBar, UIA_TitleBarControlTypeId}, + {QAccessible::MenuBar, UIA_MenuBarControlTypeId}, + {QAccessible::ScrollBar, UIA_ScrollBarControlTypeId}, + {QAccessible::Grip, UIA_ThumbControlTypeId}, + {QAccessible::Sound, UIA_CustomControlTypeId}, + {QAccessible::Cursor, UIA_CustomControlTypeId}, + {QAccessible::Caret, UIA_CustomControlTypeId}, + {QAccessible::AlertMessage, UIA_CustomControlTypeId}, + {QAccessible::Window, UIA_WindowControlTypeId}, + {QAccessible::Client, UIA_CustomControlTypeId}, + {QAccessible::PopupMenu, UIA_MenuControlTypeId}, + {QAccessible::MenuItem, UIA_MenuItemControlTypeId}, + {QAccessible::ToolTip, UIA_ToolTipControlTypeId}, + {QAccessible::Application, UIA_CustomControlTypeId}, + {QAccessible::Document, UIA_DocumentControlTypeId}, + {QAccessible::Pane, UIA_PaneControlTypeId}, + {QAccessible::Chart, UIA_CustomControlTypeId}, + {QAccessible::Dialog, UIA_WindowControlTypeId}, + {QAccessible::Border, UIA_CustomControlTypeId}, + {QAccessible::Grouping, UIA_GroupControlTypeId}, + {QAccessible::Separator, UIA_SeparatorControlTypeId}, + {QAccessible::ToolBar, UIA_ToolBarControlTypeId}, + {QAccessible::StatusBar, UIA_StatusBarControlTypeId}, + {QAccessible::Table, UIA_TableControlTypeId}, + {QAccessible::ColumnHeader, UIA_HeaderControlTypeId}, + {QAccessible::RowHeader, UIA_HeaderControlTypeId}, + {QAccessible::Column, UIA_HeaderItemControlTypeId}, + {QAccessible::Row, UIA_HeaderItemControlTypeId}, + {QAccessible::Cell, UIA_DataItemControlTypeId}, + {QAccessible::Link, UIA_HyperlinkControlTypeId}, + {QAccessible::HelpBalloon, UIA_ToolTipControlTypeId}, + {QAccessible::Assistant, UIA_CustomControlTypeId}, + {QAccessible::List, UIA_ListControlTypeId}, + {QAccessible::ListItem, UIA_ListItemControlTypeId}, + {QAccessible::Tree, UIA_TreeControlTypeId}, + {QAccessible::TreeItem, UIA_TreeItemControlTypeId}, + {QAccessible::PageTab, UIA_TabItemControlTypeId}, + {QAccessible::PropertyPage, UIA_CustomControlTypeId}, + {QAccessible::Indicator, UIA_CustomControlTypeId}, + {QAccessible::Graphic, UIA_ImageControlTypeId}, + {QAccessible::StaticText, UIA_EditControlTypeId}, + {QAccessible::EditableText, UIA_EditControlTypeId}, + {QAccessible::Button, UIA_ButtonControlTypeId}, + {QAccessible::CheckBox, UIA_CheckBoxControlTypeId}, + {QAccessible::RadioButton, UIA_RadioButtonControlTypeId}, + {QAccessible::ComboBox, UIA_ComboBoxControlTypeId}, + {QAccessible::ProgressBar, UIA_ProgressBarControlTypeId}, + {QAccessible::Dial, UIA_CustomControlTypeId}, + {QAccessible::HotkeyField, UIA_CustomControlTypeId}, + {QAccessible::Slider, UIA_SliderControlTypeId}, + {QAccessible::SpinBox, UIA_SpinnerControlTypeId}, + {QAccessible::Canvas, UIA_CustomControlTypeId}, + {QAccessible::Animation, UIA_CustomControlTypeId}, + {QAccessible::Equation, UIA_CustomControlTypeId}, + {QAccessible::ButtonDropDown, UIA_ButtonControlTypeId}, + {QAccessible::ButtonMenu, UIA_ButtonControlTypeId}, + {QAccessible::ButtonDropGrid, UIA_ButtonControlTypeId}, + {QAccessible::Whitespace, UIA_CustomControlTypeId}, + {QAccessible::PageTabList, UIA_TabControlTypeId}, + {QAccessible::Clock, UIA_CustomControlTypeId}, + {QAccessible::Splitter, UIA_CustomControlTypeId}, + }; + + return mapping.value(role, UIA_CustomControlTypeId); +} + +// True if a character can be a separator for a text unit. +bool isTextUnitSeparator(TextUnit unit, const QChar &ch) +{ + return (((unit == TextUnit_Word) || (unit == TextUnit_Format)) && ch.isSpace()) + || ((unit == TextUnit_Line) && (ch.toLatin1() == '\n')); +} + +} // namespace QWindowsUiAutomation + + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h new file mode 100644 index 0000000000..15f4d6e8ba --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAUTILS_H +#define QWINDOWSUIAUTILS_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QWindowsUiAutomation { + +QWindow *windowForAccessible(const QAccessibleInterface *accessible); + +HWND hwndForAccessible(const QAccessibleInterface *accessible); + +void rectToNativeUiaRect(const QRect &rect, const QWindow *w, UiaRect *uiaRect); + +void nativeUiaPointToPoint(const UiaPoint &uiaPoint, const QWindow *w, QPoint *point); + +long roleToControlTypeId(QAccessible::Role role); + +bool isTextUnitSeparator(TextUnit unit, const QChar &ch); + +void clearVariant(VARIANT *variant); + +void setVariantI4(int value, VARIANT *variant); + +void setVariantBool(bool value, VARIANT *variant); + +void setVariantDouble(double value, VARIANT *variant); + +BSTR bStrFromQString(const QString &value); + +void setVariantString(const QString &value, VARIANT *variant); + +} // namespace QWindowsUiAutomation + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIAUTILS_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp new file mode 100644 index 0000000000..ef7d564e22 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiavalueprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaValueProvider::QWindowsUiaValueProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaValueProvider::~QWindowsUiaValueProvider() +{ +} + +// Sets the value associated with the control. +HRESULT STDMETHODCALLTYPE QWindowsUiaValueProvider::SetValue(LPCWSTR val) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + // First sets the value as a text. + QString strVal = QString::fromUtf16(reinterpret_cast(val)); + accessible->setText(QAccessible::Value, strVal); + + // Then, if the control supports the value interface (range value) + // and the supplied text can be converted to a number, and that number + // lies within the min/max limits, sets it as the control's current (numeric) value. + if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { + bool ok = false; + double numval = strVal.toDouble(&ok); + if (ok) { + double minimum = valueInterface->minimumValue().toDouble(); + double maximum = valueInterface->maximumValue().toDouble(); + if ((numval >= minimum) && (numval <= maximum)) { + valueInterface->setCurrentValue(QVariant(numval)); + } + } + } + return S_OK; +} + +// True for read-only controls. +HRESULT STDMETHODCALLTYPE QWindowsUiaValueProvider::get_IsReadOnly(BOOL *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = FALSE; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = accessible->state().readOnly; + return S_OK; +} + +// Returns the value in text form. +HRESULT STDMETHODCALLTYPE QWindowsUiaValueProvider::get_Value(BSTR *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + *pRetVal = bStrFromQString(accessible->text(QAccessible::Value)); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h new file mode 100644 index 0000000000..db54fc0a46 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAVALUEPROVIDER_H +#define QWINDOWSUIAVALUEPROVIDER_H + +#include +#ifndef QT_NO_ACCESSIBILITY + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Value control pattern provider. +// Supported for all controls that can return text(QAccessible::Value). +class QWindowsUiaValueProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase +{ + Q_DISABLE_COPY(QWindowsUiaValueProvider) +public: + explicit QWindowsUiaValueProvider(QAccessible::Id id); + virtual ~QWindowsUiaValueProvider(); + + // IValueProvider + HRESULT STDMETHODCALLTYPE SetValue(LPCWSTR val); + HRESULT STDMETHODCALLTYPE get_IsReadOnly(BOOL *pRetVal); + HRESULT STDMETHODCALLTYPE get_Value(BSTR *pRetVal); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY + +#endif // QWINDOWSUIAVALUEPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/uiautomation.pri b/src/plugins/platforms/windows/uiautomation/uiautomation.pri new file mode 100644 index 0000000000..e3071766d9 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/uiautomation.pri @@ -0,0 +1,43 @@ +qtHaveModule(windowsuiautomation_support-private): \ + QT += windowsuiautomation_support-private + +SOURCES += \ + $$PWD/qwindowsuiaaccessibility.cpp \ + $$PWD/qwindowsuiaprovidercache.cpp \ + $$PWD/qwindowsuiamainprovider.cpp \ + $$PWD/qwindowsuiabaseprovider.cpp \ + $$PWD/qwindowsuiavalueprovider.cpp \ + $$PWD/qwindowsuiatextprovider.cpp \ + $$PWD/qwindowsuiatextrangeprovider.cpp \ + $$PWD/qwindowsuiatoggleprovider.cpp \ + $$PWD/qwindowsuiaselectionprovider.cpp \ + $$PWD/qwindowsuiaselectionitemprovider.cpp \ + $$PWD/qwindowsuiainvokeprovider.cpp \ + $$PWD/qwindowsuiarangevalueprovider.cpp \ + $$PWD/qwindowsuiatableprovider.cpp \ + $$PWD/qwindowsuiatableitemprovider.cpp \ + $$PWD/qwindowsuiagridprovider.cpp \ + $$PWD/qwindowsuiagriditemprovider.cpp \ + $$PWD/qwindowsuiautils.cpp + +HEADERS += \ + $$PWD/qwindowsuiaaccessibility.h \ + $$PWD/qwindowsuiaprovidercache.h \ + $$PWD/qwindowsuiamainprovider.h \ + $$PWD/qwindowsuiabaseprovider.h \ + $$PWD/qwindowsuiavalueprovider.h \ + $$PWD/qwindowsuiatextprovider.h \ + $$PWD/qwindowsuiatextrangeprovider.h \ + $$PWD/qwindowsuiatoggleprovider.h \ + $$PWD/qwindowsuiaselectionprovider.h \ + $$PWD/qwindowsuiaselectionitemprovider.h \ + $$PWD/qwindowsuiainvokeprovider.h \ + $$PWD/qwindowsuiarangevalueprovider.h \ + $$PWD/qwindowsuiatableprovider.h \ + $$PWD/qwindowsuiatableitemprovider.h \ + $$PWD/qwindowsuiagridprovider.h \ + $$PWD/qwindowsuiagriditemprovider.h \ + $$PWD/qwindowsuiautils.h + +mingw: LIBS *= -luuid + -- cgit v1.2.3