Slider support
authorPatryk Kaczmarek <patryk.k@samsung.com>
Fri, 26 Jun 2015 08:07:43 +0000 (10:07 +0200)
committerPatryk Kaczmarek <patryk.k@samsung.com>
Thu, 9 Jul 2015 15:36:31 +0000 (17:36 +0200)
   * Slider value can be changed by one finger flick up/down
   * Slider value can be changed by one finger double tap and hold
   * Slider value is spoken

Change-Id: I50d72268c95a0d84393ec02c5b965b699db42c24
Signed-off-by: Patryk Kaczmarek <patryk.k@samsung.com>
include/screen_reader_gestures.h
src/navigator.c
src/screen_reader_gestures.c

index ba82d05..f952466 100644 (file)
@@ -55,7 +55,7 @@ typedef struct
    int x_beg, x_end;     // (x,y) coordinates when gesture begin (screen coords)
    int y_beg, y_end;     // (x,y) coordinates when gesture ends (screen coords)
    pid_t pid;            // pid of process on which gesture took place.
-   int state;            // 0 - begin, 1 - ongoing, 2 - ended
+   int state;            // 0 - begin, 1 - ongoing, 2 - ended, 3 - aborted
 } Gesture_Info;
 
 /**
@@ -79,4 +79,19 @@ typedef void (*GestureCB)(void *data, Gesture_Info *info);
  */
 void screen_reader_gestures_tracker_register(GestureCB cb, void *data);
 
+/**
+ * @brief Start event emission
+ */
+void start_scroll(int x, int y);
+
+/**
+ * @brief Continue event emission
+ */
+void continue_scroll(int x, int y);
+
+/**
+ * @brief End event emit
+ */
+void end_scroll(int x, int y);
+
 #endif
index 27744cf..bb6bc07 100644 (file)
@@ -25,6 +25,7 @@
 #define MENU_ITEM_TAB_INDEX_SIZE 16
 #define HOVERSEL_TRAIT_SIZE 70
 #define TTS_MAX_TEXT_SIZE  2000
+#define GESTURE_LIMIT 10
 
 #define HOVERSEL_TRAIT "Dropdown list. Showing %d items. Double tap to open the menu."
 #define GROUP_INDEX_TRAIT "group index"
@@ -60,6 +61,8 @@ static AtspiAccessible *top_window;
 static Eina_Bool _window_cache_builded;
 static Eina_Bool _window_top_changed;
 static FlatNaviContext *context;
+static bool prepared = false;
+static int counter=0;
 
 static struct
 {
@@ -183,12 +186,19 @@ display_info_about_object(AtspiAccessible *obj)
    AtspiStateSet *st = atspi_accessible_get_state_set (obj);
    GArray *states = atspi_state_set_get_states (st);
    AtspiComponent *comp = atspi_accessible_get_component_iface(obj);
+   AtspiValue *value = atspi_accessible_get_value_iface(obj);
 
    DEBUG("NAME:%s", name);
    DEBUG("ROLE:%s", role)
    DEBUG("DESCRIPTION:%s", description);
    DEBUG("CHILDS:%d", atspi_accessible_get_child_count(obj, NULL));
    DEBUG("HIGHLIGHT_INDEX:%d", atspi_component_get_highlight_index(comp, NULL));
+   if (value)
+      {
+         DEBUG("VALUE:%f", atspi_value_get_current_value (value, NULL));
+         DEBUG("VALUE MAX:%f", atspi_value_get_maximum_value (value, NULL));
+         DEBUG("VALUE MIN:%f", atspi_value_get_minimum_value (value, NULL));
+      }
    DEBUG("STATES:");
    int a;
    AtspiStateType stat;
@@ -921,133 +931,79 @@ static void _caret_move_backward(void)
    return;
 }
 
