#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/internal/system/common/locale-utils.h>
-#include <dali/internal/system/common/singleton-service-impl.h>
#include <dali/public-api/adaptor-framework/input-method.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
#include <dali/internal/input/common/key-impl.h>
+#include <dali/internal/system/common/locale-utils.h>
#include <dali/internal/window-system/common/window-render-surface.h>
#define TOKEN_STRING(x) #x
Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
#endif
+const int kUninitializedWindowId = 0;
+
// Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
size_t Utf8SequenceLength(const unsigned char leadByte)
{
}
}
+int GetWindowIdFromActor( Dali::Actor actor )
+{
+ int windowId = kUninitializedWindowId;
+
+ if( actor.OnStage() )
+ {
+ Any nativeWindowHandle = Dali::Integration::SceneHolder::Get( actor ).GetNativeHandle();
+
+#ifdef ECORE_WAYLAND2
+ windowId = ecore_wl2_window_id_get( AnyCast< Ecore_Wl2_Window* >( nativeWindowHandle ) );
+#else
+ windowId = ecore_wl_window_id_get( AnyCast< Ecore_Wl_Window* >( nativeWindowHandle ) );
+#endif
+ }
+
+ return windowId;
+}
+
BaseHandle Create()
{
- return Dali::InputMethodContext::New();
+ return Dali::InputMethodContext::New( Dali::Actor() );
}
Dali::TypeRegistration type( typeid(Dali::InputMethodContext), typeid(Dali::BaseHandle), Create );
} // unnamed namespace
-InputMethodContextPtr InputMethodContextEcoreWl::New()
+InputMethodContextPtr InputMethodContextEcoreWl::New( Dali::Actor actor )
{
InputMethodContextPtr inputMethodContext;
- // Create instance only if the adaptor is available
- if ( Dali::Adaptor::IsAvailable() )
+ // Create instance only if the adaptor is available and the valid actor exists
+ if ( actor && Dali::Adaptor::IsAvailable() )
{
- Any nativeWindow = Dali::Adaptor::Get().GetNativeWindowHandle();
-
- // The window needs to use the InputMethodContext.
- if( !nativeWindow.Empty() )
- {
- inputMethodContext = new InputMethodContextEcoreWl();
- }
- else
- {
- DALI_LOG_ERROR("Failed to get native window handle, can't create InputMethodContext instance.\n");
- }
+ inputMethodContext = new InputMethodContextEcoreWl( actor );
}
return inputMethodContext;
}
DeleteContext();
}
-InputMethodContextEcoreWl::InputMethodContextEcoreWl()
+InputMethodContextEcoreWl::InputMethodContextEcoreWl( Dali::Actor actor )
: mIMFContext(),
mIMFCursorPosition( 0 ),
mSurroundingText(),
mRestoreAfterFocusLost( false ),
- mIdleCallbackConnected( false )
+ mIdleCallbackConnected( false ),
+ mWindowId( GetWindowIdFromActor( actor ) )
{
ecore_imf_init();
+
+ actor.OnStageSignal().Connect( this, &InputMethodContextEcoreWl::OnStaged );
}
InputMethodContextEcoreWl::~InputMethodContextEcoreWl()
{
CreateContext();
ConnectCallbacks();
+ ApplyBackupOperations();
}
void InputMethodContextEcoreWl::CreateContext()
{
DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::CreateContext\n" );
+ if( mWindowId == kUninitializedWindowId )
+ {
+ return;
+ }
+
const char *contextId = ecore_imf_context_default_id_get();
if( contextId )
{
if( mIMFContext )
{
- // If we fail to get window id, we can't use the InputMethodContext correctly.
- // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
-
- Any nativeWindowHandle = Dali::Adaptor::Get().GetNativeWindowHandle();
-
-#ifdef ECORE_WAYLAND2
- int windowId = ecore_wl2_window_id_get( AnyCast< Ecore_Wl2_Window* >( nativeWindowHandle ) );
-#else
- int windowId = ecore_wl_window_id_get( AnyCast< Ecore_Wl_Window* >( nativeWindowHandle ) );
-#endif
-
- if( windowId != 0 )
- {
- ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast< void* >( windowId ) );
- }
+ ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast< void* >( mWindowId ) );
}
else
{
- DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
+ DALI_LOG_WARNING( "InputMethodContext Unable to get IMFContext\n" );
}
}
else
{
- DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
+ DALI_LOG_WARNING( "InputMethodContext Unable to get IMFContext\n" );
}
}
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 );
// 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 )
{
- // 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 = 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
- }
+ data.startIndex = visualCharacterIndex;
+ }
+ if ( byteIndex >= attr->end_index )
+ {
+ 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
+ }
+ }
- DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
+ 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 );
}
}
if( callbackData.update )
{
+ if( cursorPosition )
+ {
+ mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
+ *cursorPosition = mIMFCursorPosition;
+ }
+
if( text )
{
const char* plainText = callbackData.currentText.c_str();
+
if( plainText )
{
+ // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
+ *text = strdup( plainText );
+
// If the current input panel is password mode, dali should replace the plain text with '*' (Asterisk) character.
- if( ecore_imf_context_input_hint_get( mIMFContext ) & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA )
+ if( ( ecore_imf_context_input_hint_get( mIMFContext ) & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA ) && *text )
{
- char* iter = NULL;
- for( iter = const_cast<char*>( plainText ); iter && *iter; ++iter )
+ for( char* iter = *text; *iter; ++iter )
{
*iter = '*';
}
}
- }
- // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
- *text = strdup( plainText );
- }
- if( cursorPosition )
- {
- mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
- *cursorPosition = mIMFCursorPosition;
+ return EINA_TRUE;
+ }
}
}
- return EINA_TRUE;
+ return EINA_FALSE;
}
/**
void InputMethodContextEcoreWl::NotifyTextInputMultiLine( bool multiLine )
{
- Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
- ecore_imf_context_input_hint_set( mIMFContext,
- static_cast< Ecore_IMF_Input_Hints >( multiLine ?
- (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) :
- (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
+ if( mIMFContext )
+ {
+ Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
+ ecore_imf_context_input_hint_set( mIMFContext,
+ static_cast< Ecore_IMF_Input_Hints >( multiLine ?
+ (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) :
+ (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
+ }
+
+ mBackupOperations[Operation::NOTIFY_TEXT_INPUT_MULTILINE] = std::bind( &InputMethodContextEcoreWl::NotifyTextInputMultiLine, this, multiLine );
}
Dali::InputMethodContext::TextDirection InputMethodContextEcoreWl::GetTextDirection()
int length = data.length();
ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
}
+
+ mBackupOperations[Operation::SET_INPUT_PANEL_DATA] = std::bind( &InputMethodContextEcoreWl::SetInputPanelData, this, data );
}
void InputMethodContextEcoreWl::GetInputPanelData( std::string& data )
{
ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
}
+
+ mBackupOperations[Operation::SET_RETURN_KEY_STATE] = std::bind( &InputMethodContextEcoreWl::SetReturnKeyState, this, visible );
}
void InputMethodContextEcoreWl::AutoEnableInputPanel( bool enabled )
{
ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
}
+
+ mBackupOperations[Operation::AUTO_ENABLE_INPUT_PANEL] = std::bind( &InputMethodContextEcoreWl::AutoEnableInputPanel, this, enabled );
}
void InputMethodContextEcoreWl::ShowInputPanel()
{
ecore_imf_context_mime_type_accept_set( mIMFContext, mimeTypes.c_str() );
}
+
+ mBackupOperations[Operation::SET_CONTENT_MIME_TYPES] = std::bind( &InputMethodContextEcoreWl::SetContentMIMETypes, this, mimeTypes );
}
bool InputMethodContextEcoreWl::FilterEventKey( const Dali::KeyEvent& keyEvent )
{
ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
}
+
+ mBackupOperations[Operation::ALLOW_TEXT_PREDICTION] = std::bind( &InputMethodContextEcoreWl::AllowTextPrediction, this, prediction );
}
bool InputMethodContextEcoreWl::IsTextPredictionAllowed() const
}
}
}
+
+ mBackupOperations[Operation::SET_INPUT_PANEL_LANGUAGE] = std::bind( &InputMethodContextEcoreWl::SetInputPanelLanguage, this, language );
}
Dali::InputMethodContext::InputPanelLanguage InputMethodContextEcoreWl::GetInputPanelLanguage() const
return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
}
+void InputMethodContextEcoreWl::SetInputPanelPosition( unsigned int x, unsigned int y )
+{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelPosition\n" );
+
+ if( mIMFContext )
+ {
+ ecore_imf_context_input_panel_position_set( mIMFContext, x, y );
+ }
+
+ mBackupOperations[Operation::SET_INPUT_PANEL_POSITION] = std::bind( &InputMethodContextEcoreWl::SetInputPanelPosition, this, x, y );
+}
+
+void InputMethodContextEcoreWl::GetPreeditStyle( Vector< Dali::InputMethodContext::PreeditAttributeData >& attrs ) const
+{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetPreeditStyle\n" );
+ attrs = mPreeditAttrs;
+}
+
bool InputMethodContextEcoreWl::ProcessEventKeyDown( const KeyEvent& keyEvent )
{
bool eventHandled( false );
ecoreKeyDownEvent.dev_name = deviceName.c_str();
ecoreKeyDownEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
ecoreKeyDownEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
+#if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
+ ecoreKeyDownEvent.keycode = keyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
+#endif // Since ecore_imf 1.22 version
// 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)) ||
ecoreKeyUpEvent.dev_name = deviceName.c_str();
ecoreKeyUpEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
ecoreKeyUpEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
+#if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
+ ecoreKeyUpEvent.keycode = keyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
+#endif // Since ecore_imf 1.22 version
eventHandled = ecore_imf_context_filter_event(mIMFContext,
ECORE_IMF_EVENT_KEY_UP,
return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
}
+void InputMethodContextEcoreWl::OnStaged( Dali::Actor actor )
+{
+ int windowId = GetWindowIdFromActor( actor );
+
+ if( mWindowId != windowId )
+ {
+ mWindowId = windowId;
+
+ // Reset
+ Finalize();
+ Initialize();
+ }
+}
+
} // Adaptor
} // Internal