Gesture's implementation 94/64994/7
authorSubodhKumar <s7158.kumar@samsung.com>
Mon, 11 Apr 2016 13:39:01 +0000 (19:09 +0530)
committershilpa singh <shilpa.singh@samsung.com>
Mon, 2 May 2016 06:17:15 +0000 (23:17 -0700)
Change-Id: I1f7f070a3fcf2cc2e86fb59a06a16ad38e4134a6

autogen.sh
src/Makefile.am
src/e_mod_main.c
src/e_screen_reader_config.c [new file with mode: 0644]
src/e_screen_reader_config.h [new file with mode: 0644]
src/e_screen_reader_gestures.c [new file with mode: 0644]
src/e_screen_reader_private.h [new file with mode: 0644]

index ab0c7d2..3938e2b 100755 (executable)
@@ -6,3 +6,4 @@ autoconf
 libtoolize --copy --force
 autoheader
 automake --foreign --add-missing --copy
+
index 6f439a2..28dd76e 100644 (file)
@@ -6,7 +6,9 @@ LDFLAGS +=
 pkgdir                 = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH)
 pkg_LTLIBRARIES        = module.la
 module_la_SOURCES      = \
-       e_mod_main.c
+       e_mod_main.c \
+       e_screen_reader_config.c \
+       e_screen_reader_gestures.c
 
 #if HAVE_WAYLAND_ONLY
 #module_la_SOURCES      += e_screen_reader_*.c \
index 7ba6bbd..0391537 100644 (file)
@@ -1,10 +1,15 @@
 #include "e.h"
 #include "eina_log.h"
 #include "e_mod_main.h"
+#include <e_screen_reader_config.h>
+#include <e_screen_reader_private.h>
 
 #undef DBG
-int _log_dom = -1;
-#define DBG(...)  do EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__); while(0)
+int _eina_log_dom = -1;
+#define DBG(...)  do EINA_LOG_DOM_DBG(_eina_log_dom, __VA_ARGS__); while(0)
+
+static Eina_Bool g_gesture_navi;
+static Eina_List *handlers;
 
 EAPI E_Module_Api e_modapi =
 {
@@ -12,23 +17,173 @@ EAPI E_Module_Api e_modapi =
    "Screen Reader Module of Window Manager"
 };
 
+/* Use this util function for gesture enum to string conversion */
+static const char *_gesture_enum_to_string(Gesture g)
+{
+   switch(g)
+     {
+      case ONE_FINGER_HOVER:
+         return "OneFingerHover";
+      case TWO_FINGERS_HOVER:
+         return "TwoFingersHover";
+      case THREE_FINGERS_HOVER:
+         return "ThreeFingersHover";
+      case ONE_FINGER_FLICK_LEFT:
+         return "OneFingerFlickLeft";
+      case ONE_FINGER_FLICK_RIGHT:
+         return "OneFingerFlickRight";
+      case ONE_FINGER_FLICK_UP:
+         return "OneFingerFlickUp";
+      case ONE_FINGER_FLICK_DOWN:
+         return "OneFingerFlickDown";
+      case TWO_FINGERS_FLICK_UP:
+         return "TwoFingersFlickUp";
+      case TWO_FINGERS_FLICK_DOWN:
+         return "TwoFingersFlickDown";
+      case TWO_FINGERS_FLICK_LEFT:
+         return "TwoFingersFlickLeft";
+      case TWO_FINGERS_FLICK_RIGHT:
+         return "TwoFingersFlickRight";
+      case THREE_FINGERS_FLICK_LEFT:
+         return "ThreeFingersFlickLeft";
+      case THREE_FINGERS_FLICK_RIGHT:
+         return "ThreeFingersFlickRight";
+      case THREE_FINGERS_FLICK_UP:
+         return "ThreeFingersFlickUp";
+      case THREE_FINGERS_FLICK_DOWN:
+         return "ThreeFingersFlickDown";
+      case ONE_FINGER_SINGLE_TAP:
+         return "OneFingerSingleTap";
+      case ONE_FINGER_DOUBLE_TAP:
+         return "OneFingerDoubleTap";
+      case ONE_FINGER_TRIPLE_TAP:
+         return "OneFingerTripleTap";
+      case TWO_FINGERS_SINGLE_TAP:
+         return "TwoFingersSingleTap";
+      case TWO_FINGERS_DOUBLE_TAP:
+         return "TwoFingersDoubleTap";
+      case TWO_FINGERS_TRIPLE_TAP:
+         return "TwoFingersTripleTap";
+      case THREE_FINGERS_SINGLE_TAP:
+         return "ThreeFingersSingleTap";
+      case THREE_FINGERS_DOUBLE_TAP:
+         return "ThreeFingersDoubleTap";
+      case THREE_FINGERS_TRIPLE_TAP:
+         return "ThreeFingersTripleTap";
+      case ONE_FINGER_FLICK_LEFT_RETURN:
+         return "OneFingerFlickLeftReturn";
+      case ONE_FINGER_FLICK_RIGHT_RETURN:
+         return "OneFingerFlickRightReturn";
+      case ONE_FINGER_FLICK_UP_RETURN:
+         return "OneFingerFlickUpReturn";
+      case ONE_FINGER_FLICK_DOWN_RETURN:
+         return "OneFingerFlickDownReturn";
+      case TWO_FINGERS_FLICK_LEFT_RETURN:
+         return "TwoFingersFlickLeftReturn";
+      case TWO_FINGERS_FLICK_RIGHT_RETURN:
+         return "TwoFingersFlickRightReturn";
+      case TWO_FINGERS_FLICK_UP_RETURN:
+         return "TwoFingersFlickUpReturn";
+      case TWO_FINGERS_FLICK_DOWN_RETURN:
+         return "TwoFingersFlickDownReturn";
+      case THREE_FINGERS_FLICK_LEFT_RETURN:
+         return "ThreeFingersFlickLeftReturn";
+      case THREE_FINGERS_FLICK_RIGHT_RETURN:
+         return "ThreeFingersFlickRightReturn";
+      case THREE_FINGERS_FLICK_UP_RETURN:
+         return "ThreeFingersFlickUpReturn";
+      case THREE_FINGERS_FLICK_DOWN_RETURN:
+         return "ThreeFingersFlickDownReturn";
+      default:
+         ERROR("[atspi] dbus: unhandled gesture enum");
+         return NULL;
+     }
+}
+
+int _e_mod_atspi_dbus_broadcast(Gesture_Info *gi)
+{
+   /* Implement this for gesture broadcast */
+   const char *name;
+
+   name = _gesture_enum_to_string(gi->type);
+   if (!name) return -1;
+
+   INFO("GestureDetected %s (%d %d %d %d %d)", name, gi->x_beg, gi->y_beg, gi->x_end, gi->y_end, gi->state);
+   return 0;
+}
+
+static Eina_Bool
+_gesture_cb(void    *data,
+            int      type EINA_UNUSED,
+            void    *event)
+{
+   Gesture_Info *gi = event;
+
+   if (g_gesture_navi)
+     _e_mod_atspi_dbus_broadcast(gi);
+
+   return EINA_TRUE;
+}
+
+static void
+_events_init(void)
+{
+#define HANDLER_APPEND(event, cb) \
+   handlers = eina_list_append( \
+      handlers, ecore_event_handler_add(event, cb, NULL));
+   HANDLER_APPEND(E_EVENT_ATSPI_GESTURE_DETECTED, _gesture_cb);
+   /* Use this list for other handlers */
+#undef APPEND_HANDLER
+}
+
+static void
+_events_shutdown(void)
+{
+   E_FREE_LIST(handlers, ecore_event_handler_del);
+}
+
 EAPI void *
 e_modapi_init(E_Module *m)
 {
-   _log_dom = eina_log_domain_register("e_screen_reader", EINA_COLOR_YELLOW);
-   if (_log_dom < 0)
+   _eina_log_dom = eina_log_domain_register("e_screen_reader", EINA_COLOR_YELLOW);
+   if (!_eina_log_dom)
      {
         DBG("Failed @ eina_log_domain_register()..!");
         return NULL;
      }
 
+   if (_e_mod_atspi_config_init())
+     goto fail;
+   if (_e_mod_atspi_gestures_init())
+     goto fail_gestures;
+
+   _events_init();
+   g_gesture_navi = EINA_TRUE;
    return m;
+
+fail_gestures:
+   ERROR("Gestures submodule initialization failed.");
+   _e_mod_atspi_config_shutdown();
+fail:
+   ERROR("Module initialization failed.");
+
+   return NULL;
 }
 
 EAPI int
 e_modapi_shutdown(E_Module *m EINA_UNUSED)
 {
-   eina_log_domain_unregister(_log_dom);
+   if (_eina_log_dom)
+     {
+        eina_log_domain_unregister(_eina_log_dom);
+        _eina_log_dom = 0;
+     }
+
+   _events_shutdown();
+   g_gesture_navi = EINA_FALSE;
+   _e_mod_atspi_config_save();
+   _e_mod_atspi_config_shutdown();
+   _e_mod_atspi_gestures_shutdown();
 
    return 1;
 }
