Fix IME (key input) issues on Text control
[platform/core/uifw/dali-adaptor.git] / adaptors / ecore / wayland / event-handler-ecore-wl.cpp
index 1d38c49..f92fbdb 100644 (file)
 #include <vconf-keys.h>
 #endif // DALI_PROFILE_UBUNTU
 
+#ifdef DALI_ELDBUS_AVAILABLE
+#include <Eldbus.h>
+#endif // DALI_ELDBUS_AVAILABLE
+
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/events/touch-point.h>
 #include <dali/public-api/events/key-event.h>
@@ -64,7 +68,6 @@ namespace Adaptor
 namespace
 {
 Integration::Log::Filter* gTouchEventLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_TOUCH");
-Integration::Log::Filter* gClientMessageLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_CLIENT_MESSAGE");
 Integration::Log::Filter* gDragAndDropLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_DND");
 Integration::Log::Filter* gImfLogging  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_IMF");
 Integration::Log::Filter* gSelectionEventLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_SELECTION");
@@ -74,6 +77,12 @@ Integration::Log::Filter* gSelectionEventLogFilter = Integration::Log::Filter::N
 
 namespace
 {
+
+// DBUS accessibility
+const char* BUS = "org.enlightenment.wm-screen-reader";
+const char* INTERFACE = "org.tizen.GestureNavigation";
+const char* PATH = "/org/tizen/GestureNavigation";
+
 const unsigned int PRIMARY_TOUCH_BUTTON_ID( 1 );
 
 const unsigned int BYTES_PER_CHARACTER_FOR_ATTRIBUTES = 3;
@@ -172,6 +181,9 @@ struct EventHandler::Impl
   : mHandler( handler ),
     mEcoreEventHandler(),
     mWindow( window )
+#ifdef DALI_ELDBUS_AVAILABLE
+  , mSystemConnection( NULL )
+#endif // DALI_ELDBUS_AVAILABLE
   {
     // Only register for touch and key events if we have a window
     if ( window != 0 )
@@ -193,11 +205,31 @@ struct EventHandler::Impl
       mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_KEY_DOWN,           EcoreEventKeyDown,         handler ) );
       mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_KEY_UP,             EcoreEventKeyUp,           handler ) );
 
+      // Register Selection event - clipboard selection
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_WL_EVENT_DATA_SOURCE_SEND, EcoreEventDataSend, handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_WL_EVENT_SELECTION_DATA_READY, EcoreEventDataReceive, handler ) );
+
+      // Register Rotate event
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_WL_EVENT_WINDOW_ROTATE, EcoreEventRotate, handler) );
+
+      // Register Detent event
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_DETENT_ROTATE, EcoreEventDetent, handler) );
+
 #ifndef DALI_PROFILE_UBUNTU
       // Register Vconf notify - font name and size
       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" );
+
+      // Pass in handler.
+      EcoreElDBusInitialisation( handler );
+
+      DALI_LOG_INFO( gImfLogging, Debug::General, "Finished DBus Initialization\n" );
+#endif // DALI_ELDBUS_AVAILABLE
     }
   }
 
@@ -215,6 +247,14 @@ struct EventHandler::Impl
     {
       ecore_event_handler_del( *iter );
     }
+
+#ifdef DALI_ELDBUS_AVAILABLE
+    // Close down ElDBus connections.
+    if( mSystemConnection )
+    {
+      eldbus_connection_unref( mSystemConnection );
+    }
+#endif // DALI_ELDBUS_AVAILABLE
   }
 
   // Static methods
@@ -356,6 +396,11 @@ struct EventHandler::Impl
         ecoreKeyDownEvent.timestamp = keyEvent->timestamp;
         ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier ( keyEvent->modifiers );
         ecoreKeyDownEvent.locks     = (Ecore_IMF_Keyboard_Locks) ECORE_IMF_KEYBOARD_LOCK_NONE;