-#if 0
-static void _value_inc_widget(void)
+static void _read_value( AtspiValue *value)
+{
+   if (!value)
+      return;
+
+   gdouble current_val = atspi_value_get_current_value(value, NULL);
+   gdouble max_val = atspi_value_get_maximum_value (value, NULL);
+   gdouble min_val = atspi_value_get_minimum_value (value, NULL);
+
+   int proc = (current_val/fabs(max_val-min_val)) * 100;
+
+   char buf[256] = "\0";
+   snprintf(buf, sizeof(buf), "%d percent", proc);
+   DEBUG("has value %s", buf);
+   tts_speak(strdup(buf), EINA_TRUE);
+}
+
+static void _value_inc(void)
 {
    AtspiAccessible* current_widget = NULL;
-   AtspiText *text_interface;
-   gint current_offset;
-   gboolean ret;
    GError *err = NULL;
-   gchar *role;
 
    if(!current_obj)
       return;
 
    current_widget = current_obj;
 
-   role = atspi_accessible_get_role_name(current_widget, &err);
-   if (!role)
-      {
-         ERROR("The role is null");
-         return;
-      }
-   GERROR_CHECK(err)
-
-   if(!strcmp(role, "entry"))
-      {
-         text_interface = atspi_accessible_get_text_iface(current_widget);
-         if(text_interface)
-            {
-               current_offset = atspi_text_get_caret_offset(text_interface, &err);
-               GERROR_CHECK(err)
-               ret = atspi_text_set_caret_offset(text_interface, current_offset + 1, &err);
-               GERROR_CHECK(err)
-               if(ret)
-                  {
-                     ERROR("Caret position increment done");
-                  }
-               else
-                  {
-                     ERROR("Caret position increment error");
-                  }
-            }
-         else
-            ERROR("No text interface supported!");
-         g_free(role);
-         return;
-      }
-   g_free(role);
    AtspiValue *value_interface = atspi_accessible_get_value_iface(current_widget);
    if(value_interface)
       {
-         ERROR("Value interface supported!\n");
+         DEBUG("Value interface supported!\n");
          gdouble current_val = atspi_value_get_current_value(value_interface, &err);
          GERROR_CHECK(err)
-         ERROR("Current value: %f\n ", (double)current_val);
+         DEBUG("Current value: %f\n ", (double)current_val);
          gdouble minimum_inc = atspi_value_get_minimum_increment(value_interface, &err);
-         ERROR("Minimum increment: %f\n ", (double)minimum_inc);
+         DEBUG("Minimum increment: %f\n ", (double)minimum_inc);
          GERROR_CHECK(err)
          atspi_value_set_current_value(value_interface, current_val + minimum_inc, &err);
          GERROR_CHECK(err)
+         _read_value(value_interface);
+         g_object_unref(value_interface);
+         return;
       }
-   else
-      ERROR("No value interface supported!\n");
+   ERROR("No value interface supported!\n");
 }
 
-static void _value_dec_widget(void)
+static void _value_dec(void)
 {
    AtspiAccessible* current_widget = NULL;
-   AtspiText *text_interface;
-   gint current_offset;
    GError *err = NULL;
-   gboolean ret;
-   gchar *role;
 
    if(!current_obj)
       return;
    current_widget = current_obj;
 
-   role = atspi_accessible_get_role_name(current_widget, &err);
-   if (!role)
-      {
-         ERROR("The role is null");
-         return;
-      }
-   GERROR_CHECK(err)
-
-   if(!strcmp(role, "entry"))
-      {
-         text_interface = atspi_accessible_get_text_iface(current_widget);
-         if(text_interface)
-            {
-               current_offset = atspi_text_get_caret_offset(text_interface, &err);
-               GERROR_CHECK(err)
-               ret = atspi_text_set_caret_offset(text_interface, current_offset - 1, &err);
-               GERROR_CHECK(err)
-               if(ret)
-                  {
-                     ERROR("Caret position decrement done");
-                  }
-               else
-                  {
-                     ERROR("Caret position decrement error");
-                  }
-            }
-         else
-            ERROR("No text interface supported!");
-         g_free(role);
-         return;
-      }
-   g_free(role);
-
    AtspiValue *value_interface = atspi_accessible_get_value_iface(current_widget);
    if(value_interface)
       {
-         ERROR("Value interface supported!\n");
+         DEBUG("Value interface supported!\n");
          gdouble current_val = atspi_value_get_current_value(value_interface, &err);
          GERROR_CHECK(err)
-         ERROR("Current value: %f\n ", (double)current_val);
+         DEBUG("Current value: %f\n ", (double)current_val);
          gdouble minimum_inc = atspi_value_get_minimum_increment(value_interface, &err);
          GERROR_CHECK(err)
-         ERROR("Minimum increment: %f\n ", (double)minimum_inc);
+         DEBUG("Minimum increment: %f\n ", (double)minimum_inc);
          atspi_value_set_current_value(value_interface, current_val - minimum_inc, &err);
          GERROR_CHECK(err)
+         _read_value(value_interface);
+         g_object_unref(value_interface);
+         return;
       }
-   else
-      ERROR("No value interface supported!\n");
+   ERROR("No value interface supported!\n");
 }
-#endif
 
 static bool
 _check_if_widget_is_enabled(AtspiAccessible *obj)
@@ -1708,6 +1664,31 @@ _direct_scroll_to_last(void)
 }
 
 static Eina_Bool
