Improve reading on text-changed and caret-moved events in TV version 52/292752/1
authorLukasz Oleksak <l.oleksak@samsung.com>
Thu, 20 Apr 2023 10:32:44 +0000 (12:32 +0200)
committerLukasz Oleksak <l.oleksak@samsung.com>
Fri, 12 May 2023 08:31:37 +0000 (08:31 +0000)
This patch introduces following features while handling text-changed and
caret-moved events:

* announce capital letters (e.g read "Capital C" for input text "C")
* announce symbols (e.g read "space" for input text " ")
* prevent reveal fragments or whole of the password text

Change-Id: I17e107c2f1adabf7c5bae734d0d580ac20e19776
(cherry picked from commit 05e4a2a75453479545c7a8abe190a2fcda12181c)

include/utils.h
src/app_tracker.c
src/screen_reader_spi.c
src/symbols.c

index cb4bb3e866ca211e72140e99f41cad7afe6dabfe..1287fb38013ba28b266b0162e1248204d189b72c 100644 (file)
@@ -113,6 +113,12 @@ void cycle_detection_initialize(cycle_detection_data *data, const void *key);
  */
 Eina_Bool cycle_detection_check_if_in_cycle(cycle_detection_data *data, const void *key);
 
+typedef enum {
+       ACCESSIBLE_LIVE_REGION_OFF = 0,
+       ACCESSIBLE_LIVE_REGION_ASSERTIVE = 1,
+       ACCESSIBLE_LIVE_REGION_POLITE = 2
+} Live_Region_Politeness;
+
 typedef enum {
        ACCESSIBLE_VALUE_FORMAT_PERCENT = 1 << 0,
        ACCESSIBLE_VALUE_FORMAT_NUMBER = 1 << 1,
index 690df0588fd3af5ab7eb7430d0fbbcd41085e2f3..bab1240de8802432af9a31343c710c23cfafc9ef 100644 (file)
@@ -529,20 +529,20 @@ static void _on_atspi_event_cb(AtspiEvent *event, void *user_data)
 
                        GHashTable *attrs = atspi_accessible_get_attributes(event->source, NULL);
 
-                       int mode = 1;
+                       Live_Region_Politeness mode = ACCESSIBLE_LIVE_REGION_ASSERTIVE;
                        if (attrs) {
                                char *val = g_hash_table_lookup(attrs, "container-live");
                                DEBUG("got attributes, containter-live is '%s'", val);
                                if (val) {
-                                       if (g_strcmp0(val, "polite") == 0) mode = 2;
-                                       else if (g_strcmp0(val, "off") == 0) mode = 0;
+                                       if (g_strcmp0(val, "polite") == 0) mode = ACCESSIBLE_LIVE_REGION_POLITE;
+                                       else if (g_strcmp0(val, "off") == 0) mode = ACCESSIBLE_LIVE_REGION_OFF;
                                }
                                g_hash_table_destroy(attrs);
                        }
 
                        DEBUG("speaking mode is %d", mode);
-                       if (mode != 0)
-                               tw_speak_and_free(eina_strbuf_release(buf), mode == 1);
+                       if (mode != ACCESSIBLE_LIVE_REGION_OFF)
+                               tw_speak_and_free(eina_strbuf_release(buf), mode == ACCESSIBLE_LIVE_REGION_ASSERTIVE);
                        else
                                eina_strbuf_free(buf);
 
@@ -596,17 +596,14 @@ static void _on_atspi_event_cb(AtspiEvent *event, void *user_data)
                                if (!_is_valid_status(event->detail2))
                                        goto end;
                                AtspiText *iface_text = NULL;
-                               char buf[64] = "\0";
+                               Eina_Strbuf *buf = eina_strbuf_new();
                                iface_text = atspi_accessible_get_text_iface(event->source);
                                if (iface_text) {
                                        gint count = atspi_text_get_character_count(iface_text, NULL);
-                                       SUPPRESS_FORMAT_ERROR(g_snprintf(buf, sizeof(buf),
-                                                                                                  ngettext("PLURAL_ZERO_ACCS_TBOPT_PD_CHARACTERS",
-                                                                                                                       "PLURAL_ZERO_ACCS_TBOPT_PD_CHARACTERS", count),
-                                                                                                  count));
+                                       ESAF(buf, ngettext("PLURAL_ZERO_ACCS_TBOPT_PD_CHARACTERS", "PLURAL_ZERO_ACCS_TBOPT_PD_CHARACTERS", count), count);
                                        g_object_unref(iface_text);
                                }
-                               tw_speak(buf, EINA_TRUE);
+                               tw_speak(eina_strbuf_release(buf), EINA_TRUE);
                        }
                }
        }
