Customizable forwarding of gestures directly to app. 31/207431/1 accepted/tizen/unified/20190613.061507 submit/tizen/20190612.074127 submit/tizen/20190612.075202
authorOskar Chodowicz <o.chodowicz@samsung.com>
Mon, 19 Nov 2018 17:35:42 +0000 (18:35 +0100)
committerOskar Chodowicz <o.chodowicz@samsung.com>
Tue, 4 Jun 2019 13:31:37 +0000 (15:31 +0200)
This commit provides mechanism that allows app developer to request
delivery of particular gestures directly to application and by-passing
screen-reader.
The list of gesture is sent from application to screen-reader as ATSPI
attribute.
Then screen-reader forwards this list (using DBus interface,
AppGestureSupport) to e-mod which decides how to route detected
gestures.

Change-Id: I49e87a5c78ed39ac917deeade8b2f954c5bb6b9d

src/e_mod_main.c
src/e_screen_reader_gestures.c
src/e_screen_reader_private.h

index dcfb5d0..bb0a9d3 100644 (file)
@@ -24,7 +24,6 @@ static Eina_List *handlers;
 Eldbus_Connection *conn = NULL;
 Eldbus_Service_Interface *iface = NULL;
 Eina_Bool is_slider;
-Eina_Bool is_screen_reader_support;
 int highlighted_object_x, highlighted_object_y;
 Eina_Bool is_selection_mode;
 int object_needs_scroll_from_x, object_needs_scroll_from_y;
