diff options
Diffstat (limited to 'src/plugins/platforms/winrt')
70 files changed, 6202 insertions, 112 deletions
diff --git a/src/plugins/platforms/winrt/main.cpp b/src/plugins/platforms/winrt/main.cpp index 222287b3ef..a37bd1e3d8 100644 --- a/src/plugins/platforms/winrt/main.cpp +++ b/src/plugins/platforms/winrt/main.cpp @@ -58,7 +58,7 @@ QPlatformIntegration *QWinRTIntegrationPlugin::create(const QString& system, con if (!system.compare(QLatin1String("winrt"), Qt::CaseInsensitive)) return QWinRTIntegration::create(); - return 0; + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp index 113886f9b4..c23d48b2dd 100644 --- a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp @@ -50,9 +50,6 @@ QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(lcQpaBackingStore, "qt.qpa.backingstore") -Q_LOGGING_CATEGORY(lcQpaBackingStoreVerbose, "qt.qpa.backingstore.verbose") - class QWinRTBackingStorePrivate { public: @@ -68,7 +65,7 @@ QWinRTBackingStore::QWinRTBackingStore(QWindow *window) : QPlatformBackingStore(window), d_ptr(new QWinRTBackingStorePrivate) { Q_D(QWinRTBackingStore); - qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window; + qCInfo(lcQpaBackingStore) << __FUNCTION__ << this << window; d->initialized = false; d->screen = static_cast<QWinRTScreen*>(window->screen()->handle()); @@ -80,7 +77,7 @@ QWinRTBackingStore::QWinRTBackingStore(QWindow *window) bool QWinRTBackingStore::initialize() { Q_D(QWinRTBackingStore); - qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << d->initialized; + qCDebug(lcQpaBackingStore) << __FUNCTION__ << d->initialized; if (d->initialized) return true; @@ -102,7 +99,7 @@ bool QWinRTBackingStore::initialize() QWinRTBackingStore::~QWinRTBackingStore() { - qCDebug(lcQpaBackingStore) << __FUNCTION__ << this; + qCInfo(lcQpaBackingStore) << __FUNCTION__ << this; } QPaintDevice *QWinRTBackingStore::paintDevice() @@ -116,16 +113,19 @@ void QWinRTBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo Q_D(QWinRTBackingStore); Q_UNUSED(offset) - qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << this << window << region; + qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << region; if (d->size.isEmpty()) return; + const QRect bounds = region.boundingRect() & d->paintDevice.rect(); + if (bounds.isEmpty()) + return; + const bool ok = d->context->makeCurrent(window); if (!ok) qWarning("unable to flush"); - const QRect bounds = region.boundingRect(); glBindTexture(GL_TEXTURE_2D, d->fbo->texture()); // TODO: when ANGLE GLES3 support is finished, use the glPixelStorei functions to minimize upload glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.y(), d->size.width(), bounds.height(), @@ -151,7 +151,7 @@ void QWinRTBackingStore::resize(const QSize &size, const QRegion &staticContents Q_D(QWinRTBackingStore); Q_UNUSED(staticContents) - qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << this << size; + qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << size; if (!initialize()) return; @@ -182,14 +182,14 @@ QImage QWinRTBackingStore::toImage() const void QWinRTBackingStore::beginPaint(const QRegion ®ion) { - qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << this << region; + qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << region; resize(window()->size(), region); } void QWinRTBackingStore::endPaint() { - qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << this; + qCDebug(lcQpaBackingStore) << __FUNCTION__ << this; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.h b/src/plugins/platforms/winrt/qwinrtbackingstore.h index cd05faa63e..b62d340b82 100644 --- a/src/plugins/platforms/winrt/qwinrtbackingstore.h +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.h @@ -47,9 +47,6 @@ QT_BEGIN_NAMESPACE -Q_DECLARE_LOGGING_CATEGORY(lcQpaBackingStore) -Q_DECLARE_LOGGING_CATEGORY(lcQpaBackingStoreVerbose) - class QWinRTScreen; class QWinRTBackingStorePrivate; @@ -57,7 +54,7 @@ class QWinRTBackingStore : public QPlatformBackingStore { public: explicit QWinRTBackingStore(QWindow *window); - ~QWinRTBackingStore(); + ~QWinRTBackingStore() override; QPaintDevice *paintDevice() override; void beginPaint(const QRegion &) override; void endPaint() override; diff --git a/src/plugins/platforms/winrt/qwinrtcanvas.cpp b/src/plugins/platforms/winrt/qwinrtcanvas.cpp new file mode 100644 index 0000000000..dd6b52d9cd --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtcanvas.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "qwinrtcanvas.h" +#include "uiautomation/qwinrtuiaaccessibility.h" +#include "uiautomation/qwinrtuiamainprovider.h" +#include "uiautomation/qwinrtuiametadatacache.h" +#include "uiautomation/qwinrtuiautils.h" + +#include <QtCore/QLoggingCategory> +#include <QtCore/qfunctions_winrt.h> + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::System; +using namespace ABI::Windows::UI; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; + +QT_BEGIN_NAMESPACE + +QWinRTCanvas::QWinRTCanvas(const std::function<QWindow*()> &delegateWindow) +{ + ComPtr<Xaml::Controls::ICanvasFactory> factory; + HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), IID_PPV_ARGS(&factory)); + Q_ASSERT_SUCCEEDED(hr); + + hr = factory->CreateInstance(this, &m_base, &m_core); + Q_ASSERT_SUCCEEDED(hr); + + delegate = delegateWindow; +} + +HRESULT STDMETHODCALLTYPE QWinRTCanvas::QueryInterface(REFIID iid, LPVOID *iface) +{ + if (!iface) + return E_POINTER; + *iface = nullptr; + + if (iid == IID_IUnknown) { + *iface = static_cast<Xaml::IUIElementOverrides *>(this); + AddRef(); + return S_OK; + } else if (iid == Xaml::IID_IUIElementOverrides) { + *iface = static_cast<Xaml::IUIElementOverrides *>(this); + AddRef(); + return S_OK; + } else { + return m_base.CopyTo(iid, iface); + } +} + +HRESULT STDMETHODCALLTYPE QWinRTCanvas::GetIids(ULONG *iidCount, IID **iids) +{ + *iidCount = 0; + *iids = nullptr; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTCanvas::GetRuntimeClassName(HSTRING *className) +{ + const wchar_t *name = L"QWinRTCanvas"; + return ::WindowsCreateString(name, static_cast<UINT32>(::wcslen(name)), className); +} + +HRESULT STDMETHODCALLTYPE QWinRTCanvas::GetTrustLevel(TrustLevel *trustLevel) +{ + *trustLevel = TrustLevel::BaseTrust; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTCanvas::OnCreateAutomationPeer(Xaml::Automation::Peers::IAutomationPeer **returnValue) +{ + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + + if (delegate) { + if (QWindow *window = delegate()) { + QWinRTUiaAccessibility::activate(); + if (QAccessibleInterface *accessible = window->accessibleRoot()) { + QAccessible::Id accid = QWinRTUiAutomation::idForAccessible(accessible); + QWinRTUiaMetadataCache::instance()->load(accid); + if (ComPtr<QWinRTUiaMainProvider> provider = QWinRTUiaMainProvider::providerForAccessibleId(accid)) + return provider.CopyTo(returnValue); + } + } + } + return m_base->OnCreateAutomationPeer(returnValue); +} + +HRESULT STDMETHODCALLTYPE QWinRTCanvas::OnDisconnectVisualChildren() +{ + return m_base->OnDisconnectVisualChildren(); +} + +HRESULT STDMETHODCALLTYPE QWinRTCanvas::FindSubElementsForTouchTargeting(Point point, Rect boundingRect, IIterable<IIterable<ABI::Windows::Foundation::Point>*> **returnValue) +{ + return m_base->FindSubElementsForTouchTargeting(point, boundingRect, returnValue); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/winrt/qwinrtcanvas.h b/src/plugins/platforms/winrt/qwinrtcanvas.h new file mode 100644 index 0000000000..bc3b708ac2 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtcanvas.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTCANVAS_H +#define QWINRTCANVAS_H + +#include <QtCore/qglobal.h> +#include <QtGui/QWindow> + +#include <wrl.h> +#include <windows.ui.xaml.h> +#include <functional> + +QT_BEGIN_NAMESPACE + +class QWinRTCanvas: + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::IUIElementOverrides> +{ +public: + QWinRTCanvas(const std::function<QWindow*()> &delegateWindow); + ~QWinRTCanvas() override = default; + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *iface) override; + HRESULT STDMETHODCALLTYPE GetIids(ULONG *iidCount, IID **iids) override; + HRESULT STDMETHODCALLTYPE GetRuntimeClassName(HSTRING *className) override; + HRESULT STDMETHODCALLTYPE GetTrustLevel(TrustLevel *trustLevel) override; + HRESULT STDMETHODCALLTYPE OnCreateAutomationPeer(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **returnValue) override; + HRESULT STDMETHODCALLTYPE OnDisconnectVisualChildren() override; + HRESULT STDMETHODCALLTYPE FindSubElementsForTouchTargeting(ABI::Windows::Foundation::Point point, ABI::Windows::Foundation::Rect boundingRect, ABI::Windows::Foundation::Collections::IIterable<ABI::Windows::Foundation::Collections::IIterable<ABI::Windows::Foundation::Point>*> **returnValue) override; + +private: + Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElementOverrides> m_base; + Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Controls::ICanvas> m_core; + std::function<QWindow*()> delegate; +}; + +QT_END_NAMESPACE + +#endif // QWINRTCANVAS_H diff --git a/src/plugins/platforms/winrt/qwinrtclipboard.cpp b/src/plugins/platforms/winrt/qwinrtclipboard.cpp index 05c34b82f8..fd0ed8aed2 100644 --- a/src/plugins/platforms/winrt/qwinrtclipboard.cpp +++ b/src/plugins/platforms/winrt/qwinrtclipboard.cpp @@ -99,7 +99,7 @@ QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode) quint32 size; const wchar_t *textStr = result.GetRawBuffer(&size); - QString text = QString::fromWCharArray(textStr, size); + QString text = QString::fromWCharArray(textStr, int(size)); text.replace(QLatin1String("\r\n"), QLatin1String("\n")); if (m_mimeData) { @@ -161,7 +161,8 @@ void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) &package); const QString nativeString = convertToWindowsLineEnding(text); - HStringReference textRef(reinterpret_cast<LPCWSTR>(nativeString.utf16()), nativeString.length()); + HStringReference textRef(reinterpret_cast<LPCWSTR>(nativeString.utf16()), + uint(nativeString.length())); hr = package->SetText(textRef.Get()); RETURN_HR_IF_FAILED("Could not set text to clipboard data package."); diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp index 3c918df935..180905945b 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.cpp +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -56,6 +56,11 @@ using namespace ABI::Windows::Foundation; QT_BEGIN_NAMESPACE +static inline bool qIsPointInRect(const Point &p, const Rect &r) +{ + return (p.X >= r.X && p.Y >= r.Y && p.X < r.X + r.Width && p.Y < r.Y + r.Height); +} + class QWinRTCursorPrivate { public: @@ -73,10 +78,6 @@ QWinRTCursor::QWinRTCursor() Q_ASSERT_SUCCEEDED(hr); } -QWinRTCursor::~QWinRTCursor() -{ -} - #ifndef QT_NO_CURSOR void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) { @@ -169,14 +170,60 @@ QPoint QWinRTCursor::pos() const ICoreWindow *coreWindow = screen->coreWindow(); Q_ASSERT(coreWindow); Point point; - HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &point]() { - return coreWindow->get_PointerPosition(&point); + Rect bounds; + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &point, &bounds]() { + HRESULT hr = coreWindow->get_PointerPosition(&point); + RETURN_HR_IF_FAILED("Failed to obtain pointer position."); + hr = coreWindow->get_Bounds(&bounds); + RETURN_HR_IF_FAILED("Failed to obtain window bounds."); + return hr; }); Q_ASSERT_SUCCEEDED(hr); - const QPoint position = QPoint(point.X, point.Y) * screen->scaleFactor(); + QPointF position(qreal(point.X), qreal(point.Y)); // If no cursor get_PointerPosition returns SHRT_MIN for x and y - return position.x() == SHRT_MIN && position.y() == SHRT_MIN || FAILED(hr) ? QPointF(Q_INFINITY, Q_INFINITY).toPoint() - : position; + if ((int(position.x()) == SHRT_MIN && int(position.y()) == SHRT_MIN) + || FAILED(hr)) + return QPointF(Q_INFINITY, Q_INFINITY).toPoint(); + position.rx() -= qreal(bounds.X); + position.ry() -= qreal(bounds.Y); + position *= screen->scaleFactor(); + return position.toPoint(); +} + +void QWinRTCursor::setPos(const QPoint &pos) +{ + QWinRTScreen *screen = static_cast<QWinRTScreen *>(QGuiApplication::primaryScreen()->handle()); + Q_ASSERT(screen); + ComPtr<ICoreWindow> coreWindow = screen->coreWindow(); + Q_ASSERT(coreWindow); + const QPointF scaledPos = QPointF(pos) / screen->scaleFactor(); + QWinRTScreen::MousePositionTransition t; + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, scaledPos, &t]() { + ComPtr<ICoreWindow2> coreWindow2; + HRESULT hr = coreWindow.As(&coreWindow2); + RETURN_HR_IF_FAILED("Failed to cast core window."); + Rect bounds; + hr = coreWindow->get_Bounds(&bounds); + RETURN_HR_IF_FAILED("Failed to obtain window bounds."); + Point mousePos; + hr = coreWindow->get_PointerPosition(&mousePos); + RETURN_HR_IF_FAILED("Failed to obtain mouse position."); + const Point p = { FLOAT(scaledPos.x()) + bounds.X, + FLOAT(scaledPos.y()) + bounds.Y }; + const bool wasInWindow = qIsPointInRect(mousePos, bounds); + const bool willBeInWindow = qIsPointInRect(p, bounds); + if (wasInWindow && willBeInWindow) + t = QWinRTScreen::MousePositionTransition::StayedIn; + else if (wasInWindow && !willBeInWindow) + t = QWinRTScreen::MousePositionTransition::MovedOut; + else if (!wasInWindow && willBeInWindow) + t = QWinRTScreen::MousePositionTransition::MovedIn; + else + t = QWinRTScreen::MousePositionTransition::StayedOut; + return coreWindow2->put_PointerPosition(p); + }); + RETURN_VOID_IF_FAILED("Failed to set cursor position"); + screen->emulateMouseMove(scaledPos, t); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtcursor.h b/src/plugins/platforms/winrt/qwinrtcursor.h index 7f579f1531..eca3d8c7ca 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.h +++ b/src/plugins/platforms/winrt/qwinrtcursor.h @@ -49,11 +49,12 @@ class QWinRTCursor : public QPlatformCursor { public: explicit QWinRTCursor(); - ~QWinRTCursor(); + ~QWinRTCursor() override = default; #ifndef QT_NO_CURSOR void changeCursor(QCursor * windowCursor, QWindow *window) override; #endif QPoint pos() const override; + void setPos(const QPoint &pos) override; private: QScopedPointer<QWinRTCursorPrivate> d_ptr; diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp index 0c918230b3..3ed4cd692d 100644 --- a/src/plugins/platforms/winrt/qwinrtdrag.cpp +++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp @@ -81,7 +81,7 @@ ComPtr<IBuffer> createIBufferFromData(const char *data, qint32 size) } ComPtr<IBuffer> buffer; - const UINT32 length = size; + const UINT32 length = UINT32(size); hr = bufferFactory->Create(length, &buffer); Q_ASSERT_SUCCEEDED(hr); hr = buffer->put_Length(length); @@ -118,13 +118,13 @@ inline QString hStringToQString(const HString &hString) { quint32 l; const wchar_t *raw = hString.GetRawBuffer(&l); - return (QString::fromWCharArray(raw, l)); + return (QString::fromWCharArray(raw, int(l))); } inline HString qStringToHString(const QString &qString) { HString h; - h.Set(reinterpret_cast<const wchar_t*>(qString.utf16()), qString.size()); + h.Set(reinterpret_cast<const wchar_t*>(qString.utf16()), uint(qString.size())); return h; } @@ -184,10 +184,6 @@ QWinRTInternalMimeData::QWinRTInternalMimeData() } } -QWinRTInternalMimeData::~QWinRTInternalMimeData() -{ -} - bool QWinRTInternalMimeData::hasFormat_sys(const QString &mimetype) const { qCDebug(lcQpaMime) << __FUNCTION__ << mimetype; @@ -311,7 +307,7 @@ QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVari ComPtr<IAsyncOperation<IInspectable*>> op; ComPtr<IInspectable> res; HString type; - type.Set(reinterpret_cast<const wchar_t*>(mimetype.utf16()), mimetype.size()); + type.Set(reinterpret_cast<const wchar_t*>(mimetype.utf16()), uint(mimetype.size())); hr = dataView->GetDataAsync(type.Get(), &op); RETURN_OK_IF_FAILED("Could not query custom drag data."); hr = QWinRTFunctions::await(op, res.GetAddressOf()); @@ -434,7 +430,7 @@ QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVari IID_PPV_ARGS(&bufferFactory)); Q_ASSERT_SUCCEEDED(hr); - UINT32 length = qBound(quint64(0), quint64(size), quint64(UINT_MAX)); + UINT32 length = UINT32(qBound(quint64(0), quint64(size), quint64(UINT_MAX))); ComPtr<IBuffer> buffer; hr = bufferFactory->Create(length, &buffer); Q_ASSERT_SUCCEEDED(hr); @@ -452,7 +448,7 @@ QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVari byte *bytes; hr = byteArrayAccess->Buffer(&bytes); - QByteArray array((char *)bytes, length); + QByteArray array((char *)bytes, int(length)); result.setValue(array); return S_OK; } @@ -559,7 +555,7 @@ extern ComPtr<ABI::Windows::UI::Input::IPointerPoint> qt_winrt_lastPointerPoint; QWinRTDrag::QWinRTDrag() : QPlatformDrag() - , m_dragTarget(0) + , m_dragTarget(nullptr) { qCDebug(lcQpaMime) << __FUNCTION__; m_enter = new Q_INST_DRAGHANDLER(Enter); @@ -612,7 +608,7 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) ComPtr<IAsyncOperation<ABI::Windows::ApplicationModel::DataTransfer::DataPackageOperation>> op; EventRegistrationToken startingToken; - hr = QEventDispatcherWinRT::runOnXamlThread([drag, &op, &hr, elem3, &startingToken, this]() { + hr = QEventDispatcherWinRT::runOnXamlThread([drag, &op, &hr, elem3, &startingToken]() { hr = elem3->put_CanDrag(true); Q_ASSERT_SUCCEEDED(hr); @@ -660,7 +656,8 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) const QImage image = image2.convertToFormat(QImage::Format_ARGB32); if (!image.isNull()) { // Create IBuffer containing image - ComPtr<IBuffer> imageBuffer = createIBufferFromData(reinterpret_cast<const char*>(image.bits()), image.byteCount()); + ComPtr<IBuffer> imageBuffer + = createIBufferFromData(reinterpret_cast<const char*>(image.bits()), int(image.sizeInBytes())); ComPtr<ISoftwareBitmapFactory> bitmapFactory; hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Imaging_SoftwareBitmap).Get(), @@ -697,7 +694,7 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag) hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), &ras); Q_ASSERT_SUCCEEDED(hr); - hr = ras->put_Size(data.size()); + hr = ras->put_Size(UINT64(data.size())); ComPtr<IOutputStream> outputStream; hr = ras->GetOutputStreamAt(0, &outputStream); Q_ASSERT_SUCCEEDED(hr); @@ -802,7 +799,7 @@ void QWinRTDrag::handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::X Point relativePoint; hr = e->GetPosition(m_ui.Get(), &relativePoint); RETURN_VOID_IF_FAILED("Could not query drag position."); - const QPoint p(relativePoint.X, relativePoint.Y); + const QPoint p(int(relativePoint.X), int(relativePoint.Y)); ComPtr<IDragEventArgs2> e2; hr = e->QueryInterface(IID_PPV_ARGS(&e2)); diff --git a/src/plugins/platforms/winrt/qwinrtdrag.h b/src/plugins/platforms/winrt/qwinrtdrag.h index 3868c9f015..ab57999bba 100644 --- a/src/plugins/platforms/winrt/qwinrtdrag.h +++ b/src/plugins/platforms/winrt/qwinrtdrag.h @@ -77,7 +77,7 @@ class QWinRTInternalMimeData; class QWinRTInternalMimeData : public QInternalMimeData { public: QWinRTInternalMimeData(); - virtual ~QWinRTInternalMimeData(); + ~QWinRTInternalMimeData() override = default; bool hasFormat_sys(const QString &mimetype) const override; QStringList formats_sys() const override; @@ -92,7 +92,7 @@ private: class QWinRTDrag : public QPlatformDrag { public: QWinRTDrag(); - virtual ~QWinRTDrag(); + ~QWinRTDrag() override; static QWinRTDrag *instance(); Qt::DropAction drag(QDrag *) override; diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h index 325dc82c40..8dbd0fc7d0 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.h +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -50,7 +50,7 @@ class QWinRTEGLContext : public QPlatformOpenGLContext { public: explicit QWinRTEGLContext(QOpenGLContext *context); - ~QWinRTEGLContext(); + ~QWinRTEGLContext() override; void initialize() override; diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.h b/src/plugins/platforms/winrt/qwinrteventdispatcher.h index 4c5c19c6b0..61c824f0a9 100644 --- a/src/plugins/platforms/winrt/qwinrteventdispatcher.h +++ b/src/plugins/platforms/winrt/qwinrteventdispatcher.h @@ -48,7 +48,7 @@ class QWinRTEventDispatcher : public QEventDispatcherWinRT { Q_OBJECT public: - explicit QWinRTEventDispatcher(QObject *parent = 0); + explicit QWinRTEventDispatcher(QObject *parent = nullptr); protected: bool hasPendingEvents() override; diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp index 3c90334c8c..114d6dacd8 100644 --- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp @@ -51,7 +51,7 @@ #include <wrl.h> #include <windows.foundation.h> #include <windows.storage.pickers.h> -#include <Windows.ApplicationModel.activation.h> +#include <Windows.Applicationmodel.Activation.h> using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -73,12 +73,12 @@ class WindowsStringVector : public RuntimeClass<IVector<HSTRING>> public: HRESULT __stdcall GetAt(quint32 index, HSTRING *item) { - *item = impl.at(index); + *item = impl.at(int(index)); return S_OK; } HRESULT __stdcall get_Size(quint32 *size) { - *size = impl.size(); + *size = quint32(impl.size()); return S_OK; } HRESULT __stdcall GetView(IVectorView<HSTRING> **view) @@ -108,7 +108,7 @@ public: HRESULT hr = WindowsDuplicateString(item, &newItem); if (FAILED(hr)) return hr; - impl[index] = newItem; + impl[int(index)] = newItem; return S_OK; } HRESULT __stdcall InsertAt(quint32 index, HSTRING item) @@ -117,12 +117,12 @@ public: HRESULT hr = WindowsDuplicateString(item, &newItem); if (FAILED(hr)) return hr; - impl.insert(index, newItem); + impl.insert(int(index), newItem); return S_OK; } HRESULT __stdcall RemoveAt(quint32 index) { - WindowsDeleteString(impl.takeAt(index)); + WindowsDeleteString(impl.takeAt(int(index))); return S_OK; } HRESULT __stdcall Append(HSTRING item) @@ -164,7 +164,7 @@ static bool initializePicker(HSTRING runtimeId, T **picker, const QSharedPointer if (options->isLabelExplicitlySet(QFileDialogOptions::Accept)) { const QString labelText = options->labelText(QFileDialogOptions::Accept); HStringReference labelTextRef(reinterpret_cast<const wchar_t *>(labelText.utf16()), - labelText.length()); + uint(labelText.length())); hr = (*picker)->put_CommitButtonText(labelTextRef.Get()); RETURN_FALSE_IF_FAILED("Failed to set commit button text"); } @@ -188,7 +188,7 @@ static bool initializeOpenPickerOptions(T *picker, const QSharedPointer<QFileDia // Remove leading star const int offset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0; HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + offset), - filter.length() - offset); + uint(filter.length() - offset)); hr = filters->Append(filterRef.Get()); if (FAILED(hr)) { qWarning("Failed to add named file filter \"%s\": %s", @@ -290,16 +290,12 @@ QWinRTFileDialogHelper::QWinRTFileDialogHelper() d->shown = false; } -QWinRTFileDialogHelper::~QWinRTFileDialogHelper() -{ -} - void QWinRTFileDialogHelper::exec() { Q_D(QWinRTFileDialogHelper); if (!d->shown) - show(Qt::Dialog, Qt::ApplicationModal, 0); + show(Qt::Dialog, Qt::ApplicationModal, nullptr); d->loop.exec(); } @@ -369,7 +365,7 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit // Remove leading star const int starOffset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0; HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + starOffset), - filter.length() - starOffset); + uint(filter.length() - starOffset)); hr = entry->Append(filterRef.Get()); if (FAILED(hr)) { qWarning("Failed to add named file filter \"%s\": %s", @@ -379,7 +375,7 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit const int offset = namedFilter.indexOf(QLatin1String(" (")); const QString filterTitle = namedFilter.mid(0, offset); HStringReference namedFilterRef(reinterpret_cast<const wchar_t *>(filterTitle.utf16()), - filterTitle.length()); + uint(filterTitle.length())); boolean replaced; hr = choices->Insert(namedFilterRef.Get(), entry.Get(), &replaced); // Only print a warning as * or *.* is not a valid choice on Windows 10 @@ -396,7 +392,7 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit if (!suffix.startsWith(QLatin1Char('.'))) suffix.prepend(QLatin1Char('.')); HStringReference nativeSuffix(reinterpret_cast<const wchar_t *>(suffix.utf16()), - suffix.length()); + uint(suffix.length())); hr = picker->put_DefaultFileExtension(nativeSuffix.Get()); RETURN_FALSE_IF_FAILED_WITH_ARGS("Failed to set default file extension \"%s\"", qPrintable(suffix)); } @@ -404,7 +400,7 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit const QString suggestedName = QFileInfo(d->saveFileName.toLocalFile()).fileName(); if (!suggestedName.isEmpty()) { HStringReference nativeSuggestedName(reinterpret_cast<const wchar_t *>(suggestedName.utf16()), - suggestedName.length()); + uint(suggestedName.length())); hr = picker->put_SuggestedFileName(nativeSuggestedName.Get()); RETURN_FALSE_IF_FAILED("Failed to set suggested file name"); } diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h index 99239aad3a..994d099dcf 100644 --- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h @@ -70,7 +70,7 @@ class QWinRTFileDialogHelper : public QPlatformFileDialogHelper Q_OBJECT public: explicit QWinRTFileDialogHelper(); - ~QWinRTFileDialogHelper(); + ~QWinRTFileDialogHelper() override = default; void exec() override; bool show(Qt::WindowFlags, Qt::WindowModality, QWindow *) override; diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp index 76efdf6cc8..3014b30c38 100644 --- a/src/plugins/platforms/winrt/qwinrtfileengine.cpp +++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp @@ -122,10 +122,6 @@ QWinRTFileEngineHandler::QWinRTFileEngineHandler() { } -QWinRTFileEngineHandler::~QWinRTFileEngineHandler() -{ -} - void QWinRTFileEngineHandler::registerFile(const QString &fileName, IStorageItem *file) { handlerInstance->d_func()->files.insert(QDir::cleanPath(fileName), file); @@ -168,7 +164,7 @@ static HRESULT getDestinationFolder(const QString &fileName, const QString &newF const QString newFilePath = QDir::toNativeSeparators(newFileInfo.absolutePath()); HStringReference nativeNewFilePath(reinterpret_cast<LPCWSTR>(newFilePath.utf16()), - newFilePath.length()); + uint(newFilePath.length())); hr = folderFactory->GetFolderFromPathAsync(nativeNewFilePath.Get(), &op); } if (FAILED(hr)) @@ -181,10 +177,6 @@ QWinRTFileEngine::QWinRTFileEngine(const QString &fileName, IStorageItem *file) { } -QWinRTFileEngine::~QWinRTFileEngine() -{ -} - bool QWinRTFileEngine::open(QIODevice::OpenMode openMode) { Q_D(QWinRTFileEngine); @@ -278,7 +270,7 @@ bool QWinRTFileEngine::seek(qint64 pos) if (!d->stream) return false; - HRESULT hr = d->stream->Seek(pos); + HRESULT hr = d->stream->Seek(UINT64(pos)); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::PositionError, false); d->pos = pos; return SUCCEEDED(hr); @@ -311,7 +303,8 @@ bool QWinRTFileEngine::copy(const QString &newName) RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false); const QString destinationName = QFileInfo(newName).fileName(); - HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length()); + HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), + uint(destinationName.length())); ComPtr<IAsyncOperation<StorageFile *>> op; hr = file->CopyOverloadDefaultOptions(destinationFolder.Get(), nativeDestinationName.Get(), &op); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false); @@ -332,7 +325,8 @@ bool QWinRTFileEngine::rename(const QString &newName) RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false); const QString destinationName = QFileInfo(newName).fileName(); - HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length()); + HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), + uint(destinationName.length())); ComPtr<IAsyncAction> op; hr = d->file->RenameAsyncOverloadDefaultOptions(nativeDestinationName.Get(), &op); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false); @@ -349,7 +343,8 @@ bool QWinRTFileEngine::renameOverwrite(const QString &newName) RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false); const QString destinationName = QFileInfo(newName).fileName(); - HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length()); + HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), + uint(destinationName.length())); ComPtr<IAsyncAction> op; hr = d->file->RenameAsync(nativeDestinationName.Get(), NameCollisionOption_ReplaceExisting, &op); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false); @@ -451,7 +446,7 @@ qint64 QWinRTFileEngine::read(char *data, qint64 maxlen) HRESULT hr = d->stream.As(&stream); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); - UINT32 length = qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX)); + UINT32 length = UINT32(qBound(quint64(0), quint64(maxlen), quint64(UINT32_MAX))); ComPtr<IBuffer> buffer; hr = d->bufferFactory->Create(length, &buffer); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); @@ -494,7 +489,7 @@ qint64 QWinRTFileEngine::write(const char *data, qint64 maxlen) HRESULT hr = d->stream.As(&stream); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); - UINT32 length = qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX)); + UINT32 length = UINT32(qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX))); ComPtr<IBuffer> buffer; hr = d->bufferFactory->Create(length, &buffer); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1); diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.h b/src/plugins/platforms/winrt/qwinrtfileengine.h index 73ff54b0c8..4485917c9e 100644 --- a/src/plugins/platforms/winrt/qwinrtfileengine.h +++ b/src/plugins/platforms/winrt/qwinrtfileengine.h @@ -57,7 +57,7 @@ class QWinRTFileEngineHandler : public QAbstractFileEngineHandler { public: QWinRTFileEngineHandler(); - ~QWinRTFileEngineHandler(); + ~QWinRTFileEngineHandler() override = default; QAbstractFileEngine *create(const QString &fileName) const override; static void registerFile(const QString &fileName, ABI::Windows::Storage::IStorageItem *file); @@ -73,7 +73,7 @@ class QWinRTFileEngine : public QAbstractFileEngine { public: QWinRTFileEngine(const QString &fileName, ABI::Windows::Storage::IStorageItem *file); - ~QWinRTFileEngine(); + ~QWinRTFileEngine() override = default; bool open(QIODevice::OpenMode openMode) override; bool close() override; diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp index 63e5b0cf27..f7e91bb047 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp @@ -64,8 +64,8 @@ inline QRectF getInputPaneRect(ComPtr<IInputPane> pane, qreal scaleFactor) { Rect rect; pane->get_OccludedRect(&rect); - return QRectF(qRound(rect.X * scaleFactor), qRound(rect.Y * scaleFactor), - qRound(rect.Width * scaleFactor), qRound(rect.Height * scaleFactor)); + return QRectF(qRound(qreal(rect.X) * scaleFactor), qRound(qreal(rect.Y) * scaleFactor), + qRound(qreal(rect.Width) * scaleFactor), qRound(qreal(rect.Height) * scaleFactor)); } /*! @@ -205,6 +205,8 @@ void QWinRTInputContext::showInputPanel() void QWinRTInputContext::hideInputPanel() { qCDebug(lcQpaInputMethods) << __FUNCTION__; + if (!m_isInputPanelVisible) + return; QEventDispatcherWinRT::runOnXamlThread([&]() { ComPtr<IInputPane2> inputPane; diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index c52207d23b..4f37583bed 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -50,6 +50,9 @@ #if QT_CONFIG(draganddrop) #include "qwinrtdrag.h" #endif +#if QT_CONFIG(accessibility) +# include "uiautomation/qwinrtuiaaccessibility.h" +#endif #include <QtGui/QOffscreenSurface> #include <QtGui/QOpenGLContext> @@ -119,6 +122,9 @@ public: QPlatformClipboard *clipboard; QWinRTScreen *mainScreen; QScopedPointer<QWinRTInputContext> inputContext; +#if QT_CONFIG(accessibility) + QWinRTUiaAccessibility *accessibility; +#endif ComPtr<ICoreApplication> application; QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens; @@ -198,6 +204,9 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) screenAdded(d->mainScreen); d->platformServices = new QWinRTServices; d->clipboard = new QWinRTClipboard; +#if QT_CONFIG(accessibility) + d->accessibility = new QWinRTUiaAccessibility; +#endif } QWinRTIntegration::~QWinRTIntegration() @@ -315,6 +324,14 @@ QPlatformDrag *QWinRTIntegration::drag() const } #endif // QT_CONFIG(draganddrop) +#if QT_CONFIG(accessibility) +QPlatformAccessibility *QWinRTIntegration::accessibility() const +{ + Q_D(const QWinRTIntegration); + return d->accessibility; +} +#endif // QT_CONFIG(accessibility) + Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const { Q_D(const QWinRTIntegration); diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h index d1a9b7edbd..636e594b4b 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.h +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -75,7 +75,7 @@ class QWinRTIntegration : public QPlatformIntegration private: explicit QWinRTIntegration(); public: - ~QWinRTIntegration(); + ~QWinRTIntegration() override; static QWinRTIntegration *create() { @@ -100,6 +100,9 @@ public: #if QT_CONFIG(draganddrop) QPlatformDrag *drag() const override; #endif +#if QT_CONFIG(accessibility) + QPlatformAccessibility *accessibility() const override; +#endif Qt::KeyboardModifiers queryKeyboardModifiers() const override; diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp index d69c63e9a4..7016b47f7e 100644 --- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp @@ -99,7 +99,7 @@ void QWinRTMessageDialogHelper::exec() Q_D(QWinRTMessageDialogHelper); if (!d->shown) - show(Qt::Dialog, Qt::ApplicationModal, 0); + show(Qt::Dialog, Qt::ApplicationModal, nullptr); d->loop.exec(); } @@ -134,9 +134,11 @@ bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModa RETURN_FALSE_IF_FAILED("Failed to create command factory"); ComPtr<IMessageDialog> dialog; - HStringReference nativeText(reinterpret_cast<LPCWSTR>(text.utf16()), text.size()); + HStringReference nativeText(reinterpret_cast<LPCWSTR>(text.utf16()), + uint(text.size())); if (!title.isEmpty()) { - HStringReference nativeTitle(reinterpret_cast<LPCWSTR>(title.utf16()), title.size()); + HStringReference nativeTitle(reinterpret_cast<LPCWSTR>(title.utf16()), + uint(title.size())); hr = dialogFactory->CreateWithTitle(nativeText.Get(), nativeTitle.Get(), &dialog); RETURN_FALSE_IF_FAILED("Failed to create dialog with title"); } else { @@ -162,7 +164,8 @@ bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModa continue; // Add native command const QString label = d->theme->standardButtonText(i); - HStringReference nativeLabel(reinterpret_cast<LPCWSTR>(label.utf16()), label.size()); + HStringReference nativeLabel(reinterpret_cast<LPCWSTR>(label.utf16()), + uint(label.size())); ComPtr<IUICommand> command; hr = commandFactory->Create(nativeLabel.Get(), &command); RETURN_HR_IF_FAILED("Failed to create message box command"); diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h index 14b6d4b715..ab704b1c7d 100644 --- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h @@ -67,7 +67,7 @@ class QWinRTMessageDialogHelper : public QPlatformMessageDialogHelper Q_OBJECT public: explicit QWinRTMessageDialogHelper(const QWinRTTheme *theme); - ~QWinRTMessageDialogHelper(); + ~QWinRTMessageDialogHelper() override; void exec() override; bool show(Qt::WindowFlags windowFlags, diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index e39a87148a..bd2bbcb81c 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -46,9 +46,11 @@ #include "qwinrtdrag.h" #endif #include "qwinrtwindow.h" +#include "qwinrtcanvas.h" #include <private/qeventdispatcher_winrt_p.h> #include <private/qhighdpiscaling_p.h> +#include <QtCore/qdebug.h> #include <QtCore/QLoggingCategory> #include <QtGui/QSurfaceFormat> #include <QtGui/QGuiApplication> @@ -99,6 +101,31 @@ typedef ITypedEventHandler<ApplicationView*, IInspectable*> VisibleBoundsChanged QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") + +#if !defined(QT_NO_DEBUG_STREAM) +QDebug operator<<(QDebug dbg, QWinRTScreen::MousePositionTransition transition) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "QWinRTScreen::MousePositionTransition::"; + switch (transition) { + case QWinRTScreen::MousePositionTransition::MovedOut: + dbg << "MovedOut"; + break; + case QWinRTScreen::MousePositionTransition::MovedIn: + dbg << "MovedIn"; + break; + case QWinRTScreen::MousePositionTransition::StayedOut: + dbg << "StayedOut"; + break; + case QWinRTScreen::MousePositionTransition::StayedIn: + dbg << "StayedIn"; + break; + } + return dbg; +} +#endif + struct KeyInfo { KeyInfo() { @@ -463,7 +490,7 @@ public: QTouchDevice *touchDevice; ComPtr<ICoreWindow> coreWindow; ComPtr<ICorePointerRedirector> redirect; - ComPtr<Xaml::IDependencyObject> canvas; + ComPtr<QWinRTCanvas> canvas; ComPtr<IApplicationView> view; ComPtr<IDisplayInformation> displayInformation; @@ -490,6 +517,7 @@ public: QAtomicPointer<QWinRTWindow> keyboardGrabWindow; QWindow *currentPressWindow = nullptr; QWindow *currentTargetWindow = nullptr; + bool firstMouseMove = true; }; // To be called from the XAML thread @@ -553,27 +581,25 @@ QWinRTScreen::QWinRTScreen() hr = applicationViewStatics->GetForCurrentView(&d->view); RETURN_VOID_IF_FAILED("Could not access currentView"); - // Create a canvas and set it as the window content. Eventually, this should have its own method so multiple "screens" can be added - ComPtr<Xaml::Controls::ICanvas> canvas; - hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), &canvas); - Q_ASSERT_SUCCEEDED(hr); + d->canvas = Make<QWinRTCanvas>([this]() { return topWindow(); }); + ComPtr<Xaml::IFrameworkElement> frameworkElement; - hr = canvas.As(&frameworkElement); + hr = d->canvas.As(&frameworkElement); Q_ASSERT_SUCCEEDED(hr); hr = frameworkElement->put_Width(d->logicalRect.width()); Q_ASSERT_SUCCEEDED(hr); hr = frameworkElement->put_Height(d->logicalRect.height()); Q_ASSERT_SUCCEEDED(hr); + ComPtr<Xaml::IUIElement> uiElement; - hr = canvas.As(&uiElement); + hr = d->canvas.As(&uiElement); Q_ASSERT_SUCCEEDED(hr); + #if QT_CONFIG(draganddrop) QWinRTDrag::instance()->setUiElement(uiElement); #endif hr = window->put_Content(uiElement.Get()); Q_ASSERT_SUCCEEDED(hr); - hr = canvas.As(&d->canvas); - Q_ASSERT_SUCCEEDED(hr); d->cursor.reset(new QWinRTCursor); @@ -723,7 +749,10 @@ ICoreWindow *QWinRTScreen::coreWindow() const Xaml::IDependencyObject *QWinRTScreen::canvas() const { Q_D(const QWinRTScreen); - return d->canvas.Get(); + Xaml::IDependencyObject *depCanvas; + if (SUCCEEDED(d->canvas.CopyTo(&depCanvas))) + return depCanvas; + return nullptr; } void QWinRTScreen::initialize() @@ -848,6 +877,7 @@ void QWinRTScreen::addWindow(QWindow *window) } handleExpose(); + d->firstMouseMove = true; QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); #if QT_CONFIG(draganddrop) @@ -860,6 +890,8 @@ void QWinRTScreen::removeWindow(QWindow *window) Q_D(QWinRTScreen); qCDebug(lcQpaWindows) << __FUNCTION__ << window; + handleExpose(); + const bool wasTopWindow = window == topWindow(); if (!d->visibleWindows.removeAll(window)) return; @@ -867,7 +899,6 @@ void QWinRTScreen::removeWindow(QWindow *window) const Qt::WindowType type = window->type(); if (wasTopWindow && type != Qt::Popup && type != Qt::ToolTip && type != Qt::Tool) QWindowSystemInterface::handleWindowActivated(nullptr, Qt::OtherFocusReason); - handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); #if QT_CONFIG(draganddrop) if (wasTopWindow) @@ -1075,6 +1106,7 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, ICharacterReceivedEvent HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) { Q_D(QWinRTScreen); + qCDebug(lcQpaEvents) << __FUNCTION__; ComPtr<IPointerPoint> pointerPoint; if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) { @@ -1087,7 +1119,9 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) if (d->mouseGrabWindow) d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow << pos; QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, pos, pos); + d->firstMouseMove = false; } return S_OK; } @@ -1095,7 +1129,7 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) { Q_D(QWinRTScreen); - + qCDebug(lcQpaEvents) << __FUNCTION__; ComPtr<IPointerPoint> pointerPoint; if (FAILED(args->get_CurrentPoint(&pointerPoint))) return E_INVALIDARG; @@ -1109,6 +1143,7 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) if (d->mouseGrabWindow) d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow; QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow); d->currentTargetWindow = nullptr; return S_OK; @@ -1120,6 +1155,7 @@ ComPtr<IPointerPoint> qt_winrt_lastPointerPoint; HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) { Q_D(QWinRTScreen); + qCDebug(lcQpaEvents) << __FUNCTION__; ComPtr<IPointerPoint> pointerPoint; if (FAILED(args->get_CurrentPoint(&pointerPoint))) return E_INVALIDARG; @@ -1175,6 +1211,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) boolean isHorizontal; properties->get_IsHorizontalMouseWheel(&isHorizontal); QPoint angleDelta(isHorizontal ? delta : 0, isHorizontal ? 0 : delta); + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleWheelEvent" << d->currentTargetWindow + << localPos << pos << angleDelta << mods; QWindowSystemInterface::handleWheelEvent(d->currentTargetWindow, localPos, pos, QPoint(), angleDelta, mods); break; } @@ -1213,6 +1251,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) const QPointF globalPosDelta = pos - posPoint; const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta; + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentPressWindow + << localPressPos << pos << buttons << mods; QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos, buttons, mods); d->currentPressWindow = nullptr; } @@ -1224,6 +1264,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) d->currentPressWindow = nullptr; } + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentTargetWindow + << localPos << pos << buttons << mods; QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, buttons, mods); break; @@ -1280,6 +1322,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) it.value().normalPosition = QPointF(point.X/d->logicalRect.width(), point.Y/d->logicalRect.height()); it.value().pressure = pressure; + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleTouchEvent" << d->currentTargetWindow + << d->touchDevice << d->touchPoints.values() << mods; QWindowSystemInterface::handleTouchEvent(d->currentTargetWindow, d->touchDevice, d->touchPoints.values(), mods); if (wasPressEvent) it.value().state = Qt::TouchPointStationary; @@ -1301,6 +1345,9 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) float rotation; properties->get_Twist(&rotation); + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleTabletEvent" << d->currentTargetWindow + << isPressed << pos << pointerType << pressure << xTilt << yTilt + << rotation << id << mods; QWindowSystemInterface::handleTabletEvent(d->currentTargetWindow, isPressed, pos, pos, 0, pointerType, pressure, xTilt, yTilt, 0, rotation, 0, id, mods); @@ -1312,6 +1359,70 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) return S_OK; } +void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransition transition) +{ + Q_D(QWinRTScreen); + qCDebug(lcQpaEvents) << __FUNCTION__ << point << transition; + if (transition == MousePositionTransition::StayedOut) + return; + qt_winrt_lastPointerPoint = nullptr; + const QPointF pos(point.x() * d->scaleFactor, point.y() * d->scaleFactor); + QPointF localPos = pos; + + const QPoint posPoint = pos.toPoint(); + QWindow *windowUnderPointer = windowAt(QHighDpiScaling::mapPositionFromNative(posPoint, this)); + d->currentTargetWindow = windowUnderPointer; + + if (d->mouseGrabWindow) + d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + + if (d->currentTargetWindow) { + const QPointF globalPosDelta = pos - posPoint; + localPos = d->currentTargetWindow->mapFromGlobal(posPoint) + globalPosDelta; + } + + // In case of a mouse grab we have to store the target of a press event + // to be able to send one additional release event to this target when the mouse + // button is released. This is a similar approach to AutoMouseCapture in the + // windows qpa backend. Otherwise the release might not be propagated and the original + // press event receiver considers a button to still be pressed, as in Qt Quick Controls 1 + // menus. + if (d->currentPressWindow && d->mouseGrabWindow) { + const QPointF globalPosDelta = pos - posPoint; + const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta; + + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentPressWindow + << localPressPos << pos << Qt::NoButton << Qt::NoModifier; + QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos, + Qt::NoButton, Qt::NoModifier); + d->currentPressWindow = nullptr; + } + // If the mouse button is released outside of a window, targetWindow is 0, but the event + // has to be delivered to the window, that initially received the mouse press. Do not reset + // d->currentTargetWindow though, as it is used (and reset) in onPointerExited. + if (d->currentPressWindow && !d->currentTargetWindow) { + d->currentTargetWindow = d->currentPressWindow; + d->currentPressWindow = nullptr; + } + + if (transition == MousePositionTransition::MovedOut) { + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow; + QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow); + return; + } + + if (transition == MousePositionTransition::MovedIn || d->firstMouseMove) { + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow + << localPos << pos; + QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, localPos, pos); + d->firstMouseMove = false; + } + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentTargetWindow + << localPos << pos << Qt::NoButton << Qt::NoModifier; + QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, Qt::NoButton, + Qt::NoModifier); +} + HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args) { Q_D(QWinRTScreen); @@ -1413,6 +1524,7 @@ HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEvent { // When dragging ends with a non-mouse input device then onRedirectRelease is invoked. // QTBUG-58781 + qCDebug(lcQpaEvents) << __FUNCTION__; return onPointerUpdated(nullptr, args); } diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index fd6499c2b9..cde148a638 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -89,7 +89,7 @@ class QWinRTScreen : public QPlatformScreen { public: explicit QWinRTScreen(); - ~QWinRTScreen(); + ~QWinRTScreen() override; QRect geometry() const override; QRect availableGeometry() const override; @@ -128,6 +128,15 @@ public: void setCursorRect(const QRectF &cursorRect); void setKeyboardRect(const QRectF &keyboardRect); + enum class MousePositionTransition { + MovedOut, + MovedIn, + StayedIn, + StayedOut + }; + + void emulateMouseMove(const QPointF &point, MousePositionTransition transition); + private: void handleExpose(); diff --git a/src/plugins/platforms/winrt/qwinrtservices.cpp b/src/plugins/platforms/winrt/qwinrtservices.cpp index 05620ca4c8..b27c408f40 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.cpp +++ b/src/plugins/platforms/winrt/qwinrtservices.cpp @@ -83,17 +83,14 @@ QWinRTServices::QWinRTServices() Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); } -QWinRTServices::~QWinRTServices() -{ -} - bool QWinRTServices::openUrl(const QUrl &url) { Q_D(QWinRTServices); ComPtr<IUriRuntimeClass> uri; QString urlString = url.toString(); - HStringReference uriString(reinterpret_cast<LPCWSTR>(urlString.utf16()), urlString.length()); + HStringReference uriString(reinterpret_cast<LPCWSTR>(urlString.utf16()), + uint(urlString.length())); HRESULT hr = d->uriFactory->CreateUri(uriString.Get(), &uri); RETURN_FALSE_IF_FAILED("Failed to create URI from QUrl."); @@ -122,7 +119,8 @@ bool QWinRTServices::openDocument(const QUrl &url) } if (!file) { const QString pathString = QDir::toNativeSeparators(url.toLocalFile()); - HStringReference path(reinterpret_cast<LPCWSTR>(pathString.utf16()), pathString.length()); + HStringReference path(reinterpret_cast<LPCWSTR>(pathString.utf16()), + uint(pathString.length())); ComPtr<IAsyncOperation<StorageFile *>> op; hr = d->fileFactory->GetFileFromPathAsync(path.Get(), &op); RETURN_FALSE_IF_FAILED("Failed to initialize file URI."); diff --git a/src/plugins/platforms/winrt/qwinrtservices.h b/src/plugins/platforms/winrt/qwinrtservices.h index 80b9a6c92a..202ce722cf 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.h +++ b/src/plugins/platforms/winrt/qwinrtservices.h @@ -50,7 +50,7 @@ class QWinRTServices : public QPlatformServices { public: explicit QWinRTServices(); - ~QWinRTServices(); + ~QWinRTServices() override = default; bool openUrl(const QUrl &url) override; bool openDocument(const QUrl &url) override; diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index cbf0ba36c9..29d234d276 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -126,7 +126,7 @@ QWinRTWindow::QWinRTWindow(QWindow *window) hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), IID_PPV_ARGS(&d->canvas)); Q_ASSERT_SUCCEEDED(hr); - hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + hr = QEventDispatcherWinRT::runOnXamlThread([d]() { // Create a new swapchain and place it inside the canvas HRESULT hr; hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_SwapChainPanel).Get(), diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 9604b4bbaa..0445e6bf54 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -54,7 +54,7 @@ class QWinRTWindow : public QPlatformWindow { public: QWinRTWindow(QWindow *window); - ~QWinRTWindow(); + ~QWinRTWindow() override; QSurfaceFormat format() const override; bool isActive() const override; diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp new file mode 100644 index 0000000000..40274fb967 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiaaccessibility.h" +#include "qwinrtuiamainprovider.h" + +#include <QtGui/QAccessible> +#include <QtGui/QWindow> +#include <QtGui/QGuiApplication> +#include <QtGui/private/qguiapplication_p.h> +#include <QtCore/qt_windows.h> +#include <qpa/qplatformintegration.h> + +QT_BEGIN_NAMESPACE + +QWinRTUiaAccessibility::QWinRTUiaAccessibility() +{ +} + +QWinRTUiaAccessibility::~QWinRTUiaAccessibility() +{ +} + +// Handles UI Automation window messages. +void QWinRTUiaAccessibility::activate() +{ + // Start handling accessibility internally + QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true); +} + +// Handles accessibility update notifications. +void QWinRTUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) +{ + if (!event) + return; + + QAccessibleInterface *accessible = event->accessibleInterface(); + if (!isActive() || !accessible || !accessible->isValid()) + return; + + switch (event->type()) { + case QAccessible::Focus: + QWinRTUiaMainProvider::notifyFocusChange(event); + break; + case QAccessible::ObjectCreated: + case QAccessible::ObjectDestroyed: + case QAccessible::ObjectShow: + case QAccessible::ObjectHide: + case QAccessible::ObjectReorder: + QWinRTUiaMainProvider::notifyVisibilityChange(event); + break; + case QAccessible::StateChanged: + QWinRTUiaMainProvider::notifyStateChange(static_cast<QAccessibleStateChangeEvent *>(event)); + break; + case QAccessible::ValueChanged: + QWinRTUiaMainProvider::notifyValueChange(static_cast<QAccessibleValueChangeEvent *>(event)); + break; + case QAccessible::TextAttributeChanged: + case QAccessible::TextColumnChanged: + case QAccessible::TextInserted: + case QAccessible::TextRemoved: + case QAccessible::TextUpdated: + case QAccessible::TextSelectionChanged: + case QAccessible::TextCaretMoved: + QWinRTUiaMainProvider::notifyTextChange(event); + break; + default: + break; + } +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h new file mode 100644 index 0000000000..b966271e21 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAACCESSIBILITY_H +#define QWINRTUIAACCESSIBILITY_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include <qpa/qplatformaccessibility.h> + +QT_BEGIN_NAMESPACE + +// WinRT platform accessibility implemented over UI Automation. +class QWinRTUiaAccessibility : public QPlatformAccessibility +{ +public: + explicit QWinRTUiaAccessibility(); + virtual ~QWinRTUiaAccessibility(); + static void activate(); + void notifyAccessibilityUpdate(QAccessibleEvent *event) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAACCESSIBILITY_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp new file mode 100644 index 0000000000..ee53714caa --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +QWinRTUiaBaseProvider::QWinRTUiaBaseProvider(QAccessible::Id id) : + m_id(id) +{ +} + +QWinRTUiaBaseProvider::~QWinRTUiaBaseProvider() +{ +} + +QAccessibleInterface *QWinRTUiaBaseProvider::accessibleInterface() const +{ + QAccessibleInterface *accessible = QAccessible::accessibleInterface(m_id); + if (accessible && accessible->isValid()) + return accessible; + return nullptr; +} + +QAccessible::Id QWinRTUiaBaseProvider::id() const +{ + return m_id; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h new file mode 100644 index 0000000000..d8837354dc --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIABASEPROVIDER_H +#define QWINRTUIABASEPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +// Base class for UI Automation providers. +class QWinRTUiaBaseProvider : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaBaseProvider) +public: + explicit QWinRTUiaBaseProvider(QAccessible::Id id); + virtual ~QWinRTUiaBaseProvider(); + + QAccessibleInterface *accessibleInterface() const; + QAccessible::Id id() const; + +private: + QAccessible::Id m_id; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIABASEPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp new file mode 100644 index 0000000000..4e406a3545 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiacontrolmetadata.h" +#include "qwinrtuiautils.h" + +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; + +QWinRTUiaControlMetadata::QWinRTUiaControlMetadata() +{ +} + +QWinRTUiaControlMetadata::QWinRTUiaControlMetadata(QAccessible::Id id) +{ + update(id); +} + +void QWinRTUiaControlMetadata::update(QAccessible::Id id) +{ + if (QAccessibleInterface *accessible = accessibleForId(id)) { + m_automationId = generateAutomationId(accessible); + m_className = generateClassName(accessible); + m_controlName = generateControlName(accessible); + m_role = generateRole(accessible); + m_state = accessible->state(); + m_accelerator = accessible->text(QAccessible::Accelerator); + m_access = accessible->text(QAccessible::Accelerator); + m_help = accessible->text(QAccessible::Help); + m_description = accessible->text(QAccessible::Description); + m_value = accessible->text(QAccessible::Value); + m_boundingRect = accessible->rect(); + updateValueData(accessible); + updateTableData(accessible); + updateTextData(accessible); + } +} + +QString QWinRTUiaControlMetadata::generateControlName(QAccessibleInterface *accessible) +{ + const bool clientTopLevel = (accessible->role() == QAccessible::Client) + && accessible->parent() && (accessible->parent()->role() == QAccessible::Application); + + QString name = accessible->text(QAccessible::Name); + if (name.isEmpty() && clientTopLevel) + name = QCoreApplication::applicationName(); + return name; +} + +QString QWinRTUiaControlMetadata::generateClassName(QAccessibleInterface *accessible) +{ + QString name; + + if (QObject *obj = accessible->object()) + name = QLatin1String(obj->metaObject()->className()); + return name; +} + +// Generates an ID based on the name of the controls and their parents. +QString QWinRTUiaControlMetadata::generateAutomationId(QAccessibleInterface *accessible) +{ + QString autid; + QObject *obj = accessible->object(); + while (obj) { + QString name = obj->objectName(); + if (name.isEmpty()) { + autid = QStringLiteral(""); + break; + } + if (!autid.isEmpty()) + autid.prepend(QLatin1Char('.')); + autid.prepend(name); + obj = obj->parent(); + } + return autid; +} + +QAccessible::Role QWinRTUiaControlMetadata::generateRole(QAccessibleInterface *accessible) +{ + const bool clientTopLevel = (accessible->role() == QAccessible::Client) + && accessible->parent() && (accessible->parent()->role() == QAccessible::Application); + + if (clientTopLevel) { + // Reports a top-level widget as a window. + return QAccessible::Window; + } else { + return accessible->role(); + } +} + +void QWinRTUiaControlMetadata::updateValueData(QAccessibleInterface *accessible) +{ + if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { + m_minimumValue = valueInterface->minimumValue().toDouble(); + m_maximumValue = valueInterface->maximumValue().toDouble(); + m_currentValue = valueInterface->currentValue().toDouble(); + m_minimumStepSize = valueInterface->minimumStepSize().toDouble(); + } else { + m_minimumValue = 0.0; + m_maximumValue = 0.0; + m_currentValue = 0.0; + m_minimumStepSize = 0.0; + } +} + +void QWinRTUiaControlMetadata::updateTableData(QAccessibleInterface *accessible) +{ + if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) { + m_rowIndex = 0; + m_columnIndex = 0; + m_rowCount = tableInterface->rowCount(); + m_columnCount = tableInterface->columnCount(); + } else if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) { + m_rowIndex = tableCellInterface->rowIndex(); + m_columnIndex = tableCellInterface->columnIndex(); + m_rowCount = tableCellInterface->rowExtent(); + m_columnCount = tableCellInterface->columnExtent(); + } else { + m_rowIndex = 0; + m_columnIndex = 0; + m_rowCount = 0; + m_columnCount = 0; + } +} + +void QWinRTUiaControlMetadata::updateTextData(QAccessibleInterface *accessible) +{ + if (QAccessibleTextInterface *textInterface = accessible->textInterface()) { + m_cursorPosition = textInterface->cursorPosition(); + m_text = textInterface->text(0, textInterface->characterCount()); + } else { + m_cursorPosition = 0; + m_text = QStringLiteral(""); + } +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h new file mode 100644 index 0000000000..769f073a1b --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIACONTROLMETADATA_H +#define QWINRTUIACONTROLMETADATA_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include <QString> +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> + +QT_BEGIN_NAMESPACE + +// Cacheable control metadata +class QWinRTUiaControlMetadata +{ +public: + QWinRTUiaControlMetadata(); + QWinRTUiaControlMetadata(QAccessible::Id id); + void update(QAccessible::Id id); + QString automationId() const { return m_automationId; } + QString className() const { return m_className; } + QString controlName() const { return m_controlName; } + QString accelerator() const { return m_accelerator; } + QString access() const { return m_access; } + QString help() const { return m_help; } + QString description() const { return m_description; } + QString value() const { return m_value; } + QString text() const { return m_text; } + QAccessible::Role role() const { return m_role; } + QAccessible::State state() const { return m_state; } + QRect boundingRect() const { return m_boundingRect; } + double minimumValue() const { return m_minimumValue; } + double maximumValue() const { return m_maximumValue; } + double currentValue() const { return m_currentValue; } + double minimumStepSize() const { return m_minimumStepSize; } + int rowIndex() const { return m_rowIndex; } + int columnIndex() const { return m_columnIndex; } + int rowCount() const { return m_rowCount; } + int columnCount() const { return m_columnCount; } + int characterCount() const { return m_text.length(); } + int cursorPosition() const { return m_cursorPosition; } + +private: + QString generateControlName(QAccessibleInterface *accessible); + QString generateClassName(QAccessibleInterface *accessible); + QString generateAutomationId(QAccessibleInterface *accessible); + QAccessible::Role generateRole(QAccessibleInterface *accessible); + void updateValueData(QAccessibleInterface *accessible); + void updateTableData(QAccessibleInterface *accessible); + void updateTextData(QAccessibleInterface *accessible); + QString m_automationId; + QString m_className; + QString m_controlName; + QString m_accelerator; + QString m_access; + QString m_help; + QString m_description; + QString m_value; + QString m_text; + QAccessible::Role m_role = QAccessible::NoRole; + QAccessible::State m_state; + QRect m_boundingRect; + double m_minimumValue = 0.0; + double m_maximumValue = 0.0; + double m_currentValue = 0.0; + double m_minimumStepSize = 0.0; + int m_rowIndex = 0; + int m_columnIndex = 0; + int m_rowCount = 0; + int m_columnCount = 0; + int m_cursorPosition = 0; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIACONTROLMETADATA_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h new file mode 100644 index 0000000000..35e4df75fc --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAEMPTYPROPERTYVALUE_H +#define QWINRTUIAEMPTYPROPERTYVALUE_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements an empty property value. +class QWinRTUiaEmptyPropertyValue : + public Microsoft::WRL::RuntimeClass<ABI::Windows::Foundation::IPropertyValue> +{ + InspectableClass(L"QWinRTUiaEmptyPropertyValue", BaseTrust); +public: + + HRESULT STDMETHODCALLTYPE get_Type(ABI::Windows::Foundation::PropertyType *value) + { + *value = ABI::Windows::Foundation::PropertyType_Empty; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE get_IsNumericScalar(boolean*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetUInt8(BYTE*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetInt16(INT16*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetUInt16(UINT16*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetInt32(INT32*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetUInt32(UINT32*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetInt64(INT64*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetUInt64(UINT64*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetSingle(FLOAT*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetDouble(DOUBLE*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetChar16(WCHAR*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetBoolean(boolean*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetString(HSTRING*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetGuid(GUID*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetDateTime(ABI::Windows::Foundation::DateTime*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetTimeSpan(ABI::Windows::Foundation::TimeSpan*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetPoint(ABI::Windows::Foundation::Point*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetSize(ABI::Windows::Foundation::Size*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetRect(ABI::Windows::Foundation::Rect*) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetUInt8Array(UINT32*, BYTE**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetInt16Array(UINT32*, INT16**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetUInt16Array(UINT32*, UINT16**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetInt32Array(UINT32*, INT32**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetUInt32Array(UINT32*, UINT32**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetInt64Array(UINT32*, INT64**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetUInt64Array(UINT32*, UINT64**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetSingleArray(UINT32*, FLOAT**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetDoubleArray(UINT32*, DOUBLE**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetChar16Array(UINT32*, WCHAR**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetBooleanArray(UINT32*, boolean**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetStringArray(UINT32*, HSTRING**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetInspectableArray(UINT32*, IInspectable***) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetGuidArray(UINT32*, GUID**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetDateTimeArray(UINT32*, ABI::Windows::Foundation::DateTime**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetTimeSpanArray(UINT32*, ABI::Windows::Foundation::TimeSpan**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetPointArray(UINT32*, ABI::Windows::Foundation::Point**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetSizeArray(UINT32*, ABI::Windows::Foundation::Size**) { return E_FAIL; } + HRESULT STDMETHODCALLTYPE GetRectArray(UINT32*, ABI::Windows::Foundation::Rect**) { return E_FAIL; } +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAEMPTYPROPERTYVALUE_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp new file mode 100644 index 0000000000..524000b618 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiagriditemprovider.h" +#include "qwinrtuiamainprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; +using namespace ABI::Windows::UI::Xaml::Automation::Peers; + +QWinRTUiaGridItemProvider::QWinRTUiaGridItemProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaGridItemProvider::~QWinRTUiaGridItemProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +// Returns the column index of the item. +HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_Column(INT32 *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->columnIndex(); + return S_OK; +} + +// Returns the number of columns occupied by the item. +HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_ColumnSpan(INT32 *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->columnCount(); + return S_OK; +} + +// Returns the provider for the containing table/tree. +HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_ContainingGrid(IIRawElementProviderSimple **value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + *value = nullptr; + + auto accid = id(); + auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0)); + auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) { + if (QAccessibleInterface *table = tableCellInterface->table()) { + **ptrElementId = idForAccessible(table); + QWinRTUiaMetadataCache::instance()->load(**ptrElementId); + } + } + } + delete ptrElementId; + return S_OK; + }))) { + return E_FAIL; + } + + if (!*elementId) + return S_OK; + + return QWinRTUiaMainProvider::rawProviderForAccessibleId(*elementId, value); +} + +// Returns the row index of the item. +HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_Row(INT32 *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->rowIndex(); + return S_OK; +} + +// Returns the number of rows occupied by the item. +HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_RowSpan(INT32 *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->rowCount(); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h new file mode 100644 index 0000000000..70504fc555 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAGRIDITEMPROVIDER_H +#define QWINRTUIAGRIDITEMPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Grid Item control pattern provider. Used by items within a table/tree. +class QWinRTUiaGridItemProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IGridItemProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaGridItemProvider) + InspectableClass(L"QWinRTUiaGridItemProvider", BaseTrust); + +public: + explicit QWinRTUiaGridItemProvider(QAccessible::Id id); + virtual ~QWinRTUiaGridItemProvider(); + + // IGridItemProvider + HRESULT STDMETHODCALLTYPE get_Column(INT32 *value) override; + HRESULT STDMETHODCALLTYPE get_ColumnSpan(INT32 *value) override; + HRESULT STDMETHODCALLTYPE get_ContainingGrid(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **value) override; + HRESULT STDMETHODCALLTYPE get_Row(INT32 *value) override; + HRESULT STDMETHODCALLTYPE get_RowSpan(INT32 *value) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAGRIDITEMPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp new file mode 100644 index 0000000000..e469991de2 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiagridprovider.h" +#include "qwinrtuiamainprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; +using namespace ABI::Windows::UI::Xaml::Automation::Peers; + +QWinRTUiaGridProvider::QWinRTUiaGridProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaGridProvider::~QWinRTUiaGridProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +// Returns the number of columns. +HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::get_ColumnCount(INT32 *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->columnCount(); + return S_OK; +} + +// Returns the number of rows. +HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::get_RowCount(INT32 *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->rowCount(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::GetItem(INT32 row, INT32 column, IIRawElementProviderSimple **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + + auto accid = id(); + auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0)); + auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, row, column, ptrElementId]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) { + if ((row >= 0) && (row < tableInterface->rowCount()) && (column >= 0) && (column < tableInterface->columnCount())) { + if (QAccessibleInterface *cell = tableInterface->cellAt(row, column)) { + **ptrElementId = idForAccessible(cell); + QWinRTUiaMetadataCache::instance()->load(**ptrElementId); + } + } + } + } + delete ptrElementId; + return S_OK; + }))) { + return E_FAIL; + } + + if (!*elementId) + return E_FAIL; + + return QWinRTUiaMainProvider::rawProviderForAccessibleId(*elementId, returnValue); +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h new file mode 100644 index 0000000000..d6dfaed315 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAGRIDPROVIDER_H +#define QWINRTUIAGRIDPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Grid control pattern provider. Used by tables/trees. +class QWinRTUiaGridProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IGridProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaGridProvider) + InspectableClass(L"QWinRTUiaGridProvider", BaseTrust); + +public: + explicit QWinRTUiaGridProvider(QAccessible::Id id); + virtual ~QWinRTUiaGridProvider(); + + // IGridProvider + HRESULT STDMETHODCALLTYPE get_ColumnCount(INT32 *value) override; + HRESULT STDMETHODCALLTYPE get_RowCount(INT32 *value) override; + HRESULT STDMETHODCALLTYPE GetItem(INT32 row, INT32 column, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAGRIDPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp new file mode 100644 index 0000000000..e2cf7bc107 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiainvokeprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; + +QWinRTUiaInvokeProvider::QWinRTUiaInvokeProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaInvokeProvider::~QWinRTUiaInvokeProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaInvokeProvider::Invoke() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + + QEventDispatcherWinRT::runOnMainThread([accid]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) + if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) + actionInterface->doAction(QAccessibleActionInterface::pressAction()); + QWinRTUiaMetadataCache::instance()->load(accid); + return S_OK; + }, 0); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h new file mode 100644 index 0000000000..dfe7917a16 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAINVOKEPROVIDER_H +#define QWINRTUIAINVOKEPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Invoke control pattern provider. +class QWinRTUiaInvokeProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IInvokeProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaInvokeProvider) + InspectableClass(L"QWinRTUiaInvokeProvider", BaseTrust); + +public: + explicit QWinRTUiaInvokeProvider(QAccessible::Id id); + virtual ~QWinRTUiaInvokeProvider(); + + // IInvokeProvider + HRESULT STDMETHODCALLTYPE Invoke() override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAINVOKEPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp new file mode 100644 index 0000000000..6f3ad6dcd2 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp @@ -0,0 +1,789 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiamainprovider.h" +#include "qwinrtuiaprovidercache.h" +#include "qwinrtuiavalueprovider.h" +#include "qwinrtuiarangevalueprovider.h" +#include "qwinrtuiatextprovider.h" +#include "qwinrtuiatoggleprovider.h" +#include "qwinrtuiainvokeprovider.h" +#include "qwinrtuiaselectionprovider.h" +#include "qwinrtuiaselectionitemprovider.h" +#include "qwinrtuiatableprovider.h" +#include "qwinrtuiatableitemprovider.h" +#include "qwinrtuiagridprovider.h" +#include "qwinrtuiagriditemprovider.h" +#include "qwinrtuiapeervector.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiaemptypropertyvalue.h" +#include "qwinrtuiautils.h" + +#include <QCoreApplication> +#include <QSemaphore> +#include <QtCore/QLoggingCategory> +#include <QtCore/qfunctions_winrt.h> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +using namespace QWinRTUiAutomation; +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::System; +using namespace ABI::Windows::UI; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; +using namespace ABI::Windows::UI::Xaml::Automation::Peers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; + +QT_BEGIN_NAMESPACE + +QWinRTUiaMainProvider::QWinRTUiaMainProvider(QAccessible::Id id) + : QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + ComPtr<IAutomationPeerFactory> factory; + HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Automation_Peers_AutomationPeer).Get(), IID_PPV_ARGS(&factory)); + Q_ASSERT_SUCCEEDED(hr); + + hr = factory->CreateInstance(this, &m_base, &m_core); + Q_ASSERT_SUCCEEDED(hr); +} + +QWinRTUiaMainProvider::~QWinRTUiaMainProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!iface) + return E_POINTER; + *iface = nullptr; + + if (iid == IID_IUnknown) { + *iface = static_cast<IAutomationPeerOverrides *>(this); + AddRef(); + return S_OK; + } else if (iid == IID_IAutomationPeerOverrides) { + *iface = static_cast<IAutomationPeerOverrides *>(this); + AddRef(); + return S_OK; + } else { + return m_base.CopyTo(iid, iface); + } +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetIids(ULONG *iidCount, IID **iids) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + *iidCount = 0; + *iids = nullptr; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetRuntimeClassName(HSTRING *className) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + return qHString(QStringLiteral("QWinRTUiaMainProvider"), className); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetTrustLevel(TrustLevel *trustLevel) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + *trustLevel = TrustLevel::BaseTrust; + return S_OK; +} + +// Returns a cached instance of the provider for a specific accessible interface. +QWinRTUiaMainProvider *QWinRTUiaMainProvider::providerForAccessibleId(QAccessible::Id id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QWinRTUiaProviderCache *providerCache = QWinRTUiaProviderCache::instance(); + QWinRTUiaMainProvider *provider = qobject_cast<QWinRTUiaMainProvider *>(providerCache->providerForId(id)); + + if (provider) { + provider->AddRef(); + } else { + ComPtr<QWinRTUiaMainProvider> p = Make<QWinRTUiaMainProvider>(id); + provider = p.Get(); + provider->AddRef(); + providerCache->insert(id, provider); + } + return provider; +} + +// Returns an IIRawElementProviderSimple for a specific accessible interface. +HRESULT QWinRTUiaMainProvider::rawProviderForAccessibleId(QAccessible::Id elementId, + IIRawElementProviderSimple **returnValue) +{ + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + + if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(elementId)) { + ComPtr<IAutomationPeer> automationPeer; + if (SUCCEEDED(provider.As(&automationPeer))) { + ComPtr<IAutomationPeerProtected> automationPeerProtected; + if (SUCCEEDED(provider.As(&automationPeerProtected))) { + return automationPeerProtected->ProviderFromPeer(automationPeer.Get(), returnValue); + } + } + } + return E_FAIL; +} + +// Returns an array of IIRawElementProviderSimple instances for a list of accessible interface ids. +HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QList<QAccessible::Id> &elementIds, + UINT32 *returnValueSize, + IIRawElementProviderSimple ***returnValue) +{ + if (!returnValueSize || !returnValue) + return E_INVALIDARG; + *returnValueSize = 0; + *returnValue = nullptr; + + QList<IIRawElementProviderSimple *> rawProviderList; + + for (auto elementId : qAsConst(elementIds)) { + IIRawElementProviderSimple *rawProvider; + if (SUCCEEDED(rawProviderForAccessibleId(elementId, &rawProvider))) + rawProviderList.append(rawProvider); + } + + if (rawProviderList.size() == 0) + return S_OK; + + *returnValue = static_cast<IIRawElementProviderSimple **>(CoTaskMemAlloc(rawProviderList.size() * sizeof(IIRawElementProviderSimple *))); + if (!*returnValue) { + for (auto rawProvider : qAsConst(rawProviderList)) + rawProvider->Release(); + return E_OUTOFMEMORY; + } + + int index = 0; + for (auto rawProvider : qAsConst(rawProviderList)) + (*returnValue)[index++] = rawProvider; + *returnValueSize = rawProviderList.size(); + return S_OK; +} + +void QWinRTUiaMainProvider::notifyFocusChange(QAccessibleEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + QAccessible::Id accid = idForAccessible(accessible); + QWinRTUiaMetadataCache::instance()->load(accid); + QEventDispatcherWinRT::runOnXamlThread([accid]() { + if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) { + ComPtr<IAutomationPeer> automationPeer; + if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) { + automationPeer->RaiseAutomationEvent(AutomationEvents_AutomationFocusChanged); + } + } + return S_OK; + }, false); + } +} + +void QWinRTUiaMainProvider::notifyVisibilityChange(QAccessibleEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + QAccessible::Id accid = idForAccessible(accessible); + QWinRTUiaMetadataCache::instance()->load(accid); + } +} + +void QWinRTUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + QAccessible::Id accid = idForAccessible(accessible); + QWinRTUiaMetadataCache::instance()->load(accid); + + if (event->changedStates().checked || event->changedStates().checkStateMixed) { + // Notifies states changes in checkboxes. + if (accessible->role() == QAccessible::CheckBox) { + QEventDispatcherWinRT::runOnXamlThread([accid]() { + if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) { + ComPtr<IAutomationPeer> automationPeer; + if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) { + ComPtr<ITogglePatternIdentifiersStatics> toggleStatics; + if (SUCCEEDED(RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Automation_TogglePatternIdentifiers).Get(), IID_PPV_ARGS(&toggleStatics)))) { + ComPtr<IAutomationProperty> toggleStateProperty; + if (SUCCEEDED(toggleStatics->get_ToggleStateProperty(&toggleStateProperty))) { + ComPtr<QWinRTUiaEmptyPropertyValue> emptyValue = Make<QWinRTUiaEmptyPropertyValue>(); + // by sending an event with an empty value we force ui automation to refresh its state + automationPeer->RaisePropertyChangedEvent(toggleStateProperty.Get(), emptyValue.Get(), emptyValue.Get()); + } + } + } + } + return S_OK; + }, false); + } + } + if (event->changedStates().active) { + if (accessible->role() == QAccessible::Window) { + // Notifies window opened/closed. + bool active = accessible->state().active; + QEventDispatcherWinRT::runOnXamlThread([accid, active]() { + if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) { + ComPtr<IAutomationPeer> automationPeer; + if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) { + if (active) { + automationPeer->RaiseAutomationEvent(AutomationEvents_WindowOpened); + } else { + automationPeer->RaiseAutomationEvent(AutomationEvents_WindowClosed); + } + } + } + return S_OK; + }, false); + } + } + } +} + +void QWinRTUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + QAccessible::Id accid = idForAccessible(accessible); + QWinRTUiaMetadataCache::instance()->load(accid); + if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { + // Notifies changes in values of controls supporting the value interface. + double value = valueInterface->currentValue().toDouble(); + QEventDispatcherWinRT::runOnXamlThread([accid, value]() { + // For some reason RaisePropertyChangedEvent() does not seem to be + // forwarding notifications for any property types except empty, + // which would do nothing here. ToDo: find a workaround. + return S_OK; + }, false); + } + } +} + +// Notifies changes in text content and selection state of text controls. +void QWinRTUiaMainProvider::notifyTextChange(QAccessibleEvent *event) +{ + if (QAccessibleInterface *accessible = event->accessibleInterface()) { + QAccessible::Id accid = idForAccessible(accessible); + QWinRTUiaMetadataCache::instance()->load(accid); + bool readOnly = accessible->state().readOnly; + QAccessible::Event eventType = event->type(); + if (accessible->textInterface()) { + QEventDispatcherWinRT::runOnXamlThread([accid, eventType, readOnly]() { + if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) { + ComPtr<IAutomationPeer> automationPeer; + if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) { + if (eventType == QAccessible::TextSelectionChanged) { + automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextSelectionChanged); + } else if (eventType == QAccessible::TextCaretMoved) { + if (!readOnly) { + automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextSelectionChanged); + } + } else { + automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextChanged); + } + } + } + return S_OK; + }, false); + } + } +} + +// Return providers for specific control patterns +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPatternCore(PatternInterface patternInterface, IInspectable **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << patternInterface; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return E_FAIL; + + switch (patternInterface) { + case PatternInterface_Text: + case PatternInterface_Text2: { + // All text controls. + if (accessible->textInterface()) { + ComPtr<QWinRTUiaTextProvider> provider = Make<QWinRTUiaTextProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + case PatternInterface_Value: { + // All accessible controls return text(QAccessible::Value) (which may be empty). + ComPtr<QWinRTUiaValueProvider> provider = Make<QWinRTUiaValueProvider>(id()); + return provider.CopyTo(returnValue); + } + case PatternInterface_RangeValue: { + // Controls providing a numeric value within a range (e.g., sliders, scroll bars, dials). + if (accessible->valueInterface()) { + ComPtr<QWinRTUiaRangeValueProvider> provider = Make<QWinRTUiaRangeValueProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + case PatternInterface_Toggle: { + // Checkbox controls. + if (accessible->role() == QAccessible::CheckBox) { + ComPtr<QWinRTUiaToggleProvider> provider = Make<QWinRTUiaToggleProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + case PatternInterface_Selection: { + // Lists of items. + if (accessible->role() == QAccessible::List) { + ComPtr<QWinRTUiaSelectionProvider> provider = Make<QWinRTUiaSelectionProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + case PatternInterface_SelectionItem: { + // Items within a list and radio buttons. + if ((accessible->role() == QAccessible::RadioButton) + || (accessible->role() == QAccessible::ListItem)) { + ComPtr<QWinRTUiaSelectionItemProvider> provider = Make<QWinRTUiaSelectionItemProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + case PatternInterface_Table: { + // Table/tree. + if (accessible->tableInterface() + && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) { + ComPtr<QWinRTUiaTableProvider> provider = Make<QWinRTUiaTableProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + case PatternInterface_TableItem: { + // Item within a table/tree. + if (accessible->tableCellInterface() + && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) { + ComPtr<QWinRTUiaTableItemProvider> provider = Make<QWinRTUiaTableItemProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + case PatternInterface_Grid: { + // Table/tree. + if (accessible->tableInterface() + && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) { + ComPtr<QWinRTUiaGridProvider> provider = Make<QWinRTUiaGridProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + case PatternInterface_GridItem: { + // Item within a table/tree. + if (accessible->tableCellInterface() + && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) { + ComPtr<QWinRTUiaGridItemProvider> provider = Make<QWinRTUiaGridItemProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + case PatternInterface_Invoke: { + // Things that have an invokable action (e.g., simple buttons). + if (accessible->actionInterface()) { + ComPtr<QWinRTUiaInvokeProvider> provider = Make<QWinRTUiaInvokeProvider>(id()); + return provider.CopyTo(returnValue); + } + break; + } + default: + break; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAcceleratorKeyCore(HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + return qHString(metadata->accelerator(), returnValue); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAccessKeyCore(HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + return qHString(metadata->access(), returnValue); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAutomationControlTypeCore(AutomationControlType *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *returnValue = roleToControlType(metadata->role()); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAutomationIdCore(HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + return qHString(metadata->automationId(), returnValue); +} + +// Returns the bounding rectangle for the accessible control. +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetBoundingRectangleCore(ABI::Windows::Foundation::Rect *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + + QRect rect = metadata->boundingRect(); + returnValue->X = rect.x(); + returnValue->Y = rect.y(); + returnValue->Width = rect.width(); + returnValue->Height = rect.height(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<AutomationPeer *> **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + + auto accid = id(); + auto children = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); + auto ptrChildren = new QSharedPointer<QList<QAccessible::Id>>(children); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrChildren]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + int childCount = accessible->childCount(); + for (int i = 0; i < childCount; ++i) { + if (QAccessibleInterface *childAcc = accessible->child(i)) { + QAccessible::Id childId = idForAccessible(childAcc); + QWinRTUiaMetadataCache::instance()->load(childId); + if (!childAcc->state().invisible) + (*ptrChildren)->append(childId); + } + } + } + delete ptrChildren; + return S_OK; + }))) { + return E_FAIL; + } + + ComPtr<IVector<AutomationPeer *>> peerVector = Make<QWinRTUiaPeerVector>(); + + for (auto childId : qAsConst(*children)) { + if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(childId)) { + IAutomationPeer *peer; + if (SUCCEEDED(provider.CopyTo(&peer))) + peerVector->Append(peer); + } + } + return peerVector.CopyTo(returnValue); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetClassNameCore(HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + return qHString(metadata->className(), returnValue); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetClickablePointCore(ABI::Windows::Foundation::Point *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetHelpTextCore(HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + return qHString(metadata->help(), returnValue); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetItemStatusCore(HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetItemTypeCore(HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLabeledByCore(IAutomationPeer **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLocalizedControlTypeCore(HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetNameCore(HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + return qHString(metadata->controlName(), returnValue); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetOrientationCore(AutomationOrientation *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = AutomationOrientation_None; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::HasKeyboardFocusCore(boolean *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *returnValue = (metadata->state().focused != 0); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsContentElementCore(boolean *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = true; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsControlElementCore(boolean *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = true; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsEnabledCore(boolean *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *returnValue = (metadata->state().disabled == 0); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsKeyboardFocusableCore(boolean *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *returnValue = (metadata->state().focusable != 0); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsOffscreenCore(boolean *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *returnValue = (metadata->state().offscreen != 0); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsPasswordCore(boolean *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *returnValue = (metadata->role() == QAccessible::EditableText) && (metadata->state().passwordEdit != 0); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsRequiredForFormCore(boolean *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = false; + return S_OK; +} + +// Sets focus to the control. +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::SetFocusCore() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return E_FAIL; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return E_FAIL; + + QEventDispatcherWinRT::runOnMainThread([actionInterface]() { + actionInterface->doAction(QAccessibleActionInterface::setFocusAction()); + return S_OK; + }); + return S_OK; +} + +// Returns a provider for the UI element present at the specified screen coordinates. +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPeerFromPointCore(ABI::Windows::Foundation::Point point, IAutomationPeer **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + + // Scale coordinates from High DPI screens? + + auto accid = id(); + auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0)); + auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId, point]() { + // Controls can be embedded within grouping elements. By default returns the innermost control. + QAccessibleInterface *target = accessibleForId(accid); + while (QAccessibleInterface *tmpacc = target->childAt(point.X, point.Y)) { + target = tmpacc; + // For accessibility tools it may be better to return the text element instead of its subcomponents. + if (target->textInterface()) break; + } + **ptrElementId = idForAccessible(target); + QWinRTUiaMetadataCache::instance()->load(**ptrElementId); + delete ptrElementId; + return S_OK; + }))) { + return E_FAIL; + } + + if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(*elementId)) + return provider.CopyTo(returnValue); + return E_FAIL; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLiveSettingCore(AutomationLiveSetting *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + return E_NOTIMPL; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h new file mode 100644 index 0000000000..384a166cf7 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAMAINPROVIDER_H +#define QWINRTUIAMAINPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <QtCore/qglobal.h> +#include <QtCore/QPointer> +#include <QtCore/QSharedPointer> +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// The main WinRT UI Automation class. +class QWinRTUiaMainProvider: + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaMainProvider) + +public: + explicit QWinRTUiaMainProvider(QAccessible::Id id); + virtual ~QWinRTUiaMainProvider(); + static QWinRTUiaMainProvider *providerForAccessibleId(QAccessible::Id id); + static HRESULT rawProviderForAccessibleId(QAccessible::Id elementId, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue); + static HRESULT rawProviderArrayForAccessibleIdList(const QList<QAccessible::Id> &elementIds, UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue); + static void notifyFocusChange(QAccessibleEvent *event); + static void notifyVisibilityChange(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) override; + + // IInspectable + HRESULT STDMETHODCALLTYPE GetIids(ULONG *iidCount, IID **iids) override; + HRESULT STDMETHODCALLTYPE GetRuntimeClassName(HSTRING *className) override; + HRESULT STDMETHODCALLTYPE GetTrustLevel(TrustLevel *trustLevel) override; + + // IAutomationPeerOverrides + HRESULT STDMETHODCALLTYPE GetPatternCore(ABI::Windows::UI::Xaml::Automation::Peers::PatternInterface patternInterface, IInspectable **returnValue) override; + HRESULT STDMETHODCALLTYPE GetAcceleratorKeyCore(HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE GetAccessKeyCore(HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE GetAutomationControlTypeCore(ABI::Windows::UI::Xaml::Automation::Peers::AutomationControlType *returnValue) override; + HRESULT STDMETHODCALLTYPE GetAutomationIdCore(HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE GetBoundingRectangleCore(ABI::Windows::Foundation::Rect *returnValue) override; + HRESULT STDMETHODCALLTYPE GetChildrenCore(ABI::Windows::Foundation::Collections::IVector<ABI::Windows::UI::Xaml::Automation::Peers::AutomationPeer*> **returnValue) override; + HRESULT STDMETHODCALLTYPE GetClassNameCore(HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE GetClickablePointCore(ABI::Windows::Foundation::Point *returnValue) override; + HRESULT STDMETHODCALLTYPE GetHelpTextCore(HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE GetItemStatusCore(HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE GetItemTypeCore(HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE GetLabeledByCore(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **returnValue) override; + HRESULT STDMETHODCALLTYPE GetLocalizedControlTypeCore(HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE GetNameCore(HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE GetOrientationCore(ABI::Windows::UI::Xaml::Automation::Peers::AutomationOrientation *returnValue) override; + HRESULT STDMETHODCALLTYPE HasKeyboardFocusCore(boolean *returnValue) override; + HRESULT STDMETHODCALLTYPE IsContentElementCore(boolean *returnValue) override; + HRESULT STDMETHODCALLTYPE IsControlElementCore(boolean *returnValue) override; + HRESULT STDMETHODCALLTYPE IsEnabledCore(boolean *returnValue) override; + HRESULT STDMETHODCALLTYPE IsKeyboardFocusableCore(boolean *returnValue) override; + HRESULT STDMETHODCALLTYPE IsOffscreenCore(boolean *returnValue) override; + HRESULT STDMETHODCALLTYPE IsPasswordCore(boolean *returnValue) override; + HRESULT STDMETHODCALLTYPE IsRequiredForFormCore(boolean *returnValue) override; + HRESULT STDMETHODCALLTYPE SetFocusCore() override; + HRESULT STDMETHODCALLTYPE GetPeerFromPointCore(ABI::Windows::Foundation::Point point, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **returnValue) override; + HRESULT STDMETHODCALLTYPE GetLiveSettingCore(ABI::Windows::UI::Xaml::Automation::Peers::AutomationLiveSetting *returnValue) override; + +private: + Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeerOverrides> m_base; + Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer> m_core; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAMAINPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp new file mode 100644 index 0000000000..442ff184a8 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtCore/QLoggingCategory> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; + +// Private constructor +QWinRTUiaMetadataCache::QWinRTUiaMetadataCache() +{ +} + +// shared instance +QWinRTUiaMetadataCache *QWinRTUiaMetadataCache::instance() +{ + static QWinRTUiaMetadataCache metadataCache; + return &metadataCache; +} + +// Returns the cached metadata associated with the ID, or an instance with default values. +QSharedPointer<QWinRTUiaControlMetadata> QWinRTUiaMetadataCache::metadataForId(QAccessible::Id id) +{ + QSharedPointer<QWinRTUiaControlMetadata> metadata; + + m_mutex.lock(); + if (m_metadataTable.contains(id)) + metadata = m_metadataTable[id]; + else + metadata = QSharedPointer<QWinRTUiaControlMetadata>(new QWinRTUiaControlMetadata); + m_mutex.unlock(); + return metadata; +} + +// Caches metadata from the accessibility framework within the main thread. +bool QWinRTUiaMetadataCache::load(QAccessible::Id id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([id]() { + QWinRTUiaMetadataCache::instance()->insert(id, QSharedPointer<QWinRTUiaControlMetadata>(new QWinRTUiaControlMetadata(id))); + return S_OK; + }))) { + return false; + } + return true; +} + +// Inserts metadata in the cache and associates it with an accessibility ID. +void QWinRTUiaMetadataCache::insert(QAccessible::Id id, const QSharedPointer<QWinRTUiaControlMetadata> &metadata) +{ + m_mutex.lock(); + m_metadataTable[id] = metadata; + m_mutex.unlock(); +} + +// Removes metadata with a given id from the cache. +void QWinRTUiaMetadataCache::remove(QAccessible::Id id) +{ + m_mutex.lock(); + m_metadataTable.remove(id); + m_mutex.unlock(); +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h new file mode 100644 index 0000000000..2d68d1b654 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAMETADATACACHE_H +#define QWINRTUIAMETADATACACHE_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiacontrolmetadata.h" + +#include <QtCore/QHash> +#include <QtCore/QMutex> +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> + +QT_BEGIN_NAMESPACE + +// Singleton used to cache metadata using the accessibility ID as the key. +class QWinRTUiaMetadataCache : public QObject +{ + QWinRTUiaMetadataCache(); + Q_OBJECT +public: + static QWinRTUiaMetadataCache *instance(); + QSharedPointer<QWinRTUiaControlMetadata> metadataForId(QAccessible::Id id); + void insert(QAccessible::Id id, const QSharedPointer<QWinRTUiaControlMetadata> &metadata); + void remove(QAccessible::Id id); + bool load(QAccessible::Id id); + +private: + QHash<QAccessible::Id, QSharedPointer<QWinRTUiaControlMetadata>> m_metadataTable; + QMutex m_mutex; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAMETADATACACHE_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp new file mode 100644 index 0000000000..e3d6bcae4b --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiapeervector.h" +#include "qwinrtuiautils.h" + +using namespace ABI::Windows::UI::Xaml::Automation::Peers; +using namespace ABI::Windows::Foundation::Collections; + +QT_BEGIN_NAMESPACE + +HRESULT QWinRTUiaPeerVector::GetAt(quint32 index, IAutomationPeer **item) +{ + if (index >= quint32(m_impl.size())) + return E_FAIL; + if ((*item = m_impl.at(index))) + (*item)->AddRef(); + return S_OK; +} + +HRESULT QWinRTUiaPeerVector::get_Size(quint32 *size) +{ + *size = m_impl.size(); + return S_OK; +} + +HRESULT QWinRTUiaPeerVector::GetView(IVectorView<AutomationPeer *> **view) +{ + *view = nullptr; + return E_NOTIMPL; +} + +HRESULT QWinRTUiaPeerVector::IndexOf(IAutomationPeer *value, quint32 *index, boolean *found) +{ + int idx = m_impl.indexOf(value); + if (idx > -1) { + *index = quint32(idx); + *found = true; + } else { + *found = false; + } + return S_OK; +} + +HRESULT QWinRTUiaPeerVector::SetAt(quint32 index, IAutomationPeer *item) +{ + if (index >= quint32(m_impl.size())) + return E_FAIL; + if (IAutomationPeer *elem = m_impl.at(index)) { + if (elem == item) + return S_OK; + else + elem->Release(); + } + if (item) + item->AddRef(); + m_impl[index] = item; + return S_OK; +} + +HRESULT QWinRTUiaPeerVector::InsertAt(quint32 index, IAutomationPeer *item) +{ + if (index >= quint32(m_impl.size())) + return E_FAIL; + if (item) + item->AddRef(); + m_impl.insert(index, item); + return S_OK; +} + +HRESULT QWinRTUiaPeerVector::RemoveAt(quint32 index) +{ + if (index >= quint32(m_impl.size())) + return E_FAIL; + if (IAutomationPeer *elem = m_impl.at(index)) + elem->Release(); + m_impl.remove(index); + return S_OK; +} + +HRESULT QWinRTUiaPeerVector::Append(IAutomationPeer *item) +{ + if (item) + item->AddRef(); + m_impl.append(item); + return S_OK; +} + +HRESULT QWinRTUiaPeerVector::RemoveAtEnd() +{ + if (m_impl.size() == 0) + return E_FAIL; + if (IAutomationPeer *elem = m_impl.last()) + elem->Release(); + m_impl.removeLast(); + return S_OK; +} + +HRESULT QWinRTUiaPeerVector::Clear() +{ + for (auto elem : qAsConst(m_impl)) + if (elem) + elem->Release(); + m_impl.clear(); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h new file mode 100644 index 0000000000..265526de09 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAPEERVECTOR_H +#define QWINRTUIAPEERVECTOR_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include <QtCore/QString> +#include <QtCore/qt_windows.h> +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtGui/QWindow> +#include <QVector> + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements IVector<AutomationPeer *> +class QWinRTUiaPeerVector : public Microsoft::WRL::RuntimeClass<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::UI::Xaml::Automation::Peers::AutomationPeer *>> +{ +public: + HRESULT STDMETHODCALLTYPE GetAt(quint32 index, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer **item) override; + HRESULT STDMETHODCALLTYPE get_Size(quint32 *size) override; + HRESULT STDMETHODCALLTYPE GetView(ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::UI::Xaml::Automation::Peers::AutomationPeer *> **view) override; + HRESULT STDMETHODCALLTYPE IndexOf(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *value, quint32 *index, boolean *found) override; + HRESULT STDMETHODCALLTYPE SetAt(quint32 index, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *item) override; + HRESULT STDMETHODCALLTYPE InsertAt(quint32 index, ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *item) override; + HRESULT STDMETHODCALLTYPE RemoveAt(quint32 index) override; + HRESULT STDMETHODCALLTYPE Append(ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *item) override; + HRESULT STDMETHODCALLTYPE RemoveAtEnd() override; + HRESULT STDMETHODCALLTYPE Clear() override; +private: + QVector<ABI::Windows::UI::Xaml::Automation::Peers::IAutomationPeer *> m_impl; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAPEERVECTOR_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp new file mode 100644 index 0000000000..06ff094c45 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiaprovidercache.h" + +QT_BEGIN_NAMESPACE + +// Private constructor +QWinRTUiaProviderCache::QWinRTUiaProviderCache() +{ +} + +// shared instance +QWinRTUiaProviderCache *QWinRTUiaProviderCache::instance() +{ + static QWinRTUiaProviderCache providerCache; + return &providerCache; +} + +// Returns the provider instance associated with the ID, or nullptr. +QWinRTUiaBaseProvider *QWinRTUiaProviderCache::providerForId(QAccessible::Id id) const +{ + return m_providerTable.value(id); +} + +// Inserts a provider in the cache and associates it with an accessibility ID. +void QWinRTUiaProviderCache::insert(QAccessible::Id id, QWinRTUiaBaseProvider *provider) +{ + remove(id); + if (provider) { + m_providerTable[id] = provider; + m_inverseTable[provider] = id; + // Connects the destroyed signal to our slot, to remove deleted objects from the cache. + QObject::connect(provider, &QObject::destroyed, this, &QWinRTUiaProviderCache::objectDestroyed); + } +} + +// Removes deleted provider objects from the cache. +void QWinRTUiaProviderCache::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 = m_inverseTable.find(obj); + if (it != m_inverseTable.end()) { + m_providerTable.remove(*it); + m_inverseTable.remove(obj); + } +} + +// Removes a provider with a given id from the cache. +void QWinRTUiaProviderCache::remove(QAccessible::Id id) +{ + m_inverseTable.remove(m_providerTable.value(id)); + m_providerTable.remove(id); +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h new file mode 100644 index 0000000000..393ef7d562 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAPROVIDERCACHE_H +#define QWINRTUIAPROVIDERCACHE_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <QtCore/QHash> +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> + +QT_BEGIN_NAMESPACE + +// Singleton used to cache provider instances using the accessibility ID as the key. +class QWinRTUiaProviderCache : public QObject +{ + QWinRTUiaProviderCache(); + Q_OBJECT +public: + static QWinRTUiaProviderCache *instance(); + QWinRTUiaBaseProvider *providerForId(QAccessible::Id id) const; + void insert(QAccessible::Id id, QWinRTUiaBaseProvider *provider); + void remove(QAccessible::Id id); + +private Q_SLOTS: + void objectDestroyed(QObject *obj); + +private: + QHash<QAccessible::Id, QWinRTUiaBaseProvider *> m_providerTable; + QHash<QObject *, QAccessible::Id> m_inverseTable; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAPROVIDERCACHE_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp new file mode 100644 index 0000000000..4ac59c890a --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiarangevalueprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; + +QWinRTUiaRangeValueProvider::QWinRTUiaRangeValueProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaRangeValueProvider::~QWinRTUiaRangeValueProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_IsReadOnly(boolean *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = (metadata->state().readOnly != 0); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_LargeChange(DOUBLE *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->minimumStepSize(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_Maximum(DOUBLE *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->maximumValue(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_Minimum(DOUBLE *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->minimumValue(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_SmallChange(DOUBLE *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->minimumStepSize(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::get_Value(DOUBLE *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = metadata->currentValue(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaRangeValueProvider::SetValue(DOUBLE value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + + QEventDispatcherWinRT::runOnMainThread([accid, value]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { + double minimum = valueInterface->minimumValue().toDouble(); + double maximum = valueInterface->maximumValue().toDouble(); + if ((value >= minimum) && (value <= maximum)) { + valueInterface->setCurrentValue(QVariant(value)); + } + } + } + QWinRTUiaMetadataCache::instance()->load(accid); + return S_OK; + }, 0); + + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h new file mode 100644 index 0000000000..4e98959526 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIARANGEVALUEPROVIDER_H +#define QWINRTUIARANGEVALUEPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Range Value control pattern provider. +class QWinRTUiaRangeValueProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IRangeValueProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaRangeValueProvider) + InspectableClass(L"QWinRTUiaRangeValueProvider", BaseTrust); + +public: + explicit QWinRTUiaRangeValueProvider(QAccessible::Id id); + virtual ~QWinRTUiaRangeValueProvider(); + + // IRangeValueProvider + HRESULT STDMETHODCALLTYPE get_IsReadOnly(boolean *value) override; + HRESULT STDMETHODCALLTYPE get_LargeChange(DOUBLE *value) override; + HRESULT STDMETHODCALLTYPE get_Maximum(DOUBLE *value) override; + HRESULT STDMETHODCALLTYPE get_Minimum(DOUBLE *value) override; + HRESULT STDMETHODCALLTYPE get_SmallChange(DOUBLE *value) override; + HRESULT STDMETHODCALLTYPE get_Value(DOUBLE *value) override; + HRESULT STDMETHODCALLTYPE SetValue(DOUBLE value) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIARANGEVALUEPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp new file mode 100644 index 0000000000..9bc88272ba --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiaselectionitemprovider.h" +#include "qwinrtuiamainprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; +using namespace ABI::Windows::UI::Xaml::Automation::Peers; + +QWinRTUiaSelectionItemProvider::QWinRTUiaSelectionItemProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaSelectionItemProvider::~QWinRTUiaSelectionItemProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +// Returns true if element is currently selected. +HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::get_IsSelected(boolean *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + if (metadata->role() == QAccessible::RadioButton) + *value = metadata->state().checked; + else + *value = metadata->state().selected; + return S_OK; +} + +// Returns the provider for the container element (e.g., the list for the list item). +HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::get_SelectionContainer(IIRawElementProviderSimple **value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + *value = nullptr; + + auto accid = id(); + auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0)); + auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + // Radio buttons do not require a container. + if (accessible->role() == QAccessible::ListItem) { + if (QAccessibleInterface *parent = accessible->parent()) { + if (parent->role() == QAccessible::List) { + **ptrElementId = idForAccessible(parent); + } + } + } + } + delete ptrElementId; + return S_OK; + }))) { + return E_FAIL; + } + + if (!*elementId) + return S_OK; + + return QWinRTUiaMainProvider::rawProviderForAccessibleId(*elementId, value); +} + +// Adds the element to the list of selected elements. +HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::AddToSelection() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + + QEventDispatcherWinRT::runOnMainThread([accid]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) { + 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()); + } + } + } + } + QWinRTUiaMetadataCache::instance()->load(accid); + return S_OK; + }, 0); + return S_OK; +} + +// Removes a list item from selection. +HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::RemoveFromSelection() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + + QEventDispatcherWinRT::runOnMainThread([accid]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) { + if (accessible->role() != QAccessible::RadioButton) { + if (accessible->state().selected) { + actionInterface->doAction(QAccessibleActionInterface::toggleAction()); + } + } + } + } + QWinRTUiaMetadataCache::instance()->load(accid); + return S_OK; + }, 0); + return S_OK; +} + +// Selects the element (deselecting all others). +HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::Select() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + + QEventDispatcherWinRT::runOnMainThread([accid]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) { + 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()); + } + } + } + } + } + } + } + } + QWinRTUiaMetadataCache::instance()->load(accid); + return S_OK; + }, 0); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h new file mode 100644 index 0000000000..1b3cce7495 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIASELECTIONITEMPROVIDER_H +#define QWINRTUIASELECTIONITEMPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Selection Item control pattern provider. Used for List items and radio buttons. +class QWinRTUiaSelectionItemProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ISelectionItemProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaSelectionItemProvider) + InspectableClass(L"QWinRTUiaSelectionItemProvider", BaseTrust); + +public: + explicit QWinRTUiaSelectionItemProvider(QAccessible::Id id); + virtual ~QWinRTUiaSelectionItemProvider(); + + // ISelectionItemProvider + HRESULT STDMETHODCALLTYPE get_IsSelected(boolean *value) override; + HRESULT STDMETHODCALLTYPE get_SelectionContainer(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **value) override; + HRESULT STDMETHODCALLTYPE AddToSelection() override; + HRESULT STDMETHODCALLTYPE RemoveFromSelection() override; + HRESULT STDMETHODCALLTYPE Select() override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIASELECTIONITEMPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp new file mode 100644 index 0000000000..9e61a8df61 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiaselectionprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiamainprovider.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; +using namespace ABI::Windows::UI::Xaml::Automation::Peers; + +QWinRTUiaSelectionProvider::QWinRTUiaSelectionProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaSelectionProvider::~QWinRTUiaSelectionProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_CanSelectMultiple(boolean *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = (metadata->state().multiSelectable != 0); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_IsSelectionRequired(boolean *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + *value = false; + + auto accid = id(); + auto selectionRequired = QSharedPointer<bool>(new bool(false)); + auto ptrSelectionRequired = new QSharedPointer<bool>(selectionRequired); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelectionRequired]() { + // Initially returns false if none are selected. After the first selection, it may be required. + bool anySelected = false; + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + int childCount = accessible->childCount(); + for (int i = 0; i < childCount; ++i) { + if (QAccessibleInterface *childAcc = accessible->child(i)) { + if (childAcc->state().selected) { + anySelected = true; + break; + } + } + } + **ptrSelectionRequired = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable; + } + delete ptrSelectionRequired; + return S_OK; + }))) { + return E_FAIL; + } + + *value = *selectionRequired; + return S_OK; +} + +// Returns an array of providers with the selected items. +HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::GetSelection(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValueSize || !returnValue) + return E_INVALIDARG; + *returnValueSize = 0; + *returnValue = nullptr; + + auto accid = id(); + auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); + auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + int childCount = accessible->childCount(); + for (int i = 0; i < childCount; ++i) { + if (QAccessibleInterface *childAcc = accessible->child(i)) { + if (childAcc->state().selected) { + QAccessible::Id childId = idForAccessible(childAcc); + QWinRTUiaMetadataCache::instance()->load(childId); + (*ptrElementIds)->append(childId); + } + } + } + } + delete ptrElementIds; + return S_OK; + }))) { + return E_FAIL; + } + + return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue); +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h new file mode 100644 index 0000000000..dcd286800f --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIASELECTIONPROVIDER_H +#define QWINRTUIASELECTIONPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Selection control pattern provider. Used for Lists. +class QWinRTUiaSelectionProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ISelectionProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaSelectionProvider) + InspectableClass(L"QWinRTUiaSelectionProvider", BaseTrust); + +public: + explicit QWinRTUiaSelectionProvider(QAccessible::Id id); + virtual ~QWinRTUiaSelectionProvider(); + + // ISelectionProvider + HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(boolean *value) override; + HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(boolean *value) override; + HRESULT STDMETHODCALLTYPE GetSelection(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIASELECTIONPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp new file mode 100644 index 0000000000..1af74a8b72 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiatableitemprovider.h" +#include "qwinrtuiamainprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; + +QWinRTUiaTableItemProvider::QWinRTUiaTableItemProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaTableItemProvider::~QWinRTUiaTableItemProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +// Returns the providers for the column headers associated with the item. +HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetColumnHeaderItems(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValueSize || !returnValue) + return E_INVALIDARG; + *returnValueSize = 0; + *returnValue = nullptr; + + auto accid = id(); + auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); + auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) { + QList<QAccessibleInterface *> headers = tableCellInterface->columnHeaderCells(); + for (auto header : qAsConst(headers)) { + QAccessible::Id headerId = idForAccessible(header); + QWinRTUiaMetadataCache::instance()->load(headerId); + (*ptrElementIds)->append(headerId); + } + } + } + delete ptrElementIds; + return S_OK; + }))) { + return E_FAIL; + } + + return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue); +} + +// Returns the providers for the row headers associated with the item. +HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetRowHeaderItems(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValueSize || !returnValue) + return E_INVALIDARG; + *returnValueSize = 0; + *returnValue = nullptr; + + auto accid = id(); + auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); + auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) { + QList<QAccessibleInterface *> headers = tableCellInterface->rowHeaderCells(); + for (auto header : qAsConst(headers)) { + QAccessible::Id headerId = idForAccessible(header); + QWinRTUiaMetadataCache::instance()->load(headerId); + (*ptrElementIds)->append(headerId); + } + } + } + delete ptrElementIds; + return S_OK; + }))) { + return E_FAIL; + } + + return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue); +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h new file mode 100644 index 0000000000..cb759864ae --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIATABLEITEMPROVIDER_H +#define QWINRTUIATABLEITEMPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Table Item control pattern provider. Used by items within a table/tree. +class QWinRTUiaTableItemProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITableItemProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaTableItemProvider) + InspectableClass(L"QWinRTUiaTableItemProvider", BaseTrust); + +public: + explicit QWinRTUiaTableItemProvider(QAccessible::Id id); + virtual ~QWinRTUiaTableItemProvider(); + + // ITableItemProvider + HRESULT STDMETHODCALLTYPE GetColumnHeaderItems(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override; + HRESULT STDMETHODCALLTYPE GetRowHeaderItems(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIATABLEITEMPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp new file mode 100644 index 0000000000..e71ade3c1f --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiatableprovider.h" +#include "qwinrtuiamainprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; +using namespace ABI::Windows::UI::Xaml::Automation::Peers; + +QWinRTUiaTableProvider::QWinRTUiaTableProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaTableProvider::~QWinRTUiaTableProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +// Returns the primary direction of traversal for the table. +HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::get_RowOrColumnMajor(RowOrColumnMajor *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + *value = RowOrColumnMajor_Indeterminate; + return S_OK; +} + +// Gets the providers for all the column headers in the table. +HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetColumnHeaders(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValueSize || !returnValue) + return E_INVALIDARG; + *returnValueSize = 0; + *returnValue = nullptr; + + auto accid = id(); + auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); + auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) { + for (int i = 0; i < tableInterface->columnCount(); ++i) { + if (QAccessibleInterface *cell = tableInterface->cellAt(0, i)) { + QWinRTUiaMetadataCache::instance()->load(idForAccessible(cell)); + if (QAccessibleTableCellInterface *tableCellInterface = cell->tableCellInterface()) { + QList<QAccessibleInterface *> headers = tableCellInterface->columnHeaderCells(); + for (auto header : qAsConst(headers)) { + QAccessible::Id headerId = idForAccessible(header); + QWinRTUiaMetadataCache::instance()->load(headerId); + (*ptrElementIds)->append(headerId); + } + } + } + } + } + } + delete ptrElementIds; + return S_OK; + }))) { + return E_FAIL; + } + + return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue); +} + +// Gets the providers for all the row headers in the table. +HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetRowHeaders(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValueSize || !returnValue) + return E_INVALIDARG; + *returnValueSize = 0; + *returnValue = nullptr; + + auto accid = id(); + auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>); + auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) { + for (int i = 0; i < tableInterface->rowCount(); ++i) { + if (QAccessibleInterface *cell = tableInterface->cellAt(i, 0)) { + QWinRTUiaMetadataCache::instance()->load(idForAccessible(cell)); + if (QAccessibleTableCellInterface *tableCellInterface = cell->tableCellInterface()) { + QList<QAccessibleInterface *> headers = tableCellInterface->rowHeaderCells(); + for (auto header : qAsConst(headers)) { + QAccessible::Id headerId = idForAccessible(header); + QWinRTUiaMetadataCache::instance()->load(headerId); + (*ptrElementIds)->append(headerId); + } + } + } + } + } + } + delete ptrElementIds; + return S_OK; + }))) { + return E_FAIL; + } + + return QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(*elementIds, returnValueSize, returnValue); +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h new file mode 100644 index 0000000000..0cd174e401 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIATABLEPROVIDER_H +#define QWINRTUIATABLEPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Table control pattern provider. Used by tables/trees. +class QWinRTUiaTableProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITableProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaTableProvider) + InspectableClass(L"QWinRTUiaTableProvider", BaseTrust); + +public: + explicit QWinRTUiaTableProvider(QAccessible::Id id); + virtual ~QWinRTUiaTableProvider(); + + // ITableProvider + HRESULT STDMETHODCALLTYPE get_RowOrColumnMajor(ABI::Windows::UI::Xaml::Automation::RowOrColumnMajor *value) override; + HRESULT STDMETHODCALLTYPE GetColumnHeaders(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override; + HRESULT STDMETHODCALLTYPE GetRowHeaders(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIATABLEPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp new file mode 100644 index 0000000000..aa120377df --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiatextprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiatextrangeprovider.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; + +QWinRTUiaTextProvider::QWinRTUiaTextProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaTextProvider::~QWinRTUiaTextProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +// Returns a text range provider for the entire text. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::get_DocumentRange(ITextRangeProvider **value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), 0, metadata->characterCount()); + return textRangeProvider.CopyTo(value); +} + +// Currently supporting single selection. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::get_SupportedTextSelection(SupportedTextSelection *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!value) + return E_INVALIDARG; + *value = SupportedTextSelection_Single; + return S_OK; + +} + +// Returns an array of providers for the selected text ranges. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetSelection(UINT32 *returnValueSize, ITextRangeProvider ***returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValueSize || !returnValue) + return E_INVALIDARG; + *returnValueSize = 0; + *returnValue = nullptr; + + auto accid = id(); + auto selections = QSharedPointer<QList<QPair<int,int>>>(new QList<QPair<int,int>>); + auto ptrSelections = new QSharedPointer<QList<QPair<int,int>>>(selections); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelections]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleTextInterface *textInterface = accessible->textInterface()) { + for (int i = 0; i < textInterface->selectionCount(); ++i) { + QPair<int,int> sel; + textInterface->selection(i, &sel.first, &sel.second); + (*ptrSelections)->append(sel); + } + if ((*ptrSelections)->size() == 0) { + // If there is no selection, we return an array with a single degenerate (empty) text range at the cursor position. + QPair<int,int> sel(textInterface->cursorPosition(), textInterface->cursorPosition()); + (*ptrSelections)->append(sel); + } + } + } + delete ptrSelections; + return S_OK; + }))) { + return E_FAIL; + } + + int selCount = selections->size(); + if (selCount < 1) + return E_FAIL; + + ITextRangeProvider **providerArray = static_cast<ITextRangeProvider **>(CoTaskMemAlloc(selCount * sizeof(ITextRangeProvider *))); + if (!providerArray) + return E_OUTOFMEMORY; + + for (int i = 0; i < selCount; ++i) { + ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), (*selections)[i].first, (*selections)[i].second); + textRangeProvider.CopyTo(&providerArray[i]); + } + *returnValueSize = selCount; + *returnValue = providerArray; + return S_OK; +} + +// Returns an array of providers for the visible text ranges. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetVisibleRanges(UINT32 *returnValueSize, ITextRangeProvider ***returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValueSize || !returnValue) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + + // Considering the entire text as visible. + ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), 0, metadata->characterCount()); + textRangeProvider.CopyTo(*returnValue); + *returnValueSize = 1; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromChild(IIRawElementProviderSimple *childElement, ITextRangeProvider **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!childElement || !returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + // No children supported. + return S_OK; +} + +// Returns a degenerate text range at the specified point. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromPoint(ABI::Windows::Foundation::Point screenLocation, ITextRangeProvider **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + + const QPoint pt(screenLocation.X, screenLocation.Y); + auto accid = id(); + auto offset = QSharedPointer<int>(new int); + auto ptrOffset = new QSharedPointer<int>(offset); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, pt, ptrOffset]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) + if (QAccessibleTextInterface *textInterface = accessible->textInterface()) + **ptrOffset = qBound(0, textInterface->offsetAtPoint(pt), textInterface->characterCount() - 1); + delete ptrOffset; + return S_OK; + }))) { + return E_FAIL; + } + + ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), *offset, *offset); + textRangeProvider.CopyTo(returnValue); + return S_OK; +} + +// Not supporting annotations. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromAnnotation(IIRawElementProviderSimple *annotationElement, ITextRangeProvider **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!annotationElement || !returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetCaretRange(boolean *isActive, ITextRangeProvider **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!isActive || !returnValue) + return E_INVALIDARG; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *isActive = metadata->state().focused; + + ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), metadata->cursorPosition(), metadata->cursorPosition()); + return textRangeProvider.CopyTo(returnValue); +} + + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h new file mode 100644 index 0000000000..80d88e4115 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIATEXTPROVIDER_H +#define QWINRTUIATEXTPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Text control pattern provider. Used for text controls. +class QWinRTUiaTextProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITextProvider, ABI::Windows::UI::Xaml::Automation::Provider::ITextProvider2> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaTextProvider) + InspectableClass(L"QWinRTUiaTextProvider", BaseTrust); + +public: + explicit QWinRTUiaTextProvider(QAccessible::Id id); + virtual ~QWinRTUiaTextProvider(); + + // ITextProvider + HRESULT STDMETHODCALLTYPE get_DocumentRange(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **value) override; + HRESULT STDMETHODCALLTYPE get_SupportedTextSelection(ABI::Windows::UI::Xaml::Automation::SupportedTextSelection *value) override; + HRESULT STDMETHODCALLTYPE GetSelection(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider ***returnValue) override; + HRESULT STDMETHODCALLTYPE GetVisibleRanges(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider ***returnValue) override; + HRESULT STDMETHODCALLTYPE RangeFromChild(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple *childElement, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override; + HRESULT STDMETHODCALLTYPE RangeFromPoint(ABI::Windows::Foundation::Point screenLocation, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override; + + // ITextProvider2 + HRESULT STDMETHODCALLTYPE RangeFromAnnotation(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple *annotationElement, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override; + HRESULT STDMETHODCALLTYPE GetCaretRange(boolean *isActive, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIATEXTPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp new file mode 100644 index 0000000000..fc3778d652 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp @@ -0,0 +1,497 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiatextrangeprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiamainprovider.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; +using namespace ABI::Windows::UI::Xaml::Automation::Text; + +QWinRTUiaTextRangeProvider::QWinRTUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset) : + QWinRTUiaBaseProvider(id), + m_startOffset(startOffset), + m_endOffset(endOffset) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << startOffset << endOffset; +} + +QWinRTUiaTextRangeProvider::~QWinRTUiaTextRangeProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Clone(ITextRangeProvider **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!returnValue) + return E_INVALIDARG; + + ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), m_startOffset, m_endOffset); + textRangeProvider.CopyTo(returnValue); + return S_OK; +} + +// Two ranges are considered equal if their start/end points are the same. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Compare(ITextRangeProvider *textRangeProvider, boolean *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!textRangeProvider || !returnValue) + return E_INVALIDARG; + + QWinRTUiaTextRangeProvider *targetProvider = static_cast<QWinRTUiaTextRangeProvider *>(textRangeProvider); + *returnValue = ((targetProvider->m_startOffset == m_startOffset) && (targetProvider->m_endOffset == m_endOffset)); + return S_OK; +} + +// Compare different endpoinds between two providers. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::CompareEndpoints(TextPatternRangeEndpoint endpoint, ITextRangeProvider *textRangeProvider, TextPatternRangeEndpoint targetEndpoint, INT32 *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!textRangeProvider || !returnValue) + return E_INVALIDARG; + + QWinRTUiaTextRangeProvider *targetProvider = static_cast<QWinRTUiaTextRangeProvider *>(textRangeProvider); + + int point = (endpoint == TextPatternRangeEndpoint_Start) ? m_startOffset : m_endOffset; + int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ? + targetProvider->m_startOffset : targetProvider->m_endOffset; + *returnValue = point - targetPoint; + return S_OK; +} + +// Expands/normalizes the range for a given text unit. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::ExpandToEnclosingUnit(TextUnit unit) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "unit=" << unit << "this: " << this; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + + int len = metadata->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 = metadata->text(); + 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 STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::FindAttribute(INT32 /*attributeId*/, IInspectable * /*value*/, boolean /*backward*/, ITextRangeProvider **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::FindText(HSTRING /*text*/, boolean /*backward*/, boolean /*ignoreCase*/, ITextRangeProvider **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + return S_OK; +} + +// Returns the value of a given attribute. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetAttributeValue(INT32 attributeId, IInspectable **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "attributeId=" << attributeId; + + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + + ComPtr<IPropertyValueStatics> propertyValueStatics; + if (FAILED(RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), IID_PPV_ARGS(&propertyValueStatics)))) + return E_FAIL; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + + switch (attributeId) { + case AutomationTextAttributesEnum_IsReadOnlyAttribute: + return propertyValueStatics->CreateBoolean(metadata->state().readOnly, returnValue); + case AutomationTextAttributesEnum_CaretPositionAttribute: + if (metadata->cursorPosition() == 0) + return propertyValueStatics->CreateInt32(AutomationCaretPosition_BeginningOfLine, returnValue); + else if (metadata->cursorPosition() == metadata->characterCount()) + return propertyValueStatics->CreateInt32(AutomationCaretPosition_EndOfLine, returnValue); + else + return propertyValueStatics->CreateInt32(AutomationCaretPosition_Unknown, returnValue); + default: + break; + } + return E_FAIL; +} + +// Returns an array of bounding rectangles for text lines within the range. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT32 *returnValueSize, DOUBLE **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValueSize || !returnValue) + return E_INVALIDARG; + *returnValueSize = 0; + *returnValue = nullptr; + + auto accid = id(); + auto startOffset = m_startOffset; + auto endOffset = m_endOffset; + auto rects = QSharedPointer<QList<QRect>>(new QList<QRect>); + auto ptrRects = new QSharedPointer<QList<QRect>>(rects); + + if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset, ptrRects]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + if (QAccessibleTextInterface *textInterface = accessible->textInterface()) { + int len = textInterface->characterCount(); + if ((startOffset >= 0) && (endOffset <= len) && (startOffset < endOffset)) { + int start, end; + textInterface->textAtOffset(startOffset, QAccessible::LineBoundary, &start, &end); + while ((start >= 0) && (end >= 0)) { + int startRange = qMax(start, startOffset); + int endRange = qMin(end, endOffset); + if (startRange < endRange) { + // Calculates a bounding rectangle for the line and adds it to the list. + const QRect startRect = textInterface->characterRect(startRange); + const QRect endRect = textInterface->characterRect(endRange - 1); + const 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())); + (*ptrRects)->append(lineRect); + } + if (end >= len) break; + textInterface->textAfterOffset(end + 1, QAccessible::LineBoundary, &start, &end); + } + } + } + } + delete ptrRects; + return S_OK; + }))) { + return E_FAIL; + } + + DOUBLE *doubleArray = static_cast<DOUBLE *>(CoTaskMemAlloc(4 * rects->size() * sizeof(DOUBLE))); + if (!doubleArray) + return E_OUTOFMEMORY; + + for (int i = 0; i < rects->size(); ++i) { + doubleArray[i*4] = (*rects)[i].left(); + doubleArray[i*4+1] = (*rects)[i].top(); + doubleArray[i*4+2] = (*rects)[i].width(); + doubleArray[i*4+3] = (*rects)[i].height(); + } + *returnValue = doubleArray; + *returnValueSize = 4 * rects->size(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetEnclosingElement(IIRawElementProviderSimple **returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!returnValue) + return E_INVALIDARG; + return QWinRTUiaMainProvider::rawProviderForAccessibleId(id(), returnValue); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetText(INT32 maxLength, HSTRING *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!returnValue) + return E_INVALIDARG; + *returnValue = nullptr; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + + QString rangeText = metadata->text().mid(m_startOffset, m_endOffset - m_startOffset); + + if ((maxLength > -1) && (rangeText.size() > maxLength)) + rangeText.truncate(maxLength); + return qHString(rangeText, returnValue); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Move(TextUnit unit, INT32 count, INT32 *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!returnValue) + return E_INVALIDARG; + *returnValue = 0; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + + int len = metadata->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; + *returnValue = start - m_startOffset; // Returns the actually moved distance. + m_startOffset = start; + } else { + if (count > 0) { + MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, returnValue); + MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, returnValue); + } else { + MoveEndpointByUnit(TextPatternRangeEndpoint_Start, unit, count, returnValue); + MoveEndpointByUnit(TextPatternRangeEndpoint_End, unit, count, returnValue); + } + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, INT32 count, INT32 *returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!returnValue) + return E_INVALIDARG; + *returnValue = 0; + + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + + int len = metadata->characterCount(); + if (len < 1) + return S_OK; + + if (unit == TextUnit_Character) { + if (endpoint == TextPatternRangeEndpoint_Start) { + int boundedValue = qBound(0, m_startOffset + count, len - 1); + *returnValue = boundedValue - m_startOffset; + m_startOffset = boundedValue; + m_endOffset = qBound(m_startOffset, m_endOffset, len); + } else { + int boundedValue = qBound(0, m_endOffset + count, len); + *returnValue = boundedValue - m_endOffset; + m_endOffset = boundedValue; + m_startOffset = qBound(0, m_startOffset, m_endOffset); + } + } else { + QString text = metadata->text(); + 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); + } + } + *returnValue = moved; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::MoveEndpointByRange(TextPatternRangeEndpoint endpoint, ITextRangeProvider *textRangeProvider, TextPatternRangeEndpoint targetEndpoint) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + if (!textRangeProvider) + return E_INVALIDARG; + + QWinRTUiaTextRangeProvider *targetProvider = static_cast<QWinRTUiaTextRangeProvider *>(textRangeProvider); + + 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; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::Select() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + auto startOffset = m_startOffset; + auto endOffset = m_endOffset; + + QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) + if (QAccessibleTextInterface *textInterface = accessible->textInterface()) { + // unselects all and adds a new selection + for (int i = textInterface->selectionCount() - 1; i >= 0; --i) + textInterface->removeSelection(i); + textInterface->addSelection(startOffset, endOffset); + } + QWinRTUiaMetadataCache::instance()->load(accid); + return S_OK; + }, 0); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::AddToSelection() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + return Select(); +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::RemoveFromSelection() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + + QEventDispatcherWinRT::runOnMainThread([accid]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) + if (QAccessibleTextInterface *textInterface = accessible->textInterface()) { + // unselects all + for (int i = textInterface->selectionCount() - 1; i >= 0; --i) + textInterface->removeSelection(i); + } + QWinRTUiaMetadataCache::instance()->load(accid); + return S_OK; + }, 0); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::ScrollIntoView(boolean /*alignToTop*/) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + auto startOffset = m_startOffset; + auto endOffset = m_endOffset; + + QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) + if (QAccessibleTextInterface *textInterface = accessible->textInterface()) { + textInterface->scrollToSubstring(startOffset, endOffset); + } + QWinRTUiaMetadataCache::instance()->load(accid); + return S_OK; + }, 0); + return S_OK; +} + +// Returns an array of children elements embedded within the range. +HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetChildren(UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!returnValue) + return E_INVALIDARG; + // Not supporting any children. + returnValueSize = 0; + *returnValue = nullptr; + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h new file mode 100644 index 0000000000..81b5f0d400 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIATEXTRANGEPROVIDER_H +#define QWINRTUIATEXTRANGEPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Text Range control pattern provider. Used for text controls. +class QWinRTUiaTextRangeProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaTextRangeProvider) + InspectableClass(L"QWinRTUiaTextRangeProvider", BaseTrust); + +public: + explicit QWinRTUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset); + virtual ~QWinRTUiaTextRangeProvider(); + + // ITextRangeProvider + HRESULT STDMETHODCALLTYPE Clone(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override; + HRESULT STDMETHODCALLTYPE Compare(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider *textRangeProvider, boolean *returnValue) override; + HRESULT STDMETHODCALLTYPE CompareEndpoints(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider *textRangeProvider, ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint, INT32 *returnValue) override; + HRESULT STDMETHODCALLTYPE ExpandToEnclosingUnit(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit) override; + HRESULT STDMETHODCALLTYPE FindAttribute(INT32 attributeId, IInspectable *value, boolean backward, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override; + HRESULT STDMETHODCALLTYPE FindText(HSTRING text, boolean backward, boolean ignoreCase, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider **returnValue) override; + HRESULT STDMETHODCALLTYPE GetAttributeValue(INT32 attributeId, IInspectable **returnValue) override; + HRESULT STDMETHODCALLTYPE GetBoundingRectangles(UINT32 *returnValueSize, DOUBLE **returnValue) override; + HRESULT STDMETHODCALLTYPE GetEnclosingElement(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue) override; + HRESULT STDMETHODCALLTYPE GetText(INT32 maxLength, HSTRING *returnValue) override; + HRESULT STDMETHODCALLTYPE Move(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit, INT32 count, INT32 *returnValue) override; + HRESULT STDMETHODCALLTYPE MoveEndpointByUnit(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint, ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit, INT32 count, INT32 *returnValue) override; + HRESULT STDMETHODCALLTYPE MoveEndpointByRange(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint, ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider *textRangeProvider, ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint) override; + HRESULT STDMETHODCALLTYPE Select() override; + HRESULT STDMETHODCALLTYPE AddToSelection() override; + HRESULT STDMETHODCALLTYPE RemoveFromSelection() override; + HRESULT STDMETHODCALLTYPE ScrollIntoView(boolean alignToTop) override; + HRESULT STDMETHODCALLTYPE GetChildren(UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue) override; + +private: + int m_startOffset; + int m_endOffset; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIATEXTRANGEPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp new file mode 100644 index 0000000000..59f55eb422 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiatoggleprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; + +QWinRTUiaToggleProvider::QWinRTUiaToggleProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaToggleProvider::~QWinRTUiaToggleProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +// Gets the current toggle state. +HRESULT STDMETHODCALLTYPE QWinRTUiaToggleProvider::get_ToggleState(ToggleState *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + if (metadata->state().checked) + *value = metadata->state().checkStateMixed ? ToggleState_Indeterminate : ToggleState_On; + else + *value = ToggleState_Off; + return S_OK; +} + +// Toggles the state by invoking the toggle action. +HRESULT STDMETHODCALLTYPE QWinRTUiaToggleProvider::Toggle() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + + QEventDispatcherWinRT::runOnMainThread([accid]() { + if (QAccessibleInterface *accessible = accessibleForId(accid)) + if (QAccessibleActionInterface *actionInterface = accessible->actionInterface()) + actionInterface->doAction(QAccessibleActionInterface::toggleAction()); + QWinRTUiaMetadataCache::instance()->load(accid); + return S_OK; + }, 0); + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h new file mode 100644 index 0000000000..3d1740c0a1 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIATOGGLEPROVIDER_H +#define QWINRTUIATOGGLEPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Toggle control pattern provider. Used for checkboxes. +class QWinRTUiaToggleProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IToggleProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaToggleProvider) + InspectableClass(L"QWinRTUiaToggleProvider", BaseTrust); + +public: + explicit QWinRTUiaToggleProvider(QAccessible::Id id); + virtual ~QWinRTUiaToggleProvider(); + + // IToggleProvider + HRESULT STDMETHODCALLTYPE get_ToggleState(ABI::Windows::UI::Xaml::Automation::ToggleState *value) override; + HRESULT STDMETHODCALLTYPE Toggle() override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIATOGGLEPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp new file mode 100644 index 0000000000..16197c99b9 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiautils.h" + +using namespace ABI::Windows::UI::Xaml::Automation::Peers; +using namespace ABI::Windows::UI::Xaml::Automation::Text; +using namespace ABI::Windows::Foundation::Collections; + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcQpaUiAutomation, "qt.qpa.uiautomation") + +namespace QWinRTUiAutomation { + +// 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; +} + +QAccessibleInterface *accessibleForId(QAccessible::Id id) +{ + QAccessibleInterface *accessible = QAccessible::accessibleInterface(id); + if (!accessible || !accessible->isValid()) + return nullptr; + return accessible; +} + +QAccessible::Id idForAccessible(QAccessibleInterface *accessible) +{ + if (!accessible) + return QAccessible::Id(0); + return QAccessible::uniqueId(accessible); +} + +// Maps an accessibility role ID to an UI Automation control type ID. +AutomationControlType roleToControlType(QAccessible::Role role) +{ + static const QHash<QAccessible::Role, AutomationControlType> mapping { + {QAccessible::TitleBar, AutomationControlType::AutomationControlType_TitleBar}, + {QAccessible::MenuBar, AutomationControlType::AutomationControlType_MenuBar}, + {QAccessible::ScrollBar, AutomationControlType::AutomationControlType_ScrollBar}, + {QAccessible::Grip, AutomationControlType::AutomationControlType_Thumb}, + {QAccessible::Sound, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Cursor, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Caret, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::AlertMessage, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Window, AutomationControlType::AutomationControlType_Window}, + {QAccessible::Client, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::PopupMenu, AutomationControlType::AutomationControlType_Menu}, + {QAccessible::MenuItem, AutomationControlType::AutomationControlType_MenuItem}, + {QAccessible::ToolTip, AutomationControlType::AutomationControlType_ToolTip}, + {QAccessible::Application, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Document, AutomationControlType::AutomationControlType_Document}, + {QAccessible::Pane, AutomationControlType::AutomationControlType_Pane}, + {QAccessible::Chart, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Dialog, AutomationControlType::AutomationControlType_Window}, + {QAccessible::Border, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Grouping, AutomationControlType::AutomationControlType_Group}, + {QAccessible::Separator, AutomationControlType::AutomationControlType_Separator}, + {QAccessible::ToolBar, AutomationControlType::AutomationControlType_ToolBar}, + {QAccessible::StatusBar, AutomationControlType::AutomationControlType_StatusBar}, + {QAccessible::Table, AutomationControlType::AutomationControlType_Table}, + {QAccessible::ColumnHeader, AutomationControlType::AutomationControlType_Header}, + {QAccessible::RowHeader, AutomationControlType::AutomationControlType_Header}, + {QAccessible::Column, AutomationControlType::AutomationControlType_HeaderItem}, + {QAccessible::Row, AutomationControlType::AutomationControlType_HeaderItem}, + {QAccessible::Cell, AutomationControlType::AutomationControlType_DataItem}, + {QAccessible::Link, AutomationControlType::AutomationControlType_Hyperlink}, + {QAccessible::HelpBalloon, AutomationControlType::AutomationControlType_ToolTip}, + {QAccessible::Assistant, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::List, AutomationControlType::AutomationControlType_List}, + {QAccessible::ListItem, AutomationControlType::AutomationControlType_ListItem}, + {QAccessible::Tree, AutomationControlType::AutomationControlType_Tree}, + {QAccessible::TreeItem, AutomationControlType::AutomationControlType_TreeItem}, + {QAccessible::PageTab, AutomationControlType::AutomationControlType_TabItem}, + {QAccessible::PropertyPage, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Indicator, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Graphic, AutomationControlType::AutomationControlType_Image}, + {QAccessible::StaticText, AutomationControlType::AutomationControlType_Text}, + {QAccessible::EditableText, AutomationControlType::AutomationControlType_Edit}, + {QAccessible::Button, AutomationControlType::AutomationControlType_Button}, + {QAccessible::CheckBox, AutomationControlType::AutomationControlType_CheckBox}, + {QAccessible::RadioButton, AutomationControlType::AutomationControlType_RadioButton}, + {QAccessible::ComboBox, AutomationControlType::AutomationControlType_ComboBox}, + {QAccessible::ProgressBar, AutomationControlType::AutomationControlType_ProgressBar}, + {QAccessible::Dial, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::HotkeyField, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Slider, AutomationControlType::AutomationControlType_Slider}, + {QAccessible::SpinBox, AutomationControlType::AutomationControlType_Spinner}, + {QAccessible::Canvas, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Animation, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Equation, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::ButtonDropDown, AutomationControlType::AutomationControlType_Button}, + {QAccessible::ButtonMenu, AutomationControlType::AutomationControlType_Button}, + {QAccessible::ButtonDropGrid, AutomationControlType::AutomationControlType_Button}, + {QAccessible::Whitespace, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::PageTabList, AutomationControlType::AutomationControlType_Tab}, + {QAccessible::Clock, AutomationControlType::AutomationControlType_Custom}, + {QAccessible::Splitter, AutomationControlType::AutomationControlType_Custom}, + }; + + return mapping.value(role, AutomationControlType::AutomationControlType_Custom); +} + +// 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')); +} + +HRESULT qHString(const QString &str, HSTRING *returnValue) +{ + if (!returnValue) + return E_INVALIDARG; + + const wchar_t *wstr = reinterpret_cast<const wchar_t *>(str.utf16()); + return ::WindowsCreateString(wstr, static_cast<UINT32>(::wcslen(wstr)), returnValue); +} + +QString hStrToQStr(const HSTRING &hStr) +{ + quint32 len; + const wchar_t *wstr = ::WindowsGetStringRawBuffer(hStr, &len); + return QString::fromWCharArray(wstr, len); +} + +} // namespace QWinRTUiAutomation + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h new file mode 100644 index 0000000000..9519cb4eb5 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAUTILS_H +#define QWINRTUIAUTILS_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include <QtCore/QString> +#include <QtCore/qt_windows.h> +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtGui/QWindow> +#include <QtCore/QLoggingCategory> + +#include <wrl.h> +#include <windows.ui.xaml.h> +#include <functional> + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcQpaUiAutomation) + +namespace QWinRTUiAutomation { + +QWindow *windowForAccessible(const QAccessibleInterface *accessible); + +QAccessibleInterface *accessibleForId(QAccessible::Id id); + +QAccessible::Id idForAccessible(QAccessibleInterface *accessible); + +ABI::Windows::UI::Xaml::Automation::Peers::AutomationControlType roleToControlType(QAccessible::Role role); + +bool isTextUnitSeparator(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit, const QChar &ch); + +HRESULT qHString(const QString &str, HSTRING *returnValue); + +QString hStrToQStr(const HSTRING &hStr); + +} // namespace QWinRTUiAutomation + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAUTILS_H diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp new file mode 100644 index 0000000000..21389b74d2 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiavalueprovider.h" +#include "qwinrtuiametadatacache.h" +#include "qwinrtuiautils.h" + +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleInterface> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QWinRTUiAutomation; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Automation::Provider; + +QWinRTUiaValueProvider::QWinRTUiaValueProvider(QAccessible::Id id) : + QWinRTUiaBaseProvider(id) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +QWinRTUiaValueProvider::~QWinRTUiaValueProvider() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; +} + +// True for read-only controls. +HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::get_IsReadOnly(boolean *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + *value = (metadata->state().readOnly != 0); + return S_OK; +} + +// Returns the value in text form. +HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::get_Value(HSTRING *value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!value) + return E_INVALIDARG; + QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id()); + return qHString(metadata->value(), value); +} + +// Sets the value associated with the control. +HRESULT STDMETHODCALLTYPE QWinRTUiaValueProvider::SetValue(HSTRING value) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + auto accid = id(); + auto tmpValue = QSharedPointer<QString>(new QString); + auto ptrValue = new QSharedPointer<QString>(tmpValue); + + *tmpValue = hStrToQStr(value); + + QEventDispatcherWinRT::runOnMainThread([accid, ptrValue]() { + + if (QAccessibleInterface *accessible = accessibleForId(accid)) { + + // First sets the value as a text. + accessible->setText(QAccessible::Value, **ptrValue); + + // 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 = (*ptrValue)->toDouble(&ok); + if (ok) { + double minimum = valueInterface->minimumValue().toDouble(); + double maximum = valueInterface->maximumValue().toDouble(); + if ((numval >= minimum) && (numval <= maximum)) { + valueInterface->setCurrentValue(QVariant(numval)); + } + } + } + } + QWinRTUiaMetadataCache::instance()->load(accid); + delete ptrValue; + return S_OK; + }, 0); + + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h new file mode 100644 index 0000000000..d9cd5d200d --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QWINRTUIAVALUEPROVIDER_H +#define QWINRTUIAVALUEPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwinrtuiabaseprovider.h" + +#include <wrl.h> +#include <windows.ui.xaml.h> + +QT_BEGIN_NAMESPACE + +// Implements the Value control pattern provider. +// Supported for all controls that can return text(QAccessible::Value). +class QWinRTUiaValueProvider : + public QWinRTUiaBaseProvider, + public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::Automation::Provider::IValueProvider> +{ + Q_OBJECT + Q_DISABLE_COPY(QWinRTUiaValueProvider) + InspectableClass(L"QWinRTUiaValueProvider", BaseTrust); + +public: + explicit QWinRTUiaValueProvider(QAccessible::Id id); + virtual ~QWinRTUiaValueProvider(); + + // IValueProvider + HRESULT STDMETHODCALLTYPE get_IsReadOnly(boolean *value) override; + HRESULT STDMETHODCALLTYPE get_Value(HSTRING *value) override; + HRESULT STDMETHODCALLTYPE SetValue(HSTRING value) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINRTUIAVALUEPROVIDER_H diff --git a/src/plugins/platforms/winrt/uiautomation/uiautomation.pri b/src/plugins/platforms/winrt/uiautomation/uiautomation.pri new file mode 100644 index 0000000000..ca0dfae53f --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/uiautomation.pri @@ -0,0 +1,45 @@ + +SOURCES += \ + $$PWD/qwinrtuiaaccessibility.cpp \ + $$PWD/qwinrtuiabaseprovider.cpp \ + $$PWD/qwinrtuiacontrolmetadata.cpp \ + $$PWD/qwinrtuiagriditemprovider.cpp \ + $$PWD/qwinrtuiagridprovider.cpp \ + $$PWD/qwinrtuiainvokeprovider.cpp \ + $$PWD/qwinrtuiamainprovider.cpp \ + $$PWD/qwinrtuiametadatacache.cpp \ + $$PWD/qwinrtuiapeervector.cpp \ + $$PWD/qwinrtuiaprovidercache.cpp \ + $$PWD/qwinrtuiarangevalueprovider.cpp \ + $$PWD/qwinrtuiaselectionitemprovider.cpp \ + $$PWD/qwinrtuiaselectionprovider.cpp \ + $$PWD/qwinrtuiatableitemprovider.cpp \ + $$PWD/qwinrtuiatableprovider.cpp \ + $$PWD/qwinrtuiatextprovider.cpp \ + $$PWD/qwinrtuiatextrangeprovider.cpp \ + $$PWD/qwinrtuiatoggleprovider.cpp \ + $$PWD/qwinrtuiautils.cpp \ + $$PWD/qwinrtuiavalueprovider.cpp + +HEADERS += \ + $$PWD/qwinrtuiaaccessibility.h \ + $$PWD/qwinrtuiabaseprovider.h \ + $$PWD/qwinrtuiacontrolmetadata.h \ + $$PWD/qwinrtuiaemptypropertyvalue.h \ + $$PWD/qwinrtuiagriditemprovider.h \ + $$PWD/qwinrtuiagridprovider.h \ + $$PWD/qwinrtuiainvokeprovider.h \ + $$PWD/qwinrtuiamainprovider.h \ + $$PWD/qwinrtuiametadatacache.h \ + $$PWD/qwinrtuiapeervector.h \ + $$PWD/qwinrtuiaprovidercache.h \ + $$PWD/qwinrtuiarangevalueprovider.h \ + $$PWD/qwinrtuiaselectionitemprovider.h \ + $$PWD/qwinrtuiaselectionprovider.h \ + $$PWD/qwinrtuiatableitemprovider.h \ + $$PWD/qwinrtuiatableprovider.h \ + $$PWD/qwinrtuiatextprovider.h \ + $$PWD/qwinrtuiatextrangeprovider.h \ + $$PWD/qwinrtuiatoggleprovider.h \ + $$PWD/qwinrtuiautils.h \ + $$PWD/qwinrtuiavalueprovider.h diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 46371b4880..6a847465e4 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -13,6 +13,7 @@ LIBS += -lws2_32 -ld3d11 SOURCES = \ main.cpp \ qwinrtbackingstore.cpp \ + qwinrtcanvas.cpp \ qwinrtclipboard.cpp \ qwinrtcursor.cpp \ qwinrteglcontext.cpp \ @@ -30,6 +31,7 @@ SOURCES = \ HEADERS = \ qwinrtbackingstore.h \ + qwinrtcanvas.h \ qwinrtclipboard.h \ qwinrtcursor.h \ qwinrteglcontext.h \ @@ -56,6 +58,8 @@ qtConfig(draganddrop) { HEADERS += qwinrtdrag.h } +qtConfig(accessibility): include($$PWD/uiautomation/uiautomation.pri) + PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin !equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - |