1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include <QtGui/qtguiglobal.h>
41 #if QT_CONFIG(accessibility)
42
43 #include "qwinrtuiamainprovider.h"
44 #include "qwinrtuiaprovidercache.h"
45 #include "qwinrtuiavalueprovider.h"
46 #include "qwinrtuiarangevalueprovider.h"
47 #include "qwinrtuiatextprovider.h"
48 #include "qwinrtuiatoggleprovider.h"
49 #include "qwinrtuiainvokeprovider.h"
50 #include "qwinrtuiaselectionprovider.h"
51 #include "qwinrtuiaselectionitemprovider.h"
52 #include "qwinrtuiatableprovider.h"
53 #include "qwinrtuiatableitemprovider.h"
54 #include "qwinrtuiagridprovider.h"
55 #include "qwinrtuiagriditemprovider.h"
56 #include "qwinrtuiapeervector.h"
57 #include "qwinrtuiametadatacache.h"
58 #include "qwinrtuiaemptypropertyvalue.h"
59 #include "qwinrtuiautils.h"
60
61 #include <QCoreApplication>
62 #include <QSemaphore>
63 #include <QtCore/QLoggingCategory>
64 #include <QtCore/qfunctions_winrt.h>
65 #include <QtCore/private/qeventdispatcher_winrt_p.h>
66
67 #include <memory>
68
69 using namespace QWinRTUiAutomation;
70 using namespace Microsoft::WRL;
71 using namespace Microsoft::WRL::Wrappers;
72 using namespace ABI::Windows::System;
73 using namespace ABI::Windows::UI;
74 using namespace ABI::Windows::UI::Core;
75 using namespace ABI::Windows::UI::Xaml;
76 using namespace ABI::Windows::UI::Xaml::Automation;
77 using namespace ABI::Windows::UI::Xaml::Automation::Provider;
78 using namespace ABI::Windows::UI::Xaml::Automation::Peers;
79 using namespace ABI::Windows::Foundation;
80 using namespace ABI::Windows::Foundation::Collections;
81
82 QT_BEGIN_NAMESPACE
83
QWinRTUiaMainProvider(QAccessible::Id id)84 QWinRTUiaMainProvider::QWinRTUiaMainProvider(QAccessible::Id id)
85 : QWinRTUiaBaseProvider(id)
86 {
87 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
88
89 ComPtr<IAutomationPeerFactory> factory;
90 HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Automation_Peers_AutomationPeer).Get(), IID_PPV_ARGS(&factory));
91 Q_ASSERT_SUCCEEDED(hr);
92
93 hr = factory->CreateInstance(this, &m_base, &m_core);
94 Q_ASSERT_SUCCEEDED(hr);
95 }
96
~QWinRTUiaMainProvider()97 QWinRTUiaMainProvider::~QWinRTUiaMainProvider()
98 {
99 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
100 }
101
QueryInterface(REFIID iid,LPVOID * iface)102 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
103 {
104 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
105
106 if (!iface)
107 return E_POINTER;
108 *iface = nullptr;
109
110 if (iid == IID_IUnknown) {
111 *iface = static_cast<IAutomationPeerOverrides *>(this);
112 AddRef();
113 return S_OK;
114 } else if (iid == IID_IAutomationPeerOverrides) {
115 *iface = static_cast<IAutomationPeerOverrides *>(this);
116 AddRef();
117 return S_OK;
118 } else {
119 return m_base.CopyTo(iid, iface);
120 }
121 }
122
GetIids(ULONG * iidCount,IID ** iids)123 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetIids(ULONG *iidCount, IID **iids)
124 {
125 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
126 *iidCount = 0;
127 *iids = nullptr;
128 return S_OK;
129 }
130
GetRuntimeClassName(HSTRING * className)131 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetRuntimeClassName(HSTRING *className)
132 {
133 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
134 return qHString(QStringLiteral("QWinRTUiaMainProvider"), className);
135 }
136
GetTrustLevel(TrustLevel * trustLevel)137 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetTrustLevel(TrustLevel *trustLevel)
138 {
139 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
140 *trustLevel = TrustLevel::BaseTrust;
141 return S_OK;
142 }
143
144 // Returns a cached instance of the provider for a specific accessible interface.
providerForAccessibleId(QAccessible::Id id)145 QWinRTUiaMainProvider *QWinRTUiaMainProvider::providerForAccessibleId(QAccessible::Id id)
146 {
147 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
148
149 QWinRTUiaProviderCache *providerCache = QWinRTUiaProviderCache::instance();
150 QWinRTUiaMainProvider *provider = qobject_cast<QWinRTUiaMainProvider *>(providerCache->providerForId(id));
151
152 if (provider) {
153 provider->AddRef();
154 } else {
155 ComPtr<QWinRTUiaMainProvider> p = Make<QWinRTUiaMainProvider>(id);
156 provider = p.Get();
157 provider->AddRef();
158 providerCache->insert(id, provider);
159 }
160 return provider;
161 }
162
163 // Returns an IIRawElementProviderSimple for a specific accessible interface.
rawProviderForAccessibleId(QAccessible::Id elementId,IIRawElementProviderSimple ** returnValue)164 HRESULT QWinRTUiaMainProvider::rawProviderForAccessibleId(QAccessible::Id elementId,
165 IIRawElementProviderSimple **returnValue)
166 {
167 if (!returnValue)
168 return E_INVALIDARG;
169 *returnValue = nullptr;
170
171 if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(elementId)) {
172 ComPtr<IAutomationPeer> automationPeer;
173 if (SUCCEEDED(provider.As(&automationPeer))) {
174 ComPtr<IAutomationPeerProtected> automationPeerProtected;
175 if (SUCCEEDED(provider.As(&automationPeerProtected))) {
176 return automationPeerProtected->ProviderFromPeer(automationPeer.Get(), returnValue);
177 }
178 }
179 }
180 return E_FAIL;
181 }
182
183 // Returns an array of IIRawElementProviderSimple instances for a list of accessible interface ids.
rawProviderArrayForAccessibleIdList(const QVarLengthArray<QAccessible::Id> & elementIds,UINT32 * returnValueSize,IIRawElementProviderSimple *** returnValue)184 HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QVarLengthArray<QAccessible::Id> &elementIds,
185 UINT32 *returnValueSize,
186 IIRawElementProviderSimple ***returnValue)
187 {
188 if (!returnValueSize || !returnValue)
189 return E_INVALIDARG;
190 *returnValueSize = 0;
191 *returnValue = nullptr;
192
193 QList<IIRawElementProviderSimple *> rawProviderList;
194
195 for (auto elementId : elementIds) {
196 IIRawElementProviderSimple *rawProvider;
197 if (SUCCEEDED(rawProviderForAccessibleId(elementId, &rawProvider)))
198 rawProviderList.append(rawProvider);
199 }
200
201 if (rawProviderList.size() == 0)
202 return S_OK;
203
204 *returnValue = static_cast<IIRawElementProviderSimple **>(CoTaskMemAlloc(rawProviderList.size() * sizeof(IIRawElementProviderSimple *)));
205 if (!*returnValue) {
206 for (auto rawProvider : qAsConst(rawProviderList))
207 rawProvider->Release();
208 return E_OUTOFMEMORY;
209 }
210
211 int index = 0;
212 for (auto rawProvider : qAsConst(rawProviderList))
213 (*returnValue)[index++] = rawProvider;
214 *returnValueSize = rawProviderList.size();
215 return S_OK;
216 }
217
notifyFocusChange(QAccessibleEvent * event)218 void QWinRTUiaMainProvider::notifyFocusChange(QAccessibleEvent *event)
219 {
220 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
221 QAccessible::Id accid = idForAccessible(accessible);
222 QWinRTUiaMetadataCache::instance()->load(accid);
223 QEventDispatcherWinRT::runOnXamlThread([accid]() {
224 if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
225 ComPtr<IAutomationPeer> automationPeer;
226 if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
227 automationPeer->RaiseAutomationEvent(AutomationEvents_AutomationFocusChanged);
228 }
229 }
230 return S_OK;
231 }, false);
232 }
233 }
234
notifyVisibilityChange(QAccessibleEvent * event)235 void QWinRTUiaMainProvider::notifyVisibilityChange(QAccessibleEvent *event)
236 {
237 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
238 QAccessible::Id accid = idForAccessible(accessible);
239 QWinRTUiaMetadataCache::instance()->load(accid);
240 }
241 }
242
notifyStateChange(QAccessibleStateChangeEvent * event)243 void QWinRTUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *event)
244 {
245 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
246 QAccessible::Id accid = idForAccessible(accessible);
247 QWinRTUiaMetadataCache::instance()->load(accid);
248
249 if (event->changedStates().checked || event->changedStates().checkStateMixed) {
250 // Notifies states changes in checkboxes.
251 if (accessible->role() == QAccessible::CheckBox) {
252 QEventDispatcherWinRT::runOnXamlThread([accid]() {
253 if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
254 ComPtr<IAutomationPeer> automationPeer;
255 if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
256 ComPtr<ITogglePatternIdentifiersStatics> toggleStatics;
257 if (SUCCEEDED(RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Automation_TogglePatternIdentifiers).Get(), IID_PPV_ARGS(&toggleStatics)))) {
258 ComPtr<IAutomationProperty> toggleStateProperty;
259 if (SUCCEEDED(toggleStatics->get_ToggleStateProperty(&toggleStateProperty))) {
260 ComPtr<QWinRTUiaEmptyPropertyValue> emptyValue = Make<QWinRTUiaEmptyPropertyValue>();
261 // by sending an event with an empty value we force ui automation to refresh its state
262 automationPeer->RaisePropertyChangedEvent(toggleStateProperty.Get(), emptyValue.Get(), emptyValue.Get());
263 }
264 }
265 }
266 }
267 return S_OK;
268 }, false);
269 }
270 }
271 if (event->changedStates().active) {
272 if (accessible->role() == QAccessible::Window) {
273 // Notifies window opened/closed.
274 bool active = accessible->state().active;
275 QEventDispatcherWinRT::runOnXamlThread([accid, active]() {
276 if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
277 ComPtr<IAutomationPeer> automationPeer;
278 if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
279 if (active) {
280 automationPeer->RaiseAutomationEvent(AutomationEvents_WindowOpened);
281 } else {
282 automationPeer->RaiseAutomationEvent(AutomationEvents_WindowClosed);
283 }
284 }
285 }
286 return S_OK;
287 }, false);
288 }
289 }
290 }
291 }
292
notifyValueChange(QAccessibleValueChangeEvent * event)293 void QWinRTUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event)
294 {
295 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
296 QAccessible::Id accid = idForAccessible(accessible);
297 QWinRTUiaMetadataCache::instance()->load(accid);
298 if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
299 // Notifies changes in values of controls supporting the value interface.
300 double value = valueInterface->currentValue().toDouble();
301 QEventDispatcherWinRT::runOnXamlThread([accid, value]() {
302 // For some reason RaisePropertyChangedEvent() does not seem to be
303 // forwarding notifications for any property types except empty,
304 // which would do nothing here. ToDo: find a workaround.
305 return S_OK;
306 }, false);
307 }
308 }
309 }
310
311 // Notifies changes in text content and selection state of text controls.
notifyTextChange(QAccessibleEvent * event)312 void QWinRTUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
313 {
314 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
315 QAccessible::Id accid = idForAccessible(accessible);
316 QWinRTUiaMetadataCache::instance()->load(accid);
317 bool readOnly = accessible->state().readOnly;
318 QAccessible::Event eventType = event->type();
319 if (accessible->textInterface()) {
320 QEventDispatcherWinRT::runOnXamlThread([accid, eventType, readOnly]() {
321 if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(accid)) {
322 ComPtr<IAutomationPeer> automationPeer;
323 if (SUCCEEDED(provider->QueryInterface(IID_PPV_ARGS(&automationPeer)))) {
324 if (eventType == QAccessible::TextSelectionChanged) {
325 automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextSelectionChanged);
326 } else if (eventType == QAccessible::TextCaretMoved) {
327 if (!readOnly) {
328 automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextSelectionChanged);
329 }
330 } else {
331 automationPeer->RaiseAutomationEvent(AutomationEvents_TextPatternOnTextChanged);
332 }
333 }
334 }
335 return S_OK;
336 }, false);
337 }
338 }
339 }
340
341 // Return providers for specific control patterns
GetPatternCore(PatternInterface patternInterface,IInspectable ** returnValue)342 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPatternCore(PatternInterface patternInterface, IInspectable **returnValue)
343 {
344 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << patternInterface;
345
346 if (!returnValue)
347 return E_INVALIDARG;
348 *returnValue = nullptr;
349
350 QAccessibleInterface *accessible = accessibleInterface();
351 if (!accessible)
352 return E_FAIL;
353
354 switch (patternInterface) {
355 case PatternInterface_Text:
356 case PatternInterface_Text2: {
357 // All text controls.
358 if (accessible->textInterface()) {
359 ComPtr<QWinRTUiaTextProvider> provider = Make<QWinRTUiaTextProvider>(id());
360 return provider.CopyTo(returnValue);
361 }
362 break;
363 }
364 case PatternInterface_Value: {
365 // All accessible controls return text(QAccessible::Value) (which may be empty).
366 ComPtr<QWinRTUiaValueProvider> provider = Make<QWinRTUiaValueProvider>(id());
367 return provider.CopyTo(returnValue);
368 }
369 case PatternInterface_RangeValue: {
370 // Controls providing a numeric value within a range (e.g., sliders, scroll bars, dials).
371 if (accessible->valueInterface()) {
372 ComPtr<QWinRTUiaRangeValueProvider> provider = Make<QWinRTUiaRangeValueProvider>(id());
373 return provider.CopyTo(returnValue);
374 }
375 break;
376 }
377 case PatternInterface_Toggle: {
378 // Checkbox controls.
379 if (accessible->role() == QAccessible::CheckBox) {
380 ComPtr<QWinRTUiaToggleProvider> provider = Make<QWinRTUiaToggleProvider>(id());
381 return provider.CopyTo(returnValue);
382 }
383 break;
384 }
385 case PatternInterface_Selection: {
386 // Lists of items.
387 if (accessible->role() == QAccessible::List) {
388 ComPtr<QWinRTUiaSelectionProvider> provider = Make<QWinRTUiaSelectionProvider>(id());
389 return provider.CopyTo(returnValue);
390 }
391 break;
392 }
393 case PatternInterface_SelectionItem: {
394 // Items within a list and radio buttons.
395 if ((accessible->role() == QAccessible::RadioButton)
396 || (accessible->role() == QAccessible::ListItem)) {
397 ComPtr<QWinRTUiaSelectionItemProvider> provider = Make<QWinRTUiaSelectionItemProvider>(id());
398 return provider.CopyTo(returnValue);
399 }
400 break;
401 }
402 case PatternInterface_Table: {
403 // Table/tree.
404 if (accessible->tableInterface()
405 && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) {
406 ComPtr<QWinRTUiaTableProvider> provider = Make<QWinRTUiaTableProvider>(id());
407 return provider.CopyTo(returnValue);
408 }
409 break;
410 }
411 case PatternInterface_TableItem: {
412 // Item within a table/tree.
413 if (accessible->tableCellInterface()
414 && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) {
415 ComPtr<QWinRTUiaTableItemProvider> provider = Make<QWinRTUiaTableItemProvider>(id());
416 return provider.CopyTo(returnValue);
417 }
418 break;
419 }
420 case PatternInterface_Grid: {
421 // Table/tree.
422 if (accessible->tableInterface()
423 && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) {
424 ComPtr<QWinRTUiaGridProvider> provider = Make<QWinRTUiaGridProvider>(id());
425 return provider.CopyTo(returnValue);
426 }
427 break;
428 }
429 case PatternInterface_GridItem: {
430 // Item within a table/tree.
431 if (accessible->tableCellInterface()
432 && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) {
433 ComPtr<QWinRTUiaGridItemProvider> provider = Make<QWinRTUiaGridItemProvider>(id());
434 return provider.CopyTo(returnValue);
435 }
436 break;
437 }
438 case PatternInterface_Invoke: {
439 // Things that have an invokable action (e.g., simple buttons).
440 if (accessible->actionInterface()) {
441 ComPtr<QWinRTUiaInvokeProvider> provider = Make<QWinRTUiaInvokeProvider>(id());
442 return provider.CopyTo(returnValue);
443 }
444 break;
445 }
446 default:
447 break;
448 }
449 return S_OK;
450 }
451
GetAcceleratorKeyCore(HSTRING * returnValue)452 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAcceleratorKeyCore(HSTRING *returnValue)
453 {
454 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
455
456 if (!returnValue)
457 return E_INVALIDARG;
458 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
459 return qHString(metadata->accelerator(), returnValue);
460 }
461
GetAccessKeyCore(HSTRING * returnValue)462 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAccessKeyCore(HSTRING *returnValue)
463 {
464 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
465
466 if (!returnValue)
467 return E_INVALIDARG;
468 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
469 return qHString(metadata->access(), returnValue);
470 }
471
GetAutomationControlTypeCore(AutomationControlType * returnValue)472 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAutomationControlTypeCore(AutomationControlType *returnValue)
473 {
474 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
475
476 if (!returnValue)
477 return E_INVALIDARG;
478 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
479 *returnValue = roleToControlType(metadata->role());
480 return S_OK;
481 }
482
GetAutomationIdCore(HSTRING * returnValue)483 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetAutomationIdCore(HSTRING *returnValue)
484 {
485 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
486
487 if (!returnValue)
488 return E_INVALIDARG;
489 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
490 return qHString(metadata->automationId(), returnValue);
491 }
492
493 // Returns the bounding rectangle for the accessible control.
GetBoundingRectangleCore(ABI::Windows::Foundation::Rect * returnValue)494 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetBoundingRectangleCore(ABI::Windows::Foundation::Rect *returnValue)
495 {
496 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
497
498 if (!returnValue)
499 return E_INVALIDARG;
500
501 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
502
503 QRect rect = metadata->boundingRect();
504 returnValue->X = rect.x();
505 returnValue->Y = rect.y();
506 returnValue->Width = rect.width();
507 returnValue->Height = rect.height();
508 return S_OK;
509 }
510
GetChildrenCore(IVector<AutomationPeer * > ** returnValue)511 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<AutomationPeer *> **returnValue)
512 {
513 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
514
515 if (!returnValue)
516 return E_INVALIDARG;
517 *returnValue = nullptr;
518
519 auto accid = id();
520 auto children = std::make_shared<QVarLengthArray<QAccessible::Id>>();
521
522 if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, children]() {
523 if (QAccessibleInterface *accessible = accessibleForId(accid)) {
524 int childCount = accessible->childCount();
525 for (int i = 0; i < childCount; ++i) {
526 if (QAccessibleInterface *childAcc = accessible->child(i)) {
527 QAccessible::Id childId = idForAccessible(childAcc);
528 QWinRTUiaMetadataCache::instance()->load(childId);
529 if (!childAcc->state().invisible)
530 children->append(childId);
531 }
532 }
533 }
534 return S_OK;
535 }))) {
536 return E_FAIL;
537 }
538
539 ComPtr<IVector<AutomationPeer *>> peerVector = Make<QWinRTUiaPeerVector>();
540
541 for (auto childId : *children) {
542 if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(childId)) {
543 IAutomationPeer *peer;
544 if (SUCCEEDED(provider.CopyTo(&peer)))
545 peerVector->Append(peer);
546 }
547 }
548 return peerVector.CopyTo(returnValue);
549 }
550
GetClassNameCore(HSTRING * returnValue)551 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetClassNameCore(HSTRING *returnValue)
552 {
553 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
554
555 if (!returnValue)
556 return E_INVALIDARG;
557 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
558 return qHString(metadata->className(), returnValue);
559 }
560
GetClickablePointCore(ABI::Windows::Foundation::Point * returnValue)561 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetClickablePointCore(ABI::Windows::Foundation::Point *returnValue)
562 {
563 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
564
565 if (!returnValue)
566 return E_INVALIDARG;
567 return E_NOTIMPL;
568 }
569
GetHelpTextCore(HSTRING * returnValue)570 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetHelpTextCore(HSTRING *returnValue)
571 {
572 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
573
574 if (!returnValue)
575 return E_INVALIDARG;
576 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
577 return qHString(metadata->help(), returnValue);
578 }
579
GetItemStatusCore(HSTRING * returnValue)580 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetItemStatusCore(HSTRING *returnValue)
581 {
582 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
583
584 if (!returnValue)
585 return E_INVALIDARG;
586 return E_NOTIMPL;
587 }
588
GetItemTypeCore(HSTRING * returnValue)589 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetItemTypeCore(HSTRING *returnValue)
590 {
591 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
592
593 if (!returnValue)
594 return E_INVALIDARG;
595 return E_NOTIMPL;
596 }
597
GetLabeledByCore(IAutomationPeer ** returnValue)598 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLabeledByCore(IAutomationPeer **returnValue)
599 {
600 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
601
602 if (!returnValue)
603 return E_INVALIDARG;
604 return E_NOTIMPL;
605 }
606
GetLocalizedControlTypeCore(HSTRING * returnValue)607 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLocalizedControlTypeCore(HSTRING *returnValue)
608 {
609 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
610
611 if (!returnValue)
612 return E_INVALIDARG;
613 return E_NOTIMPL;
614 }
615
GetNameCore(HSTRING * returnValue)616 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetNameCore(HSTRING *returnValue)
617 {
618 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
619
620 if (!returnValue)
621 return E_INVALIDARG;
622 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
623 return qHString(metadata->controlName(), returnValue);
624 }
625
GetOrientationCore(AutomationOrientation * returnValue)626 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetOrientationCore(AutomationOrientation *returnValue)
627 {
628 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
629
630 if (!returnValue)
631 return E_INVALIDARG;
632 *returnValue = AutomationOrientation_None;
633 return S_OK;
634 }
635
HasKeyboardFocusCore(boolean * returnValue)636 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::HasKeyboardFocusCore(boolean *returnValue)
637 {
638 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
639
640 if (!returnValue)
641 return E_INVALIDARG;
642 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
643 *returnValue = (metadata->state().focused != 0);
644 return S_OK;
645 }
646
IsContentElementCore(boolean * returnValue)647 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsContentElementCore(boolean *returnValue)
648 {
649 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
650
651 if (!returnValue)
652 return E_INVALIDARG;
653 *returnValue = true;
654 return S_OK;
655 }
656
IsControlElementCore(boolean * returnValue)657 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsControlElementCore(boolean *returnValue)
658 {
659 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
660
661 if (!returnValue)
662 return E_INVALIDARG;
663 *returnValue = true;
664 return S_OK;
665 }
666
IsEnabledCore(boolean * returnValue)667 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsEnabledCore(boolean *returnValue)
668 {
669 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
670
671 if (!returnValue)
672 return E_INVALIDARG;
673 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
674 *returnValue = (metadata->state().disabled == 0);
675 return S_OK;
676 }
677
IsKeyboardFocusableCore(boolean * returnValue)678 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsKeyboardFocusableCore(boolean *returnValue)
679 {
680 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
681
682 if (!returnValue)
683 return E_INVALIDARG;
684 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
685 *returnValue = (metadata->state().focusable != 0);
686 return S_OK;
687 }
688
IsOffscreenCore(boolean * returnValue)689 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsOffscreenCore(boolean *returnValue)
690 {
691 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
692
693 if (!returnValue)
694 return E_INVALIDARG;
695 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
696 *returnValue = (metadata->state().offscreen != 0);
697 return S_OK;
698 }
699
IsPasswordCore(boolean * returnValue)700 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsPasswordCore(boolean *returnValue)
701 {
702 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
703
704 if (!returnValue)
705 return E_INVALIDARG;
706 QSharedPointer<QWinRTUiaControlMetadata> metadata = QWinRTUiaMetadataCache::instance()->metadataForId(id());
707 *returnValue = (metadata->role() == QAccessible::EditableText) && (metadata->state().passwordEdit != 0);
708 return S_OK;
709 }
710
IsRequiredForFormCore(boolean * returnValue)711 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::IsRequiredForFormCore(boolean *returnValue)
712 {
713 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
714
715 if (!returnValue)
716 return E_INVALIDARG;
717 *returnValue = false;
718 return S_OK;
719 }
720
721 // Sets focus to the control.
SetFocusCore()722 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::SetFocusCore()
723 {
724 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
725
726 QAccessibleInterface *accessible = accessibleInterface();
727 if (!accessible)
728 return E_FAIL;
729
730 QAccessibleActionInterface *actionInterface = accessible->actionInterface();
731 if (!actionInterface)
732 return E_FAIL;
733
734 QEventDispatcherWinRT::runOnMainThread([actionInterface]() {
735 actionInterface->doAction(QAccessibleActionInterface::setFocusAction());
736 return S_OK;
737 });
738 return S_OK;
739 }
740
741 // Returns a provider for the UI element present at the specified screen coordinates.
GetPeerFromPointCore(ABI::Windows::Foundation::Point point,IAutomationPeer ** returnValue)742 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPeerFromPointCore(ABI::Windows::Foundation::Point point, IAutomationPeer **returnValue)
743 {
744 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
745
746 if (!returnValue)
747 return E_INVALIDARG;
748 *returnValue = nullptr;
749
750 // Scale coordinates from High DPI screens?
751
752 auto accid = id();
753 auto elementId = std::make_shared<QAccessible::Id>(0);
754
755 if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId, point]() {
756 // Controls can be embedded within grouping elements. By default returns the innermost control.
757 QAccessibleInterface *target = accessibleForId(accid);
758 while (QAccessibleInterface *tmpacc = target->childAt(point.X, point.Y)) {
759 target = tmpacc;
760 // For accessibility tools it may be better to return the text element instead of its subcomponents.
761 if (target->textInterface()) break;
762 }
763 *elementId = idForAccessible(target);
764 QWinRTUiaMetadataCache::instance()->load(*elementId);
765 return S_OK;
766 }))) {
767 return E_FAIL;
768 }
769
770 if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(*elementId))
771 return provider.CopyTo(returnValue);
772 return E_FAIL;
773 }
774
GetLiveSettingCore(AutomationLiveSetting * returnValue)775 HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetLiveSettingCore(AutomationLiveSetting *returnValue)
776 {
777 qCDebug(lcQpaUiAutomation) << __FUNCTION__;
778
779 if (!returnValue)
780 return E_INVALIDARG;
781 return E_NOTIMPL;
782 }
783
784 QT_END_NAMESPACE
785
786 #endif // QT_CONFIG(accessibility)
787
788