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.

347 lines
11KB

  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. AccessibilityHandler* AccessibilityHandler::currentlyFocusedHandler = nullptr;
  21. enum class InternalAccessibilityEvent
  22. {
  23. elementCreated,
  24. elementDestroyed,
  25. focusChanged,
  26. windowOpened,
  27. windowClosed
  28. };
  29. void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent event);
  30. inline String getAccessibleApplicationOrPluginName()
  31. {
  32. #if defined (JucePlugin_Name)
  33. return JucePlugin_Name;
  34. #else
  35. if (auto* app = JUCEApplicationBase::getInstance())
  36. return app->getApplicationName();
  37. return "JUCE Application";
  38. #endif
  39. }
  40. AccessibilityHandler::AccessibilityHandler (Component& comp,
  41. AccessibilityRole accessibilityRole,
  42. AccessibilityActions accessibilityActions,
  43. Interfaces interfacesIn)
  44. : component (comp),
  45. typeIndex (typeid (component)),
  46. role (accessibilityRole),
  47. actions (std::move (accessibilityActions)),
  48. interfaces (std::move (interfacesIn)),
  49. nativeImpl (createNativeImpl (*this))
  50. {
  51. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::elementCreated);
  52. }
  53. AccessibilityHandler::~AccessibilityHandler()
  54. {
  55. giveAwayFocus();
  56. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::elementDestroyed);
  57. }
  58. //==============================================================================
  59. AccessibleState AccessibilityHandler::getCurrentState() const
  60. {
  61. auto state = AccessibleState().withFocusable();
  62. return hasFocus (false) ? state.withFocused() : state;
  63. }
  64. static bool isComponentVisibleWithinWindow (const Component& comp)
  65. {
  66. if (auto* peer = comp.getPeer())
  67. return ! peer->getAreaCoveredBy (comp).getIntersection (peer->getComponent().getLocalBounds()).isEmpty();
  68. return false;
  69. }
  70. static bool isComponentVisibleWithinParent (Component* comp)
  71. {
  72. if (auto* parent = comp->getParentComponent())
  73. {
  74. if (comp->getBoundsInParent().getIntersection (parent->getLocalBounds()).isEmpty())
  75. return false;
  76. return isComponentVisibleWithinParent (parent);
  77. }
  78. return true;
  79. }
  80. bool AccessibilityHandler::isIgnored() const
  81. {
  82. const auto state = getCurrentState();
  83. return role == AccessibilityRole::ignored
  84. || state.isIgnored()
  85. || ! component.isShowing()
  86. || (! state.isAccessibleOffscreen()
  87. && (! isComponentVisibleWithinParent (&component)
  88. || ! isComponentVisibleWithinWindow (component)));
  89. }
  90. //==============================================================================
  91. const AccessibilityActions& AccessibilityHandler::getActions() const noexcept
  92. {
  93. return actions;
  94. }
  95. AccessibilityValueInterface* AccessibilityHandler::getValueInterface() const
  96. {
  97. return interfaces.value.get();
  98. }
  99. AccessibilityTableInterface* AccessibilityHandler::getTableInterface() const
  100. {
  101. return interfaces.table.get();
  102. }
  103. AccessibilityCellInterface* AccessibilityHandler::getCellInterface() const
  104. {
  105. return interfaces.cell.get();
  106. }
  107. AccessibilityTextInterface* AccessibilityHandler::getTextInterface() const
  108. {
  109. return interfaces.text.get();
  110. }
  111. //==============================================================================
  112. static AccessibilityHandler* findEnclosingHandler (Component* comp)
  113. {
  114. if (comp != nullptr)
  115. {
  116. if (auto* handler = comp->getAccessibilityHandler())
  117. return handler;
  118. return findEnclosingHandler (comp->getParentComponent());
  119. }
  120. return nullptr;
  121. }
  122. static AccessibilityHandler* getUnignoredAncestor (AccessibilityHandler* handler)
  123. {
  124. while (handler != nullptr
  125. && handler->isIgnored()
  126. && handler->getParent() != nullptr)
  127. {
  128. handler = handler->getParent();
  129. }
  130. return handler;
  131. }
  132. static AccessibilityHandler* findFirstUnignoredChild (const std::vector<AccessibilityHandler*>& handlers)
  133. {
  134. if (! handlers.empty())
  135. {
  136. const auto iter = std::find_if (handlers.cbegin(), handlers.cend(),
  137. [] (const AccessibilityHandler* handler) { return ! handler->isIgnored(); });
  138. if (iter != handlers.cend())
  139. return *iter;
  140. for (auto* handler : handlers)
  141. if (auto* unignored = findFirstUnignoredChild (handler->getChildren()))
  142. return unignored;
  143. }
  144. return nullptr;
  145. }
  146. static AccessibilityHandler* getFirstUnignoredDescendant (AccessibilityHandler* handler)
  147. {
  148. if (handler != nullptr && handler->isIgnored())
  149. return findFirstUnignoredChild (handler->getChildren());
  150. return handler;
  151. }
  152. AccessibilityHandler* AccessibilityHandler::getParent() const
  153. {
  154. if (auto* focusContainer = component.findFocusContainer())
  155. return getUnignoredAncestor (findEnclosingHandler (focusContainer));
  156. return nullptr;
  157. }
  158. std::vector<AccessibilityHandler*> AccessibilityHandler::getChildren() const
  159. {
  160. if (! component.isFocusContainer() && component.getParentComponent() != nullptr)
  161. return {};
  162. std::vector<AccessibilityHandler*> children;
  163. if (auto traverser = component.createFocusTraverser())
  164. {
  165. for (auto* focusableChild : traverser->getAllComponents (&component))
  166. {
  167. if (auto* handler = findEnclosingHandler (focusableChild))
  168. {
  169. if (! isParentOf (handler))
  170. continue;
  171. if (auto* unignored = getFirstUnignoredDescendant (handler))
  172. if (std::find (children.cbegin(), children.cend(), unignored) == children.cend())
  173. children.push_back (unignored);
  174. }
  175. }
  176. }
  177. return children;
  178. }
  179. bool AccessibilityHandler::isParentOf (const AccessibilityHandler* possibleChild) const noexcept
  180. {
  181. while (possibleChild != nullptr)
  182. {
  183. possibleChild = possibleChild->getParent();
  184. if (possibleChild == this)
  185. return true;
  186. }
  187. return false;
  188. }
  189. AccessibilityHandler* AccessibilityHandler::getChildAt (Point<int> screenPoint)
  190. {
  191. if (auto* comp = Desktop::getInstance().findComponentAt (screenPoint))
  192. if (isParentOf (comp->getAccessibilityHandler()))
  193. return getUnignoredAncestor (findEnclosingHandler (comp));
  194. return nullptr;
  195. }
  196. AccessibilityHandler* AccessibilityHandler::getChildFocus()
  197. {
  198. return hasFocus (true) ? getUnignoredAncestor (currentlyFocusedHandler)
  199. : nullptr;
  200. }
  201. bool AccessibilityHandler::hasFocus (bool trueIfChildFocused) const
  202. {
  203. return currentlyFocusedHandler != nullptr
  204. && (currentlyFocusedHandler == this
  205. || (trueIfChildFocused && isParentOf (currentlyFocusedHandler)));
  206. }
  207. void AccessibilityHandler::grabFocus()
  208. {
  209. if (! hasFocus (false))
  210. grabFocusInternal (true);
  211. }
  212. void AccessibilityHandler::giveAwayFocus() const
  213. {
  214. if (hasFocus (true))
  215. giveAwayFocusInternal();
  216. }
  217. void AccessibilityHandler::grabFocusInternal (bool canTryParent)
  218. {
  219. if (getCurrentState().isFocusable() && ! isIgnored())
  220. {
  221. takeFocus();
  222. return;
  223. }
  224. if (isParentOf (currentlyFocusedHandler) && ! currentlyFocusedHandler->isIgnored())
  225. return;
  226. if (component.isFocusContainer() || component.getParentComponent() == nullptr)
  227. {
  228. if (auto traverser = component.createFocusTraverser())
  229. {
  230. if (auto* defaultComp = traverser->getDefaultComponent (&component))
  231. {
  232. if (auto* handler = getUnignoredAncestor (findEnclosingHandler (defaultComp)))
  233. {
  234. if (isParentOf (handler))
  235. {
  236. handler->grabFocusInternal (false);
  237. return;
  238. }
  239. }
  240. }
  241. }
  242. }
  243. if (canTryParent)
  244. if (auto* parent = getParent())
  245. parent->grabFocusInternal (true);
  246. }
  247. void AccessibilityHandler::giveAwayFocusInternal() const
  248. {
  249. currentlyFocusedHandler = nullptr;
  250. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged);
  251. if (auto* focusedComponent = Component::getCurrentlyFocusedComponent())
  252. if (auto* handler = focusedComponent->getAccessibilityHandler())
  253. handler->grabFocus();
  254. }
  255. void AccessibilityHandler::takeFocus()
  256. {
  257. currentlyFocusedHandler = this;
  258. WeakReference<Component> weakComponent (&component);
  259. actions.invoke (AccessibilityActionType::focus);
  260. if (weakComponent != nullptr
  261. && component.getWantsKeyboardFocus()
  262. && ! component.hasKeyboardFocus (true))
  263. {
  264. component.grabKeyboardFocus();
  265. }
  266. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged);
  267. }
  268. //==============================================================================
  269. #if ! (JUCE_MAC || (JUCE_WINDOWS && ! JUCE_MINGW))
  270. class AccessibilityHandler::AccessibilityNativeImpl { public: AccessibilityNativeImpl (AccessibilityHandler&) {} };
  271. void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent) const {}
  272. void AccessibilityHandler::postAnnouncement (const String&, AnnouncementPriority) {}
  273. AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const { return nullptr; }
  274. AccessibilityHandler::AccessibilityNativeImpl* AccessibilityHandler::createNativeImpl (AccessibilityHandler&) { return nullptr; }
  275. void AccessibilityHandler::DestroyNativeImpl::operator() (AccessibilityHandler::AccessibilityNativeImpl*) const noexcept {}
  276. void notifyAccessibilityEventInternal (const AccessibilityHandler&, InternalAccessibilityEvent) {}
  277. #endif
  278. } // namespace juce