Add screen reader feature 17/17417/1
authorHaifeng Deng <haifeng.deng@samsung.com>
Sun, 19 May 2013 08:27:58 +0000 (16:27 +0800)
committerJihoon Kim <jihoon48.kim@samsung.com>
Fri, 7 Mar 2014 01:27:55 +0000 (10:27 +0900)
Change-Id: I29ff6c05b84617556b76cb06d5c1952aef5ac2ee

configure.ac
ism/extras/efl_panel/Makefile.am
ism/extras/efl_panel/isf_panel_efl.cpp
packaging/isf.spec

index f01c1ae..ae88db9 100755 (executable)
@@ -254,6 +254,9 @@ PKG_CHECK_MODULES(PRIVILEGE_CONTROL, [libprivilege-control >= 0])
 # Check notification library
 PKG_CHECK_MODULES(NOTIFICATION, [notification])
 
+# Check tts library
+PKG_CHECK_MODULES(TTS, [tts])
+
 # Check vconf library
 PKG_CHECK_MODULES(VCONF, [vconf],
                   [ISF_HAS_VCONF=yes],
index d5ff1bd..faa4b2b 100644 (file)
@@ -28,13 +28,14 @@ bin_PROGRAMS           = $(CONFIG_SCIM_PANEL_EFL)
 isf_panel_efl_SOURCES  = isf_panel_efl.cpp \
                          isf_panel_utility.cpp
 
-isf_panel_efl_CXXFLAGS = @EFL_CFLAGS@ @VCONF_CFLAGS@ @PRIVILEGE_CONTROL_CFLAGS@ @DLOG_CFLAGS@
+isf_panel_efl_CXXFLAGS = @EFL_CFLAGS@ @VCONF_CFLAGS@ @PRIVILEGE_CONTROL_CFLAGS@ @DLOG_CFLAGS@ @TTS_CFLAGS@
 
 isf_panel_efl_LDFLAGS  = @EFL_LIBS@ @LTLIBINTL@ -rpath $(libdir) \
                          @VCONF_LIBS@ \
                          @X11_LIBS@ \
                          @PRIVILEGE_CONTROL_LIBS@ \
-                         @DLOG_LIBS@
+                         @DLOG_LIBS@ \
+                         @TTS_LIBS@
 
 isf_panel_efl_LDADD    = $(top_builddir)/ism/src/libscim@SCIM_EPOCH@.la
 
index 8f0eca9..7dce2d2 100644 (file)
@@ -57,7 +57,7 @@
 #include <privilege-control.h>
 #include "isf_panel_utility.h"
 #include <dlog.h>
-
+#include <tts.h>
 
 using namespace scim;
 
@@ -288,13 +288,14 @@ static Ecore_Timer       *_longpress_timer                  = NULL;
 static Ecore_Timer       *_destroy_timer                    = NULL;
 static Ecore_Timer       *_system_ready_timer               = NULL;
 
-static Ecore_X_Window    _ise_window                        = 0;
-static Ecore_X_Window    _app_window                        = 0;
-static Ecore_X_Window    _control_window                    = 0;
+static Ecore_X_Window     _ise_window                       = 0;
+static Ecore_X_Window     _app_window                       = 0;
+static Ecore_X_Window     _control_window                   = 0;
 
 static Ecore_File_Monitor *_helper_ise_em                   = NULL;
 static Ecore_File_Monitor *_keyboard_ise_em                 = NULL;
 
+static tts_h              _tts                              = NULL;
 
 /////////////////////////////////////////////////////////////////////////////
 // Implementation of internal functions.
@@ -1343,6 +1344,180 @@ static void ui_mouse_moved_cb (void *data, Evas *e, Evas_Object *button, void *e
 }
 
 /**
+ * @brief Open TTS device.
+ *
+ * @return false if open is failed, otherwise return true.
+ */
+static bool ui_open_tts (void)
+{
+    SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
+
+    int r = tts_create (&_tts);
+    if (TTS_ERROR_NONE != r) {
+        std::cerr << "tts_create FAILED : result(" << r << ")\n";
+        _tts = NULL;
+        return false;
+    }
+
+    r = tts_set_mode (_tts, TTS_MODE_SCREEN_READER);
+    if (TTS_ERROR_NONE != r) {
+        std::cerr << "tts_set_mode FAILED : result(" << r << ")\n";
+    }
+
+    tts_state_e current_state;
+    tts_get_state (_tts, &current_state);
+
+    if (TTS_STATE_CREATED == current_state)  {
+        r = tts_prepare (_tts);
+        if (TTS_ERROR_NONE != r) {
+            std::cerr << "tts_prepare FAILED : ret(" << r << ")\n";
+        }
+    }
+    return true;
+}
+
+/**
+ * @brief Close TTS device.
+ */
+static void ui_close_tts (void)
+{
+    SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
+
+    if (_tts) {
+        int r = tts_unprepare (_tts);
+        if (TTS_ERROR_NONE != r) {
+            std::cerr << "tts_unprepare FAILED : result(" << r << ")\n";
+        }
+
+        r = tts_destroy (_tts);
+        if (TTS_ERROR_NONE != r) {
+            std::cerr << "tts_destroy FAILED : result(" << r << ")\n";
+        }
+    }
+}
+
+/**
+ * @brief Play string by TTS.
+ *
+ * @param str The string for playing.
+ */
+static void ui_play_tts (const char* str)
+{
+    SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " str=" << str << "\n";
+
+    if (_tts == NULL) {
+        if (!ui_open_tts ())
+            return;
+    }
+
+    if (str) {
+        int r;
+        int utt_id = 0;
+        tts_state_e current_state;
+
+        r = tts_get_state (_tts, &current_state);
+        if (TTS_ERROR_NONE != r) {
+            std::cerr << "Fail to get state from TTS : ret(" << r << ")\n";
+        }
+
+        if (TTS_STATE_PLAYING == current_state)  {
+            r = tts_stop (_tts);
+            if (TTS_ERROR_NONE != r) {
+                std::cerr << "Fail to stop TTS : ret(" << r << ")\n";
+            }
+        }
+        /* FIXME: Should support for all languages */
+        r = tts_add_text (_tts, str, "en_US", TTS_VOICE_TYPE_FEMALE, TTS_SPEED_NORMAL, &utt_id);
+        if (TTS_ERROR_NONE == r) {
+            r = tts_play (_tts);
+            if (TTS_ERROR_NONE != r) {
+                std::cerr << "Fail to play TTS : ret(" << r << ")\n";
+            }
+        }
+    }
+}
+
+/**
+ * @brief Mouse over (find focus object and play text by TTS) when screen reader is enabled.
+ *
+ * @param mouse_x Mouse X position.
+ * @param mouse_y Mouse Y position.
+ */
+static void ui_mouse_over (int mouse_x, int mouse_y)
+{
+    SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
+    if (_candidate_window == NULL || !evas_object_visible_get (_candidate_window))
+        return;
+
+    int x, y, width, height;
+    for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
+        if (_candidate_0 [i]) {
+            evas_object_geometry_get (_candidate_0 [i], &x, &y, &width, &height);
+            if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
+                /* FIXME: Should consider emoji case */
+                String mbs = utf8_wcstombs (g_isf_candidate_table.get_candidate_in_current_page (i));
+                SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " play candidate string: " << mbs << "\n";
+                ui_play_tts (mbs.c_str ());
+                return;
+            }
+        }
+    }
+
+    String strTts = String ("");
+    if (evas_object_visible_get (_candidate_area_2)) {
+        evas_object_geometry_get (_close_btn, &x, &y, &width, &height);
+        if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height)
+            strTts = String ("close button");
+    } else {
+        evas_object_geometry_get (_more_btn, &x, &y, &width, &height);
+        if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height)
+            strTts = String ("more button");
+    }
+    if (strTts.length () > 0)
+        ui_play_tts (strTts.c_str ());
+}
+
+/**
+ * @brief Mouse click (find focus object and do click event) when screen reader is enabled.
+ *
+ * @param mouse_x Mouse X position.
+ * @param mouse_y Mouse Y position.
+ */
+static void ui_mouse_click (int mouse_x, int mouse_y)
+{
+    SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n";
+    if (_candidate_window == NULL || !evas_object_visible_get (_candidate_window))
+        return;
+
+    int x, y, width, height;
+    for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) {
+        if (_candidate_0 [i]) {
+            evas_object_geometry_get (_candidate_0 [i], &x, &y, &width, &height);
+            if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
+                Evas_Event_Mouse_Down event_info;
+                event_info.canvas.x = mouse_x;
+                event_info.canvas.y = mouse_y;
+                ui_mouse_button_pressed_cb (GINT_TO_POINTER ((i << 8) + ISF_EFL_CANDIDATE_0), NULL, NULL, &event_info);
+                ui_mouse_button_released_cb (GINT_TO_POINTER (i), NULL, NULL, &event_info);
+                return;
+            }
+        }
+    }
+
+    if (evas_object_visible_get (_candidate_area_2)) {
+        evas_object_geometry_get (_close_btn, &x, &y, &width, &height);
+        if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
+            ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL);
+        }
+    } else {
+        evas_object_geometry_get (_more_btn, &x, &y, &width, &height);
+        if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) {
+            ui_candidate_window_more_button_cb (NULL, NULL, NULL, NULL);
+        }
+    }
+}
+
+/**
  * @brief Create native style candidate window.
  */
 static void ui_create_native_candidate_window (void)
