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.

332 lines
10KB

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