/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <dali/internal/input/ubuntu-x11/input-method-context-impl-x.h>
// EXTERNAL INCLUDES
-#include <Ecore_IMF.h>
-#include <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/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>
-// Ecore is littered with C style cast
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
+#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/common/singleton-service-impl.h>
+#include <dali/internal/system/linux/dali-ecore.h>
namespace Dali
{
{
size_t length = 0;
- if ((leadByte & 0x80) == 0 ) //ASCII character (lead bit zero)
+ if( ( leadByte & 0x80 ) == 0 ) //ASCII character (lead bit zero)
{
length = 1;
}
- else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
+ else if( ( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
{
length = 2;
}
- else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
+ else if( ( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
{
length = 3;
}
- else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
+ else if( ( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
{
length = 4;
}
+ else if( ( leadByte & 0xfc ) == 0xf8 ) //1111 10xx
+ {
+ length = 5;
+ }
+ else if( ( leadByte & 0xfe ) == 0xfc ) //1111 110x
+ {
+ length = 6;
+ }
return length;
}
// 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 );
}
}
{
if ( data )
{
- InputMethodContextX* inputMethodContext = reinterpret_cast< InputMethodContextX* > ( data );
+ InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
}
else
* 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;
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()
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 )
{
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
{
* 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 );
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
+ Dali::InputMethodContext::PreeditAttributeData data;
+ data.startIndex = 0;
+ data.endIndex = 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 ).
+ char leadByte = preEditString[byteIndex];
+
+ while( leadByte != '\0' )
{
- // 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.
+ leadByte = preEditString[byteIndex]; // Update the character to get the number of its byte
- size_t visualCharacterIndex = 0;
- size_t byteIndex = 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 )
+ {
+ 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
+ }
+ }
- // 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' )
+ 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:
{
- // 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
- }
-
- DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
+ data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
+ break;
}
}
+ mPreeditAttrs.PushBack( data );
}
}
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 );
* 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 );
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 );
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( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const
+{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetPreeditStyle\n" );
+ attrs = mPreeditAttrs;
+}
+
bool InputMethodContextX::ProcessEventKeyDown( const KeyEvent& keyEvent )
{
bool eventHandled( false );
if ( mIMFContext )
{
+ Integration::KeyEvent integKeyEvent( keyEvent );
+ std::string key = integKeyEvent.logicalKey;
+
std::string compose = keyEvent.GetCompose();
// We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
- ecoreKeyDownEvent.key = keyEvent.keyPressedName.c_str();
+ ecoreKeyDownEvent.key = key.c_str();
ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
ecoreKeyDownEvent.compose = compose.c_str();
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)) ||
{
eventHandled = ecore_imf_context_filter_event(mIMFContext,
ECORE_IMF_EVENT_KEY_DOWN,
- (Ecore_IMF_Event *) &ecoreKeyDownEvent);
+ reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ));
}
// If the event has not been handled by InputMethodContext then check if we should reset our IMFcontext
bool eventHandled( false );
if( mIMFContext )
{
+ Integration::KeyEvent integKeyEvent( keyEvent );
+ std::string key = integKeyEvent.logicalKey;
+
std::string compose = keyEvent.GetCompose();
// We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
- ecoreKeyUpEvent.key = keyEvent.keyPressedName.c_str();
+ ecoreKeyUpEvent.key = key.c_str();
ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
ecoreKeyUpEvent.compose = compose.c_str();
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,
- (Ecore_IMF_Event *) &ecoreKeyUpEvent);
+ reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ));
}
return eventHandled;
}
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
} // Dali
-
-#pragma GCC diagnostic pop