@@ -3571,6 +3746,29 @@ static Eina_Bool x_event_client_message_cb (void *data, int type, void *event)
         }
     }
 
+    /* Screen reader feature */
+    if (ev->message_type == ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL) {
+        static int last_pos_x = -10000;
+        static int last_pos_y = -10000;
+
+        if (_candidate_window) {
+            if ((unsigned int)ev->data.l[0] == elm_win_xwindow_get (_candidate_window)) {
+                if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE) {
+                    // 1 finger double tap
+                    SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "    1 finger double tap (" << last_pos_x << ", " << last_pos_y << ")\n";
+                    ui_mouse_click (last_pos_x, last_pos_y);
+                } else if ((unsigned int)ev->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ) {
+                    // 1 finger tap
+                    // 1 finger touch & move
+                    last_pos_x = ev->data.l[2];
+                    last_pos_y = ev->data.l[3];
+                    SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "    1 finger touch & move (" << last_pos_x << ", " << last_pos_y << ")\n";
+                    ui_mouse_over (last_pos_x, last_pos_y);
+                }
+            }
+        }
+    }
+
     return ECORE_CALLBACK_RENEW;
 }
 
@@ -3958,6 +4156,7 @@ cleanup:
     ui_candidate_delete_destroy_timer ();
     delete_keyboard_ise_em ();
     delete_helper_ise_em ();
+    ui_close_tts ();
 
     if (!_config.null ())
         _config.reset ();
index 8b81f9a..226a389 100644 (file)
@@ -24,6 +24,7 @@ BuildRequires:  pkgconfig(edje)
 BuildRequires:  pkgconfig(x11)
 BuildRequires:  pkgconfig(notification)
 BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(tts)
 Requires(post): /sbin/ldconfig /usr/bin/vconftool
 Requires(postun): /sbin/ldconfig