+#ifdef ECORE_IMF_1_13
+        ecoreKeyDownEvent.dev_name  = "";
+        ecoreKeyDownEvent.dev_class = ECORE_IMF_DEVICE_CLASS_KEYBOARD;
+        ecoreKeyDownEvent.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
+#endif // ECORE_IMF_1_13
 
         eventHandled = ecore_imf_context_filter_event( imfContext,
                                                        ECORE_IMF_EVENT_KEY_DOWN,
@@ -434,6 +479,11 @@ struct EventHandler::Impl
         ecoreKeyUpEvent.timestamp = keyEvent->timestamp;
         ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier ( keyEvent->modifiers );
         ecoreKeyUpEvent.locks     = (Ecore_IMF_Keyboard_Locks) ECORE_IMF_KEYBOARD_LOCK_NONE;
+#ifdef ECORE_IMF_1_13
+        ecoreKeyUpEvent.dev_name  = "";
+        ecoreKeyUpEvent.dev_class = ECORE_IMF_DEVICE_CLASS_KEYBOARD;
+        ecoreKeyUpEvent.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
+#endif // ECORE_IMF_1_13
 
         eventHandled = ecore_imf_context_filter_event( imfContext,
                                                        ECORE_IMF_EVENT_KEY_UP,
@@ -500,7 +550,8 @@ struct EventHandler::Impl
           }
         }
       }
-      // No need to connect callbacks as KeyboardStatusChanged will be called.
+      Dali::Clipboard clipboard = Clipboard::Get();
+      clipboard.HideClipboard();
     }
 
     return ECORE_CALLBACK_PASS_ON;
@@ -532,9 +583,13 @@ struct EventHandler::Impl
         }
       }
 
-      // Clipboard don't support that whether clipboard is shown or not. Hide clipboard.
+      // Hiding clipboard event will be ignored once because window focus out event is always received on showing clipboard
       Dali::Clipboard clipboard = Clipboard::Get();
-      clipboard.HideClipboard();
+      if ( clipboard )
+      {
+        Clipboard& clipBoardImpl( GetImplementation( clipboard ) );
+        clipBoardImpl.HideClipboard(true);
+      }
     }
 
     return ECORE_CALLBACK_PASS_ON;