@@ -41,7 +40,7 @@ static Eldbus_Message *_accessories_switch_provider_enabled(const Eldbus_Service
 static Eldbus_Message *_back_button_interception_enabled(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
 static Eldbus_Message *_is_slider(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
 static Eldbus_Message *_highlighted_object_info(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
-static Eldbus_Message *_is_screen_reader_support(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
+static Eldbus_Message *_is_app_gesture_support(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
 static Eldbus_Message *_is_selection_mode(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
 static Eldbus_Message *_object_needs_scroll_gesture(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
 static Eldbus_Message *_dispatch_drag_event(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
@@ -69,8 +68,8 @@ static const Eldbus_Method methods[] = {
       { "HighlightedObjectInfo", ELDBUS_ARGS({"i", "int"}, {"i", "int"}), NULL,
         _highlighted_object_info
       },
-      { "IsScreenReaderSupport", ELDBUS_ARGS({"b", "bool"}), NULL,
-        _is_screen_reader_support
+      { "AppGestureSupport", ELDBUS_ARGS({"s", "string"}), NULL,
+        _is_app_gesture_support
       },
       { "IsSelectionMode", ELDBUS_ARGS({"b", "bool"}), NULL,
         _is_selection_mode
@@ -121,7 +120,7 @@ static const Eldbus_Service_Interface_Desc iface_desc = {
 
 
 /* Use this util function for gesture enum to string conversion */
-static const char *_gesture_enum_to_string(Gesture g)
+const char *gesture_enum_to_string(Gesture g)
 {
    switch(g)
      {
@@ -236,7 +235,7 @@ int _e_mod_atspi_dbus_broadcast(Gesture_Info *gi)
    eldbus_service_signal_emit(iface, GESTURE_DETECTED_SIGNAL, (int)gi->type, gi->x_beg, gi->y_beg,
                               gi->x_end, gi->y_end, gi->state, gi->event_time);
 
-   INFO("GestureDetected %s %d (%d %d %d %d %d %u)", _gesture_enum_to_string(gi->type),
+   INFO("GestureDetected %s %d (%d %d %d %d %d %u)", gesture_enum_to_string(gi->type),
         (int)gi->type, gi->x_beg, gi->y_beg, gi->x_end, gi->y_end, gi->state, gi->event_time);
 
    return 0;
@@ -248,7 +247,7 @@ _gesture_cb(void    *data,
             void    *event)
 {
    Gesture_Info *gi = event;
-   DEBUG("Gesture cb hit\n");
+   DEBUG("Gesture cb hit");
    if (g_gesture_navi)
      _e_mod_atspi_dbus_broadcast(gi);
 
@@ -410,13 +409,19 @@ _is_slider(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
 }
 
 static Eldbus_Message *
-_is_screen_reader_support(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+_is_app_gesture_support(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
 {
-   if (!eldbus_message_arguments_get(msg, "b", &is_screen_reader_support))
+   char *text = "";
+
+   if (!eldbus_message_arguments_get(msg, "s", &text))
+   {
      ERROR("eldbus_message_arguments_get() error\n");
+     return NULL;
+   }
 
-   DEBUG("screen reader support :%d", is_screen_reader_support);
-   return NULL;
+   app_gesture_support (text);
+
+   return eldbus_message_method_return_new(msg);
 }
 
 static Eldbus_Message *
index 90b23dd..dfb6b82 100644 (file)
@@ -6,6 +6,8 @@
 #define HISTORY_MAX 8
 
 double MAGIC_NUMBER = 987654321.0;
+Eina_Bool app_support_gestures;
+Eina_Bool gestures_supported_by_app [ GESTURES_COUNT ];
 
 typedef enum {
      FLICK_DIRECTION_UNDEFINED,
@@ -68,7 +70,8 @@ struct _Cover
         unsigned int timestamp; // time of gesture;
         unsigned int last_emission_time; // last time of gesture emission
         Ecore_Timer *timer;
-        Eina_Bool longpressed;
+        Eina_Bool longpressed, atspi_mouse_down_emitted;
+        Ecore_Event_Mouse_Button ev_first_down;
    } hover_gesture;
 
    struct {
@@ -110,6 +113,47 @@ _gesture_info_free(void *data, void *info)
    free(data);
 }
 
+void app_gesture_support (char *msg)
+{
+  if (!strcmp(msg, "all"))
+   {
+     app_support_gestures = EINA_TRUE;
+     DEBUG("App support all gestures");
+
+     return;
+   }
+
+  app_support_gestures = EINA_FALSE;
+  int k;
+  for (k = 0; k < GESTURES_COUNT; ++k)
+    gestures_supported_by_app [k] = EINA_FALSE;
+
+   if (!strcmp(msg, ""))
+   {
+     DEBUG("App support none gestures");
+     return;
+   }
+
+   unsigned int n = 0;
+   char **list = eina_str_split_full(msg, "|", 0, &n);
+   if (list) {
+     int i;
+     for (i = 0; i < n; ++i) {
+       for (k = 0; k < GESTURES_COUNT; ++k)
+         if (strcmp(list[i], gesture_enum_to_string(k)) == 0) {
+           gestures_supported_by_app[k] = EINA_TRUE;
+           break;
+         }
+       if (k >= GESTURES_COUNT)
+        DEBUG("unknown gesture '%s'", list[i]);
+     }
+   free(list[0]);
+   free(list);
+   }
+
+   DEBUG("App support :%s gestures", msg);
+}
+
 int gesture_state_enum_to_int(gesture_state_e state)
 {
    int gesture_state;
@@ -338,97 +382,103 @@ _flick_gesture_direction_get(int x, int y, int x_org, int y_org)
    return FLICK_DIRECTION_UNDEFINED;
 }
 
-static void
-_flick_event_emit(Cover *cov)
+static int _flick_event_emit_get_type(Cover *cov)
 {
-   int ax, ay, axe, aye, i, type = -1;
-   ax = ay = axe = aye = 0;
-
-   for (i = 0; i < cov->flick_gesture.n_fingers; i++)
-     {
-        ax += cov->flick_gesture.x_org[i];
-        ay += cov->flick_gesture.y_org[i];
-        axe += cov->flick_gesture.x_end[i];
-        aye += cov->flick_gesture.y_end[i];
-     }
-
-   ax /= cov->flick_gesture.n_fingers;
-   ay /= cov->flick_gesture.n_fingers;
-   axe /= cov->flick_gesture.n_fingers;
-   aye /= cov->flick_gesture.n_fingers;
-
    if (cov->flick_gesture.dir == FLICK_DIRECTION_LEFT)
      {
         if (cov->flick_gesture.n_fingers == 1)
-          type = ONE_FINGER_FLICK_LEFT;
+          return ONE_FINGER_FLICK_LEFT;
         if (cov->flick_gesture.n_fingers == 2)
-          type = TWO_FINGERS_FLICK_LEFT;
+          return TWO_FINGERS_FLICK_LEFT;
         if (cov->flick_gesture.n_fingers == 3)
-          type = THREE_FINGERS_FLICK_LEFT;
+          return THREE_FINGERS_FLICK_LEFT;
      }
    else if (cov->flick_gesture.dir == FLICK_DIRECTION_RIGHT)
      {
         if (cov->flick_gesture.n_fingers == 1)
-          type = ONE_FINGER_FLICK_RIGHT;
+          return ONE_FINGER_FLICK_RIGHT;
         if (cov->flick_gesture.n_fingers == 2)
-          type = TWO_FINGERS_FLICK_RIGHT;
+          return TWO_FINGERS_FLICK_RIGHT;
         if (cov->flick_gesture.n_fingers == 3)
-          type = THREE_FINGERS_FLICK_RIGHT;
+          return THREE_FINGERS_FLICK_RIGHT;
      }
    else if (cov->flick_gesture.dir == FLICK_DIRECTION_UP)
      {
         if (cov->flick_gesture.n_fingers == 1)
-          type = ONE_FINGER_FLICK_UP;
+          return ONE_FINGER_FLICK_UP;
         if (cov->flick_gesture.n_fingers == 2)
-          type = TWO_FINGERS_FLICK_UP;
+          return TWO_FINGERS_FLICK_UP;
         if (cov->flick_gesture.n_fingers == 3)
-          type = THREE_FINGERS_FLICK_UP;
+          return THREE_FINGERS_FLICK_UP;
      }
    else if (cov->flick_gesture.dir == FLICK_DIRECTION_DOWN)
      {
         if (cov->flick_gesture.n_fingers == 1)
-          type = ONE_FINGER_FLICK_DOWN;
+          return ONE_FINGER_FLICK_DOWN;
         if (cov->flick_gesture.n_fingers == 2)
-          type = TWO_FINGERS_FLICK_DOWN;
+          return TWO_FINGERS_FLICK_DOWN;
         if (cov->flick_gesture.n_fingers == 3)
-          type = THREE_FINGERS_FLICK_DOWN;
+          return THREE_FINGERS_FLICK_DOWN;
      }
    else if (cov->flick_gesture.dir == FLICK_DIRECTION_DOWN_RETURN)
      {
         if (cov->flick_gesture.n_fingers == 1)
-          type = ONE_FINGER_FLICK_DOWN_RETURN;
+          return ONE_FINGER_FLICK_DOWN_RETURN;
         if (cov->flick_gesture.n_fingers == 2)
-          type = TWO_FINGERS_FLICK_DOWN_RETURN;
+          return TWO_FINGERS_FLICK_DOWN_RETURN;
         if (cov->flick_gesture.n_fingers == 3)
-          type = THREE_FINGERS_FLICK_DOWN_RETURN;
+          return THREE_FINGERS_FLICK_DOWN_RETURN;
      }
    else if (cov->flick_gesture.dir == FLICK_DIRECTION_UP_RETURN)
      {
         if (cov->flick_gesture.n_fingers == 1)
-          type = ONE_FINGER_FLICK_UP_RETURN;
+          return ONE_FINGER_FLICK_UP_RETURN;
         if (cov->flick_gesture.n_fingers == 2)
-          type = TWO_FINGERS_FLICK_UP_RETURN;
+          return TWO_FINGERS_FLICK_UP_RETURN;
         if (cov->flick_gesture.n_fingers == 3)
-          type = THREE_FINGERS_FLICK_UP_RETURN;
+          return THREE_FINGERS_FLICK_UP_RETURN;
      }
    else if (cov->flick_gesture.dir == FLICK_DIRECTION_LEFT_RETURN)
      {
         if (cov->flick_gesture.n_fingers == 1)
-          type = ONE_FINGER_FLICK_LEFT_RETURN;
+          return ONE_FINGER_FLICK_LEFT_RETURN;
         if (cov->flick_gesture.n_fingers == 2)
-          type = TWO_FINGERS_FLICK_LEFT_RETURN;
+          return TWO_FINGERS_FLICK_LEFT_RETURN;
         if (cov->flick_gesture.n_fingers == 3)
-          type = THREE_FINGERS_FLICK_LEFT_RETURN;
+          return THREE_FINGERS_FLICK_LEFT_RETURN;
      }
    else if (cov->flick_gesture.dir == FLICK_DIRECTION_RIGHT_RETURN)
      {
         if (cov->flick_gesture.n_fingers == 1)
-          type = ONE_FINGER_FLICK_RIGHT_RETURN;
+          return ONE_FINGER_FLICK_RIGHT_RETURN;
         if (cov->flick_gesture.n_fingers == 2)
-          type = TWO_FINGERS_FLICK_RIGHT_RETURN;
+          return TWO_FINGERS_FLICK_RIGHT_RETURN;
         if (cov->flick_gesture.n_fingers == 3)
-          type = THREE_FINGERS_FLICK_RIGHT_RETURN;
+          return THREE_FINGERS_FLICK_RIGHT_RETURN;
      }
+   return 0;
+}
+
+static void
+_flick_event_emit(Cover *cov)
+{
+   int ax, ay, axe, aye, i, type = -1;
+   ax = ay = axe = aye = 0;
+
+   for (i = 0; i < cov->flick_gesture.n_fingers; i++)
+     {
+        ax += cov->flick_gesture.x_org[i];
+        ay += cov->flick_gesture.y_org[i];
+        axe += cov->flick_gesture.x_end[i];
+        aye += cov->flick_gesture.y_end[i];
+     }
+
+   ax /= cov->flick_gesture.n_fingers;
+   ay /= cov->flick_gesture.n_fingers;
+   axe /= cov->flick_gesture.n_fingers;
+   aye /= cov->flick_gesture.n_fingers;
+   type = _flick_event_emit_get_type(cov);
+
    _event_emit(type, ax, ay, axe, aye, GESTURE_FINISHED, cov->event_time);
 }
 
@@ -790,6 +840,9 @@ _hover_gesture_mouse_down(Ecore_Event_Mouse_Button *ev, Cover *cov)
         cov->hover_gesture.y[0] = ev->root.y;
         cov->hover_gesture.finger[0] = ev->multi.device;
         cov->hover_gesture.n_fingers = 1;
+        cov->hover_gesture.atspi_mouse_down_emitted = EINA_FALSE;
+        memcpy(&cov->hover_gesture.ev_first_down, ev, sizeof(*ev));
+        cov->hover_gesture.ev_first_down.multi.radius += MAGIC_NUMBER;
         _hover_gesture_timer_reset(cov, _e_mod_config->one_finger_hover_longpress_timeout);
      }
    if (cov->hover_gesture.state == GESTURE_ONGOING &&
@@ -949,7 +1002,25 @@ _hover_event_emit(Cover *cov, gesture_state_e state)
    switch (cov->hover_gesture.n_fingers)
      {
       case 1:
-         _event_emit(ONE_FINGER_HOVER, ax, ay, ax, ay, state, cov->event_time);
+         if (!gestures_supported_by_app[ONE_FINGER_HOVER])
+           {
+            _event_emit(ONE_FINGER_HOVER, ax, ay, ax, ay, state, cov->event_time);
+           }
+         else
+           {
+             if (!cov->hover_gesture.atspi_mouse_down_emitted) {
+               cov->hover_gesture.atspi_mouse_down_emitted = EINA_TRUE;
+               _emit_mouse_move_event(&cov->hover_gesture.ev_first_down);
+               Ecore_Event_Mouse_Button *ev = malloc(sizeof(Ecore_Event_Mouse_Button));
+               memcpy(ev, &cov->hover_gesture.ev_first_down, sizeof(*ev));
+               ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
+             }
+             Ecore_Event_Mouse_Button ev_move;
+             memcpy(&ev_move, &cov->hover_gesture.ev_first_down, sizeof(ev_move));
+             ev_move.root.x = ev_move.x = ax;
+             ev_move.root.y = ev_move.y = ay;
+             _emit_mouse_move_event(&ev_move);
+           }
          break;
       case 2:
          _event_emit(TWO_FINGERS_HOVER, ax, ay, ax, ay, state, cov->event_time);
@@ -1430,6 +1501,11 @@ _mouse_button_up(int type, Ecore_Event_Mouse_Button *event)
    _tap_gestures_mouse_up(ev, cover);
    DEBUG("single mouse up,taps: %d Multi :%d", cover->n_taps,ev->multi.device);
 
+   if (cover->hover_gesture.n_fingers == 1 && cover->hover_gesture.atspi_mouse_down_emitted)
+     {
+       cover->hover_gesture.atspi_mouse_down_emitted = EINA_FALSE;
+       return EINA_TRUE;
+     }
    return EINA_FALSE;
 }
 
@@ -1458,9 +1534,9 @@ static Eina_Bool
 _event_filter(void *data, void *loop_data, int type, void *event)
 {
    Eina_Bool ret = EINA_TRUE;
-   if (!is_screen_reader_support)
+   if (app_support_gestures)
      {
-        DEBUG("screen reader is not supported");
+        DEBUG("Gestures supported by app");
         return ret;
      }
 
@@ -1470,7 +1546,7 @@ _event_filter(void *data, void *loop_data, int type, void *event)
      }
    else if (type == ECORE_EVENT_MOUSE_BUTTON_UP)
      {
-        ret = _mouse_button_up(type, event);
+       ret = _mouse_button_up(type, event);
      }
    else if (type == ECORE_EVENT_MOUSE_MOVE)
      {
@@ -1510,7 +1586,10 @@ _gesture_init()
         return;
      }
    is_slider = EINA_FALSE;
-   is_screen_reader_support = EINA_TRUE;
+   app_support_gestures = EINA_FALSE;
+   int i;
+   for (i = 0; i < GESTURES_COUNT; ++i)
+       gestures_supported_by_app[i] = EINA_FALSE;
    highlighted_object_x = -1;
    highlighted_object_y = -1;
    object_needs_scroll_from_x = -1;
index 6328c1c..ae7820a 100644 (file)
@@ -67,11 +67,13 @@ typedef struct {
 } Gesture_Info;
 
 extern Eina_Bool is_slider;
-extern Eina_Bool is_screen_reader_support;
 extern int highlighted_object_x, highlighted_object_y;
 extern Eina_Bool is_selection_mode;
 extern int object_needs_scroll_from_x, object_needs_scroll_from_y;
 
+const char *gesture_enum_to_string(Gesture g);
+void app_gesture_support (char *msg);
+
 int _e_mod_log_init(void);
 void _e_mod_log_shutdown(void);