Audio plugin host https://kx.studio/carla
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.

juce_AccessibilityHandler.cpp 10.0KB

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