summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp')
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp142
1 files changed, 79 insertions, 63 deletions
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index 03cac60e08..95ddbcced6 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -18,7 +18,6 @@
#include "qwindowsuiagriditemprovider.h"
#include "qwindowsuiawindowprovider.h"
#include "qwindowsuiaexpandcollapseprovider.h"
-#include "qwindowscombase.h"
#include "qwindowscontext.h"
#include "qwindowsuiautils.h"
#include "qwindowsuiaprovidercache.h"
@@ -27,6 +26,7 @@
#include <QtGui/qaccessible.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qwindow.h>
+#include <qpa/qplatforminputcontextfactory_p.h>
#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
#include <comdef.h>
@@ -38,10 +38,13 @@ QT_BEGIN_NAMESPACE
using namespace QWindowsUiAutomation;
+QMutex QWindowsUiaMainProvider::m_mutex;
// Returns a cached instance of the provider for a specific accessible interface.
QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessibleInterface *accessible)
{
+ QMutexLocker locker(&m_mutex);
+
if (!accessible)
return nullptr;
@@ -58,9 +61,8 @@ QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessi
return provider;
}
-QWindowsUiaMainProvider::QWindowsUiaMainProvider(QAccessibleInterface *a, int initialRefCount)
- : QWindowsUiaBaseProvider(QAccessible::uniqueId(a)),
- m_ref(initialRefCount)
+QWindowsUiaMainProvider::QWindowsUiaMainProvider(QAccessibleInterface *a)
+ : QWindowsUiaBaseProvider(QAccessible::uniqueId(a))
{
}
@@ -71,12 +73,13 @@ QWindowsUiaMainProvider::~QWindowsUiaMainProvider()
void QWindowsUiaMainProvider::notifyFocusChange(QAccessibleEvent *event)
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
- // If this is a table/tree/list, raise event for the focused cell/item instead.
- if (accessible->tableInterface())
+ // If this is a complex element, raise event for the focused child instead.
+ if (accessible->childCount()) {
if (QAccessibleInterface *child = accessible->focusChild())
accessible = child;
+ }
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible))
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_AutomationFocusChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_AutomationFocusChangedEventId);
}
}
@@ -93,7 +96,7 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
if (accessible->state().checked)
toggleState = accessible->state().checkStateMixed ? ToggleState_Indeterminate : ToggleState_On;
setVariantI4(toggleState, &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ToggleToggleStatePropertyId, oldVal, newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_ToggleToggleStatePropertyId, oldVal, newVal);
}
}
}
@@ -102,13 +105,13 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
// Notifies window opened/closed.
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
if (accessible->state().active) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Window_WindowOpenedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Window_WindowOpenedEventId);
if (QAccessibleInterface *focused = accessible->focusChild()) {
if (QWindowsUiaMainProvider *focusedProvider = providerForAccessible(focused))
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(focusedProvider, UIA_AutomationFocusChangedEventId);
+ UiaRaiseAutomationEvent(focusedProvider, UIA_AutomationFocusChangedEventId);
}
} else {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Window_WindowClosedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Window_WindowClosedEventId);
}
}
}
@@ -137,27 +140,11 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
}
if (event->value().typeId() == QMetaType::QString) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
-
- // Tries to notify the change using UiaRaiseNotificationEvent(), which is only available on
- // Windows 10 version 1709 or newer. Otherwise uses UiaRaiseAutomationPropertyChangedEvent().
-
- BSTR displayString = bStrFromQString(event->value().toString());
- BSTR activityId = bStrFromQString(QString());
-
- HRESULT hr = QWindowsUiaWrapper::instance()->raiseNotificationEvent(provider, NotificationKind_Other,
- NotificationProcessing_ImportantMostRecent,
- displayString, activityId);
-
- ::SysFreeString(displayString);
- ::SysFreeString(activityId);
-
- if (hr == static_cast<HRESULT>(UIA_E_NOTSUPPORTED)) {
- VARIANT oldVal, newVal;
- clearVariant(&oldVal);
- setVariantString(event->value().toString(), &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
- ::SysFreeString(newVal.bstrVal);
- }
+ // Notifies changes in string values.
+ VARIANT oldVal, newVal;
+ clearVariant(&oldVal);
+ setVariantString(event->value().toString(), &newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
}
} else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
@@ -165,7 +152,7 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantDouble(valueInterface->currentValue().toDouble(), &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_RangeValueValuePropertyId, oldVal, newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_RangeValueValuePropertyId, oldVal, newVal);
}
}
}
@@ -181,7 +168,7 @@ void QWindowsUiaMainProvider::notifyNameChange(QAccessibleEvent *event)
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantString(accessible->text(QAccessible::Name), &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_NamePropertyId, oldVal, newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_NamePropertyId, oldVal, newVal);
::SysFreeString(newVal.bstrVal);
}
}
@@ -192,7 +179,7 @@ void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event)
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
}
}
}
@@ -204,13 +191,13 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
if (accessible->textInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
if (event->type() == QAccessible::TextSelectionChanged) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
} else if (event->type() == QAccessible::TextCaretMoved) {
if (!accessible->state().readOnly) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
}
} else {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Text_TextChangedEventId);
}
}
}
@@ -219,31 +206,26 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
HRESULT STDMETHODCALLTYPE QWindowsUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
{
- if (!iface)
- return E_INVALIDARG;
- *iface = nullptr;
-
- QAccessibleInterface *accessible = accessibleInterface();
+ HRESULT result = QComObject::QueryInterface(iid, iface);
- const bool result = qWindowsComQueryUnknownInterfaceMulti<IRawElementProviderSimple>(this, iid, iface)
- || qWindowsComQueryInterface<IRawElementProviderSimple>(this, iid, iface)
- || qWindowsComQueryInterface<IRawElementProviderFragment>(this, iid, iface)
- || (accessible && hwndForAccessible(accessible) && qWindowsComQueryInterface<IRawElementProviderFragmentRoot>(this, iid, iface));
- return result ? S_OK : E_NOINTERFACE;
-}
+ if (SUCCEEDED(result) && iid == __uuidof(IRawElementProviderFragmentRoot)) {
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (accessible && hwndForAccessible(accessible)) {
+ result = S_OK;
+ } else {
+ result = E_NOINTERFACE;
+ iface = nullptr;
+ }
+ }
-ULONG QWindowsUiaMainProvider::AddRef()
-{
- return ++m_ref;
+ return result;
}
ULONG STDMETHODCALLTYPE QWindowsUiaMainProvider::Release()
{
- if (!--m_ref) {
- delete this;
- return 0;
- }
- return m_ref;
+ QMutexLocker locker(&m_mutex);
+
+ return QComObject::Release();
}
HRESULT QWindowsUiaMainProvider::get_ProviderOptions(ProviderOptions *pRetVal)
@@ -298,15 +280,18 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
*pRetVal = new QWindowsUiaToggleProvider(id());
break;
case UIA_SelectionPatternId:
- // Lists of items.
- if (accessible->role() == QAccessible::List
+ case UIA_SelectionPattern2Id:
+ // Selections via QAccessibleSelectionInterface or lists of items.
+ if (accessible->selectionInterface()
+ || accessible->role() == QAccessible::List
|| accessible->role() == QAccessible::PageTabList) {
*pRetVal = new QWindowsUiaSelectionProvider(id());
}
break;
case UIA_SelectionItemPatternId:
- // Items within a list and radio buttons.
- if ((accessible->role() == QAccessible::RadioButton)
+ // Parent supports selection interface or items within a list and radio buttons.
+ if ((accessible->parent() && accessible->parent()->selectionInterface())
+ || (accessible->role() == QAccessible::RadioButton)
|| (accessible->role() == QAccessible::ListItem)
|| (accessible->role() == QAccessible::PageTab)) {
*pRetVal = new QWindowsUiaSelectionItemProvider(id());
@@ -363,6 +348,28 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
return S_OK;
}
+void QWindowsUiaMainProvider::fillVariantArrayForRelation(QAccessibleInterface* accessible,
+ QAccessible::Relation relation, VARIANT *pRetVal)
+{
+ Q_ASSERT(accessible);
+
+ typedef QPair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
+ const QList<RelationPair> relationInterfaces = accessible->relations(relation);
+ if (relationInterfaces.empty())
+ return;
+
+ SAFEARRAY *elements = SafeArrayCreateVector(VT_UNKNOWN, 0, relationInterfaces.size());
+ for (LONG i = 0; i < relationInterfaces.size(); ++i) {
+ if (QWindowsUiaMainProvider *childProvider = QWindowsUiaMainProvider::providerForAccessible(relationInterfaces.at(i).first)) {
+ SafeArrayPutElement(elements, &i, static_cast<IRawElementProviderSimple*>(childProvider));
+ childProvider->Release();
+ }
+ }
+
+ pRetVal->vt = VT_UNKNOWN | VT_ARRAY;
+ pRetVal->parray = elements;
+}
+
HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal)
{
qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idProp;
@@ -397,6 +404,15 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
setVariantString(className, pRetVal);
}
break;
+ case UIA_DescribedByPropertyId:
+ fillVariantArrayForRelation(accessible, QAccessible::DescriptionFor, pRetVal);
+ break;
+ case UIA_FlowsFromPropertyId:
+ fillVariantArrayForRelation(accessible, QAccessible::FlowsTo, pRetVal);
+ break;
+ case UIA_FlowsToPropertyId:
+ fillVariantArrayForRelation(accessible, QAccessible::FlowsFrom, pRetVal);
+ break;
case UIA_FrameworkIdPropertyId:
setVariantString(QStringLiteral("Qt"), pRetVal);
break;
@@ -410,7 +426,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
// The native OSK should be disabled if the Qt OSK is in use,
// or if disabled via application attribute.
- static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE");
+ static bool imModuleEmpty = QPlatformInputContextFactory::requested().isEmpty();
bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_DisableNativeVirtualKeyboard);
// If we want to disable the native OSK auto-showing
@@ -513,7 +529,7 @@ HRESULT QWindowsUiaMainProvider::get_HostRawElementProvider(IRawElementProviderS
// Returns a host provider only for controls associated with a native window handle. Others should return NULL.
if (QAccessibleInterface *accessible = accessibleInterface()) {
if (HWND hwnd = hwndForAccessible(accessible)) {
- return QWindowsUiaWrapper::instance()->hostProviderFromHwnd(hwnd, pRetVal);
+ return UiaHostProviderFromHwnd(hwnd, pRetVal);
}
}
return S_OK;