From 1e68de0b411bd9eeefae41a99242e35c316d9026 Mon Sep 17 00:00:00 2001 From: Seoyeon Kim Date: Mon, 31 Oct 2016 19:04:33 +0900 Subject: [PATCH] [3.0] Implement wayland specific Accessibility Change-Id: I45c11d4a70e844b8a9aab413446598d5b255ddc5 Signed-off-by: Seoyeon Kim --- adaptors/ecore/wayland/event-handler-ecore-wl.cpp | 451 ++++++++++++++++++++++ 1 file changed, 451 insertions(+) diff --git a/adaptors/ecore/wayland/event-handler-ecore-wl.cpp b/adaptors/ecore/wayland/event-handler-ecore-wl.cpp index 6d29d80..6ea2e83 100644 --- a/adaptors/ecore/wayland/event-handler-ecore-wl.cpp +++ b/adaptors/ecore/wayland/event-handler-ecore-wl.cpp @@ -31,6 +31,10 @@ #include #endif // DALI_PROFILE_UBUNTU +#ifdef DALI_ELDBUS_AVAILABLE +#include +#endif // DALI_ELDBUS_AVAILABLE + #include #include #include @@ -74,10 +78,98 @@ Integration::Log::Filter* gSelectionEventLogFilter = Integration::Log::Filter::N namespace { + +// DBUS accessibility +#define A11Y_BUS "org.a11y.Bus" +#define A11Y_INTERFACE "org.a11y.Bus" +#define A11Y_PATH "/org/a11y/bus" +#define A11Y_GET_ADDRESS "GetAddress" +#define BUS "com.samsung.EModule" +#define INTERFACE "com.samsung.GestureNavigation" +#define PATH "/com/samsung/GestureNavigation" +#define SIGNAL "GestureDetected" + const unsigned int PRIMARY_TOUCH_BUTTON_ID( 1 ); const unsigned int BYTES_PER_CHARACTER_FOR_ATTRIBUTES = 3; +#ifdef DALI_ELDBUS_AVAILABLE +// DBus gesture string matching lists. +// TODO: This needs moving to its own module. +const char * ElDBusAccessibilityFingerCountStrings[] = +{ + "OneFinger", + "TwoFingers", + "ThreeFingers" +}; +const unsigned int FingerCountStringsTotal = sizeof( ElDBusAccessibilityFingerCountStrings ) / sizeof( ElDBusAccessibilityFingerCountStrings[0] ); +enum GestureType +{ + GESTURE_TYPE_NONE, + GESTURE_TYPE_HOVER, + GESTURE_TYPE_SINGLE_TAP, + GESTURE_TYPE_DOUBLE_TAP, + GESTURE_TYPE_TRIPLE_TAP +}; +struct GestureTypeTable +{ + const char* name; + const GestureType type; +}; +GestureTypeTable ElDBusAccessibilityFullEventTypeStrings[] = +{ + { "Hover", GESTURE_TYPE_HOVER }, + { "SingleTap", GESTURE_TYPE_SINGLE_TAP }, + { "DoubleTap", GESTURE_TYPE_DOUBLE_TAP }, + { "TripleTap", GESTURE_TYPE_TRIPLE_TAP } +}; +const unsigned int FullEventTypeStringsTotal = sizeof( ElDBusAccessibilityFullEventTypeStrings ) / sizeof( ElDBusAccessibilityFullEventTypeStrings[0] ); +enum SubGestureType +{ + SUB_GESTURE_TYPE_NONE, + SUB_GESTURE_TYPE_FLICK +}; +struct SubGestureTypeTable +{ + const char* name; + const SubGestureType type; +}; +SubGestureTypeTable ElDBusAccessibilityDirectionalEventTypeStrings[] = +{ + { "Flick", SUB_GESTURE_TYPE_FLICK } +}; +const unsigned int DirectionalEventTypeStringsTotal = sizeof( ElDBusAccessibilityDirectionalEventTypeStrings ) / sizeof( ElDBusAccessibilityDirectionalEventTypeStrings[0] ); +enum GestureDirection +{ + GESTURE_DIRECTION_NONE, + GESTURE_DIRECTION_UP, + GESTURE_DIRECTION_DOWN, + GESTURE_DIRECTION_LEFT, + GESTURE_DIRECTION_RIGHT, + GESTURE_DIRECTION_UP_RETURN, + GESTURE_DIRECTION_DOWN_RETURN, + GESTURE_DIRECTION_LEFT_RETURN, + GESTURE_DIRECTION_RIGHT_RETURN +}; +struct GestureDirectionTable +{ + const char* name; + const GestureDirection direction; +}; +GestureDirectionTable ElDBusAccessibilityDirectionStrings[] = +{ + { "Up", GESTURE_DIRECTION_UP }, + { "Down", GESTURE_DIRECTION_DOWN }, + { "Left", GESTURE_DIRECTION_LEFT }, + { "Right", GESTURE_DIRECTION_RIGHT }, + { "UpReturn", GESTURE_DIRECTION_UP_RETURN }, + { "DownReturn", GESTURE_DIRECTION_DOWN_RETURN }, + { "LeftReturn", GESTURE_DIRECTION_LEFT_RETURN }, + { "RightReturn", GESTURE_DIRECTION_RIGHT_RETURN } +}; +const unsigned int DirectionStringsTotal = sizeof( ElDBusAccessibilityDirectionStrings ) / sizeof( ElDBusAccessibilityDirectionStrings[0] ); +#endif // DALI_ELDBUS_AVAILABLE + /** * Ecore_Event_Modifier enums in Ecore_Input.h do not match Ecore_IMF_Keyboard_Modifiers in Ecore_IMF.h. * This function converts from Ecore_Event_Modifier to Ecore_IMF_Keyboard_Modifiers enums. @@ -172,6 +264,10 @@ struct EventHandler::Impl : mHandler( handler ), mEcoreEventHandler(), mWindow( window ) +#ifdef DALI_ELDBUS_AVAILABLE + , mSessionConnection( NULL ), + mA11yConnection( NULL ) +#endif { // Only register for touch and key events if we have a window if ( window != 0 ) @@ -205,6 +301,24 @@ struct EventHandler::Impl vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontNameChanged, handler ); vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, handler ); #endif // DALI_PROFILE_UBUNTU + +#ifdef DALI_ELDBUS_AVAILABLE + + // Initialize ElDBus. + DALI_LOG_INFO( gImfLogging, Debug::General, "Starting DBus Initialization\n" ); + eldbus_init(); + + mSessionConnection = eldbus_connection_get( ELDBUS_CONNECTION_TYPE_SESSION ); + + Eldbus_Object *a11yObject = eldbus_object_get( mSessionConnection, A11Y_BUS, A11Y_PATH ); + Eldbus_Proxy *elDBusManager = eldbus_proxy_get( a11yObject, A11Y_INTERFACE ); + + // Pass in handler in the cb_data field so we can access the accessibility adaptor within the callback. + eldbus_proxy_call( elDBusManager, A11Y_GET_ADDRESS, EcoreElDBusInitialisation, handler, -1, "" ); + + DALI_LOG_INFO( gImfLogging, Debug::General, "Finished DBus Initialization\n" ); + +#endif // DALI_ELDBUS_AVAILABLE } } @@ -222,6 +336,21 @@ struct EventHandler::Impl { ecore_event_handler_del( *iter ); } + +#ifdef DALI_ELDBUS_AVAILABLE + // Close down ElDBus + if( mA11yConnection ) + { + eldbus_connection_unref( mA11yConnection ); + } + + if( mSessionConnection ) + { + eldbus_connection_unref( mSessionConnection ); + } + + eldbus_shutdown(); +#endif // DALI_ELDBUS_AVAILABLE } // Static methods @@ -642,6 +771,323 @@ struct EventHandler::Impl return ECORE_CALLBACK_PASS_ON; } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + // ElDBus Accessibility Callbacks + ///////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef DALI_ELDBUS_AVAILABLE + // Callback for Ecore ElDBus accessibility events. + static void OnEcoreElDBusAccessibilityNotification( void *context EINA_UNUSED, const Eldbus_Message *message ) + { + EventHandler* handler = static_cast< EventHandler* >( context ); + // Ignore any accessibility events when paused. + if( handler->mPaused ) + { + return; + } + + if ( !handler->mAccessibilityAdaptor ) + { + DALI_LOG_ERROR( "Invalid accessibility adaptor\n" ); + return; + } + + AccessibilityAdaptor* accessibilityAdaptor( &AccessibilityAdaptor::GetImplementation( handler->mAccessibilityAdaptor ) ); + if ( !accessibilityAdaptor ) + { + DALI_LOG_ERROR( "Cannot access accessibility adaptor\n" ); + return; + } + + const char *gestureName; + int xS, yS, xE, yE; + unsigned int state; + + // The string defines the arg-list's respective types. + if( !eldbus_message_arguments_get( message, "siiiiu", &gestureName, &xS, &yS, &xE, &yE, &state ) ) + { + DALI_LOG_ERROR( "OnEcoreElDBusAccessibilityNotification: Error getting arguments\n" ); + } + + DALI_LOG_INFO( gImfLogging, Debug::General, "Got gesture: Name: %s Args: %d,%d,%d,%d State: %d\n", gestureName, xS, yS, xE, yE ); + + unsigned int fingers = 0; + char* stringPosition = ( char* )gestureName; + + // Check how many fingers the gesture uses. + for( unsigned int i = 0; i < FingerCountStringsTotal; ++i ) + { + unsigned int matchLength = strlen( ElDBusAccessibilityFingerCountStrings[ i ] ); + if( strncmp( gestureName, ElDBusAccessibilityFingerCountStrings[ i ], matchLength ) == 0 ) + { + fingers = i + 1; + stringPosition += matchLength; + break; + } + } + + if( fingers == 0 ) + { + // Error: invalid gesture. + return; + } + + GestureType gestureType = GESTURE_TYPE_NONE; + SubGestureType subGestureType = SUB_GESTURE_TYPE_NONE; + GestureDirection direction = GESTURE_DIRECTION_NONE; + + // Check for full gesture type names first. + for( unsigned int i = 0; i < FullEventTypeStringsTotal; ++i ) + { + unsigned int matchLength = strlen( ElDBusAccessibilityFullEventTypeStrings[ i ].name ); + if( strncmp( stringPosition, ElDBusAccessibilityFullEventTypeStrings[ i ].name, matchLength ) == 0 ) + { + gestureType = ElDBusAccessibilityFullEventTypeStrings[ i ].type; + break; + } + } + + // If we didn't find a full gesture, check for sub gesture type names. + if( gestureType == GESTURE_TYPE_NONE ) + { + // No full gesture name found, look for partial types. + for( unsigned int i = 0; i < DirectionalEventTypeStringsTotal; ++i ) + { + unsigned int matchLength = strlen( ElDBusAccessibilityDirectionalEventTypeStrings[ i ].name ); + if( strncmp( stringPosition, ElDBusAccessibilityDirectionalEventTypeStrings[ i ].name, matchLength ) == 0 ) + { + subGestureType = ElDBusAccessibilityDirectionalEventTypeStrings[ i ].type; + stringPosition += matchLength; + break; + } + } + + if( subGestureType == SUB_GESTURE_TYPE_NONE ) + { + // ERROR: Gesture not recognised. + return; + } + + // If the gesture was a sub type, get it's respective direction. + for( unsigned int i = 0; i < DirectionStringsTotal; ++i ) + { + unsigned int matchLength = strlen( ElDBusAccessibilityDirectionStrings[ i ].name ); + if( strncmp( stringPosition, ElDBusAccessibilityDirectionStrings[ i ].name, matchLength ) == 0 ) + { + direction = ElDBusAccessibilityDirectionStrings[ i ].direction; + stringPosition += matchLength; + break; + } + } + + if( direction == GESTURE_DIRECTION_NONE ) + { + // ERROR: Gesture not recognised. + return; + } + } + + // Action the detected gesture here. + if( gestureType != GESTURE_TYPE_NONE ) + { + DALI_LOG_INFO( gImfLogging, Debug::General, "Got gesture: Fingers: %d Gesture type: %d\n", fingers, gestureType ); + } + else + { + DALI_LOG_INFO( gImfLogging, Debug::General, "Got gesture: Fingers: %d Gesture sub type: %d Gesture direction: %d\n", + fingers, subGestureType, direction ); + } + + // Create a touch point object. + TouchPoint::State touchPointState( TouchPoint::Down ); + if ( state == 0 ) + { + touchPointState = TouchPoint::Down; // Mouse down. + } + else if ( state == 1 ) + { + touchPointState = TouchPoint::Motion; // Mouse move. + } + else if ( state == 2 ) + { + touchPointState = TouchPoint::Up; // Mouse up. + } + else + { + touchPointState = TouchPoint::Interrupted; // Error. + } + + // Send touch event to accessibility adaptor. + TouchPoint point( 0, touchPointState, (float)xS, (float)yS ); + + // Perform actions based on received gestures. + // Note: This is seperated from the reading so we can (in future) + // have other input readers without changing the below code. + switch( fingers ) + { + case 1: + { + if( gestureType == GESTURE_TYPE_SINGLE_TAP || ( gestureType == GESTURE_TYPE_HOVER && touchPointState == TouchPoint::Motion ) ) + { + // Focus, read out. + accessibilityAdaptor->HandleActionReadEvent( (unsigned int)xS, (unsigned int)yS, true /* allow read again */ ); + } + else if( gestureType == GESTURE_TYPE_DOUBLE_TAP ) + { + if( false ) // TODO: how to detect double tap + hold + { + // Move or drag icon / view more options for selected items. + // accessibilityAdaptor->HandleActionTouchEvent( point, GetCurrentMilliSeconds() ); + } + else + { + // Activate selected item / active edit mode. + accessibilityAdaptor->HandleActionActivateEvent(); + } + } + else if( gestureType == GESTURE_TYPE_TRIPLE_TAP ) + { + // Zoom + accessibilityAdaptor->HandleActionZoomEvent(); + } + else if( subGestureType == SUB_GESTURE_TYPE_FLICK ) + { + if( direction == GESTURE_DIRECTION_LEFT ) + { + // Move to previous item. + accessibilityAdaptor->HandleActionReadPreviousEvent(); + } + else if( direction == GESTURE_DIRECTION_RIGHT ) + { + // Move to next item. + accessibilityAdaptor->HandleActionReadNextEvent(); + } + else if( direction == GESTURE_DIRECTION_UP ) + { + // Move to next item. + accessibilityAdaptor->HandleActionPreviousEvent(); + } + else if( direction == GESTURE_DIRECTION_DOWN ) + { + // Move to next item. + accessibilityAdaptor->HandleActionNextEvent(); + } + else if( direction == GESTURE_DIRECTION_LEFT_RETURN ) + { + // Scroll up to the previous page + accessibilityAdaptor->HandleActionPageUpEvent(); + } + else if( direction == GESTURE_DIRECTION_RIGHT_RETURN ) + { + // Scroll down to the next page + accessibilityAdaptor->HandleActionPageDownEvent(); + } + else if( direction == GESTURE_DIRECTION_UP_RETURN ) + { + // Move to the first item on screen + accessibilityAdaptor->HandleActionMoveToFirstEvent(); + } + else if( direction == GESTURE_DIRECTION_DOWN_RETURN ) + { + // Move to the last item on screen + accessibilityAdaptor->HandleActionMoveToLastEvent(); + } + } + break; + } + + case 2: + { + if( gestureType == GESTURE_TYPE_HOVER ) + { + // In accessibility mode, scroll action should be handled when the currently focused actor is contained in scrollable control + accessibilityAdaptor->HandleActionScrollEvent( point, GetCurrentMilliSeconds() ); + } + else if( gestureType == GESTURE_TYPE_SINGLE_TAP ) + { + // Pause/Resume current speech + accessibilityAdaptor->HandleActionReadPauseResumeEvent(); + } + else if( gestureType == GESTURE_TYPE_DOUBLE_TAP ) + { + // Start/Stop current action + accessibilityAdaptor->HandleActionStartStopEvent(); + } + else if( gestureType == GESTURE_TYPE_TRIPLE_TAP ) + { + // Read information from indicator + accessibilityAdaptor->HandleActionReadIndicatorInformationEvent(); + } + else if( subGestureType == SUB_GESTURE_TYPE_FLICK ) + { + if( direction == GESTURE_DIRECTION_LEFT ) + { + // Scroll left to the previous page + accessibilityAdaptor->HandleActionPageLeftEvent(); + } + else if( direction == GESTURE_DIRECTION_RIGHT ) + { + // Scroll right to the next page + accessibilityAdaptor->HandleActionPageRightEvent(); + } + else if( direction == GESTURE_DIRECTION_UP ) + { + // Scroll up the list. + accessibilityAdaptor->HandleActionScrollUpEvent(); + } + else if( direction == GESTURE_DIRECTION_DOWN ) + { + // Scroll down the list. + accessibilityAdaptor->HandleActionScrollDownEvent(); + } + } + break; + } + + case 3: + { + if( gestureType == GESTURE_TYPE_SINGLE_TAP ) + { + // Read from top item on screen continuously. + accessibilityAdaptor->HandleActionReadFromTopEvent(); + } + else if( gestureType == GESTURE_TYPE_DOUBLE_TAP ) + { + // Read from next item continuously. + accessibilityAdaptor->HandleActionReadFromNextEvent(); + } + break; + } + } + } + + // Callback for to set up Ecore ElDBus for accessibility callbacks. + static void EcoreElDBusInitialisation( void *handle, const Eldbus_Message *message, Eldbus_Pending *pending EINA_UNUSED ) + { + Eldbus_Object *object; + Eldbus_Proxy *manager; + const char *a11yBusAddress = NULL; + EventHandler* handler = static_cast< EventHandler* >( handle ); + + // The string defines the arg-list's respective types. + if( !eldbus_message_arguments_get( message, "s", &a11yBusAddress ) ) + { + DALI_LOG_ERROR( "EcoreElDBusInitialisation: Error getting arguments\n" ); + } + + DALI_LOG_INFO( gImfLogging, Debug::General, "Ecore ElDBus Accessibility address: %s\n", a11yBusAddress ); + + handler->mImpl->mA11yConnection = eldbus_address_connection_get( a11yBusAddress ); + + object = eldbus_object_get( handler->mImpl->mA11yConnection, BUS, PATH ); + manager = eldbus_proxy_get( object, INTERFACE ); + + // Pass the callback data through to the signal handler. + eldbus_proxy_signal_handler_add( manager, SIGNAL, OnEcoreElDBusAccessibilityNotification, handle ); + } +#endif // DALI_ELDBUS_AVAILABLE + /** * Called when the source window notifies us the content in clipboard is selected. */ @@ -745,6 +1191,11 @@ struct EventHandler::Impl EventHandler* mHandler; std::vector mEcoreEventHandler; Ecore_Wl_Window* mWindow; + +#ifdef DALI_ELDBUS_AVAILABLE + Eldbus_Connection* mSessionConnection; + Eldbus_Connection* mA11yConnection; +#endif }; EventHandler::EventHandler( RenderSurface* surface, CoreEventInterface& coreEventInterface, GestureManager& gestureManager, DamageObserver& damageObserver, DragAndDropDetectorPtr dndDetector ) -- 2.7.4