2 * Copyright (c) 2020 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.
20 #include <dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h>
23 #include <Ecore_Input.h>
26 #include <Ecore_Wl2.h>
28 #include <Ecore_Wayland.h>
31 #include <dali/public-api/events/key-event.h>
32 #include <dali/public-api/adaptor-framework/key.h>
33 #include <dali/public-api/object/type-registry.h>
34 #include <dali/devel-api/common/singleton-service.h>
35 #include <dali/integration-api/debug.h>
38 #include <dali/public-api/adaptor-framework/input-method.h>
39 #include <dali/integration-api/adaptor-framework/adaptor.h>
40 #include <dali/integration-api/adaptor-framework/scene-holder.h>
41 #include <dali/internal/input/common/key-impl.h>
42 #include <dali/internal/system/common/locale-utils.h>
43 #include <dali/internal/window-system/common/window-render-surface.h>
45 Ecore_IMF_Input_Panel_Layout panelLayoutMap[] =
47 ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL,
48 ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER,
49 ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL,
50 ECORE_IMF_INPUT_PANEL_LAYOUT_URL,
51 ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER,
52 ECORE_IMF_INPUT_PANEL_LAYOUT_IP,
53 ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH,
54 ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY,
55 ECORE_IMF_INPUT_PANEL_LAYOUT_HEX,
56 ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL,
57 ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD,
58 ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME,
59 ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON,
60 ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE
63 Ecore_IMF_Autocapital_Type autoCapitalMap[] =
65 ECORE_IMF_AUTOCAPITAL_TYPE_NONE,
66 ECORE_IMF_AUTOCAPITAL_TYPE_WORD,
67 ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE,
68 ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER,
71 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyTypeMap[] =
73 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT,
74 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE,
75 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO,
76 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN,
77 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN,
78 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT,
79 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH,
80 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND,
81 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN
95 #if defined(DEBUG_ENABLED)
96 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
99 const int kUninitializedWindowId = 0;
101 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
102 size_t Utf8SequenceLength(const unsigned char leadByte)
106 if( ( leadByte & 0x80 ) == 0 ) //ASCII character (lead bit zero)
110 else if( ( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
114 else if( ( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
118 else if( ( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
122 else if( ( leadByte & 0xfc ) == 0xf8 ) //1111 10xx
126 else if( ( leadByte & 0xfe ) == 0xfc ) //1111 110x
134 // Static function calls used by ecore 'c' style callback registration
135 void Commit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
139 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
140 inputMethodContext->CommitReceived( data, imfContext, eventInfo );
144 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
148 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
149 inputMethodContext->PreEditChanged( data, imfContext, eventInfo );
153 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
157 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
158 return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
166 void InputPanelStateChangeCallback( void* data, Ecore_IMF_Context* context, int value )
172 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
175 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
177 inputMethodContext->StatusChangedSignal().Emit( true );
181 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
183 inputMethodContext->StatusChangedSignal().Emit( false );
187 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
196 void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value )
202 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
203 // Emit the signal that the language has changed
204 inputMethodContext->LanguageChangedSignal().Emit(value);
207 void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value )
213 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
214 // Emit signal that the keyboard is resized
215 inputMethodContext->ResizedSignal().Emit(value);
218 void InputPanelKeyboardTypeChangedCallback( void *data, Ecore_IMF_Context *context, int value )
225 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
228 case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
230 // Emit Signal that the keyboard type is changed to Software Keyboard
231 inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD );
234 case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
236 // Emit Signal that the keyboard type is changed to Hardware Keyboard
237 inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::HARDWARE_KEYBOARD );
244 * Called when an IMF delete surrounding event is received.
245 * Here we tell the application that it should delete a certain range.
247 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
251 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
252 inputMethodContext->DeleteSurrounding( data, imfContext, eventInfo );
257 * Called when the input method sends a private command.
259 void PrivateCommand( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
263 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
264 inputMethodContext->SendPrivateCommand( data, imfContext, eventInfo );
269 * Called when the input method commits content, such as an image.
271 void CommitContent( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
275 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
276 inputMethodContext->SendCommitContent( data, imfContext, eventInfo );
280 int GetWindowIdFromActor( Dali::Actor actor )
282 int windowId = kUninitializedWindowId;
284 if( actor.GetProperty< bool >( Dali::Actor::Property::CONNECTED_TO_SCENE ) )
286 Any nativeWindowHandle = Dali::Integration::SceneHolder::Get( actor ).GetNativeHandle();
288 #ifdef ECORE_WAYLAND2
289 windowId = ecore_wl2_window_id_get( AnyCast< Ecore_Wl2_Window* >( nativeWindowHandle ) );
291 windowId = ecore_wl_window_id_get( AnyCast< Ecore_Wl_Window* >( nativeWindowHandle ) );
300 return Dali::InputMethodContext::New( Dali::Actor() );
303 Dali::TypeRegistration type( typeid(Dali::InputMethodContext), typeid(Dali::BaseHandle), Create );
305 } // unnamed namespace
307 InputMethodContextPtr InputMethodContextEcoreWl::New( Dali::Actor actor )
309 InputMethodContextPtr inputMethodContext;
311 // Create instance only if the adaptor is available and the valid actor exists
312 if ( actor && Dali::Adaptor::IsAvailable() )
314 inputMethodContext = new InputMethodContextEcoreWl( actor );
316 return inputMethodContext;
319 void InputMethodContextEcoreWl::Finalize()
321 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::Finalize\n" );
323 DisconnectCallbacks();
327 InputMethodContextEcoreWl::InputMethodContextEcoreWl( Dali::Actor actor )
329 mIMFCursorPosition( 0 ),
331 mRestoreAfterFocusLost( false ),
332 mIdleCallbackConnected( false ),
333 mWindowId( GetWindowIdFromActor( actor ) )
337 actor.OnSceneSignal().Connect( this, &InputMethodContextEcoreWl::OnStaged );
340 InputMethodContextEcoreWl::~InputMethodContextEcoreWl()
343 ecore_imf_shutdown();
346 void InputMethodContextEcoreWl::Initialize()
350 ApplyBackupOperations();
353 void InputMethodContextEcoreWl::CreateContext()
355 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::CreateContext\n" );
357 if( mWindowId == kUninitializedWindowId )
362 const char *contextId = ecore_imf_context_default_id_get();
365 mIMFContext = ecore_imf_context_add( contextId );
369 ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast< void* >( mWindowId ) );
373 DALI_LOG_WARNING( "InputMethodContext Unable to get IMFContext\n" );
378 DALI_LOG_WARNING( "InputMethodContext Unable to get IMFContext\n" );
382 void InputMethodContextEcoreWl::DeleteContext()
384 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteContext\n" );
388 ecore_imf_context_del( mIMFContext );
393 // Callbacks for predicitive text support.
394 void InputMethodContextEcoreWl::ConnectCallbacks()
398 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ConnectCallbacks\n" );
400 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit, this );
401 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit, this );
402 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
403 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand, this );
404 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT, CommitContent, this );
406 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback, this );
407 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback, this );
408 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, this );
409 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback, this );
411 ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
415 void InputMethodContextEcoreWl::DisconnectCallbacks()
419 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DisconnectCallbacks\n" );
421 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit );
422 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit );
423 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
424 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand );
425 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT, CommitContent );
427 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback );
428 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback );
429 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback );
430 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback );
432 // We do not need to unset the retrieve surrounding callback.
436 void InputMethodContextEcoreWl::Activate()
438 // Reset mIdleCallbackConnected
439 mIdleCallbackConnected = false;
443 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Activate\n" );
445 ecore_imf_context_focus_in( mIMFContext );
447 // emit keyboard activated signal
448 Dali::InputMethodContext handle( this );
449 mActivatedSignal.Emit( handle );
453 void InputMethodContextEcoreWl::Deactivate()
457 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Deactivate\n" );
460 ecore_imf_context_focus_out( mIMFContext );
463 // Reset mIdleCallbackConnected
464 mIdleCallbackConnected = false;
467 void InputMethodContextEcoreWl::Reset()
469 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Reset\n" );
473 ecore_imf_context_reset( mIMFContext );
477 ImfContext* InputMethodContextEcoreWl::GetContext()
479 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetContext\n" );
484 bool InputMethodContextEcoreWl::RestoreAfterFocusLost() const
486 return mRestoreAfterFocusLost;
489 void InputMethodContextEcoreWl::SetRestoreAfterFocusLost( bool toggle )
491 mRestoreAfterFocusLost = toggle;
495 * Called when an InputMethodContext Pre-Edit changed event is received.
496 * We are still predicting what the user is typing. The latest string is what the InputMethodContext module thinks
497 * the user wants to type.
499 void InputMethodContextEcoreWl::PreEditChanged( void*, ImfContext* imfContext, void* eventInfo )
501 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::PreEditChanged\n" );
502 auto context = static_cast<Ecore_IMF_Context*>( imfContext );
504 char* preEditString( NULL );
505 int cursorPosition( 0 );
506 Eina_List* attrs = NULL;
509 Ecore_IMF_Preedit_Attr* attr;
511 mPreeditAttrs.Clear();
513 // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
514 // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
515 ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
519 // iterate through the list of attributes getting the type, start and end position.
520 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) ) ))
522 Dali::InputMethodContext::PreeditAttributeData data;
526 size_t visualCharacterIndex = 0;
527 size_t byteIndex = 0;
529 // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
530 char leadByte = preEditString[byteIndex];
532 while( leadByte != '\0' )
534 leadByte = preEditString[byteIndex]; // Update the character to get the number of its byte
536 // attr->end_index is provided as a byte position not character and we need to know the character position.
537 const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
538 if( byteIndex <= attr->start_index )
540 data.startIndex = visualCharacterIndex;
542 if( byteIndex >= attr->end_index )
544 data.endIndex = visualCharacterIndex;
546 // end loop as found cursor position that matches byte position
550 byteIndex += currentSequenceLength; // jump to next character
551 visualCharacterIndex++; // increment character count so we know our position for when we get a match
555 switch( attr->preedit_type )
557 case ECORE_IMF_PREEDIT_TYPE_NONE:
559 data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
562 case ECORE_IMF_PREEDIT_TYPE_SUB1:
564 data.preeditType = Dali::InputMethodContext::PreeditStyle::UNDERLINE;
567 case ECORE_IMF_PREEDIT_TYPE_SUB2:
569 data.preeditType = Dali::InputMethodContext::PreeditStyle::REVERSE;
572 case ECORE_IMF_PREEDIT_TYPE_SUB3:
574 data.preeditType = Dali::InputMethodContext::PreeditStyle::HIGHLIGHT;
577 case ECORE_IMF_PREEDIT_TYPE_SUB4:
579 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1;
582 case ECORE_IMF_PREEDIT_TYPE_SUB5:
584 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2;
587 case ECORE_IMF_PREEDIT_TYPE_SUB6:
589 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3;
592 case ECORE_IMF_PREEDIT_TYPE_SUB7:
594 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4;
599 data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
603 mPreeditAttrs.PushBack( data );
607 if ( Dali::Adaptor::IsAvailable() )
609 Dali::InputMethodContext handle( this );
610 Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
611 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
613 if ( callbackData.update )
615 SetCursorPosition( callbackData.cursorPosition );
616 SetSurroundingText( callbackData.currentText );
618 NotifyCursorPosition();
621 if ( callbackData.preeditResetRequired )
626 free( preEditString );
629 void InputMethodContextEcoreWl::CommitReceived( void*, ImfContext* imfContext, void* eventInfo )
631 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::CommitReceived\n" );
633 if ( Dali::Adaptor::IsAvailable() )
635 const std::string keyString( static_cast<char*>( eventInfo ) );
637 Dali::InputMethodContext handle( this );
638 Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
639 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
641 if( callbackData.update )
643 SetCursorPosition( callbackData.cursorPosition );
644 SetSurroundingText( callbackData.currentText );
646 NotifyCursorPosition();
652 * Called when an InputMethodContext retrieve surround event is received.
653 * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
654 * We need to signal the application to tell us this information.
656 bool InputMethodContextEcoreWl::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
658 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::RetrieveSurrounding\n" );
660 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
661 Dali::InputMethodContext handle( this );
662 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
664 if( callbackData.update )
668 mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
669 *cursorPosition = mIMFCursorPosition;
674 const char* plainText = callbackData.currentText.c_str();
678 // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
679 *text = strdup( plainText );
681 // If the current input panel is password mode, dali should replace the plain text with '*' (Asterisk) character.
682 if( ( ecore_imf_context_input_hint_get( mIMFContext ) & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA ) && *text )
684 for( char* iter = *text; *iter; ++iter )
699 * Called when an InputMethodContext delete surrounding event is received.
700 * Here we tell the application that it should delete a certain range.
702 void InputMethodContextEcoreWl::DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo )
704 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteSurrounding\n" );
706 if( Dali::Adaptor::IsAvailable() )
708 Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( eventInfo );
710 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
711 Dali::InputMethodContext handle( this );
712 mEventSignal.Emit( handle, imfData );
717 * Called when the input method sends a private command.
719 void InputMethodContextEcoreWl::SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo )
721 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendPrivateCommand\n" );
723 if( Dali::Adaptor::IsAvailable() )
725 const char* privateCommandSendEvent = static_cast<const char*>( eventInfo );
727 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::PRIVATE_COMMAND, privateCommandSendEvent, 0, 0 );
728 Dali::InputMethodContext handle( this );
729 mEventSignal.Emit( handle, imfData );
734 * Called when the input method commits content, such as an image.
736 void InputMethodContextEcoreWl::SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo )
738 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent\n" );
740 if( Dali::Adaptor::IsAvailable() )
742 Ecore_IMF_Event_Commit_Content* commitContent = static_cast<Ecore_IMF_Event_Commit_Content *>( eventInfo );
745 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent commit content : %s, description : %s, mime type : %s\n",
746 commitContent->content_uri, commitContent->description, commitContent->mime_types );
747 mContentReceivedSignal.Emit( commitContent->content_uri, commitContent->description, commitContent->mime_types );
752 void InputMethodContextEcoreWl::NotifyCursorPosition()
754 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::NotifyCursorPosition\n" );
758 ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
762 void InputMethodContextEcoreWl::SetCursorPosition( unsigned int cursorPosition )
764 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetCursorPosition\n" );
766 mIMFCursorPosition = static_cast<int>( cursorPosition );
769 unsigned int InputMethodContextEcoreWl::GetCursorPosition() const
771 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetCursorPosition\n" );
773 return static_cast<unsigned int>( mIMFCursorPosition );
776 void InputMethodContextEcoreWl::SetSurroundingText( const std::string& text )
778 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetSurroundingText\n" );
780 mSurroundingText = text;
783 const std::string& InputMethodContextEcoreWl::GetSurroundingText() const
785 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetSurroundingText\n" );
787 return mSurroundingText;
790 void InputMethodContextEcoreWl::NotifyTextInputMultiLine( bool multiLine )
794 Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
795 ecore_imf_context_input_hint_set( mIMFContext,
796 static_cast< Ecore_IMF_Input_Hints >( multiLine ?
797 (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) :
798 (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
801 mBackupOperations[Operation::NOTIFY_TEXT_INPUT_MULTILINE] = std::bind( &InputMethodContextEcoreWl::NotifyTextInputMultiLine, this, multiLine );
804 Dali::InputMethodContext::TextDirection InputMethodContextEcoreWl::GetTextDirection()
806 Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LEFT_TO_RIGHT );
810 char* locale( NULL );
811 ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
815 direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
823 Rect<int> InputMethodContextEcoreWl::GetInputMethodArea()
825 int xPos, yPos, width, height;
827 width = height = xPos = yPos = 0;
831 ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
835 DALI_LOG_WARNING("VKB Unable to get IMFContext so GetSize unavailable\n");
836 // return 0 as real size unknown.
839 return Rect<int>(xPos,yPos,width,height);
842 void InputMethodContextEcoreWl::ApplyOptions( const InputMethodOptions& options )
844 using namespace Dali::InputMethod::Category;
848 if( mIMFContext == NULL )
850 DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
854 if( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
856 ecore_imf_context_input_panel_layout_set( mIMFContext, panelLayoutMap[index] );
858 // Sets the input hint which allows input methods to fine-tune their behavior.
859 if( panelLayoutMap[index] == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD )
861 ecore_imf_context_input_hint_set( mIMFContext, static_cast< Ecore_IMF_Input_Hints >( ecore_imf_context_input_hint_get( mIMFContext ) | ECORE_IMF_INPUT_HINT_SENSITIVE_DATA ) );
865 ecore_imf_context_input_hint_set( mIMFContext, static_cast< Ecore_IMF_Input_Hints >( ecore_imf_context_input_hint_get( mIMFContext ) & ~ECORE_IMF_INPUT_HINT_SENSITIVE_DATA ) );
868 if( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
870 ecore_imf_context_input_panel_return_key_type_set( mIMFContext, returnKeyTypeMap[index] );
872 if( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
874 ecore_imf_context_autocapital_type_set( mIMFContext, autoCapitalMap[index] );
876 if( mOptions.CompareAndSet(VARIATION, options, index) )
878 ecore_imf_context_input_panel_layout_variation_set( mIMFContext, index );
882 void InputMethodContextEcoreWl::SetInputPanelData( const std::string& data )
884 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelData\n" );
888 int length = data.length();
889 ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
892 mBackupOperations[Operation::SET_INPUT_PANEL_DATA] = std::bind( &InputMethodContextEcoreWl::SetInputPanelData, this, data );
895 void InputMethodContextEcoreWl::GetInputPanelData( std::string& data )
897 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelData\n" );
901 int length = 4096; // The max length is 4096 bytes
902 Dali::Vector< char > buffer;
903 buffer.Resize( length );
904 ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
905 data = std::string( buffer.Begin(), buffer.End() );
909 Dali::InputMethodContext::State InputMethodContextEcoreWl::GetInputPanelState()
911 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelState\n" );
916 value = ecore_imf_context_input_panel_state_get( mIMFContext );
920 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
922 return Dali::InputMethodContext::SHOW;
926 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
928 return Dali::InputMethodContext::HIDE;
932 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
934 return Dali::InputMethodContext::WILL_SHOW;
940 return Dali::InputMethodContext::DEFAULT;
944 return Dali::InputMethodContext::DEFAULT;
947 void InputMethodContextEcoreWl::SetReturnKeyState( bool visible )
949 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetReturnKeyState\n" );
953 ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
956 mBackupOperations[Operation::SET_RETURN_KEY_STATE] = std::bind( &InputMethodContextEcoreWl::SetReturnKeyState, this, visible );
959 void InputMethodContextEcoreWl::AutoEnableInputPanel( bool enabled )
961 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AutoEnableInputPanel\n" );
965 ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
968 mBackupOperations[Operation::AUTO_ENABLE_INPUT_PANEL] = std::bind( &InputMethodContextEcoreWl::AutoEnableInputPanel, this, enabled );
971 void InputMethodContextEcoreWl::ShowInputPanel()
973 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ShowInputPanel\n" );
977 ecore_imf_context_input_panel_show( mIMFContext );
981 void InputMethodContextEcoreWl::HideInputPanel()
983 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::HideInputPanel\n" );
987 ecore_imf_context_input_panel_hide( mIMFContext );
991 Dali::InputMethodContext::KeyboardType InputMethodContextEcoreWl::GetKeyboardType()
993 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetKeyboardType\n" );
998 value = ecore_imf_context_keyboard_mode_get( mIMFContext );
1002 case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
1004 return Dali::InputMethodContext::SOFTWARE_KEYBOARD;
1007 case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
1009 return Dali::InputMethodContext::HARDWARE_KEYBOARD;
1015 return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
1018 std::string InputMethodContextEcoreWl::GetInputPanelLocale()
1020 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLocale\n" );
1022 std::string locale = "";
1027 ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
1031 std::string valueCopy( value );
1034 // The locale string retrieved must be freed with free().
1041 void InputMethodContextEcoreWl::SetContentMIMETypes( const std::string& mimeTypes )
1043 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetContentMIMETypes\n" );
1047 ecore_imf_context_mime_type_accept_set( mIMFContext, mimeTypes.c_str() );
1050 mBackupOperations[Operation::SET_CONTENT_MIME_TYPES] = std::bind( &InputMethodContextEcoreWl::SetContentMIMETypes, this, mimeTypes );
1053 bool InputMethodContextEcoreWl::FilterEventKey( const Dali::KeyEvent& keyEvent )
1055 bool eventHandled( false );
1057 // If a device key then skip ecore_imf_context_filter_event.
1058 if ( ! KeyLookup::IsDeviceButton( keyEvent.GetKeyName().c_str() ))
1060 //check whether it's key down or key up event
1061 if ( keyEvent.GetState() == Dali::KeyEvent::DOWN )
1063 eventHandled = ProcessEventKeyDown( keyEvent );
1065 else if ( keyEvent.GetState() == Dali::KeyEvent::UP )
1067 eventHandled = ProcessEventKeyUp( keyEvent );
1071 return eventHandled;
1074 void InputMethodContextEcoreWl::AllowTextPrediction( bool prediction )
1076 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AllowTextPrediction\n" );
1080 ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
1083 mBackupOperations[Operation::ALLOW_TEXT_PREDICTION] = std::bind( &InputMethodContextEcoreWl::AllowTextPrediction, this, prediction );
1086 bool InputMethodContextEcoreWl::IsTextPredictionAllowed() const
1088 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::IsTextPredictionAllowed\n" );
1089 bool prediction = false;
1092 prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
1097 void InputMethodContextEcoreWl::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
1099 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelLanguage\n" );
1104 case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
1106 ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC );
1109 case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
1111 ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET );
1117 mBackupOperations[Operation::SET_INPUT_PANEL_LANGUAGE] = std::bind( &InputMethodContextEcoreWl::SetInputPanelLanguage, this, language );
1120 Dali::InputMethodContext::InputPanelLanguage InputMethodContextEcoreWl::GetInputPanelLanguage() const
1122 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLanguage\n" );
1126 value = ecore_imf_context_input_panel_language_get( mIMFContext );
1130 case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
1132 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
1135 case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
1137 return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
1142 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
1145 void InputMethodContextEcoreWl::SetInputPanelPosition( unsigned int x, unsigned int y )
1147 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelPosition\n" );
1151 ecore_imf_context_input_panel_position_set( mIMFContext, x, y );
1154 mBackupOperations[Operation::SET_INPUT_PANEL_POSITION] = std::bind( &InputMethodContextEcoreWl::SetInputPanelPosition, this, x, y );
1157 void InputMethodContextEcoreWl::GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const
1159 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetPreeditStyle\n" );
1160 attrs = mPreeditAttrs;
1163 bool InputMethodContextEcoreWl::ProcessEventKeyDown( const Dali::KeyEvent& keyEvent )
1165 bool eventHandled( false );
1168 Integration::KeyEvent integKeyEvent( keyEvent.GetKeyName(), keyEvent.GetLogicalKey(), keyEvent.GetKeyString(), keyEvent.GetKeyCode(), keyEvent.GetKeyModifier(), keyEvent.GetTime(), static_cast< Integration::KeyEvent::State >( keyEvent.GetState() ), keyEvent.GetCompose(), keyEvent.GetDeviceName(), keyEvent.GetDeviceClass(), keyEvent.GetDeviceSubclass() );
1169 std::string key = integKeyEvent.logicalKey;
1171 std::string compose = integKeyEvent.compose;
1172 std::string deviceName = integKeyEvent.deviceName;
1174 // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
1175 Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
1176 ecoreKeyDownEvent.keyname = integKeyEvent.keyName.c_str();
1177 ecoreKeyDownEvent.key = key.c_str();
1178 ecoreKeyDownEvent.string = integKeyEvent.keyString.c_str();
1179 ecoreKeyDownEvent.compose = compose.c_str();
1180 ecoreKeyDownEvent.timestamp = integKeyEvent.time;
1181 ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( integKeyEvent.keyModifier );
1182 ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( integKeyEvent.keyModifier );
1183 ecoreKeyDownEvent.dev_name = deviceName.c_str();
1184 ecoreKeyDownEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( integKeyEvent.deviceClass );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1185 ecoreKeyDownEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( integKeyEvent.deviceSubclass );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
1186 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
1187 ecoreKeyDownEvent.keycode = integKeyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
1188 #endif // Since ecore_imf 1.22 version
1190 // 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.
1191 if ((integKeyEvent.deviceName == "ime") && ((!strncmp(integKeyEvent.keyName.c_str(), "Left", 4)) ||
1192 (!strncmp(integKeyEvent.keyName.c_str(), "Right", 5)) ||
1193 (!strncmp(integKeyEvent.keyName.c_str(), "Up", 2)) ||
1194 (!strncmp(integKeyEvent.keyName.c_str(), "Down", 4))))
1200 eventHandled = ecore_imf_context_filter_event(mIMFContext,
1201 ECORE_IMF_EVENT_KEY_DOWN,
1202 reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ) );
1205 // If the event has not been handled by InputMethodContext then check if we should reset our input method context
1208 if (!strcmp(integKeyEvent.keyName.c_str(), "Escape") ||
1209 !strcmp(integKeyEvent.keyName.c_str(), "Return") ||
1210 !strcmp(integKeyEvent.keyName.c_str(), "KP_Enter"))
1212 ecore_imf_context_reset(mIMFContext);
1216 return eventHandled;
1219 bool InputMethodContextEcoreWl::ProcessEventKeyUp( const Dali::KeyEvent& keyEvent )
1221 bool eventHandled( false );
1224 Integration::KeyEvent integKeyEvent( keyEvent.GetKeyName(), keyEvent.GetLogicalKey(), keyEvent.GetKeyString(), keyEvent.GetKeyCode(), keyEvent.GetKeyModifier(), keyEvent.GetTime(), static_cast< Integration::KeyEvent::State >( keyEvent.GetState() ), keyEvent.GetCompose(), keyEvent.GetDeviceName(), keyEvent.GetDeviceClass(), keyEvent.GetDeviceSubclass() );
1225 std::string key = integKeyEvent.logicalKey;
1227 std::string compose = integKeyEvent.compose;
1228 std::string deviceName = integKeyEvent.deviceName;
1230 // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
1231 Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
1232 ecoreKeyUpEvent.keyname = integKeyEvent.keyName.c_str();
1233 ecoreKeyUpEvent.key = key.c_str();
1234 ecoreKeyUpEvent.string = integKeyEvent.keyString.c_str();
1235 ecoreKeyUpEvent.compose = compose.c_str();
1236 ecoreKeyUpEvent.timestamp = integKeyEvent.time;
1237 ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( integKeyEvent.keyModifier );
1238 ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( integKeyEvent.keyModifier );
1239 ecoreKeyUpEvent.dev_name = deviceName.c_str();
1240 ecoreKeyUpEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( integKeyEvent.deviceClass );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1241 ecoreKeyUpEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( integKeyEvent.deviceSubclass );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
1242 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
1243 ecoreKeyUpEvent.keycode = integKeyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
1244 #endif // Since ecore_imf 1.22 version
1246 eventHandled = ecore_imf_context_filter_event(mIMFContext,
1247 ECORE_IMF_EVENT_KEY_UP,
1248 reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ) );
1250 return eventHandled;
1253 Ecore_IMF_Keyboard_Modifiers InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
1255 unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE ); // If no other matches returns NONE.
1257 if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT ) // enums from ecore_input/Ecore_Input.h
1259 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT; // enums from ecore_imf/ecore_imf.h
1262 if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
1264 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
1267 if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
1269 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
1272 if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
1274 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
1277 if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
1279 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
1282 return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
1285 Ecore_IMF_Keyboard_Locks InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
1287 unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
1289 if( modifier & ECORE_EVENT_LOCK_NUM )
1291 lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
1294 if( modifier & ECORE_EVENT_LOCK_CAPS )
1296 lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
1299 if( modifier & ECORE_EVENT_LOCK_SCROLL )
1301 lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
1304 return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
1307 void InputMethodContextEcoreWl::OnStaged( Dali::Actor actor )
1309 int windowId = GetWindowIdFromActor( actor );
1311 if( mWindowId != windowId )
1313 mWindowId = windowId;