+_has_value(void)
+{
+   DEBUG("START");
+   AtspiAccessible *obj = NULL;
+
+   if(!current_obj)
+      return EINA_FALSE;
+
+   obj = current_obj;
+
+   if (!obj)
+      return EINA_FALSE;
+
+   AtspiValue *value = atspi_accessible_get_value_iface(obj);
+
+   if (value)
+      {
+         g_object_unref(value);
+         return EINA_TRUE;
+      }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
 _is_active_entry(void)
 {
    DEBUG("START");
@@ -1741,15 +1722,131 @@ _is_active_entry(void)
    DEBUG("END");
 }
 
+static Eina_Bool
+_is_slider(AtspiAccessible *obj)
+{
+   DEBUG("START");
+
+   if (!obj)
+      return EINA_FALSE;
+
+   AtspiRole role;
+
+   role = atspi_accessible_get_role(obj, NULL);
+   if (role == ATSPI_ROLE_SLIDER)
+      {
+         return EINA_TRUE;
+      }
+   return EINA_FALSE;
+}
+
+static void
+_move_slider(Gesture_Info *gi)
+{
+   DEBUG("ONE FINGER DOUBLE TAP AND HOLD");
+
+   if (!context)
+      {
+         ERROR("No navigation context created");
+         return;
+      }
+
+   AtspiAccessible *obj = NULL;
+   AtspiValue *value = NULL;
+   AtspiComponent *comp = NULL;
+   AtspiRect *rect = NULL;
+   int click_point_x = 0;
+   int click_point_y = 0;
+
+   obj = current_obj;
+
+   if (!obj)
+      {
+         DEBUG("no object");
+         return;
+      }
+
+   if (!_is_slider(obj))
+      {
+         ERROR("Object is not a slider");
+         return;
+      }
+
+   if (gi->state == 0)
+      {
+         comp = atspi_accessible_get_component_iface(obj);
+         if (!comp)
+            {
+               ERROR("that slider do not have component interface");
+               return;
+            }
+
+         rect = atspi_component_get_extents(comp, ATSPI_COORD_TYPE_SCREEN, NULL);
+
+         DEBUG("Current object is in:%d %d", rect->x, rect->y);
+         DEBUG("Current object has size:%d %d", rect->width, rect->height);
+
+         click_point_x = rect->x+rect->width/2;
+         click_point_y = rect->y+rect->height/2;
+         DEBUG("Click on point %d %d", click_point_x, click_point_y);
+         start_scroll(click_point_x, click_point_y);
+      }
+
+   if (gi->state == 1)
+      {
+         counter ++;
+         DEBUG("SCROLLING but not meet counter:%d", counter)
+         if (counter >= GESTURE_LIMIT)
+            {
+               counter = 0;
+               DEBUG("Scroll on point %d %d", gi->x_end, gi->y_end);
+               continue_scroll(gi->x_end, gi->y_end);
+            }
+      }
+
+   if (gi->state == 2)
+      {
+         DEBUG("state == 2");
+         end_scroll(gi->x_end, gi->y_end);
+         prepared = false;
+         value = atspi_accessible_get_value_iface(obj);
+         if (value)
+            {
+               _read_value(value);
+               g_object_unref(value);
+            }
+         else
+            {
+               ERROR("There is not value interface in slider");
+            }
+      }
+   DEBUG("END");
+}
+
 static void on_gesture_detected(void *data, Gesture_Info *info)
 {
    dbus_gesture_adapter_emit(info);
    _on_auto_review_stop();
 
+   if (info->type == ONE_FINGER_SINGLE_TAP && info->state == 3)
+      {
+         DEBUG("One finger single tap aborted");
+         prepared = true;
+      }
+
    switch(info->type)
       {
       case ONE_FINGER_HOVER:
-         _focus_widget(info);
+         if (prepared)
+            {
+               DEBUG("Prepare to move slider");
+               _move_slider(info);
+            }
+         else
+            {
+               DEBUG("Will focus on object, slider is not ready");
+               _focus_widget(info);
+            }
          break;
       case TWO_FINGERS_HOVER:
          _widget_scroll(info);
@@ -1763,17 +1860,22 @@ static void on_gesture_detected(void *data, Gesture_Info *info)
       case ONE_FINGER_FLICK_UP:
          if (_is_active_entry())
             _caret_move_backward();
+         else if (_has_value())
+            _value_inc();
          else
             _focus_prev();
          break;
       case ONE_FINGER_FLICK_DOWN:
          if (_is_active_entry())
             _caret_move_forward();
+         else if(_has_value())
+            _value_dec();
          else
             _focus_next();
          break;
       case ONE_FINGER_SINGLE_TAP:
-         _focus_widget(info);
+         if (!prepared)
+            _focus_widget(info);
          break;
       case ONE_FINGER_DOUBLE_TAP:
          _activate_widget();
index 038e6c5..4a4658a 100644 (file)
@@ -609,8 +609,8 @@ static void _get_root_coords(Ecore_X_Window win, int *x, int *y)
       }
 }
 
-static void
-_start_scroll(int x, int y)
+void
+start_scroll(int x, int y)
 {
    Ecore_X_Window under = ecore_x_window_at_xy_get(x, y);
    _get_root_coords(under, &rx, &ry);
@@ -621,15 +621,15 @@ _start_scroll(int x, int y)
    scrolled_win = under;
 }
 
-static void
-_continue_scroll(int x, int y)
+void
+continue_scroll(int x, int y)
 {
    DEBUG("Send move: %d %d", x - rx, y - ry);
    ecore_x_mouse_move_send(scrolled_win, x - rx, y - ry);
 }
 
-static void
-_end_scroll(int x, int y)
+void
+end_scroll(int x, int y)
 {
    DEBUG("Send up: %d %d", x - rx, y - ry);
    ecore_x_mouse_up_send(scrolled_win, x - rx, y - ry, 1);
@@ -659,11 +659,11 @@ _hover_event_emit(Cover *cov, int state)
          INFO("TWO FINGERS HOVER");
          _event_emit(TWO_FINGERS_HOVER, ax, ay, ax, ay, state);
          if (state == 0)
-            _start_scroll(ax, ay);
+            start_scroll(ax, ay);
          else if (state == 1)
-            _continue_scroll(ax, ay);
+            continue_scroll(ax, ay);
          else if (state == 2)
-            _end_scroll(ax, ay);
+            end_scroll(ax, ay);
          break;
       default:
          break;
@@ -697,7 +697,7 @@ _hover_gesture_mouse_move(Ecore_Event_Mouse_Move *ev, Cover *cov)
 }
 
 static void
-_tap_event_emit(Cover *cov)
+_tap_event_emit(Cover *cov, int state)
 {
    switch (cov->tap_gesture_data.n_taps)
       {
@@ -708,7 +708,7 @@ _tap_event_emit(Cover *cov)
                _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);
+                           state);
             }
          else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
             {
@@ -716,7 +716,7 @@ _tap_event_emit(Cover *cov)
                _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);
