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.
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/integration-api/debug.h>
37 #include <dali/integration-api/adaptor.h>
38 #include <dali/internal/system/common/locale-utils.h>
39 #include <dali/internal/system/common/singleton-service-impl.h>
40 #include <dali/public-api/adaptor-framework/input-method.h>
41 #include <dali/internal/input/common/key-impl.h>
42 #include <dali/internal/window-system/common/window-render-surface.h>
44 #define TOKEN_STRING(x) #x
46 Ecore_IMF_Input_Panel_Layout panelLayoutMap[] =
48 ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL,
49 ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER,
50 ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL,
51 ECORE_IMF_INPUT_PANEL_LAYOUT_URL,
52 ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER,
53 ECORE_IMF_INPUT_PANEL_LAYOUT_IP,
54 ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH,
55 ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY,
56 ECORE_IMF_INPUT_PANEL_LAYOUT_HEX,
57 ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL,
58 ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD,
59 ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME,
60 ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON,
61 ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE
64 Ecore_IMF_Autocapital_Type autoCapitalMap[] =
66 ECORE_IMF_AUTOCAPITAL_TYPE_NONE,
67 ECORE_IMF_AUTOCAPITAL_TYPE_WORD,
68 ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE,
69 ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER,
72 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyTypeMap[] =
74 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT,
75 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE,
76 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO,
77 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN,
78 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN,
79 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT,
80 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH,
81 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND,
82 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN
96 #if defined(DEBUG_ENABLED)
97 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
100 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
101 size_t Utf8SequenceLength(const unsigned char leadByte)
105 if ((leadByte & 0x80) == 0 ) //ASCII character (lead bit zero)
109 else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
113 else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
117 else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
125 // Static function calls used by ecore 'c' style callback registration
126 void Commit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
130 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
131 inputMethodContext->CommitReceived( data, imfContext, eventInfo );
135 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
139 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
140 inputMethodContext->PreEditChanged( data, imfContext, eventInfo );
144 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
148 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
149 return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
157 void InputPanelStateChangeCallback( void* data, Ecore_IMF_Context* context, int value )
163 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
166 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
168 inputMethodContext->StatusChangedSignal().Emit( true );
172 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
174 inputMethodContext->StatusChangedSignal().Emit( false );
178 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
187 void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value )
193 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
194 // Emit the signal that the language has changed
195 inputMethodContext->LanguageChangedSignal().Emit(value);
198 void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value )
204 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
205 // Emit signal that the keyboard is resized
206 inputMethodContext->ResizedSignal().Emit(value);
209 void InputPanelKeyboardTypeChangedCallback( void *data, Ecore_IMF_Context *context, int value )
216 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
219 case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
221 // Emit Signal that the keyboard type is changed to Software Keyboard
222 inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD );
225 case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
227 // Emit Signal that the keyboard type is changed to Hardware Keyboard
228 inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::HARDWARE_KEYBOARD );
235 * Called when an IMF delete surrounding event is received.
236 * Here we tell the application that it should delete a certain range.
238 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
242 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
243 inputMethodContext->DeleteSurrounding( data, imfContext, eventInfo );
248 * Called when the input method sends a private command.
250 void PrivateCommand( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
254 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
255 inputMethodContext->SendPrivateCommand( data, imfContext, eventInfo );
260 * Called when the input method commits content, such as an image.
262 void CommitContent( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
266 InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
267 inputMethodContext->SendCommitContent( data, imfContext, eventInfo );
273 return Dali::InputMethodContext::New();
276 Dali::TypeRegistration type( typeid(Dali::InputMethodContext), typeid(Dali::BaseHandle), Create );
278 } // unnamed namespace
280 InputMethodContextPtr InputMethodContextEcoreWl::New()
282 InputMethodContextPtr inputMethodContext;
284 // Create instance only if the adaptor is available
285 if ( Dali::Adaptor::IsAvailable() )
287 Any nativeWindow = Dali::Adaptor::Get().GetNativeWindowHandle();
289 // The window needs to use the InputMethodContext.
290 if( !nativeWindow.Empty() )
292 inputMethodContext = new InputMethodContextEcoreWl();
296 DALI_LOG_ERROR("Failed to get native window handle, can't create InputMethodContext instance.\n");
299 return inputMethodContext;
302 void InputMethodContextEcoreWl::Finalize()
304 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::Finalize\n" );
306 DisconnectCallbacks();
310 InputMethodContextEcoreWl::InputMethodContextEcoreWl()
312 mIMFCursorPosition( 0 ),
314 mRestoreAfterFocusLost( false ),
315 mIdleCallbackConnected( false )
320 InputMethodContextEcoreWl::~InputMethodContextEcoreWl()
323 ecore_imf_shutdown();
326 void InputMethodContextEcoreWl::Initialize()
332 void InputMethodContextEcoreWl::CreateContext()
334 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::CreateContext\n" );
336 const char *contextId = ecore_imf_context_default_id_get();
339 mIMFContext = ecore_imf_context_add( contextId );
343 // If we fail to get window id, we can't use the InputMethodContext correctly.
344 // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
346 Any nativeWindowHandle = Dali::Adaptor::Get().GetNativeWindowHandle();
348 #ifdef ECORE_WAYLAND2
349 int windowId = ecore_wl2_window_id_get( AnyCast< Ecore_Wl2_Window* >( nativeWindowHandle ) );
351 int windowId = ecore_wl_window_id_get( AnyCast< Ecore_Wl_Window* >( nativeWindowHandle ) );
356 ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast< void* >( windowId ) );
361 DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
366 DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
370 void InputMethodContextEcoreWl::DeleteContext()
372 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteContext\n" );
376 ecore_imf_context_del( mIMFContext );
381 // Callbacks for predicitive text support.
382 void InputMethodContextEcoreWl::ConnectCallbacks()
386 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ConnectCallbacks\n" );
388 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit, this );
389 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit, this );
390 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
391 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand, this );
392 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT, CommitContent, this );
394 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback, this );
395 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback, this );
396 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, this );
397 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback, this );
399 ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
403 void InputMethodContextEcoreWl::DisconnectCallbacks()
407 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DisconnectCallbacks\n" );
409 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit );
410 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit );
411 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
412 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand );
413 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT, CommitContent );
415 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback );
416 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback );
417 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback );
418 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback );
420 // We do not need to unset the retrieve surrounding callback.
424 void InputMethodContextEcoreWl::Activate()
426 // Reset mIdleCallbackConnected
427 mIdleCallbackConnected = false;
431 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Activate\n" );
433 ecore_imf_context_focus_in( mIMFContext );
435 // emit keyboard activated signal
436 Dali::InputMethodContext handle( this );
437 mActivatedSignal.Emit( handle );
441 void InputMethodContextEcoreWl::Deactivate()
445 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Deactivate\n" );
448 ecore_imf_context_focus_out( mIMFContext );
451 // Reset mIdleCallbackConnected
452 mIdleCallbackConnected = false;
455 void InputMethodContextEcoreWl::Reset()
457 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Reset\n" );
461 ecore_imf_context_reset( mIMFContext );
465 ImfContext* InputMethodContextEcoreWl::GetContext()
467 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetContext\n" );
472 bool InputMethodContextEcoreWl::RestoreAfterFocusLost() const
474 return mRestoreAfterFocusLost;
477 void InputMethodContextEcoreWl::SetRestoreAfterFocusLost( bool toggle )
479 mRestoreAfterFocusLost = toggle;
483 * Called when an InputMethodContext Pre-Edit changed event is received.
484 * We are still predicting what the user is typing. The latest string is what the InputMethodContext module thinks
485 * the user wants to type.
487 void InputMethodContextEcoreWl::PreEditChanged( void*, ImfContext* imfContext, void* eventInfo )
489 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::PreEditChanged\n" );
490 auto context = static_cast<Ecore_IMF_Context*>( imfContext );
492 char* preEditString( NULL );
493 int cursorPosition( 0 );
494 Eina_List* attrs = NULL;
497 Ecore_IMF_Preedit_Attr* attr;
499 // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
500 // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
501 ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
505 // iterate through the list of attributes getting the type, start and end position.
506 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) ) ))
508 #ifdef DALI_PROFILE_UBUNTU
509 if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
510 #else // DALI_PROFILE_UBUNTU
511 if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
512 #endif // DALI_PROFILE_UBUNTU
514 // 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.
516 size_t visualCharacterIndex = 0;
517 size_t byteIndex = 0;
519 // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
520 const char leadByte = preEditString[byteIndex];
521 while( leadByte != '\0' )
523 // attr->end_index is provided as a byte position not character and we need to know the character position.
524 const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
525 if ( byteIndex == attr->end_index )
527 cursorPosition = visualCharacterIndex;
529 // end loop as found cursor position that matches byte position
533 byteIndex += currentSequenceLength; // jump to next character
534 visualCharacterIndex++; // increment character count so we know our position for when we get a match
537 DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
543 if ( Dali::Adaptor::IsAvailable() )
545 Dali::InputMethodContext handle( this );
546 Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
547 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
549 if ( callbackData.update )
551 SetCursorPosition( callbackData.cursorPosition );
552 SetSurroundingText( callbackData.currentText );
554 NotifyCursorPosition();
557 if ( callbackData.preeditResetRequired )
562 free( preEditString );
565 void InputMethodContextEcoreWl::CommitReceived( void*, ImfContext* imfContext, void* eventInfo )
567 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::CommitReceived\n" );
569 if ( Dali::Adaptor::IsAvailable() )
571 const std::string keyString( static_cast<char*>( eventInfo ) );
573 Dali::InputMethodContext handle( this );
574 Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
575 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
577 if( callbackData.update )
579 SetCursorPosition( callbackData.cursorPosition );
580 SetSurroundingText( callbackData.currentText );
582 NotifyCursorPosition();
588 * Called when an InputMethodContext retrieve surround event is received.
589 * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
590 * We need to signal the application to tell us this information.
592 bool InputMethodContextEcoreWl::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
594 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::RetrieveSurrounding\n" );
596 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
597 Dali::InputMethodContext handle( this );
598 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
600 if( callbackData.update )
604 const char* plainText = callbackData.currentText.c_str();
607 // If the current input panel is password mode, dali should replace the plain text with '*' (Asterisk) character.
608 if( ecore_imf_context_input_hint_get( mIMFContext ) & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA )
611 for( iter = const_cast<char*>( plainText ); iter && *iter; ++iter )
617 // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
618 *text = strdup( plainText );
623 mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
624 *cursorPosition = mIMFCursorPosition;
632 * Called when an InputMethodContext delete surrounding event is received.
633 * Here we tell the application that it should delete a certain range.
635 void InputMethodContextEcoreWl::DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo )
637 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteSurrounding\n" );
639 if( Dali::Adaptor::IsAvailable() )
641 Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( eventInfo );
643 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
644 Dali::InputMethodContext handle( this );
645 mEventSignal.Emit( handle, imfData );
650 * Called when the input method sends a private command.
652 void InputMethodContextEcoreWl::SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo )
654 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendPrivateCommand\n" );
656 if( Dali::Adaptor::IsAvailable() )
658 const char* privateCommandSendEvent = static_cast<const char*>( eventInfo );
660 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::PRIVATE_COMMAND, privateCommandSendEvent, 0, 0 );
661 Dali::InputMethodContext handle( this );
662 mEventSignal.Emit( handle, imfData );
667 * Called when the input method commits content, such as an image.
669 void InputMethodContextEcoreWl::SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo )
671 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent\n" );
673 if( Dali::Adaptor::IsAvailable() )
675 Ecore_IMF_Event_Commit_Content* commitContent = static_cast<Ecore_IMF_Event_Commit_Content *>( eventInfo );
678 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent commit content : %s, description : %s, mime type : %s\n",
679 commitContent->content_uri, commitContent->description, commitContent->mime_types );
680 mContentReceivedSignal.Emit( commitContent->content_uri, commitContent->description, commitContent->mime_types );
685 void InputMethodContextEcoreWl::NotifyCursorPosition()
687 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::NotifyCursorPosition\n" );
691 ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
695 void InputMethodContextEcoreWl::SetCursorPosition( unsigned int cursorPosition )
697 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetCursorPosition\n" );
699 mIMFCursorPosition = static_cast<int>( cursorPosition );
702 unsigned int InputMethodContextEcoreWl::GetCursorPosition() const
704 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetCursorPosition\n" );
706 return static_cast<unsigned int>( mIMFCursorPosition );
709 void InputMethodContextEcoreWl::SetSurroundingText( const std::string& text )
711 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetSurroundingText\n" );
713 mSurroundingText = text;
716 const std::string& InputMethodContextEcoreWl::GetSurroundingText() const
718 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetSurroundingText\n" );
720 return mSurroundingText;
723 void InputMethodContextEcoreWl::NotifyTextInputMultiLine( bool multiLine )
725 Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
726 ecore_imf_context_input_hint_set( mIMFContext,
727 static_cast< Ecore_IMF_Input_Hints >( multiLine ?
728 (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) :
729 (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
732 Dali::InputMethodContext::TextDirection InputMethodContextEcoreWl::GetTextDirection()
734 Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
738 char* locale( NULL );
739 ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
743 direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
751 Rect<int> InputMethodContextEcoreWl::GetInputMethodArea()
753 int xPos, yPos, width, height;
755 width = height = xPos = yPos = 0;
759 ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
763 DALI_LOG_WARNING("VKB Unable to get IMFContext so GetSize unavailable\n");
764 // return 0 as real size unknown.
767 return Rect<int>(xPos,yPos,width,height);
770 void InputMethodContextEcoreWl::ApplyOptions( const InputMethodOptions& options )
772 using namespace Dali::InputMethod::Category;
776 if( mIMFContext == NULL )
778 DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
782 if( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
784 ecore_imf_context_input_panel_layout_set( mIMFContext, panelLayoutMap[index] );
786 // Sets the input hint which allows input methods to fine-tune their behavior.
787 if( panelLayoutMap[index] == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD )
789 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 ) );
793 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 ) );
796 if( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
798 ecore_imf_context_input_panel_return_key_type_set( mIMFContext, returnKeyTypeMap[index] );
800 if( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
802 ecore_imf_context_autocapital_type_set( mIMFContext, autoCapitalMap[index] );
804 if( mOptions.CompareAndSet(VARIATION, options, index) )
806 ecore_imf_context_input_panel_layout_variation_set( mIMFContext, index );
810 void InputMethodContextEcoreWl::SetInputPanelData( const std::string& data )
812 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelData\n" );
816 int length = data.length();
817 ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
821 void InputMethodContextEcoreWl::GetInputPanelData( std::string& data )
823 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelData\n" );
827 int length = 4096; // The max length is 4096 bytes
828 Dali::Vector< char > buffer;
829 buffer.Resize( length );
830 ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
831 data = std::string( buffer.Begin(), buffer.End() );
835 Dali::InputMethodContext::State InputMethodContextEcoreWl::GetInputPanelState()
837 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelState\n" );
842 value = ecore_imf_context_input_panel_state_get( mIMFContext );
846 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
848 return Dali::InputMethodContext::SHOW;
852 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
854 return Dali::InputMethodContext::HIDE;
858 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
860 return Dali::InputMethodContext::WILL_SHOW;
866 return Dali::InputMethodContext::DEFAULT;
870 return Dali::InputMethodContext::DEFAULT;
873 void InputMethodContextEcoreWl::SetReturnKeyState( bool visible )
875 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetReturnKeyState\n" );
879 ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
883 void InputMethodContextEcoreWl::AutoEnableInputPanel( bool enabled )
885 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AutoEnableInputPanel\n" );
889 ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
893 void InputMethodContextEcoreWl::ShowInputPanel()
895 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ShowInputPanel\n" );
899 ecore_imf_context_input_panel_show( mIMFContext );
903 void InputMethodContextEcoreWl::HideInputPanel()
905 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::HideInputPanel\n" );
909 ecore_imf_context_input_panel_hide( mIMFContext );
913 Dali::InputMethodContext::KeyboardType InputMethodContextEcoreWl::GetKeyboardType()
915 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetKeyboardType\n" );
920 value = ecore_imf_context_keyboard_mode_get( mIMFContext );
924 case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
926 return Dali::InputMethodContext::SOFTWARE_KEYBOARD;
929 case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
931 return Dali::InputMethodContext::HARDWARE_KEYBOARD;
937 return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
940 std::string InputMethodContextEcoreWl::GetInputPanelLocale()
942 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLocale\n" );
944 std::string locale = "";
949 ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
953 std::string valueCopy( value );
956 // The locale string retrieved must be freed with free().
963 void InputMethodContextEcoreWl::SetContentMIMETypes( const std::string& mimeTypes )
965 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetContentMIMETypes\n" );
969 ecore_imf_context_mime_type_accept_set( mIMFContext, mimeTypes.c_str() );
973 bool InputMethodContextEcoreWl::FilterEventKey( const Dali::KeyEvent& keyEvent )
975 bool eventHandled( false );
977 // If a device key then skip ecore_imf_context_filter_event.
978 if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))
980 //check whether it's key down or key up event
981 if ( keyEvent.state == KeyEvent::Down )
983 eventHandled = ProcessEventKeyDown( keyEvent );
985 else if ( keyEvent.state == KeyEvent::Up )
987 eventHandled = ProcessEventKeyUp( keyEvent );
994 void InputMethodContextEcoreWl::AllowTextPrediction( bool prediction )
996 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AllowTextPrediction\n" );
1000 ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
1004 bool InputMethodContextEcoreWl::IsTextPredictionAllowed() const
1006 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::IsTextPredictionAllowed\n" );
1007 bool prediction = false;
1010 prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
1015 void InputMethodContextEcoreWl::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
1017 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelLanguage\n" );
1022 case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
1024 ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC );
1027 case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
1029 ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET );
1036 Dali::InputMethodContext::InputPanelLanguage InputMethodContextEcoreWl::GetInputPanelLanguage() const
1038 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLanguage\n" );
1042 value = ecore_imf_context_input_panel_language_get( mIMFContext );
1046 case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
1048 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
1051 case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
1053 return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
1058 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
1061 bool InputMethodContextEcoreWl::ProcessEventKeyDown( const KeyEvent& keyEvent )
1063 bool eventHandled( false );
1066 Integration::KeyEvent integKeyEvent( keyEvent );
1067 std::string key = integKeyEvent.logicalKey;
1069 std::string compose = keyEvent.GetCompose();
1070 std::string deviceName = keyEvent.GetDeviceName();
1072 // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
1073 Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
1074 ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
1075 ecoreKeyDownEvent.key = key.c_str();
1076 ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
1077 ecoreKeyDownEvent.compose = compose.c_str();
1078 ecoreKeyDownEvent.timestamp = keyEvent.time;
1079 ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
1080 ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
1081 ecoreKeyDownEvent.dev_name = deviceName.c_str();
1082 ecoreKeyDownEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1083 ecoreKeyDownEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
1085 // 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.
1086 if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
1087 (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
1088 (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
1089 (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
1095 eventHandled = ecore_imf_context_filter_event(mIMFContext,
1096 ECORE_IMF_EVENT_KEY_DOWN,
1097 reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ) );
1100 // If the event has not been handled by InputMethodContext then check if we should reset our input method context
1103 if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
1104 !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
1105 !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
1107 ecore_imf_context_reset(mIMFContext);
1111 return eventHandled;
1114 bool InputMethodContextEcoreWl::ProcessEventKeyUp( const KeyEvent& keyEvent )
1116 bool eventHandled( false );
1119 Integration::KeyEvent integKeyEvent( keyEvent );
1120 std::string key = integKeyEvent.logicalKey;
1122 std::string compose = keyEvent.GetCompose();
1123 std::string deviceName = keyEvent.GetDeviceName();
1125 // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
1126 Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
1127 ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
1128 ecoreKeyUpEvent.key = key.c_str();
1129 ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
1130 ecoreKeyUpEvent.compose = compose.c_str();
1131 ecoreKeyUpEvent.timestamp = keyEvent.time;
1132 ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
1133 ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
1134 ecoreKeyUpEvent.dev_name = deviceName.c_str();
1135 ecoreKeyUpEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1136 ecoreKeyUpEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
1138 eventHandled = ecore_imf_context_filter_event(mIMFContext,
1139 ECORE_IMF_EVENT_KEY_UP,
1140 reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ) );
1142 return eventHandled;
1145 Ecore_IMF_Keyboard_Modifiers InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
1147 unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE ); // If no other matches returns NONE.
1149 if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT ) // enums from ecore_input/Ecore_Input.h
1151 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT; // enums from ecore_imf/ecore_imf.h
1154 if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
1156 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
1159 if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
1161 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
1164 if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
1166 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
1169 if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
1171 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
1174 return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
1177 Ecore_IMF_Keyboard_Locks InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
1179 unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
1181 if( modifier & ECORE_EVENT_LOCK_NUM )
1183 lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
1186 if( modifier & ECORE_EVENT_LOCK_CAPS )
1188 lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
1191 if( modifier & ECORE_EVENT_LOCK_SCROLL )
1193 lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
1196 return static_cast<Ecore_IMF_Keyboard_Locks>( lock );