1 #ifndef DALI_INTERNAL_ATSPI_ACCESSIBILITY_IMPL_H
2 #define DALI_INTERNAL_ATSPI_ACCESSIBILITY_IMPL_H
5 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 #include <dali/public-api/actors/actor.h>
23 #include <dali/public-api/math/rect.h>
24 #include <dali/public-api/object/object-registry.h>
32 #include <unordered_map>
33 #include <unordered_set>
37 #include <dali/devel-api/adaptor-framework/accessibility.h>
38 #include <dali/integration-api/debug.h>
42 namespace Accessibility
44 class DALI_ADAPTOR_API Accessible;
45 class DALI_ADAPTOR_API Text;
46 class DALI_ADAPTOR_API Value;
47 class DALI_ADAPTOR_API Component;
48 class DALI_ADAPTOR_API Collection;
49 class DALI_ADAPTOR_API Action;
52 * @brief Base class for different accessibility bridges
54 * Bridge is resposible for initializing and managing connection on accessibility bus.
55 * Accessibility clients will not get any information about UI without initialized and upraised bridge.
56 * Concrete implementation depends on the accessibility technology available on the platform.
58 * @note This class is singleton.
60 struct DALI_ADAPTOR_API Bridge
62 enum class ForceUpResult
71 virtual ~Bridge() = default;
74 * @brief Get bus name which bridge is initialized on
76 virtual const std::string& GetBusName() const = 0;
79 * @brief Registers top level window
81 * Hierarchy of objects visible for accessibility clients is based on tree-like
82 * structure created from Actors objects. This method allows to connect chosen
83 * object as direct ancestor of application and therefore make it visible for
84 * accessibility clients.
86 virtual void AddTopLevelWindow(Accessible*) = 0;
89 * @brief Removes top level window
91 * Hierarchy of objects visible for accessibility clients is based on tree-like
92 * structure created from Actors objects. This method removes previously added
93 * window from visible accessibility objects.
95 virtual void RemoveTopLevelWindow(Accessible*) = 0;
98 * @brief Adds popup window
100 * Hierarchy of objects visible for accessibility clients is based on tree-like
101 * structure created from Actors objects. This method adds new popup to the tree.
103 virtual void AddPopup(Accessible*) = 0;
106 * @brief Removes popup window
108 * Hierarchy of objects visible for accessibility clients is based on tree-like
109 * structure created from Actors objects. This method removes previously added
112 virtual void RemovePopup(Accessible*) = 0;
115 * @brief Set name of current application which will be visible on accessibility bus
117 virtual void SetApplicationName(std::string) = 0;
120 * @brief Get object being root of accessibility tree
122 * @return handler to accessibility object
124 virtual Accessible* GetApplication() const = 0;
127 * @brief Find an object in accessibility tree
129 * @param[in] s path to object
131 * @return handler to accessibility object
133 virtual Accessible* FindByPath(const std::string& s) const = 0;
136 * @brief Show application on accessibility bus
138 virtual void ApplicationShown() = 0;
141 * @brief Hide application on accessibility bus
143 virtual void ApplicationHidden() = 0;
146 * @brief Initialize accessibility bus
148 virtual void Initialize() = 0;
151 * @brief Terminate accessibility bus
153 virtual void Terminate() = 0;
156 * @brief This method is called, when bridge is being activated.
158 virtual ForceUpResult ForceUp()
162 return ForceUpResult::ALREADY_UP;
164 data = std::make_shared<Data>();
166 return ForceUpResult::JUST_STARTED;
170 * @brief This method is called, when bridge is being deactivated.
172 virtual void ForceDown() = 0;
175 * @brief Check if bridge is activated or not.
176 * @return True if brige is activated.
184 * @brief Emits caret-moved event on at-spi bus.
186 virtual void EmitCaretMoved(Accessible* obj, unsigned int cursorPosition) = 0;
189 * @brief Emits active-descendant-changed event on at-spi bus.
191 virtual void EmitActiveDescendantChanged(Accessible* obj, Accessible* child) = 0;
194 * @brief Emits text-changed event on at-spi bus.
196 virtual void EmitTextChanged(Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string& content) = 0;
199 * @brief Emits state-changed event on at-spi bus.
201 virtual void EmitStateChanged(Accessible* obj, State state, int val1, int val2 = 0) = 0;
204 * @brief Emits window event on at-spi bus.
206 virtual void Emit(Accessible* obj, WindowEvent we, unsigned int detail1 = 0) = 0;
209 * @brief Emits property-changed event on at-spi bus.
211 virtual void Emit(Accessible* obj, ObjectPropertyChangeEvent event) = 0;
214 * @brief Emits bounds-changed event on at-spi bus.
216 virtual void EmitBoundsChanged(Accessible* obj, Rect<> rect) = 0;
219 * @brief Emits key event on at-spi bus.
221 * Screen-reader might receive this event and reply, that given keycode is consumed. In that case
222 * further processing of the keycode should be ignored.
224 virtual Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) = 0;
227 * @brief Reads given text by screen reader
229 * @param text The text to read
230 * @param discardable If TRUE, reading can be discarded by subsequent reading requests,
231 * if FALSE the reading must finish before next reading request can be started
232 * @param callback the callback function that is called on reading signals emitted
233 * during processing of this reading request.
234 * Callback can be one of the following signals:
235 * ReadingCancelled, ReadingStopped, ReadingSkipped
237 virtual void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) = 0;
240 * @brief Force accessibility client to pause.
242 virtual void Pause() = 0;
245 * @brief Force accessibility client to resume.
247 virtual void Resume() = 0;
250 * @brief Cancels anything screen-reader is reading / has queued to read
252 * @param alsoNonDiscardable whether to cancel non-discardable readings as well
254 virtual void StopReading(bool alsoNonDiscardable) = 0;
257 * @brief Suppresses reading of screen-reader
259 * @param suppress whether to suppress reading of screen-reader
261 virtual void SuppressScreenReader(bool suppress) = 0;
264 * @brief Get screen reader status.
266 virtual bool GetScreenReaderEnabled() = 0;
269 * @brief Get ATSPI status.
271 virtual bool GetIsEnabled() = 0;
274 * @brief Returns instance of bridge singleton object.
276 static Bridge* GetCurrentBridge();
279 * @brief Blocks auto-initialization of AT-SPI bridge
281 * Use this only if your application starts before DBus does, and call it early in main()
282 * (before GetCurrentBridge() is called by anyone). GetCurrentBridge() will then return an
283 * instance of DummyBridge.
285 * When DBus is ready, call EnableAutoInit(). Please note that GetCurrentBridge() may still
286 * return an instance of DummyBridge if AT-SPI was disabled at compile time or using an
287 * environment variable, or if creating the real bridge failed.
289 * @see Dali::Accessibility::DummyBridge
290 * @see Dali::Accessibility::Bridge::EnableAutoInit
292 static void DisableAutoInit();
295 * @brief Re-enables auto-initialization of AT-SPI bridge
297 * @param topLevelWindow Accessible object for Scene::GetRootLayer()
298 * @param applicationName Application name
300 * Normal applications do not have to call this function. GetCurrentBridge() tries to
301 * initialize the AT-SPI bridge when it is called for the first time.
303 * @see Dali::Accessibility::Bridge::DisableAutoInit
304 * @see Dali::Accessibility::Bridge::AddTopLevelWindow
305 * @see Dali::Accessibility::Bridge::SetApplicationName
307 static void EnableAutoInit(Accessible* topLevelWindow, const std::string& applicationName);
312 std::unordered_set<Accessible*> knownObjects;
314 Bridge* bridge = nullptr;
315 Actor highlightActor, currentlyHighlightedActor;
317 std::shared_ptr<Data> data;
318 friend class Accessible;
320 enum class AutoInitState
325 inline static AutoInitState autoInitState = AutoInitState::ENABLED;
328 * @brief Registers accessible object to be known in bridge object
330 * Bridge must known about all currently alive accessible objects, as some requst
331 * might come and object will be identified by number id (it's memory address).
332 * To avoid memory corruption number id is checked against set of known objects.
334 void RegisterOnBridge(Accessible*);
337 * @brief Tells bridge, that given object is considered root (doesn't have any parents).
339 * All root objects will have the same parent - application object. Application object
340 * is controlled by bridge and private.
342 void SetIsOnRootLevel(Accessible*);
346 * @brief Check if ATSPI is activated or not.
347 * @return True if ATSPI is activated.
351 if(Bridge::GetCurrentBridge() == nullptr)
355 if(Bridge::GetCurrentBridge()->GetIsEnabled() == false)
359 return Bridge::GetCurrentBridge()->IsUp();
363 * @brief Basic interface implemented by all accessibility objects
368 virtual ~Accessible();
370 using utf8_t = unsigned char;
373 * @brief Calculaties word boundaries in given utf8 text.
375 * s and length represents source text pointer and it's length respectively. langauge represents
376 * language to use. Word boundaries are returned as non-zero values in table breaks, which
377 * must be of size at least length.
379 void FindWordSeparationsUtf8(const utf8_t* s, size_t length, const char* language, char* breaks);
382 * @brief Calculaties line boundaries in given utf8 text.
384 * s and length represents source text pointer and it's length respectively. langauge represents
385 * language to use. Line boundaries are returned as non-zero values in table breaks, which
386 * must be of size at least length.
388 void FindLineSeparationsUtf8(const utf8_t* s, size_t length, const char* language, char* breaks);
391 * @brief Helper function for emiting active-descendant-changed event
393 void EmitActiveDescendantChanged(Accessible* obj, Accessible* child);
396 * @brief Helper function for emiting state-changed event
398 void EmitStateChanged(State state, int newValue1, int newValue2 = 0);
401 * @brief Helper function for emiting bounds-changed event
403 void EmitBoundsChanged(Rect<> rect);
406 * @brief Emit "showing" event.
407 * The method inform accessibility clients about "showing" state
409 * @param[in] showing flag pointing if object is showing
411 void EmitShowing(bool showing);
414 * @brief Emit "visible" event.
415 * The method inform accessibility clients about "visible" state
417 * @param[in] visible flag pointing if object is visible
419 void EmitVisible(bool visible);
422 * @brief Emit "highlighted" event.
423 * The method inform accessibility clients about "highlighted" state
425 * @param[in] set flag pointing if object is highlighted
427 void EmitHighlighted(bool set);
430 * @brief Emit "focused" event.
431 * The method inform accessibility clients about "focused" state
433 * @param[in] set flag pointing if object is focused
435 void EmitFocused(bool set);
438 * @brief Emit "text inserted" event
440 * @param[in] position caret position
441 * @param[in] length text length
442 * @param[in] content inserted text
444 void EmitTextInserted(unsigned int position, unsigned int length, const std::string& content);
447 * @brief Emit "text deleted" event
449 * @param[in] position caret position
450 * @param[in] length text length
451 * @param[in] content deleted text
453 void EmitTextDeleted(unsigned int position, unsigned int length, const std::string& content);
456 * @brief Emit "caret moved" event
458 * @param[in] cursorPosition new caret position
460 void EmitTextCaretMoved(unsigned int cursorPosition);
463 * @brief Emit "highlighted" event
465 * @param[in] we enumerated window event
466 * @param[in] detail1 additional parameter which interpretation depends on chosen event
468 void Emit(WindowEvent we, unsigned int detail1 = 0);
471 * @brief Emits property-changed event
472 * @param[in] event Property changed event
474 void Emit(ObjectPropertyChangeEvent event);
477 * @brief Get accessibility name
479 * @return string with name
481 virtual std::string GetName() = 0;
484 * @brief Get accessibility description
486 * @return string with description
488 virtual std::string GetDescription() = 0;
493 * @return handler to accessibility object
495 virtual Accessible* GetParent() = 0;
498 * @brief Get count of children
500 * @return unsigned integer value
502 virtual size_t GetChildCount() = 0;
505 * @brief Get collection with all children
507 * @return collection of accessibility objects
509 virtual std::vector<Accessible*> GetChildren();
512 * @brief Get nth child
514 * @return accessibility object
516 virtual Accessible* GetChildAtIndex(size_t index) = 0;
519 * @brief Get index that current object has in its parent's children collection
521 * @return unsigned integer index
523 virtual size_t GetIndexInParent() = 0;
526 * @brief Get accessibility role
528 * @return Role enumeration
530 * @see Dali::Accessibility::Role
532 virtual Role GetRole() = 0;
535 * @brief Get name of accessibility role
537 * @return string with human readable role converted from enumeration
539 * @see Dali::Accessibility::Role
540 * @see Accessibility::Accessible::GetRole
542 virtual std::string GetRoleName();
545 * @brief Get localized name of accessibility role
547 * @return string with human readable role translated according to current
550 * @see Dali::Accessibility::Role
551 * @see Accessibility::Accessible::GetRole
552 * @see Accessibility::Accessible::GetRoleName
554 * @note translation is not supported in this version
556 virtual std::string GetLocalizedRoleName();
559 * @brief Get accessibility states
561 * @return collection of states
563 * @note States class is instatation of ArrayBitset template class
565 * @see Dali::Accessibility::State
566 * @see Dali::Accessibility::ArrayBitset
568 virtual States GetStates() = 0;
571 * @brief Get accessibility attributes
573 * @return map of attributes and their values
575 virtual Attributes GetAttributes() = 0;
578 * @brief Check if this is proxy
580 * @return True if this is proxy
582 virtual bool IsProxy();
585 * @brief Get unique address on accessibility bus
587 * @return class containing address
589 * @see Dali::Accessibility::Address
591 virtual Address GetAddress();
594 * @brief Get accessibility object, which is "default label" for this object
596 virtual Accessible* GetDefaultLabel();
599 * @brief Depute an object to perform provided gesture
601 * @param[in] gestureInfo structure describing the gesture
603 * @return true on success, false otherwise
605 * @see Dali::Accessibility::GestureInfo
607 virtual bool DoGesture(const GestureInfo& gestureInfo) = 0;
610 * @brief Re-emits selected states of an Accessibility Object
612 * @param[in] states chosen states to re-emit
613 * @param[in] doRecursive if true all children of the Accessibility Object will also re-emit the states
615 void NotifyAccessibilityStateChange(Dali::Accessibility::States states, bool doRecursive);
618 * @brief Get information about current object and all relations that connects
619 * it with other accessibility objects
621 * @return iterable collection of Relation objects
623 * @see Dali::Accessibility::Relation
625 virtual std::vector<Relation> GetRelationSet() = 0;
628 * @brief Get all implemented interfaces
630 * @return collection of strings with implemented interfaces
632 std::vector<std::string> GetInterfaces();
635 * @brief Check if object is on root level
637 bool GetIsOnRootLevel() const
639 return isOnRootLevel;
643 * @brief The method registers functor resposible for converting Actor into Accessible
644 * @param functor returning Accessible handle from Actor object
646 static void RegisterControlAccessibilityGetter(std::function<Accessible*(Dali::Actor)> functor);
649 * @brief Acquire Accessible object from Actor object
651 * @param[in] actor Actor object
652 * @param[in] root true, if it's top level object (window)
654 * @return handle to Accessible object
656 static Accessible* Get(Dali::Actor actor, bool root = false);
660 Accessible(const Accessible&) = delete;
661 Accessible(Accessible&&) = delete;
662 Accessible& operator=(const Accessible&) = delete;
663 Accessible& operator=(Accessible&&) = delete;
664 std::shared_ptr<Bridge::Data> GetBridgeData();
667 static Dali::Actor GetHighlightActor();
668 static void SetHighlightActor(Dali::Actor actor);
669 static Dali::Actor GetCurrentlyHighlightedActor();
670 static void SetCurrentlyHighlightedActor(Dali::Actor);
671 static void SetObjectRegistry(ObjectRegistry registry);
676 std::weak_ptr<Bridge::Data> bridgeData;
677 bool isOnRootLevel = false;
681 * @brief Interface enabling to perform provided actions
683 class Action : public virtual Accessible
687 * @brief Get name of action with given index
689 * @param[in] index index of action
691 * @return string with name of action
693 virtual std::string GetActionName(size_t index) = 0;
696 * @brief Get translated name of action with given index
698 * @param[in] index index of action
700 * @return string with name of action translated according to current translation domain
702 * @note translation is not supported in this version
704 virtual std::string GetLocalizedActionName(size_t index) = 0;
707 * @brief Get description of action with given index
709 * @param[in] index index of action
711 * @return string with description of action
713 virtual std::string GetActionDescription(size_t index) = 0;
716 * @brief Get key code binded to action with given index
718 * @param[in] index index of action
720 * @return string with key name
722 virtual std::string GetActionKeyBinding(size_t index) = 0;
725 * @brief Get number of provided actions
727 * @return unsigned integer with number of actions
729 virtual size_t GetActionCount() = 0;
732 * @brief Perform an action with given index
734 * @param index index of action
736 * @return true on success, false otherwise
738 virtual bool DoAction(size_t index) = 0;
741 * @brief Perform an action with given name
743 * @param name name of action
745 * @return true on success, false otherwise
747 virtual bool DoAction(const std::string& name) = 0;
751 * @brief Interface enabling advanced quering of accessibility objects
753 * @note since all mathods can be implemented inside bridge,
754 * none methods have to be overrided
756 class Collection : public virtual Accessible
762 * @brief Interface representing objects having screen coordinates
764 class Component : public virtual Accessible
768 * @brief Get rectangle describing size
770 * @param[in] ctype enumeration with type of coordinate systems
772 * @return Rect<> object
776 virtual Rect<> GetExtents(CoordType ctype) = 0;
779 * @brief Get layer current object is localized on
781 * @return enumeration pointing layer
783 * @see Dali::Accessibility::ComponentLayer
785 virtual ComponentLayer GetLayer() = 0;
788 * @brief Get value of z-order
790 * @return value of z-order
792 virtual int16_t GetMdiZOrder() = 0;
795 * @brief Set current object as "focused"
797 * @return true on success, false otherwise
799 virtual bool GrabFocus() = 0;
802 * @brief Get value of alpha channel
804 * @return alpha channel value in range [0.0, 1.0]
806 virtual double GetAlpha() = 0;
809 * @brief Set current object as "highlighted"
811 * The method assings "highlighted" state, simultaneously removing it
812 * from currently highlighted object.
814 * @return true on success, false otherwise
816 virtual bool GrabHighlight() = 0;
819 * @brief Set current object as "unhighlighted"
821 * The method removes "highlighted" state from object.
823 * @return true on success, false otherwise
825 * @see Dali:Accessibility::State
827 virtual bool ClearHighlight() = 0;
830 * @brief Check whether object can be scrolled
832 * @return true if object is scrollable, false otherwise
834 * @see Dali:Accessibility::State
836 virtual bool IsScrollable();
839 * @brief Get Accessible object containing given point
841 * @param[in] p two-dimensional point
842 * @param[in] ctype enumeration with type of coordinate system
844 * @return handle to last child of current object which contains given point
846 * @see Dali::Accessibility::Point
848 virtual Accessible* GetAccessibleAtPoint(Point p, CoordType ctype);
851 * @brief Check if current object contains given point
853 * @param[in] p two-dimensional point
854 * @param[in] ctype enumeration with type of coordinate system
856 * @return handle to Accessible object
858 * @see Dali::Accessibility::Point
860 virtual bool Contains(Point p, CoordType ctype);
864 * @brief Interface representing objects which can store numeric value
866 class Value : public virtual Accessible
870 * @brief Get the lowest possible value
872 * @return double value
874 virtual double GetMinimum() = 0;
877 * @brief Get current value
879 * @return double value
881 virtual double GetCurrent() = 0;
884 * @brief Get the highest possible value
886 * @return double value
888 virtual double GetMaximum() = 0;
893 * @param[in] val double value
895 * @return true if value could have been assigned, false otherwise
897 virtual bool SetCurrent(double val) = 0;
900 * @brief Get the lowest increment that can be distinguished
902 * @return double value
904 virtual double GetMinimumIncrement() = 0;
908 * @brief Interface representing objects which can store immutable texts
910 * @see Dali::Accessibility::EditableText
912 class DALI_ADAPTOR_API Text : public virtual Accessible
916 * @brief Get stored text in given range
918 * @param[in] startOffset index of first character
919 * @param[in] endOffset index of first character after the last one expected
921 * @return substring of stored text
923 virtual std::string GetText(size_t startOffset, size_t endOffset) = 0;
926 * @brief Get number of all stored characters
928 * @return number of characters
930 virtual size_t GetCharacterCount() = 0;
933 * @brief Get caret offset
935 * @return Value of caret offset
937 virtual size_t GetCaretOffset() = 0;
940 * @brief Set caret offset
942 * @param[in] offset Caret offset
944 * @return True if successful
946 virtual bool SetCaretOffset(size_t offset) = 0;
949 * @brief Get substring of stored text truncated in concrete gradation
951 * @param[in] offset position in stored text
952 * @param[in] boundary enumeration describing text gradation
954 * @return Range structure containing acquired text and offsets in original string
956 * @see Dali::Accessibility::Range
958 virtual Range GetTextAtOffset(size_t offset, TextBoundary boundary) = 0;
961 * @brief Get selected text
963 * @param[in] selectionNum selection index
964 * @note Currently only one selection (i.e. with index = 0) is supported
966 * @return Range structure containing acquired text and offsets in original string
968 * @see Dali::Accessibility::Range
970 virtual Range GetSelection(size_t selectionNum) = 0;
973 * @brief Remove selection
975 * @param[in] selectionNum selection index
976 * @note Currently only one selection (i.e. with index = 0) is supported
978 * @return bool on success, false otherwise
980 virtual bool RemoveSelection(size_t selectionNum) = 0;
983 * @brief Get selected text
985 * @param[in] selectionNum selection index
986 * @param[in] startOffset index of first character
987 * @param[in] endOffset index of first character after the last one expected
989 * @note Currently only one selection (i.e. with index = 0) is supported
991 * @return true on success, false otherwise
993 virtual bool SetSelection(size_t selectionNum, size_t startOffset, size_t endOffset) = 0;
997 * @brief Interface representing objects which can store editable texts
999 * @note Paste method is entirely implemented inside bridge
1001 * @see Dali::Accessibility::EditableText
1003 class DALI_ADAPTOR_API EditableText : public virtual Accessible
1007 * @brief Copy text in range to system clipboard
1009 * @param[in] startPosition index of first character
1010 * @param[in] endPosition index of first character after the last one expected
1012 * @return true on success, false otherwise
1014 virtual bool CopyText(size_t startPosition, size_t endPosition) = 0;
1017 * @brief Cut text in range to system clipboard
1019 * @param[in] startPosition index of first character
1020 * @param[in] endPosition index of first character after the last one expected
1022 * @return true on success, false otherwise
1024 virtual bool CutText(size_t startPosition, size_t endPosition) = 0;
1028 * @brief minimalistic, always empty Accessible object with settable address
1030 * For those situations, where you want to return address in different bridge
1031 * (embedding for example), but the object itself ain't planned to be used otherwise.
1032 * This object has null parent, no children, empty name and so on
1034 class DALI_ADAPTOR_API EmptyAccessibleWithAddress : public virtual Accessible
1037 EmptyAccessibleWithAddress() = default;
1038 EmptyAccessibleWithAddress(Address address)
1039 : address(std::move(address))
1043 void SetAddress(Address address)
1045 this->address = std::move(address);
1048 std::string GetName() override
1052 std::string GetDescription() override
1056 Accessible* GetParent() override
1060 size_t GetChildCount() override
1064 std::vector<Accessible*> GetChildren() override
1068 Accessible* GetChildAtIndex(size_t index) override
1070 throw std::domain_error{"out of bounds index (" + std::to_string(index) + ") - no children"};
1072 size_t GetIndexInParent() override
1074 return static_cast<size_t>(-1);
1076 Role GetRole() override
1080 std::string GetRoleName() override;
1081 States GetStates() override
1085 Attributes GetAttributes() override
1089 Address GetAddress() override
1093 bool DoGesture(const GestureInfo& gestureInfo) override
1097 std::vector<Relation> GetRelationSet() override
1106 } // namespace Accessibility
1109 #endif // DALI_INTERNAL_ATSPI_ACCESSIBILITY_IMPL_H