+                           state);
             }
          else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
             {
@@ -724,7 +724,7 @@ _tap_event_emit(Cover *cov)
                _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);
+                           state);
             }
          else
             {
@@ -738,7 +738,7 @@ _tap_event_emit(Cover *cov)
                _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);
+                           state);
             }
          else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
             {
@@ -746,7 +746,7 @@ _tap_event_emit(Cover *cov)
                _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);
+                           state);
             }
          else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
             {
@@ -754,7 +754,7 @@ _tap_event_emit(Cover *cov)
                _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);
+                           state);
             }
          else
             {
@@ -768,7 +768,7 @@ _tap_event_emit(Cover *cov)
                _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);
+                           state);
             }
          else if(cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE)
             {
@@ -776,7 +776,7 @@ _tap_event_emit(Cover *cov)
                _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);
+                           state);
             }
          else if(cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE)
             {
@@ -784,7 +784,7 @@ _tap_event_emit(Cover *cov)
                _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);
+                           state);
             }
          else
             {
@@ -804,7 +804,9 @@ _on_tap_timer_expire(void *data)
    DEBUG("Timer expired");
 
    if (cov->tap_gesture_data.started && !cov->tap_gesture_data.pressed)
-      _tap_event_emit(cov);
+      _tap_event_emit(cov,2);
+   else
+      _tap_event_emit(cov,3);
 
    // finish gesture
    cov->tap_gesture_data.started = EINA_FALSE;
@@ -1013,9 +1015,9 @@ _tap_gestures_move(Ecore_Event_Mouse_Move *ev, Cover *cov)
 {
    int i;
    for (i = 0; i < sizeof(cov->tap_gesture_data.finger)/sizeof(cov->tap_gesture_data.finger[0]); i++)
-     {
-        if (ev->multi.device == cov->tap_gesture_data.finger[i])
-          {
+      {
+         if (ev->multi.device == cov->tap_gesture_data.finger[i])
+            {
                int dx = ev->root.x - cov->tap_gesture_data.x_org[i];
                int dy = ev->root.y - cov->tap_gesture_data.y_org[i];
 
@@ -1031,9 +1033,9 @@ _tap_gestures_move(Ecore_Event_Mouse_Move *ev, Cover *cov)
                      cov->tap_gesture_data.finger[1] = -1;
                      cov->tap_gesture_data.finger[2] = -1;
                   }
-             break;
-          }
-     }
+               break;
+            }
+      }
 }
 
 static Eina_Bool