From f87c073b69bfb2997b4ae83ba588c954213d6a63 Mon Sep 17 00:00:00 2001 From: Lukasz Oleksak Date: Thu, 8 Oct 2015 10:55:26 +0200 Subject: [PATCH 01/16] flat_navi: fixes asymetry between forward and backward dfs traversing Change-Id: I65e4216a15ab1842f62ef6a3a587986943afab64 Signed-off-by: Lukasz Oleksak --- src/flat_navi.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/flat_navi.c b/src/flat_navi.c index 72aac40..a7f299f 100644 --- a/src/flat_navi.c +++ b/src/flat_navi.c @@ -436,12 +436,19 @@ AtspiAccessible *_directional_depth_first_search(AtspiAccessible * root, AtspiAc g_object_unref(next_related_in_direction); } + Eina_Bool all_children_visited = (start && start != root && next_sibling_idx_modifier < 0)?EINA_TRUE:EINA_FALSE; + while (node) { AtspiAccessible *prev_related_in_direction = (next_sibling_idx_modifier > 0) ? _get_object_in_relation(node, ATSPI_RELATION_FLOWS_FROM) : _get_object_in_relation(node, ATSPI_RELATION_FLOWS_TO); - if (node != start && (relation_mode || !prev_related_in_direction) && stop_condition(node)) { + int cc = atspi_accessible_get_child_count(node, NULL); + // do not accept: + // 1. start node + // 2. internal nodes of flow relation chains + // 3. parent before children in backward traversing + if (node != start && (relation_mode || !prev_related_in_direction) && !(cc > 0 && next_sibling_idx_modifier < 0 && !all_children_visited) && stop_condition(node)) { g_object_unref(prev_related_in_direction); return node; } @@ -466,16 +473,19 @@ AtspiAccessible *_directional_depth_first_search(AtspiAccessible * root, AtspiAc g_object_unref(prev_related_in_direction); g_object_unref(next_related_in_direction); relation_mode = EINA_FALSE; - int cc = atspi_accessible_get_child_count(node, NULL); + ss = atspi_accessible_get_state_set(node); - if (cc > 0 && atspi_state_set_contains(ss, ATSPI_STATE_SHOWING)) // walk down + if (cc > 0 && !all_children_visited && atspi_state_set_contains(ss, ATSPI_STATE_SHOWING)) // walk down { int idx = next_sibling_idx_modifier > 0 ? 0 : cc - 1; g_object_unref(node); node = atspi_accessible_get_child_at_index(node, idx, NULL); DEBUG("DFS DOWN"); } else { + all_children_visited = EINA_TRUE; + DEBUG("ALL CHILD VISITED (TRUE)"); + Eina_Bool up_node_found = EINA_FALSE; while (!_has_next_sibling(node, next_sibling_idx_modifier) || node == root) // no next sibling { DEBUG("DFS NO SIBLING"); @@ -488,11 +498,20 @@ AtspiAccessible *_directional_depth_first_search(AtspiAccessible * root, AtspiAc g_object_unref(node); node = atspi_accessible_get_parent(node, NULL); // walk up... DEBUG("DFS UP"); + // in backward traversing stop the walk up on parent + if (next_sibling_idx_modifier < 0) { + up_node_found = EINA_TRUE; + break; + } + } + if (!up_node_found) { + int idx = atspi_accessible_get_index_in_parent(node, NULL); + g_object_unref(node); + node = atspi_accessible_get_child_at_index(atspi_accessible_get_parent(node, NULL), idx + next_sibling_idx_modifier, NULL); //... and next + all_children_visited = EINA_FALSE; + DEBUG("RESET ALL CHILD VISITED (FALSE) FOR NEW SIBLING"); + DEBUG("DFS NEXT %d", idx + next_sibling_idx_modifier); } - int idx = atspi_accessible_get_index_in_parent(node, NULL); - g_object_unref(node); - node = atspi_accessible_get_child_at_index(atspi_accessible_get_parent(node, NULL), idx + next_sibling_idx_modifier, NULL); //... and next - DEBUG("DFS NEXT %d", idx + next_sibling_idx_modifier); } g_object_unref(ss); } -- 2.7.4 From b16ed7196408ed653740158c9d43734ecf271e49 Mon Sep 17 00:00:00 2001 From: Tomasz Olszak Date: Thu, 8 Oct 2015 12:36:22 +0200 Subject: [PATCH 02/16] Fixed compilation warnings (unused variables, implicit declaration) Change-Id: Iab1baced700e5a2d1706591bc30b1a180c48cfbe --- src/keyboard_tracker.c | 2 +- src/screen_reader_switch.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/keyboard_tracker.c b/src/keyboard_tracker.c index 70f62d9..c0d3c4e 100644 --- a/src/keyboard_tracker.c +++ b/src/keyboard_tracker.c @@ -20,7 +20,7 @@ #include #include "keyboard_tracker.h" #include "logger.h" - +#include "screen_reader_tts.h" static AtspiDeviceListener *listener; static Keyboard_Tracker_Cb user_cb; static void *user_data; diff --git a/src/screen_reader_switch.c b/src/screen_reader_switch.c index 651d49f..b6b18c1 100644 --- a/src/screen_reader_switch.c +++ b/src/screen_reader_switch.c @@ -69,8 +69,8 @@ Eina_Bool screen_reader_switch_enabled_set(Eina_Bool value) Eldbus_Connection *conn; Eldbus_Object *dobj; Eldbus_Proxy *proxy; - Eldbus_Message *req, *reply; - const char *errname = NULL, *errmsg = NULL; + Eldbus_Message *req; + Eina_Bool ret = EINA_FALSE; Eldbus_Message_Iter *iter; -- 2.7.4 From cfc71295c3783a77d5a432447656304e41d29f55 Mon Sep 17 00:00:00 2001 From: Tomasz Olszak Date: Fri, 9 Oct 2015 14:51:50 +0200 Subject: [PATCH 03/16] Added setting vconf key when SR created and terminated. Change-Id: I20600cead27c1de070e33075f16cc9b8c194c6da --- src/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 613d0d2..b1b91a8 100644 --- a/src/main.c +++ b/src/main.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "navigator.h" #include "window_tracker.h" #include "logger.h" @@ -211,6 +212,8 @@ void set_signal_handler() static int app_create(void *data) { + if (vconf_set_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, 1)) + ERROR("Can't set value of %s vconf key to 1", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS); elm_init(0, NULL); atspi_init(); @@ -240,7 +243,8 @@ static int app_terminate(void *data) DEBUG("libatspi terminated"); atspi_exit(); - + if (vconf_set_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, 0)) + ERROR("Can't set value of %s vconf key to 1", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS); return 0; } -- 2.7.4 From 9970b7bfab0900ad5a37511408d676c02cd8fd44 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Tue, 4 Aug 2015 21:42:30 +0900 Subject: [PATCH 04/16] Remove tizen 2.4 keyword, and follow tizen 3.0 general definition Change-Id: I822e9507822ec4940e3176f15db9ad5b38a893f4 --- CMakeLists.txt | 2 +- org.tizen.screen-reader.xml | 3 +-- packaging/org.tizen.screen-reader.spec | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 650c47c..f9188a6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,7 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${SLP_LD_PATH_FLAGS} ${SLP INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) INSTALL(DIRECTORY ${RESOURCE_DIR}/icons DESTINATION res) # Install Manifest File -INSTALL(FILES org.tizen.screen-reader.xml DESTINATION /opt/share/packages) +INSTALL(FILES org.tizen.screen-reader.xml DESTINATION /usr/share/packages) ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/res/po) ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/tests) diff --git a/org.tizen.screen-reader.xml b/org.tizen.screen-reader.xml index f13fa26..99284a4 100755 --- a/org.tizen.screen-reader.xml +++ b/org.tizen.screen-reader.xml @@ -1,5 +1,5 @@ - + SMART NAVIGATOR @@ -9,7 +9,6 @@ - diff --git a/packaging/org.tizen.screen-reader.spec b/packaging/org.tizen.screen-reader.spec index 396b8f9..96ee306 100755 --- a/packaging/org.tizen.screen-reader.spec +++ b/packaging/org.tizen.screen-reader.spec @@ -74,4 +74,4 @@ rm -rf %{buildroot} %{AppInstallPath}/bin/screen-reader %{AppInstallPath}/res/icons/screen-reader.png %{AppInstallPath}/res/locale/*/LC_MESSAGES/* -/opt/share/packages/%{name}.xml +/usr/share/packages/%{name}.xml -- 2.7.4 From 944348726ee91cc0fd38078640997ba21df9ac56 Mon Sep 17 00:00:00 2001 From: Tomasz Olszak Date: Tue, 20 Oct 2015 16:19:55 +0200 Subject: [PATCH 05/16] tizen_2.4 adapted for 3.0 TV Change-Id: I19bc03f45871ec5f87a9e14265b8a07df67193b0 --- CMakeLists.txt | 32 +++++++++++++++++++++-- org.tizen.screen-reader.manifest | 48 +++------------------------------- packaging/org.tizen.screen-reader.spec | 11 +++++--- src/main.c | 5 ++-- src/screen_reader_vconf.c | 8 +++--- 5 files changed, 48 insertions(+), 56 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f9188a6..739a1b8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,22 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) ENABLE_TESTING() # FIND ALL SOURCE IN A SOURCE DIRECTORY -AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src SRCS) +#AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src SRCS) + +SET(SRCS ${CMAKE_SOURCE_DIR}/src/app_tracker.c + ${CMAKE_SOURCE_DIR}/src/flat_navi.c + ${CMAKE_SOURCE_DIR}/src/main.c + ${CMAKE_SOURCE_DIR}/src/pivot_chooser.c + ${CMAKE_SOURCE_DIR}/src/screen_reader.c + ${CMAKE_SOURCE_DIR}/src/screen_reader_haptic.c + ${CMAKE_SOURCE_DIR}/src/screen_reader_spi.c + ${CMAKE_SOURCE_DIR}/src/screen_reader_switch.c + ${CMAKE_SOURCE_DIR}/src/screen_reader_system.c + ${CMAKE_SOURCE_DIR}/src/screen_reader_tts.c + ${CMAKE_SOURCE_DIR}/src/screen_reader_vconf.c + ${CMAKE_SOURCE_DIR}/src/smart_notification.c +) + #INCLUDE FILE INCLUDE(CMakeLists.sub) @@ -12,11 +27,24 @@ SET(LOCALEDIR "/usr/apps/org.tizen.screen-reader/res/locale") IF("${SEC_FEATURE_TAPI_ENABLE}" STREQUAL "1") MESSAGE("SEC_FEATURE_TAPI_ENABLE: ${SEC_FEATURE_TAPI_ENABLE}") SET(TAPI_REQUIRED_PKG "tapi") + SET(SRCS ${SRCS} + ${CMAKE_SOURCE_DIR}/src/dbus_gesture_adapter.c + ${CMAKE_SOURCE_DIR}/src/elm_access_adapter.c + ${CMAKE_SOURCE_DIR}/src/screen_reader_gestures.c + ${CMAKE_SOURCE_DIR}/src/navigator.c + ${CMAKE_SOURCE_DIR}/src/keyboard_tracker.c + ${CMAKE_SOURCE_DIR}/src/window_tracker.c) ELSE() MESSAGE("SEC_FEATURE_TAPI_ENABLE: ${SEC_FEATURE_TAPI_ENABLE}") ADD_DEFINITIONS("-DSCREEN_READER_TV") ENDIF() +IF("${X11_ENABLED}" STREQUAL "1") + MESSSAGE("X11 is enabled") + SET(CONDITIONAL_PACKAGES ${CONDITIONAL_PACKAGES} "ecore-x") + ADD_DEFINITIONS("-DX11_ENABLED") +ENDIF() + INCLUDE(FindPkgConfig) pkg_check_modules(pkgs REQUIRED bundle @@ -26,7 +54,6 @@ pkg_check_modules(pkgs REQUIRED ecore atspi-2 gobject-2.0 - ecore-x dlog vconf tts @@ -36,6 +63,7 @@ pkg_check_modules(pkgs REQUIRED notification capi-network-wifi ${TAPI_REQUIRED_PKG} + ${CONDITIONAL_PACKAGES} ) FOREACH(flag ${pkgs_CFLAGS}) diff --git a/org.tizen.screen-reader.manifest b/org.tizen.screen-reader.manifest index cbe437f..9c82c66 100644 --- a/org.tizen.screen-reader.manifest +++ b/org.tizen.screen-reader.manifest @@ -1,47 +1,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/packaging/org.tizen.screen-reader.spec b/packaging/org.tizen.screen-reader.spec index 96ee306..d0bd43c 100755 --- a/packaging/org.tizen.screen-reader.spec +++ b/packaging/org.tizen.screen-reader.spec @@ -14,7 +14,9 @@ BuildRequires: at-spi2-core-devel BuildRequires: cmake BuildRequires: pkgconfig(appcore-efl) BuildRequires: pkgconfig(ecore) +%if %{with x} BuildRequires: pkgconfig(ecore-x) +%endif BuildRequires: pkgconfig(eina) BuildRequires: pkgconfig(eldbus) BuildRequires: pkgconfig(elementary) @@ -28,7 +30,7 @@ BuildRequires: pkgconfig(check) BuildRequires: pkgconfig(capi-network-bluetooth) BuildRequires: pkgconfig(notification) BuildRequires: pkgconfig(capi-network-wifi) -%if "%{?tizen_profile_name}" != "tv" +%if "%{?profile}" != "tv" BuildRequires: pkgconfig(tapi) %endif @@ -41,16 +43,19 @@ An utility library for developers of the menu screen. %build rm -rf CMakeFiles CMakeCache.txt -%if "%{?tizen_profile_name}" != "tv" +%if "%{profile}" != "tv" export SEC_FEATURE_TAPI_ENABLE="1" + export CFLAGS+=" -DELM_ACCESS_KEYBOARD" %else export SEC_FEATURE_TAPI_ENABLE="0" %endif -export CFLAGS+=" -DELM_ACCESS_KEYBOARD" cmake . -DCMAKE_INSTALL_PREFIX="%{AppInstallPath}" \ -DCMAKE_TARGET="%{Exec}" \ -DCMAKE_PACKAGE="%{name}" \ +%if %{with x} + -DX11_ENABLED=1 \ +%endif -DSEC_FEATURE_TAPI_ENABLE=${SEC_FEATURE_TAPI_ENABLE} make %{?jobs:-j%jobs} \ diff --git a/src/main.c b/src/main.c index b1b91a8..f6017f4 100644 --- a/src/main.c +++ b/src/main.c @@ -22,11 +22,12 @@ #include #include #include +#ifndef SCREEN_READER_TV #include "navigator.h" -#include "window_tracker.h" +#include "screen_reader_gestures.h" +#endif #include "logger.h" #include "screen_reader.h" -#include "screen_reader_gestures.h" #include "screen_reader_switch.h" #define MAX_STACK_FRAMES 64 diff --git a/src/screen_reader_vconf.c b/src/screen_reader_vconf.c index f6ae5c1..fbf7818 100644 --- a/src/screen_reader_vconf.c +++ b/src/screen_reader_vconf.c @@ -36,10 +36,10 @@ keylist_t *keys = NULL; void app_termination_cb(keynode_t * node, void *user_data) { DEBUG("START"); - DEBUG("Application terminate %d", !node->value.i); + DEBUG("Application terminate %d", !vconf_keynode_get_int(node)); Service_Data *service_data = user_data; - service_data->run_service = node->value.i; + service_data->run_service = vconf_keynode_get_int(node); if (service_data->run_service == 0) { elm_exit(); @@ -51,10 +51,10 @@ void app_termination_cb(keynode_t * node, void *user_data) void display_language_cb(keynode_t * node, void *user_data) { DEBUG("START"); - DEBUG("Trying to set LC_MESSAGES to: %s", node->value.s); + DEBUG("Trying to set LC_MESSAGES to: %s", vconf_keynode_get_str(node)); Service_Data *sd = user_data; - snprintf(sd->display_language, LANGUAGE_NAME_SIZE, "%s", node->value.s); + snprintf(sd->display_language, LANGUAGE_NAME_SIZE, "%s", vconf_keynode_get_str(node)); //to make gettext work setenv("LC_MESSAGES", sd->display_language, 1); -- 2.7.4 From b0032b59aeb941b658a0fa2ccc36263fd7cb2fe4 Mon Sep 17 00:00:00 2001 From: Tomasz Olszak Date: Tue, 27 Oct 2015 11:09:32 +0100 Subject: [PATCH 06/16] Changes that allow to compile SR on Tizen 3.0 Mobile. There are still many issues related to fact that Wayland differs a lot comparing to X11 and we used X11 a lot - especially for gesture recognition, scrolling. Change-Id: I24ea4d42006fe39359f484c9eddeffc8b7ac6572 --- CMakeLists.txt | 5 ++- include/elm_access_adapter.h | 13 +++++- include/screen_reader_gestures.h | 15 ++++++- packaging/org.tizen.screen-reader.spec | 6 ++- src/elm_access_adapter.c | 13 +++++- src/keyboard_tracker.c | 9 +++- src/navigator.c | 14 ++++-- src/screen_reader_gestures.c | 82 ++++++++++++++++++++++++++++------ src/window_tracker.c | 8 +++- 9 files changed, 140 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 739a1b8..8044755 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,9 +40,12 @@ ELSE() ENDIF() IF("${X11_ENABLED}" STREQUAL "1") - MESSSAGE("X11 is enabled") + MESSAGE(STATUS "X11 is enabled") SET(CONDITIONAL_PACKAGES ${CONDITIONAL_PACKAGES} "ecore-x") ADD_DEFINITIONS("-DX11_ENABLED") +ELSE() + MESSAGE(STATUS "X11 is disabled - using wayland") + SET(CONDITIONAL_PACKAGES ${CONDITIONAL_PACKAGES} "ecore-wayland") ENDIF() INCLUDE(FindPkgConfig) diff --git a/include/elm_access_adapter.h b/include/elm_access_adapter.h index 027108b..3c6b209 100644 --- a/include/elm_access_adapter.h +++ b/include/elm_access_adapter.h @@ -1,8 +1,11 @@ #ifndef ELM_ACCESS_KEYBOARD_ADAPTER_H_ #define ELM_ACCESS_KEYBOARD_ADAPTER_H_ -#include +#ifdef X11_ENABLED #include +#else +#include +#endif /** * @brief Send ecore x message with elm access read action @@ -12,7 +15,11 @@ * @param y y coordinate of gesture relative to X root window * */ +#ifdef X11_ENABLED void elm_access_adaptor_emit_read(Ecore_X_Window win, int x, int y); +#else +void elm_access_adaptor_emit_read(Ecore_Wl_Window *win, int x, int y); +#endif /** * @brief Send ecore x message with elm access activate action @@ -22,6 +29,10 @@ void elm_access_adaptor_emit_read(Ecore_X_Window win, int x, int y); * @param y y coordinate of gesture relative to X root window * */ +#ifdef X11_ENABLED void elm_access_adaptor_emit_activate(Ecore_X_Window win, int x, int y); +#else +void elm_access_adaptor_emit_activate(Ecore_Wl_Window *win, int x, int y); +#endif #endif diff --git a/include/screen_reader_gestures.h b/include/screen_reader_gestures.h index 0e5b1d4..3ac3114 100644 --- a/include/screen_reader_gestures.h +++ b/include/screen_reader_gestures.h @@ -2,8 +2,11 @@ #define SCREEN_READER_GESTURES_H_ #include +#ifdef X11_ENABLED #include - +#else +#include +#endif /** * @brief Accessibility gestures */ @@ -70,8 +73,11 @@ Eina_Bool screen_reader_gestures_init(void); * @brief Shutdown gesture navigation profile. */ void screen_reader_gestures_shutdown(void); - +#ifdef X11_ENABLED Eina_Bool screen_reader_gesture_x_grab_touch_devices(Ecore_X_Window win); +#else +Eina_Bool screen_reader_gesture_wl_grab_touch_devices(Ecore_Wl_Window win); +#endif typedef void (*GestureCB)(void *data, Gesture_Info *info); @@ -103,5 +109,10 @@ void end_scroll(int x, int y); * * @return Ecore_X_Window Object which represents top window on which gesture occure */ +#ifdef X11_ENABLED Ecore_X_Window top_window_get (int x, int y); +#else +Ecore_Wl_Window *top_window_get (int x, int y); +#endif + #endif diff --git a/packaging/org.tizen.screen-reader.spec b/packaging/org.tizen.screen-reader.spec index d0bd43c..9d10be4 100755 --- a/packaging/org.tizen.screen-reader.spec +++ b/packaging/org.tizen.screen-reader.spec @@ -1,6 +1,7 @@ %define AppInstallPath /usr/apps/%{name} %define Exec screen-reader - +%bcond_with x +%bcond_with wayland Name: org.tizen.screen-reader Summary: Screen Reader Assistive Technology @@ -17,6 +18,9 @@ BuildRequires: pkgconfig(ecore) %if %{with x} BuildRequires: pkgconfig(ecore-x) %endif +%if %{with wayland} +BuildRequires: pkgconfig(ecore-wayland) +%endif BuildRequires: pkgconfig(eina) BuildRequires: pkgconfig(eldbus) BuildRequires: pkgconfig(elementary) diff --git a/src/elm_access_adapter.c b/src/elm_access_adapter.c index fc46227..233e51a 100644 --- a/src/elm_access_adapter.c +++ b/src/elm_access_adapter.c @@ -17,6 +17,7 @@ #include "elm_access_adapter.h" #include "logger.h" +#ifdef X11_ENABLED static void _get_root_coords(Ecore_X_Window win, int *x, int *y) { Ecore_X_Window root = ecore_x_window_root_first_get(); @@ -37,7 +38,6 @@ static void _get_root_coords(Ecore_X_Window win, int *x, int *y) parent = ecore_x_window_parent_get(parent); } } - static void _send_ecore_x_client_msg(Ecore_X_Window win, int x, int y, Eina_Bool activate) { int x_win, y_win; @@ -63,3 +63,14 @@ void elm_access_adaptor_emit_read(Ecore_X_Window win, int x, int y) { _send_ecore_x_client_msg(win, x, y, EINA_FALSE); } +#else +void elm_access_adaptor_emit_activate(Ecore_Wl_Window *win, int x, int y) +{ + +} + +void elm_access_adaptor_emit_read(Ecore_Wl_Window *win, int x, int y) +{ + +} +#endif \ No newline at end of file diff --git a/src/keyboard_tracker.c b/src/keyboard_tracker.c index c0d3c4e..74befc9 100644 --- a/src/keyboard_tracker.c +++ b/src/keyboard_tracker.c @@ -17,13 +17,16 @@ #include #include #include +#ifdef X11_ENABLED #include +#endif #include "keyboard_tracker.h" #include "logger.h" #include "screen_reader_tts.h" static AtspiDeviceListener *listener; static Keyboard_Tracker_Cb user_cb; static void *user_data; +#ifdef X11_ENABLED static Ecore_Event_Handler *root_xwindow_property_changed_hld = NULL; static Ecore_Event_Handler *active_xwindow_property_changed_hld = NULL; @@ -134,7 +137,7 @@ void root_xwindow_property_tracker_unregister() root_xwindow_property_changed_hld = NULL; } } - +#endif static gboolean device_cb(const AtspiDeviceEvent * stroke, void *data) { Key k; @@ -159,8 +162,10 @@ void keyboard_tracker_init(void) { listener = atspi_device_listener_new(device_cb, NULL, NULL); atspi_register_keystroke_listener(listener, NULL, 0, ATSPI_KEY_PRESSED, ATSPI_KEYLISTENER_SYNCHRONOUS | ATSPI_KEYLISTENER_CANCONSUME, NULL); +#ifdef X11_ENABLED active_xwindow_property_tracker_register(); root_xwindow_property_tracker_register(); +#endif DEBUG("keyboard tracker init"); } @@ -173,7 +178,9 @@ void keyboard_tracker_register(Keyboard_Tracker_Cb cb, void *data) void keyboard_tracker_shutdown(void) { atspi_deregister_keystroke_listener(listener, NULL, 0, ATSPI_KEY_PRESSED, NULL); +#ifdef X11_ENABLED root_xwindow_property_tracker_unregister(); active_xwindow_property_tracker_unregister(); +#endif DEBUG("keyboard tracker shutdown"); } diff --git a/src/navigator.c b/src/navigator.c index c965cd8..1dcc68a 100644 --- a/src/navigator.c +++ b/src/navigator.c @@ -16,7 +16,11 @@ #define _GNU_SOURCE #include +#ifdef X11_ENABLED #include +#else +#include +#endif #include #include #include @@ -1348,6 +1352,7 @@ static void _activate_widget(void) static void _quickpanel_change_state(gboolean quickpanel_switch) { DEBUG("START"); +#ifdef X11_ENABLED Ecore_X_Window xwin = 0; if (quickpanel_switch) @@ -1366,6 +1371,7 @@ static void _quickpanel_change_state(gboolean quickpanel_switch) ecore_x_e_illume_quickpanel_state_send(ecore_x_e_illume_zone_get(xwin), state); ecore_main_loop_iterate(); +#endif } /** @@ -2018,7 +2024,9 @@ static void _start_stop_signal_send(void) static void on_gesture_detected(void *data, Gesture_Info * info) { +#ifdef X11_ENABLED Ecore_X_Window keyboard_win; +#endif _on_auto_review_stop(); if (info->type == ONE_FINGER_SINGLE_TAP && info->state == 3) { @@ -2039,7 +2047,7 @@ static void on_gesture_detected(void *data, Gesture_Info * info) if ((info->event_time - _last_hover_event_time) < ONGOING_HOVER_GESTURE_INTERPRETATION_INTERVAL && info->state == 1) return; _last_hover_event_time = info->state != 1 ? -1 : info->event_time; -#ifdef ELM_ACCESS_KEYBOARD +#if defined(ELM_ACCESS_KEYBOARD) && defined(X11_ENABLED) keyboard_win = top_window_get(info->x_end, info->y_end); if (keyboard_win && ecore_x_e_virtual_keyboard_get(keyboard_win)) { elm_access_adaptor_emit_read(keyboard_win, info->x_end, info->y_end); @@ -2075,7 +2083,7 @@ static void on_gesture_detected(void *data, Gesture_Info * info) _focus_next(); break; case ONE_FINGER_SINGLE_TAP: -#ifdef ELM_ACCESS_KEYBOARD +#if defined(ELM_ACCESS_KEYBOARD) && defined(X11_ENABLED) keyboard_win = top_window_get(info->x_end, info->y_end); if (keyboard_win && ecore_x_e_virtual_keyboard_get(keyboard_win)) { elm_access_adaptor_emit_read(keyboard_win, info->x_end, info->y_end); @@ -2086,7 +2094,7 @@ static void on_gesture_detected(void *data, Gesture_Info * info) _focus_widget(info); break; case ONE_FINGER_DOUBLE_TAP: -#ifdef ELM_ACCESS_KEYBOARD +#if defined(ELM_ACCESS_KEYBOARD) && defined(X11_ENABLED) keyboard_win = top_window_get(info->x_end, info->y_end); if (keyboard_win && ecore_x_e_virtual_keyboard_get(keyboard_win)) { elm_access_adaptor_emit_activate(keyboard_win, info->x_end, info->y_end); diff --git a/src/screen_reader_gestures.c b/src/screen_reader_gestures.c index c55d606..1a83297 100644 --- a/src/screen_reader_gestures.c +++ b/src/screen_reader_gestures.c @@ -19,11 +19,21 @@ #include #include +#ifdef X11_ENABLED #include +#else +#include +#endif static GestureCB _global_cb; static void *_global_data; -static Ecore_Window win; + +#ifdef X11_ENABLED +static Ecore_X_Window win; +#else +static Ecore_Wl_Window *win; +#endif + static Ecore_Event_Handler *property_changed_hld; struct _Gestures_Config { @@ -70,7 +80,11 @@ typedef enum { } gesture_type_e; struct _Cover { +#ifdef X11_ENABLED Ecore_X_Window win; /**< Input window covering given zone */ +#else + Ecore_Wl_Window *win; /**< Input window covering given zone */ +#endif unsigned int n_taps; /**< Number of fingers touching screen */ unsigned int event_time; @@ -115,8 +129,10 @@ struct _Cover { typedef struct _Cover Cover; Gestures_Config *_e_mod_config; +#ifdef X11_ENABLED static Ecore_X_Window scrolled_win; static int rx, ry; +#endif static Eina_List *handlers; static Cover *cov; static int win_angle; @@ -126,24 +142,25 @@ static unsigned int _win_angle_get(void); void __transform_coordinates(int *ax, int *ay) { - Ecore_X_Window root; int w; int h; int tmp; +#ifdef X11_ENABLED + ecore_x_window_geometry_get(ecore_x_window_root_first_get(), NULL, NULL, &w, &h); +#else + ecore_wl_screen_size_get(&w, &h); +#endif win_angle = _win_angle_get(); switch (win_angle) { case 90: - root = ecore_x_window_root_first_get(); - ecore_x_window_geometry_get(root, NULL, NULL, &w, &h); tmp = *ax; *ax = h - *ay; *ay = tmp; break; case 270: - root = ecore_x_window_root_first_get(); - ecore_x_window_geometry_get(root, NULL, NULL, &w, &h); + tmp = *ax; *ax = *ay; *ay = w - tmp; @@ -615,7 +632,7 @@ static void _hover_gesture_mouse_up(Ecore_Event_Mouse_Button * ev, Cover * cov) if (cov->n_taps == 0) cov->hover_gesture.state = GESTURE_NOT_STARTED; } - +#ifdef X11_ENABLED static void _get_root_coords(Ecore_X_Window win, int *x, int *y) { Ecore_X_Window root = ecore_x_window_root_first_get(); @@ -648,9 +665,17 @@ Ecore_X_Window top_window_get(int x, int y) } return 0; } +#else +Ecore_Wl_Window *top_window_get(int x, int y) +{ + return 0; +} +#endif + void start_scroll(int x, int y) { +#ifdef X11_ENABLED Ecore_X_Window wins[1] = { win }; Ecore_X_Window under = ecore_x_window_at_xy_with_skip_get(x, y, wins, sizeof(wins) / sizeof(wins[0])); _get_root_coords(under, &rx, &ry); @@ -658,25 +683,31 @@ void start_scroll(int x, int y) ecore_x_window_focus(under); ecore_x_mouse_down_send(under, x - rx, y - ry, 1); scrolled_win = under; +#endif } void continue_scroll(int x, int y) { +#ifdef X11_ENABLED ecore_x_mouse_move_send(scrolled_win, x - rx, y - ry); +#endif } void end_scroll(int x, int y) { - ecore_x_mouse_up_send(scrolled_win, x - rx, y - ry, 1); +#ifdef X11_ENABLED + ecore_x_mouse_up_send(scrolled_win, x - rx, y - ry, 1); ecore_x_mouse_out_send(scrolled_win, x - rx, y - ry); +#endif } static unsigned int _win_angle_get(void) { + int angle = 0; +#ifdef X11_ENABLED Ecore_X_Window root, first_root; int ret; int count; - int angle = 0; unsigned char *prop_data = NULL; first_root = ecore_x_window_root_first_get(); @@ -688,7 +719,9 @@ static unsigned int _win_angle_get(void) if (prop_data) free(prop_data); +#else +#endif return angle; } @@ -1025,25 +1058,34 @@ static Eina_Bool _gesture_input_win_create(void) int w, h; if (!win) { +#ifdef X11_ENABLED Ecore_Window root = ecore_x_window_root_first_get(); if (!root) return EINA_FALSE; ecore_x_window_geometry_get(root, NULL, NULL, &w, &h); win = ecore_x_window_input_new(root, 0, 0, w, h); +#else + ecore_wl_screen_size_get(&w, &h); + win = ecore_wl_window_new(NULL, 0, 0, w, h, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW); +#endif } if (!win) return EINA_FALSE; +#ifdef X11_ENABLED ecore_x_input_multi_select(win); ecore_x_window_show(win); ecore_x_window_raise(win); - +#else + ecore_wl_window_show(win); + ecore_wl_window_raise(win); +#endif // restet gestures memset(cov, 0x0, sizeof(Cover)); return EINA_TRUE; } - +#ifdef X11_ENABLED static Eina_Bool _win_property_changed(void *data, int type, void *event) { Ecore_X_Event_Window_Property *wp = event; @@ -1055,9 +1097,11 @@ static Eina_Bool _win_property_changed(void *data, int type, void *event) return EINA_TRUE; } +#endif static Eina_Bool _gestures_input_window_init(void) { +#ifdef X11_ENABLED Ecore_Window root = ecore_x_window_root_first_get(); if (!root) { ERROR("No root window found. Is Window manager running?"); @@ -1065,7 +1109,7 @@ static Eina_Bool _gestures_input_window_init(void) } ecore_x_event_mask_set(root, ECORE_X_EVENT_MASK_WINDOW_PROPERTY); property_changed_hld = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, _win_property_changed, NULL); - +#endif return _gesture_input_win_create(); } @@ -1073,15 +1117,22 @@ static void _gestures_input_widnow_shutdown(void) { ecore_event_handler_del(property_changed_hld); if (win) +#ifdef X11_ENABLED ecore_x_window_free(win); +#else + ecore_wl_window_free(win); +#endif win = 0; } Eina_Bool screen_reader_gestures_init(void) { ecore_init(); +#ifdef X11_ENABLED ecore_x_init(NULL); - +#else + ecore_wl_init(NULL); +#endif cov = calloc(sizeof(Cover), 1); if (!_gestures_input_window_init()) { @@ -1112,8 +1163,11 @@ void screen_reader_gestures_shutdown(void) ecore_event_handler_del(hdlr); } _gestures_input_widnow_shutdown(); - +#ifdef X11_ENABLED ecore_x_shutdown(); +#else + ecore_wl_shutdown(); +#endif ecore_shutdown(); free(_e_mod_config); free(cov); diff --git a/src/window_tracker.c b/src/window_tracker.c index ebdb9be..4dbfc8b 100644 --- a/src/window_tracker.c +++ b/src/window_tracker.c @@ -17,8 +17,11 @@ #include #include "window_tracker.h" #include "logger.h" + +#ifdef X11_ENABLED #include #include +#endif static Window_Tracker_Cb user_cb; static void *user_data; @@ -49,8 +52,10 @@ static AtspiAccessible *_get_active_win(void) return NULL; } - Ecore_X_Window focus_window = ecore_x_window_focus_get(); unsigned int active_window_pid = 0; +#ifdef X11_ENABLED + Ecore_X_Window focus_window = ecore_x_window_focus_get(); + if (focus_window) { //invoking atspi_accessible_get_child_count for non active apps results in very long screen-reader startup //not active apps have low priority and dbus calls take a lot of time (a few hundred ms per call) @@ -60,6 +65,7 @@ static AtspiAccessible *_get_active_win(void) if (active_window_pid) DEBUG("First we will try filter apps by PID: %i", active_window_pid); } +#endif desktop_children_count = atspi_accessible_get_child_count(desktop, NULL); for (i = 0; i < desktop_children_count; i++) { AtspiAccessible *app = atspi_accessible_get_child_at_index(desktop, i, NULL); -- 2.7.4 From 55443e3c996b8960ecb390a508073ad97fcc445a Mon Sep 17 00:00:00 2001 From: Tomasz Olszak Date: Wed, 28 Oct 2015 17:59:28 +0100 Subject: [PATCH 07/16] Make the condition in flat_navi_context_current_at_x_y_set more readable Change-Id: I08ef56c290f13739927e238221494c18856a6dde --- src/flat_navi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/flat_navi.c b/src/flat_navi.c index a7f299f..20176a7 100644 --- a/src/flat_navi.c +++ b/src/flat_navi.c @@ -358,7 +358,11 @@ Eina_Bool flat_navi_context_current_at_x_y_set(FlatNaviContext * ctx, gint x_cor } if (youngest_ancestor_in_context && !_object_has_modal_state(youngest_ancestor_in_context)) { - if (youngest_ancestor_in_context == current_obj || flat_navi_context_current_set(ctx, youngest_ancestor_in_context)) { + + Eina_Bool update_target = youngest_ancestor_in_context == current_obj; + if (!update_target) + update_target = flat_navi_context_current_set(ctx, youngest_ancestor_in_context); + if (update_target) { DEBUG("Setting highlight to object %s with role %s", atspi_accessible_get_name(youngest_ancestor_in_context, NULL), atspi_accessible_get_role_name(youngest_ancestor_in_context, NULL)); *target = youngest_ancestor_in_context; ret = EINA_TRUE; -- 2.7.4 From 5f959737dd27e5dd374bcd6db77e0770d49379fc Mon Sep 17 00:00:00 2001 From: Lukasz Stanislawski Date: Thu, 24 Sep 2015 13:43:06 +0200 Subject: [PATCH 08/16] lua: add lua engine to process internal logic Change-Id: Idd194972e06d1c6764d9fde4178afb54eebfeafa --- CMakeLists.txt | 4 + include/lua_engine.h | 64 +++ include/screen_reader.h | 1 + include/screen_reader_spi.h | 1 + packaging/org.tizen.screen-reader.spec | 2 + res/po/en_US.po | 2 +- res/scripts/mobile.lua | 129 ++++++ src/lua_engine.c | 809 +++++++++++++++++++++++++++++++++ src/navigator.c | 562 +---------------------- src/screen_reader.c | 5 + src/screen_reader_spi.c | 110 +---- tests/CMakeLists.txt | 2 + tests/atspi/atspi.c | 26 ++ tests/atspi/atspi.h | 238 +++++----- tests/smart_navi_suite.c | 29 +- 15 files changed, 1213 insertions(+), 771 deletions(-) create mode 100644 include/lua_engine.h create mode 100644 res/scripts/mobile.lua create mode 100644 src/lua_engine.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8044755..da4d5df 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ SET(SRCS ${CMAKE_SOURCE_DIR}/src/app_tracker.c ${CMAKE_SOURCE_DIR}/src/screen_reader_tts.c ${CMAKE_SOURCE_DIR}/src/screen_reader_vconf.c ${CMAKE_SOURCE_DIR}/src/smart_notification.c + ${CMAKE_SOURCE_DIR}/src/lua_engine.c ) @@ -23,6 +24,7 @@ SET(SRCS ${CMAKE_SOURCE_DIR}/src/app_tracker.c INCLUDE(CMakeLists.sub) SET(RESOURCE_DIR "${CMAKE_SOURCE_DIR}/res") SET(LOCALEDIR "/usr/apps/org.tizen.screen-reader/res/locale") +ADD_DEFINITIONS(-DSCRIPTDIR="/usr/apps/org.tizen.screen-reader/res/scripts") IF("${SEC_FEATURE_TAPI_ENABLE}" STREQUAL "1") MESSAGE("SEC_FEATURE_TAPI_ENABLE: ${SEC_FEATURE_TAPI_ENABLE}") @@ -65,6 +67,7 @@ pkg_check_modules(pkgs REQUIRED capi-network-bluetooth notification capi-network-wifi + lua ${TAPI_REQUIRED_PKG} ${CONDITIONAL_PACKAGES} ) @@ -85,6 +88,7 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${SLP_LD_PATH_FLAGS} ${SLP # Install INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) INSTALL(DIRECTORY ${RESOURCE_DIR}/icons DESTINATION res) +INSTALL(DIRECTORY ${RESOURCE_DIR}/scripts DESTINATION res) # Install Manifest File INSTALL(FILES org.tizen.screen-reader.xml DESTINATION /usr/share/packages) diff --git a/include/lua_engine.h b/include/lua_engine.h new file mode 100644 index 0000000..7ca15ea --- /dev/null +++ b/include/lua_engine.h @@ -0,0 +1,64 @@ +#ifndef _LUA_ENGINE_H__ +#define _LUA_ENGINE_H__ + +#include + +/** + * @brief Registers additional AT-SPI2 related method on given lua state. + * + * + * List of additional lua functions: + * + * desktop() -- global function returning desktop frame object. + * T() -- returns translated string using gettext function. + * + * # Accessible object class methods + * name() -- return string with accessible name of object. + * description() -- return string with accessible description of object. + * children() -- return table with accessible children references. + * parent() -- return accessible parent reference. + * role() -- return accessible role of object. + * inRelation(r) -- return table with references to accessible objects in relation 'd'. + * roleName() -- return string with name of the role. + * is(s) -- return true is accessible object has state 's'. + * index() -- return index of accessible object in its parent list. + * value() -- return reference to value object or nil + * selection() -- return reference to selection object or nil + * + * # Value object class methods + * current() -- return current value of value object. + * range() -- return minimal and maximal (tuple: min, max) values of value object. + * increment() -- return minimal incremetation value of value object. + * + * # Selection object class methods + * count() -- return number of selected children of selection object. + * isSelected(i) -- return true if 'i' child of selection object is selected. + * + * @param absolute path to lua script. + * @return 0 on success, different value on failure. + */ +int lua_engine_init(const char *script); + +/* + * @brief Create a description for given accessible object. + * + * Internally it calls 'describeObject' function from lua script loaded in + * lua_engine_init + * + * Function 'describeObject' must have following prototype: + * + * function describeObject(obj) + * return "some string" + * end + * + * @param AtspiAccessible reference + * @return string with a text describing object 'obj'. Should be free. + */ +char *lua_engine_describe_object(AtspiAccessible *obj); + +/* + * @brief Shutdowns lua engine + */ +void lua_engine_shutdown(); + +#endif diff --git a/include/screen_reader.h b/include/screen_reader.h index 7608a6f..28829ff 100644 --- a/include/screen_reader.h +++ b/include/screen_reader.h @@ -63,6 +63,7 @@ typedef struct _Service_Data char **available_apps; const char *text_from_dbus; + const char *lua_script_path; } Service_Data; Service_Data *get_pointer_to_service_data_struct(); diff --git a/include/screen_reader_spi.h b/include/screen_reader_spi.h index c616369..d020790 100644 --- a/include/screen_reader_spi.h +++ b/include/screen_reader_spi.h @@ -7,5 +7,6 @@ void spi_init(Service_Data *sd); void spi_event_listener_cb(AtspiEvent *event, void *user_data); char *spi_event_get_text_to_read(AtspiEvent *event, void *user_data); +void spi_shutdown(Service_Data *sd); #endif /* SCREEN_READER_SPI_H_ */ diff --git a/packaging/org.tizen.screen-reader.spec b/packaging/org.tizen.screen-reader.spec index 9d10be4..f75613f 100755 --- a/packaging/org.tizen.screen-reader.spec +++ b/packaging/org.tizen.screen-reader.spec @@ -37,6 +37,7 @@ BuildRequires: pkgconfig(capi-network-wifi) %if "%{?profile}" != "tv" BuildRequires: pkgconfig(tapi) %endif +BuildRequires: pkgconfig(lua) %description An utility library for developers of the menu screen. @@ -84,3 +85,4 @@ rm -rf %{buildroot} %{AppInstallPath}/res/icons/screen-reader.png %{AppInstallPath}/res/locale/*/LC_MESSAGES/* /usr/share/packages/%{name}.xml +%{AppInstallPath}/res/scripts/* diff --git a/res/po/en_US.po b/res/po/en_US.po index 04325e4..4476e6d 100644 --- a/res/po/en_US.po +++ b/res/po/en_US.po @@ -51,7 +51,7 @@ msgid "IDS_TRAIT_GROUP_INDEX_COLLAPSED" msgstr "Expandable list, Double tap to expand" msgid "IDS_TRAIT_MENU_ITEM_TAB_INDEX" -msgstr "Tab %1$d of %2$d" +msgstr "Tab %d of %d" msgid "IDS_TRAIT_TEXT_EDIT" msgstr "Double tap to edit" diff --git a/res/scripts/mobile.lua b/res/scripts/mobile.lua new file mode 100644 index 0000000..c53c2e0 --- /dev/null +++ b/res/scripts/mobile.lua @@ -0,0 +1,129 @@ +function entry_trait(obj) + local ret = "" + if obj:is(FOCUSED) then + ret = T("IDS_TRAIT_TEXT_EDIT_FOCUSED") + else + ret = T("IDS_TRAIT_TEXT_EDIT") + end + return obj:roleName() .. ", " .. ret +end + +function menu_item_trait(obj) + n = table.getn(obj:parent():children()) + return string.format(T("IDS_TRAIT_MENU_ITEM_TAB_INDEX"), obj:index() + 1, n) +end + +function popup_menu_trait(obj) + local tr = { T("IDS_TRAIT_CTX_POPUP") , T("IDS_TRAIT_SHOWING") , tostring(table.getn(obj:children())), + T("IDS_TRAIT_ITEMS") , T("IDS_TRAIT_POPUP_CLOSE")} + return table.concat(tr, " ") +end + +function dialog_trait(obj) + local n = table.getn(obj:children()) + local ret = T("IDS_TRAIT_POPUP") + if n > 0 then + ret = ret .. T("IDS_TRAIT_SHOWING") .. " " .. tostring(n) .. " " .. T("IDS_TRAIT_ITEMS") + end + return ret .. T("IDS_TRAIT_POPUP_CLOSE") +end + +function list_item_trait(obj) + local ret = "" + local p = obj:parent() + if p and p:is(MULTISELECTABLE) then + if obj:is(SELECTED) then + ret = ret .. T("IDS_TRAIT_ITEM_SELECTED") + end + if p:selection() then + ret = ret .. string.format(T("IDS_TRAIT_ITEM_SELECTED_COUNT"), p:selection():count()) + end + else + if obj:is(EXPANDABLE) then + if obj:is(EXPANDED) then + ret = ret .. T("IDS_TRAIT_GROUP_INDEX_EXPANDED") + else + ret = ret .. T("IDS_TRAIT_GROUP_INDEX_COLLAPSED") + end + end + end + return ret +end + +function check_radio_trait(obj) + if obj:is(CHECKED) then + return T("IDS_TRAIT_CHECK_BOX_SELECTED") + else + return T("IDS_TRAIT_CHECK_BOX_NOT_SELECTED") + end +end + +function push_button_trait(obj) + return T("IDS_TRAIT_PUSH_BUTTON") +end + +function progress_bar_trait(obj) + if obj:value() then + cv = obj:value():current() + if cv >= 0 then + return string.format(T("IDS_TRAIT_PD_PROGRESSBAR_PERCENT"), cv * 100) + else + return T("IDS_TRAIT_PD_PROGRESSBAR") + end + end + return "" +end + +function toggle_button_trait(obj) + if obj:is(CHECKED) then + local state = T("IDS_TRAIT_TOGGLE_BUTTON_ON") + else + local state = T("IDS_TRAIT_TOGGLE_BUTTON_OFF") + end + return T("IDS_TRAIT_TOGGLE_BUTTON") .. ", " .. state +end + +function heading_trait(obj) + return "" +end + +function default_trait(obj) + return obj:roleName() +end + +local trait_map = { + [ENTRY] = entry_trait, + [MENU_ITEM] = menu_item_trait, + [POPUP_MENU] = popup_menu_trait, + [DIALOG] = dialog_trait, + [LIST_ITEM] = list_item_trait, + [CHECK_BOX] = check_radio_trait, + [RADIO_BUTTON] = check_radio_trait, + [PUSH_BUTTON] = push_button_trait, + [PROGRESS_BAR] = progress_bar_trait, + [TOGGLE_BUTTON] = toggle_button_trait, + [HEADING] = heading_trait, +} + +function trait(obj) + local func = trait_map[obj:role()] + if func ~= nil then + return func(obj) + else + return default_trait(obj) + end +end + +function describeObject(obj) + local related_trait = {} + for k, target in ipairs(obj:inRelation(RELATION_DESCRIBED_BY)) do + table.insert(related_trait, trait(target)) + end + local ret = {obj:name(), trait(obj), obj:description(), table.concat(related_trait, ", ")} + for i=#ret,1,-1 do + if ret[i] == nil or ret[i] == "" then + table.remove(ret, i) + end + end + return table.concat(ret, ", ") +end diff --git a/src/lua_engine.c b/src/lua_engine.c new file mode 100644 index 0000000..b2d8207 --- /dev/null +++ b/src/lua_engine.c @@ -0,0 +1,809 @@ +#include +#include +#include + +#include +#include + +#include "logger.h" +#include "lua_engine.h" + +#include + +#define ACCESSIBLE_CLASS_NAME "Accessible" +#define VALUE_CLASS_NAME "Value" +#define SELECTION_CLASS_NAME "Selection" + +#define GERROR_CHECK(err) \ + if (err) { lua_error(L); printf("GError: %s\n", err->message); g_error_free(err); } + +static lua_State *L; + + +static void *_pop_class_obj(lua_State *L, int index, int narg, const char *class) +{ + luaL_checktype(L, narg, LUA_TUSERDATA); + void **ret = lua_touserdata(L, index); + if (!ret) luaL_typerror(L, narg, class); + return *ret; +} + +static void _push_class_obj(lua_State *L, void *obj, const char *class) +{ + void **ptr = lua_newuserdata(L, sizeof(void*)); + *ptr = obj; + luaL_getmetatable(L, class); + lua_setmetatable(L, -2); +} + +static int _accessible_name(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, -1, 1, ACCESSIBLE_CLASS_NAME); + GError *err = NULL; + if (!obj) return 0; + + char *name = atspi_accessible_get_name(obj, &err); + GERROR_CHECK(err); + + lua_pushstring(L, name); + g_free(name); + return 1; +} + +static int _accessible_description(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + GError *err = NULL; + if (!obj) + return 0; + char *name = atspi_accessible_get_description(obj, &err); + GERROR_CHECK(err); + + lua_pushstring(L, name); + g_free(name); + return 1; +} + +static int l_get_root(lua_State *L) { + AtspiAccessible *root = atspi_get_desktop(0); + _push_class_obj(L, root, ACCESSIBLE_CLASS_NAME); + return 1; +} + +static int l_get_translation(lua_State *L) { + const char *str = lua_tostring(L, -1); + lua_pushstring(L, _(str)); + return 1; +} + +static int _accessible_children(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + GError *err = NULL; + if (!obj) + return 0; + int i, n = atspi_accessible_get_child_count(obj, &err); + GERROR_CHECK(err); + + lua_createtable(L, n, 0); + + for (i = 0; i < n; i++) + { + AtspiAccessible *child = atspi_accessible_get_child_at_index(obj, i, &err); + if (!child) continue; + GERROR_CHECK(err); + lua_pushinteger(L, i + 1); + _push_class_obj(L, child, ACCESSIBLE_CLASS_NAME); + lua_settable(L, -3); + } + return 1; +} + +static int _accessible_parent(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + GError *err = NULL; + if (!obj) return 0; + + AtspiAccessible *parent = atspi_accessible_get_parent(obj, &err); + if (!parent) return 0; + GERROR_CHECK(err); + _push_class_obj(L, parent, ACCESSIBLE_CLASS_NAME); + + return 1; +} + +static int _accessible_role(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + GError *err = NULL; + if (!obj) return 0; + + AtspiRole role = atspi_accessible_get_role(obj, &err); + GERROR_CHECK(err); + + lua_pushinteger(L, role); + + return 1; +} + +static int _accessible_role_name(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + GError *err = NULL; + if (!obj) { + return 0; + } + char *name = atspi_accessible_get_localized_role_name(obj, &err); + GERROR_CHECK(err); + + lua_pushstring(L, name); + g_free(name); + return 1; +} + +static int _accessible_is(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + AtspiStateType type = lua_tonumber(L, -1); + + AtspiStateSet *ss = atspi_accessible_get_state_set(obj); + + if (atspi_state_set_contains(ss, type)) + lua_pushboolean(L, 1); + else + lua_pushboolean(L, 0); + + return 1; +} + +static int _accessible_index(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + GError *err = NULL; + if (!obj) return 0; + + int idx = atspi_accessible_get_index_in_parent(obj, &err); + GERROR_CHECK(err); + + lua_pushinteger(L, idx); + return 1; +} + +static int _accessible_relations(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + AtspiRelationType type = lua_tonumber(L, -1); + GError *err = NULL; + int i, j; + + lua_newtable(L); + if (!obj) return 1; + GArray *rels = atspi_accessible_get_relation_set(obj, &err); + GERROR_CHECK(err); + if (!rels) return 1; + + for (i = 0; i < rels->len; i++) + { + AtspiRelation *rel = g_array_index(rels, AtspiRelation*, i); + if (atspi_relation_get_relation_type(rel) == type) + { + for (j = 0; j < atspi_relation_get_n_targets(rel); j++) + { + AtspiAccessible *target = atspi_relation_get_target(rel, j); + if (!target) continue; + lua_pushinteger(L, j); + _push_class_obj(L, target, ACCESSIBLE_CLASS_NAME); + lua_settable(L, -3); + } + } + g_object_unref(rel); + } + g_array_free(rels, TRUE); + + return 1; +} + +static int _accessible_value(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + AtspiValue *val = atspi_accessible_get_value_iface(obj); + if (!val) + { + lua_pushnil(L); + return 1; + } + _push_class_obj(L, val, VALUE_CLASS_NAME); + return 1; +} + +static int _accessible_selection(lua_State *L) { + AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); + AtspiSelection *sel = atspi_accessible_get_selection_iface(obj); + if (!sel) + { + lua_pushnil(L); + return 1; + } + _push_class_obj(L, sel, SELECTION_CLASS_NAME); + return 1; +} + +static int _gobject_unref(lua_State *L) { +#ifdef SCREEN_READER_FLAT_NAVI_TEST_DUMMY_IMPLEMENTATION + return 0; +#else + void **ret = lua_touserdata(L, -1); + g_object_unref(*ret); + return 0; +#endif +} + +static const luaL_reg _meta_methods[] = { + { "__gc", _gobject_unref}, + { NULL, NULL} +}; + +static const luaL_reg _accessible_methods[] = { + { "name", _accessible_name }, + { "description", _accessible_description }, + { "children", _accessible_children }, + { "parent", _accessible_parent }, + { "role", _accessible_role }, + { "inRelation", _accessible_relations }, + { "roleName", _accessible_role_name }, + { "is", _accessible_is }, + { "index", _accessible_index }, + { "value", _accessible_value }, + { "selection", _accessible_selection }, + { NULL, NULL} +}; + +static int _value_current_value(lua_State *L) { + AtspiValue *val = _pop_class_obj(L, -1, 1, VALUE_CLASS_NAME); + GError *err = NULL; + + double cv = atspi_value_get_current_value(val, &err); + GERROR_CHECK(err); + + lua_pushnumber(L, cv); + + return 1; +} + +static int _value_range(lua_State *L) { + AtspiValue *val = _pop_class_obj(L, -1, 1, VALUE_CLASS_NAME); + GError *err = NULL; + double max, min; + + max = atspi_value_get_maximum_value(val, &err); + GERROR_CHECK(err); + + min = atspi_value_get_minimum_value(val, &err); + GERROR_CHECK(err); + + lua_pushnumber(L, min); + lua_pushnumber(L, max); + + return 2; +} + +static int _value_increment(lua_State *L) { + AtspiValue *val = _pop_class_obj(L, 1, 1, VALUE_CLASS_NAME); + GError *err = NULL; + + double mi = atspi_value_get_minimum_increment(val, &err); + GERROR_CHECK(err); + + lua_pushnumber(L, mi); + + return 1; +} + +static const luaL_reg _value_methods[] = { + { "current", _value_current_value }, + { "range", _value_range }, + { "increment", _value_increment }, + { NULL, NULL} +}; + +static int _selection_is_selected(lua_State *L) { + AtspiSelection *sel = _pop_class_obj(L, 1, 1, SELECTION_CLASS_NAME); + GError *err = NULL; + int id = lua_tointeger(L, -1); + + gboolean ret = atspi_selection_is_child_selected(sel, id, &err); + GERROR_CHECK(err); + + lua_pushboolean(L, ret); + + return 1; +} + +static int _selection_count(lua_State *L) { + AtspiSelection *sel = _pop_class_obj(L, 1, 1, SELECTION_CLASS_NAME); + GError *err = NULL; + + int mi = atspi_selection_get_n_selected_children(sel, &err); + GERROR_CHECK(err); + + lua_pushinteger(L, mi); + + return 1; +} + +static const luaL_reg _selection_methods[] = { + { "count", _selection_count }, + { "isSelected", _selection_is_selected }, + { NULL, NULL} +}; + +static void _register_role_enums(lua_State *L) +{ + lua_pushinteger(L, ATSPI_ROLE_INVALID); + lua_setglobal(L, "INVALID"); + lua_pushinteger(L, ATSPI_ROLE_ACCELERATOR_LABEL); + lua_setglobal(L, "ACCELERATOR_LABEL"); + lua_pushinteger(L, ATSPI_ROLE_ALERT); + lua_setglobal(L, "ALERT"); + lua_pushinteger(L, ATSPI_ROLE_ANIMATION); + lua_setglobal(L, "ANIMATION"); + lua_pushinteger(L, ATSPI_ROLE_ARROW); + lua_setglobal(L, "ARROW"); + lua_pushinteger(L, ATSPI_ROLE_CALENDAR); + lua_setglobal(L, "CALENDAR"); + lua_pushinteger(L, ATSPI_ROLE_CANVAS); + lua_setglobal(L, "CANVAS"); + lua_pushinteger(L, ATSPI_ROLE_CHECK_BOX); + lua_setglobal(L, "CHECK_BOX"); + lua_pushinteger(L, ATSPI_ROLE_CHECK_MENU_ITEM); + lua_setglobal(L, "CHECK_MENU_ITEM"); + lua_pushinteger(L, ATSPI_ROLE_COLOR_CHOOSER); + lua_setglobal(L, "COLOR_CHOOSER"); + lua_pushinteger(L, ATSPI_ROLE_COLUMN_HEADER); + lua_setglobal(L, "COLUMN_HEADER"); + lua_pushinteger(L, ATSPI_ROLE_COMBO_BOX); + lua_setglobal(L, "COMBO_BOX"); + lua_pushinteger(L, ATSPI_ROLE_DATE_EDITOR); + lua_setglobal(L, "DATE_EDITOR"); + lua_pushinteger(L, ATSPI_ROLE_DESKTOP_ICON); + lua_setglobal(L, "DESKTOP_ICON"); + lua_pushinteger(L, ATSPI_ROLE_DESKTOP_FRAME); + lua_setglobal(L, "DESKTOP_FRAME"); + lua_pushinteger(L, ATSPI_ROLE_DIAL); + lua_setglobal(L, "DIAL"); + lua_pushinteger(L, ATSPI_ROLE_DIALOG); + lua_setglobal(L, "DIALOG"); + lua_pushinteger(L, ATSPI_ROLE_DIRECTORY_PANE); + lua_setglobal(L, "DIRECTORY_PANE"); + lua_pushinteger(L, ATSPI_ROLE_DRAWING_AREA); + lua_setglobal(L, "DRAWING_AREA"); + lua_pushinteger(L, ATSPI_ROLE_FILE_CHOOSER); + lua_setglobal(L, "FILE_CHOOSER"); + lua_pushinteger(L, ATSPI_ROLE_FILLER); + lua_setglobal(L, "FILLER"); + lua_pushinteger(L, ATSPI_ROLE_FOCUS_TRAVERSABLE); + lua_setglobal(L, "FOCUS_TRAVERSABLE"); + lua_pushinteger(L, ATSPI_ROLE_FONT_CHOOSER); + lua_setglobal(L, "FONT_CHOOSER"); + lua_pushinteger(L, ATSPI_ROLE_FRAME); + lua_setglobal(L, "FRAME"); + lua_pushinteger(L, ATSPI_ROLE_GLASS_PANE); + lua_setglobal(L, "GLASS_PANE"); + lua_pushinteger(L, ATSPI_ROLE_HTML_CONTAINER); + lua_setglobal(L, "HTML_CONTAINER"); + lua_pushinteger(L, ATSPI_ROLE_ICON); + lua_setglobal(L, "ICON"); + lua_pushinteger(L, ATSPI_ROLE_IMAGE); + lua_setglobal(L, "IMAGE"); + lua_pushinteger(L, ATSPI_ROLE_INTERNAL_FRAME); + lua_setglobal(L, "INTERNAL_FRAME"); + lua_pushinteger(L, ATSPI_ROLE_LABEL); + lua_setglobal(L, "LABEL"); + lua_pushinteger(L, ATSPI_ROLE_LAYERED_PANE); + lua_setglobal(L, "LAYERED_PANE"); + lua_pushinteger(L, ATSPI_ROLE_LIST); + lua_setglobal(L, "LIST"); + lua_pushinteger(L, ATSPI_ROLE_LIST_ITEM); + lua_setglobal(L, "LIST_ITEM"); + lua_pushinteger(L, ATSPI_ROLE_MENU); + lua_setglobal(L, "MENU"); + lua_pushinteger(L, ATSPI_ROLE_MENU_BAR); + lua_setglobal(L, "MENU_BAR"); + lua_pushinteger(L, ATSPI_ROLE_MENU_ITEM); + lua_setglobal(L, "MENU_ITEM"); + lua_pushinteger(L, ATSPI_ROLE_OPTION_PANE); + lua_setglobal(L, "OPTION_PANE"); + lua_pushinteger(L, ATSPI_ROLE_PAGE_TAB); + lua_setglobal(L, "PAGE_TAB"); + lua_pushinteger(L, ATSPI_ROLE_PAGE_TAB_LIST); + lua_setglobal(L, "PAGE_TAB_LIST"); + lua_pushinteger(L, ATSPI_ROLE_PANEL); + lua_setglobal(L, "PANEL"); + lua_pushinteger(L, ATSPI_ROLE_PASSWORD_TEXT); + lua_setglobal(L, "PASSWORD_TEXT"); + lua_pushinteger(L, ATSPI_ROLE_POPUP_MENU); + lua_setglobal(L, "POPUP_MENU"); + lua_pushinteger(L, ATSPI_ROLE_PROGRESS_BAR); + lua_setglobal(L, "PROGRESS_BAR"); + lua_pushinteger(L, ATSPI_ROLE_PUSH_BUTTON); + lua_setglobal(L, "PUSH_BUTTON"); + lua_pushinteger(L, ATSPI_ROLE_RADIO_BUTTON); + lua_setglobal(L, "RADIO_BUTTON"); + lua_pushinteger(L, ATSPI_ROLE_RADIO_MENU_ITEM); + lua_setglobal(L, "RADIO_MENU_ITEM"); + lua_pushinteger(L, ATSPI_ROLE_ROOT_PANE); + lua_setglobal(L, "ROOT_PANE"); + lua_pushinteger(L, ATSPI_ROLE_ROW_HEADER); + lua_setglobal(L, "ROW_HEADER"); + lua_pushinteger(L, ATSPI_ROLE_SCROLL_BAR); + lua_setglobal(L, "SCROLL_BAR"); + lua_pushinteger(L, ATSPI_ROLE_SCROLL_PANE); + lua_setglobal(L, "SCROLL_PANE"); + lua_pushinteger(L, ATSPI_ROLE_SEPARATOR); + lua_setglobal(L, "SEPARATOR"); + lua_pushinteger(L, ATSPI_ROLE_SLIDER); + lua_setglobal(L, "SLIDER"); + lua_pushinteger(L, ATSPI_ROLE_SPIN_BUTTON); + lua_setglobal(L, "SPIN_BUTTON"); + lua_pushinteger(L, ATSPI_ROLE_SPLIT_PANE); + lua_setglobal(L, "SPLIT_PANE"); + lua_pushinteger(L, ATSPI_ROLE_STATUS_BAR); + lua_setglobal(L, "STATUS_BAR"); + lua_pushinteger(L, ATSPI_ROLE_TABLE); + lua_setglobal(L, "TABLE"); + lua_pushinteger(L, ATSPI_ROLE_TABLE_CELL); + lua_setglobal(L, "TABLE_CELL"); + lua_pushinteger(L, ATSPI_ROLE_TABLE_COLUMN_HEADER); + lua_setglobal(L, "TABLE_COLUMN_HEADER"); + lua_pushinteger(L, ATSPI_ROLE_TABLE_ROW_HEADER); + lua_setglobal(L, "TABLE_ROW_HEADER"); + lua_pushinteger(L, ATSPI_ROLE_TEAROFF_MENU_ITEM); + lua_setglobal(L, "TEAROFF_MENU_ITEM"); + lua_pushinteger(L, ATSPI_ROLE_TERMINAL); + lua_setglobal(L, "TERMINAL"); + lua_pushinteger(L, ATSPI_ROLE_TEXT); + lua_setglobal(L, "TEXT"); + lua_pushinteger(L, ATSPI_ROLE_TOGGLE_BUTTON); + lua_setglobal(L, "TOGGLE_BUTTON"); + lua_pushinteger(L, ATSPI_ROLE_TOOL_BAR); + lua_setglobal(L, "TOOL_BAR"); + lua_pushinteger(L, ATSPI_ROLE_TOOL_TIP); + lua_setglobal(L, "TOOL_TIP"); + lua_pushinteger(L, ATSPI_ROLE_TREE); + lua_setglobal(L, "TREE"); + lua_pushinteger(L, ATSPI_ROLE_TREE_TABLE); + lua_setglobal(L, "TREE_TABLE"); + lua_pushinteger(L, ATSPI_ROLE_UNKNOWN); + lua_setglobal(L, "UNKNOWN"); + lua_pushinteger(L, ATSPI_ROLE_VIEWPORT); + lua_setglobal(L, "VIEWPORT"); + lua_pushinteger(L, ATSPI_ROLE_WINDOW); + lua_setglobal(L, "WINDOW"); + lua_pushinteger(L, ATSPI_ROLE_EXTENDED); + lua_setglobal(L, "EXTENDED"); + lua_pushinteger(L, ATSPI_ROLE_HEADER); + lua_setglobal(L, "HEADER"); + lua_pushinteger(L, ATSPI_ROLE_FOOTER); + lua_setglobal(L, "FOOTER"); + lua_pushinteger(L, ATSPI_ROLE_PARAGRAPH); + lua_setglobal(L, "PARAGRAPH"); + lua_pushinteger(L, ATSPI_ROLE_RULER); + lua_setglobal(L, "RULER"); + lua_pushinteger(L, ATSPI_ROLE_APPLICATION); + lua_setglobal(L, "APPLICATION"); + lua_pushinteger(L, ATSPI_ROLE_AUTOCOMPLETE); + lua_setglobal(L, "AUTOCOMPLETE"); + lua_pushinteger(L, ATSPI_ROLE_EDITBAR); + lua_setglobal(L, "EDITBAR"); + lua_pushinteger(L, ATSPI_ROLE_EMBEDDED); + lua_setglobal(L, "EMBEDDED"); + lua_pushinteger(L, ATSPI_ROLE_ENTRY); + lua_setglobal(L, "ENTRY"); + lua_pushinteger(L, ATSPI_ROLE_CHART); + lua_setglobal(L, "CHART"); + lua_pushinteger(L, ATSPI_ROLE_CAPTION); + lua_setglobal(L, "CAPTION"); + lua_pushinteger(L, ATSPI_ROLE_DOCUMENT_FRAME); + lua_setglobal(L, "DOCUMENT_FRAME"); + lua_pushinteger(L, ATSPI_ROLE_HEADING); + lua_setglobal(L, "HEADING"); + lua_pushinteger(L, ATSPI_ROLE_PAGE); + lua_setglobal(L, "PAGE"); + lua_pushinteger(L, ATSPI_ROLE_SECTION); + lua_setglobal(L, "SECTION"); + lua_pushinteger(L, ATSPI_ROLE_REDUNDANT_OBJECT); + lua_setglobal(L, "REDUNDANT_OBJECT"); + lua_pushinteger(L, ATSPI_ROLE_FORM); + lua_setglobal(L, "FORM"); + lua_pushinteger(L, ATSPI_ROLE_LINK); + lua_setglobal(L, "LINK"); + lua_pushinteger(L, ATSPI_ROLE_INPUT_METHOD_WINDOW); + lua_setglobal(L, "INPUT_METHOD_WINDOW"); + lua_pushinteger(L, ATSPI_ROLE_TABLE_ROW); + lua_setglobal(L, "TABLE_ROW"); + lua_pushinteger(L, ATSPI_ROLE_TREE_ITEM); + lua_setglobal(L, "TREE_ITEM"); + lua_pushinteger(L, ATSPI_ROLE_DOCUMENT_SPREADSHEET); + lua_setglobal(L, "DOCUMENT_SPREADSHEET"); + lua_pushinteger(L, ATSPI_ROLE_DOCUMENT_PRESENTATION); + lua_setglobal(L, "DOCUMENT_PRESENTATION"); + lua_pushinteger(L, ATSPI_ROLE_DOCUMENT_TEXT); + lua_setglobal(L, "DOCUMENT_TEXT"); + lua_pushinteger(L, ATSPI_ROLE_DOCUMENT_WEB); + lua_setglobal(L, "DOCUMENT_WEB"); + lua_pushinteger(L, ATSPI_ROLE_DOCUMENT_EMAIL); + lua_setglobal(L, "DOCUMENT_EMAIL"); + lua_pushinteger(L, ATSPI_ROLE_COMMENT); + lua_setglobal(L, "COMMENT"); + lua_pushinteger(L, ATSPI_ROLE_LIST_BOX); + lua_setglobal(L, "LIST_BOX"); + lua_pushinteger(L, ATSPI_ROLE_GROUPING); + lua_setglobal(L, "GROUPING"); + lua_pushinteger(L, ATSPI_ROLE_IMAGE_MAP); + lua_setglobal(L, "IMAGE_MAP"); + lua_pushinteger(L, ATSPI_ROLE_NOTIFICATION); + lua_setglobal(L, "NOTIFICATION"); + lua_pushinteger(L, ATSPI_ROLE_INFO_BAR); + lua_setglobal(L, "INFO_BAR"); + lua_pushinteger(L, ATSPI_ROLE_LEVEL_BAR); + lua_setglobal(L, "LEVEL_BAR"); + lua_pushinteger(L, ATSPI_ROLE_TITLE_BAR); + lua_setglobal(L, "TITLE_BAR"); + lua_pushinteger(L, ATSPI_ROLE_BLOCK_QUOTE); + lua_setglobal(L, "BLOCK_QUOTE"); + lua_pushinteger(L, ATSPI_ROLE_AUDIO); + lua_setglobal(L, "AUDIO"); + lua_pushinteger(L, ATSPI_ROLE_VIDEO); + lua_setglobal(L, "VIDEO"); + lua_pushinteger(L, ATSPI_ROLE_DEFINITION); + lua_setglobal(L, "DEFINITION"); + lua_pushinteger(L, ATSPI_ROLE_ARTICLE); + lua_setglobal(L, "ARTICLE"); + lua_pushinteger(L, ATSPI_ROLE_LANDMARK); + lua_setglobal(L, "LANDMARK"); + lua_pushinteger(L, ATSPI_ROLE_LOG); + lua_setglobal(L, "LOG"); + lua_pushinteger(L, ATSPI_ROLE_MARQUEE); + lua_setglobal(L, "MARQUEE"); + lua_pushinteger(L, ATSPI_ROLE_MATH); + lua_setglobal(L, "MATH"); + lua_pushinteger(L, ATSPI_ROLE_RATING); + lua_setglobal(L, "RATING"); + lua_pushinteger(L, ATSPI_ROLE_TIMER); + lua_setglobal(L, "TIMER"); + lua_pushinteger(L, ATSPI_ROLE_STATIC); + lua_setglobal(L, "STATIC"); + lua_pushinteger(L, ATSPI_ROLE_MATH_FRACTION); + lua_setglobal(L, "MATH_FRACTION"); + lua_pushinteger(L, ATSPI_ROLE_MATH_ROOT); + lua_setglobal(L, "MATH_ROOT"); + lua_pushinteger(L, ATSPI_ROLE_SUBSCRIPT); + lua_setglobal(L, "SUBSCRIPT"); + lua_pushinteger(L, ATSPI_ROLE_SUPERSCRIPT); + lua_setglobal(L, "SUPERSCRIPT"); + lua_pushinteger(L, ATSPI_ROLE_LAST_DEFINED); + lua_setglobal(L, "LAST_DEFINED"); + + // relations enums + lua_pushinteger(L, ATSPI_RELATION_NULL); + lua_setglobal(L, "RELATION_NULL"); + lua_pushinteger(L, ATSPI_RELATION_LABEL_FOR); + lua_setglobal(L, "RELATION_LABEL_FOR"); + lua_pushinteger(L, ATSPI_RELATION_LABELLED_BY); + lua_setglobal(L, "RELATION_LABELLED_BY"); + lua_pushinteger(L, ATSPI_RELATION_CONTROLLER_FOR); + lua_setglobal(L, "RELATION_CONTROLLER_FOR"); + lua_pushinteger(L, ATSPI_RELATION_CONTROLLED_BY); + lua_setglobal(L, "RELATION_CONTROLLED_BY"); + lua_pushinteger(L, ATSPI_RELATION_MEMBER_OF); + lua_setglobal(L, "RELATION_MEMBER_OF"); + lua_pushinteger(L, ATSPI_RELATION_TOOLTIP_FOR); + lua_setglobal(L, "RELATION_TOOLTIP_FOR"); + lua_pushinteger(L, ATSPI_RELATION_NODE_CHILD_OF); + lua_setglobal(L, "RELATION_NODE_CHILD_OF"); + lua_pushinteger(L, ATSPI_RELATION_NODE_PARENT_OF); + lua_setglobal(L, "RELATION_NODE_PARENT_OF"); + lua_pushinteger(L, ATSPI_RELATION_EXTENDED); + lua_setglobal(L, "RELATION_EXTENDED"); + lua_pushinteger(L, ATSPI_RELATION_FLOWS_TO); + lua_setglobal(L, "RELATION_FLOWS_TO"); + lua_pushinteger(L, ATSPI_RELATION_FLOWS_FROM); + lua_setglobal(L, "RELATION_FLOWS_FROM"); + lua_pushinteger(L, ATSPI_RELATION_SUBWINDOW_OF); + lua_setglobal(L, "RELATION_SUBWINDOW_OF"); + lua_pushinteger(L, ATSPI_RELATION_EMBEDS); + lua_setglobal(L, "RELATION_EMBEDS"); + lua_pushinteger(L, ATSPI_RELATION_EMBEDDED_BY); + lua_setglobal(L, "RELATION_EMBEDDED_BY"); + lua_pushinteger(L, ATSPI_RELATION_POPUP_FOR); + lua_setglobal(L, "RELATION_POPUP_FOR"); + lua_pushinteger(L, ATSPI_RELATION_PARENT_WINDOW_OF); + lua_setglobal(L, "RELATION_PARENT_WINDOW_OF"); + lua_pushinteger(L, ATSPI_RELATION_DESCRIPTION_FOR); + lua_setglobal(L, "RELATION_DESCRIPTION_FOR"); + lua_pushinteger(L, ATSPI_RELATION_DESCRIBED_BY); + lua_setglobal(L, "RELATION_DESCRIBED_BY"); + lua_pushinteger(L, ATSPI_RELATION_LAST_DEFINED); + lua_setglobal(L, "RELATION_LAST_DEFINED"); + + // state enums + lua_pushinteger(L, ATSPI_STATE_INVALID); + lua_setglobal(L, "INVALID"); + lua_pushinteger(L, ATSPI_STATE_ACTIVE); + lua_setglobal(L, "ACTIVE"); + lua_pushinteger(L, ATSPI_STATE_ARMED); + lua_setglobal(L, "ARMED"); + lua_pushinteger(L, ATSPI_STATE_BUSY); + lua_setglobal(L, "BUSY"); + lua_pushinteger(L, ATSPI_STATE_CHECKED); + lua_setglobal(L, "CHECKED"); + lua_pushinteger(L, ATSPI_STATE_COLLAPSED); + lua_setglobal(L, "COLLAPSED"); + lua_pushinteger(L, ATSPI_STATE_DEFUNCT); + lua_setglobal(L, "DEFUNCT"); + lua_pushinteger(L, ATSPI_STATE_EDITABLE); + lua_setglobal(L, "EDITABLE"); + lua_pushinteger(L, ATSPI_STATE_ENABLED); + lua_setglobal(L, "ENABLED"); + lua_pushinteger(L, ATSPI_STATE_EXPANDABLE); + lua_setglobal(L, "EXPANDABLE"); + lua_pushinteger(L, ATSPI_STATE_EXPANDED); + lua_setglobal(L, "EXPANDED"); + lua_pushinteger(L, ATSPI_STATE_FOCUSABLE); + lua_setglobal(L, "FOCUSABLE"); + lua_pushinteger(L, ATSPI_STATE_FOCUSED); + lua_setglobal(L, "FOCUSED"); + lua_pushinteger(L, ATSPI_STATE_HAS_TOOLTIP); + lua_setglobal(L, "HAS_TOOLTIP"); + lua_pushinteger(L, ATSPI_STATE_HORIZONTAL); + lua_setglobal(L, "HORIZONTAL"); + lua_pushinteger(L, ATSPI_STATE_ICONIFIED); + lua_setglobal(L, "ICONIFIED"); + lua_pushinteger(L, ATSPI_STATE_MODAL); + lua_setglobal(L, "MODAL"); + lua_pushinteger(L, ATSPI_STATE_MULTI_LINE); + lua_setglobal(L, "MULTI_LINE"); + lua_pushinteger(L, ATSPI_STATE_MULTISELECTABLE); + lua_setglobal(L, "MULTISELECTABLE"); + lua_pushinteger(L, ATSPI_STATE_OPAQUE); + lua_setglobal(L, "OPAQUE"); + lua_pushinteger(L, ATSPI_STATE_PRESSED); + lua_setglobal(L, "PRESSED"); + lua_pushinteger(L, ATSPI_STATE_RESIZABLE); + lua_setglobal(L, "RESIZABLE"); + lua_pushinteger(L, ATSPI_STATE_SELECTABLE); + lua_setglobal(L, "SELECTABLE"); + lua_pushinteger(L, ATSPI_STATE_SELECTED); + lua_setglobal(L, "SELECTED"); + lua_pushinteger(L, ATSPI_STATE_SENSITIVE); + lua_setglobal(L, "SENSITIVE"); + lua_pushinteger(L, ATSPI_STATE_SHOWING); + lua_setglobal(L, "SHOWING"); + lua_pushinteger(L, ATSPI_STATE_SINGLE_LINE); + lua_setglobal(L, "SINGLE_LINE"); + lua_pushinteger(L, ATSPI_STATE_STALE); + lua_setglobal(L, "STALE"); + lua_pushinteger(L, ATSPI_STATE_TRANSIENT); + lua_setglobal(L, "TRANSIENT"); + lua_pushinteger(L, ATSPI_STATE_VERTICAL); + lua_setglobal(L, "VERTICAL"); + lua_pushinteger(L, ATSPI_STATE_VISIBLE); + lua_setglobal(L, "VISIBLE"); + lua_pushinteger(L, ATSPI_STATE_MANAGES_DESCENDANTS); + lua_setglobal(L, "MANAGES_DESCENDANTS"); + lua_pushinteger(L, ATSPI_STATE_INDETERMINATE); + lua_setglobal(L, "INDETERMINATE"); + lua_pushinteger(L, ATSPI_STATE_REQUIRED); + lua_setglobal(L, "REQUIRED"); + lua_pushinteger(L, ATSPI_STATE_TRUNCATED); + lua_setglobal(L, "TRUNCATED"); + lua_pushinteger(L, ATSPI_STATE_ANIMATED); + lua_setglobal(L, "ANIMATED"); + lua_pushinteger(L, ATSPI_STATE_INVALID_ENTRY); + lua_setglobal(L, "INVALID_ENTRY"); + lua_pushinteger(L, ATSPI_STATE_SUPPORTS_AUTOCOMPLETION); + lua_setglobal(L, "SUPPORTS_AUTOCOMPLETION"); + lua_pushinteger(L, ATSPI_STATE_SELECTABLE_TEXT); + lua_setglobal(L, "SELECTABLE_TEXT"); + lua_pushinteger(L, ATSPI_STATE_IS_DEFAULT); + lua_setglobal(L, "IS_DEFAULT"); + lua_pushinteger(L, ATSPI_STATE_VISITED); + lua_setglobal(L, "VISITED"); + lua_pushinteger(L, ATSPI_STATE_HIGHLIGHTED); + lua_setglobal(L, "HIGHLIGHTED"); + lua_pushinteger(L, ATSPI_STATE_LAST_DEFINED); + lua_setglobal(L, "LAST_DEFINED"); +} + +static void _register_class(lua_State *L, const char *class_name, const luaL_Reg *funcs) +{ + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, class_name); + int metatable = lua_gettop(L); + + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__index"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + luaI_openlib(L, 0, _meta_methods, 0); + + lua_pop(L, 1); + + luaI_openlib(L, 0, funcs, 0); + lua_pop(L, 1); +} + +static int _extensions_register(lua_State *L) +{ + _register_class(L, ACCESSIBLE_CLASS_NAME, _accessible_methods); + _register_class(L, VALUE_CLASS_NAME, _value_methods); + _register_class(L, SELECTION_CLASS_NAME, _selection_methods); + + _register_role_enums(L); + + lua_register(L, "desktop", l_get_root); + lua_register(L, "T", l_get_translation); + + return 0; +} + +int lua_engine_init(const char *script) +{ + L = luaL_newstate(); + + luaL_openlibs(L); + + DEBUG("Initializing lua engine with script file: %s", script); + + if (_extensions_register(L)) + { + ERROR("Failed to load screen-reader lua extensions"); + lua_close(L); + return -1; + } + if (luaL_loadfile(L, script)) + { + ERROR("Script loading failed: %s\n", lua_tostring(L, -1)); + lua_close(L); + return -1; + } + if (lua_pcall(L, 0, 0, 0)) + { + ERROR("Failed to init lua script: %s", lua_tostring(L, -1)); + lua_close(L); + return -1; + } + DEBUG("Lua engine successfully inited."); + return 0; +} + +void lua_engine_shutdown(void) +{ + lua_close(L); +} + +char *lua_engine_describe_object(AtspiAccessible *obj) +{ + const char *ret = NULL; + + // get 'describeObject' function and push arguments on stack + lua_getglobal(L, "describeObject"); + + _push_class_obj(L, obj, ACCESSIBLE_CLASS_NAME); + + // launch function + if (lua_pcall(L, 1, 1, 0)) + { + ERROR("Failed to run function 'describeObject': %s", lua_tostring(L, -1)); + goto end; + } + // get result from lua stack + if (!lua_isstring(L, -1)) + { + ERROR("Function 'describeObject' do not returned string value."); + goto end; + } + ret = lua_tostring(L, -1); + +end: + // unref all AtspiAccessible references + lua_gc(L, LUA_GCCOLLECT, 1); + lua_pop(L, 1); + return ret ? strdup(ret) : NULL; +} diff --git a/src/navigator.c b/src/navigator.c index 1dcc68a..52d8891 100644 --- a/src/navigator.c +++ b/src/navigator.c @@ -38,6 +38,7 @@ #include "screen_reader_gestures.h" #include "dbus_gesture_adapter.h" #include "elm_access_adapter.h" +#include "lua_engine.h" #define QUICKPANEL_DOWN TRUE #define QUICKPANEL_UP FALSE @@ -88,6 +89,16 @@ static struct { } s_auto_review = { .focused_object = NULL,.auto_review_on = false}; +static bool _widget_has_state(AtspiAccessible * obj, AtspiStateType type) +{ + Eina_Bool ret = EINA_FALSE; + AtspiStateSet *st = atspi_accessible_get_state_set(obj); + if (atspi_state_set_contains(st, type)) + ret = EINA_TRUE; + g_object_unref(st); + return ret; +} + char *state_to_char(AtspiStateType state) { switch (state) { @@ -261,553 +272,9 @@ static void display_info_about_object(AtspiAccessible * obj, bool display_parent g_free(description); } -char *generate_description_for_subtrees(AtspiAccessible * obj) -{ - DEBUG("START"); - - if (!obj) - return strdup(""); - return strdup(""); - /* - AtspiRole role; - int child_count; - int i; - char *name = NULL; - char *below = NULL; - char ret[TTS_MAX_TEXT_SIZE] = "\0"; - AtspiAccessible *child = NULL; - - int child_count = atspi_accessible_get_child_count(obj, NULL); - - role = atspi_accessible_get_role(obj, NULL); - - // Do not generate that for popups - if (role == ATSPI_ROLE_POPUP_MENU || role == ATSPI_ROLE_DIALOG) - return strdup(""); - - child_count = atspi_accessible_get_child_count(obj, NULL); - - DEBUG("There is %d children inside this object", child_count); - if (!child_count) - return strdup(""); - - for (i=0; i < child_count; i++) - { - child = atspi_accessible_get_child_at_index(obj, i, NULL); - name = atspi_accessible_get_name(child, NULL); - DEBUG("%d child name:%s", i, name); - if (name && strncmp(name, "\0", 1)) - { - strncat(ret, name, sizeof(ret) - strlen(ret) - 1); - } - strncat(ret, " ", sizeof(ret) - strlen(ret) - 1); - below = generate_description_for_subtrees(child); - DEBUG("%s from below", below); - if (strncmp(below, "\0", 1)) - { - strncat(ret, below, sizeof(ret) - strlen(ret) - 1); - } - - g_object_unref(child); - free(below); - free(name); - } - return strdup(ret); - */ -} - -static int _check_list_children_count(AtspiAccessible * obj) -{ - int list_count = 0; - int i; - AtspiAccessible *child = NULL; - - if (!obj) - return 0; - - if (atspi_accessible_get_role(obj, NULL) == ATSPI_ROLE_LIST) { - int children_count = atspi_accessible_get_child_count(obj, NULL); - - for (i = 0; i < children_count; i++) { - child = atspi_accessible_get_child_at_index(obj, i, NULL); - if (atspi_accessible_get_role(child, NULL) == ATSPI_ROLE_LIST_ITEM) - list_count++; - g_object_unref(child); - } - } - - return list_count; -} - -static int _find_popup_list_children_count(AtspiAccessible * obj) -{ - int list_items_count = 0; - int children_count = atspi_accessible_get_child_count(obj, NULL); - int i; - AtspiAccessible *child = NULL; - - list_items_count = _check_list_children_count(obj); - if (list_items_count > 0) - return list_items_count; - - for (i = 0; i < children_count; i++) { - child = atspi_accessible_get_child_at_index(obj, i, NULL); - list_items_count = _find_popup_list_children_count(child); - if (list_items_count > 0) - return list_items_count; - g_object_unref(child); - } - - return 0; -} - -static bool _widget_has_state(AtspiAccessible * obj, AtspiStateType type) -{ - Eina_Bool ret = EINA_FALSE; - AtspiStateSet *st = atspi_accessible_get_state_set(obj); - if (atspi_state_set_contains(st, type)) - ret = EINA_TRUE; - g_object_unref(st); - return ret; -} - -int get_accuracy(double val, int max_accuracy) -{ - char val_str[HOVERSEL_TRAIT_SIZE] = ""; - int position; - int accuracy; - - snprintf(val_str, HOVERSEL_TRAIT_SIZE, "%.*f", max_accuracy, val); - accuracy = max_accuracy; - position = strlen(val_str) - 1; - while ( position > 0 && val_str[position] == '0' ) { - --position; - --accuracy; - } - return accuracy; -} - -void add_slider_description(char *dest, uint dest_size, AtspiAccessible *obj) -{ - gchar *role_name; - AtspiValue *value_iface; - double val; - double min_val; - double max_val; - char trait[HOVERSEL_TRAIT_SIZE] = ""; - int accuracy; - - role_name = atspi_accessible_get_localized_role_name(obj, NULL); - if (role_name) { - strncat(dest, role_name, dest_size - strlen(dest) - 1); - g_free(role_name); - } - - value_iface = atspi_accessible_get_value_iface(obj); - if (!value_iface) { - return; - } - - accuracy = get_accuracy( atspi_value_get_minimum_increment(value_iface, NULL), 3 ); - val = atspi_value_get_current_value(value_iface, NULL); - max_val = atspi_value_get_maximum_value(value_iface, NULL); - min_val = atspi_value_get_minimum_value(value_iface, NULL); - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_SLIDER_VALUE"), accuracy, min_val, accuracy, max_val, accuracy, val); - strncat(dest, trait, dest_size - strlen(dest) - 1); - - if (_widget_has_state(obj, ATSPI_STATE_ENABLED)) { - strncat(dest, _("IDS_TRAIT_SLIDER_SWIPE_COMMUNICATE"), dest_size - strlen(dest) - 1); - } - g_object_unref(value_iface); -} - -char *generate_trait(AtspiAccessible * obj) -{ - if (!obj) - return strdup(""); - - AtspiRole role = atspi_accessible_get_role(obj, NULL); - AtspiStateSet *state_set = atspi_accessible_get_state_set(obj); - char ret[TTS_MAX_TEXT_SIZE] = "\0"; - switch (role) { - case ATSPI_ROLE_ENTRY: { - gchar *role_name = atspi_accessible_get_localized_role_name(obj, NULL); - if (role_name) { - strncat(ret, role_name, sizeof(ret) - strlen(ret) - 1); - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - if (atspi_state_set_contains(state_set, ATSPI_STATE_FOCUSED)) - strncat(ret, _("IDS_TRAIT_TEXT_EDIT_FOCUSED"), sizeof(ret) - strlen(ret) - 1); - else - strncat(ret, _("IDS_TRAIT_TEXT_EDIT"), sizeof(ret) - strlen(ret) - 1); - g_free(role_name); - } - break; - } - case ATSPI_ROLE_MENU_ITEM: { - AtspiAccessible *parent = atspi_accessible_get_parent(obj, NULL); - int children_count = atspi_accessible_get_child_count(parent, NULL); - int index = atspi_accessible_get_index_in_parent(obj, NULL); - char tab_index[MENU_ITEM_TAB_INDEX_SIZE]; - snprintf(tab_index, MENU_ITEM_TAB_INDEX_SIZE, _("IDS_TRAIT_MENU_ITEM_TAB_INDEX"), index + 1, children_count); - strncat(ret, tab_index, sizeof(ret) - strlen(ret) - 1); - g_object_unref(parent); - break; - } - case ATSPI_ROLE_POPUP_MENU: { - int children_count = atspi_accessible_get_child_count(obj, NULL); - char trait[HOVERSEL_TRAIT_SIZE]; - - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_CTX_POPUP")); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_SHOWING")); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - strncat(ret, " ", sizeof(ret) - strlen(ret) - 1); - - snprintf(trait, HOVERSEL_TRAIT_SIZE, "%d", children_count); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - strncat(ret, " ", sizeof(ret) - strlen(ret) - 1); - - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_ITEMS")); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_POPUP_CLOSE")); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - break; - } - case ATSPI_ROLE_DIALOG: { - int children_count = _find_popup_list_children_count(obj); - char trait[HOVERSEL_TRAIT_SIZE]; - - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_POPUP")); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - - if (children_count > 0) { - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_SHOWING")); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - strncat(ret, " ", sizeof(ret) - strlen(ret) - 1); - - snprintf(trait, HOVERSEL_TRAIT_SIZE, "%d", children_count); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - strncat(ret, " ", sizeof(ret) - strlen(ret) - 1); - - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_ITEMS")); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - } - - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_POPUP_CLOSE")); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - break; - } - case ATSPI_ROLE_GLASS_PANE: { - AtspiAccessible *parent = atspi_accessible_get_parent(obj, NULL); - int children_count = atspi_accessible_get_child_count(parent, NULL); - char trait[HOVERSEL_TRAIT_SIZE]; - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_PD_HOVERSEL"), children_count); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - g_object_unref(parent); - break; - } - case ATSPI_ROLE_LIST_ITEM: { - AtspiAccessible *parent = atspi_accessible_get_parent(obj, NULL); - AtspiRole parent_role = atspi_accessible_get_role(parent, NULL); - - if(parent_role == ATSPI_ROLE_TREE_TABLE) { - - AtspiStateSet *state_set = atspi_accessible_get_state_set(obj); - gboolean is_selected = atspi_state_set_contains(state_set, ATSPI_STATE_SELECTED); - g_object_unref(state_set); - - if(is_selected) { - strncat(ret, _("IDS_TRAIT_ITEM_SELECTED"), sizeof(ret) - strlen(ret) - 1); - } - - AtspiStateSet *parent_state_set = atspi_accessible_get_state_set(parent); - bool is_parent_multiselectable = atspi_state_set_contains(parent_state_set, ATSPI_STATE_MULTISELECTABLE); - - g_object_unref(parent_state_set); - g_object_unref(parent); - - if(is_parent_multiselectable) { - - char buf[200]; - - AtspiSelection *parent_selection = atspi_accessible_get_selection(parent); - int selected_children_count = atspi_selection_get_n_selected_children(parent_selection, NULL); - - if(is_selected) { - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - } - - snprintf(buf, 200, _("IDS_TRAIT_ITEM_SELECTED_COUNT"), selected_children_count); - strncat(ret, buf, sizeof(ret) - strlen(ret) - 1); - - g_object_unref(parent_selection); - } - - } else if (atspi_state_set_contains(state_set, ATSPI_STATE_EXPANDABLE)) { - if (atspi_state_set_contains(state_set, ATSPI_STATE_EXPANDED)) { - strncat(ret, _("IDS_TRAIT_GROUP_INDEX_EXPANDED"), sizeof(ret) - strlen(ret) - 1); - } else { - strncat(ret, _("IDS_TRAIT_GROUP_INDEX_COLLAPSED"), sizeof(ret) - strlen(ret) - 1); - } - } - g_object_unref(parent); - break; - } - case ATSPI_ROLE_CHECK_BOX: - case ATSPI_ROLE_RADIO_BUTTON: { - if (atspi_state_set_contains(state_set, ATSPI_STATE_CHECKED)) { - strncat(ret, _("IDS_TRAIT_CHECK_BOX_SELECTED"), sizeof(ret) - strlen(ret) - 1); - } else { - strncat(ret, _("IDS_TRAIT_CHECK_BOX_NOT_SELECTED"), sizeof(ret) - strlen(ret) - 1); - } - - if (role == ATSPI_ROLE_RADIO_BUTTON) { - /* Say role name ("radio button"), but only if it's not a color chooser */ - AtspiAccessible *parent; - AtspiRole parent_role; - parent = atspi_accessible_get_parent(obj, NULL); - parent_role = atspi_accessible_get_role(parent, NULL); - if (parent_role != ATSPI_ROLE_COLOR_CHOOSER) { - gchar *role_name; - role_name = atspi_accessible_get_localized_role_name(obj, NULL); - if (role_name) { - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - strncat(ret, role_name, sizeof(ret) - strlen(ret) - 1); - g_free(role_name); - } - } - g_object_unref(parent); - } - break; - } - case ATSPI_ROLE_PUSH_BUTTON: { - strncat(ret, _("IDS_TRAIT_PUSH_BUTTON"), sizeof(ret) - strlen(ret) - 1); - break; - } - case ATSPI_ROLE_PROGRESS_BAR: { - AtspiValue *value = atspi_accessible_get_value_iface(obj); - if (value) { - double val = atspi_value_get_current_value(value, NULL); - char trait[HOVERSEL_TRAIT_SIZE]; - if (val > 0) { - snprintf(trait, HOVERSEL_TRAIT_SIZE, _("IDS_TRAIT_PD_PROGRESSBAR_PERCENT"), val * 100); - strncat(ret, trait, sizeof(ret) - strlen(ret) - 1); - } else { - strncat(ret, _("IDS_TRAIT_PD_PROGRESSBAR"), sizeof(ret) - strlen(ret) - 1); - } - g_object_unref(value); - } - break; - } - case ATSPI_ROLE_TOGGLE_BUTTON: { - strncat(ret, _("IDS_TRAIT_TOGGLE_BUTTON"), sizeof(ret) - strlen(ret) - 1); - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - if (atspi_state_set_contains(state_set, ATSPI_STATE_CHECKED)) { - strncat(ret, _("IDS_TRAIT_TOGGLE_BUTTON_ON"), sizeof(ret) - strlen(ret) - 1); - } else { - strncat(ret, _("IDS_TRAIT_TOGGLE_BUTTON_OFF"), sizeof(ret) - strlen(ret) - 1); - } - break; - } - case ATSPI_ROLE_SLIDER: { - add_slider_description(ret, sizeof(ret), obj); - break; - } - case ATSPI_ROLE_HEADING: - case ATSPI_ROLE_GROUPING: { - break; - } - default: { - gchar *role_name = atspi_accessible_get_localized_role_name(obj, NULL); - if (role_name) { - strncat(ret, role_name, sizeof(ret) - strlen(ret) - 1); - g_free(role_name); - } - } - } - - if (state_set) - g_object_unref(state_set); - - return strdup(ret); -} - -char *generate_text_for_relation_objects(AtspiAccessible * obj, AtspiRelationType search, char *(*text_generate_cb)(AtspiAccessible *obj)) -{ - GError *err = NULL; - GArray *relations; - AtspiRelation *relation; - AtspiRelationType type; - Eina_Strbuf *buf; - int i, j; - char *ret = NULL; - - if (!obj || !text_generate_cb) return NULL; - - relations = atspi_accessible_get_relation_set(obj, &err); - if (err || !relations) - { - if (err) g_error_free(err); - return NULL; - } - - buf = eina_strbuf_new(); - - for (i = 0; i < relations->len; i++) - { - relation = g_array_index(relations, AtspiRelation *, i); - type = atspi_relation_get_relation_type(relation); - if (type == search) - { - for (j = 0; j < atspi_relation_get_n_targets(relation); j++) - { - AtspiAccessible *target = atspi_relation_get_target(relation, j); - char *text = text_generate_cb(target); - if (j == 0) - eina_strbuf_append_printf(buf, "%s", text); - else - eina_strbuf_append_printf(buf, ", %s", text); - g_object_unref(target); - free(text); - } - } - g_object_unref(relation); - } - g_array_free(relations, TRUE); - ret = eina_strbuf_string_steal(buf); - eina_strbuf_free(buf); - - return ret; -} - -static char *generate_description_from_relation_object(AtspiAccessible *obj) -{ - GError *err = NULL; - char *ret = generate_trait(obj); - char *desc = atspi_accessible_get_description(obj, &err); - - if (err) - { - g_error_free(err); - g_free(desc); - return ret; - } - - if (desc) { - if (desc[0] != '\0') { - char *tmp = ret; - if (asprintf(&ret, "%s, %s", desc, ret) < 0) - ERROR("asprintf failed."); - free(tmp); - } - g_free(desc); - } - - - return ret; -} - -static char *generate_name_from_relation_object(AtspiAccessible *obj) -{ - GError *err = NULL; - char *name = atspi_accessible_get_name(obj, &err); - - if(err) - { - g_error_free(err); - g_free(name); - return NULL; - } - - return name; -} - static char *generate_what_to_read(AtspiAccessible * obj) { - char *name; - char *names = NULL; - char *description; - char *role_name; - char *other; - char *text = NULL; - char ret[TTS_MAX_TEXT_SIZE] = "\0"; - char *description_from_relation; - char *name_from_relation; - - description = atspi_accessible_get_description(obj, NULL); - name = atspi_accessible_get_name(obj, NULL); - role_name = generate_trait(obj); - other = generate_description_for_subtrees(obj); - description_from_relation = generate_text_for_relation_objects(obj, ATSPI_RELATION_DESCRIBED_BY, generate_description_from_relation_object); - name_from_relation = generate_text_for_relation_objects(obj, ATSPI_RELATION_LABELLED_BY, generate_name_from_relation_object); - AtspiText *iface_text = atspi_accessible_get_text_iface(obj); - if (iface_text) { - text = atspi_text_get_text(iface_text, 0, atspi_text_get_character_count(iface_text, NULL), NULL); - g_object_unref(iface_text); - } - - DEBUG("->->->->->-> WIDGET GAINED HIGHLIGHT: %s <-<-<-<-<-<-<-", name); - DEBUG("->->->->->-> FROM SUBTREE HAS NAME: %s <-<-<-<-<-<-<-", other); - - display_info_about_object(obj, false); - - if (name && strncmp(name, "\0", 1)) - names = strdup(name); - else if (other && strncmp(other, "\0", 1)) - names = strdup(other); - - if (text) { - strncat(ret, text, sizeof(ret) - strlen(ret) - 1); - } - - DEBUG("Text:%s", text); - - if (names && strlen(names) > 0) { - if (strlen(ret) > 0) - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - strncat(ret, names, sizeof(ret) - strlen(ret) - 1); - } - - if (name_from_relation && strlen(name_from_relation) > 0) { - if(strlen(ret) > 0) - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - strncat(ret, name_from_relation, sizeof(ret) - strlen(ret) - 1); - } - - if (role_name && strlen(role_name) > 0) { - if (strlen(ret) > 0) - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - strncat(ret, role_name, sizeof(ret) - strlen(ret) - 1); - } - - if (description && strlen(description) > 0) { - if (strlen(ret) > 0) - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - strncat(ret, description, sizeof(ret) - strlen(ret) - 1); - } - - if (description_from_relation && (description_from_relation[0] != '\n')) { - if (strlen(ret) > 0) - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - strncat(ret, description_from_relation, sizeof(ret) - strlen(ret) - 1); - } - - free(text); - free(name); - free(names); - free(name_from_relation); - free(description); - free(role_name); - free(other); - free(description_from_relation); - - return strdup(ret); + return lua_engine_describe_object(obj); } static void _current_highlight_object_set(AtspiAccessible * obj) @@ -2260,7 +1727,9 @@ void navigator_init(void) set_utterance_cb(_on_utterance); screen_reader_gestures_tracker_register(on_gesture_detected, NULL); - // register on active_window + //FIXME add some config to get script path + if (lua_engine_init(SCRIPTDIR "/mobile.lua")) + ERROR("Failed to init lua engine."); dbus_gesture_adapter_init(); app_tracker_init(); app_tracker_new_obj_highlighted_callback_register(_new_highlighted_obj_changed); @@ -2289,6 +1758,7 @@ void navigator_shutdown(void) flat_navi_context_free(context); context = NULL; } + lua_engine_shutdown(); dbus_gesture_adapter_shutdown(); app_tracker_shutdown(); window_tracker_shutdown(); diff --git a/src/screen_reader.c b/src/screen_reader.c index e465e1b..e6a6ff0 100644 --- a/src/screen_reader.c +++ b/src/screen_reader.c @@ -42,6 +42,7 @@ Service_Data service_data = { //Actions to do when tts state is 'ready' .update_language_list = false, + .lua_script_path = SCRIPTDIR "/mobile.lua", .text_to_say_info = NULL }; @@ -77,6 +78,10 @@ int screen_reader_terminate_service(void *data) Service_Data *service_data = data; +#ifdef SCREEN_READER_TV + spi_shutdown(service_data); +#endif + tts_stop(service_data->tts); tts_unprepare(service_data->tts); tts_destroy(service_data->tts); diff --git a/src/screen_reader_spi.c b/src/screen_reader_spi.c index 10645de..197e27e 100644 --- a/src/screen_reader_spi.c +++ b/src/screen_reader_spi.c @@ -20,6 +20,7 @@ #include "screen_reader_spi.h" #include "screen_reader_tts.h" #include "logger.h" +#include "lua_engine.h" #ifdef RUN_IPC_TEST_SUIT #include "test_suite/test_suite.h" #endif @@ -29,11 +30,6 @@ /** @brief Service_Data used as screen reader internal data struct*/ static Service_Data *service_data; -typedef struct { - char *key; - char *val; -} Attr; - /** * @brief Debug function. Print current toolkit version/event * type/event source/event detail1/event detail2 @@ -54,105 +50,12 @@ static void display_info(const AtspiEvent * event) DEBUG("--------------------------------------------------------"); } -Eina_Bool double_click_timer_cb(void *data) -{ - Service_Data *sd = data; - sd->clicked_widget = NULL; - - return EINA_FALSE; -} - -bool allow_recursive_name(AtspiAccessible * obj) -{ - AtspiRole r = atspi_accessible_get_role(obj, NULL); - if (r == ATSPI_ROLE_FILLER) - return true; - return false; -} - -char *generate_description_for_subtree(AtspiAccessible * obj) -{ - DEBUG("START"); - if (!allow_recursive_name(obj)) - return strdup(""); - - if (!obj) - return strdup(""); - int child_count = atspi_accessible_get_child_count(obj, NULL); - - DEBUG("There is %d children inside this filler", child_count); - if (!child_count) - return strdup(""); - - int i; - char *name = NULL; - char *below = NULL; - char ret[256] = "\0"; - AtspiAccessible *child = NULL; - for (i = 0; i < child_count; i++) { - child = atspi_accessible_get_child_at_index(obj, i, NULL); - name = atspi_accessible_get_name(child, NULL); - DEBUG("%d child name:%s", i, name); - if (name && strncmp(name, "\0", 1)) { - strncat(ret, name, sizeof(ret) - strlen(ret) - 1); - } - strncat(ret, " ", sizeof(ret) - strlen(ret) - 1); - below = generate_description_for_subtree(child); - if (strncmp(below, "\0", 1)) { - strncat(ret, below, sizeof(ret) - strlen(ret) - 1); - } - g_object_unref(child); - free(below); - free(name); - } - return strdup(ret); -} - static char *spi_on_state_changed_get_text(AtspiEvent * event, void *user_data) { Service_Data *sd = (Service_Data *) user_data; - char *name; - char *names = NULL; - char *description; - char *role_name; - char *other; - char ret[256] = "\0"; sd->currently_focused = event->source; - description = atspi_accessible_get_description(sd->currently_focused, NULL); - name = atspi_accessible_get_name(sd->currently_focused, NULL); - role_name = atspi_accessible_get_localized_role_name(sd->currently_focused, NULL); - other = generate_description_for_subtree(sd->currently_focused); - - DEBUG("->->->->->-> WIDGET GAINED HIGHLIGHT: %s <-<-<-<-<-<-<-", name); - DEBUG("->->->->->-> FROM SUBTREE HAS NAME: %s <-<-<-<-<-<-<-", other); - - if (name && strncmp(name, "\0", 1)) - names = strdup(name); - else if (other && strncmp(other, "\0", 1)) - names = strdup(other); - - if (names) { - strncat(ret, names, sizeof(ret) - strlen(ret) - 1); - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - } - - if (role_name) - strncat(ret, role_name, sizeof(ret) - strlen(ret) - 1); - - if (description) { - if (strncmp(description, "\0", 1)) - strncat(ret, ", ", sizeof(ret) - strlen(ret) - 1); - strncat(ret, description, sizeof(ret) - strlen(ret) - 1); - } - - free(name); - free(names); - free(description); - free(role_name); - free(other); - - return strdup(ret); + return lua_engine_describe_object(sd->currently_focused); } static char *spi_on_caret_move_get_text(AtspiEvent * event, void *user_data) @@ -292,6 +195,10 @@ void spi_init(Service_Data * sd) DEBUG("--------------------- SPI_init START ---------------------"); service_data = sd; + DEBUG(">>> Init lua engine<<<"); + if (lua_engine_init(sd->lua_script_path)) + ERROR("Failed to init lua engine."); + DEBUG(">>> Creating listeners <<<"); sd->spi_listener = atspi_event_listener_new(spi_event_listener_cb, service_data, NULL); @@ -327,3 +234,8 @@ void spi_init(Service_Data * sd) DEBUG("---------------------- SPI_init END ----------------------\n\n"); } + +void spi_shutdown(Service_Data * sd) +{ + lua_engine_shutdown(); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 75034d8..dc59d11 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,6 +21,7 @@ pkg_check_modules(tests REQUIRED check vconf elementary + lua ) FOREACH(flag ${tests_CFLAGS}) @@ -35,6 +36,7 @@ SET(TESTED_SRCS ${CMAKE_SOURCE_DIR}/src/screen_reader.c ${CMAKE_SOURCE_DIR}/src/screen_reader_vconf.c ${CMAKE_SOURCE_DIR}/src/screen_reader_spi.c ${CMAKE_SOURCE_DIR}/src/screen_reader_tts.c + ${CMAKE_SOURCE_DIR}/src/lua_engine.c ${CMAKE_SOURCE_DIR}/src/flat_navi.c) ADD_DEFINITIONS(-DSCREEN_READER_FLAT_NAVI_TEST_DUMMY_IMPLEMENTATION) diff --git a/tests/atspi/atspi.c b/tests/atspi/atspi.c index 096a51f..2623840 100644 --- a/tests/atspi/atspi.c +++ b/tests/atspi/atspi.c @@ -517,3 +517,29 @@ int atspi_exit(void) { return 1; } + +AtspiAccessible* atspi_get_desktop (gint i) +{ + return NULL; +} + +gdouble atspi_value_get_minimum_increment (AtspiValue *obj, GError **error) +{ + return 0.0; +} + +gint +atspi_selection_get_n_selected_children (AtspiSelection *obj, GError **error) +{ + return 0; +} + +gboolean atspi_selection_is_child_selected (AtspiSelection *obj, gint child_index, GError **error) +{ + return FALSE; +} + +AtspiSelection * atspi_accessible_get_selection_iface (AtspiAccessible *obj) +{ + return NULL; +} diff --git a/tests/atspi/atspi.h b/tests/atspi/atspi.h index e03f548..bfe1f62 100644 --- a/tests/atspi/atspi.h +++ b/tests/atspi/atspi.h @@ -51,6 +51,7 @@ typedef struct _AtspiRect AtspiRect; typedef struct _AtspiEditableText AtspiEditableText; typedef struct _AtspiRelation AtspiRelation; typedef struct _AtspiAction AtspiAction; +typedef struct _AtspiSelection AtspiSelection; typedef struct _AtspiAccessibleClass AtspiAccessibleClass; typedef struct _AtspiActionClass AtspiActionClass; @@ -80,111 +81,128 @@ typedef enum typedef enum { - ATSPI_ROLE_INVALID, - ATSPI_ROLE_ACCELERATOR_LABEL, - ATSPI_ROLE_ALERT, - ATSPI_ROLE_ANIMATION, - ATSPI_ROLE_ARROW, - ATSPI_ROLE_CALENDAR, - ATSPI_ROLE_CANVAS, - ATSPI_ROLE_CHECK_BOX, - ATSPI_ROLE_CHECK_MENU_ITEM, - ATSPI_ROLE_COLOR_CHOOSER, - ATSPI_ROLE_COLUMN_HEADER, - ATSPI_ROLE_COMBO_BOX, - ATSPI_ROLE_DATE_EDITOR, - ATSPI_ROLE_DESKTOP_ICON, - ATSPI_ROLE_DESKTOP_FRAME, - ATSPI_ROLE_DIAL, - ATSPI_ROLE_DIALOG, - ATSPI_ROLE_DIRECTORY_PANE, - ATSPI_ROLE_DRAWING_AREA, - ATSPI_ROLE_FILE_CHOOSER, - ATSPI_ROLE_FILLER, - ATSPI_ROLE_FOCUS_TRAVERSABLE, - ATSPI_ROLE_FONT_CHOOSER, - ATSPI_ROLE_FRAME, - ATSPI_ROLE_GLASS_PANE, - ATSPI_ROLE_HTML_CONTAINER, - ATSPI_ROLE_ICON, - ATSPI_ROLE_IMAGE, - ATSPI_ROLE_INTERNAL_FRAME, - ATSPI_ROLE_LABEL, - ATSPI_ROLE_LAYERED_PANE, - ATSPI_ROLE_LIST, - ATSPI_ROLE_LIST_ITEM, - ATSPI_ROLE_MENU, - ATSPI_ROLE_MENU_BAR, - ATSPI_ROLE_MENU_ITEM, - ATSPI_ROLE_OPTION_PANE, - ATSPI_ROLE_PAGE_TAB, - ATSPI_ROLE_PAGE_TAB_LIST, - ATSPI_ROLE_PANEL, - ATSPI_ROLE_PASSWORD_TEXT, - ATSPI_ROLE_POPUP_MENU, - ATSPI_ROLE_PROGRESS_BAR, - ATSPI_ROLE_PUSH_BUTTON, - ATSPI_ROLE_RADIO_BUTTON, - ATSPI_ROLE_RADIO_MENU_ITEM, - ATSPI_ROLE_ROOT_PANE, - ATSPI_ROLE_ROW_HEADER, - ATSPI_ROLE_SCROLL_BAR, - ATSPI_ROLE_SCROLL_PANE, - ATSPI_ROLE_SEPARATOR, - ATSPI_ROLE_SLIDER, - ATSPI_ROLE_SPIN_BUTTON, - ATSPI_ROLE_SPLIT_PANE, - ATSPI_ROLE_STATUS_BAR, - ATSPI_ROLE_TABLE, - ATSPI_ROLE_TABLE_CELL, - ATSPI_ROLE_TABLE_COLUMN_HEADER, - ATSPI_ROLE_TABLE_ROW_HEADER, - ATSPI_ROLE_TEAROFF_MENU_ITEM, - ATSPI_ROLE_TERMINAL, - ATSPI_ROLE_TEXT, - ATSPI_ROLE_TOGGLE_BUTTON, - ATSPI_ROLE_TOOL_BAR, - ATSPI_ROLE_TOOL_TIP, - ATSPI_ROLE_TREE, - ATSPI_ROLE_TREE_TABLE, - ATSPI_ROLE_UNKNOWN, - ATSPI_ROLE_VIEWPORT, - ATSPI_ROLE_WINDOW, - ATSPI_ROLE_EXTENDED, - ATSPI_ROLE_HEADER, - ATSPI_ROLE_FOOTER, - ATSPI_ROLE_PARAGRAPH, - ATSPI_ROLE_RULER, - ATSPI_ROLE_APPLICATION, - ATSPI_ROLE_AUTOCOMPLETE, - ATSPI_ROLE_EDITBAR, - ATSPI_ROLE_EMBEDDED, - ATSPI_ROLE_ENTRY, - ATSPI_ROLE_CHART, - ATSPI_ROLE_CAPTION, - ATSPI_ROLE_DOCUMENT_FRAME, - ATSPI_ROLE_HEADING, - ATSPI_ROLE_PAGE, - ATSPI_ROLE_SECTION, - ATSPI_ROLE_REDUNDANT_OBJECT, - ATSPI_ROLE_FORM, - ATSPI_ROLE_LINK, - ATSPI_ROLE_INPUT_METHOD_WINDOW, - ATSPI_ROLE_TABLE_ROW, - ATSPI_ROLE_TREE_ITEM, - ATSPI_ROLE_DOCUMENT_SPREADSHEET, - ATSPI_ROLE_DOCUMENT_PRESENTATION, - ATSPI_ROLE_DOCUMENT_TEXT, - ATSPI_ROLE_DOCUMENT_WEB, - ATSPI_ROLE_DOCUMENT_EMAIL, - ATSPI_ROLE_COMMENT, - ATSPI_ROLE_LIST_BOX, - ATSPI_ROLE_GROUPING, - ATSPI_ROLE_IMAGE_MAP, - ATSPI_ROLE_NOTIFICATION, - ATSPI_ROLE_INFO_BAR, - ATSPI_ROLE_LEVEL_BAR, - ATSPI_ROLE_LAST_DEFINED, + ATSPI_ROLE_INVALID, + ATSPI_ROLE_ACCELERATOR_LABEL, + ATSPI_ROLE_ALERT, + ATSPI_ROLE_ANIMATION, + ATSPI_ROLE_ARROW, + ATSPI_ROLE_CALENDAR, + ATSPI_ROLE_CANVAS, + ATSPI_ROLE_CHECK_BOX, + ATSPI_ROLE_CHECK_MENU_ITEM, + ATSPI_ROLE_COLOR_CHOOSER, + ATSPI_ROLE_COLUMN_HEADER, + ATSPI_ROLE_COMBO_BOX, + ATSPI_ROLE_DATE_EDITOR, + ATSPI_ROLE_DESKTOP_ICON, + ATSPI_ROLE_DESKTOP_FRAME, + ATSPI_ROLE_DIAL, + ATSPI_ROLE_DIALOG, + ATSPI_ROLE_DIRECTORY_PANE, + ATSPI_ROLE_DRAWING_AREA, + ATSPI_ROLE_FILE_CHOOSER, + ATSPI_ROLE_FILLER, + ATSPI_ROLE_FOCUS_TRAVERSABLE, + ATSPI_ROLE_FONT_CHOOSER, + ATSPI_ROLE_FRAME, + ATSPI_ROLE_GLASS_PANE, + ATSPI_ROLE_HTML_CONTAINER, + ATSPI_ROLE_ICON, + ATSPI_ROLE_IMAGE, + ATSPI_ROLE_INTERNAL_FRAME, + ATSPI_ROLE_LABEL, + ATSPI_ROLE_LAYERED_PANE, + ATSPI_ROLE_LIST, + ATSPI_ROLE_LIST_ITEM, + ATSPI_ROLE_MENU, + ATSPI_ROLE_MENU_BAR, + ATSPI_ROLE_MENU_ITEM, + ATSPI_ROLE_OPTION_PANE, + ATSPI_ROLE_PAGE_TAB, + ATSPI_ROLE_PAGE_TAB_LIST, + ATSPI_ROLE_PANEL, + ATSPI_ROLE_PASSWORD_TEXT, + ATSPI_ROLE_POPUP_MENU, + ATSPI_ROLE_PROGRESS_BAR, + ATSPI_ROLE_PUSH_BUTTON, + ATSPI_ROLE_RADIO_BUTTON, + ATSPI_ROLE_RADIO_MENU_ITEM, + ATSPI_ROLE_ROOT_PANE, + ATSPI_ROLE_ROW_HEADER, + ATSPI_ROLE_SCROLL_BAR, + ATSPI_ROLE_SCROLL_PANE, + ATSPI_ROLE_SEPARATOR, + ATSPI_ROLE_SLIDER, + ATSPI_ROLE_SPIN_BUTTON, + ATSPI_ROLE_SPLIT_PANE, + ATSPI_ROLE_STATUS_BAR, + ATSPI_ROLE_TABLE, + ATSPI_ROLE_TABLE_CELL, + ATSPI_ROLE_TABLE_COLUMN_HEADER, + ATSPI_ROLE_TABLE_ROW_HEADER, + ATSPI_ROLE_TEAROFF_MENU_ITEM, + ATSPI_ROLE_TERMINAL, + ATSPI_ROLE_TEXT, + ATSPI_ROLE_TOGGLE_BUTTON, + ATSPI_ROLE_TOOL_BAR, + ATSPI_ROLE_TOOL_TIP, + ATSPI_ROLE_TREE, + ATSPI_ROLE_TREE_TABLE, + ATSPI_ROLE_UNKNOWN, + ATSPI_ROLE_VIEWPORT, + ATSPI_ROLE_WINDOW, + ATSPI_ROLE_EXTENDED, + ATSPI_ROLE_HEADER, + ATSPI_ROLE_FOOTER, + ATSPI_ROLE_PARAGRAPH, + ATSPI_ROLE_RULER, + ATSPI_ROLE_APPLICATION, + ATSPI_ROLE_AUTOCOMPLETE, + ATSPI_ROLE_EDITBAR, + ATSPI_ROLE_EMBEDDED, + ATSPI_ROLE_ENTRY, + ATSPI_ROLE_CHART, + ATSPI_ROLE_CAPTION, + ATSPI_ROLE_DOCUMENT_FRAME, + ATSPI_ROLE_HEADING, + ATSPI_ROLE_PAGE, + ATSPI_ROLE_SECTION, + ATSPI_ROLE_REDUNDANT_OBJECT, + ATSPI_ROLE_FORM, + ATSPI_ROLE_LINK, + ATSPI_ROLE_INPUT_METHOD_WINDOW, + ATSPI_ROLE_TABLE_ROW, + ATSPI_ROLE_TREE_ITEM, + ATSPI_ROLE_DOCUMENT_SPREADSHEET, + ATSPI_ROLE_DOCUMENT_PRESENTATION, + ATSPI_ROLE_DOCUMENT_TEXT, + ATSPI_ROLE_DOCUMENT_WEB, + ATSPI_ROLE_DOCUMENT_EMAIL, + ATSPI_ROLE_COMMENT, + ATSPI_ROLE_LIST_BOX, + ATSPI_ROLE_GROUPING, + ATSPI_ROLE_IMAGE_MAP, + ATSPI_ROLE_NOTIFICATION, + ATSPI_ROLE_INFO_BAR, + ATSPI_ROLE_LEVEL_BAR, + ATSPI_ROLE_TITLE_BAR, + ATSPI_ROLE_BLOCK_QUOTE, + ATSPI_ROLE_AUDIO, + ATSPI_ROLE_VIDEO, + ATSPI_ROLE_DEFINITION, + ATSPI_ROLE_ARTICLE, + ATSPI_ROLE_LANDMARK, + ATSPI_ROLE_LOG, + ATSPI_ROLE_MARQUEE, + ATSPI_ROLE_MATH, + ATSPI_ROLE_RATING, + ATSPI_ROLE_TIMER, + ATSPI_ROLE_STATIC, + ATSPI_ROLE_MATH_FRACTION, + ATSPI_ROLE_MATH_ROOT, + ATSPI_ROLE_SUBSCRIPT, + ATSPI_ROLE_SUPERSCRIPT, + ATSPI_ROLE_LAST_DEFINED, } AtspiRole; typedef enum @@ -375,6 +393,11 @@ struct _AtspiRelation GTypeInterface parent; }; +struct _AtspiSelection +{ + GTypeInterface parent; +}; + struct _AtspiRect { gint x; @@ -396,6 +419,7 @@ gchar * atspi_accessible_get_toolkit_name (AtspiAccessible *obj, GError **error) gchar * atspi_accessible_get_description (AtspiAccessible *obj, GError **error); AtspiText * atspi_accessible_get_text_iface (AtspiAccessible *obj); AtspiAction * atspi_accessible_get_action_iface (AtspiAccessible *obj); +AtspiSelection * atspi_accessible_get_selection_iface (AtspiAccessible *obj); gint atspi_text_get_character_count (AtspiText *obj, GError **error); gint atspi_text_get_caret_offset (AtspiText *obj, GError **error); gchar * atspi_text_get_text (AtspiText *obj, gint start_offset, gint end_offset, GError **error); @@ -447,5 +471,9 @@ gint atspi_action_get_n_actions (AtspiAction *obj, GError **error); gchar * atspi_action_get_action_name (AtspiAction *obj, gint i, GError **error); int atspi_exit(void); +AtspiAccessible* atspi_get_desktop (gint i); +gdouble atspi_value_get_minimum_increment (AtspiValue *obj, GError **error); +gint atspi_selection_get_n_selected_children (AtspiSelection *obj, GError **error); +gboolean atspi_selection_is_child_selected (AtspiSelection *obj, gint child_index, GError **error); #endif /*__ATSPI_H__*/ diff --git a/tests/smart_navi_suite.c b/tests/smart_navi_suite.c index b7b637a..98f362e 100644 --- a/tests/smart_navi_suite.c +++ b/tests/smart_navi_suite.c @@ -16,6 +16,7 @@ #include "screen_reader_spi.h" #include "flat_navi.h" +#include "lua_engine.h" #include #include #include @@ -65,14 +66,17 @@ void setup(void) data->update_language_list = false; data->text_to_say_info = NULL; + data->lua_script_path = "./res/scripts/mobile.lua"; + spi_init(data); } void teardown(void) { + Service_Data *data = get_pointer_to_service_data_struct(); + spi_shutdown(data); } -void setup_flat_navi() -{ +void setup_flat_navi() { setup(); root = atspi_create_accessible(); root->role = ATSPI_ROLE_APPLICATION; @@ -259,18 +263,7 @@ void teardown_flat_navi() teardown(); } -START_TEST(spi_init_null_parameter) -{ - spi_init(NULL); -} - -END_TEST START_TEST(spi_init_service_data_parameter) -{ - Service_Data *data = get_pointer_to_service_data_struct(); - spi_init(data); -} - -END_TEST START_TEST(spi_on_state_change_name) +START_TEST(spi_on_state_change_name) { Service_Data *sd = get_pointer_to_service_data_struct(); AtspiEvent event; @@ -514,7 +507,6 @@ END_TEST Suite * screen_reader_suite(void) { Suite *s; - TCase *tc_spi_screen_reader_init; TCase *tc_spi_screen_reader_on_state_changed; TCase *tc_spi_screen_reader_on_caret_move; TCase *tc_spi_screen_reader_on_access_value; @@ -522,25 +514,23 @@ Suite * screen_reader_suite(void) TCase *tc_spi_screen_reader_flat_navi2; s = suite_create("Screen reader"); - tc_spi_screen_reader_init = tcase_create("tc_spi_screen_reader_init"); tc_spi_screen_reader_on_state_changed = tcase_create("tc_spi_screen_reader_on_state_changed"); tc_spi_screen_reader_on_caret_move = tcase_create("tc_spi_screen_reader_on_caret_move"); tc_spi_screen_reader_on_access_value = tcase_create("tc_spi_screen_reader_on_access_value"); tc_spi_screen_reader_flat_navi = tcase_create("tc_scpi_screen_reader_flat_navi"); tc_spi_screen_reader_flat_navi2 = tcase_create("tc_scpi_screen_reader_flat_navi2"); - tcase_add_checked_fixture(tc_spi_screen_reader_init, setup, teardown); tcase_add_checked_fixture(tc_spi_screen_reader_on_state_changed, setup, teardown); tcase_add_checked_fixture(tc_spi_screen_reader_on_caret_move, setup, teardown); tcase_add_checked_fixture(tc_spi_screen_reader_on_access_value, setup, teardown); tcase_add_checked_fixture(tc_spi_screen_reader_flat_navi, setup_flat_navi2, teardown_flat_navi); tcase_add_checked_fixture(tc_spi_screen_reader_flat_navi2, setup_flat_navi3, teardown_flat_navi); - tcase_add_test(tc_spi_screen_reader_init, spi_init_null_parameter); - tcase_add_test(tc_spi_screen_reader_init, spi_init_service_data_parameter); +#if 1 tcase_add_test(tc_spi_screen_reader_on_state_changed, spi_on_state_change_name); tcase_add_test(tc_spi_screen_reader_on_state_changed, spi_on_state_change_description); tcase_add_test(tc_spi_screen_reader_on_state_changed, spi_on_state_change_role); +#endif tcase_add_test(tc_spi_screen_reader_on_caret_move, spi_on_caret_move); tcase_add_test(tc_spi_screen_reader_on_access_value, spi_on_value_changed); @@ -570,7 +560,6 @@ Suite * screen_reader_suite(void) tcase_add_test(tc_spi_screen_reader_flat_navi, spi_flat_navi_context_current_set_null_parameters); tcase_add_test(tc_spi_screen_reader_flat_navi, spi_flat_navi_context_current_set_valid_parameters); - suite_add_tcase(s, tc_spi_screen_reader_init); suite_add_tcase(s, tc_spi_screen_reader_on_state_changed); suite_add_tcase(s, tc_spi_screen_reader_on_caret_move); suite_add_tcase(s, tc_spi_screen_reader_on_access_value); -- 2.7.4 From 123508b3aaf8258ee24c05de4ef9b257d28c9f11 Mon Sep 17 00:00:00 2001 From: Lukasz Stanislawski Date: Tue, 3 Nov 2015 09:00:09 +0100 Subject: [PATCH 09/16] remove dead code Change-Id: If1f605f029963810ada89a4e90e526833bba0a42 --- CMakeLists.txt | 1 - include/pivot_chooser.h | 15 ----- src/pivot_chooser.c | 142 ------------------------------------------------ 3 files changed, 158 deletions(-) delete mode 100644 include/pivot_chooser.h delete mode 100644 src/pivot_chooser.c diff --git a/CMakeLists.txt b/CMakeLists.txt index da4d5df..95718a7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,6 @@ ENABLE_TESTING() SET(SRCS ${CMAKE_SOURCE_DIR}/src/app_tracker.c ${CMAKE_SOURCE_DIR}/src/flat_navi.c ${CMAKE_SOURCE_DIR}/src/main.c - ${CMAKE_SOURCE_DIR}/src/pivot_chooser.c ${CMAKE_SOURCE_DIR}/src/screen_reader.c ${CMAKE_SOURCE_DIR}/src/screen_reader_haptic.c ${CMAKE_SOURCE_DIR}/src/screen_reader_spi.c diff --git a/include/pivot_chooser.h b/include/pivot_chooser.h deleted file mode 100644 index 164e84c..0000000 --- a/include/pivot_chooser.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef SMART_NAVI_PIVOT_CHOOSER_H_ -#define SMART_NAVI_PIVOT_CHOOSER_H_ - -#include - -/** - * @brief Some heuristic choosing candidate to reacieve highlight. - * - * @param win Accessibility search tree object root. - * - * @return Highlight candidate - */ -AtspiAccessible *pivot_chooser_pivot_get(AtspiAccessible *win); - -#endif /* end of include guard: PIVOT_CHOOSER_H_ */ diff --git a/src/pivot_chooser.c b/src/pivot_chooser.c deleted file mode 100644 index 481663b..0000000 --- a/src/pivot_chooser.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. - * - * Licensed under the Flora License, Version 1.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://floralicense.org/license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "logger.h" -#include - -/** - * @brief Finds first leaf in object hierarchy with given states, - * starting from object given as parent. - * - * This heuristic assumes that focused element have focused - * parent widgets. - */ -static AtspiAccessible *_pivot_with_state_top_down_find(AtspiAccessible * parent, AtspiStateType type) -{ - AtspiAccessible *ret = NULL; - AtspiStateSet *states; - int i; - - states = atspi_accessible_get_state_set(parent); - if (!states || atspi_state_set_contains(states, type)) { - int n = atspi_accessible_get_child_count(parent, NULL); - if (n == 0) - ret = parent; - for (i = 0; i < n; i++) { - AtspiAccessible *child = atspi_accessible_get_child_at_index(parent, i, NULL); - if (!child) - continue; - - ret = _pivot_with_state_top_down_find(child, type); - - g_object_unref(child); - - if (ret) - break; - } - } - - g_object_unref(states); - - return ret; -} - -/** - * @brief Finds first leaf descendant of given object with state @p type - */ -static AtspiAccessible *_pivot_with_state_flat_find(AtspiAccessible * parent, AtspiStateType type) -{ - Eina_List *candidates = NULL, *queue = NULL; - - // ref object to keep same ref count - g_object_ref(parent); - queue = eina_list_append(queue, parent); - - while (queue) { - AtspiAccessible *obj = eina_list_data_get(queue); - queue = eina_list_remove_list(queue, queue); - - int n = atspi_accessible_get_child_count(obj, NULL); - if (n == 0) - candidates = eina_list_append(candidates, obj); - else { - int i; - for (i = 0; i < n; i++) { - AtspiAccessible *child = atspi_accessible_get_child_at_index(obj, i, NULL); - if (child) - queue = eina_list_append(queue, child); - } - g_object_unref(obj); - } - } - - // FIXME sort by (x,y) first ?? - while (candidates) { - AtspiAccessible *obj = eina_list_data_get(candidates); - candidates = eina_list_remove_list(candidates, candidates); - - AtspiStateSet *states = atspi_accessible_get_state_set(obj); - if (states && atspi_state_set_contains(states, type)) { - g_object_unref(states); - g_object_unref(obj); - eina_list_free(candidates); - - return obj; - } - - g_object_unref(states); - g_object_unref(obj); - } - - return NULL; -} - -/** - * @brief Purpose of this methods is to find first visible object in - * hierarchy - */ -AtspiAccessible *pivot_chooser_pivot_get(AtspiAccessible * win) -{ - AtspiAccessible *ret; - - if (atspi_accessible_get_role(win, NULL) != ATSPI_ROLE_WINDOW) { - ERROR("Pivot search entry point must be a Window!"); - return NULL; - } - - DEBUG("Finding SHOWING widget using top-down method."); - ret = _pivot_with_state_top_down_find(win, ATSPI_STATE_SHOWING); - if (ret) - return ret; - - DEBUG("Finding SHOWING widget using top-down method."); - ret = _pivot_with_state_flat_find(win, ATSPI_STATE_SHOWING); - if (ret) - return ret; - - DEBUG("Finding FOCUSED widget using top-down method."); - ret = _pivot_with_state_top_down_find(win, ATSPI_STATE_FOCUSED); - if (ret) - return ret; - - DEBUG("Finding FOCUSED widget using flat search method."); - ret = _pivot_with_state_flat_find(win, ATSPI_STATE_FOCUSED); - if (ret) - return ret; - - return NULL; -} -- 2.7.4 From 5c51fc1812d943621f7d367d9ef62f0218f0957d Mon Sep 17 00:00:00 2001 From: Lukasz Stanislawski Date: Tue, 3 Nov 2015 09:11:00 +0100 Subject: [PATCH 10/16] screen-reader: remove dead code Change-Id: Iedbc5f12a5c863fc7107d4085c109ec2d2fdbc0b --- src/screen_reader.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/screen_reader.c b/src/screen_reader.c index e6a6ff0..1f5e29e 100644 --- a/src/screen_reader.c +++ b/src/screen_reader.c @@ -62,13 +62,6 @@ int screen_reader_create_service(void *data) #ifdef SCREEN_READER_TV spi_init(service_data); #endif - - /* XML TEST */ -#ifdef RUN_IPC_TEST_SUIT - run_xml_tests(); - test_suite_init(); -#endif - return 0; } -- 2.7.4 From e58fd38860fed7b3ce5577de3f86b97ae64ede4a Mon Sep 17 00:00:00 2001 From: Tomasz Olszak Date: Tue, 17 Nov 2015 12:25:08 +0100 Subject: [PATCH 11/16] Setting CTEST_OUTPUT_ON_FAILURE env var before make test. This enables stdout/stderr output after failed tests. Change-Id: Iba445d9e6418e74e12e0757b853cd58610bb4bee --- packaging/org.tizen.screen-reader.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/org.tizen.screen-reader.spec b/packaging/org.tizen.screen-reader.spec index f75613f..0f6e4b2 100755 --- a/packaging/org.tizen.screen-reader.spec +++ b/packaging/org.tizen.screen-reader.spec @@ -68,6 +68,7 @@ make %{?jobs:-j%jobs} \ -e 's%^.*: error: .*$%\x1b[37;41m&\x1b[m%' \ -e 's%^.*: warning: .*$%\x1b[30;43m&\x1b[m%' export LD_LIBRARY_PATH=/emul/ia32-linux/lib:/emul/ia32-linux/usr/lib:$LD_LIBRARY_PATH +export CTEST_OUTPUT_ON_FAILURE=1 make test %install -- 2.7.4 From bc468b12d9f6db7c2eb1d9f22989c1c4c6b5ea0e Mon Sep 17 00:00:00 2001 From: Lukasz Stanislawski Date: Wed, 18 Nov 2015 15:51:45 +0100 Subject: [PATCH 12/16] navigator: remove non-existing include file Change-Id: If8b8c49819761b2ec3da66226227082272754f97 --- src/navigator.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/navigator.c b/src/navigator.c index 52d8891..b5b9e66 100644 --- a/src/navigator.c +++ b/src/navigator.c @@ -28,7 +28,6 @@ #include "navigator.h" #include "window_tracker.h" #include "keyboard_tracker.h" -#include "pivot_chooser.h" #include "flat_navi.h" #include "app_tracker.h" #include "smart_notification.h" -- 2.7.4 From 9d9260eadb124a7418855e7d06afccae66cc0667 Mon Sep 17 00:00:00 2001 From: Lukasz Stanislawski Date: Tue, 3 Nov 2015 11:41:50 +0100 Subject: [PATCH 13/16] mobile-lua: add additional LABELLED_BY relation Change-Id: I543b531ad4386ce7996e3b7ee061d70e5e564a9e --- res/scripts/mobile.lua | 44 ++++++++++++++++++++++++++++++++++++-------- src/lua_engine.c | 6 +++--- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/res/scripts/mobile.lua b/res/scripts/mobile.lua index c53c2e0..39d5396 100644 --- a/res/scripts/mobile.lua +++ b/res/scripts/mobile.lua @@ -114,16 +114,44 @@ function trait(obj) end end +function stringArrayAppend(strings, string) + if string ~= "" then + table.insert(strings, string) + end +end + +function generateStringArray(objects, createFunc) + local ret = {} + for k, target in ipairs(objects) do + stringArrayAppend(ret, createFunc(target)) + end + return ret +end + function describeObject(obj) - local related_trait = {} - for k, target in ipairs(obj:inRelation(RELATION_DESCRIBED_BY)) do - table.insert(related_trait, trait(target)) + local labels = generateStringArray(obj:inRelation(RELATION_LABELLED_BY), function(x) return x:name() end) + local descriptions = generateStringArray(obj:inRelation(RELATION_DESCRIBED_BY), function(x) return x:description() end) + local traits = generateStringArray(obj:inRelation(RELATION_DESCRIBED_BY), trait) + + -- use original object name if related objects do not provide other + if table.getn(labels) == 0 then + stringArrayAppend(labels, obj:name()) end - local ret = {obj:name(), trait(obj), obj:description(), table.concat(related_trait, ", ")} - for i=#ret,1,-1 do - if ret[i] == nil or ret[i] == "" then - table.remove(ret, i) - end + + -- use original object description if related objects do not provide other + if table.getn(descriptions) == 0 then + stringArrayAppend(descriptions, obj:description()) end + + -- use original object trait if related objects do not provide other + if table.getn(traits) == 0 then + stringArrayAppend(traits, trait(obj)) + end + + local ret = {} + stringArrayAppend(ret, table.concat(labels, ", ")) + stringArrayAppend(ret, table.concat(traits, ", ")) + stringArrayAppend(ret, table.concat(descriptions, ", ")) + return table.concat(ret, ", ") end diff --git a/src/lua_engine.c b/src/lua_engine.c index b2d8207..76cd94f 100644 --- a/src/lua_engine.c +++ b/src/lua_engine.c @@ -166,7 +166,7 @@ static int _accessible_relations(lua_State *L) { AtspiAccessible *obj = _pop_class_obj(L, 1, 1, ACCESSIBLE_CLASS_NAME); AtspiRelationType type = lua_tonumber(L, -1); GError *err = NULL; - int i, j; + int i, j, idx; lua_newtable(L); if (!obj) return 1; @@ -174,7 +174,7 @@ static int _accessible_relations(lua_State *L) { GERROR_CHECK(err); if (!rels) return 1; - for (i = 0; i < rels->len; i++) + for (i = 0, idx = 1; i < rels->len; i++) { AtspiRelation *rel = g_array_index(rels, AtspiRelation*, i); if (atspi_relation_get_relation_type(rel) == type) @@ -183,7 +183,7 @@ static int _accessible_relations(lua_State *L) { { AtspiAccessible *target = atspi_relation_get_target(rel, j); if (!target) continue; - lua_pushinteger(L, j); + lua_pushinteger(L, idx++); _push_class_obj(L, target, ACCESSIBLE_CLASS_NAME); lua_settable(L, -3); } -- 2.7.4 From bdc459e63ab88aae600d72deb68052d189b878f9 Mon Sep 17 00:00:00 2001 From: Bartlomiej Uliasz Date: Mon, 23 Nov 2015 11:40:22 +0100 Subject: [PATCH 14/16] Added TV trait descriptions for Screen Reader in new lua script and translation texts Change-Id: I852ca5bd344e23722891eb9a35ee1088ec30f257 Signed-off-by: Bartlomiej Uliasz --- res/po/en_US.po | 15 ++++++ res/scripts/tv.lua | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/screen_reader.c | 4 ++ 3 files changed, 149 insertions(+) create mode 100644 res/scripts/tv.lua diff --git a/res/po/en_US.po b/res/po/en_US.po index 4476e6d..9587016 100644 --- a/res/po/en_US.po +++ b/res/po/en_US.po @@ -47,15 +47,24 @@ msgstr "group index" msgid "IDS_TRAIT_GROUP_INDEX_EXPANDED" msgstr "Expandable list, Double tap to collapse" +msgid "IDS_TRAIT_GROUP_INDEX_EXPANDED_TV" +msgstr "Expandable list, press OK button to collapse" + msgid "IDS_TRAIT_GROUP_INDEX_COLLAPSED" msgstr "Expandable list, Double tap to expand" +msgid "IDS_TRAIT_GROUP_INDEX_COLLAPSED_TV" +msgstr "Expandable list, press OK button to expand" + msgid "IDS_TRAIT_MENU_ITEM_TAB_INDEX" msgstr "Tab %d of %d" msgid "IDS_TRAIT_TEXT_EDIT" msgstr "Double tap to edit" +msgid "IDS_TRAIT_TEXT_EDIT_TV" +msgstr "press OK button to edit" + msgid "IDS_TRAIT_CTX_POPUP" msgstr "Contextual popup" @@ -71,9 +80,15 @@ msgstr "Items" msgid "IDS_TRAIT_POPUP_CLOSE" msgstr "double tap to close it" +msgid "IDS_TRAIT_POPUP_CLOSE_TV" +msgstr "press OK button to close it" + msgid "IDS_TRAIT_TEXT_EDIT_FOCUSED" msgstr "Editing, flick up and down to adjust position." +msgid "IDS_TRAIT_TEXT_EDIT_FOCUSED_TV" +msgstr "Editing, press right and left button to adjust position." + msgid "IDS_TRAIT_PD_PROGRESSBAR" msgstr "Progressing" diff --git a/res/scripts/tv.lua b/res/scripts/tv.lua new file mode 100644 index 0000000..8c71768 --- /dev/null +++ b/res/scripts/tv.lua @@ -0,0 +1,130 @@ +function entry_trait(obj) + local ret = "" + if obj:is(FOCUSED) then + ret = T("IDS_TRAIT_TEXT_EDIT_FOCUSED_TV") + else + ret = T("IDS_TRAIT_TEXT_EDIT_TV") + end + return obj:roleName() .. ", " .. ret +end + +function menu_item_trait(obj) + n = table.getn(obj:parent():children()) + return string.format(T("IDS_TRAIT_MENU_ITEM_TAB_INDEX"), obj:index() + 1, n) +end + +function popup_menu_trait(obj) + local tr = { T("IDS_TRAIT_CTX_POPUP") , T("IDS_TRAIT_SHOWING") , tostring(table.getn(obj:children())), + T("IDS_TRAIT_ITEMS") , T("IDS_TRAIT_POPUP_CLOSE_TV")} + return table.concat(tr, " ") +end + +function dialog_trait(obj) + local n = table.getn(obj:children()) + local ret = T("IDS_TRAIT_POPUP") + if n > 0 then + ret = ret .. T("IDS_TRAIT_SHOWING") .. " " .. tostring(n) .. " " .. T("IDS_TRAIT_ITEMS") + end + return ret .. T("IDS_TRAIT_POPUP_CLOSE_TV") +end + +function list_item_trait(obj) + local ret = "" + local p = obj:parent() + if p and p:is(MULTISELECTABLE) then + if obj:is(SELECTED) then + ret = ret .. T("IDS_TRAIT_ITEM_SELECTED") + end + if p:selection() then + ret = ret .. string.format(T("IDS_TRAIT_ITEM_SELECTED_COUNT"), p:selection():count()) + end + else + if obj:is(EXPANDABLE) then + if obj:is(EXPANDED) then + ret = ret .. T("IDS_TRAIT_GROUP_INDEX_EXPANDED_TV") + else + ret = ret .. T("IDS_TRAIT_GROUP_INDEX_COLLAPSED_TV") + end + end + end + return ret +end + +function check_radio_trait(obj) + if obj:is(CHECKED) then + return T("IDS_TRAIT_CHECK_BOX_SELECTED") + else + return T("IDS_TRAIT_CHECK_BOX_NOT_SELECTED") + end +end + +function push_button_trait(obj) + return T("IDS_TRAIT_PUSH_BUTTON") +end + +function progress_bar_trait(obj) + if obj:value() then + cv = obj:value():current() + if cv >= 0 then + return string.format(T("IDS_TRAIT_PD_PROGRESSBAR_PERCENT"), cv * 100) + else + return T("IDS_TRAIT_PD_PROGRESSBAR") + end + end + return "" +end + +function toggle_button_trait(obj) + if obj:is(CHECKED) then + local state = T("IDS_TRAIT_TOGGLE_BUTTON_ON") + else + local state = T("IDS_TRAIT_TOGGLE_BUTTON_OFF") + end + return T("IDS_TRAIT_TOGGLE_BUTTON") .. ", " .. state +end + +function empty_trait(obj) + return "" +end + +function default_trait(obj) + return obj:roleName() +end + +local trait_map = { + [ENTRY] = entry_trait, + [MENU_ITEM] = menu_item_trait, + [POPUP_MENU] = popup_menu_trait, + [DIALOG] = dialog_trait, + [LIST_ITEM] = list_item_trait, + [CHECK_BOX] = check_radio_trait, + [RADIO_BUTTON] = check_radio_trait, + [PUSH_BUTTON] = push_button_trait, + [PROGRESS_BAR] = progress_bar_trait, + [TOGGLE_BUTTON] = toggle_button_trait, + [HEADING] = empty_trait, + [FILLER] = empty_trait, +} + +function trait(obj) + local func = trait_map[obj:role()] + if func ~= nil then + return func(obj) + else + return default_trait(obj) + end +end + +function describeObject(obj) + local related_trait = {} + for k, target in ipairs(obj:inRelation(RELATION_DESCRIBED_BY)) do + table.insert(related_trait, trait(target)) + end + local ret = {obj:name(), trait(obj), obj:description(), table.concat(related_trait, ", ")} + for i=#ret,1,-1 do + if ret[i] == nil or ret[i] == "" then + table.remove(ret, i) + end + end + return table.concat(ret, ", ") +end diff --git a/src/screen_reader.c b/src/screen_reader.c index 1f5e29e..4d800af 100644 --- a/src/screen_reader.c +++ b/src/screen_reader.c @@ -42,7 +42,11 @@ Service_Data service_data = { //Actions to do when tts state is 'ready' .update_language_list = false, +#ifdef SCREEN_READER_TV + .lua_script_path = SCRIPTDIR "/tv.lua", +#else .lua_script_path = SCRIPTDIR "/mobile.lua", +#endif .text_to_say_info = NULL }; -- 2.7.4 From f56aa771bc25ccac450afa9cc20b23d9971af3b0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Uliasz Date: Wed, 25 Nov 2015 16:26:04 +0100 Subject: [PATCH 15/16] keyboard_tracker.c: Added "back button" tts when hardware back button is used Change-Id: I9de80740ec672642d7c35b81aada160af14ee549 Signed-off-by: Bartlomiej Uliasz --- res/po/en_US.po | 3 +++ src/keyboard_tracker.c | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/res/po/en_US.po b/res/po/en_US.po index 9587016..194c68c 100644 --- a/res/po/en_US.po +++ b/res/po/en_US.po @@ -1,4 +1,7 @@ +msgid "IDS_BACK_BUTTON" +msgstr "back button" + msgid "IDS_TRAIT_SLIDER_SWIPE_COMMUNICATE" msgstr "flick up and down to adjust the position. " diff --git a/src/keyboard_tracker.c b/src/keyboard_tracker.c index 74befc9..b43cd7c 100644 --- a/src/keyboard_tracker.c +++ b/src/keyboard_tracker.c @@ -24,6 +24,7 @@ #include "logger.h" #include "screen_reader_tts.h" static AtspiDeviceListener *listener; +static AtspiDeviceListener *async_listener; static Keyboard_Tracker_Cb user_cb; static void *user_data; #ifdef X11_ENABLED @@ -158,10 +159,23 @@ static gboolean device_cb(const AtspiDeviceEvent * stroke, void *data) return TRUE; } +static gboolean async_keyboard_cb(const AtspiDeviceEvent * stroke, void *data) +{ + if (!strcmp(stroke->event_string, "XF86Back")) + { + tts_speak(_("IDS_BACK_BUTTON"), EINA_TRUE); + return TRUE; + } + else + return FALSE; +} + void keyboard_tracker_init(void) { listener = atspi_device_listener_new(device_cb, NULL, NULL); - atspi_register_keystroke_listener(listener, NULL, 0, ATSPI_KEY_PRESSED, ATSPI_KEYLISTENER_SYNCHRONOUS | ATSPI_KEYLISTENER_CANCONSUME, NULL); + atspi_register_keystroke_listener(listener, NULL, 0, 1 << ATSPI_KEY_PRESSED_EVENT, ATSPI_KEYLISTENER_SYNCHRONOUS | ATSPI_KEYLISTENER_CANCONSUME, NULL); + async_listener = atspi_device_listener_new(async_keyboard_cb, NULL, NULL); + atspi_register_keystroke_listener(async_listener, NULL, 0, 1 << ATSPI_KEY_RELEASED_EVENT, ATSPI_KEYLISTENER_NOSYNC, NULL); #ifdef X11_ENABLED active_xwindow_property_tracker_register(); root_xwindow_property_tracker_register(); @@ -177,7 +191,8 @@ void keyboard_tracker_register(Keyboard_Tracker_Cb cb, void *data) void keyboard_tracker_shutdown(void) { - atspi_deregister_keystroke_listener(listener, NULL, 0, ATSPI_KEY_PRESSED, NULL); + atspi_deregister_keystroke_listener(listener, NULL, 0, 1 << ATSPI_KEY_PRESSED, NULL); + atspi_deregister_keystroke_listener(async_listener, NULL, 0, 1 << ATSPI_KEY_RELEASED_EVENT, NULL); #ifdef X11_ENABLED root_xwindow_property_tracker_unregister(); active_xwindow_property_tracker_unregister(); -- 2.7.4 From 3c666a4a0161ac6f319580d4f76c2cb24e07a2cc Mon Sep 17 00:00:00 2001 From: Kamil Lipiszko Date: Fri, 27 Nov 2015 15:37:11 +0100 Subject: [PATCH 16/16] haptic: Vibrate on highlighted object change. Change-Id: Ic2749bc8520ed85721190ec8a06b4964d5ba5e59 Signed-off-by: Kamil Lipiszko --- include/screen_reader_haptic.h | 2 +- org.tizen.screen-reader.xml | 3 +++ src/navigator.c | 6 ++++++ src/screen_reader_haptic.c | 4 ++-- src/smart_notification.c | 5 +++++ 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/screen_reader_haptic.h b/include/screen_reader_haptic.h index d3f9beb..6bc6dcf 100644 --- a/include/screen_reader_haptic.h +++ b/include/screen_reader_haptic.h @@ -1,4 +1,4 @@ void haptic_module_init(void); void haptic_module_disconnect(void); -void haptic_vibrate_start(void); +void haptic_vibrate_start(int duration, int feedback); void haptic_vibrate_stop(void); diff --git a/org.tizen.screen-reader.xml b/org.tizen.screen-reader.xml index 99284a4..bc7e0a6 100755 --- a/org.tizen.screen-reader.xml +++ b/org.tizen.screen-reader.xml @@ -10,5 +10,8 @@ + + http://tizen.org/privilege/haptic + diff --git a/src/navigator.c b/src/navigator.c index b5b9e66..014260a 100644 --- a/src/navigator.c +++ b/src/navigator.c @@ -48,6 +48,9 @@ #define TTS_MAX_TEXT_SIZE 2000 #define GESTURE_LIMIT 10 +#define HAPTIC_VIBRATE_DURATION 50 +#define HAPTIC_VIBRATE_INTENSITY 50 + //Timeout in ms which will be used as interval for handling ongoing //hoved gesture updates. It is introduced to improve performance. //Even if user makes many mouse move events within hover gesture @@ -1634,6 +1637,9 @@ static void _new_highlighted_obj_changed(AtspiAccessible * new_highlighted_obj, if (context && flat_navi_context_current_get(context) != new_highlighted_obj) { flat_navi_context_current_set(context, g_object_ref(new_highlighted_obj)); } + + haptic_vibrate_start(HAPTIC_VIBRATE_DURATION, HAPTIC_VIBRATE_INTENSITY); + } void clear(gpointer d) diff --git a/src/screen_reader_haptic.c b/src/screen_reader_haptic.c index f099cb4..028ba0e 100644 --- a/src/screen_reader_haptic.c +++ b/src/screen_reader_haptic.c @@ -67,13 +67,13 @@ void haptic_module_disconnect(void) * @brief Start vibrations * */ -void haptic_vibrate_start(void) +void haptic_vibrate_start(int duration, int feedback) { if (!handle) { ERROR("Haptic handle lost"); return; } - if (!device_haptic_vibrate(handle, 1000, 100, &effect_handle)) { + if (!device_haptic_vibrate(handle, duration, feedback, &effect_handle)) { DEBUG(RED "Vibrations started!" RESET); } else { ERROR("Cannot start vibration"); diff --git a/src/smart_notification.c b/src/smart_notification.c index e519797..70b0a16 100644 --- a/src/smart_notification.c +++ b/src/smart_notification.c @@ -141,7 +141,9 @@ void smart_notification_init(void) atspi_event_listener_register(listener, "object:scroll-start", NULL); atspi_event_listener_register(listener, "object:scroll-end", NULL); +#ifndef SCREEN_READER_TV haptic_module_init(); +#endif status = EINA_TRUE; } @@ -152,6 +154,9 @@ void smart_notification_init(void) */ void smart_notification_shutdown(void) { +#ifndef SCREEN_READER_TV + haptic_module_disconnect(); +#endif status = EINA_FALSE; } -- 2.7.4