Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwindowsuiamainprovider.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtGui/qtguiglobal.h>
5#if QT_CONFIG(accessibility)
6
21#include "qwindowscontext.h"
22#include "qwindowsuiautils.h"
24
25#include <QtCore/qloggingcategory.h>
26#include <QtGui/qaccessible.h>
27#include <QtGui/qguiapplication.h>
28#include <QtGui/qwindow.h>
29#include <qpa/qplatforminputcontextfactory_p.h>
30
31#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
32#include <comdef.h>
33#endif
34
35#include <QtCore/qt_windows.h>
36
38
39using namespace QWindowsUiAutomation;
40
41QMutex QWindowsUiaMainProvider::m_mutex;
42
43// Returns a cached instance of the provider for a specific accessible interface.
44QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessibleInterface *accessible)
45{
46 QMutexLocker locker(&m_mutex);
47
48 if (!accessible)
49 return nullptr;
50
51 QAccessible::Id id = QAccessible::uniqueId(accessible);
52 QWindowsUiaProviderCache *providerCache = QWindowsUiaProviderCache::instance();
53 auto *provider = qobject_cast<QWindowsUiaMainProvider *>(providerCache->providerForId(id));
54
55 if (provider) {
56 provider->AddRef();
57 } else {
58 provider = new QWindowsUiaMainProvider(accessible);
59 providerCache->insert(id, provider);
60 }
61 return provider;
62}
63
64QWindowsUiaMainProvider::QWindowsUiaMainProvider(QAccessibleInterface *a)
65 : QWindowsUiaBaseProvider(QAccessible::uniqueId(a))
66{
67}
68
69QWindowsUiaMainProvider::~QWindowsUiaMainProvider()
70{
71}
72
73void QWindowsUiaMainProvider::notifyFocusChange(QAccessibleEvent *event)
74{
75 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
76 // If this is a complex element, raise event for the focused child instead.
77 if (accessible->childCount()) {
78 if (QAccessibleInterface *child = accessible->focusChild())
79 accessible = child;
80 }
81 if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible))
82 UiaRaiseAutomationEvent(provider, UIA_AutomationFocusChangedEventId);
83 }
84}
85
86void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *event)
87{
88 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
89 if (event->changedStates().checked || event->changedStates().checkStateMixed) {
90 // Notifies states changes in checkboxes.
91 if (accessible->role() == QAccessible::CheckBox) {
92 if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
93 VARIANT oldVal, newVal;
94 clearVariant(&oldVal);
95 int toggleState = ToggleState_Off;
96 if (accessible->state().checked)
97 toggleState = accessible->state().checkStateMixed ? ToggleState_Indeterminate : ToggleState_On;
98 setVariantI4(toggleState, &newVal);
99 UiaRaiseAutomationPropertyChangedEvent(provider, UIA_ToggleToggleStatePropertyId, oldVal, newVal);
100 }
101 }
102 }
103 if (event->changedStates().active) {
104 if (accessible->role() == QAccessible::Window) {
105 // Notifies window opened/closed.
106 if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
107 if (accessible->state().active) {
108 UiaRaiseAutomationEvent(provider, UIA_Window_WindowOpenedEventId);
109 if (QAccessibleInterface *focused = accessible->focusChild()) {
110 if (QWindowsUiaMainProvider *focusedProvider = providerForAccessible(focused))
111 UiaRaiseAutomationEvent(focusedProvider, UIA_AutomationFocusChangedEventId);
112 }
113 } else {
114 UiaRaiseAutomationEvent(provider, UIA_Window_WindowClosedEventId);
115 }
116 }
117 }
118 }
119 }
120}
121
122void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event)
123{
124 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
125 if (accessible->role() == QAccessible::ComboBox && accessible->childCount() > 0) {
126 QAccessibleInterface *listacc = accessible->child(0);
127 if (listacc && listacc->role() == QAccessible::List) {
128 int count = listacc->childCount();
129 for (int i = 0; i < count; ++i) {
130 QAccessibleInterface *item = listacc->child(i);
131 if (item && item->isValid() && item->text(QAccessible::Name) == event->value()) {
132 if (!item->state().selected) {
133 if (QAccessibleActionInterface *actionInterface = item->actionInterface())
134 actionInterface->doAction(QAccessibleActionInterface::toggleAction());
135 }
136 break;
137 }
138 }
139 }
140 }
141 if (event->value().typeId() == QMetaType::QString) {
142 if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
143 // Notifies changes in string values.
144 VARIANT oldVal, newVal;
145 clearVariant(&oldVal);
146 setVariantString(event->value().toString(), &newVal);
147 UiaRaiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
148 }
149 } else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
150 if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
151 // Notifies changes in values of controls supporting the value interface.
152 VARIANT oldVal, newVal;
153 clearVariant(&oldVal);
154 setVariantDouble(valueInterface->currentValue().toDouble(), &newVal);
155 UiaRaiseAutomationPropertyChangedEvent(provider, UIA_RangeValueValuePropertyId, oldVal, newVal);
156 }
157 }
158 }
159}
160
161void QWindowsUiaMainProvider::notifyNameChange(QAccessibleEvent *event)
162{
163 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
164 // Restrict notification to combo boxes, which need it for accessibility,
165 // in order to avoid slowdowns with unnecessary notifications.
166 if (accessible->role() == QAccessible::ComboBox) {
167 if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
168 VARIANT oldVal, newVal;
169 clearVariant(&oldVal);
170 setVariantString(accessible->text(QAccessible::Name), &newVal);
171 UiaRaiseAutomationPropertyChangedEvent(provider, UIA_NamePropertyId, oldVal, newVal);
172 ::SysFreeString(newVal.bstrVal);
173 }
174 }
175 }
176}
177
178void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event)
179{
180 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
181 if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
182 UiaRaiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
183 }
184 }
185}
186
187// Notifies changes in text content and selection state of text controls.
188void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
189{
190 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
191 if (accessible->textInterface()) {
192 if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
193 if (event->type() == QAccessible::TextSelectionChanged) {
194 UiaRaiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
195 } else if (event->type() == QAccessible::TextCaretMoved) {
196 if (!accessible->state().readOnly) {
197 UiaRaiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
198 }
199 } else {
200 UiaRaiseAutomationEvent(provider, UIA_Text_TextChangedEventId);
201 }
202 }
203 }
204 }
205}
206
207void QWindowsUiaMainProvider::raiseNotification(QAccessibleAnnouncementEvent *event)
208{
209 if (QAccessibleInterface *accessible = event->accessibleInterface()) {
210 if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
211 BSTR message = bStrFromQString(event->message());
212 QAccessible::AnnouncementPriority prio = event->priority();
213 NotificationProcessing processing = (prio == QAccessible::AnnouncementPriority::Assertive)
214 ? NotificationProcessing_ImportantAll
215 : NotificationProcessing_All;
216 BSTR activityId = bStrFromQString(QString::fromLatin1(""));
217 UiaRaiseNotificationEvent(provider, NotificationKind_Other, processing, message, activityId);
218
219 ::SysFreeString(message);
220 ::SysFreeString(activityId);
221 }
222 }
223}
224
225HRESULT STDMETHODCALLTYPE QWindowsUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
226{
227 HRESULT result = QComObject::QueryInterface(iid, iface);
228
229 if (SUCCEEDED(result) && iid == __uuidof(IRawElementProviderFragmentRoot)) {
230 QAccessibleInterface *accessible = accessibleInterface();
231 if (accessible && hwndForAccessible(accessible)) {
232 result = S_OK;
233 } else {
234 result = E_NOINTERFACE;
235 iface = nullptr;
236 }
237 }
238
239 return result;
240}
241
242ULONG STDMETHODCALLTYPE QWindowsUiaMainProvider::Release()
243{
244 QMutexLocker locker(&m_mutex);
245
246 return QComObject::Release();
247}
248
249HRESULT QWindowsUiaMainProvider::get_ProviderOptions(ProviderOptions *pRetVal)
250{
251 if (!pRetVal)
252 return E_INVALIDARG;
253 // We are STA, (OleInitialize()).
254 *pRetVal = static_cast<ProviderOptions>(ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading);
255 return S_OK;
256}
257
258// Return providers for specific control patterns
259HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknown **pRetVal)
260{
261 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idPattern;
262
263 if (!pRetVal)
264 return E_INVALIDARG;
265 *pRetVal = nullptr;
266
267 QAccessibleInterface *accessible = accessibleInterface();
268 if (!accessible)
269 return UIA_E_ELEMENTNOTAVAILABLE;
270
271 switch (idPattern) {
272 case UIA_WindowPatternId:
273 if (accessible->parent() && (accessible->parent()->role() == QAccessible::Application)) {
274 *pRetVal = new QWindowsUiaWindowProvider(id());
275 }
276 break;
277 case UIA_TextPatternId:
278 case UIA_TextPattern2Id:
279 // All text controls.
280 if (accessible->textInterface()) {
281 *pRetVal = new QWindowsUiaTextProvider(id());
282 }
283 break;
284 case UIA_ValuePatternId:
285 // All non-static controls support the Value pattern.
286 if (accessible->role() != QAccessible::StaticText)
287 *pRetVal = new QWindowsUiaValueProvider(id());
288 break;
289 case UIA_RangeValuePatternId:
290 // Controls providing a numeric value within a range (e.g., sliders, scroll bars, dials).
291 if (accessible->valueInterface()) {
292 *pRetVal = new QWindowsUiaRangeValueProvider(id());
293 }
294 break;
295 case UIA_TogglePatternId:
296 // Checkboxes and other checkable controls.
297 if (accessible->state().checkable)
298 *pRetVal = new QWindowsUiaToggleProvider(id());
299 break;
300 case UIA_SelectionPatternId:
301 case UIA_SelectionPattern2Id:
302 // Selections via QAccessibleSelectionInterface or lists of items.
303 if (accessible->selectionInterface()
304 || accessible->role() == QAccessible::List
305 || accessible->role() == QAccessible::PageTabList) {
306 *pRetVal = new QWindowsUiaSelectionProvider(id());
307 }
308 break;
309 case UIA_SelectionItemPatternId:
310 // Parent supports selection interface or items within a list and radio buttons.
311 if ((accessible->parent() && accessible->parent()->selectionInterface())
312 || (accessible->role() == QAccessible::RadioButton)
313 || (accessible->role() == QAccessible::ListItem)
314 || (accessible->role() == QAccessible::PageTab)) {
315 *pRetVal = new QWindowsUiaSelectionItemProvider(id());
316 }
317 break;
318 case UIA_TablePatternId:
319 // Table/tree.
320 if (accessible->tableInterface()
321 && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) {
322 *pRetVal = new QWindowsUiaTableProvider(id());
323 }
324 break;
325 case UIA_TableItemPatternId:
326 // Item within a table/tree.
327 if (accessible->tableCellInterface()
328 && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) {
329 *pRetVal = new QWindowsUiaTableItemProvider(id());
330 }
331 break;
332 case UIA_GridPatternId:
333 // Table/tree.
334 if (accessible->tableInterface()
335 && ((accessible->role() == QAccessible::Table) || (accessible->role() == QAccessible::Tree))) {
336 *pRetVal = new QWindowsUiaGridProvider(id());
337 }
338 break;
339 case UIA_GridItemPatternId:
340 // Item within a table/tree.
341 if (accessible->tableCellInterface()
342 && ((accessible->role() == QAccessible::Cell) || (accessible->role() == QAccessible::TreeItem))) {
343 *pRetVal = new QWindowsUiaGridItemProvider(id());
344 }
345 break;
346 case UIA_InvokePatternId:
347 // Things that have an invokable action (e.g., simple buttons).
348 if (accessible->actionInterface()) {
349 *pRetVal = new QWindowsUiaInvokeProvider(id());
350 }
351 break;
352 case UIA_ExpandCollapsePatternId:
353 // Menu items with submenus.
354 if ((accessible->role() == QAccessible::MenuItem
355 && accessible->childCount() > 0
356 && accessible->child(0)->role() == QAccessible::PopupMenu)
357 || accessible->role() == QAccessible::ComboBox
358 || (accessible->role() == QAccessible::TreeItem && accessible->state().expandable)) {
359 *pRetVal = new QWindowsUiaExpandCollapseProvider(id());
360 }
361 break;
362 default:
363 break;
364 }
365
366 return S_OK;
367}
368
369void QWindowsUiaMainProvider::fillVariantArrayForRelation(QAccessibleInterface* accessible,
370 QAccessible::Relation relation, VARIANT *pRetVal)
371{
372 Q_ASSERT(accessible);
373
374 typedef QPair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
375 const QList<RelationPair> relationInterfaces = accessible->relations(relation);
376 if (relationInterfaces.empty())
377 return;
378
379 SAFEARRAY *elements = SafeArrayCreateVector(VT_UNKNOWN, 0, relationInterfaces.size());
380 for (LONG i = 0; i < relationInterfaces.size(); ++i) {
381 if (QWindowsUiaMainProvider *childProvider = QWindowsUiaMainProvider::providerForAccessible(relationInterfaces.at(i).first)) {
382 SafeArrayPutElement(elements, &i, static_cast<IRawElementProviderSimple*>(childProvider));
383 childProvider->Release();
384 }
385 }
386
387 pRetVal->vt = VT_UNKNOWN | VT_ARRAY;
388 pRetVal->parray = elements;
389}
390
391HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal)
392{
393 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idProp;
394
395 if (!pRetVal)
396 return E_INVALIDARG;
397 clearVariant(pRetVal);
398
399 QAccessibleInterface *accessible = accessibleInterface();
400 if (!accessible)
401 return UIA_E_ELEMENTNOTAVAILABLE;
402
403 bool topLevelWindow = accessible->parent() && (accessible->parent()->role() == QAccessible::Application);
404
405 switch (idProp) {
406 case UIA_ProcessIdPropertyId:
407 // PID
408 setVariantI4(int(GetCurrentProcessId()), pRetVal);
409 break;
410 case UIA_AccessKeyPropertyId:
411 // Accelerator key.
412 setVariantString(accessible->text(QAccessible::Accelerator), pRetVal);
413 break;
414 case UIA_AutomationIdPropertyId:
415 // Automation ID, which can be used by tools to select a specific control in the UI.
416 setVariantString(automationIdForAccessible(accessible), pRetVal);
417 break;
418 case UIA_ClassNamePropertyId:
419 // Class name.
420 if (QObject *o = accessible->object()) {
421 QString className = QLatin1StringView(o->metaObject()->className());
422 setVariantString(className, pRetVal);
423 }
424 break;
425 case UIA_DescribedByPropertyId:
426 fillVariantArrayForRelation(accessible, QAccessible::DescriptionFor, pRetVal);
427 break;
428 case UIA_FlowsFromPropertyId:
429 fillVariantArrayForRelation(accessible, QAccessible::FlowsTo, pRetVal);
430 break;
431 case UIA_FlowsToPropertyId:
432 fillVariantArrayForRelation(accessible, QAccessible::FlowsFrom, pRetVal);
433 break;
434 case UIA_FrameworkIdPropertyId:
435 setVariantString(QStringLiteral("Qt"), pRetVal);
436 break;
437 case UIA_ControlTypePropertyId:
438 if (topLevelWindow) {
439 // Reports a top-level widget as a window, instead of "custom".
440 setVariantI4(UIA_WindowControlTypeId, pRetVal);
441 } else {
442 // Control type converted from role.
443 auto controlType = roleToControlTypeId(accessible->role());
444
445 // The native OSK should be disabled if the Qt OSK is in use,
446 // or if disabled via application attribute.
447 static bool imModuleEmpty = QPlatformInputContextFactory::requested().isEmpty();
449
450 // If we want to disable the native OSK auto-showing
451 // we have to report text fields as non-editable.
452 if (controlType == UIA_EditControlTypeId && (!imModuleEmpty || nativeVKDisabled))
453 controlType = UIA_TextControlTypeId;
454
455 setVariantI4(controlType, pRetVal);
456 }
457 break;
458 case UIA_HelpTextPropertyId:
459 setVariantString(accessible->text(QAccessible::Help), pRetVal);
460 break;
461 case UIA_HasKeyboardFocusPropertyId:
462 if (topLevelWindow) {
463 // Windows set the active state to true when they are focused
464 setVariantBool(accessible->state().active, pRetVal);
465 } else {
466 setVariantBool(accessible->state().focused, pRetVal);
467 }
468 break;
469 case UIA_IsKeyboardFocusablePropertyId:
470 if (topLevelWindow) {
471 // Windows should always be focusable
472 setVariantBool(true, pRetVal);
473 } else {
474 setVariantBool(accessible->state().focusable, pRetVal);
475 }
476 break;
477 case UIA_IsOffscreenPropertyId:
478 setVariantBool(accessible->state().offscreen, pRetVal);
479 break;
480 case UIA_IsContentElementPropertyId:
481 setVariantBool(true, pRetVal);
482 break;
483 case UIA_IsControlElementPropertyId:
484 setVariantBool(true, pRetVal);
485 break;
486 case UIA_IsEnabledPropertyId:
487 setVariantBool(!accessible->state().disabled, pRetVal);
488 break;
489 case UIA_IsPasswordPropertyId:
490 setVariantBool(accessible->role() == QAccessible::EditableText
491 && accessible->state().passwordEdit, pRetVal);
492 break;
493 case UIA_IsPeripheralPropertyId:
494 // True for peripheral UIs.
495 if (QWindow *window = windowForAccessible(accessible)) {
496 const Qt::WindowType wt = window->type();
497 setVariantBool(wt == Qt::Popup || wt == Qt::ToolTip || wt == Qt::SplashScreen, pRetVal);
498 }
499 break;
500 case UIA_IsDialogPropertyId:
501 setVariantBool(accessible->role() == QAccessible::Dialog
502 || accessible->role() == QAccessible::AlertMessage, pRetVal);
503 break;
504 case UIA_FullDescriptionPropertyId:
505 setVariantString(accessible->text(QAccessible::Description), pRetVal);
506 break;
507 case UIA_NamePropertyId: {
508 QString name = accessible->text(QAccessible::Name);
509 if (name.isEmpty() && topLevelWindow)
511 setVariantString(name, pRetVal);
512 break;
513 }
514 default:
515 break;
516 }
517 return S_OK;
518}
519
520// Generates an ID based on the name of the controls and their parents.
521QString QWindowsUiaMainProvider::automationIdForAccessible(const QAccessibleInterface *accessible)
522{
524 if (accessible) {
525 QObject *obj = accessible->object();
526 while (obj) {
527 QString name = obj->objectName();
528 if (name.isEmpty())
529 return result;
530 if (!result.isEmpty())
531 result.prepend(u'.');
533 obj = obj->parent();
534 }
535 }
536 return result;
537}
538
539HRESULT QWindowsUiaMainProvider::get_HostRawElementProvider(IRawElementProviderSimple **pRetVal)
540{
541 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
542
543 if (!pRetVal)
544 return E_INVALIDARG;
545 *pRetVal = nullptr;
546
547 // Returns a host provider only for controls associated with a native window handle. Others should return NULL.
548 if (QAccessibleInterface *accessible = accessibleInterface()) {
549 if (HWND hwnd = hwndForAccessible(accessible)) {
550 return UiaHostProviderFromHwnd(hwnd, pRetVal);
551 }
552 }
553 return S_OK;
554}
555
556// Navigates within the tree of accessible controls.
557HRESULT QWindowsUiaMainProvider::Navigate(NavigateDirection direction, IRawElementProviderFragment **pRetVal)
558{
559 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << direction << " this: " << this;
560
561 if (!pRetVal)
562 return E_INVALIDARG;
563 *pRetVal = nullptr;
564
565 QAccessibleInterface *accessible = accessibleInterface();
566 if (!accessible)
567 return UIA_E_ELEMENTNOTAVAILABLE;
568
569 QAccessibleInterface *targetacc = nullptr;
570
571 if (direction == NavigateDirection_Parent) {
572 if (QAccessibleInterface *parent = accessible->parent()) {
573 // The Application's children are considered top level objects.
574 if (parent->isValid() && parent->role() != QAccessible::Application) {
575 targetacc = parent;
576 }
577 }
578 } else {
579 QAccessibleInterface *parent = nullptr;
580 int index = 0;
581 int incr = 1;
582 switch (direction) {
583 case NavigateDirection_FirstChild:
584 parent = accessible;
585 index = 0;
586 incr = 1;
587 break;
588 case NavigateDirection_LastChild:
589 parent = accessible;
590 index = accessible->childCount() - 1;
591 incr = -1;
592 break;
593 case NavigateDirection_NextSibling:
594 if ((parent = accessible->parent()))
595 index = parent->indexOfChild(accessible) + 1;
596 incr = 1;
597 break;
598 case NavigateDirection_PreviousSibling:
599 if ((parent = accessible->parent()))
600 index = parent->indexOfChild(accessible) - 1;
601 incr = -1;
602 break;
603 default:
604 Q_UNREACHABLE();
605 break;
606 }
607
608 if (parent && parent->isValid()) {
609 for (int count = parent->childCount(); index >= 0 && index < count; index += incr) {
610 if (QAccessibleInterface *child = parent->child(index)) {
611 if (child->isValid() && !child->state().invisible) {
612 targetacc = child;
613 break;
614 }
615 }
616 }
617 }
618 }
619
620 if (targetacc)
621 *pRetVal = providerForAccessible(targetacc);
622 return S_OK;
623}
624
625// Returns a unique id assigned to the UI element, used as key by the UI Automation framework.
626HRESULT QWindowsUiaMainProvider::GetRuntimeId(SAFEARRAY **pRetVal)
627{
628 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
629
630 if (!pRetVal)
631 return E_INVALIDARG;
632 *pRetVal = nullptr;
633
634 QAccessibleInterface *accessible = accessibleInterface();
635 if (!accessible)
636 return UIA_E_ELEMENTNOTAVAILABLE;
637
638 // The UiaAppendRuntimeId constant is used to make then ID unique
639 // among multiple instances running on the system.
640 int rtId[] = { UiaAppendRuntimeId, int(id()) };
641
642 if ((*pRetVal = SafeArrayCreateVector(VT_I4, 0, 2))) {
643 for (LONG i = 0; i < 2; ++i)
644 SafeArrayPutElement(*pRetVal, &i, &rtId[i]);
645 }
646 return S_OK;
647}
648
649// Returns the bounding rectangle for the accessible control.
650HRESULT QWindowsUiaMainProvider::get_BoundingRectangle(UiaRect *pRetVal)
651{
652 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
653
654 if (!pRetVal)
655 return E_INVALIDARG;
656
657 QAccessibleInterface *accessible = accessibleInterface();
658 if (!accessible)
659 return UIA_E_ELEMENTNOTAVAILABLE;
660
661 QWindow *window = windowForAccessible(accessible);
662 if (!window)
663 return UIA_E_ELEMENTNOTAVAILABLE;
664
665 rectToNativeUiaRect(accessible->rect(), window, pRetVal);
666 return S_OK;
667}
668
669HRESULT QWindowsUiaMainProvider::GetEmbeddedFragmentRoots(SAFEARRAY **pRetVal)
670{
671 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
672
673 if (!pRetVal)
674 return E_INVALIDARG;
675 *pRetVal = nullptr;
676 // No embedded roots.
677 return S_OK;
678}
679
680// Sets focus to the control.
681HRESULT QWindowsUiaMainProvider::SetFocus()
682{
683 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
684
685 QAccessibleInterface *accessible = accessibleInterface();
686 if (!accessible)
687 return UIA_E_ELEMENTNOTAVAILABLE;
688
689 QAccessibleActionInterface *actionInterface = accessible->actionInterface();
690 if (!actionInterface)
691 return UIA_E_ELEMENTNOTAVAILABLE;
692
693 actionInterface->doAction(QAccessibleActionInterface::setFocusAction());
694 return S_OK;
695}
696
697HRESULT QWindowsUiaMainProvider::get_FragmentRoot(IRawElementProviderFragmentRoot **pRetVal)
698{
699 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
700
701 if (!pRetVal)
702 return E_INVALIDARG;
703 *pRetVal = nullptr;
704
705 // Our UI Automation implementation considers the window as the root for
706 // non-native controls/fragments.
707 if (QAccessibleInterface *accessible = accessibleInterface()) {
708 if (QWindow *window = windowForAccessible(accessible)) {
709 if (QAccessibleInterface *rootacc = window->accessibleRoot()) {
710 *pRetVal = providerForAccessible(rootacc);
711 }
712 }
713 }
714 return S_OK;
715}
716
717// Returns a provider for the UI element present at the specified screen coordinates.
718HRESULT QWindowsUiaMainProvider::ElementProviderFromPoint(double x, double y, IRawElementProviderFragment **pRetVal)
719{
720 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << x << y;
721
722 if (!pRetVal) {
723 return E_INVALIDARG;
724 }
725 *pRetVal = nullptr;
726
727 QAccessibleInterface *accessible = accessibleInterface();
728 if (!accessible)
729 return UIA_E_ELEMENTNOTAVAILABLE;
730
731 QWindow *window = windowForAccessible(accessible);
732 if (!window)
733 return UIA_E_ELEMENTNOTAVAILABLE;
734
735 // Scales coordinates from High DPI screens.
736 UiaPoint uiaPoint = {x, y};
737 QPoint point;
738 nativeUiaPointToPoint(uiaPoint, window, &point);
739
740 QAccessibleInterface *targetacc = accessible->childAt(point.x(), point.y());
741
742 if (targetacc) {
743 QAccessibleInterface *acc = targetacc;
744 // Controls can be embedded within grouping elements. By default returns the innermost control.
745 while (acc) {
746 targetacc = acc;
747 // For accessibility tools it may be better to return the text element instead of its subcomponents.
748 if (targetacc->textInterface()) break;
749 acc = acc->childAt(point.x(), point.y());
750 }
751 *pRetVal = providerForAccessible(targetacc);
752 }
753 return S_OK;
754}
755
756// Returns the fragment with focus.
757HRESULT QWindowsUiaMainProvider::GetFocus(IRawElementProviderFragment **pRetVal)
758{
759 qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
760
761 if (!pRetVal)
762 return E_INVALIDARG;
763 *pRetVal = nullptr;
764
765 if (QAccessibleInterface *accessible = accessibleInterface()) {
766 if (QAccessibleInterface *focusacc = accessible->focusChild()) {
767 *pRetVal = providerForAccessible(focusacc);
768 }
769 }
770 return S_OK;
771}
772
774
775#endif // QT_CONFIG(accessibility)
The QAccessible class provides enums and static functions related to accessibility.
static bool testAttribute(Qt::ApplicationAttribute attribute)
Returns true if attribute attribute is set; otherwise returns false.
QString applicationName
the name of this application
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
\inmodule QtCore
Definition qobject.h:103
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
QString & prepend(QChar c)
Definition qstring.h:478
\inmodule QtGui
Definition qwindow.h:63
direction
Combined button and popup list for selecting options.
constexpr QBindableInterface iface
Definition qproperty.h:666
@ AA_DisableNativeVirtualKeyboard
Definition qnamespace.h:434
WindowType
Definition qnamespace.h:205
@ ToolTip
Definition qnamespace.h:213
@ Popup
Definition qnamespace.h:211
@ SplashScreen
Definition qnamespace.h:214
#define qCDebug(category,...)
GLint GLint GLint GLint GLint x
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLenum GLenum GLsizei count
GLuint GLsizei const GLchar * message
GLuint name
GLint y
struct _cl_event * event
GLhandleARB obj
[2]
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
static const QTextHtmlElement elements[Html_NumElements]
long HRESULT
const char className[16]
[1]
Definition qwizard.cpp:100
QGraphicsItem * item
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]