Moved SingletonService into dali-core
[platform/core/uifw/dali-adaptor.git] / dali / internal / input / ubuntu-x11 / input-method-context-impl-x.cpp
index add026d..7101b58 100755 (executable)
 #include <dali/internal/input/ubuntu-x11/input-method-context-impl-x.h>
 
 // EXTERNAL INCLUDES
-#include <dali/internal/input/linux/dali-ecore-imf.h>
-#include <dali/internal/input/ubuntu-x11/dali-ecore-input.h>
 #include <dali/public-api/events/key-event.h>
-#include <dali/public-api/adaptor-framework/key.h>
 #include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
-#include <dali/integration-api/adaptor.h>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/internal/adaptor/common/adaptor-impl.h>
-#include <dali/internal/system/common/locale-utils.h>
-#include <dali/internal/system/common/singleton-service-impl.h>
-#include <dali/internal/input/common/virtual-keyboard-impl.h>
 #include <dali/internal/input/common/key-impl.h>
+#include <dali/internal/input/common/virtual-keyboard-impl.h>
+#include <dali/internal/input/linux/dali-ecore-imf.h>
 #include <dali/internal/input/tizen-wayland/ecore-virtual-keyboard.h>
+#include <dali/internal/input/ubuntu-x11/dali-ecore-input.h>
+#include <dali/internal/system/common/locale-utils.h>
+#include <dali/internal/system/linux/dali-ecore.h>
 
 namespace Dali
 {
@@ -76,21 +77,21 @@ size_t Utf8SequenceLength(const unsigned char leadByte)
 }
 
 // Static function calls used by ecore 'c' style callback registration
-void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
+void Commit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
 {
   if ( data )
   {
-    InputMethodContextX* inputMethodContext = reinterpret_cast< InputMethodContextX* > ( data );
-    inputMethodContext->CommitReceived( data, imfContext, event_info );
+    InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
+    inputMethodContext->CommitReceived( data, imfContext, eventInfo );
   }
 }
 
-void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
+void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
 {
   if ( data )
   {
-    InputMethodContextX* inputMethodContext = reinterpret_cast< InputMethodContextX* > ( data );
-    inputMethodContext->PreEditChanged( data, imfContext, event_info );
+    InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
+    inputMethodContext->PreEditChanged( data, imfContext, eventInfo );
   }
 }
 
@@ -98,7 +99,7 @@ Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char
 {
   if ( data )
   {
-    InputMethodContextX* inputMethodContext = reinterpret_cast< InputMethodContextX* > ( data );
+    InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
     return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
   }
   else
@@ -111,42 +112,24 @@ Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char
  * Called when an InputMethodContext delete surrounding event is received.
  * Here we tell the application that it should delete a certain range.
  */
-void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
+void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
 {
   if ( data )
   {
-    InputMethodContextX* inputMethodContext = reinterpret_cast< InputMethodContextX* > ( data );
-    inputMethodContext->DeleteSurrounding( data, imfContext, event_info );
+    InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
+    inputMethodContext->DeleteSurrounding( data, imfContext, eventInfo );
   }
 }
 
 } // unnamed namespace
 
-InputMethodContextPtr InputMethodContextX::New()
+InputMethodContextPtr InputMethodContextX::New( Dali::Actor actor )
 {
   InputMethodContextPtr manager;
 
-  if ( Adaptor::IsAvailable() )
+  if( actor && Dali::Adaptor::IsAvailable() )
   {
-    // Create instance and register singleton only if the adaptor is available
-    Adaptor& adaptorImpl( Adaptor::GetImplementation( Adaptor::Get() ) );
-    Any nativeWindow = adaptorImpl.GetNativeWindowHandle();
-
-    // The Ecore_X_Window needs to use the InputMethodContext.
-    // Only when the render surface is window, we can get the Ecore_X_Window.
-    Ecore_X_Window ecoreXwin( AnyCast<Ecore_X_Window>(nativeWindow) );
-    if (ecoreXwin)
-    {
-      // If we fail to get Ecore_X_Window, we can't use the InputMethodContext correctly.
-      // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
-      // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
-
-      manager = new InputMethodContextX( ecoreXwin );
-    }
-    else
-    {
-      DALI_LOG_ERROR("Failed to get native window handle\n");
-    }
+    manager = new InputMethodContextX( actor );
   }
 
   return manager;
@@ -160,15 +143,17 @@ void InputMethodContextX::Finalize()
   DeleteContext();
 }
 
