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.

271 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. if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
  49. {
  50. ComSmartPtr<IRawElementProviderSimple> provider;
  51. accessibilityElement->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
  52. wrapper->disconnectProvider (provider);
  53. if (--providerCount == 0)
  54. wrapper->disconnectAllProviders();
  55. }
  56. }
  57. //==============================================================================
  58. ComSmartPtr<AccessibilityNativeHandle> accessibilityElement;
  59. static int providerCount;
  60. //==============================================================================
  61. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeImpl)
  62. };
  63. int AccessibilityHandler::AccessibilityNativeImpl::providerCount = 0;
  64. //==============================================================================
  65. AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
  66. {
  67. return nativeImpl->accessibilityElement;
  68. }
  69. template <typename Callback>
  70. void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback)
  71. {
  72. if (isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
  73. return;
  74. if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
  75. {
  76. if (! wrapper->clientsAreListening())
  77. return;
  78. ComSmartPtr<IRawElementProviderSimple> provider;
  79. handler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
  80. callback (wrapper, provider);
  81. }
  82. }
  83. void sendAccessibilityAutomationEvent (const AccessibilityHandler& handler, EVENTID event)
  84. {
  85. jassert (event != EVENTID{});
  86. getProviderWithCheckedWrapper (handler, [event] (WindowsUIAWrapper* wrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
  87. {
  88. wrapper->raiseAutomationEvent (provider, event);
  89. });
  90. }
  91. void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler& handler, PROPERTYID property, VARIANT newValue)
  92. {
  93. jassert (property != PROPERTYID{});
  94. getProviderWithCheckedWrapper (handler, [property, newValue] (WindowsUIAWrapper* wrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
  95. {
  96. VARIANT oldValue;
  97. VariantHelpers::clear (&oldValue);
  98. wrapper->raiseAutomationPropertyChangedEvent (provider, property, oldValue, newValue);
  99. });
  100. }
  101. void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent eventType)
  102. {
  103. auto event = [eventType]() -> EVENTID
  104. {
  105. switch (eventType)
  106. {
  107. case InternalAccessibilityEvent::elementCreated:
  108. case InternalAccessibilityEvent::elementDestroyed: return UIA_StructureChangedEventId;
  109. case InternalAccessibilityEvent::focusChanged: return UIA_AutomationFocusChangedEventId;
  110. case InternalAccessibilityEvent::windowOpened: return UIA_Window_WindowOpenedEventId;
  111. case InternalAccessibilityEvent::windowClosed: return UIA_Window_WindowClosedEventId;
  112. }
  113. return {};
  114. }();
  115. if (event != EVENTID{})
  116. sendAccessibilityAutomationEvent (handler, event);
  117. }
  118. void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
  119. {
  120. auto event = [eventType] () -> EVENTID
  121. {
  122. switch (eventType)
  123. {
  124. case AccessibilityEvent::textSelectionChanged: return UIA_Text_TextSelectionChangedEventId;
  125. case AccessibilityEvent::textChanged: return UIA_Text_TextChangedEventId;
  126. case AccessibilityEvent::structureChanged: return UIA_StructureChangedEventId;
  127. case AccessibilityEvent::rowSelectionChanged: return UIA_SelectionItem_ElementSelectedEventId;
  128. case AccessibilityEvent::valueChanged: break;
  129. }
  130. return {};
  131. }();
  132. if (event != EVENTID{})
  133. sendAccessibilityAutomationEvent (*this, event);
  134. }
  135. struct SpVoiceWrapper : public DeletedAtShutdown
  136. {
  137. SpVoiceWrapper()
  138. {
  139. auto hr = voice.CoCreateInstance (CLSID_SpVoice);
  140. jassert (SUCCEEDED (hr));
  141. ignoreUnused (hr);
  142. }
  143. ~SpVoiceWrapper() override
  144. {
  145. clearSingletonInstance();
  146. }
  147. ComSmartPtr<ISpVoice> voice;
  148. JUCE_DECLARE_SINGLETON (SpVoiceWrapper, false)
  149. };
  150. JUCE_IMPLEMENT_SINGLETON (SpVoiceWrapper)
  151. void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority priority)
  152. {
  153. if (auto* sharedVoice = SpVoiceWrapper::getInstance())
  154. {
  155. auto voicePriority = [priority]
  156. {
  157. switch (priority)
  158. {
  159. case AnnouncementPriority::low: return SPVPRI_OVER;
  160. case AnnouncementPriority::medium: return SPVPRI_NORMAL;
  161. case AnnouncementPriority::high: return SPVPRI_ALERT;
  162. }
  163. jassertfalse;
  164. return SPVPRI_OVER;
  165. }();
  166. sharedVoice->voice->SetPriority (voicePriority);
  167. sharedVoice->voice->Speak (announcementString.toWideCharPointer(), SPF_ASYNC, nullptr);
  168. }
  169. }
  170. AccessibilityHandler::AccessibilityNativeImpl* AccessibilityHandler::createNativeImpl (AccessibilityHandler& handler)
  171. {
  172. return new AccessibilityHandler::AccessibilityNativeImpl (handler);
  173. }
  174. void AccessibilityHandler::DestroyNativeImpl::operator() (AccessibilityHandler::AccessibilityNativeImpl* impl) const noexcept
  175. {
  176. delete impl;
  177. }
  178. //==============================================================================
  179. namespace WindowsAccessibility
  180. {
  181. void initialiseUIAWrapper()
  182. {
  183. WindowsUIAWrapper::getInstance();
  184. }
  185. long getUiaRootObjectId()
  186. {
  187. return static_cast<long> (UiaRootObjectId);
  188. }
  189. bool handleWmGetObject (AccessibilityHandler* handler, WPARAM wParam, LPARAM lParam, LRESULT* res)
  190. {
  191. if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
  192. return false;
  193. if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
  194. {
  195. ComSmartPtr<IRawElementProviderSimple> provider;
  196. handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
  197. if (! wrapper->isProviderDisconnecting (provider))
  198. *res = wrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
  199. return true;
  200. }
  201. return false;
  202. }
  203. void revokeUIAMapEntriesForWindow (HWND hwnd)
  204. {
  205. if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
  206. wrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
  207. }
  208. }
  209. JUCE_IMPLEMENT_SINGLETON (WindowsUIAWrapper)
  210. } // namespace juce