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.

404 lines
12KB

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