| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2022 - Raw Material Software Limited
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 -    Agreement and JUCE Privacy Policy.
 - 
 -    End User License Agreement: www.juce.com/juce-7-licence
 -    Privacy Policy: www.juce.com/juce-privacy-policy
 - 
 -    Or: You may also use this code under the terms of the GPL v3 (see
 -    www.gnu.org/licenses).
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace juce
 - {
 - 
 - #define JUCE_NATIVE_ACCESSIBILITY_INCLUDED 1
 - 
 - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 - 
 - static bool isStartingUpOrShuttingDown()
 - {
 -     if (auto* app = JUCEApplicationBase::getInstance())
 -         if (app->isInitialising())
 -             return true;
 - 
 -     if (auto* mm = MessageManager::getInstanceWithoutCreating())
 -         if (mm->hasStopMessageBeenSent())
 -             return true;
 - 
 -     return false;
 - }
 - 
 - static bool isHandlerValid (const AccessibilityHandler& handler)
 - {
 -     if (auto* provider = handler.getNativeImplementation())
 -         return provider->isElementValid();
 - 
 -     return false;
 - }
 - 
 - //==============================================================================
 - class AccessibilityHandler::AccessibilityNativeImpl
 - {
 - public:
 -     explicit AccessibilityNativeImpl (AccessibilityHandler& owner)
 -         : accessibilityElement (new AccessibilityNativeHandle (owner))
 -     {
 -         ++providerCount;
 -     }
 - 
 -     ~AccessibilityNativeImpl()
 -     {
 -         ComSmartPtr<IRawElementProviderSimple> provider;
 -         accessibilityElement->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 - 
 -         accessibilityElement->invalidateElement();
 -         --providerCount;
 - 
 -         if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 -         {
 -             uiaWrapper->disconnectProvider (provider);
 - 
 -             if (providerCount == 0 && JUCEApplicationBase::isStandaloneApp())
 -                 uiaWrapper->disconnectAllProviders();
 -         }
 -     }
 - 
 -     //==============================================================================
 -     ComSmartPtr<AccessibilityNativeHandle> accessibilityElement;
 -     static int providerCount;
 - 
 -     //==============================================================================
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeImpl)
 - };
 - 
 - int AccessibilityHandler::AccessibilityNativeImpl::providerCount = 0;
 - 
 - //==============================================================================
 - AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
 - {
 -     return nativeImpl->accessibilityElement;
 - }
 - 
 - static 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 (! areAnyAccessibilityClientsActive() || isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
 -         return;
 - 
 -     if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 -     {
 -         ComSmartPtr<IRawElementProviderSimple> provider;
 -         handler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 - 
 -         callback (uiaWrapper, provider);
 -     }
 - }
 - 
 - void sendAccessibilityAutomationEvent (const AccessibilityHandler& handler, EVENTID event)
 - {
 -     jassert (event != EVENTID{});
 - 
 -     getProviderWithCheckedWrapper (handler, [event] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
 -     {
 -         uiaWrapper->raiseAutomationEvent (provider, event);
 -     });
 - }
 - 
 - void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler& handler, PROPERTYID property, VARIANT newValue)
 - {
 -     jassert (property != PROPERTYID{});
 - 
 -     getProviderWithCheckedWrapper (handler, [property, newValue] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
 -     {
 -         VARIANT oldValue;
 -         VariantHelpers::clear (&oldValue);
 - 
 -         uiaWrapper->raiseAutomationPropertyChangedEvent (provider, property, oldValue, newValue);
 -     });
 - }
 - 
 - void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent eventType)
 - {
 -     using namespace ComTypes::Constants;
 - 
 -     if (eventType == InternalAccessibilityEvent::elementCreated
 -         || eventType == InternalAccessibilityEvent::elementDestroyed)
 -     {
 -         if (auto* parent = handler.getParent())
 -             sendAccessibilityAutomationEvent (*parent, UIA_LayoutInvalidatedEventId);
 - 
 -         return;
 -     }
 - 
 -     if (eventType == InternalAccessibilityEvent::windowOpened
 -         || eventType == InternalAccessibilityEvent::windowClosed)
 -     {
 -         if (auto* peer = handler.getComponent().getPeer())
 -             if ((peer->getStyleFlags() & ComponentPeer::windowHasTitleBar) == 0)
 -                 return;
 -     }
 - 
 -     auto event = [eventType]() -> EVENTID
 -     {
 -         switch (eventType)
 -         {
 -             case InternalAccessibilityEvent::focusChanged:           return UIA_AutomationFocusChangedEventId;
 -             case InternalAccessibilityEvent::windowOpened:           return UIA_Window_WindowOpenedEventId;
 -             case InternalAccessibilityEvent::windowClosed:           return UIA_Window_WindowClosedEventId;
 -             case InternalAccessibilityEvent::elementCreated:
 -             case InternalAccessibilityEvent::elementDestroyed:
 -             case InternalAccessibilityEvent::elementMovedOrResized:  break;
 -         }
 - 
 -         return {};
 -     }();
 - 
 -     if (event != EVENTID{})
 -         sendAccessibilityAutomationEvent (handler, event);
 - }
 - 
 - void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
 - {
 -     if (eventType == AccessibilityEvent::titleChanged)
 -     {
 -         VARIANT newValue;
 -         VariantHelpers::setString (getTitle(), &newValue);
 - 
 -         sendAccessibilityPropertyChangedEvent (*this, UIA_NamePropertyId, newValue);
 -         return;
 -     }
 - 
 -     if (eventType == AccessibilityEvent::valueChanged)
 -     {
 -         if (auto* valueInterface = getValueInterface())
 -         {
 -             const auto propertyType = getRole() == AccessibilityRole::slider ? UIA_RangeValueValuePropertyId
 -                                                                              : UIA_ValueValuePropertyId;
 - 
 -             const auto value = getRole() == AccessibilityRole::slider
 -                                ? VariantHelpers::getWithValue (valueInterface->getCurrentValue())
 -                                : VariantHelpers::getWithValue (valueInterface->getCurrentValueAsString());
 - 
 -             sendAccessibilityPropertyChangedEvent (*this, propertyType, value);
 -         }
 - 
 -         return;
 -     }
 - 
 -     auto event = [eventType]() -> EVENTID
 -     {
 -         using namespace ComTypes::Constants;
 - 
 -         switch (eventType)
 -         {
 -             case AccessibilityEvent::textSelectionChanged:  return UIA_Text_TextSelectionChangedEventId;
 -             case AccessibilityEvent::textChanged:           return UIA_Text_TextChangedEventId;
 -             case AccessibilityEvent::structureChanged:      return UIA_StructureChangedEventId;
 -             case AccessibilityEvent::rowSelectionChanged:   return UIA_SelectionItem_ElementSelectedEventId;
 -             case AccessibilityEvent::titleChanged:
 -             case AccessibilityEvent::valueChanged:          break;
 -         }
 - 
 -         return {};
 -     }();
 - 
 -     if (event != EVENTID{})
 -         sendAccessibilityAutomationEvent (*this, event);
 - }
 - 
 - struct SpVoiceWrapper  : public DeletedAtShutdown
 - {
 -     SpVoiceWrapper()
 -     {
 -         auto hr = voice.CoCreateInstance (ComTypes::CLSID_SpVoice);
 - 
 -         jassertquiet (SUCCEEDED (hr));
 -     }
 - 
 -     ~SpVoiceWrapper() override
 -     {
 -         clearSingletonInstance();
 -     }
 - 
 -     ComSmartPtr<ISpVoice> voice;
 - 
 -     JUCE_DECLARE_SINGLETON (SpVoiceWrapper, false)
 - };
 - 
 - JUCE_IMPLEMENT_SINGLETON (SpVoiceWrapper)
 - 
 - 
 - void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority priority)
 - {
 -     if (! areAnyAccessibilityClientsActive())
 -         return;
 - 
 -     if (auto* sharedVoice = SpVoiceWrapper::getInstance())
 -     {
 -         auto voicePriority = [priority]
 -         {
 -             switch (priority)
 -             {
 -                 case AnnouncementPriority::low:    return SPVPRI_OVER;
 -                 case AnnouncementPriority::medium: return SPVPRI_NORMAL;
 -                 case AnnouncementPriority::high:   return SPVPRI_ALERT;
 -             }
 - 
 -             jassertfalse;
 -             return SPVPRI_OVER;
 -         }();
 - 
 -         sharedVoice->voice->SetPriority (voicePriority);
 -         sharedVoice->voice->Speak (announcementString.toWideCharPointer(), SPF_ASYNC, nullptr);
 -     }
 - }
 - 
 - //==============================================================================
 - namespace WindowsAccessibility
 - {
 -     static long getUiaRootObjectId()
 -     {
 -         return static_cast<long> (UiaRootObjectId);
 -     }
 - 
 -     static bool handleWmGetObject (AccessibilityHandler* handler, WPARAM wParam, LPARAM lParam, LRESULT* res)
 -     {
 -         if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
 -             return false;
 - 
 -         if (auto* uiaWrapper = WindowsUIAWrapper::getInstance())
 -         {
 -             ComSmartPtr<IRawElementProviderSimple> provider;
 -             handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 - 
 -             if (! uiaWrapper->isProviderDisconnecting (provider))
 -                 *res = uiaWrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
 - 
 -             return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     static void revokeUIAMapEntriesForWindow (HWND hwnd)
 -     {
 -         if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 -             uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
 -     }
 - }
 - 
 - 
 - JUCE_IMPLEMENT_SINGLETON (WindowsUIAWrapper)
 - 
 - JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 - 
 - } // namespace juce
 
 
  |