diff options
Diffstat (limited to 'src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp')
-rw-r--r-- | src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp | 779 |
1 files changed, 779 insertions, 0 deletions
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp new file mode 100644 index 0000000000..99efe27c34 --- /dev/null +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp @@ -0,0 +1,779 @@ +/**************************************************************************** +** +** 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::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); + (*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; + *returnValue = false; + 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) + |