-InputMethodContextX::InputMethodContextX( Ecore_X_Window ecoreXwin )
+InputMethodContextX::InputMethodContextX( Dali::Actor actor )
 : mIMFContext(),
-  mEcoreXwin( ecoreXwin ),
+  mEcoreXwin( 0 ),
   mIMFCursorPosition( 0 ),
   mSurroundingText(),
   mRestoreAfterFocusLost( false ),
   mIdleCallbackConnected( false )
 {
   ecore_imf_init();
+
+  actor.OnStageSignal().Connect( this, &InputMethodContextX::OnStaged );
 }
 
 InputMethodContextX::~InputMethodContextX()
@@ -179,15 +164,20 @@ InputMethodContextX::~InputMethodContextX()
 
 void InputMethodContextX::Initialize()
 {
-  CreateContext( mEcoreXwin );
+  CreateContext();
   ConnectCallbacks();
   VirtualKeyboard::ConnectCallbacks( mIMFContext );
 }
 
-void InputMethodContextX::CreateContext( Ecore_X_Window ecoreXwin )
+void InputMethodContextX::CreateContext()
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CreateContext\n" );
 
+  if( !mEcoreXwin )
+  {
+    return;
+  }
+
   const char *contextId = ecore_imf_context_default_id_get();
   if( contextId )
   {
@@ -195,10 +185,7 @@ void InputMethodContextX::CreateContext( Ecore_X_Window ecoreXwin )
 
     if( mIMFContext )
     {
-      if( ecoreXwin )
-      {
-        ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast<void*>( ecoreXwin ) );
-      }
+      ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast<void*>( mEcoreXwin ) );
     }
     else
     {
@@ -314,10 +301,10 @@ void InputMethodContextX::SetRestoreAfterFocusLost( bool toggle )
  * We are still predicting what the user is typing.  The latest string is what the InputMethodContext module thinks
  * the user wants to type.
  */
-void InputMethodContextX::PreEditChanged( void*, ImfContext* imfContext, void* event_info )
+void InputMethodContextX::PreEditChanged( void*, ImfContext* imfContext, void* eventInfo )
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::PreEditChanged\n" );
-  auto context = reinterpret_cast<Ecore_IMF_Context*>(imfContext);
+  auto context = static_cast<Ecore_IMF_Context*>( imfContext );
 
   char* preEditString( NULL );
   int cursorPosition( 0 );
@@ -326,6 +313,8 @@ void InputMethodContextX::PreEditChanged( void*, ImfContext* imfContext, void* e
 
   Ecore_IMF_Preedit_Attr* attr;
 
+  mPreeditAttrs.Clear();
+
   // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
   // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
   ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
@@ -335,38 +324,85 @@ void InputMethodContextX::PreEditChanged( void*, ImfContext* imfContext, void* e
     // iterate through the list of attributes getting the type, start and end position.
     for ( l = attrs, (attr =  static_cast<Ecore_IMF_Preedit_Attr*>( eina_list_data_get(l) ) ); l; l = eina_list_next(l), ( attr = static_cast<Ecore_IMF_Preedit_Attr*>( eina_list_data_get(l) ) ))
     {
-#ifdef DALI_PROFILE_UBUNTU
-      if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
-#else // DALI_PROFILE_UBUNTU
-      if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
-#endif // DALI_PROFILE_UBUNTU
-      {
-        // check first byte so know how many bytes a character is represented by as keyboard returns cursor position in bytes. Which is different for some languages.
+      Dali::InputMethodContext::PreeditAttributeData data;
+      data.startIndex = 0;
+      data.endIndex = 0;
 
-        size_t visualCharacterIndex = 0;
-        size_t byteIndex = 0;
+      size_t visualCharacterIndex = 0;
+      size_t byteIndex = 0;
 
-        // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
-        const char leadByte = preEditString[byteIndex];
-        while( leadByte != '\0' )
+      // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
+      const char leadByte = preEditString[byteIndex];
+      while( leadByte != '\0' )
+      {
+        // attr->end_index is provided as a byte position not character and we need to know the character position.
+        const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
+        if( byteIndex <= attr->start_index )
+        {
+           data.startIndex = visualCharacterIndex;
+        }
+        if ( byteIndex >= attr->end_index )
         {
-          // attr->end_index is provided as a byte position not character and we need to know the character position.
-          const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
-          if ( byteIndex == attr->end_index )
-          {
-            cursorPosition = static_cast<int>( visualCharacterIndex );
-            break;
-            // end loop as found cursor position that matches byte position
-          }
-          else
-          {
-            byteIndex += currentSequenceLength; // jump to next character
-            visualCharacterIndex++;  // increment character count so we know our position for when we get a match
-          }
-
-          DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
+          data.endIndex = visualCharacterIndex;
+          break;
+          // end loop as found cursor position that matches byte position
+        }
+        else
+        {
+          byteIndex += currentSequenceLength; // jump to next character
+          visualCharacterIndex++;  // increment character count so we know our position for when we get a match
         }
       }
+
+      switch( attr->preedit_type )
+      {
+        case ECORE_IMF_PREEDIT_TYPE_NONE:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB1:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::UNDERLINE;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB2:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::REVERSE;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB3:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::HIGHLIGHT;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB4:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB5:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB6:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB7:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4;
+          break;
+        }
+        default:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
+          break;
+        }
+      }
+      mPreeditAttrs.PushBack( data );
     }
   }
 
@@ -391,13 +427,13 @@ void InputMethodContextX::PreEditChanged( void*, ImfContext* imfContext, void* e
   free( preEditString );
 }
 
-void InputMethodContextX::CommitReceived( void*, ImfContext* imfContext, void* event_info )
+void InputMethodContextX::CommitReceived( void*, ImfContext* imfContext, void* eventInfo )
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CommitReceived\n" );
 
   if ( Dali::Adaptor::IsAvailable() )
   {
-    const std::string keyString( static_cast<char*>( event_info ) );
+    const std::string keyString( static_cast<char*>( eventInfo ) );
 
     Dali::InputMethodContext handle( this );
     Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
@@ -446,13 +482,13 @@ bool InputMethodContextX::RetrieveSurrounding( void* data, ImfContext* imfContex
  * Called when an InputMethodContext delete surrounding event is received.
  * Here we tell the application that it should delete a certain range.
  */
-void InputMethodContextX::DeleteSurrounding( void* data, ImfContext* imfContext, void* event_info )
+void InputMethodContextX::DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo )
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DeleteSurrounding\n" );
 
   if( Dali::Adaptor::IsAvailable() )
   {
-    Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( event_info );
+    Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( eventInfo );
 
     Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
     Dali::InputMethodContext handle( this );
@@ -703,6 +739,12 @@ std::string InputMethodContextX::GetInputPanelLocale()
   return locale;
 }
 
+void InputMethodContextX::SetContentMIMETypes( const std::string& mimeTypes )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetContentMIMETypes\n" );
+  // ecore_imf_context_mime_type_accept_set() is supported from ecore-imf 1.20.0 version.
+}
+
 bool InputMethodContextX::FilterEventKey( const Dali::KeyEvent& keyEvent )
 {
   bool eventHandled( false );
@@ -745,6 +787,65 @@ bool InputMethodContextX::IsTextPredictionAllowed() const
   return prediction;
 }
 
+void InputMethodContextX::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelLanguage\n" );
+  if( mIMFContext )
+  {
+    switch (language)
+    {
+      case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
+      {
+        ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC );
+        break;
+      }
+      case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
+      {
+        ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET );
+        break;
+      }
+    }
+  }
+}
+
+Dali::InputMethodContext::InputPanelLanguage InputMethodContextX::GetInputPanelLanguage() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLanguage\n" );
+  if( mIMFContext )
+  {
+    int value;
+    value =  ecore_imf_context_input_panel_language_get( mIMFContext );
+
+    switch (value)
+    {
+      case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
+      {
+        return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
+        break;
+      }
+      case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
+      {
+        return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
+        break;
+      }
+    }
+  }
+  return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
+}
+
+void InputMethodContextX::SetInputPanelPosition( unsigned int x, unsigned int y )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelPosition\n" );
+
+  // ecore_imf_context_input_panel_position_set() is supported from ecore-imf 1.21.0 version.
+}
+
+void InputMethodContextX::GetPreeditStyle( Vector< Dali::InputMethodContext::PreeditAttributeData >& attrs ) const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetPreeditStyle\n" );
+  attrs = mPreeditAttrs;
+}
+
 bool InputMethodContextX::ProcessEventKeyDown( const KeyEvent& keyEvent )
 {
   bool eventHandled( false );
@@ -764,11 +865,17 @@ bool InputMethodContextX::ProcessEventKeyDown( const KeyEvent& keyEvent )
     ecoreKeyDownEvent.timestamp = keyEvent.time;
     ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
     ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
-#ifdef ECORE_IMF_1_13
+
+#if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
+#if (ECORE_VERSION_MINOR >= 14)
     ecoreKeyDownEvent.dev_name  = "";
     ecoreKeyDownEvent.dev_class = ECORE_IMF_DEVICE_CLASS_KEYBOARD;
     ecoreKeyDownEvent.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
-#endif // ECORE_IMF_1_13
+#endif // Since ecore_imf 1.14 version
+#if (ECORE_VERSION_MINOR >= 22)
+    ecoreKeyDownEvent.keycode = keyEvent.keyCode;
+#endif // Since ecore_imf 1.22 version
+#endif // Since ecore_imf Version 1
 
     // If the device is IME and the focused key is the direction keys, then we should send a key event to move a key cursor.
     if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
@@ -818,9 +925,14 @@ bool InputMethodContextX::ProcessEventKeyUp( const KeyEvent& keyEvent )
     ecoreKeyUpEvent.timestamp = keyEvent.time;
     ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
     ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
-#ifdef ECORE_IMF_1_13
+#if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
+#if (ECORE_VERSION_MINOR >= 14)
     ecoreKeyUpEvent.dev_name  = "";
-#endif // ECORE_IMF_1_13
+#endif // Since ecore_imf 1.14 version
+#if (ECORE_VERSION_MINOR >= 22)
+    ecoreKeyUpEvent.keycode = keyEvent.keyCode;
+#endif // Since ecore_imf 1.22 version
+#endif // Since ecore_imf Version 1
 
     eventHandled = ecore_imf_context_filter_event(mIMFContext,
                                                   ECORE_IMF_EVENT_KEY_UP,
@@ -883,6 +995,20 @@ Ecore_IMF_Keyboard_Locks InputMethodContextX::EcoreInputModifierToEcoreIMFLock(
     return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
 }
 
+void InputMethodContextX::OnStaged( Dali::Actor actor )
+{
+  Ecore_X_Window ecoreXwin( AnyCast< Ecore_X_Window >( Dali::Integration::SceneHolder::Get( actor ).GetNativeHandle() ) );
+
+  if( mEcoreXwin != ecoreXwin )
+  {
+    mEcoreXwin = ecoreXwin;
+
+    // Reset
+    Finalize();
+    Initialize();
+  }
+}
+
 } // Adaptor
 
 } // Internal