2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/input/ubuntu-x11/input-method-context-impl-x.h>
22 #include <dali/internal/input/linux/dali-ecore-imf.h>
23 #include <dali/internal/input/ubuntu-x11/dali-ecore-input.h>
24 #include <dali/public-api/events/key-event.h>
25 #include <dali/public-api/adaptor-framework/key.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/integration-api/debug.h>
30 #include <dali/integration-api/adaptor.h>
31 #include <dali/internal/adaptor/common/adaptor-impl.h>
32 #include <dali/internal/system/common/locale-utils.h>
33 #include <dali/internal/system/common/singleton-service-impl.h>
34 #include <dali/internal/input/common/virtual-keyboard-impl.h>
35 #include <dali/internal/input/common/key-impl.h>
36 #include <dali/internal/input/tizen-wayland/ecore-virtual-keyboard.h>
49 #if defined(DEBUG_ENABLED)
50 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
53 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
54 size_t Utf8SequenceLength(const unsigned char leadByte)
58 if ((leadByte & 0x80) == 0 ) //ASCII character (lead bit zero)
62 else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
66 else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
70 else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
78 // Static function calls used by ecore 'c' style callback registration
79 void Commit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
83 InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
84 inputMethodContext->CommitReceived( data, imfContext, eventInfo );
88 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
92 InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
93 inputMethodContext->PreEditChanged( data, imfContext, eventInfo );
97 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
101 InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
102 return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
111 * Called when an InputMethodContext delete surrounding event is received.
112 * Here we tell the application that it should delete a certain range.
114 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
118 InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
119 inputMethodContext->DeleteSurrounding( data, imfContext, eventInfo );
123 } // unnamed namespace
125 InputMethodContextPtr InputMethodContextX::New( Dali::Actor actor )
127 InputMethodContextPtr manager;
129 if( actor && Dali::Adaptor::IsAvailable() )
131 manager = new InputMethodContextX( actor );
137 void InputMethodContextX::Finalize()
139 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Finalize\n" );
140 VirtualKeyboard::DisconnectCallbacks( mIMFContext );
141 DisconnectCallbacks();
145 InputMethodContextX::InputMethodContextX( Dali::Actor actor )
148 mIMFCursorPosition( 0 ),
150 mRestoreAfterFocusLost( false ),
151 mIdleCallbackConnected( false )
155 actor.OnStageSignal().Connect( this, &InputMethodContextX::OnStaged );
158 InputMethodContextX::~InputMethodContextX()
161 ecore_imf_shutdown();
164 void InputMethodContextX::Initialize()
168 VirtualKeyboard::ConnectCallbacks( mIMFContext );
171 void InputMethodContextX::CreateContext()
173 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CreateContext\n" );
180 const char *contextId = ecore_imf_context_default_id_get();
183 mIMFContext = ecore_imf_context_add( contextId );
187 ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast<void*>( mEcoreXwin ) );
191 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
196 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
200 void InputMethodContextX::DeleteContext()
202 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DeleteContext\n" );
206 ecore_imf_context_del( mIMFContext );
211 // Callbacks for predicitive text support.
212 void InputMethodContextX::ConnectCallbacks()
216 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::ConnectCallbacks\n" );
218 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit, this );
219 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit, this );
220 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
222 ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
226 void InputMethodContextX::DisconnectCallbacks()
230 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DisconnectCallbacks\n" );
232 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit );
233 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit );
234 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
236 // We do not need to unset the retrieve surrounding callback.
240 void InputMethodContextX::Activate()
242 // Reset mIdleCallbackConnected
243 mIdleCallbackConnected = false;
247 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Activate\n" );
249 ecore_imf_context_focus_in( mIMFContext );
251 // emit keyboard activated signal
252 Dali::InputMethodContext handle( this );
253 mActivatedSignal.Emit( handle );
257 void InputMethodContextX::Deactivate()
261 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Deactivate\n" );
264 ecore_imf_context_focus_out( mIMFContext );
267 // Reset mIdleCallbackConnected
268 mIdleCallbackConnected = false;
271 void InputMethodContextX::Reset()
273 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Reset\n" );
277 ecore_imf_context_reset( mIMFContext );
281 ImfContext* InputMethodContextX::GetContext()
283 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetContext\n" );
288 bool InputMethodContextX::RestoreAfterFocusLost() const
290 return mRestoreAfterFocusLost;
293 void InputMethodContextX::SetRestoreAfterFocusLost( bool toggle )
295 mRestoreAfterFocusLost = toggle;
299 * Called when an InputMethodContext Pre-Edit changed event is received.
300 * We are still predicting what the user is typing. The latest string is what the InputMethodContext module thinks
301 * the user wants to type.
303 void InputMethodContextX::PreEditChanged( void*, ImfContext* imfContext, void* eventInfo )
305 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::PreEditChanged\n" );
306 auto context = static_cast<Ecore_IMF_Context*>( imfContext );
308 char* preEditString( NULL );
309 int cursorPosition( 0 );
310 Eina_List* attrs = NULL;
313 Ecore_IMF_Preedit_Attr* attr;
315 // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
316 // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
317 ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
321 // iterate through the list of attributes getting the type, start and end position.
322 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) ) ))
324 #ifdef DALI_PROFILE_UBUNTU
325 if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
326 #else // DALI_PROFILE_UBUNTU
327 if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
328 #endif // DALI_PROFILE_UBUNTU
330 // 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.
332 size_t visualCharacterIndex = 0;
333 size_t byteIndex = 0;
335 // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
336 const char leadByte = preEditString[byteIndex];
337 while( leadByte != '\0' )
339 // attr->end_index is provided as a byte position not character and we need to know the character position.
340 const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
341 if ( byteIndex == attr->end_index )
343 cursorPosition = static_cast<int>( visualCharacterIndex );
345 // end loop as found cursor position that matches byte position
349 byteIndex += currentSequenceLength; // jump to next character
350 visualCharacterIndex++; // increment character count so we know our position for when we get a match
353 DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
359 if ( Dali::Adaptor::IsAvailable() )
361 Dali::InputMethodContext handle( this );
362 Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
363 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
365 if( callbackData.update )
367 mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
369 NotifyCursorPosition();
372 if( callbackData.preeditResetRequired )
377 free( preEditString );
380 void InputMethodContextX::CommitReceived( void*, ImfContext* imfContext, void* eventInfo )
382 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CommitReceived\n" );
384 if ( Dali::Adaptor::IsAvailable() )
386 const std::string keyString( static_cast<char*>( eventInfo ) );
388 Dali::InputMethodContext handle( this );
389 Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
390 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
392 if( callbackData.update )
394 mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
396 NotifyCursorPosition();
402 * Called when an InputMethodContext retrieve surround event is received.
403 * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
404 * We need to signal the application to tell us this information.
406 bool InputMethodContextX::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
408 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::RetrieveSurrounding\n" );
410 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
411 Dali::InputMethodContext handle( this );
412 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
414 if( callbackData.update )
418 *text = strdup( callbackData.currentText.c_str() );
423 mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
424 *cursorPosition = mIMFCursorPosition;
432 * Called when an InputMethodContext delete surrounding event is received.
433 * Here we tell the application that it should delete a certain range.
435 void InputMethodContextX::DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo )
437 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DeleteSurrounding\n" );
439 if( Dali::Adaptor::IsAvailable() )
441 Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( eventInfo );
443 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
444 Dali::InputMethodContext handle( this );
445 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
447 if( callbackData.update )
449 mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
451 NotifyCursorPosition();
456 void InputMethodContextX::NotifyCursorPosition()
458 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::NotifyCursorPosition\n" );
462 ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
466 void InputMethodContextX::SetCursorPosition( unsigned int cursorPosition )
468 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetCursorPosition\n" );
470 mIMFCursorPosition = static_cast<int>( cursorPosition );
473 unsigned int InputMethodContextX::GetCursorPosition() const
475 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetCursorPosition\n" );
477 return static_cast<unsigned int>( mIMFCursorPosition );
480 void InputMethodContextX::SetSurroundingText( const std::string& text )
482 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetSurroundingText\n" );
484 mSurroundingText = text;
487 const std::string& InputMethodContextX::GetSurroundingText() const
489 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetSurroundingText\n" );
491 return mSurroundingText;
494 void InputMethodContextX::NotifyTextInputMultiLine( bool multiLine )
498 Dali::InputMethodContext::TextDirection InputMethodContextX::GetTextDirection()
500 Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
504 char* locale( NULL );
505 ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
509 direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
517 Rect<int> InputMethodContextX::GetInputMethodArea()
519 int xPos, yPos, width, height;
521 width = height = xPos = yPos = 0;
525 ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
529 DALI_LOG_WARNING("VKB Unable to get InputMethodContext Context so GetSize unavailable\n");
532 return Rect<int>(xPos,yPos,width,height);
535 void InputMethodContextX::ApplyOptions( const InputMethodOptions& options )
537 using namespace Dali::InputMethod::Category;
541 if (mIMFContext == NULL)
543 DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
547 if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
550 if ( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
553 if ( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
556 if ( mOptions.CompareAndSet(VARIATION, options, index) )
561 void InputMethodContextX::SetInputPanelData( const std::string& data )
563 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelData\n" );
567 int length = data.length();
568 ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
572 void InputMethodContextX::GetInputPanelData( std::string& data )
574 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelData\n" );
578 int length = 4096; // The max length is 4096 bytes
579 Dali::Vector< char > buffer;
580 buffer.Resize( length );
581 ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
582 data = std::string( buffer.Begin(), buffer.End() );
586 Dali::InputMethodContext::State InputMethodContextX::GetInputPanelState()
588 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelState\n" );
593 value = ecore_imf_context_input_panel_state_get( mIMFContext );
597 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
599 return Dali::InputMethodContext::SHOW;
603 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
605 return Dali::InputMethodContext::HIDE;
609 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
611 return Dali::InputMethodContext::WILL_SHOW;
617 return Dali::InputMethodContext::DEFAULT;
621 return Dali::InputMethodContext::DEFAULT;
624 void InputMethodContextX::SetReturnKeyState( bool visible )
626 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetReturnKeyState\n" );
630 ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
634 void InputMethodContextX::AutoEnableInputPanel( bool enabled )
636 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::AutoEnableInputPanel\n" );
640 ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
644 void InputMethodContextX::ShowInputPanel()
646 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::ShowInputPanel\n" );
650 ecore_imf_context_input_panel_show( mIMFContext );
654 void InputMethodContextX::HideInputPanel()
656 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::HideInputPanel\n" );
660 ecore_imf_context_input_panel_hide( mIMFContext );
664 Dali::InputMethodContext::KeyboardType InputMethodContextX::GetKeyboardType()
666 return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
669 std::string InputMethodContextX::GetInputPanelLocale()
671 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLocale\n" );
673 std::string locale = "";
678 ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
682 std::string valueCopy( value );
685 // The locale string retrieved must be freed with free().
692 void InputMethodContextX::SetContentMIMETypes( const std::string& mimeTypes )
694 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetContentMIMETypes\n" );
695 // ecore_imf_context_mime_type_accept_set() is supported from ecore-imf 1.20.0 version.
698 bool InputMethodContextX::FilterEventKey( const Dali::KeyEvent& keyEvent )
700 bool eventHandled( false );
702 // If a device key then skip ecore_imf_context_filter_event.
703 if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))
705 //check whether it's key down or key up event
706 if ( keyEvent.state == KeyEvent::Down )
708 eventHandled = ProcessEventKeyDown( keyEvent );
710 else if ( keyEvent.state == KeyEvent::Up )
712 eventHandled = ProcessEventKeyUp( keyEvent );
719 void InputMethodContextX::AllowTextPrediction( bool prediction )
721 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::AllowTextPrediction\n" );
725 ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
729 bool InputMethodContextX::IsTextPredictionAllowed() const
731 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::IsTextPredictionAllowed\n" );
732 bool prediction = false;
735 prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
740 void InputMethodContextX::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
742 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelLanguage\n" );
747 case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
749 ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC );
752 case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
754 ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET );
761 Dali::InputMethodContext::InputPanelLanguage InputMethodContextX::GetInputPanelLanguage() const
763 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLanguage\n" );
767 value = ecore_imf_context_input_panel_language_get( mIMFContext );
771 case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
773 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
776 case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
778 return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
783 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
786 void InputMethodContextX::SetInputPanelPosition( unsigned int x, unsigned int y )
788 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelPosition\n" );
790 // ecore_imf_context_input_panel_position_set() is supported from ecore-imf 1.21.0 version.
793 bool InputMethodContextX::ProcessEventKeyDown( const KeyEvent& keyEvent )
795 bool eventHandled( false );
798 Integration::KeyEvent integKeyEvent( keyEvent );
799 std::string key = integKeyEvent.logicalKey;
801 std::string compose = keyEvent.GetCompose();
803 // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
804 Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
805 ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
806 ecoreKeyDownEvent.key = key.c_str();
807 ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
808 ecoreKeyDownEvent.compose = compose.c_str();
809 ecoreKeyDownEvent.timestamp = keyEvent.time;
810 ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
811 ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
813 #ifdef defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
814 #ifdef (ECORE_VERSION_MINOR >= 14)
815 ecoreKeyDownEvent.dev_name = "";
816 ecoreKeyDownEvent.dev_class = ECORE_IMF_DEVICE_CLASS_KEYBOARD;
817 ecoreKeyDownEvent.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
818 #endif // Since ecore_imf 1.14 version
819 #ifdef (ECORE_VERSION_MINOR >= 22)
820 ecoreKeyDownEvent.keycode = keyEvent.keyCode;
821 #endif // Since ecore_imf 1.22 version
822 #endif // Since ecore_imf Version 1
824 // 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.
825 if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
826 (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
827 (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
828 (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
834 eventHandled = ecore_imf_context_filter_event(mIMFContext,
835 ECORE_IMF_EVENT_KEY_DOWN,
836 reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ));
839 // If the event has not been handled by InputMethodContext then check if we should reset our IMFcontext
842 if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
843 !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
844 !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
846 ecore_imf_context_reset(mIMFContext);
853 bool InputMethodContextX::ProcessEventKeyUp( const KeyEvent& keyEvent )
855 bool eventHandled( false );
858 Integration::KeyEvent integKeyEvent( keyEvent );
859 std::string key = integKeyEvent.logicalKey;
861 std::string compose = keyEvent.GetCompose();
863 // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
864 Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
865 ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
866 ecoreKeyUpEvent.key = key.c_str();
867 ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
868 ecoreKeyUpEvent.compose = compose.c_str();
869 ecoreKeyUpEvent.timestamp = keyEvent.time;
870 ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
871 ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
872 #ifdef defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
873 #ifdef (ECORE_VERSION_MINOR >= 14)
874 ecoreKeyUpEvent.dev_name = "";
875 #endif // Since ecore_imf 1.14 version
876 #ifdef (ECORE_VERSION_MINOR >= 22)
877 ecoreKeyUpEvent.keycode = keyEvent.keyCode;
878 #endif // Since ecore_imf 1.22 version
879 #endif // Since ecore_imf Version 1
881 eventHandled = ecore_imf_context_filter_event(mIMFContext,
882 ECORE_IMF_EVENT_KEY_UP,
883 reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ));
888 Ecore_IMF_Keyboard_Modifiers InputMethodContextX::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
890 unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE ); // If no other matches returns NONE.
892 if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT ) // enums from ecore_input/Ecore_Input.h
894 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT; // enums from ecore_imf/ecore_imf.h
897 if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
899 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
902 if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
904 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
907 if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
909 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
912 if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
914 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
917 return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
920 Ecore_IMF_Keyboard_Locks InputMethodContextX::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
922 unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
924 if( modifier & ECORE_EVENT_LOCK_NUM )
926 lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
929 if( modifier & ECORE_EVENT_LOCK_CAPS )
931 lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
934 if( modifier & ECORE_EVENT_LOCK_SCROLL )
936 lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
939 return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
942 void InputMethodContextX::OnStaged( Dali::Actor actor )
944 Ecore_X_Window ecoreXwin( AnyCast< Ecore_X_Window >( Dali::Integration::SceneHolder::Get( actor ).GetNativeHandle() ) );
946 if( mEcoreXwin != ecoreXwin )
948 mEcoreXwin = ecoreXwin;