@@ -630,6 +685,311 @@ 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;
+    }
+
+    int gestureValue;
+    int xS, yS, xE, yE;
+    int state; // 0 - begin, 1 - ongoing, 2 - ended, 3 - aborted
+    int eventTime;
+
+    // The string defines the arg-list's respective types.
+    if( !eldbus_message_arguments_get( message, "iiiiiiu", &gestureValue, &xS, &yS, &xE, &yE, &state, &eventTime ) )
+    {
+      DALI_LOG_ERROR( "OnEcoreElDBusAccessibilityNotification: Error getting arguments\n" );
+    }
+
+    DALI_LOG_INFO( gImfLogging, Debug::General, "Got gesture: Name: %d  Args: %d,%d,%d,%d  State: %d\n", gestureValue, xS, yS, xE, yE );
+
+    // 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 have other input readers without changing the below code.
+    switch( gestureValue )
+    {
+      case 0: // OneFingerHover
+      {
+        // Focus, read out.
+        accessibilityAdaptor->HandleActionReadEvent( (unsigned int)xS, (unsigned int)yS, true /* allow read again */ );
+        break;
+      }
+      case 1: // TwoFingersHover
+      {
+        // In accessibility mode, scroll action should be handled when the currently focused actor is contained in scrollable control
+        accessibilityAdaptor->HandleActionScrollEvent( point, GetCurrentMilliSeconds() );
+        break;
+      }
+      case 2: // ThreeFingersHover
+      {
+        // Read from top item on screen continuously.
+        accessibilityAdaptor->HandleActionReadFromTopEvent();
+        break;
+      }
+      case 3: // OneFingerFlickLeft
+      {
+        // Move to previous item.
+        accessibilityAdaptor->HandleActionReadPreviousEvent();
+        break;
+      }
+      case 4: // OneFingerFlickRight
+      {
+        // Move to next item.
+        accessibilityAdaptor->HandleActionReadNextEvent();
+        break;
+      }
+      case 5: // OneFingerFlickUp
+      {
+        // Move to previous item.
+        accessibilityAdaptor->HandleActionPreviousEvent();
+        break;
+      }
+      case 6: // OneFingerFlickDown
+      {
+        // Move to next item.
+        accessibilityAdaptor->HandleActionNextEvent();
+        break;
+      }
+      case 7: // TwoFingersFlickUp
+      {
+        // Scroll up the list.
+        accessibilityAdaptor->HandleActionScrollUpEvent();
+        break;
+      }
+      case 8: // TwoFingersFlickDown
+      {
+        // Scroll down the list.
+        accessibilityAdaptor->HandleActionScrollDownEvent();
+        break;
+      }
+      case 9: // TwoFingersFlickLeft
+      {
+        // Scroll left to the previous page
+        accessibilityAdaptor->HandleActionPageLeftEvent();
+        break;
+      }
+      case 10: // TwoFingersFlickRight
+      {
+        // Scroll right to the next page
+        accessibilityAdaptor->HandleActionPageRightEvent();
+        break;
+      }
+      case 11: // ThreeFingersFlickLeft
+      {
+        // Not exist yet
+        break;
+      }
+      case 12: // ThreeFingersFlickRight
+      {
+        // Not exist yet
+        break;
+      }
+      case 13: // ThreeFingersFlickUp
+      {
+        // Not exist yet
+        break;
+      }
+      case 14: // ThreeFingersFlickDown
+      {
+        // Not exist yet
+        break;
+      }
+      case 15: // OneFingerSingleTap
+      {
+        // Focus, read out.
+        accessibilityAdaptor->HandleActionReadEvent( (unsigned int)xS, (unsigned int)yS, true /* allow read again */ );
+        break;
+      }
+      case 16: // OneFingerDoubleTap
+      {
+        // Activate selected item / active edit mode.
+        accessibilityAdaptor->HandleActionActivateEvent();
+        break;
+      }
+      case 17: // OneFingerTripleTap
+      {
+        // Zoom
+        accessibilityAdaptor->HandleActionZoomEvent();
+        break;
+      }
+      case 18: // TwoFingersSingleTap
+      {
+        // Pause/Resume current speech
+        accessibilityAdaptor->HandleActionReadPauseResumeEvent();
+        break;
+      }
+      case 19: // TwoFingersDoubleTap
+      {
+        // Start/Stop current action
+        accessibilityAdaptor->HandleActionStartStopEvent();
+        break;
+      }
+      case 20: // TwoFingersTripleTap
+      {
+        // Read information from indicator
+        accessibilityAdaptor->HandleActionReadIndicatorInformationEvent();
+        break;
+      }
+      case 21: // ThreeFingersSingleTap
+      {
+        // Read from top item on screen continuously.
+        accessibilityAdaptor->HandleActionReadFromTopEvent();
+        break;
+      }
+      case 22: // ThreeFingersDoubleTap
+      {
+        // Read from next item continuously.
+        accessibilityAdaptor->HandleActionReadFromNextEvent();
+        break;
+      }
+      case 23: // ThreeFingersTripleTap
+      {
+        // Not exist yet
+        break;
+      }
+      case 24: // OneFingerFlickLeftReturn
+      {
+        // Scroll up to the previous page
+        accessibilityAdaptor->HandleActionPageUpEvent();
+        break;
+      }
+      case 25: // OneFingerFlickRightReturn
+      {
+        // Scroll down to the next page
+        accessibilityAdaptor->HandleActionPageDownEvent();
+        break;
+      }
+      case 26: // OneFingerFlickUpReturn
+      {
+        // Move to the first item on screen
+        accessibilityAdaptor->HandleActionMoveToFirstEvent();
+        break;
+      }
+      case 27: // OneFingerFlickDownReturn
+      {
+        // Move to the last item on screen
+        accessibilityAdaptor->HandleActionMoveToLastEvent();
+        break;
+      }
+      case 28: // TwoFingersFlickLeftReturn
+      {
+        // Not exist yet
+        break;
+      }
+      case 29: // TwoFingersFlickRightReturn
+      {
+        // Not exist yet
+        break;
+      }
+      case 30: // TwoFingersFlickUpReturn
+      {
+        // Not exist yet
+        break;
+      }
+      case 31: // TwoFingersFlickDownReturn
+      {
+        // Not exist yet
+        break;
+      }
+      case 32: // ThreeFingersFlickLeftReturn
+      {
+        // Not exist yet
+        break;
+      }
+      case 33: // ThreeFingersFlickRightReturn
+      {
+        // Not exist yet
+        break;
+      }
+      case 34: // ThreeFingersFlickUpReturn
+      {
+        // Not exist yet
+        break;
+      }
+      case 35: // ThreeFingersFlickDownReturn
+      {
+        // Not exist yet
+        break;
+      }
+    }
+  }
+
+  void EcoreElDBusInitialisation( void *handle )
+  {
+    Eldbus_Object *object;
+    Eldbus_Proxy *manager;
+
+    if( !( mSystemConnection = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM) ) )
+    {
+      DALI_LOG_ERROR( "Unable to get system bus\n" );
+    }
+
+    object = eldbus_object_get( mSystemConnection, BUS, PATH );
+    if( !object )
+    {
+      DALI_LOG_ERROR( "Getting object failed\n" );
+      return;
+    }
+
+    manager = eldbus_proxy_get( object, INTERFACE );
+    if( !manager )
+    {
+      DALI_LOG_ERROR( "Getting proxy failed\n" );
+      return;
+    }
+
+    if( !eldbus_proxy_signal_handler_add( manager, "GestureDetected", OnEcoreElDBusAccessibilityNotification, handle ) )
+    {
+      DALI_LOG_ERROR( "No signal handler returned\n" );
+    }
+  }
+#endif // DALI_ELDBUS_AVAILABLE
+
   /**
    * Called when the source window notifies us the content in clipboard is selected.
    */