index 48178f7ff86d5d610e052426d3f8634c113d27be..5f5acf125ff0f297dfe144b55ce1dbdb1c003439 100644 (file)
@@ -147,6 +147,14 @@ char *generate_description_for_subtree(AtspiAccessible *obj)
 
 static char *spi_on_caret_move_get_text(SpiData *spi, AtspiEvent *event)
 {
+       if (spi->ignore_next_caret_move == EINA_TRUE)
+       {
+               DEBUG("Ignoring caret moved event");
+               spi->ignore_next_caret_move = EINA_FALSE;
+               spi->last_caret_position = event->detail1;
+               return NULL;
+       }
+
        spi->currently_focused = event->source;
 
        if (spi->last_caret_position == event->detail1) // ignore fake moves, selection moves etc.
@@ -157,17 +165,31 @@ static char *spi_on_caret_move_get_text(SpiData *spi, AtspiEvent *event)
        if (!text_interface)
                return NULL;
 
-       const char *debug_text = atspi_accessible_get_name(spi->currently_focused, NULL);
+       char *debug_text = atspi_accessible_get_name(spi->currently_focused, NULL);
        DEBUG("->->->->->-> WIDGET CARET MOVED: %s <-<-<-<-<-<-<-", debug_text);
-       g_free((char *) debug_text);
+       g_free(debug_text);
 
        int caret_pos = atspi_text_get_caret_offset(text_interface, NULL);
        gchar *text = atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL);
        g_object_unref(text_interface);
-       char *return_text = g_strdup(text);
+
+       if (!text) {
+               ERROR("Text over which carret was moved is NULL");
+               return NULL;
+       }
+
+       Eina_Strbuf *buf = eina_strbuf_new();
+       const gchar *symtext = NULL;
+       if (isupper((int)*text)) {
+               ESAF(buf, _("IDS_ACCS_OPT_CAPITAL_PS_TTS"), text);
+       } else if ((symtext = symbol_lookup(text))) {
+               ESAL(buf, _(symtext));
+       } else {
+               ESAL(buf, text);
+       }
        g_free(text);
 
-       return return_text;
+       return eina_strbuf_release(buf);
 }
 
 static char *spi_on_value_changed_get_text(SpiData *spi, AtspiEvent *event)
@@ -180,28 +202,64 @@ static char *spi_on_value_changed_get_text(SpiData *spi, AtspiEvent *event)
        return text_to_read;
 }
 