diff --git a/src/e_screen_reader_config.c b/src/e_screen_reader_config.c
new file mode 100644 (file)
index 0000000..15e2bf3
--- /dev/null
@@ -0,0 +1,63 @@
+#include <e.h>
+#include <e_screen_reader_config.h>
+#include <e_screen_reader_private.h>
+
+Gestures_Config *_e_mod_config;
+
+static E_Config_DD *_conf_edd;
+
+
+static void
+_e_mod_config_new(void)
+{
+   _e_mod_config = E_NEW(Gestures_Config, 1);
+
+   _e_mod_config->one_finger_flick_min_length = 100;
+   _e_mod_config->one_finger_flick_max_time = 400;
+   _e_mod_config->one_finger_hover_longpress_timeout = 0.81;
+   _e_mod_config->two_fingers_hover_longpress_timeout = 0.1;
+   _e_mod_config->one_finger_tap_timeout = 0.4;
+   _e_mod_config->one_finger_tap_radius = 100;
+}
+
+int _e_mod_atspi_config_init(void)
+{
+   DEBUG("Config init");
+   _conf_edd = E_CONFIG_DD_NEW("Gestures_Config", Gestures_Config);
+
+#define T Gestures_Config
+#define D _conf_edd
+   E_CONFIG_VAL(D, T, one_finger_flick_min_length, INT);
+   E_CONFIG_VAL(D, T, one_finger_flick_max_time, INT);
+   E_CONFIG_VAL(D, T, one_finger_hover_longpress_timeout, DOUBLE);
+   E_CONFIG_VAL(D, T, two_fingers_hover_longpress_timeout, DOUBLE);
+   E_CONFIG_VAL(D, T, one_finger_tap_timeout, DOUBLE);
+   E_CONFIG_VAL(D, T, one_finger_tap_radius, INT);
+
+   _e_mod_config = e_config_domain_load(E_ATSPI_CFG, _conf_edd);
+
+   if (!_e_mod_config)
+     {
+        _e_mod_config_new();
+        _e_mod_atspi_config_save();
+        INFO("New config file for e-mod-tizen-screen-reader module created.");
+     }
+   else
+     INFO("Config file for e-mod-tizen-screen-reader module loaded successfully.");
+
+   return 0;
+}
+
+int _e_mod_atspi_config_shutdown(void)
+{
+   DEBUG("Config shutdown");
+   E_FREE(_e_mod_config);
+   E_CONFIG_DD_FREE(_conf_edd);
+
+   return 0;
+}
+
+int _e_mod_atspi_config_save(void)
+{
+   return e_config_domain_save(E_ATSPI_CFG, _conf_edd, _e_mod_config);
+}
diff --git a/src/e_screen_reader_config.h b/src/e_screen_reader_config.h
new file mode 100644 (file)
index 0000000..1c82f94
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef E_SCREEN_READER_CONFIG_H_
+#define E_SCREEN_READER_CONFIG_H_
+
+#define E_ATSPI_CFG       "module.e-mod-tizen-screen-reader"
+
+struct _Gestures_Config
+{
+   // minimal required length of flick gesture (in pixels)
+   int one_finger_flick_min_length;
+   // maximal time of gesture
+   int one_finger_flick_max_time;
+   // timeout period to activate hover gesture (first longpress timeout)
+   double one_finger_hover_longpress_timeout;
+   // tap timeout - maximal ammount of time allowed between seqiential taps
+   double two_fingers_hover_longpress_timeout;
+   // tap timeout - maximal ammount of time allowed between seqiential taps
+   double one_finger_tap_timeout;
+   // tap radius(in pixels)
+   int one_finger_tap_radius;
+};
+
+typedef struct _Gestures_Config Gestures_Config;
+
+int _e_mod_atspi_config_init(void);
+int _e_mod_atspi_config_shutdown(void);
+int _e_mod_atspi_config_save(void);
+
+/*< External config handle - valid after initalization */
+extern Gestures_Config *_e_mod_config;
+
+#endif /* E_SCREEN_READER_CONFIG_H_ */
diff --git a/src/e_screen_reader_gestures.c b/src/e_screen_reader_gestures.c
new file mode 100644 (file)
index 0000000..36d6cb9
--- /dev/null
@@ -0,0 +1,1098 @@
+#include "e.h"
+#include "e_comp.h"
+#include "e_screen_reader_private.h"
+
+
+#define HISTORY_MAX 8
+#define LONGPRESS_TIMEOUT 0.4
+
+typedef enum {
+     FLICK_DIRECTION_UNDEFINED,
+     FLICK_DIRECTION_DOWN,
+     FLICK_DIRECTION_UP,
+     FLICK_DIRECTION_LEFT,
+     FLICK_DIRECTION_RIGHT,
+     FLICK_DIRECTION_DOWN_RETURN,
+     FLICK_DIRECTION_UP_RETURN,
+     FLICK_DIRECTION_LEFT_RETURN,
+     FLICK_DIRECTION_RIGHT_RETURN,
+} flick_direction_e;
+
+typedef enum {
+     GESTURE_NOT_STARTED = 0, // Gesture is ready to start
+     GESTURE_ONGOING,         // Gesture in progress.
+     GESTURE_FINISHED,        // Gesture finished - should be emited
+     GESTURE_ABORTED          // Gesture aborted
+} gesture_state_e;
+
+typedef enum {
+      ONE_FINGER_GESTURE = 1,
+      TWO_FINGERS_GESTURE,
+      THREE_FINGERS_GESTURE
+} gesture_type_e;
+
+struct _Cover
+{
+   Evas_Object   *gesture_rect; /**< Gesture rectangle */
+   unsigned int    n_taps; /**< Number of fingers touching screen */
+   unsigned int    event_time;
+
+   struct {
+        gesture_state_e state;     // current state of gesture
+        unsigned int timestamp[3]; // time of gesture;
+        int finger[3];             // finger number which initiates gesture
+        int x_org[3], y_org[3];    // coorinates of finger down event
+        int x_end[3], y_end[3];    // coorinates of finger up event
+        flick_direction_e dir;     // direction of flick
+        int n_fingers;             // number of fingers in gesture
+        int n_fingers_left;        // number of fingers in gesture
+                                   //         still touching screen
+        Eina_Bool finger_out[3];   // finger is out of the finger boundary
+        Eina_Bool return_flick[3];
+   } flick_gesture;
+
+   struct {
+        gesture_state_e state;   // currest gesture state
+        int x[2], y[2];
+        int n_fingers;
+        int finger[2];
+        unsigned int timestamp; // time of gesture;
+        unsigned int last_emission_time; // last time of gesture emission
+        Ecore_Timer *timer;
+        Eina_Bool longpressed;
+   } hover_gesture;
+
+   struct {
+        Eina_Bool started; // indicates if taps recognition process has started
+        Eina_Bool pressed; // indicates if finger is down
+        int n_taps;        // number of taps captures in sequence
+        int finger[3];        // device id of finget
+        Ecore_Timer *timer;  // sequence expiration timer
+        int x_org[3], y_org[3];    // coordinates of first tap
+        gesture_type_e tap_type;
+   } tap_gesture_data;
+};
+typedef struct _Cover Cover;
+
+int E_EVENT_ATSPI_GESTURE_DETECTED;
+
+static Cover *cover;
+static Eina_List *handlers;
+static void _gesture_init(void);
+static void _gesture_shutdown(void);
+static void _hover_event_emit(Cover *cov, int state);
+
+static void
+_gesture_info_free(void *data, void *info)
+{
+   free(data);
+}
+
+static void _event_emit(Gesture g, int x, int y, int x_e, int y_e, int state)
+{
+   Gesture_Info *info = calloc(sizeof(Gesture_Info), 1);
+   EINA_SAFETY_ON_NULL_RETURN(info);
+
+   info->type = g;
+   info->x_beg = x;
+   info->x_end = x_e;
+   info->y_beg = y;
+   info->y_end = y_e;
+   info->state = state;
+
+   ecore_event_add(E_EVENT_ATSPI_GESTURE_DETECTED, info, _gesture_info_free, NULL);
+}
+
+static void
+_flick_gesture_mouse_down(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->flick_gesture.state == GESTURE_NOT_STARTED)
+     {
+        cov->flick_gesture.state = GESTURE_ONGOING;
+        cov->flick_gesture.finger[0] = ev->multi.device;
+        cov->flick_gesture.x_org[0] = ev->root.x;
+        cov->flick_gesture.y_org[0] = ev->root.y;
+        cov->flick_gesture.timestamp[0] = ev->timestamp;
+        cov->flick_gesture.n_fingers = 1;
+        cov->flick_gesture.n_fingers_left = 1;
+        cov->flick_gesture.dir = FLICK_DIRECTION_UNDEFINED;
+        cov->flick_gesture.finger_out[0] = EINA_FALSE;
+        cov->flick_gesture.return_flick[0] = EINA_FALSE;
+     }
+   else if (cov->flick_gesture.state == GESTURE_ONGOING)
+     {
+        // abort gesture if too many fingers touched screen
+        if ((cov->n_taps > 3) || (cov->flick_gesture.n_fingers > 2))
+          {
+             cov->flick_gesture.state = GESTURE_ABORTED;
+             return;
+          }
+
+        cov->flick_gesture.x_org[cov->flick_gesture.n_fingers] = ev->root.x;
+        cov->flick_gesture.y_org[cov->flick_gesture.n_fingers] = ev->root.y;
+        cov->flick_gesture.timestamp[cov->flick_gesture.n_fingers] = ev->timestamp;
+        cov->flick_gesture.finger[cov->flick_gesture.n_fingers] = ev->multi.device;
+        cov->flick_gesture.n_fingers++;
+        cov->flick_gesture.n_fingers_left++;
+         if (cov->flick_gesture.n_fingers < 3) /* n_fingers == 3 makes out of bounds write */
+           {
+              cov->flick_gesture.finger_out[cov->flick_gesture.n_fingers] = EINA_FALSE;
+              cov->flick_gesture.return_flick[cov->flick_gesture.n_fingers] = EINA_FALSE;
+           }
+     }
+}
+
+static Eina_Bool
+_flick_gesture_time_check(unsigned int event_time, unsigned int gesture_time)
+{
+   DEBUG("Flick time: %d", event_time - gesture_time);
+   if ((event_time - gesture_time) < _e_mod_config->one_finger_flick_max_time * 2) //Double time because of the possible of return flick
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+static Eina_Bool
+_flick_gesture_length_check(int x, int y, int x_org, int y_org)
+{
+   int dx = x - x_org;
+   int dy = y - y_org;
+
+   if ((dx * dx + dy * dy) > (_e_mod_config->one_finger_flick_min_length *
+                            _e_mod_config->one_finger_flick_min_length))
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+static flick_direction_e
+_flick_gesture_direction_get(int x, int y, int x_org, int y_org)
+{
+   int dx = x - x_org;
+   int dy = y - y_org;
+
+   if ((dy < 0) && (abs(dx) < -dy))
+     return FLICK_DIRECTION_UP;
+   if ((dy > 0) && (abs(dx) < dy))
+     return FLICK_DIRECTION_DOWN;
+   if ((dx > 0) && (dx > abs(dy)))
+     return FLICK_DIRECTION_RIGHT;
+   if ((dx < 0) && (-dx > abs(dy)))
+     return FLICK_DIRECTION_LEFT;
+
+   return FLICK_DIRECTION_UNDEFINED;
+}
+
+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;
+
+   if (cov->flick_gesture.dir == FLICK_DIRECTION_LEFT)
+     {
+        if (cov->flick_gesture.n_fingers == 1)
+          type = ONE_FINGER_FLICK_LEFT;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_LEFT;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = 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;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_RIGHT;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = 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;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_UP;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = 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;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_DOWN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = 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;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_DOWN_RETURN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = 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;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_UP_RETURN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = 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;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_LEFT_RETURN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = 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;
+        if (cov->flick_gesture.n_fingers == 2)
+          type = TWO_FINGERS_FLICK_RIGHT_RETURN;
+        if (cov->flick_gesture.n_fingers == 3)
+          type = THREE_FINGERS_FLICK_RIGHT_RETURN;
+     }
+   _event_emit(type, ax, ay, axe, aye, 2);
+}
+
+static void
+_flick_gesture_mouse_up(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->flick_gesture.state == GESTURE_ONGOING)
+     {
+        int i;
+        // check if fingers match
+        for (i = 0; i < cov->flick_gesture.n_fingers; i++)
+          {
+             if (cov->flick_gesture.finger[i] == ev->multi.device)
+               break;
+          }
+        if (i == cov->flick_gesture.n_fingers)
+          {
+             DEBUG("Finger id not recognized. Gesture aborted.");
+             cov->flick_gesture.state = GESTURE_ABORTED;
+             goto end;
+          }
+
+        // check if flick for given finger is valid
+        if (!_flick_gesture_time_check(ev->timestamp,
+                                       cov->flick_gesture.timestamp[i]))
+          {
+             DEBUG("finger flick gesture timeout expired. Gesture aborted.");
+             cov->flick_gesture.state = GESTURE_ABORTED;
+             goto end;
+          }
+
+        // check minimal flick length
+        if (!_flick_gesture_length_check(ev->root.x, ev->root.y,
+                                        cov->flick_gesture.x_org[i],
+                                        cov->flick_gesture.y_org[i]))
+          {
+             if (!cov->flick_gesture.finger_out[i])
+               {
+                  DEBUG("Minimal gesture length not reached and no return flick. Gesture aborted.");
+                  cov->flick_gesture.state = GESTURE_ABORTED;
+                  goto end;
+               }
+             cov->flick_gesture.return_flick[i] = EINA_TRUE;
+          }
+
+        flick_direction_e s = cov->flick_gesture.return_flick[i] ?
+                                       cov->flick_gesture.dir :
+                                       _flick_gesture_direction_get(ev->root.x, ev->root.y,
+                                                                     cov->flick_gesture.x_org[i],
+                                                                     cov->flick_gesture.y_org[i]);
+
+        cov->flick_gesture.n_fingers_left--;
+
+        if ((cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+               cov->flick_gesture.dir > FLICK_DIRECTION_RIGHT)
+               && cov->flick_gesture.return_flick[i] == EINA_FALSE)
+         {
+            DEBUG("Flick gesture");
+            cov->flick_gesture.dir = s;
+         }
+
+        // gesture is valid only if all flicks are in same direction
+        if (cov->flick_gesture.dir != s)
+          {
+             DEBUG("Flick in different direction. Gesture aborted.");
+             cov->flick_gesture.state = GESTURE_ABORTED;
+             goto end;
+          }
+
+        cov->flick_gesture.x_end[i] = ev->root.x;
+        cov->flick_gesture.y_end[i] = ev->root.y;
+
+        if (!cov->flick_gesture.n_fingers_left)
+          {
+             _flick_event_emit(cov);
+             cov->flick_gesture.state = GESTURE_NOT_STARTED;
+          }
+     }
+
+end:
+   // if no finger is touching a screen, gesture will be reseted.
+   if ((cov->flick_gesture.state == GESTURE_ABORTED) && (cov->n_taps == 0))
+     {
+        DEBUG("Restet flick gesture");
+        cov->flick_gesture.state = GESTURE_NOT_STARTED;
+     }
+}
+
+static void
+_flick_gesture_mouse_move(Ecore_Event_Mouse_Move *ev, Cover *cov)
+{
+   if (cov->flick_gesture.state == GESTURE_ONGOING)
+      {
+         int i;
+         for(i = 0; i < cov->flick_gesture.n_fingers; ++i)
+            {
+               if (cov->flick_gesture.finger[i] == ev->multi.device)
+               break;
+            }
+         if (i == cov->flick_gesture.n_fingers)
+          {
+             if (cov->flick_gesture.n_fingers >= 3) //that is because of the EFL bug. Mouse move event before mouse down(!)
+               {
+                  ERROR("Finger id not recognized. Gesture aborted.");
+                  cov->flick_gesture.state = GESTURE_ABORTED;
+                  return;
+               }
+          }
+         if(!cov->flick_gesture.finger_out[i])
+            {
+               int dx = ev->root.x - cov->flick_gesture.x_org[i];
+               int dy = ev->root.y - cov->flick_gesture.y_org[i];
+
+               if (dx < 0) dx *= -1;
+              if (dy < 0) dy *= -1;
+
+              if (dx > _e_mod_config->one_finger_flick_min_length)
+                  {
+                     cov->flick_gesture.finger_out[i] = EINA_TRUE;
+                     if (ev->root.x > cov->flick_gesture.x_org[i])
+                        {
+                           if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+                                 cov->flick_gesture.dir == FLICK_DIRECTION_RIGHT_RETURN)
+                              {
+                                 cov->flick_gesture.dir = FLICK_DIRECTION_RIGHT_RETURN;
+                              }
+                           else
+                              {
+                                 ERROR("Invalid direction, abort");
+                                 cov->flick_gesture.state = GESTURE_ABORTED;
+                              }
+                        }
+                     else
+                        {
+                           if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+                                 cov->flick_gesture.dir == FLICK_DIRECTION_LEFT_RETURN)
+                              {
+                                 cov->flick_gesture.dir = FLICK_DIRECTION_LEFT_RETURN;
+                              }
+                           else
+                              {
+                                 ERROR("Invalid direction, abort");
+                                 cov->flick_gesture.state = GESTURE_ABORTED;
+                              }
+                        }
+                     return;
+                  }
+
+               else if (dy > _e_mod_config->one_finger_flick_min_length)
+                  {
+                     cov->flick_gesture.finger_out[i] = EINA_TRUE;
+                     if (ev->root.y > cov->flick_gesture.y_org[i])
+                        {
+                           if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+                                 cov->flick_gesture.dir == FLICK_DIRECTION_DOWN_RETURN)
+                              {
+                                 cov->flick_gesture.dir = FLICK_DIRECTION_DOWN_RETURN;
+                              }
+                           else
+                              {
+                                 ERROR("Invalid direction, abort");
+                                 cov->flick_gesture.state = GESTURE_ABORTED;
+                              }
+                        }
+                     else
+                        {
+                           if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED ||
+                                 cov->flick_gesture.dir == FLICK_DIRECTION_UP_RETURN)
+                              {
+                                 cov->flick_gesture.dir = FLICK_DIRECTION_UP_RETURN;
+                              }
+                           else
+                              {
+                                 ERROR("Invalid direction, abort");
+                                 cov->flick_gesture.state = GESTURE_ABORTED;
+                              }
+                        }
+                     return;
+                  }
+            }
+      }
+   return;
+}
+
+static Eina_Bool
+_on_hover_timeout(void *data)
+{
+   Cover *cov = data;
+   DEBUG("Hover timer expierd");
+
+   cov->hover_gesture.longpressed = EINA_TRUE;
+   cov->hover_gesture.timer = NULL;
+
+   if (cov->hover_gesture.last_emission_time == -1)
+     {
+        _hover_event_emit(cov, 0);
+        cov->hover_gesture.last_emission_time = cov->event_time;
+     }
+   return EINA_FALSE;
+}
+
+static void
+_hover_gesture_timer_reset(Cover *cov, double time)
+{
+   DEBUG("Hover timer reset");
+   cov->hover_gesture.longpressed = EINA_FALSE;
+   if (cov->hover_gesture.timer)
+     {
+        ecore_timer_reset(cov->hover_gesture.timer);
+        return;
+     }
+   cov->hover_gesture.timer = ecore_timer_add(time, _on_hover_timeout, cov);
+}
+
+static void
+_hover_gesture_mouse_down(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->hover_gesture.state == GESTURE_NOT_STARTED &&
+       cov->n_taps == 1)
+     {
+        cov->hover_gesture.state = GESTURE_ONGOING;
+        cov->hover_gesture.timestamp = ev->timestamp;
+        cov->hover_gesture.last_emission_time = -1;
+        cov->hover_gesture.x[0] = ev->root.x;
+        cov->hover_gesture.y[0] = ev->root.y;
+        cov->hover_gesture.finger[0] = ev->multi.device;
+        cov->hover_gesture.n_fingers = 1;
+        _hover_gesture_timer_reset(cov, _e_mod_config->one_finger_hover_longpress_timeout);
+     }
+   if (cov->hover_gesture.state == GESTURE_ONGOING &&
+       cov->n_taps == 2)
+     {
+        if (cov->hover_gesture.longpressed)
+          {
+             _hover_event_emit(cov, 2);
+             goto abort;
+          }
+        cov->hover_gesture.timestamp = -1;
+        cov->hover_gesture.last_emission_time = -1;
+        cov->hover_gesture.x[1] = ev->root.x;
+        cov->hover_gesture.y[1] = ev->root.y;
+        cov->hover_gesture.finger[1] = ev->multi.device;
+        cov->hover_gesture.n_fingers = 2;
+        cov->hover_gesture.longpressed = EINA_TRUE;
+        if (cov->hover_gesture.timer)
+          ecore_timer_del(cov->hover_gesture.timer);
+        cov->hover_gesture.timer = NULL;
+        _hover_event_emit(cov, 0);
+     }
+   // abort gesture if more then 2 fingers touched screen
+   if ((cov->hover_gesture.state == GESTURE_ONGOING) &&
+       cov->n_taps > 2)
+     {
+        DEBUG("More then 2 finged. Abort hover gesture");
+        _hover_event_emit(cov, 2);
+        goto abort;
+     }
+   return;
+
+abort:
+   cov->hover_gesture.state = GESTURE_ABORTED;
+   if (cov->hover_gesture.timer)
+     ecore_timer_del(cov->hover_gesture.timer);
+   cov->hover_gesture.timer = NULL;
+}
+
+static void
+_hover_gesture_mouse_up(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   int i;
+   if (cov->hover_gesture.state == GESTURE_ONGOING)
+     {
+
+        for (i = 0; i < cov->hover_gesture.n_fingers; i++)
+          {
+             if (cov->hover_gesture.finger[i] == ev->multi.device)
+              break;
+          }
+        if (i == cov->hover_gesture.n_fingers)
+          {
+             DEBUG("Invalid finger id: %d", ev->multi.device);
+             return;
+          }
+        else
+          {
+             cov->hover_gesture.state = GESTURE_ABORTED;
+             if (cov->hover_gesture.timer)
+               ecore_timer_del(cov->hover_gesture.timer);
+             cov->hover_gesture.timer = NULL;
+             // aditionally emit event to complete sequence
+             if (cov->hover_gesture.longpressed)
+                _hover_event_emit(cov, 2);
+          }
+     }
+   // reset gesture only if user released all his fingers
+   if (cov->n_taps == 0)
+     cov->hover_gesture.state = GESTURE_NOT_STARTED;
+}
+
+static void
+_hover_event_emit(Cover *cov, int state)
+{
+   DEBUG("Emit hover event");
+   int ax = 0, ay = 0, j;
+   for (j = 0; j < cov->hover_gesture.n_fingers; j++)
+     {
+        ax += cov->hover_gesture.x[j];
+        ay += cov->hover_gesture.y[j];
+     }
+
+   ax /= cov->hover_gesture.n_fingers;
+   ay /= cov->hover_gesture.n_fingers;
+
+   switch (cov->hover_gesture.n_fingers)
+     {
+      case 1:
+         _event_emit(ONE_FINGER_HOVER, ax, ay, ax, ay, state);
+         break;
+      case 2:
+         _event_emit(TWO_FINGERS_HOVER, ax, ay, ax, ay, state);
+         break;
+      default:
+         break;
+     }
+}
+
+static void
+_hover_gesture_mouse_move(Ecore_Event_Mouse_Move *ev, Cover *cov)
+{
+   if (cov->hover_gesture.state == GESTURE_ONGOING)
+     {
+        // check fingers
+        int i;
+        if (!cov->hover_gesture.longpressed)
+          return;
+
+        for (i = 0; i < cov->hover_gesture.n_fingers; i++)
+          {
+             if (cov->hover_gesture.finger[i] == ev->multi.device)
+               break;
+          }
+        if (i == cov->hover_gesture.n_fingers)
+          {
+             DEBUG("Invalid finger id: %d", ev->multi.device);
+             return;
+          }
+          cov->hover_gesture.x[i] = ev->root.x;
+          cov->hover_gesture.y[i] = ev->root.y;
+          _hover_event_emit(cov, 1);
+      }
+}
+
+static void
+_tap_event_emit(Cover *cov)
+{
+   switch (cov->tap_gesture_data.n_taps)
+     {
+      case 1:
+         if(cov->tap_gesture_data.tap_type == ONE_FINGER_GESTURE)
+            {
+               DEBUG("ONE_FINGER_SINGLE_TAP");
+               _event_emit(ONE_FINGER_SINGLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
+            {
+               DEBUG("TWO_FINGERS_SINGLE_TAP");
+               _event_emit(TWO_FINGERS_SINGLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
+            {
+               DEBUG("THREE_FINGERS_SINGLE_TAP");
+               _event_emit(THREE_FINGERS_SINGLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2],
+                     2);
+            }
+         else
+            {
+               ERROR("Unknown tap");
+            }
+         break;
+      case 2:
+         if(cov->tap_gesture_data.tap_type == ONE_FINGER_GESTURE)
+            {
+               DEBUG("ONE_FINGER_DOUBLE_TAP");
+               _event_emit(ONE_FINGER_DOUBLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
+            {
+               DEBUG("TWO_FINGERS_DOUBLE_TAP");
+               _event_emit(TWO_FINGERS_DOUBLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
+            {
+               DEBUG("THREE_FINGERS_DOUBLE_TAP");
+               _event_emit(THREE_FINGERS_DOUBLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2],
+                     2);
+            }
+         else
+            {
+               ERROR("Unknown tap");
+            }
+         break;
+      case 3:
+         if(cov->tap_gesture_data.tap_type == ONE_FINGER_GESTURE)
+            {
+               DEBUG("ONE_FINGER_TRIPLE_TAP");
+               _event_emit(ONE_FINGER_TRIPLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
+            {
+               DEBUG("TWO_FINGERS_TRIPLE_TAP");
+               _event_emit(TWO_FINGERS_TRIPLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1],
+                     2);
+            }
+         else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
+            {
+               DEBUG("THREE_FINGERS_TRIPLE_TAP");
+               _event_emit(THREE_FINGERS_TRIPLE_TAP,
+                     cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0],
+                     cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2],
+                     2);
+            }
+         else
+            {
+               ERROR("Unknown tap");
+            }
+         break;
+      default:
+         ERROR("Unknown tap");
+         break;
+     }
+}
+
+static Eina_Bool
+_on_tap_timer_expire(void *data)
+{
+   Cover *cov = data;
+   DEBUG("Timer expired");
+
+   if (cov->tap_gesture_data.started && !cov->tap_gesture_data.pressed)
+     _tap_event_emit(cov);
+
+   // finish gesture
+   cov->tap_gesture_data.started = EINA_FALSE;
+   cov->tap_gesture_data.timer = NULL;
+   cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
+   cov->tap_gesture_data.finger[0] = -1;
+   cov->tap_gesture_data.finger[1] = -1;
+   cov->tap_gesture_data.finger[2] = -1;
+
+   return EINA_FALSE;
+}
+
+static int _tap_gesture_finger_check(Cover *cov, int x, int y)
+{
+   int dx = x - cov->tap_gesture_data.x_org[0];
+   int dy = y - cov->tap_gesture_data.y_org[0];
+
+   if (cov->tap_gesture_data.finger[0] != -1 &&
+         (dx * dx + dy * dy < _e_mod_config->one_finger_tap_radius *
+         _e_mod_config->one_finger_tap_radius))
+      {
+         return 0;
+      }
+
+   dx = x - cov->tap_gesture_data.x_org[1];
+   dy = y - cov->tap_gesture_data.y_org[1];
+   if (cov->tap_gesture_data.finger[1] != -1 &&
+            (dx * dx + dy * dy < _e_mod_config->one_finger_tap_radius *
+            _e_mod_config->one_finger_tap_radius))
+      {
+         return 1;
+      }
+
+   dx = x - cov->tap_gesture_data.x_org[2];
+   dy = y - cov->tap_gesture_data.y_org[2];
+   if (cov->tap_gesture_data.finger[2] != -1 &&
+            (dx * dx + dy * dy < _e_mod_config->one_finger_tap_radius *
+            _e_mod_config->one_finger_tap_radius))
+      {
+         return 2;
+      }
+
+   return -1;
+}
+
+static void
+_tap_gestures_mouse_down(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->n_taps > 4)
+      {
+         ERROR("Too many fingers");
+         return;
+      }
+
+   cov->tap_gesture_data.pressed = EINA_TRUE;
+
+   if (cov->tap_gesture_data.started == EINA_FALSE)
+      {
+         DEBUG("First finger down");
+         cov->tap_gesture_data.started = EINA_TRUE;
+         cov->tap_gesture_data.finger[0] = ev->multi.device;
+         cov->tap_gesture_data.x_org[0] = ev->root.x;
+         cov->tap_gesture_data.y_org[0] = ev->root.y;
+         cov->tap_gesture_data.finger[1] = -1;
+         cov->tap_gesture_data.finger[2] = -1;
+         cov->tap_gesture_data.n_taps = 0;
+         cov->tap_gesture_data.timer = ecore_timer_add(
+                                           _e_mod_config->one_finger_tap_timeout,
+                                           _on_tap_timer_expire, cov);
+         cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
+      }
+
+   else
+      {
+         if (ev->multi.device == cov->tap_gesture_data.finger[0])
+            {
+               DEBUG("First finger down");
+
+               if (_tap_gesture_finger_check(cov, ev->root.x, ev->root.y) == -1)
+                  {
+                     ERROR("Abort gesture");
+                     cov->tap_gesture_data.started = EINA_FALSE;
+                     ecore_timer_del(cov->tap_gesture_data.timer);
+                     cov->tap_gesture_data.timer = NULL;
+                     cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
+                     cov->tap_gesture_data.finger[0] = -1;
+                     cov->tap_gesture_data.finger[1] = -1;
+                     cov->tap_gesture_data.finger[2] = -1;
+                     _tap_gestures_mouse_down(ev, cov);
+                     return;
+                  }
+
+               cov->tap_gesture_data.x_org[0] = ev->root.x;
+               cov->tap_gesture_data.y_org[0] = ev->root.y;
+            }
+         else if (cov->tap_gesture_data.finger[1] == -1 ||
+                  cov->tap_gesture_data.finger[1] == ev->multi.device)
+            {
+               DEBUG("Second finger down");
+               cov->tap_gesture_data.finger[1] = ev->multi.device;
+
+               cov->tap_gesture_data.x_org[1] = ev->root.x;
+               cov->tap_gesture_data.y_org[1] = ev->root.y;
+               if (cov->tap_gesture_data.tap_type < TWO_FINGERS_GESTURE)
+                  cov->tap_gesture_data.tap_type = TWO_FINGERS_GESTURE;
+            }
+         else if (cov->tap_gesture_data.finger[2] == -1 ||
+                  cov->tap_gesture_data.finger[2] == ev->multi.device)
+            {
+               DEBUG("Third finger down");
+               cov->tap_gesture_data.finger[2] = ev->multi.device;
+
+               cov->tap_gesture_data.x_org[2] = ev->root.x;
+               cov->tap_gesture_data.y_org[2] = ev->root.y;
+               if (cov->tap_gesture_data.tap_type < THREE_FINGERS_GESTURE)
+                  cov->tap_gesture_data.tap_type = THREE_FINGERS_GESTURE;
+            }
+         else
+            {
+               ERROR("Unknown finger down");
+            }
+         ecore_timer_reset(cov->tap_gesture_data.timer);
+      }
+}
+
+static void
+_tap_gestures_mouse_up(Ecore_Event_Mouse_Button *ev, Cover *cov)
+{
+   if (cov->tap_gesture_data.timer)
+      {
+         cov->tap_gesture_data.pressed = EINA_FALSE;
+
+         if (ev->multi.device == cov->tap_gesture_data.finger[0])
+            {
+               DEBUG("First finger up");
+
+               int dx = ev->root.x - cov->tap_gesture_data.x_org[0];
+               int dy = ev->root.y - cov->tap_gesture_data.y_org[0];
+
+               if((dx * dx + dy * dy) < _e_mod_config->one_finger_tap_radius *
+                     _e_mod_config->one_finger_tap_radius)
+                  {
+                     if (cov->n_taps == 0)
+                        {
+                           cov->tap_gesture_data.n_taps++;
+                        }
+                  }
+               else
+                  {
+                     ERROR("Abort gesture");
+                     cov->tap_gesture_data.started = EINA_FALSE;
+                  }
+            }
+         else if (ev->multi.device == cov->tap_gesture_data.finger[1])
+            {
+               DEBUG("Second finger up");
+
+               int dx = ev->root.x - cov->tap_gesture_data.x_org[1];
+               int dy = ev->root.y - cov->tap_gesture_data.y_org[1];
+
+               if((dx * dx + dy * dy) < _e_mod_config->one_finger_tap_radius *
+                     _e_mod_config->one_finger_tap_radius)
+                  {
+                     if (cov->n_taps == 0)
+                        {
+                           cov->tap_gesture_data.n_taps++;
+                        }
+                  }
+               else
+                  {
+                     ERROR("Abort gesture");
+                     cov->tap_gesture_data.started = EINA_FALSE;
+                  }
+            }
+         else if (ev->multi.device == cov->tap_gesture_data.finger[2])
+            {
+               DEBUG("Third finger up");
+
+               int dx = ev->root.x - cov->tap_gesture_data.x_org[2];
+               int dy = ev->root.y - cov->tap_gesture_data.y_org[2];
+
+               if((dx * dx + dy * dy) < _e_mod_config->one_finger_tap_radius *
+                     _e_mod_config->one_finger_tap_radius)
+                  {
+                     if (cov->n_taps == 0)
+                        {
+                           cov->tap_gesture_data.n_taps++;
+                        }
+                  }
+               else
+                  {
+                     ERROR("Abort gesture");
+                     cov->tap_gesture_data.started = EINA_FALSE;
+                  }
+            }
+         else
+            {
+               ERROR("Unknown finger up, abort gesture");
+               cov->tap_gesture_data.started = EINA_FALSE;
+            }
+      }
+}
+
+static void
+_tap_gestures_move(Ecore_Event_Mouse_Move *ev, Cover *cov)
+{
+   if(_tap_gesture_finger_check(cov, ev->root.x, ev->root.y) == -1)
+   {
+       ERROR("Abort gesture");
+       cov->tap_gesture_data.started = EINA_FALSE;
+       ecore_timer_del(cov->tap_gesture_data.timer);
+       cov->tap_gesture_data.timer = NULL;
+       cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
+       cov->tap_gesture_data.finger[0] = -1;
+       cov->tap_gesture_data.finger[1] = -1;
+       cov->tap_gesture_data.finger[2] = -1;
+       return;
+   }
+}
+
+static Eina_Bool
+_cb_mouse_down(void    *data EINA_UNUSED,
+               int      type EINA_UNUSED,
+               void    *event)
+{
+   Ecore_Event_Mouse_Button *ev = event;
+
+   cover->n_taps++;
+   cover->event_time = ev->timestamp;
+
+   DEBUG("single mouse down: taps: %d Multi :%d", cover->n_taps,ev->multi.device);
+
+   _flick_gesture_mouse_down(ev, cover);
+   _hover_gesture_mouse_down(ev, cover);
+   _tap_gestures_mouse_down(ev, cover);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_mouse_up(void    *data EINA_UNUSED,
+             int      type EINA_UNUSED,
+             void    *event)
+{
+   Ecore_Event_Mouse_Button *ev = event;
+
+   cover->n_taps--;
+   cover->event_time = ev->timestamp;
+
+   DEBUG("single mouse up,taps: %d Multi :%d", cover->n_taps,ev->multi.device);
+
+   _flick_gesture_mouse_up(ev, cover);
+   _hover_gesture_mouse_up(ev, cover);
+   _tap_gestures_mouse_up(ev, cover);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_mouse_move(void    *data EINA_UNUSED,
+               int      type EINA_UNUSED,
+               void    *event)
+{
+   Ecore_Event_Mouse_Move *ev = event;
+
+   cover->event_time = ev->timestamp;
+
+   _flick_gesture_mouse_move(ev, cover);
+   _hover_gesture_mouse_move(ev, cover);
+   _tap_gestures_move(ev, cover);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_events_init(void)
+{
+#define HANDLER_APPEND(event, cb) \
+   handlers = eina_list_append( \
+      handlers, ecore_event_handler_add(event, cb, NULL));
+   HANDLER_APPEND(ECORE_EVENT_MOUSE_BUTTON_DOWN, _cb_mouse_down);
+   HANDLER_APPEND(ECORE_EVENT_MOUSE_BUTTON_UP, _cb_mouse_up);
+   HANDLER_APPEND(ECORE_EVENT_MOUSE_MOVE, _cb_mouse_move);
+#undef APPEND_HANDLER
+
+   if (!E_EVENT_ATSPI_GESTURE_DETECTED)
+      E_EVENT_ATSPI_GESTURE_DETECTED = ecore_event_type_new();
+}
+
+static void
+_events_shutdown(void)
+{
+   E_FREE_LIST(handlers, ecore_event_handler_del);
+}
+
+static Evas_Object *gesture_rectangle;
+
+static void
+_resize_canvas_gesture(Ecore_Evas *ee EINA_UNUSED)
+{
+   int x, y, w, h;
+   ecore_evas_geometry_get(e_comp->ee, &x, &y, &w, &h);
+   DEBUG("Resizing to x: %i, y: %i, w: %i, h:%i", x, y, w, h);
+   // For testing purpose
+   evas_object_geometry_set(gesture_rectangle, x, y, 600,800);
+
+   //evas_object_geometry_set(gesture_rectangle, x, y, w, h);
+}
+
+static void
+_gesture_init()
+{
+   DEBUG("Gesture Rect Creation init.");
+
+   cover = E_NEW(Cover, 1);
+   if (!cover)
+     {
+        ERROR("Fatal Memory error!");
+        return;
+     }
+
+   gesture_rectangle = evas_object_rectangle_add(e_comp->evas);
+   evas_object_layer_set(gesture_rectangle, E_LAYER_MAX);
+   evas_object_repeat_events_set(gesture_rectangle, EINA_FALSE);
+   _resize_canvas_gesture(NULL);
+   evas_object_color_set(gesture_rectangle, 0, 255, 0, 100);
+   evas_object_show(gesture_rectangle);
+   cover->gesture_rect = gesture_rectangle;
+   ecore_evas_callback_resize_set(e_comp->ee, _resize_canvas_gesture);
+}
+
+static void
+_gesture_shutdown(void)
+{
+   evas_object_del(cover->gesture_rect);
+   gesture_rectangle = NULL;
+   if (cover->tap_gesture_data.timer)
+     ecore_timer_del(cover->tap_gesture_data.timer);
+   if (cover->hover_gesture.timer)
+     ecore_timer_del(cover->hover_gesture.timer);
+   free(cover);
+}
+
+int _e_mod_atspi_gestures_init(void)
+{
+   DEBUG("gesture init");
+   _gesture_init();
+   _events_init();
+
+   return 0;
+}
+
+int _e_mod_atspi_gestures_shutdown(void)
+{
+   DEBUG("gesture shutdown");
+
+   _events_shutdown();
+   _gesture_shutdown();
+
+   return 0;
+}
diff --git a/src/e_screen_reader_private.h b/src/e_screen_reader_private.h
new file mode 100644 (file)
index 0000000..1f2d7f4
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef E_SCREEN_READER_PRIVATE_H_
+#define E_SCREEN_READER_PRIVATE_H_
+
+#include "e.h"
+#include "e_screen_reader_config.h"
+#include "e_comp.h"
+
+extern int _eina_log_dom;
+
+#define INFO(...) EINA_LOG_DOM_INFO(_eina_log_dom, __VA_ARGS__);
+#define DEBUG(...) EINA_LOG_DOM_DBG(_eina_log_dom, __VA_ARGS__);
+#define ERROR(...) EINA_LOG_DOM_ERR(_eina_log_dom, __VA_ARGS__);
+
+/**
+ * @brief Accessibility gestures
+ */
+enum _Gesture {
+     ONE_FINGER_HOVER,
+     TWO_FINGERS_HOVER,
+     THREE_FINGERS_HOVER,
+     ONE_FINGER_FLICK_LEFT,
+     ONE_FINGER_FLICK_RIGHT,
+     ONE_FINGER_FLICK_UP,
+     ONE_FINGER_FLICK_DOWN,
+     TWO_FINGERS_FLICK_LEFT,
+     TWO_FINGERS_FLICK_RIGHT,
+     TWO_FINGERS_FLICK_UP,
+     TWO_FINGERS_FLICK_DOWN,
+     THREE_FINGERS_FLICK_LEFT,
+     THREE_FINGERS_FLICK_RIGHT,
+     THREE_FINGERS_FLICK_UP,
+     THREE_FINGERS_FLICK_DOWN,
+     ONE_FINGER_SINGLE_TAP,
+     ONE_FINGER_DOUBLE_TAP,
+     ONE_FINGER_TRIPLE_TAP,
+     TWO_FINGERS_SINGLE_TAP,
+     TWO_FINGERS_DOUBLE_TAP,
+     TWO_FINGERS_TRIPLE_TAP,
+     THREE_FINGERS_SINGLE_TAP,
+     THREE_FINGERS_DOUBLE_TAP,
+     THREE_FINGERS_TRIPLE_TAP,
+     ONE_FINGER_FLICK_LEFT_RETURN,
+     ONE_FINGER_FLICK_RIGHT_RETURN,
+     ONE_FINGER_FLICK_UP_RETURN,
+     ONE_FINGER_FLICK_DOWN_RETURN,
+     TWO_FINGERS_FLICK_LEFT_RETURN,
+     TWO_FINGERS_FLICK_RIGHT_RETURN,
+     TWO_FINGERS_FLICK_UP_RETURN,
+     TWO_FINGERS_FLICK_DOWN_RETURN,
+     THREE_FINGERS_FLICK_LEFT_RETURN,
+     THREE_FINGERS_FLICK_RIGHT_RETURN,
+     THREE_FINGERS_FLICK_UP_RETURN,
+     THREE_FINGERS_FLICK_DOWN_RETURN,
+     GESTURES_COUNT,
+};
+typedef enum _Gesture Gesture;
+
+typedef struct {
+     Gesture type;         // Type of recognized gesture
+     int x_beg, x_end;     // (x,y) coordinates when gesture begin
+     int y_beg, y_end;     // (x,y) coordinates when gesture ends
+     int state;            // 0 - begin, 1 - ongoing, 2 - ended
+} Gesture_Info;
+
+int _e_mod_log_init(void);
+void _e_mod_log_shutdown(void);
+
+extern int E_EVENT_ATSPI_GESTURE_DETECTED;
+
+int _e_mod_atspi_gestures_init(void);
+int _e_mod_atspi_gestures_shutdown(void);
+
+
+#endif /* E_SCREEN_READER_PRIVATE_H_ */