diff options
author | Andre de la Rocha <andre.rocha@qt.io> | 2020-03-02 20:30:13 +0100 |
---|---|---|
committer | Andre de la Rocha <andre.rocha@qt.io> | 2020-03-04 13:09:48 +0100 |
commit | 566def740ec58e842e6bb37177f80e20aebaa245 (patch) | |
tree | aa2bac7a70531a0e84e5fade27c70f4a1b41affa | |
parent | 295a16b0d3836a8f41b5133bcd9f355afb03f38b (diff) |
Windows QPA: Add support to UiaRaiseNotificationEvent()
This change adds support to UiaRaiseNotificationEvent() in the
UI Automation-based accessibility code, and uses it to notify changes
in string-typed values, allowing Narrator, NVDA and other screen readers
to notice changes in the application state that were previously missed.
Fixes: QTBUG-75003
Change-Id: I646ca3a851ab7b69817d900b002eb91a3bf607a6
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
4 files changed, 49 insertions, 6 deletions
diff --git a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp index 79541fe636..8038e1a3c3 100644 --- a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp +++ b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp @@ -53,6 +53,7 @@ QWindowsUiaWrapper::QWindowsUiaWrapper() m_pUiaHostProviderFromHwnd = reinterpret_cast<PtrUiaHostProviderFromHwnd>(uiaLib.resolve("UiaHostProviderFromHwnd")); m_pUiaRaiseAutomationPropertyChangedEvent = reinterpret_cast<PtrUiaRaiseAutomationPropertyChangedEvent>(uiaLib.resolve("UiaRaiseAutomationPropertyChangedEvent")); m_pUiaRaiseAutomationEvent = reinterpret_cast<PtrUiaRaiseAutomationEvent>(uiaLib.resolve("UiaRaiseAutomationEvent")); + m_pUiaRaiseNotificationEvent = reinterpret_cast<PtrUiaRaiseNotificationEvent>(uiaLib.resolve("UiaRaiseNotificationEvent")); m_pUiaClientsAreListening = reinterpret_cast<PtrUiaClientsAreListening>(uiaLib.resolve("UiaClientsAreListening")); } } @@ -68,7 +69,7 @@ QWindowsUiaWrapper *QWindowsUiaWrapper::instance() return &wrapper; } -// True if all symbols resolved. +// True if most symbols resolved (UiaRaiseNotificationEvent is optional). BOOL QWindowsUiaWrapper::ready() { return m_pUiaReturnRawElementProvider @@ -113,5 +114,12 @@ HRESULT QWindowsUiaWrapper::raiseAutomationEvent(IRawElementProviderSimple *pPro return m_pUiaRaiseAutomationEvent(pProvider, id); } +HRESULT QWindowsUiaWrapper::raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId) +{ + if (!m_pUiaRaiseNotificationEvent) + return UIA_E_NOTSUPPORTED; + return m_pUiaRaiseNotificationEvent(provider, notificationKind, notificationProcessing, displayString, activityId); +} + QT_END_NAMESPACE diff --git a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h index 3ebc3008d3..9208acbc31 100644 --- a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h +++ b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h @@ -80,17 +80,20 @@ public: HRESULT hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider); HRESULT raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue); HRESULT raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id); + HRESULT raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId); private: typedef LRESULT (WINAPI *PtrUiaReturnRawElementProvider)(HWND, WPARAM, LPARAM, IRawElementProviderSimple *); typedef HRESULT (WINAPI *PtrUiaHostProviderFromHwnd)(HWND, IRawElementProviderSimple **); typedef HRESULT (WINAPI *PtrUiaRaiseAutomationPropertyChangedEvent)(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT); typedef HRESULT (WINAPI *PtrUiaRaiseAutomationEvent)(IRawElementProviderSimple *, EVENTID); + typedef HRESULT (WINAPI *PtrUiaRaiseNotificationEvent)(IRawElementProviderSimple *, NotificationKind, NotificationProcessing, BSTR, BSTR); typedef BOOL (WINAPI *PtrUiaClientsAreListening)(); PtrUiaReturnRawElementProvider m_pUiaReturnRawElementProvider = nullptr; PtrUiaHostProviderFromHwnd m_pUiaHostProviderFromHwnd = nullptr; PtrUiaRaiseAutomationPropertyChangedEvent m_pUiaRaiseAutomationPropertyChangedEvent = nullptr; PtrUiaRaiseAutomationEvent m_pUiaRaiseAutomationEvent = nullptr; + PtrUiaRaiseNotificationEvent m_pUiaRaiseNotificationEvent = nullptr; PtrUiaClientsAreListening m_pUiaClientsAreListening = nullptr; }; diff --git a/src/platformsupport/windowsuiautomation/uiatypes_p.h b/src/platformsupport/windowsuiautomation/uiatypes_p.h index afbc957094..0d2e1161e4 100644 --- a/src/platformsupport/windowsuiautomation/uiatypes_p.h +++ b/src/platformsupport/windowsuiautomation/uiatypes_p.h @@ -162,6 +162,22 @@ enum ExpandCollapseState { ExpandCollapseState_LeafNode = 3 }; +enum NotificationKind { + NotificationKind_ItemAdded = 0, + NotificationKind_ItemRemoved = 1, + NotificationKind_ActionCompleted = 2, + NotificationKind_ActionAborted = 3, + NotificationKind_Other = 4 +}; + +enum NotificationProcessing { + NotificationProcessing_ImportantAll = 0, + NotificationProcessing_ImportantMostRecent = 1, + NotificationProcessing_All = 2, + NotificationProcessing_MostRecent = 3, + NotificationProcessing_CurrentThenMostRecent = 4 +}; + struct UiaRect { double left; double top; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 9adc5c78dd..59360616a1 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -166,11 +166,27 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve } if (event->value().type() == QVariant::String) { if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { - // Notifies changes in string values. - VARIANT oldVal, newVal; - clearVariant(&oldVal); - setVariantString(event->value().toString(), &newVal); - QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal); + + // 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); + } } } else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { |