Merge "[Tizen][AT-SPI] Rework intercepting key events" into tizen
[platform/core/uifw/dali-adaptor.git] / dali / devel-api / adaptor-framework / accessibility-bridge.h
1 #ifndef DALI_ADAPTOR_ACCESSIBILITY_BRIDGE_H
2 #define DALI_ADAPTOR_ACCESSIBILITY_BRIDGE_H
3
4 /*
5  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
6  *
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
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/actor.h>
23 #include <dali/public-api/events/key-event.h>
24 #include <dali/public-api/math/rect.h>
25 #include <functional>
26 #include <memory>
27 #include <stdexcept>
28 #include <string>
29 #include <unordered_set>
30
31 // INTERNAL INCLUDES
32 #include <dali/devel-api/adaptor-framework/accessibility.h>
33 #include <dali/public-api/adaptor-framework/window.h>
34
35 namespace Dali
36 {
37 namespace Accessibility
38 {
39 class Accessible;
40 class ProxyAccessible;
41
42 /**
43  * @brief Base class for different accessibility bridges.
44  *
45  * Bridge is resposible for initializing and managing connection on accessibility bus.
46  * Accessibility clients will not get any information about UI without initialized and upraised bridge.
47  * Concrete implementation depends on the accessibility technology available on the platform.
48  *
49  * @note This class is singleton.
50  */
51 struct DALI_ADAPTOR_API Bridge
52 {
53   enum class ForceUpResult
54   {
55     JUST_STARTED,
56     ALREADY_UP,
57     FAILED
58   };
59
60   /**
61    * @brief Destructor
62    */
63   virtual ~Bridge() = default;
64
65   /**
66    * @brief Gets bus name which bridge is initialized on.
67    *
68    * @return The bus name
69    */
70   virtual const std::string& GetBusName() const = 0;
71
72   /**
73    * @brief Registers top level window.
74    *
75    * Hierarchy of objects visible for accessibility clients is based on tree-like
76    * structure created from Actors objects. This method allows to connect chosen
77    * object as direct ancestor of application and therefore make it visible for
78    * accessibility clients.
79    *
80    * @param[in] object The accessible object
81    */
82   virtual void AddTopLevelWindow(Accessible* object) = 0;
83
84   /**
85    * @brief Removes top level window.
86    *
87    * Hierarchy of objects visible for accessibility clients is based on tree-like
88    * structure created from Actors objects. This method removes previously added
89    * window from visible accessibility objects.
90    *
91    * @param[in] object The accessible object
92    */
93   virtual void RemoveTopLevelWindow(Accessible* object) = 0;
94
95   /**
96    * @brief Adds object on the top of the stack of "default label" sourcing objects.
97    *
98    * @see GetDefaultLabel
99    *
100    * @param[in] object The accessible object
101    */
102   virtual void RegisterDefaultLabel(Accessible* object) = 0;
103
104   /**
105    * @brief Removes object from the stack of "default label" sourcing objects.
106    *
107    * @see GetDefaultLabel
108    *
109    * @param[in] object The accessible object
110    */
111   virtual void UnregisterDefaultLabel(Accessible* object) = 0;
112
113   /**
114    * @brief Gets the top-most object from the stack of "default label" sourcing objects.
115    *
116    * The "default label" is a reading material (text) derived from an accesibility object
117    * that could be read by screen-reader immediately after the navigation context has changed
118    * (window activates, popup shows up, tab changes) and before first UI element is highlighted.
119    *
120    * @param[in] root The root of the navigation context for which to retrieve the default label.
121    *
122    * @return The handler to accessibility object
123    * @note This is a Tizen only feature not present in upstream ATSPI.
124    * Feature can be enabled/disabled for particular context root object
125    * by setting value of its accessibility attribute "default_label".
126    * Following strings are valid values for "default_label" attribute: "enabled", "disabled".
127    * Any other value will be interpreted as "enabled".
128    */
129   virtual Accessible* GetDefaultLabel(Accessible* root) const = 0;
130
131   /**
132    * @brief Sets name of current application which will be visible on accessibility bus.
133    *
134    * @param[in] name The application name
135    */
136   virtual void SetApplicationName(std::string name) = 0;
137
138   /**
139    * @brief Sets the name of the GUI toolkit that AT-SPI clients can query.
140    *
141    * The default name is "dali".
142    *
143    * @param toolkitName The toolkit name
144    */
145   virtual void SetToolkitName(std::string_view toolkitName) = 0;
146
147   /**
148    * @brief Gets object being root of accessibility tree.
149    *
150    * @return handler to accessibility object
151    */
152   virtual Accessible* GetApplication() const = 0;
153
154   /**
155    * @brief Finds an object in accessibility tree.
156    *
157    * @param[in] path The path to object
158    *
159    * @return The handler to accessibility object
160    */
161   virtual Accessible* FindByPath(const std::string& path) const = 0;
162
163   /**
164    * @brief Notifies accessibility dbus that window has just been created.
165    *
166    * @param[in] window The window to be created
167    */
168   virtual void WindowCreated(Window window) = 0;
169
170   /**
171    * @brief Notifies accessibility dbus that window has just been shown.
172    *
173    * @param[in] window The window to be shown
174    */
175   virtual void WindowShown(Window window) = 0;
176
177   /**
178    * @brief Notifies accessibility dbus that window has just been hidden.
179    *
180    * @param[in] window The window to be hidden
181    */
182   virtual void WindowHidden(Window window) = 0;
183
184   /**
185    * @brief Notifies accessibility dbus that window has just been focused.
186    *
187    * @param[in] window The window to be focused
188    */
189   virtual void WindowFocused(Window window) = 0;
190
191   /**
192    * @brief Notifies accessibility dbus that window has just been out of focus.
193    *
194    * @param[in] window The window to be out of focus
195    */
196   virtual void WindowUnfocused(Window window) = 0;
197
198   /**
199    * @brief Notifies accessibility dbus that window has just been minimized.
200    *
201    * @param[in] window The window to be minimized
202    */
203   virtual void WindowMinimized(Window window) = 0;
204
205   /**
206    * @brief Notifies accessibility dbus that window has just been restored.
207    *
208    * @param[in] window The window to be restored
209    * @param[in] detail Restored window state
210    */
211   virtual void WindowRestored(Window window, WindowRestoreType detail) = 0;
212
213   /**
214    * @brief Notifies accessibility dbus that window has just been maximized.
215    *
216    * @param[in] window The window to be maximized
217    */
218   virtual void WindowMaximized(Window window) = 0;
219
220   /**
221    * @brief Initializes accessibility bus.
222    */
223   virtual void Initialize() = 0;
224
225   /**
226    * @brief Terminates accessibility bus.
227    */
228   virtual void Terminate() = 0;
229
230   /**
231    * @brief This method is called, when bridge is being activated.
232    */
233   virtual ForceUpResult ForceUp()
234   {
235     if(mData)
236     {
237       return ForceUpResult::ALREADY_UP;
238     }
239     mData          = std::make_shared<Data>();
240     mData->mBridge = this;
241     return ForceUpResult::JUST_STARTED;
242   }
243
244   /**
245    * @brief This method is called, when bridge is being deactivated.
246    */
247   virtual void ForceDown() = 0;
248
249   /**
250    * @brief Checks if bridge is activated or not.
251    * @return True if brige is activated.
252    */
253   bool IsUp() const
254   {
255     return bool(mData);
256   }
257
258   /**
259    * @brief Emits cursor-moved event on at-spi bus.
260    *
261    * @param[in] obj The accessible object
262    * @param[in] cursorPosition The new cursor position
263    **/
264   virtual void EmitCursorMoved(Accessible* obj, unsigned int cursorPosition) = 0;
265
266   /**
267    * @brief Emits active-descendant-changed event on at-spi bus.
268    *
269    * @param[in] obj The accessible object
270    * @param[in] child The child of the object
271    **/
272   virtual void EmitActiveDescendantChanged(Accessible* obj, Accessible* child) = 0;
273
274   /**
275    * @brief Emits text-changed event on at-spi bus.
276    *
277    * @param[in] obj The accessible object
278    * @param[in] state The changed state for text, such as Inserted or Deleted
279    * @param[in] position The cursor position
280    * @param[in] length The text length
281    * @param[in] content The changed text
282    **/
283   virtual void EmitTextChanged(Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string& content) = 0;
284
285   /**
286    * @brief Emits MoveOuted event on at-spi bus.
287    *
288    * @param[in] obj Accessible object
289    * @param[in] type Direction type when an Accessible object moves out of screen
290    **/
291   virtual void EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType type) = 0;
292
293   /**
294    * @brief Emits "org.a11y.atspi.Socket.Available" event on AT-SPI bus.
295    *
296    * @param obj Accessible object
297    */
298   virtual void EmitSocketAvailable(Accessible* obj) = 0;
299
300   /**
301    * @brief Emits ScrollStarted event on at-spi bus.
302    *
303    * @param obj Accessible Object
304    */
305   virtual void EmitScrollStarted(Accessible *obj) = 0;
306
307     /**
308    * @brief Emits ScrollFinished event on at-spi bus.
309    *
310    * @param obj Accessible Object
311    */
312   virtual void EmitScrollFinished(Accessible *obj) = 0;
313
314   /**
315    * @brief Emits state-changed event on at-spi bus.
316    *
317    * @param[in] obj The accessible object
318    * @param[in] state The accessibility state (SHOWING, HIGHLIGHTED, etc)
319    * @param[in] newValue Whether the state value is changed to new value or not.
320    * @param[in] reserved Reserved. (Currently, this argument is not implemented in dali)
321    **/
322   virtual void EmitStateChanged(Accessible* obj, State state, int newValue, int reserved = 0) = 0;
323
324   /**
325    * @brief Emits window event on at-spi bus.
326    *
327    * @param[in] obj The accessible object
328    * @param[in] event The enumerated window event
329    * @param[in] detail The additional parameter which interpretation depends on chosen event
330    **/
331   virtual void Emit(Accessible* obj, WindowEvent event, unsigned int detail = 0) = 0;
332
333   /**
334    * @brief Emits property-changed event on at-spi bus.
335    *
336    * @param[in] obj The accessible object
337    * @param[in] event Property changed event
338    **/
339   virtual void Emit(Accessible* obj, ObjectPropertyChangeEvent event) = 0;
340
341   /**
342    * @brief Emits bounds-changed event on at-spi bus.
343    *
344    * @param[in] obj The accessible object
345    * @param[in] rect The rectangle for changed bounds
346    **/
347   virtual void EmitBoundsChanged(Accessible* obj, Rect<> rect) = 0;
348
349   /**
350    * @brief Emits org.a11y.atspi.Event.Window.PostRender on the AT-SPI bus.
351    *
352    * @param[in] obj The Accessible sender object
353    *
354    * The sender of this event is expected to be an Accessible object that
355    * represents a top-level window.
356    *
357    * The actual number of events emitted during a given time interval may be smaller
358    * than the number of calls to this method, but at least one is guaranteed.
359    */
360   virtual void EmitPostRender(Accessible *obj) = 0;
361
362   /**
363    * @brief Emits key event on at-spi bus.
364    *
365    * Screen-reader might receive this event and reply, that given keycode is consumed. In that case
366    * further processing of the keycode should be ignored.
367    *
368    * @param[in] keyEvent The key event
369    * @param[in] callback Notification if the event was consumed
370    * @return true if the event was emitted
371    */
372   virtual bool EmitKeyEvent(Dali::KeyEvent keyEvent, std::function<void(Dali::KeyEvent, bool)> callback) = 0;
373
374   /**
375    * @brief Reads given text by screen reader
376    *
377    * @param[in] text The text to read
378    * @param[in] discardable If TRUE, reading can be discarded by subsequent reading requests,
379    * if FALSE the reading must finish before next reading request can be started
380    * @param[in] callback the callback function that is called on reading signals emitted
381    * during processing of this reading request.
382    * Callback can be one of the following signals:
383    * ReadingCancelled, ReadingStopped, ReadingSkipped
384    */
385   virtual void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) = 0;
386
387   /**
388    * @brief Force accessibility client to pause.
389    */
390   virtual void Pause() = 0;
391
392   /**
393    * @brief Force accessibility client to resume.
394    */
395   virtual void Resume() = 0;
396
397   /**
398    * @brief Cancels anything screen-reader is reading / has queued to read
399    *
400    * @param[in] alsoNonDiscardable whether to cancel non-discardable readings as well
401    */
402   virtual void StopReading(bool alsoNonDiscardable) = 0;
403
404   /**
405    * @brief Suppresses reading of screen-reader
406    *
407    * @param[in] suppress whether to suppress reading of screen-reader
408    */
409   virtual void SuppressScreenReader(bool suppress) = 0;
410
411   /**
412    * @brief Gets screen reader status.
413    *
414    * @return True if screen reader is enabled
415    */
416   virtual bool GetScreenReaderEnabled() = 0;
417
418   /**
419    * @brief Gets ATSPI status.
420    *
421    * @return True if ATSPI is enabled
422    */
423   virtual bool IsEnabled() = 0;
424
425   /**
426    * @brief Calls socket.Embed(plug) via D-Bus.
427    *
428    * @param[in] plug The plug
429    * @param[in] socket The socket
430    *
431    * @return Address returned by the D-Bus call.
432    *
433    * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
434    * @see UnembedSocket()
435    */
436   virtual Address EmbedSocket(const Address& plug, const Address& socket) = 0;
437
438   /**
439    * @brief Calls socket.Embedded(plug) via D-Bus.
440    *
441    * The "Embedded" D-Bus method is an ATK extension.
442    * See 'impl_Embedded' in AT_SPI2_ATK/atk-adaptor/adaptors/socket-adaptor.c for more information.
443    *
444    * @param[in] plug The plug
445    * @param[in] socket The socket
446    */
447   virtual void EmbedAtkSocket(const Address& plug, const Address& socket) = 0;
448
449   /**
450    * @brief Calls socket.Unmbed(plug) via D-Bus.
451    *
452    * @param[in] plug The plug
453    * @param[in] socket The socket
454    *
455    * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
456    * @see EmbedSocket()
457    */
458   virtual void UnembedSocket(const Address& plug, const Address& socket) = 0;
459
460   /**
461    * @brief Calls socket.SetOffset(x, y) via D-Bus.
462    *
463    * The "SetOffset" D-Bus method is a DALi extension. It can be used to inform a DALi widget about
464    * its position on the screen.
465    *
466    * @param[in] socket The socket
467    * @param[in] x Horizontal offset
468    * @param[in] y Vertical offset
469    *
470    * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
471    * @see EmbedSocket()
472    * @see SetExtentsOffset()
473    */
474   virtual void SetSocketOffset(ProxyAccessible* socket, std::int32_t x, std::int32_t y) = 0;
475
476   /**
477    * @brief Sets the global extents offset.
478    *
479    * This offset will be added during serialization of GetExtents() return value to D-Bus.
480    * Local calls to GetExtents() are unaffected.
481    *
482    * @param[in] x Horizontal offset
483    * @param[in] y Vertical offset
484    *
485    * @see SetSocketOffset()
486    * @see Dali::Accessibility::Component::GetExtents()
487    */
488   virtual void SetExtentsOffset(std::int32_t x, std::int32_t y) = 0;
489
490   /**
491    * @brief Sets the preferred bus name.
492    *
493    * If the Bridge is enabled, it will immediately release the previous name and request the new one.
494    *
495    * Otherwise, the Bridge will request this name on AT-SPI activation (and release it on deactivation).
496    * It is up to the caller to determine whether a given name will be available in the system.
497    *
498    * @param preferredBusName The preferred bus name
499    */
500   virtual void SetPreferredBusName(std::string_view preferredBusName) = 0;
501
502   /**
503    * @brief Returns instance of bridge singleton object.
504    *
505    * @return The current bridge object
506    **/
507   static std::shared_ptr<Bridge> GetCurrentBridge();
508
509   /**
510    * @brief Blocks auto-initialization of AT-SPI bridge
511    *
512    * Use this only if your application starts before DBus does, and call it early in main()
513    * (before GetCurrentBridge() is called by anyone). GetCurrentBridge() will then return an
514    * instance of DummyBridge.
515    *
516    * When DBus is ready, call EnableAutoInit(). Please note that GetCurrentBridge() may still
517    * return an instance of DummyBridge if AT-SPI was disabled at compile time or using an
518    * environment variable, or if creating the real bridge failed.
519    *
520    * @see Dali::Accessibility::DummyBridge
521    * @see Dali::Accessibility::Bridge::EnableAutoInit
522    */
523   static void DisableAutoInit();
524
525   /**
526    * @brief Re-enables auto-initialization of AT-SPI bridge
527    *
528    * Normal applications do not have to call this function. GetCurrentBridge() tries to
529    * initialize the AT-SPI bridge when it is called for the first time.
530    *
531    * @see Dali::Accessibility::Bridge::DisableAutoInit
532    * @see Dali::Accessibility::Bridge::AddTopLevelWindow
533    * @see Dali::Accessibility::Bridge::SetApplicationName
534    */
535   static void EnableAutoInit();
536
537   /**
538    * @brief Encodes a widget ID as a usable bus name.
539    *
540    * @param widgetInstanceId The instance ID of a widget
541    * @return std::string Encoded bus name
542    *
543    * @see SetPreferredBusName
544    */
545   static std::string MakeBusNameForWidget(std::string_view widgetInstanceId);
546
547   static Signal<void()>& EnabledSignal()
548   {
549     return mEnabledSignal;
550   }
551
552   static Signal<void()>& DisabledSignal()
553   {
554     return mDisabledSignal;
555   }
556
557   static Signal<void()>& ScreenReaderEnabledSignal()
558   {
559     return mScreenReaderEnabledSignal;
560   }
561
562   static Signal<void()>& ScreenReaderDisabledSignal()
563   {
564     return mScreenReaderDisabledSignal;
565   }
566
567 protected:
568   struct Data
569   {
570     std::unordered_set<const Accessible*> mKnownObjects;
571     std::string                           mBusName;
572     Bridge*                               mBridge = nullptr;
573     Actor                                 mHighlightActor;
574     Actor                                 mCurrentlyHighlightedActor;
575     std::pair<std::int32_t, std::int32_t> mExtentsOffset{0, 0};
576   };
577   std::shared_ptr<Data> mData;
578   friend class Accessible;
579
580   enum class AutoInitState
581   {
582     DISABLED,
583     ENABLED
584   };
585
586   inline static AutoInitState mAutoInitState = AutoInitState::ENABLED;
587
588   inline static Signal<void()> mEnabledSignal;
589   inline static Signal<void()> mDisabledSignal;
590   inline static Signal<void()> mScreenReaderEnabledSignal;
591   inline static Signal<void()> mScreenReaderDisabledSignal;
592
593   /**
594    * @brief Registers accessible object to be known in bridge object.
595    *
596    * Bridge must known about all currently alive accessible objects, as some requst
597    * might come and object will be identified by number id (it's memory address).
598    * To avoid memory corruption number id is checked against set of known objects.
599    *
600    * @param[in] object The accessible object
601    **/
602   void RegisterOnBridge(const Accessible* object);
603
604   /**
605    * @brief Tells bridge, that given object is considered root (doesn't have any parents).
606    *
607    * All root objects will have the same parent - application object. Application object
608    * is controlled by bridge and private.
609    *
610    * @param[in] owner The accessible object
611    **/
612   void SetIsOnRootLevel(Accessible* owner);
613 };
614
615 /**
616  * @brief Checks if ATSPI is activated or not.
617  * @return True if ATSPI is activated.
618  */
619 inline bool IsUp()
620 {
621   if(Bridge::GetCurrentBridge() == nullptr)
622   {
623     return false;
624   }
625
626   if(Bridge::GetCurrentBridge()->IsEnabled() == false)
627   {
628     return false;
629   }
630
631   return Bridge::GetCurrentBridge()->IsUp();
632 }
633
634 } // namespace Accessibility
635 } // namespace Dali
636
637 #endif // DALI_ADAPTOR_ACCESSIBILITY_BRIDGE_H