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.

341 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. bool AccessibilityHandler::isIgnored() const
  65. {
  66. return role == AccessibilityRole::ignored
  67. || getCurrentState().isIgnored()
  68. || component.isCurrentlyBlockedByAnotherModalComponent();
  69. }
  70. static bool isComponentVisibleWithinWindow (const Component& comp)
  71. {
  72. if (auto* peer = comp.getPeer())
  73. return ! peer->getAreaCoveredBy (comp).getIntersection (peer->getComponent().getLocalBounds()).isEmpty();
  74. return false;
  75. }
  76. static bool isComponentVisibleWithinParent (Component* comp)
  77. {
  78. if (auto* parent = comp->getParentComponent())
  79. {
  80. if (comp->getBoundsInParent().getIntersection (parent->getLocalBounds()).isEmpty())
  81. return false;
  82. return isComponentVisibleWithinParent (parent);
  83. }
  84. return true;
  85. }
  86. bool AccessibilityHandler::isVisibleWithinParent() const
  87. {
  88. return getCurrentState().isAccessibleOffscreen()
  89. || (isComponentVisibleWithinParent (&component) && isComponentVisibleWithinWindow (component));
  90. }
  91. //==============================================================================
  92. const AccessibilityActions& AccessibilityHandler::getActions() const noexcept
  93. {
  94. return actions;
  95. }
  96. AccessibilityValueInterface* AccessibilityHandler::getValueInterface() const
  97. {
  98. return interfaces.value.get();
  99. }
  100. AccessibilityTableInterface* AccessibilityHandler::getTableInterface() const
  101. {
  102. return interfaces.table.get();
  103. }
  104. AccessibilityCellInterface* AccessibilityHandler::getCellInterface() const
  105. {
  106. return interfaces.cell.get();
  107. }
  108. AccessibilityTextInterface* AccessibilityHandler::getTextInterface() const
  109. {
  110. return interfaces.text.get();
  111. }
  112. //==============================================================================
  113. static AccessibilityHandler* findEnclosingHandler (Component* comp)
  114. {
  115. if (comp != nullptr)
  116. {
  117. if (auto* handler = comp->getAccessibilityHandler())
  118. return handler;
  119. return findEnclosingHandler (comp->getParentComponent());
  120. }
  121. return nullptr;
  122. }
  123. static AccessibilityHandler* getUnignoredAncestor (AccessibilityHandler* handler)
  124. {
  125. while (handler != nullptr
  126. && (handler->isIgnored() || ! handler->isVisibleWithinParent())
  127. && handler->getParent() != nullptr)
  128. {
  129. handler = handler->getParent();
  130. }
  131. return handler;
  132. }
  133. static AccessibilityHandler* findFirstUnignoredChild (const std::vector<AccessibilityHandler*>& handlers)
  134. {
  135. if (! handlers.empty())
  136. {
  137. const auto iter = std::find_if (handlers.cbegin(), handlers.cend(),
  138. [] (const AccessibilityHandler* handler) { return ! handler->isIgnored() && handler->isVisibleWithinParent(); });
  139. if (iter != handlers.cend())
  140. return *iter;
  141. for (auto* handler : handlers)
  142. if (auto* unignored = findFirstUnignoredChild (handler->getChildren()))
  143. return unignored;
  144. }
  145. return nullptr;
  146. }
  147. static AccessibilityHandler* getFirstUnignoredDescendant (AccessibilityHandler* handler)
  148. {
  149. if (handler != nullptr && (handler->isIgnored() || ! handler->isVisibleWithinParent()))
  150. return findFirstUnignoredChild (handler->getChildren());
  151. return handler;
  152. }
  153. AccessibilityHandler* AccessibilityHandler::getParent() const
  154. {
  155. if (auto* focusContainer = component.findFocusContainer())
  156. return getUnignoredAncestor (findEnclosingHandler (focusContainer));
  157. return nullptr;
  158. }
  159. std::vector<AccessibilityHandler*> AccessibilityHandler::getChildren() const
  160. {
  161. if (! component.isFocusContainer() && component.getParentComponent() != nullptr)
  162. return {};
  163. std::vector<AccessibilityHandler*> children;
  164. if (auto traverser = component.createFocusTraverser())
  165. {
  166. for (auto* focusableChild : traverser->getAllComponents (&component))
  167. {
  168. if (auto* handler = findEnclosingHandler (focusableChild))
  169. {
  170. if (! isParentOf (handler))
  171. continue;
  172. if (auto* unignored = getFirstUnignoredDescendant (handler))
  173. if (std::find (children.cbegin(), children.cend(), unignored) == children.cend())
  174. children.push_back (unignored);
  175. }
  176. }
  177. }
  178. return children;
  179. }
  180. bool AccessibilityHandler::isParentOf (const AccessibilityHandler* possibleChild) const noexcept
  181. {
  182. while (possibleChild != nullptr)
  183. {
  184. possibleChild = possibleChild->getParent();
  185. if (possibleChild == this)
  186. return true;
  187. }
  188. return false;
  189. }
  190. AccessibilityHandler* AccessibilityHandler::getChildAt (Point<int> screenPoint)
  191. {
  192. if (auto* comp = Desktop::getInstance().findComponentAt (screenPoint))
  193. if (isParentOf (comp->getAccessibilityHandler()))
  194. return getUnignoredAncestor (findEnclosingHandler (comp));
  195. return nullptr;
  196. }
  197. AccessibilityHandler* AccessibilityHandler::getChildFocus()
  198. {
  199. return hasFocus (true) ? getUnignoredAncestor (currentlyFocusedHandler)
  200. : nullptr;
  201. }
  202. bool AccessibilityHandler::hasFocus (bool trueIfChildFocused) const
  203. {
  204. return currentlyFocusedHandler != nullptr
  205. && (currentlyFocusedHandler == this
  206. || (trueIfChildFocused && isParentOf (currentlyFocusedHandler)));
  207. }
  208. void AccessibilityHandler::grabFocus()
  209. {
  210. if (! hasFocus (false))
  211. grabFocusInternal (true);
  212. }
  213. void AccessibilityHandler::giveAwayFocus() const
  214. {
  215. if (hasFocus (true))
  216. giveAwayFocusInternal();
  217. }
  218. void AccessibilityHandler::grabFocusInternal (bool canTryParent)
  219. {
  220. if (getCurrentState().isFocusable() && ! isIgnored())
  221. {
  222. takeFocus();
  223. return;
  224. }
  225. if (isParentOf (currentlyFocusedHandler) && ! currentlyFocusedHandler->isIgnored())
  226. return;
  227. if (component.isFocusContainer() || component.getParentComponent() == nullptr)
  228. {
  229. if (auto traverser = component.createFocusTraverser())
  230. {
  231. if (auto* defaultComp = traverser->getDefaultComponent (&component))
  232. {
  233. if (auto* handler = getUnignoredAncestor (findEnclosingHandler (defaultComp)))
  234. {
  235. if (isParentOf (handler))
  236. {
  237. handler->grabFocusInternal (false);
  238. return;
  239. }
  240. }
  241. }
  242. }
  243. }
  244. if (canTryParent)
  245. if (auto* parent = getParent())
  246. parent->grabFocusInternal (true);
  247. }
  248. void AccessibilityHandler::giveAwayFocusInternal() const
  249. {
  250. currentlyFocusedHandler = nullptr;
  251. if (auto* parent = getParent())
  252. notifyAccessibilityEventInternal (*parent, InternalAccessibilityEvent::focusChanged);
  253. }
  254. void AccessibilityHandler::takeFocus()
  255. {
  256. currentlyFocusedHandler = this;
  257. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged);
  258. if (component.getWantsKeyboardFocus() && ! component.hasKeyboardFocus (true))
  259. component.grabKeyboardFocus();
  260. }
  261. //==============================================================================
  262. #if ! ((JUCE_MAC && (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)) \
  263. || (JUCE_WINDOWS && ! JUCE_MINGW))
  264. class AccessibilityHandler::AccessibilityNativeImpl { public: AccessibilityNativeImpl (AccessibilityHandler&) {} };
  265. void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent) const {}
  266. void AccessibilityHandler::postAnnouncement (const String&, AnnouncementPriority) {}
  267. AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const { return nullptr; }
  268. AccessibilityHandler::AccessibilityNativeImpl* AccessibilityHandler::createNativeImpl (AccessibilityHandler&) { return nullptr; }
  269. void AccessibilityHandler::DestroyNativeImpl::operator() (AccessibilityHandler::AccessibilityNativeImpl*) const noexcept {}
  270. void notifyAccessibilityEventInternal (const AccessibilityHandler&, InternalAccessibilityEvent) {}
  271. #endif
  272. } // namespace juce