mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-11 23:54:18 +00:00
Accessibility: Check if any accessibility clients are active before posting notifications and announcements
This commit is contained in:
parent
399f8d5bf6
commit
cdf3b619d8
4 changed files with 77 additions and 32 deletions
|
|
@ -28,6 +28,8 @@ namespace juce
|
|||
|
||||
AccessibilityHandler* AccessibilityHandler::currentlyFocusedHandler = nullptr;
|
||||
|
||||
bool areAnyAccessibilityClientsActive();
|
||||
|
||||
enum class InternalAccessibilityEvent
|
||||
{
|
||||
elementCreated,
|
||||
|
|
@ -37,7 +39,7 @@ enum class InternalAccessibilityEvent
|
|||
windowClosed
|
||||
};
|
||||
|
||||
void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent event);
|
||||
void notifyAccessibilityEventInternal (const AccessibilityHandler&, InternalAccessibilityEvent);
|
||||
|
||||
inline String getAccessibleApplicationOrPluginName()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -347,6 +347,7 @@ namespace juce
|
|||
AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const { return nullptr; }
|
||||
AccessibilityHandler::AccessibilityNativeImpl* AccessibilityHandler::createNativeImpl (AccessibilityHandler&) { return nullptr; }
|
||||
void AccessibilityHandler::DestroyNativeImpl::operator() (AccessibilityHandler::AccessibilityNativeImpl*) const noexcept {}
|
||||
bool areAnyAccessibilityClientsActive() { return false; }
|
||||
void notifyAccessibilityEventInternal (const AccessibilityHandler&, InternalAccessibilityEvent) {}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1025,6 +1025,20 @@ AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
|
|||
return (AccessibilityNativeHandle*) nativeImpl->getAccessibilityElement();
|
||||
}
|
||||
|
||||
bool areAnyAccessibilityClientsActive()
|
||||
{
|
||||
const String voiceOverKeyString ("voiceOverOnOffKey");
|
||||
const String applicationIDString ("com.apple.universalaccess");
|
||||
|
||||
CFUniquePtr<CFPropertyListRef> value (CFPreferencesCopyAppValue (voiceOverKeyString.toCFString(),
|
||||
applicationIDString.toCFString()));
|
||||
|
||||
if (value != nullptr)
|
||||
return CFBooleanGetValue ((CFBooleanRef) value.get());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void sendAccessibilityEvent (id accessibilityElement,
|
||||
NSAccessibilityNotificationName notification,
|
||||
NSDictionary* userInfo)
|
||||
|
|
@ -1034,6 +1048,21 @@ static void sendAccessibilityEvent (id accessibilityElement,
|
|||
NSAccessibilityPostNotificationWithUserInfo (accessibilityElement, notification, userInfo);
|
||||
}
|
||||
|
||||
static void sendHandlerNotification (const AccessibilityHandler& handler,
|
||||
NSAccessibilityNotificationName notification)
|
||||
{
|
||||
if (! areAnyAccessibilityClientsActive() || notification == NSAccessibilityNotificationName{})
|
||||
return;
|
||||
|
||||
if (id accessibilityElement = (id) handler.getNativeImplementation())
|
||||
{
|
||||
sendAccessibilityEvent (accessibilityElement, notification,
|
||||
(notification == NSAccessibilityLayoutChangedNotification
|
||||
? @{ NSAccessibilityUIElementsKey: @[ accessibilityElement ] }
|
||||
: nil));
|
||||
}
|
||||
}
|
||||
|
||||
void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent eventType)
|
||||
{
|
||||
auto notification = [eventType]
|
||||
|
|
@ -1050,9 +1079,7 @@ void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, Inte
|
|||
return NSAccessibilityNotificationName{};
|
||||
}();
|
||||
|
||||
if (notification != NSAccessibilityNotificationName{})
|
||||
if (id accessibilityElement = (id) handler.getNativeImplementation())
|
||||
sendAccessibilityEvent (accessibilityElement, notification, nil);
|
||||
sendHandlerNotification (handler, notification);
|
||||
}
|
||||
|
||||
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
|
||||
|
|
@ -1073,20 +1100,14 @@ void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventTyp
|
|||
return NSAccessibilityNotificationName{};
|
||||
}();
|
||||
|
||||
if (notification != NSAccessibilityNotificationName{})
|
||||
{
|
||||
if (id accessibilityElement = (id) getNativeImplementation())
|
||||
{
|
||||
sendAccessibilityEvent (accessibilityElement, notification,
|
||||
(notification == NSAccessibilityLayoutChangedNotification
|
||||
? @{ NSAccessibilityUIElementsKey: @[ accessibilityElement ] }
|
||||
: nil));
|
||||
}
|
||||
}
|
||||
sendHandlerNotification (*this, notification);
|
||||
}
|
||||
|
||||
void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority priority)
|
||||
{
|
||||
if (! areAnyAccessibilityClientsActive())
|
||||
return;
|
||||
|
||||
#if JUCE_OBJC_HAS_AVAILABLE_FEATURE
|
||||
if (@available (macOS 10.10, *))
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -66,15 +66,15 @@ public:
|
|||
accessibilityElement->invalidateElement();
|
||||
--providerCount;
|
||||
|
||||
if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
{
|
||||
ComSmartPtr<IRawElementProviderSimple> provider;
|
||||
accessibilityElement->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
|
||||
|
||||
wrapper->disconnectProvider (provider);
|
||||
uiaWrapper->disconnectProvider (provider);
|
||||
|
||||
if (providerCount == 0)
|
||||
wrapper->disconnectAllProviders();
|
||||
uiaWrapper->disconnectAllProviders();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,21 +94,39 @@ AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
|
|||
return nativeImpl->accessibilityElement;
|
||||
}
|
||||
|
||||
bool areAnyAccessibilityClientsActive()
|
||||
{
|
||||
const auto areClientsListening = []
|
||||
{
|
||||
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
return uiaWrapper->clientsAreListening() != 0;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto isScreenReaderRunning = []
|
||||
{
|
||||
BOOL isRunning = FALSE;
|
||||
SystemParametersInfo (SPI_GETSCREENREADER, 0, (PVOID) &isRunning, 0);
|
||||
|
||||
return isRunning != 0;
|
||||
};
|
||||
|
||||
return areClientsListening() || isScreenReaderRunning();
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback)
|
||||
{
|
||||
if (isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
|
||||
if (! areAnyAccessibilityClientsActive() || isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
|
||||
return;
|
||||
|
||||
if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
{
|
||||
if (! wrapper->clientsAreListening())
|
||||
return;
|
||||
|
||||
ComSmartPtr<IRawElementProviderSimple> provider;
|
||||
handler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
|
||||
|
||||
callback (wrapper, provider);
|
||||
callback (uiaWrapper, provider);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,9 +134,9 @@ void sendAccessibilityAutomationEvent (const AccessibilityHandler& handler, EVEN
|
|||
{
|
||||
jassert (event != EVENTID{});
|
||||
|
||||
getProviderWithCheckedWrapper (handler, [event] (WindowsUIAWrapper* wrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
|
||||
getProviderWithCheckedWrapper (handler, [event] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
|
||||
{
|
||||
wrapper->raiseAutomationEvent (provider, event);
|
||||
uiaWrapper->raiseAutomationEvent (provider, event);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -126,12 +144,12 @@ void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler& handler,
|
|||
{
|
||||
jassert (property != PROPERTYID{});
|
||||
|
||||
getProviderWithCheckedWrapper (handler, [property, newValue] (WindowsUIAWrapper* wrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
|
||||
getProviderWithCheckedWrapper (handler, [property, newValue] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
|
||||
{
|
||||
VARIANT oldValue;
|
||||
VariantHelpers::clear (&oldValue);
|
||||
|
||||
wrapper->raiseAutomationPropertyChangedEvent (provider, property, oldValue, newValue);
|
||||
uiaWrapper->raiseAutomationPropertyChangedEvent (provider, property, oldValue, newValue);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -218,6 +236,9 @@ JUCE_IMPLEMENT_SINGLETON (SpVoiceWrapper)
|
|||
|
||||
void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority priority)
|
||||
{
|
||||
if (! areAnyAccessibilityClientsActive())
|
||||
return;
|
||||
|
||||
if (auto* sharedVoice = SpVoiceWrapper::getInstance())
|
||||
{
|
||||
auto voicePriority = [priority]
|
||||
|
|
@ -261,13 +282,13 @@ namespace WindowsAccessibility
|
|||
if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
|
||||
return false;
|
||||
|
||||
if (auto* wrapper = WindowsUIAWrapper::getInstance())
|
||||
if (auto* uiaWrapper = WindowsUIAWrapper::getInstance())
|
||||
{
|
||||
ComSmartPtr<IRawElementProviderSimple> provider;
|
||||
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
|
||||
|
||||
if (! wrapper->isProviderDisconnecting (provider))
|
||||
*res = wrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
|
||||
if (! uiaWrapper->isProviderDisconnecting (provider))
|
||||
*res = uiaWrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -277,8 +298,8 @@ namespace WindowsAccessibility
|
|||
|
||||
void revokeUIAMapEntriesForWindow (HWND hwnd)
|
||||
{
|
||||
if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
wrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
|
||||
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
|
||||
uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue