The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
8.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. static bool isStartingUpOrShuttingDown()
  21. {
  22. if (auto* app = JUCEApplicationBase::getInstance())
  23. if (app->isInitialising())
  24. return true;
  25. if (auto* mm = MessageManager::getInstanceWithoutCreating())
  26. if (mm->hasStopMessageBeenSent())
  27. return true;
  28. return false;
  29. }
  30. static bool isHandlerValid (const AccessibilityHandler& handler)
  31. {
  32. if (auto* provider = handler.getNativeImplementation())
  33. return provider->isElementValid();
  34. return false;
  35. }
  36. //==============================================================================
  37. class AccessibilityHandler::AccessibilityNativeImpl
  38. {
  39. public:
  40. explicit AccessibilityNativeImpl (AccessibilityHandler& owner)
  41. : accessibilityElement (new AccessibilityNativeHandle (owner))
  42. {
  43. ++providerCount;
  44. }
  45. ~AccessibilityNativeImpl()
  46. {
  47. accessibilityElement->invalidateElement();
  48. --providerCount;
  49. if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
  50. {
  51. ComSmartPtr<IRawElementProviderSimple> provider;
  52. accessibilityElement->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
  53. wrapper->disconnectProvider (provider);
  54. if (providerCount == 0)
  55. wrapper->disconnectAllProviders();
  56. }
  57. }
  58. //==============================================================================
  59. ComSmartPtr<AccessibilityNativeHandle> accessibilityElement;
  60. static int providerCount;
  61. //==============================================================================
  62. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeImpl)
  63. };
  64. int AccessibilityHandler::AccessibilityNativeImpl::providerCount = 0;
  65. //==============================================================================
  66. AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
  67. {
  68. return nativeImpl->accessibilityElement;
  69. }
  70. template <typename Callback>
  71. void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback)
  72. {
  73. if (isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
  74. return;
  75. if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
  76. {
  77. if (! wrapper->clientsAreListening())
  78. return;
  79. ComSmartPtr<IRawElementProviderSimple> provider;
  80. handler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
  81. callback (wrapper, provider);
  82. }
  83. }
  84. void sendAccessibilityAutomationEvent (const AccessibilityHandler& handler, EVENTID event)
  85. {
  86. jassert (event != EVENTID{});
  87. getProviderWithCheckedWrapper (handler, [event] (WindowsUIAWrapper* wrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
  88. {
  89. wrapper->raiseAutomationEvent (provider, event);
  90. });
  91. }
  92. void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler& handler, PROPERTYID property, VARIANT newValue)
  93. {
  94. jassert (property != PROPERTYID{});
  95. getProviderWithCheckedWrapper (handler, [property, newValue] (WindowsUIAWrapper* wrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
  96. {
  97. VARIANT oldValue;
  98. VariantHelpers::clear (&oldValue);
  99. wrapper->raiseAutomationPropertyChangedEvent (provider, property, oldValue, newValue);
  100. });
  101. }
  102. void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent eventType)
  103. {
  104. auto event = [eventType]() -> EVENTID
  105. {
  106. switch (eventType)
  107. {
  108. case InternalAccessibilityEvent::elementCreated:
  109. case InternalAccessibilityEvent::elementDestroyed: return UIA_StructureChangedEventId;
  110. case InternalAccessibilityEvent::focusChanged: return UIA_AutomationFocusChangedEventId;
  111. case InternalAccessibilityEvent::windowOpened: return UIA_Window_WindowOpenedEventId;
  112. case InternalAccessibilityEvent::windowClosed: return UIA_Window_WindowClosedEventId;
  113. }
  114. return {};
  115. }();
  116. if (event != EVENTID{})
  117. sendAccessibilityAutomationEvent (handler, event);
  118. }
  119. void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
  120. {
  121. auto event = [eventType] () -> EVENTID
  122. {
  123. switch (eventType)
  124. {
  125. case AccessibilityEvent::textSelectionChanged: return UIA_Text_TextSelectionChangedEventId;
  126. case AccessibilityEvent::textChanged: return UIA_Text_TextChangedEventId;
  127. case AccessibilityEvent::structureChanged: return UIA_StructureChangedEventId;
  128. case AccessibilityEvent::rowSelectionChanged: return UIA_SelectionItem_ElementSelectedEventId;
  129. case AccessibilityEvent::valueChanged: break;
  130. }
  131. return {};
  132. }();
  133. if (event != EVENTID{})
  134. sendAccessibilityAutomationEvent (*this, event);
  135. }
  136. struct SpVoiceWrapper : public DeletedAtShutdown
  137. {
  138. SpVoiceWrapper()
  139. {
  140. auto hr = voice.CoCreateInstance (CLSID_SpVoice);
  141. jassert (SUCCEEDED (hr));
  142. ignoreUnused (hr);
  143. }
  144. ~SpVoiceWrapper() override
  145. {
  146. clearSingletonInstance();
  147. }
  148. ComSmartPtr<ISpVoice> voice;
  149. JUCE_DECLARE_SINGLETON (SpVoiceWrapper, false)
  150. };
  151. JUCE_IMPLEMENT_SINGLETON (SpVoiceWrapper)
  152. void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority priority)
  153. {
  154. if (auto* sharedVoice = SpVoiceWrapper::getInstance())
  155. {
  156. auto voicePriority = [priority]
  157. {
  158. switch (priority)
  159. {
  160. case AnnouncementPriority::low: return SPVPRI_OVER;
  161. case AnnouncementPriority::medium: return SPVPRI_NORMAL;
  162. case AnnouncementPriority::high: return SPVPRI_ALERT;
  163. }
  164. jassertfalse;
  165. return SPVPRI_OVER;
  166. }();
  167. sharedVoice->voice->SetPriority (voicePriority);
  168. sharedVoice->voice->Speak (announcementString.toWideCharPointer(), SPF_ASYNC, nullptr);
  169. }
  170. }
  171. AccessibilityHandler::AccessibilityNativeImpl* AccessibilityHandler::createNativeImpl (AccessibilityHandler& handler)
  172. {
  173. return new AccessibilityHandler::AccessibilityNativeImpl (handler);
  174. }
  175. void AccessibilityHandler::DestroyNativeImpl::operator() (AccessibilityHandler::AccessibilityNativeImpl* impl) const noexcept
  176. {
  177. delete impl;
  178. }
  179. //==============================================================================
  180. namespace WindowsAccessibility
  181. {
  182. long getUiaRootObjectId()
  183. {
  184. return static_cast<long> (UiaRootObjectId);
  185. }
  186. bool handleWmGetObject (AccessibilityHandler* handler, WPARAM wParam, LPARAM lParam, LRESULT* res)
  187. {
  188. if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
  189. return false;
  190. if (auto* wrapper = WindowsUIAWrapper::getInstance())
  191. {
  192. ComSmartPtr<IRawElementProviderSimple> provider;
  193. handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
  194. if (! wrapper->isProviderDisconnecting (provider))
  195. *res = wrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
  196. return true;
  197. }
  198. return false;
  199. }
  200. void revokeUIAMapEntriesForWindow (HWND hwnd)
  201. {
  202. if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
  203. wrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
  204. }
  205. }
  206. JUCE_IMPLEMENT_SINGLETON (WindowsUIAWrapper)
  207. } // namespace juce