@@ -649,6 +1009,90 @@ struct EventHandler::Impl
     return ECORE_CALLBACK_PASS_ON;
   }
 
+  /**
+  * Called when the source window notifies us the content in clipboard is selected.
+  */
+  static Eina_Bool EcoreEventDataSend( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventDataSend\n" );
+
+    Dali::Clipboard clipboard = Clipboard::Get();
+    if ( clipboard )
+    {
+      Clipboard& clipBoardImpl( GetImplementation( clipboard ) );
+      clipBoardImpl.ExcuteBuffered( true, event );
+    }
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+   /**
+    * Called when the source window sends us about the selected content.
+    * For example, when item is selected in the clipboard.
+    */
+   static Eina_Bool EcoreEventDataReceive( void* data, int type, void* event )
+   {
+     DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventDataReceive\n" );
+
+     EventHandler* handler( (EventHandler*)data );
+      Dali::Clipboard clipboard = Clipboard::Get();
+      char *selectionData = NULL;
+      if ( clipboard )
+      {
+        Clipboard& clipBoardImpl( GetImplementation( clipboard ) );
+        selectionData = clipBoardImpl.ExcuteBuffered( false, event );
+      }
+      if ( selectionData && handler->mClipboardEventNotifier )
+      {
+        ClipboardEventNotifier& clipboardEventNotifier( ClipboardEventNotifier::GetImplementation( handler->mClipboardEventNotifier ) );
+        std::string content( selectionData, strlen(selectionData) );
+
+        clipboardEventNotifier.SetContent( content );
+        clipboardEventNotifier.EmitContentSelectedSignal();
+      }
+     return ECORE_CALLBACK_PASS_ON;
+   }
+
+  /*
+  * Called when rotate event is recevied
+  */
+  static Eina_Bool EcoreEventRotate( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO( gSelectionEventLogFilter, Debug::Concise, "EcoreEventRotate\n" );
+
+    EventHandler* handler( (EventHandler*)data );
+    Ecore_Wl_Event_Window_Rotate* ev( (Ecore_Wl_Event_Window_Rotate*)event );
+
+    if( ev->win != (unsigned int)ecore_wl_window_id_get( handler->mImpl->mWindow ) )
+    {
+      return ECORE_CALLBACK_PASS_ON;
+    }
+
+    RotationEvent rotationEvent;
+    rotationEvent.angle = ev->angle;
+    rotationEvent.winResize = 0;
+    rotationEvent.width = ev->w;
+    rotationEvent.height = ev->h;
+    handler->SendRotationPrepareEvent( rotationEvent );
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /*
+  * Called when detent event is recevied
+  */
+  static Eina_Bool EcoreEventDetent( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventDetent\n" );
+    EventHandler* handler( (EventHandler*)data );
+    Ecore_Event_Detent_Rotate *e((Ecore_Event_Detent_Rotate *)event);
+    int direction = (e->direction == ECORE_DETENT_DIRECTION_CLOCKWISE) ? 1 : -1;
+    int timeStamp = e->timestamp;
+
+    WheelEvent wheelEvent( WheelEvent::CUSTOM_WHEEL, 0, 0, Vector2(0.0f, 0.0f), direction, timeStamp );
+    handler->SendWheelEvent( wheelEvent );
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Font Callbacks
   /////////////////////////////////////////////////////////////////////////////////////////////////
@@ -674,10 +1118,13 @@ struct EventHandler::Impl
   EventHandler* mHandler;
   std::vector<Ecore_Event_Handler*> mEcoreEventHandler;
   Ecore_Wl_Window* mWindow;
+#ifdef DALI_ELDBUS_AVAILABLE
+  Eldbus_Connection* mSystemConnection;
+#endif // DALI_ELDBUS_AVAILABLE
 };
 
 EventHandler::EventHandler( RenderSurface* surface, CoreEventInterface& coreEventInterface, GestureManager& gestureManager, DamageObserver& damageObserver, DragAndDropDetectorPtr dndDetector )
-: mCoreEventInterface(coreEventInterface),
+: mCoreEventInterface( coreEventInterface ),
   mGestureManager( gestureManager ),
   mStyleMonitor( StyleMonitor::Get() ),
   mDamageObserver( damageObserver ),
@@ -685,8 +1132,9 @@ EventHandler::EventHandler( RenderSurface* surface, CoreEventInterface& coreEven
   mDragAndDropDetector( dndDetector ),
   mAccessibilityAdaptor( AccessibilityAdaptor::Get() ),
   mClipboardEventNotifier( ClipboardEventNotifier::Get() ),
-  mClipboard(Clipboard::Get()),
-  mImpl( NULL )
+  mClipboard( Clipboard::Get() ),
+  mImpl( NULL ),
+  mPaused( false )
 {
   Ecore_Wl_Window* window = 0;
 
@@ -722,7 +1170,7 @@ void EventHandler::SendEvent(Integration::Point& point, unsigned long timeStamp)
   Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent(point, timeStamp, touchEvent, hoverEvent);
   if(type != Integration::TouchEventCombiner::DispatchNone )
   {
-    DALI_LOG_INFO(gTouchEventLogFilter, Debug::General, "%d: Device %d: Button state %d (%.2f, %.2f)\n", timeStamp, point.deviceId, point.state, point.local.x, point.local.y);
+    DALI_LOG_INFO(gTouchEventLogFilter, Debug::General, "%d: Device %d: Button state %d (%.2f, %.2f)\n", timeStamp, point.GetDeviceId(), point.GetState(), point.GetLocalPosition().x, point.GetLocalPosition().y);
 
     // First the touch and/or hover event & related gesture events are queued
     if(type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth)
@@ -783,15 +1231,13 @@ void EventHandler::SendRotationPrepareEvent( const RotationEvent& event )
   if( mRotationObserver != NULL )
   {
     mRotationObserver->OnRotationPrepare( event );
+    mRotationObserver->OnRotationRequest();
   }
 }
 
 void EventHandler::SendRotationRequestEvent( )
 {
-  if( mRotationObserver != NULL )
-  {
-    mRotationObserver->OnRotationRequest( );
-  }
+  // No need to separate event into prepare and request in wayland
 }
 
 void EventHandler::FeedTouchPoint( TouchPoint& point, int timeStamp)