/**************************************************************************** ** ** 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 #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 #include #include #include #include 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 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(this); AddRef(); return S_OK; } else if (iid == IID_IAutomationPeerOverrides) { *iface = static_cast(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(providerCache->providerForId(id)); if (provider) { provider->AddRef(); } else { ComPtr p = Make(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 provider = providerForAccessibleId(elementId)) { ComPtr automationPeer; if (SUCCEEDED(provider.As(&automationPeer))) { ComPtr 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 &elementIds, UINT32 *returnValueSize, IIRawElementProviderSimple ***returnValue) { if (!returnValueSize || !returnValue) return E_INVALIDARG; *returnValueSize = 0; *returnValue = nullptr; QList 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(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 provider = providerForAccessibleId(accid)) { ComPtr 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 provider = providerForAccessibleId(accid)) { ComPtr automationPeer; if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) { ComPtr toggleStatics; if (SUCCEEDED(RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Automation_TogglePatternIdentifiers).Get(), IID_PPV_ARGS(&toggleStatics)))) { ComPtr toggleStateProperty; if (SUCCEEDED(toggleStatics->get_ToggleStateProperty(&toggleStateProperty))) { ComPtr emptyValue = Make(); // 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 provider = providerForAccessibleId(accid)) { ComPtr 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 provider = providerForAccessibleId(accid)) { ComPtr 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 provider = Make(id()); return provider.CopyTo(returnValue); } break; } case PatternInterface_Value: { // All accessible controls return text(QAccessible::Value) (which may be empty). ComPtr provider = Make(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 provider = Make(id()); return provider.CopyTo(returnValue); } break; } case PatternInterface_Toggle: { // Checkbox controls. if (accessible->role() == QAccessible::CheckBox) { ComPtr provider = Make(id()); return provider.CopyTo(returnValue); } break; } case PatternInterface_Selection: { // Lists of items. if (accessible->role() == QAccessible::List) { ComPtr provider = Make(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 provider = Make(id()); return provider.CopyTo(returnValue); } break; } case PatternInterface_Table: { // Table/tree. if (accessible->tableInterface() && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) { ComPtr provider = Make(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 provider = Make(id()); return provider.CopyTo(returnValue); } break; } case PatternInterface_Grid: { // Table/tree. if (accessible->tableInterface() && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) { ComPtr provider = Make(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 provider = Make(id()); return provider.CopyTo(returnValue); } break; } case PatternInterface_Invoke: { // Things that have an invokable action (e.g., simple buttons). if (accessible->actionInterface()) { ComPtr provider = Make(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 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 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 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 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 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 **returnValue) { qCDebug(lcQpaUiAutomation) << __FUNCTION__; if (!returnValue) return E_INVALIDARG; *returnValue = nullptr; auto accid = id(); auto children = QSharedPointer>(new QList); auto ptrChildren = new QSharedPointer>(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> peerVector = Make(); for (auto childId : qAsConst(*children)) { if (ComPtr 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 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 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 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 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 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 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 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 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(new QAccessible::Id(0)); auto ptrElementId = new QSharedPointer(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 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)