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>
This commit is contained in:
parent
295a16b0d3
commit
566def740e
@ -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
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
Loading…
Reference in New Issue
Block a user