summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows/uiautomation
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/windows/uiautomation')
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp111
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h5
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp8
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h11
5 files changed, 138 insertions, 0 deletions
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
index 1abb412ccd..5892493281 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
@@ -127,6 +127,9 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
return;
switch (event->type()) {
+ case QAccessible::Announcement:
+ QWindowsUiaMainProvider::raiseNotification(static_cast<QAccessibleAnnouncementEvent *>(event));
+ break;
case QAccessible::Focus:
QWindowsUiaMainProvider::notifyFocusChange(event);
break;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index 95ddbcced6..be88ab4ae8 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -204,6 +204,24 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
}
}
+void QWindowsUiaMainProvider::raiseNotification(QAccessibleAnnouncementEvent *event)
+{
+ if (QAccessibleInterface *accessible = event->accessibleInterface()) {
+ if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
+ BSTR message = bStrFromQString(event->message());
+ QAccessible::AnnouncementPriority prio = event->priority();
+ NotificationProcessing processing = (prio == QAccessible::AnnouncementPriority::Assertive)
+ ? NotificationProcessing_ImportantAll
+ : NotificationProcessing_All;
+ BSTR activityId = bStrFromQString(QString::fromLatin1(""));
+ UiaRaiseNotificationEvent(provider, NotificationKind_Other, processing, message, activityId);
+
+ ::SysFreeString(message);
+ ::SysFreeString(activityId);
+ }
+ }
+}
+
HRESULT STDMETHODCALLTYPE QWindowsUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
{
HRESULT result = QComObject::QueryInterface(iid, iface);
@@ -370,6 +388,93 @@ void QWindowsUiaMainProvider::fillVariantArrayForRelation(QAccessibleInterface*
pRetVal->parray = elements;
}
+void QWindowsUiaMainProvider::setAriaProperties(QAccessibleInterface *accessible, VARIANT *pRetVal)
+{
+ Q_ASSERT(accessible);
+
+ QAccessibleAttributesInterface *attributesIface = accessible->attributesInterface();
+ if (!attributesIface)
+ return;
+
+ QString ariaString;
+ const QList<QAccessible::Attribute> attrKeys = attributesIface->attributeKeys();
+ for (qsizetype i = 0; i < attrKeys.size(); ++i) {
+ if (i != 0)
+ ariaString += QStringLiteral(";");
+ const QAccessible::Attribute key = attrKeys.at(i);
+ const QVariant value = attributesIface->attributeValue(key);
+ // see "Core Accessibility API Mappings" spec: https://www.w3.org/TR/core-aam-1.2/
+ switch (key) {
+ case QAccessible::Attribute::Custom:
+ {
+ // forward custom attributes as-is
+ Q_ASSERT((value.canConvert<QHash<QString, QString>>()));
+ const QHash<QString, QString> attrMap = value.value<QHash<QString, QString>>();
+ for (auto [name, val] : attrMap.asKeyValueRange()) {
+ if (name != *attrMap.keyBegin())
+ ariaString += QStringLiteral(";");
+ ariaString += name + QStringLiteral("=") + val;
+ }
+ break;
+ }
+ case QAccessible::Attribute::Level:
+ Q_ASSERT(value.canConvert<int>());
+ ariaString += QStringLiteral("level=") + QString::number(value.toInt());
+ break;
+ default:
+ break;
+ }
+ }
+
+ setVariantString(ariaString, pRetVal);
+}
+
+void QWindowsUiaMainProvider::setStyle(QAccessibleInterface *accessible, VARIANT *pRetVal)
+{
+ Q_ASSERT(accessible);
+
+ QAccessibleAttributesInterface *attributesIface = accessible->attributesInterface();
+ if (!attributesIface)
+ return;
+
+ // currently, only heading styles are implemented here
+ if (accessible->role() != QAccessible::Role::Heading)
+ return;
+
+ const QVariant levelVariant = attributesIface->attributeValue(QAccessible::Attribute::Level);
+ if (!levelVariant.isValid())
+ return;
+
+ Q_ASSERT(levelVariant.canConvert<int>());
+ // UIA only has styles for heading levels 1-9
+ const int level = levelVariant.toInt();
+ if (level < 1 || level > 9)
+ return;
+
+ const int styleId = styleIdForHeadingLevel(level);
+ setVariantI4(styleId, pRetVal);
+}
+
+int QWindowsUiaMainProvider::styleIdForHeadingLevel(int headingLevel)
+{
+ // only heading levels 1-9 have a corresponding UIA style ID
+ Q_ASSERT(headingLevel > 0 && headingLevel <= 9);
+
+ static constexpr int styles[] = {
+ StyleId_Heading1,
+ StyleId_Heading2,
+ StyleId_Heading3,
+ StyleId_Heading4,
+ StyleId_Heading5,
+ StyleId_Heading6,
+ StyleId_Heading7,
+ StyleId_Heading8,
+ StyleId_Heading9,
+ };
+
+ return styles[headingLevel - 1];
+}
+
HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal)
{
qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idProp;
@@ -393,6 +498,9 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
// Accelerator key.
setVariantString(accessible->text(QAccessible::Accelerator), pRetVal);
break;
+ case UIA_AriaPropertiesPropertyId:
+ setAriaProperties(accessible, pRetVal);
+ break;
case UIA_AutomationIdPropertyId:
// Automation ID, which can be used by tools to select a specific control in the UI.
setVariantString(automationIdForAccessible(accessible), pRetVal);
@@ -493,6 +601,9 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
setVariantString(name, pRetVal);
break;
}
+ case UIA_StyleIdAttributeId:
+ setStyle(accessible, pRetVal);
+ break;
default:
break;
}
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
index 99db0ed318..dafe877974 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
@@ -34,6 +34,7 @@ public:
static void notifyNameChange(QAccessibleEvent *event);
static void notifySelectionChange(QAccessibleEvent *event);
static void notifyTextChange(QAccessibleEvent *event);
+ static void raiseNotification(QAccessibleAnnouncementEvent *event);
// IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
@@ -60,6 +61,10 @@ public:
private:
QString automationIdForAccessible(const QAccessibleInterface *accessible);
static void fillVariantArrayForRelation(QAccessibleInterface *accessible, QAccessible::Relation relation, VARIANT *pRetVal);
+ static void setAriaProperties(QAccessibleInterface *accessible, VARIANT *pRetVal);
+ static void setStyle(QAccessibleInterface *accessible, VARIANT *pRetVal);
+ /** Returns the UIA style ID for a heading level from 1 to 9. */
+ static int styleIdForHeadingLevel(int headingLevel);
static QMutex m_mutex;
};
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
index 1593a07202..6954a881d0 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
@@ -69,6 +69,14 @@ HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *pProvider, EVE
return func.invoke(pProvider, id);
}
+HRESULT WINAPI UiaRaiseNotificationEvent(
+ IRawElementProviderSimple *pProvider, NotificationKind notificationKind,
+ NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaRaiseNotificationEvent));
+ return func.invoke(pProvider, notificationKind, notificationProcessing, displayString, activityId);
+}
+
#endif // defined(__MINGW32__) || defined(__MINGW64__)
#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
index a192b9b0fb..4eb37bafa0 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
@@ -14,8 +14,19 @@
#define UIA_SelectionPattern2Id 10034
#define UIA_IsReadOnlyAttributeId 40015
#define UIA_StrikethroughStyleAttributeId 40026
+#define UIA_StyleIdAttributeId 40034
#define UIA_CaretPositionAttributeId 40038
+#define StyleId_Heading1 70001
+#define StyleId_Heading2 70002
+#define StyleId_Heading3 70003
+#define StyleId_Heading4 70004
+#define StyleId_Heading5 70005
+#define StyleId_Heading6 70006
+#define StyleId_Heading7 70007
+#define StyleId_Heading8 70008
+#define StyleId_Heading9 70009
+
enum CaretPosition {
CaretPosition_Unknown = 0,
CaretPosition_EndOfLine = 1,