2 * Copyright (c) 2018 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 // Ecore is littered with C style cast
20 #pragma GCC diagnostic push
21 #pragma GCC diagnostic ignored "-Wold-style-cast"
23 #include <dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h>
26 #include <Ecore_Input.h>
28 #include <dali/public-api/events/key-event.h>
29 #include <dali/public-api/adaptor-framework/key.h>
30 #include <dali/public-api/object/type-registry.h>
31 #include <dali/integration-api/debug.h>
34 #include <dali/integration-api/adaptor.h>
35 #include <dali/internal/system/common/locale-utils.h>
36 #include <dali/internal/system/common/singleton-service-impl.h>
37 #include <dali/public-api/adaptor-framework/input-method.h>
38 #include <dali/internal/input/common/key-impl.h>
39 #include <dali/internal/window-system/common/window-render-surface.h>
41 #define TOKEN_STRING(x) #x
43 Ecore_IMF_Input_Panel_Layout panelLayoutMap[] =
45 ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL,
46 ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER,
47 ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL,
48 ECORE_IMF_INPUT_PANEL_LAYOUT_URL,
49 ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER,
50 ECORE_IMF_INPUT_PANEL_LAYOUT_IP,
51 ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH,
52 ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY,
53 ECORE_IMF_INPUT_PANEL_LAYOUT_HEX,
54 ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL,
55 ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD,
56 ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME,
57 ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON,
58 ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE
61 Ecore_IMF_Autocapital_Type autoCapitalMap[] =
63 ECORE_IMF_AUTOCAPITAL_TYPE_NONE,
64 ECORE_IMF_AUTOCAPITAL_TYPE_WORD,
65 ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE,
66 ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER,
69 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyTypeMap[] =
71 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT,
72 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE,
73 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO,
74 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN,
75 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN,
76 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT,
77 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH,
78 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND,
79 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN
93 #if defined(DEBUG_ENABLED)
94 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
97 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
98 size_t Utf8SequenceLength(const unsigned char leadByte)
102 if ((leadByte & 0x80) == 0 ) //ASCII character (lead bit zero)
106 else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
110 else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
114 else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
122 // Static function calls used by ecore 'c' style callback registration
123 void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
127 InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
128 inputMethodContext->CommitReceived( data, imfContext, event_info );
132 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
136 InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
137 inputMethodContext->PreEditChanged( data, imfContext, event_info );
141 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
145 InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
146 return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
154 void InputPanelStateChangeCallback( void* data, Ecore_IMF_Context* context, int value )
160 InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
163 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
165 inputMethodContext->StatusChangedSignal().Emit( true );
169 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
171 inputMethodContext->StatusChangedSignal().Emit( false );
175 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
184 void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value )
190 InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
191 // Emit the signal that the language has changed
192 inputMethodContext->LanguageChangedSignal().Emit(value);
195 void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value )
201 InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
202 // Emit signal that the keyboard is resized
203 inputMethodContext->ResizedSignal().Emit(value);
206 void InputPanelKeyboardTypeChangedCallback( void *data, Ecore_IMF_Context *context, int value )
213 InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
216 case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
218 // Emit Signal that the keyboard type is changed to Software Keyboard
219 inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD );
222 case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
224 // Emit Signal that the keyboard type is changed to Hardware Keyboard
225 inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::HARDWARE_KEYBOARD );
232 * Called when an IMF delete surrounding event is received.
233 * Here we tell the application that it should delete a certain range.
235 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
239 InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
240 inputMethodContext->DeleteSurrounding( data, imfContext, event_info );
245 * Called when the input method sends a private command.
247 void PrivateCommand( void *data, Ecore_IMF_Context *imfContext, void *event_info )
251 InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
252 inputMethodContext->SendPrivateCommand( data, imfContext, event_info );
258 return Dali::InputMethodContext::New();
261 Dali::TypeRegistration type( typeid(Dali::InputMethodContext), typeid(Dali::BaseHandle), Create );
263 } // unnamed namespace
265 InputMethodContextPtr InputMethodContextEcoreWl::New()
267 InputMethodContextPtr inputMethodContext;
269 // Create instance only if the adaptor is available
270 if ( Dali::Adaptor::IsAvailable() )
272 Any nativeWindow = Dali::Adaptor::Get().GetNativeWindowHandle();
274 // The window needs to use the InputMethodContext.
275 // Only when the render surface is window, we can get the window.
276 if( !nativeWindow.Empty() )
278 inputMethodContext = new InputMethodContextEcoreWl();
282 DALI_LOG_ERROR("Failed to get native window handle, can't create InputMethodContext instance.\n");
285 return inputMethodContext;
288 void InputMethodContextEcoreWl::Finalize()
290 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::Finalize\n" );
292 DisconnectCallbacks();
296 InputMethodContextEcoreWl::InputMethodContextEcoreWl()
298 mIMFCursorPosition( 0 ),
300 mRestoreAfterFocusLost( false ),
301 mIdleCallbackConnected( false )
306 InputMethodContextEcoreWl::~InputMethodContextEcoreWl()
309 ecore_imf_shutdown();
312 void InputMethodContextEcoreWl::Initialize()
318 void InputMethodContextEcoreWl::CreateContext()
320 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::CreateContext\n" );
322 const char *contextId = ecore_imf_context_default_id_get();
325 mIMFContext = ecore_imf_context_add( contextId );
329 // If we fail to get window id, we can't use the InputMethodContext correctly.
330 // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
331 // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
332 RenderSurface& renderSurface = Dali::Adaptor::Get().GetSurface();
333 WindowRenderSurface& windowRenderSurface = static_cast< WindowRenderSurface& >( renderSurface );
335 int windowId = windowRenderSurface.GetNativeWindowId();
338 ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast< void* >( windowId ) );
343 DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
348 DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
352 void InputMethodContextEcoreWl::DeleteContext()
354 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteContext\n" );
358 ecore_imf_context_del( mIMFContext );
363 // Callbacks for predicitive text support.
364 void InputMethodContextEcoreWl::ConnectCallbacks()
368 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ConnectCallbacks\n" );
370 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit, this );
371 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit, this );
372 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
373 ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand, this );
375 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback, this );
376 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback, this );
377 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, this );
378 ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback, this );
380 ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
384 void InputMethodContextEcoreWl::DisconnectCallbacks()
388 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DisconnectCallbacks\n" );
390 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit );
391 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit );
392 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
393 ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand );
395 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback );
396 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback );
397 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback );
398 ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback );
400 // We do not need to unset the retrieve surrounding callback.
404 void InputMethodContextEcoreWl::Activate()
406 // Reset mIdleCallbackConnected
407 mIdleCallbackConnected = false;
411 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Activate\n" );
413 ecore_imf_context_focus_in( mIMFContext );
415 // emit keyboard activated signal
416 Dali::InputMethodContext handle( this );
417 mActivatedSignal.Emit( handle );
421 void InputMethodContextEcoreWl::Deactivate()
425 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Deactivate\n" );
428 ecore_imf_context_focus_out( mIMFContext );
431 // Reset mIdleCallbackConnected
432 mIdleCallbackConnected = false;
435 void InputMethodContextEcoreWl::Reset()
437 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Reset\n" );
441 ecore_imf_context_reset( mIMFContext );
445 ImfContext* InputMethodContextEcoreWl::GetContext()
447 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetContext\n" );
452 bool InputMethodContextEcoreWl::RestoreAfterFocusLost() const
454 return mRestoreAfterFocusLost;
457 void InputMethodContextEcoreWl::SetRestoreAfterFocusLost( bool toggle )
459 mRestoreAfterFocusLost = toggle;
463 * Called when an InputMethodContext Pre-Edit changed event is received.
464 * We are still predicting what the user is typing. The latest string is what the InputMethodContext module thinks
465 * the user wants to type.
467 void InputMethodContextEcoreWl::PreEditChanged( void*, ImfContext* imfContext, void* event_info )
469 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::PreEditChanged\n" );
470 auto context = reinterpret_cast<Ecore_IMF_Context*>(imfContext);
472 char* preEditString( NULL );
473 int cursorPosition( 0 );
474 Eina_List* attrs = NULL;
477 Ecore_IMF_Preedit_Attr* attr;
479 // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
480 // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
481 ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
485 // iterate through the list of attributes getting the type, start and end position.
486 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) ) ))
488 #ifdef DALI_PROFILE_UBUNTU
489 if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
490 #else // DALI_PROFILE_UBUNTU
491 if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
492 #endif // DALI_PROFILE_UBUNTU
494 // 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.
496 size_t visualCharacterIndex = 0;
497 size_t byteIndex = 0;
499 // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
500 const char leadByte = preEditString[byteIndex];
501 while( leadByte != '\0' )
503 // attr->end_index is provided as a byte position not character and we need to know the character position.
504 const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
505 if ( byteIndex == attr->end_index )
507 cursorPosition = visualCharacterIndex;
509 // end loop as found cursor position that matches byte position
513 byteIndex += currentSequenceLength; // jump to next character
514 visualCharacterIndex++; // increment character count so we know our position for when we get a match
517 DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
523 if ( Dali::Adaptor::IsAvailable() )
525 Dali::InputMethodContext handle( this );
526 Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
527 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
529 if ( callbackData.update )
531 SetCursorPosition( callbackData.cursorPosition );
532 SetSurroundingText( callbackData.currentText );
534 NotifyCursorPosition();
537 if ( callbackData.preeditResetRequired )
542 free( preEditString );
545 void InputMethodContextEcoreWl::CommitReceived( void*, ImfContext* imfContext, void* event_info )
547 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::CommitReceived\n" );
549 if ( Dali::Adaptor::IsAvailable() )
551 const std::string keyString( static_cast<char*>( event_info ) );
553 Dali::InputMethodContext handle( this );
554 Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
555 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
557 if( callbackData.update )
559 SetCursorPosition( callbackData.cursorPosition );
560 SetSurroundingText( callbackData.currentText );
562 NotifyCursorPosition();
568 * Called when an InputMethodContext retrieve surround event is received.
569 * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
570 * We need to signal the application to tell us this information.
572 bool InputMethodContextEcoreWl::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
574 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::RetrieveSurrounding\n" );
576 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
577 Dali::InputMethodContext handle( this );
578 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
580 if( callbackData.update )
584 // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
585 *text = strdup( callbackData.currentText.c_str() );
590 mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
591 *cursorPosition = mIMFCursorPosition;
599 * Called when an InputMethodContext delete surrounding event is received.
600 * Here we tell the application that it should delete a certain range.
602 void InputMethodContextEcoreWl::DeleteSurrounding( void* data, ImfContext* imfContext, void* event_info )
604 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteSurrounding\n" );
606 if( Dali::Adaptor::IsAvailable() )
608 Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( event_info );
610 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
611 Dali::InputMethodContext handle( this );
612 mEventSignal.Emit( handle, imfData );
617 * Called when the input method sends a private command.
619 void InputMethodContextEcoreWl::SendPrivateCommand( void* data, ImfContext* imfContext, void* event_info )
621 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendPrivateCommand\n" );
623 if( Dali::Adaptor::IsAvailable() )
625 const char* privateCommandSendEvent = static_cast<const char*>( event_info );
627 Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::PRIVATE_COMMAND, privateCommandSendEvent, 0, 0 );
628 Dali::InputMethodContext handle( this );
629 mEventSignal.Emit( handle, imfData );
633 void InputMethodContextEcoreWl::NotifyCursorPosition()
635 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::NotifyCursorPosition\n" );
639 ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
643 void InputMethodContextEcoreWl::SetCursorPosition( unsigned int cursorPosition )
645 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetCursorPosition\n" );
647 mIMFCursorPosition = static_cast<int>( cursorPosition );
650 unsigned int InputMethodContextEcoreWl::GetCursorPosition() const
652 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetCursorPosition\n" );
654 return static_cast<unsigned int>( mIMFCursorPosition );
657 void InputMethodContextEcoreWl::SetSurroundingText( const std::string& text )
659 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetSurroundingText\n" );
661 mSurroundingText = text;
664 const std::string& InputMethodContextEcoreWl::GetSurroundingText() const
666 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetSurroundingText\n" );
668 return mSurroundingText;
671 void InputMethodContextEcoreWl::NotifyTextInputMultiLine( bool multiLine )
673 Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
674 ecore_imf_context_input_hint_set( mIMFContext,
675 static_cast< Ecore_IMF_Input_Hints >( multiLine ?
676 (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) :
677 (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
680 Dali::InputMethodContext::TextDirection InputMethodContextEcoreWl::GetTextDirection()
682 Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
686 char* locale( NULL );
687 ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
691 direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
699 Rect<int> InputMethodContextEcoreWl::GetInputMethodArea()
701 int xPos, yPos, width, height;
703 width = height = xPos = yPos = 0;
707 ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
711 DALI_LOG_WARNING("VKB Unable to get IMFContext so GetSize unavailable\n");
712 // return 0 as real size unknown.
715 return Rect<int>(xPos,yPos,width,height);
718 void InputMethodContextEcoreWl::ApplyOptions( const InputMethodOptions& options )
720 using namespace Dali::InputMethod::Category;
724 if (mIMFContext == NULL)
726 DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
730 if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
732 ecore_imf_context_input_panel_layout_set( mIMFContext, panelLayoutMap[index] );
734 if ( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
736 ecore_imf_context_input_panel_return_key_type_set( mIMFContext, returnKeyTypeMap[index] );
738 if ( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
740 ecore_imf_context_autocapital_type_set( mIMFContext, autoCapitalMap[index] );
742 if ( mOptions.CompareAndSet(VARIATION, options, index) )
744 ecore_imf_context_input_panel_layout_variation_set( mIMFContext, index );
748 void InputMethodContextEcoreWl::SetInputPanelData( const std::string& data )
750 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelData\n" );
754 int length = data.length();
755 ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
759 void InputMethodContextEcoreWl::GetInputPanelData( std::string& data )
761 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelData\n" );
765 int length = 4096; // The max length is 4096 bytes
766 Dali::Vector< char > buffer;
767 buffer.Resize( length );
768 ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
769 data = std::string( buffer.Begin(), buffer.End() );
773 Dali::InputMethodContext::State InputMethodContextEcoreWl::GetInputPanelState()
775 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelState\n" );
780 value = ecore_imf_context_input_panel_state_get( mIMFContext );
784 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
786 return Dali::InputMethodContext::SHOW;
790 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
792 return Dali::InputMethodContext::HIDE;
796 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
798 return Dali::InputMethodContext::WILL_SHOW;
804 return Dali::InputMethodContext::DEFAULT;
808 return Dali::InputMethodContext::DEFAULT;
811 void InputMethodContextEcoreWl::SetReturnKeyState( bool visible )
813 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetReturnKeyState\n" );
817 ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
821 void InputMethodContextEcoreWl::AutoEnableInputPanel( bool enabled )
823 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AutoEnableInputPanel\n" );
827 ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
831 void InputMethodContextEcoreWl::ShowInputPanel()
833 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ShowInputPanel\n" );
837 ecore_imf_context_input_panel_show( mIMFContext );
841 void InputMethodContextEcoreWl::HideInputPanel()
843 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::HideInputPanel\n" );
847 ecore_imf_context_input_panel_hide( mIMFContext );
851 Dali::InputMethodContext::KeyboardType InputMethodContextEcoreWl::GetKeyboardType()
853 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetKeyboardType\n" );
855 #ifdef OVER_TIZEN_VERSION_4
859 value = ecore_imf_context_keyboard_mode_get( mIMFContext );
863 case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
865 return Dali::InputMethodContext::SOFTWARE_KEYBOARD;
868 case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
870 return Dali::InputMethodContext::HARDWARE_KEYBOARD;
875 #endif // OVER_TIZEN_VERSION_4
876 return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
879 std::string InputMethodContextEcoreWl::GetInputPanelLocale()
881 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLocale\n" );
883 std::string locale = "";
888 ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
892 std::string valueCopy( value );
895 // The locale string retrieved must be freed with free().
902 bool InputMethodContextEcoreWl::FilterEventKey( const Dali::KeyEvent& keyEvent )
904 bool eventHandled( false );
906 // If a device key then skip ecore_imf_context_filter_event.
907 if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))
909 //check whether it's key down or key up event
910 if ( keyEvent.state == KeyEvent::Down )
912 eventHandled = ProcessEventKeyDown( keyEvent );
914 else if ( keyEvent.state == KeyEvent::Up )
916 eventHandled = ProcessEventKeyUp( keyEvent );
923 void InputMethodContextEcoreWl::AllowTextPrediction( bool prediction )
925 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AllowTextPrediction\n" );
929 ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
933 bool InputMethodContextEcoreWl::IsTextPredictionAllowed() const
935 DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::IsTextPredictionAllowed\n" );
936 bool prediction = false;
939 prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
944 bool InputMethodContextEcoreWl::ProcessEventKeyDown( const KeyEvent& keyEvent )
946 bool eventHandled( false );
949 // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
950 Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
951 ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
952 ecoreKeyDownEvent.key = keyEvent.keyPressedName.c_str();
953 ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
954 ecoreKeyDownEvent.compose = keyEvent.GetCompose().c_str();
955 ecoreKeyDownEvent.timestamp = keyEvent.time;
956 ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
957 ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
958 ecoreKeyDownEvent.dev_name = keyEvent.GetDeviceName().c_str();
959 ecoreKeyDownEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
960 ecoreKeyDownEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
962 // 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.
963 if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
964 (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
965 (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
966 (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
972 eventHandled = ecore_imf_context_filter_event(mIMFContext,
973 ECORE_IMF_EVENT_KEY_DOWN,
974 (Ecore_IMF_Event *) &ecoreKeyDownEvent);
977 // If the event has not been handled by InputMethodContext then check if we should reset our input method context
980 if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
981 !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
982 !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
984 ecore_imf_context_reset(mIMFContext);
991 bool InputMethodContextEcoreWl::ProcessEventKeyUp( const KeyEvent& keyEvent )
993 bool eventHandled( false );
996 // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
997 Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
998 ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
999 ecoreKeyUpEvent.key = keyEvent.keyPressedName.c_str();
1000 ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
1001 ecoreKeyUpEvent.compose = keyEvent.GetCompose().c_str();
1002 ecoreKeyUpEvent.timestamp = keyEvent.time;
1003 ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
1004 ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
1005 ecoreKeyUpEvent.dev_name = keyEvent.GetDeviceName().c_str();
1006 ecoreKeyUpEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1007 ecoreKeyUpEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
1009 eventHandled = ecore_imf_context_filter_event(mIMFContext,
1010 ECORE_IMF_EVENT_KEY_UP,
1011 (Ecore_IMF_Event *) &ecoreKeyUpEvent);
1013 return eventHandled;
1016 Ecore_IMF_Keyboard_Modifiers InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
1018 unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE ); // If no other matches returns NONE.
1020 if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT ) // enums from ecore_input/Ecore_Input.h
1022 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT; // enums from ecore_imf/ecore_imf.h
1025 if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
1027 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
1030 if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
1032 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
1035 if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
1037 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
1040 if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
1042 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
1045 return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
1048 Ecore_IMF_Keyboard_Locks InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
1050 unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
1052 if( modifier & ECORE_EVENT_LOCK_NUM )
1054 lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
1057 if( modifier & ECORE_EVENT_LOCK_CAPS )
1059 lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
1062 if( modifier & ECORE_EVENT_LOCK_SCROLL )
1064 lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
1067 return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
1076 #pragma GCC diagnostic pop