-static char *spi_on_text_delete(SpiData *spi, AtspiEvent *event)
+static char *spi_get_password_text(SpiData *spi, AtspiEvent *event)
+{
+       AtspiText *iface_text = NULL;
+       Eina_Strbuf *buf = eina_strbuf_new();
+       iface_text = atspi_accessible_get_text_iface(event->source);
+       if (iface_text) {
+               gint count = atspi_text_get_character_count(iface_text, NULL);
+               ESAF(buf, ngettext("PLURAL_ZERO_ACCS_TBOPT_PD_CHARACTERS", "PLURAL_ZERO_ACCS_TBOPT_PD_CHARACTERS", count), count);
+               g_object_unref(iface_text);
+       }
+       return eina_strbuf_release(buf);
+}
+
+static char *spi_on_text_changed_get_text(SpiData *spi, AtspiEvent *event)
 {
-       char ret[TTS_MAX_TEXT_SIZE] = "\0";
+       AtspiRole role = atspi_accessible_get_role(event->source, NULL);
+       if (role == ATSPI_ROLE_PASSWORD_TEXT) {
+               return spi_get_password_text(spi, event);
+       }
+       const gchar *text = NULL;
+       const gchar *symtext = NULL;
+       text = g_value_get_string(&event->any_data);
+       if (!text) {
+               ERROR("Received notification about NULL text insert");
+               return NULL;
+       }
 
-       g_snprintf(ret, sizeof(ret), "%s %s",
-               g_value_get_string(&event->any_data), _("IDS_HEALTH_TBBODY_REMOVED"));
+       Eina_Strbuf *buf = eina_strbuf_new();
+       if (event->detail2 == 1) {
+               if (isupper((int)*text)) {
+                       ESAF(buf, _("IDS_ACCS_OPT_CAPITAL_PS_TTS"), text);
+               } else if ((symtext = symbol_lookup(text))) {
+                       ESAL(buf, _(symtext));
+               }
+       }
 
-       //FIXME : This IDS value is not supported.
-       /*else {
-               g_strlcpy(ret, _("IDS_TEXT_REMOVED"), sizeof(ret));
-       }*/
+       if (eina_strbuf_length_get(buf) == 0) {
+               ESAL(buf, text);
+       }
 
-       if (event->detail1 != spi->last_caret_position) {
-               //FIXME : This IDS value is not supported.
-               /*if (event->detail1 == 0) {
-                       g_strlcat(ret, _("IDS_REACHED_MIN_POS"), sizeof(ret));
-               }*/
-               spi->ignore_next_caret_move = EINA_TRUE;
-       } /*else if (event->detail1 == spi_get_text_interface_text_length(event, user_data)) {
-               g_strlcat(ret, _("IDS_REACHED_MAX_POS"), sizeof(ret));
-       }*/
-       return g_strdup(ret);
+       DEBUG("Text Changed :%s", eina_strbuf_string_get(buf));
+       return eina_strbuf_release(buf);
+}
+
+static char *spi_on_text_insert_get_text(SpiData *spi, AtspiEvent *event)
+{
+       DEBUG("START");
+       return spi_on_text_changed_get_text(spi, event);
+}
+
+static char *spi_on_text_delete_get_text(SpiData *spi, AtspiEvent *event)
+{
+       DEBUG("START");
+       Eina_Strbuf *buf = eina_strbuf_new();
+       char *text = spi_on_text_changed_get_text(spi, event);
+       ESAF(buf, "%s %s", text, _("IDS_HEALTH_TBBODY_REMOVED"));
+       g_free(text);
+       return eina_strbuf_release(buf);
 }
 
 void spi_event_get_text_to_read(
@@ -246,31 +304,43 @@ void spi_event_get_text_to_read(
                *text_to_read = spi_on_caret_move_get_text(spi, event);
 
        } else if (!g_strcmp0(event->type, TEXT_INSERT_SIG)) {
+               DEBUG("Set ignore_next_caret_move event to true");
                spi->ignore_next_caret_move = EINA_TRUE;
-               *text_to_read = g_strdup(g_value_get_string(&event->any_data));
-
-               int mode = 1;
+               Live_Region_Politeness mode = ACCESSIBLE_LIVE_REGION_ASSERTIVE;
                if (attrs) {
                        char *val = g_hash_table_lookup(attrs, "container-live");
                        DEBUG("got attributes, containter-live is '%s'", val);
                        if (val) {
-                               if (g_strcmp0(val, "polite") == 0) mode = 2;
-                               else if (g_strcmp0(val, "off") == 0) mode = 0;
+                               if (g_strcmp0(val, "polite") == 0) mode = ACCESSIBLE_LIVE_REGION_POLITE;
+                               else if (g_strcmp0(val, "off") == 0) mode = ACCESSIBLE_LIVE_REGION_OFF;
                        }
                }
-
                DEBUG("speaking mode is %d", mode);
-               if (mode != 0) {
+               if (mode != ACCESSIBLE_LIVE_REGION_OFF) {
+                       *text_to_read = spi_on_text_insert_get_text(spi, event);
                        if (cancel)
-                               *cancel = mode == 1 ? 1 : 0;
-               }
-               else {
-                       g_free(*text_to_read);
-                       *text_to_read = NULL;
+                               *cancel = mode == ACCESSIBLE_LIVE_REGION_ASSERTIVE ? 1 : 0;
                }
        } else if (!g_strcmp0(event->type, TEXT_DELETE_SIG)) {
-               *text_to_read = spi_on_text_delete(spi, event);
-
+               int mode = ACCESSIBLE_LIVE_REGION_ASSERTIVE;
+               if (attrs) {
+                       char *val = g_hash_table_lookup(attrs, "container-live");
+                       DEBUG("got attributes, containter-live is '%s'", val);
+                       if (val) {
+                               if (g_strcmp0(val, "polite") == 0) mode = ACCESSIBLE_LIVE_REGION_POLITE;
+                               else if (g_strcmp0(val, "off") == 0) mode = ACCESSIBLE_LIVE_REGION_OFF;
+                       }
+               }
+               DEBUG("speaking mode is %d", mode);
+               if (mode != ACCESSIBLE_LIVE_REGION_OFF) {
+                       *text_to_read = spi_on_text_delete_get_text(spi, event);
+                       if (cancel)
+                               *cancel = mode == ACCESSIBLE_LIVE_REGION_ASSERTIVE ? 1 : 0;
+               }
+               if (event->detail1 != spi->last_caret_position) {
+                       DEBUG("Set ignore_next_caret_move to true");
+                       spi->ignore_next_caret_move = EINA_TRUE;
+               }
        } else if (!g_strcmp0(event->type, VALUE_CHANGED_SIG)) {
                *text_to_read = spi_on_value_changed_get_text(spi, event);
 
index 0ded78e797e3d03de6d4cd8ee5ab5844cea8ae66..e8acb870b0e40e2732c7d3062bdd194ac77703c7 100644 (file)
@@ -27,9 +27,7 @@ struct _symbol_mapping_table
 };
 
 const gchar * symbol_lookup(const gchar *text) {
-#ifdef SCREEN_READER_TV
-       return NULL;
-#else
+
        static GHashTable *sym_hash = NULL;
        static int init = 0;
 
@@ -108,6 +106,5 @@ const gchar * symbol_lookup(const gchar *text) {
                return NULL;
 
        return g_hash_table_lookup(sym_hash, text);
-#endif
 }