ab7c78b5ad9adf1ad984e967b7b449c739fe06c5
[platform/core/uifw/dali-adaptor.git] / dali / internal / input / tizen-wayland / input-method-context-impl-ecore-wl.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19
20 #include <dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h>
21
22 // EXTERNAL INCLUDES
23 #include <Ecore_Input.h>
24
25 #ifdef ECORE_WAYLAND2
26 #include <Ecore_Wl2.h>
27 #else
28 #include <Ecore_Wayland.h>
29 #endif
30
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>
35
36 // INTERNAL INCLUDES
37 #include <dali/public-api/adaptor-framework/input-method.h>
38 #include <dali/integration-api/adaptor-framework/adaptor.h>
39 #include <dali/integration-api/adaptor-framework/scene-holder.h>
40 #include <dali/internal/input/common/key-impl.h>
41 #include <dali/internal/system/common/locale-utils.h>
42 #include <dali/internal/system/common/singleton-service-impl.h>
43 #include <dali/internal/window-system/common/window-render-surface.h>
44
45 #define TOKEN_STRING(x) #x
46
47 Ecore_IMF_Input_Panel_Layout panelLayoutMap[] =
48 {
49    ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL,
50    ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER,
51    ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL,
52    ECORE_IMF_INPUT_PANEL_LAYOUT_URL,
53    ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER,
54    ECORE_IMF_INPUT_PANEL_LAYOUT_IP,
55    ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH,
56    ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY,
57    ECORE_IMF_INPUT_PANEL_LAYOUT_HEX,
58    ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL,
59    ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD,
60    ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME,
61    ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON,
62    ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE
63 };
64
65 Ecore_IMF_Autocapital_Type autoCapitalMap[] =
66 {
67    ECORE_IMF_AUTOCAPITAL_TYPE_NONE,
68    ECORE_IMF_AUTOCAPITAL_TYPE_WORD,
69    ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE,
70    ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER,
71 };
72
73 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyTypeMap[] =
74 {
75    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT,
76    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE,
77    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO,
78    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN,
79    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN,
80    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT,
81    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH,
82    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND,
83    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN
84 };
85
86 namespace Dali
87 {
88
89 namespace Internal
90 {
91
92 namespace Adaptor
93 {
94
95 namespace
96 {
97 #if defined(DEBUG_ENABLED)
98 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
99 #endif
100
101 const int kUninitializedWindowId = 0;
102
103 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
104 size_t Utf8SequenceLength(const unsigned char leadByte)
105 {
106   size_t length = 0;
107
108   if ((leadByte & 0x80) == 0 )          //ASCII character (lead bit zero)
109   {
110     length = 1;
111   }
112   else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
113   {
114     length = 2;
115   }
116   else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
117   {
118     length = 3;
119   }
120   else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
121   {
122     length = 4;
123   }
124
125   return length;
126 }
127
128 // Static function calls used by ecore 'c' style callback registration
129 void Commit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
130 {
131   if ( data )
132   {
133     InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
134     inputMethodContext->CommitReceived( data, imfContext, eventInfo );
135   }
136 }
137
138 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
139 {
140   if ( data )
141   {
142     InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
143     inputMethodContext->PreEditChanged( data, imfContext, eventInfo );
144   }
145 }
146
147 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
148 {
149   if ( data )
150   {
151     InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
152     return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
153   }
154   else
155   {
156     return false;
157   }
158 }
159
160 void InputPanelStateChangeCallback( void* data, Ecore_IMF_Context* context, int value )
161 {
162   if (!data)
163   {
164     return;
165   }
166   InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
167   switch (value)
168   {
169     case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
170     {
171       inputMethodContext->StatusChangedSignal().Emit( true );
172       break;
173     }
174
175     case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
176     {
177       inputMethodContext->StatusChangedSignal().Emit( false );
178       break;
179     }
180
181     case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
182     default:
183     {
184       // Do nothing
185       break;
186     }
187   }
188 }
189
190 void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value )
191 {
192   if (!data)
193   {
194     return;
195   }
196   InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
197   // Emit the signal that the language has changed
198   inputMethodContext->LanguageChangedSignal().Emit(value);
199 }
200
201 void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value )
202 {
203   if (!data)
204   {
205     return;
206   }
207   InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
208   // Emit signal that the keyboard is resized
209   inputMethodContext->ResizedSignal().Emit(value);
210 }
211
212 void InputPanelKeyboardTypeChangedCallback( void *data, Ecore_IMF_Context *context, int value )
213 {
214   if( !data )
215   {
216     return;
217   }
218
219   InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
220   switch (value)
221   {
222     case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
223     {
224       // Emit Signal that the keyboard type is changed to Software Keyboard
225       inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD );
226       break;
227     }
228     case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
229     {
230       // Emit Signal that the keyboard type is changed to Hardware Keyboard
231       inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::HARDWARE_KEYBOARD );
232       break;
233     }
234   }
235 }
236
237 /**
238  * Called when an IMF delete surrounding event is received.
239  * Here we tell the application that it should delete a certain range.
240  */
241 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
242 {
243   if ( data )
244   {
245     InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
246     inputMethodContext->DeleteSurrounding( data, imfContext, eventInfo );
247   }
248 }
249
250 /**
251  * Called when the input method sends a private command.
252  */
253 void PrivateCommand( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
254 {
255   if ( data )
256   {
257     InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
258     inputMethodContext->SendPrivateCommand( data, imfContext, eventInfo );
259   }
260 }
261
262 /**
263  * Called when the input method commits content, such as an image.
264  */
265 void CommitContent( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
266 {
267   if ( data )
268   {
269     InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
270     inputMethodContext->SendCommitContent( data, imfContext, eventInfo );
271   }
272 }
273
274 int GetWindowIdFromActor( Dali::Actor actor )
275 {
276   int windowId = kUninitializedWindowId;
277
278   if( actor.OnStage() )
279   {
280     Any nativeWindowHandle = Dali::Integration::SceneHolder::Get( actor ).GetNativeHandle();
281
282 #ifdef ECORE_WAYLAND2
283     windowId = ecore_wl2_window_id_get( AnyCast< Ecore_Wl2_Window* >( nativeWindowHandle ) );
284 #else
285     windowId = ecore_wl_window_id_get( AnyCast< Ecore_Wl_Window* >( nativeWindowHandle ) );
286 #endif
287   }
288
289   return windowId;
290 }
291
292 BaseHandle Create()
293 {
294   return Dali::InputMethodContext::New( Dali::Actor() );
295 }
296
297 Dali::TypeRegistration type( typeid(Dali::InputMethodContext), typeid(Dali::BaseHandle), Create );
298
299 } // unnamed namespace
300
301 InputMethodContextPtr InputMethodContextEcoreWl::New( Dali::Actor actor )
302 {
303   InputMethodContextPtr inputMethodContext;
304
305   // Create instance only if the adaptor is available and the valid actor exists
306   if ( actor && Dali::Adaptor::IsAvailable() )
307   {
308     inputMethodContext = new InputMethodContextEcoreWl( actor );
309   }
310   return inputMethodContext;
311 }
312
313 void InputMethodContextEcoreWl::Finalize()
314 {
315   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::Finalize\n" );
316
317   DisconnectCallbacks();
318   DeleteContext();
319 }
320
321 InputMethodContextEcoreWl::InputMethodContextEcoreWl( Dali::Actor actor )
322 : mIMFContext(),
323   mIMFCursorPosition( 0 ),
324   mSurroundingText(),
325   mRestoreAfterFocusLost( false ),
326   mIdleCallbackConnected( false ),
327   mWindowId( GetWindowIdFromActor( actor ) )
328 {
329   ecore_imf_init();
330
331   actor.OnStageSignal().Connect( this, &InputMethodContextEcoreWl::OnStaged );
332 }
333
334 InputMethodContextEcoreWl::~InputMethodContextEcoreWl()
335 {
336   Finalize();
337   ecore_imf_shutdown();
338 }
339
340 void InputMethodContextEcoreWl::Initialize()
341 {
342   CreateContext();
343   ConnectCallbacks();
344   ApplyBackupOperations();
345 }
346
347 void InputMethodContextEcoreWl::CreateContext()
348 {
349   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::CreateContext\n" );
350
351   if( mWindowId == kUninitializedWindowId )
352   {
353     return;
354   }
355
356   const char *contextId = ecore_imf_context_default_id_get();
357   if( contextId )
358   {
359     mIMFContext = ecore_imf_context_add( contextId );
360
361     if( mIMFContext )
362     {
363       ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast< void* >( mWindowId ) );
364     }
365     else
366     {
367       DALI_LOG_WARNING( "InputMethodContext Unable to get IMFContext\n" );
368     }
369   }
370   else
371   {
372     DALI_LOG_WARNING( "InputMethodContext Unable to get IMFContext\n" );
373   }
374 }
375
376 void InputMethodContextEcoreWl::DeleteContext()
377 {
378   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteContext\n" );
379
380   if ( mIMFContext )
381   {
382     ecore_imf_context_del( mIMFContext );
383     mIMFContext = NULL;
384   }
385 }
386
387 // Callbacks for predicitive text support.
388 void InputMethodContextEcoreWl::ConnectCallbacks()
389 {
390   if ( mIMFContext )
391   {
392     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ConnectCallbacks\n" );
393
394     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,      PreEdit,    this );
395     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,               Commit,     this );
396     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING,   ImfDeleteSurrounding, this );
397     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand, this );
398     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT,       CommitContent, this );
399
400     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback, this );
401     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback, this );
402     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, this );
403     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback, this );
404
405     ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
406   }
407 }
408
409 void InputMethodContextEcoreWl::DisconnectCallbacks()
410 {
411   if ( mIMFContext )
412   {
413     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DisconnectCallbacks\n" );
414
415     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,      PreEdit );
416     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,               Commit );
417     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING,   ImfDeleteSurrounding );
418     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand );
419     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT,       CommitContent );
420
421     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback     );
422     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback  );
423     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback );
424     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback );
425
426     // We do not need to unset the retrieve surrounding callback.
427   }
428 }
429
430 void InputMethodContextEcoreWl::Activate()
431 {
432   // Reset mIdleCallbackConnected
433   mIdleCallbackConnected = false;
434
435   if ( mIMFContext )
436   {
437     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Activate\n" );
438
439     ecore_imf_context_focus_in( mIMFContext );
440
441     // emit keyboard activated signal
442     Dali::InputMethodContext handle( this );
443     mActivatedSignal.Emit( handle );
444   }
445 }
446
447 void InputMethodContextEcoreWl::Deactivate()
448 {
449   if( mIMFContext )
450   {
451     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Deactivate\n" );
452
453     Reset();
454     ecore_imf_context_focus_out( mIMFContext );
455   }
456
457   // Reset mIdleCallbackConnected
458   mIdleCallbackConnected = false;
459 }
460
461 void InputMethodContextEcoreWl::Reset()
462 {
463   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Reset\n" );
464
465   if ( mIMFContext )
466   {
467     ecore_imf_context_reset( mIMFContext );
468   }
469 }
470
471 ImfContext* InputMethodContextEcoreWl::GetContext()
472 {
473   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetContext\n" );
474
475   return mIMFContext;
476 }
477
478 bool InputMethodContextEcoreWl::RestoreAfterFocusLost() const
479 {
480   return mRestoreAfterFocusLost;
481 }
482
483 void InputMethodContextEcoreWl::SetRestoreAfterFocusLost( bool toggle )
484 {
485   mRestoreAfterFocusLost = toggle;
486 }
487
488 /**
489  * Called when an InputMethodContext Pre-Edit changed event is received.
490  * We are still predicting what the user is typing.  The latest string is what the InputMethodContext module thinks
491  * the user wants to type.
492  */
493 void InputMethodContextEcoreWl::PreEditChanged( void*, ImfContext* imfContext, void* eventInfo )
494 {
495   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::PreEditChanged\n" );
496   auto context = static_cast<Ecore_IMF_Context*>( imfContext );
497
498   char* preEditString( NULL );
499   int cursorPosition( 0 );
500   Eina_List* attrs = NULL;
501   Eina_List* l = NULL;
502
503   Ecore_IMF_Preedit_Attr* attr;
504
505   mPreeditAttrs.Clear();
506
507   // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
508   // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
509   ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
510
511   if ( attrs )
512   {
513     // iterate through the list of attributes getting the type, start and end position.
514     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) ) ))
515     {
516       Dali::InputMethodContext::PreeditAttributeData data;
517       data.startIndex = 0;
518       data.endIndex = 0;
519
520       size_t visualCharacterIndex = 0;
521       size_t byteIndex = 0;
522
523       // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
524       const char leadByte = preEditString[byteIndex];
525       while( leadByte != '\0' )
526       {
527         // attr->end_index is provided as a byte position not character and we need to know the character position.
528         const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
529         if( byteIndex <= attr->start_index )
530         {
531            data.startIndex = visualCharacterIndex;
532         }
533         if ( byteIndex >= attr->end_index )
534         {
535           data.endIndex = visualCharacterIndex;
536           break;
537           // end loop as found cursor position that matches byte position
538         }
539         else
540         {
541           byteIndex += currentSequenceLength; // jump to next character
542           visualCharacterIndex++;  // increment character count so we know our position for when we get a match
543         }
544       }
545
546       switch( attr->preedit_type )
547       {
548         case ECORE_IMF_PREEDIT_TYPE_NONE:
549         {
550           data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
551           break;
552         }
553         case ECORE_IMF_PREEDIT_TYPE_SUB1:
554         {
555           data.preeditType = Dali::InputMethodContext::PreeditStyle::UNDERLINE;
556           break;
557         }
558         case ECORE_IMF_PREEDIT_TYPE_SUB2:
559         {
560           data.preeditType = Dali::InputMethodContext::PreeditStyle::REVERSE;
561           break;
562         }
563         case ECORE_IMF_PREEDIT_TYPE_SUB3:
564         {
565           data.preeditType = Dali::InputMethodContext::PreeditStyle::HIGHLIGHT;
566           break;
567         }
568         case ECORE_IMF_PREEDIT_TYPE_SUB4:
569         {
570           data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1;
571           break;
572         }
573         case ECORE_IMF_PREEDIT_TYPE_SUB5:
574         {
575           data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2;
576           break;
577         }
578         case ECORE_IMF_PREEDIT_TYPE_SUB6:
579         {
580           data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3;
581           break;
582         }
583         case ECORE_IMF_PREEDIT_TYPE_SUB7:
584         {
585           data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4;
586           break;
587         }
588         default:
589         {
590           data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
591           break;
592         }
593       }
594       mPreeditAttrs.PushBack( data );
595     }
596   }
597
598   if ( Dali::Adaptor::IsAvailable() )
599   {
600     Dali::InputMethodContext handle( this );
601     Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
602     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
603
604     if ( callbackData.update )
605     {
606       SetCursorPosition( callbackData.cursorPosition );
607       SetSurroundingText( callbackData.currentText );
608
609       NotifyCursorPosition();
610     }
611
612     if ( callbackData.preeditResetRequired )
613     {
614       Reset();
615     }
616   }
617   free( preEditString );
618 }
619
620 void InputMethodContextEcoreWl::CommitReceived( void*, ImfContext* imfContext, void* eventInfo )
621 {
622   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::CommitReceived\n" );
623
624   if ( Dali::Adaptor::IsAvailable() )
625   {
626     const std::string keyString( static_cast<char*>( eventInfo ) );
627
628     Dali::InputMethodContext handle( this );
629     Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
630     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
631
632     if( callbackData.update )
633     {
634       SetCursorPosition( callbackData.cursorPosition );
635       SetSurroundingText( callbackData.currentText );
636
637       NotifyCursorPosition();
638     }
639   }
640 }
641
642 /**
643  * Called when an InputMethodContext retrieve surround event is received.
644  * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
645  * We need to signal the application to tell us this information.
646  */
647 bool InputMethodContextEcoreWl::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
648 {
649   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::RetrieveSurrounding\n" );
650
651   Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
652   Dali::InputMethodContext handle( this );
653   Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
654
655   if( callbackData.update )
656   {
657     if( cursorPosition )
658     {
659       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
660       *cursorPosition = mIMFCursorPosition;
661     }
662
663     if( text )
664     {
665       const char* plainText = callbackData.currentText.c_str();
666
667       if( plainText )
668       {
669         // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
670         *text = strdup( plainText );
671
672         // If the current input panel is password mode, dali should replace the plain text with '*' (Asterisk) character.
673         if( ( ecore_imf_context_input_hint_get( mIMFContext ) & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA ) && *text )
674         {
675           for( char* iter = *text; *iter; ++iter )
676           {
677             *iter = '*';
678           }
679         }
680
681         return EINA_TRUE;
682       }
683     }
684   }
685
686   return EINA_FALSE;
687 }
688
689 /**
690  * Called when an InputMethodContext delete surrounding event is received.
691  * Here we tell the application that it should delete a certain range.
692  */
693 void InputMethodContextEcoreWl::DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo )
694 {
695   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteSurrounding\n" );
696
697   if( Dali::Adaptor::IsAvailable() )
698   {
699     Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( eventInfo );
700
701     Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
702     Dali::InputMethodContext handle( this );
703     mEventSignal.Emit( handle, imfData );
704   }
705 }
706
707 /**
708  * Called when the input method sends a private command.
709  */
710 void InputMethodContextEcoreWl::SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo )
711 {
712   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendPrivateCommand\n" );
713
714   if( Dali::Adaptor::IsAvailable() )
715   {
716     const char* privateCommandSendEvent = static_cast<const char*>( eventInfo );
717
718     Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::PRIVATE_COMMAND, privateCommandSendEvent, 0, 0 );
719     Dali::InputMethodContext handle( this );
720     mEventSignal.Emit( handle, imfData );
721   }
722 }
723
724 /**
725  * Called when the input method commits content, such as an image.
726  */
727 void InputMethodContextEcoreWl::SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo )
728 {
729   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent\n" );
730
731   if( Dali::Adaptor::IsAvailable() )
732   {
733     Ecore_IMF_Event_Commit_Content* commitContent = static_cast<Ecore_IMF_Event_Commit_Content *>( eventInfo );
734     if( commitContent )
735     {
736       DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent commit content : %s, description : %s, mime type : %s\n",
737                                                  commitContent->content_uri, commitContent->description, commitContent->mime_types );
738       mContentReceivedSignal.Emit( commitContent->content_uri, commitContent->description, commitContent->mime_types );
739     }
740   }
741 }
742
743 void InputMethodContextEcoreWl::NotifyCursorPosition()
744 {
745   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::NotifyCursorPosition\n" );
746
747   if( mIMFContext )
748   {
749     ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
750   }
751 }
752
753 void InputMethodContextEcoreWl::SetCursorPosition( unsigned int cursorPosition )
754 {
755   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetCursorPosition\n" );
756
757   mIMFCursorPosition = static_cast<int>( cursorPosition );
758 }
759
760 unsigned int InputMethodContextEcoreWl::GetCursorPosition() const
761 {
762   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetCursorPosition\n" );
763
764   return static_cast<unsigned int>( mIMFCursorPosition );
765 }
766
767 void InputMethodContextEcoreWl::SetSurroundingText( const std::string& text )
768 {
769   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetSurroundingText\n" );
770
771   mSurroundingText = text;
772 }
773
774 const std::string& InputMethodContextEcoreWl::GetSurroundingText() const
775 {
776   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetSurroundingText\n" );
777
778   return mSurroundingText;
779 }
780
781 void InputMethodContextEcoreWl::NotifyTextInputMultiLine( bool multiLine )
782 {
783   if( mIMFContext )
784   {
785     Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
786     ecore_imf_context_input_hint_set( mIMFContext,
787                                       static_cast< Ecore_IMF_Input_Hints >( multiLine ?
788                                         (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) :
789                                         (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
790   }
791
792   mBackupOperations[Operation::NOTIFY_TEXT_INPUT_MULTILINE] = std::bind( &InputMethodContextEcoreWl::NotifyTextInputMultiLine, this, multiLine );
793 }
794
795 Dali::InputMethodContext::TextDirection InputMethodContextEcoreWl::GetTextDirection()
796 {
797   Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
798
799     if ( mIMFContext )
800     {
801       char* locale( NULL );
802       ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
803
804       if ( locale )
805       {
806         direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
807         free( locale );
808       }
809     }
810
811   return direction;
812 }
813
814 Rect<int> InputMethodContextEcoreWl::GetInputMethodArea()
815 {
816   int xPos, yPos, width, height;
817
818   width = height = xPos = yPos = 0;
819
820   if( mIMFContext )
821   {
822     ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
823   }
824   else
825   {
826     DALI_LOG_WARNING("VKB Unable to get IMFContext so GetSize unavailable\n");
827   // return 0 as real size unknown.
828   }
829
830   return Rect<int>(xPos,yPos,width,height);
831 }
832
833 void InputMethodContextEcoreWl::ApplyOptions( const InputMethodOptions& options )
834 {
835   using namespace Dali::InputMethod::Category;
836
837   int index;
838
839   if( mIMFContext == NULL )
840   {
841     DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
842     return;
843   }
844
845   if( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
846   {
847     ecore_imf_context_input_panel_layout_set( mIMFContext, panelLayoutMap[index] );
848
849     // Sets the input hint which allows input methods to fine-tune their behavior.
850     if( panelLayoutMap[index] == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD )
851     {
852       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 ) );
853     }
854     else
855     {
856       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 ) );
857     }
858   }
859   if( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
860   {
861     ecore_imf_context_input_panel_return_key_type_set( mIMFContext, returnKeyTypeMap[index] );
862   }
863   if( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
864   {
865     ecore_imf_context_autocapital_type_set( mIMFContext, autoCapitalMap[index] );
866   }
867   if( mOptions.CompareAndSet(VARIATION, options, index) )
868   {
869     ecore_imf_context_input_panel_layout_variation_set( mIMFContext, index );
870   }
871 }
872
873 void InputMethodContextEcoreWl::SetInputPanelData( const std::string& data )
874 {
875   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelData\n" );
876
877   if( mIMFContext )
878   {
879     int length = data.length();
880     ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
881   }
882
883   mBackupOperations[Operation::SET_INPUT_PANEL_DATA] = std::bind( &InputMethodContextEcoreWl::SetInputPanelData, this, data );
884 }
885
886 void InputMethodContextEcoreWl::GetInputPanelData( std::string& data )
887 {
888   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelData\n" );
889
890   if( mIMFContext )
891   {
892     int length = 4096; // The max length is 4096 bytes
893     Dali::Vector< char > buffer;
894     buffer.Resize( length );
895     ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
896     data = std::string( buffer.Begin(), buffer.End() );
897   }
898 }
899
900 Dali::InputMethodContext::State InputMethodContextEcoreWl::GetInputPanelState()
901 {
902   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelState\n" );
903
904   if( mIMFContext )
905   {
906     int value;
907     value = ecore_imf_context_input_panel_state_get( mIMFContext );
908
909     switch (value)
910     {
911       case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
912       {
913         return Dali::InputMethodContext::SHOW;
914         break;
915       }
916
917       case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
918       {
919         return Dali::InputMethodContext::HIDE;
920         break;
921       }
922
923       case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
924       {
925         return Dali::InputMethodContext::WILL_SHOW;
926         break;
927       }
928
929       default:
930       {
931         return Dali::InputMethodContext::DEFAULT;
932       }
933     }
934   }
935   return Dali::InputMethodContext::DEFAULT;
936 }
937
938 void InputMethodContextEcoreWl::SetReturnKeyState( bool visible )
939 {
940   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetReturnKeyState\n" );
941
942   if( mIMFContext )
943   {
944     ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
945   }
946
947   mBackupOperations[Operation::SET_RETURN_KEY_STATE] = std::bind( &InputMethodContextEcoreWl::SetReturnKeyState, this, visible );
948 }
949
950 void InputMethodContextEcoreWl::AutoEnableInputPanel( bool enabled )
951 {
952   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AutoEnableInputPanel\n" );
953
954   if( mIMFContext )
955   {
956     ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
957   }
958
959   mBackupOperations[Operation::AUTO_ENABLE_INPUT_PANEL] = std::bind( &InputMethodContextEcoreWl::AutoEnableInputPanel, this, enabled );
960 }
961
962 void InputMethodContextEcoreWl::ShowInputPanel()
963 {
964   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ShowInputPanel\n" );
965
966   if( mIMFContext )
967   {
968     ecore_imf_context_input_panel_show( mIMFContext );
969   }
970 }
971
972 void InputMethodContextEcoreWl::HideInputPanel()
973 {
974   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::HideInputPanel\n" );
975
976   if( mIMFContext )
977   {
978     ecore_imf_context_input_panel_hide( mIMFContext );
979   }
980 }
981
982 Dali::InputMethodContext::KeyboardType InputMethodContextEcoreWl::GetKeyboardType()
983 {
984   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetKeyboardType\n" );
985
986   if( mIMFContext )
987   {
988     int value;
989     value = ecore_imf_context_keyboard_mode_get( mIMFContext );
990
991     switch (value)
992     {
993       case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
994       {
995         return Dali::InputMethodContext::SOFTWARE_KEYBOARD;
996         break;
997       }
998       case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
999       {
1000         return Dali::InputMethodContext::HARDWARE_KEYBOARD;
1001         break;
1002       }
1003     }
1004   }
1005
1006   return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
1007 }
1008
1009 std::string InputMethodContextEcoreWl::GetInputPanelLocale()
1010 {
1011   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLocale\n" );
1012
1013   std::string locale = "";
1014
1015   if( mIMFContext )
1016   {
1017     char* value = NULL;
1018     ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
1019
1020     if( value )
1021     {
1022       std::string valueCopy( value );
1023       locale = valueCopy;
1024
1025       // The locale string retrieved must be freed with free().
1026       free( value );
1027     }
1028   }
1029   return locale;
1030 }
1031
1032 void InputMethodContextEcoreWl::SetContentMIMETypes( const std::string& mimeTypes )
1033 {
1034   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetContentMIMETypes\n" );
1035
1036   if( mIMFContext )
1037   {
1038     ecore_imf_context_mime_type_accept_set( mIMFContext, mimeTypes.c_str() );
1039   }
1040
1041   mBackupOperations[Operation::SET_CONTENT_MIME_TYPES] = std::bind( &InputMethodContextEcoreWl::SetContentMIMETypes, this, mimeTypes );
1042 }
1043
1044 bool InputMethodContextEcoreWl::FilterEventKey( const Dali::KeyEvent& keyEvent )
1045 {
1046   bool eventHandled( false );
1047
1048   // If a device key then skip ecore_imf_context_filter_event.
1049   if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))
1050   {
1051     //check whether it's key down or key up event
1052     if ( keyEvent.state == KeyEvent::Down )
1053     {
1054       eventHandled = ProcessEventKeyDown( keyEvent );
1055     }
1056     else if ( keyEvent.state == KeyEvent::Up )
1057     {
1058       eventHandled = ProcessEventKeyUp( keyEvent );
1059     }
1060   }
1061
1062   return eventHandled;
1063 }
1064
1065 void InputMethodContextEcoreWl::AllowTextPrediction( bool prediction )
1066 {
1067   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AllowTextPrediction\n" );
1068
1069   if( mIMFContext )
1070   {
1071     ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
1072   }
1073
1074   mBackupOperations[Operation::ALLOW_TEXT_PREDICTION] = std::bind( &InputMethodContextEcoreWl::AllowTextPrediction, this, prediction );
1075 }
1076
1077 bool InputMethodContextEcoreWl::IsTextPredictionAllowed() const
1078 {
1079   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::IsTextPredictionAllowed\n" );
1080   bool prediction = false;
1081   if( mIMFContext )
1082   {
1083     prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
1084   }
1085   return prediction;
1086 }
1087
1088 void InputMethodContextEcoreWl::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
1089 {
1090   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelLanguage\n" );
1091   if( mIMFContext )
1092   {
1093     switch (language)
1094     {
1095       case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
1096       {
1097         ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC );
1098         break;
1099       }
1100       case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
1101       {
1102         ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET );
1103         break;
1104       }
1105     }
1106   }
1107
1108   mBackupOperations[Operation::SET_INPUT_PANEL_LANGUAGE] = std::bind( &InputMethodContextEcoreWl::SetInputPanelLanguage, this, language );
1109 }
1110
1111 Dali::InputMethodContext::InputPanelLanguage InputMethodContextEcoreWl::GetInputPanelLanguage() const
1112 {
1113   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLanguage\n" );
1114   if( mIMFContext )
1115   {
1116     int value;
1117     value =  ecore_imf_context_input_panel_language_get( mIMFContext );
1118
1119     switch (value)
1120     {
1121       case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
1122       {
1123         return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
1124         break;
1125       }
1126       case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
1127       {
1128         return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
1129         break;
1130       }
1131     }
1132   }
1133   return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
1134 }
1135
1136 void InputMethodContextEcoreWl::SetInputPanelPosition( unsigned int x, unsigned int y )
1137 {
1138   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelPosition\n" );
1139
1140   if( mIMFContext )
1141   {
1142     ecore_imf_context_input_panel_position_set( mIMFContext, x, y );
1143   }
1144
1145   mBackupOperations[Operation::SET_INPUT_PANEL_POSITION] = std::bind( &InputMethodContextEcoreWl::SetInputPanelPosition, this, x, y );
1146 }
1147
1148 void InputMethodContextEcoreWl::GetPreeditStyle( Vector< Dali::InputMethodContext::PreeditAttributeData >& attrs ) const
1149 {
1150   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetPreeditStyle\n" );
1151   attrs = mPreeditAttrs;
1152 }
1153
1154 bool InputMethodContextEcoreWl::ProcessEventKeyDown( const KeyEvent& keyEvent )
1155 {
1156   bool eventHandled( false );
1157   if ( mIMFContext )
1158   {
1159     Integration::KeyEvent integKeyEvent( keyEvent );
1160     std::string key = integKeyEvent.logicalKey;
1161
1162     std::string compose = keyEvent.GetCompose();
1163     std::string deviceName = keyEvent.GetDeviceName();
1164
1165     // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
1166     Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
1167     ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
1168     ecoreKeyDownEvent.key = key.c_str();
1169     ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
1170     ecoreKeyDownEvent.compose = compose.c_str();
1171     ecoreKeyDownEvent.timestamp = keyEvent.time;
1172     ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
1173     ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
1174     ecoreKeyDownEvent.dev_name = deviceName.c_str();
1175     ecoreKeyDownEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1176     ecoreKeyDownEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
1177 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
1178     ecoreKeyDownEvent.keycode = keyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
1179 #endif // Since ecore_imf 1.22 version
1180
1181     // 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.
1182     if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
1183                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
1184                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
1185                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
1186     {
1187       eventHandled = 0;
1188     }
1189     else
1190     {
1191       eventHandled = ecore_imf_context_filter_event(mIMFContext,
1192                                                     ECORE_IMF_EVENT_KEY_DOWN,
1193                                                     reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ) );
1194     }
1195
1196     // If the event has not been handled by InputMethodContext then check if we should reset our input method context
1197     if (!eventHandled)
1198     {
1199       if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
1200           !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
1201           !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
1202       {
1203         ecore_imf_context_reset(mIMFContext);
1204       }
1205     }
1206   }
1207   return eventHandled;
1208 }
1209
1210 bool InputMethodContextEcoreWl::ProcessEventKeyUp( const KeyEvent& keyEvent )
1211 {
1212   bool eventHandled( false );
1213   if( mIMFContext )
1214   {
1215     Integration::KeyEvent integKeyEvent( keyEvent );
1216     std::string key = integKeyEvent.logicalKey;
1217
1218     std::string compose = keyEvent.GetCompose();
1219     std::string deviceName = keyEvent.GetDeviceName();
1220
1221     // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
1222     Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
1223     ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
1224     ecoreKeyUpEvent.key = key.c_str();
1225     ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
1226     ecoreKeyUpEvent.compose = compose.c_str();
1227     ecoreKeyUpEvent.timestamp = keyEvent.time;
1228     ecoreKeyUpEvent.modifiers =  EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
1229     ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
1230     ecoreKeyUpEvent.dev_name = deviceName.c_str();
1231     ecoreKeyUpEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1232     ecoreKeyUpEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
1233 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
1234     ecoreKeyUpEvent.keycode = keyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
1235 #endif // Since ecore_imf 1.22 version
1236
1237     eventHandled = ecore_imf_context_filter_event(mIMFContext,
1238                                                   ECORE_IMF_EVENT_KEY_UP,
1239                                                   reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ) );
1240   }
1241   return eventHandled;
1242 }
1243
1244 Ecore_IMF_Keyboard_Modifiers InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
1245 {
1246   unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE );  // If no other matches returns NONE.
1247
1248   if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT )  // enums from ecore_input/Ecore_Input.h
1249   {
1250     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;  // enums from ecore_imf/ecore_imf.h
1251   }
1252
1253   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
1254   {
1255     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
1256   }
1257
1258   if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
1259   {
1260     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
1261   }
1262
1263   if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
1264   {
1265     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
1266   }
1267
1268   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
1269   {
1270     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
1271   }
1272
1273   return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
1274 }
1275
1276 Ecore_IMF_Keyboard_Locks InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
1277 {
1278     unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
1279
1280     if( modifier & ECORE_EVENT_LOCK_NUM )
1281     {
1282       lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
1283     }
1284
1285     if( modifier & ECORE_EVENT_LOCK_CAPS )
1286     {
1287       lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
1288     }
1289
1290     if( modifier & ECORE_EVENT_LOCK_SCROLL )
1291     {
1292       lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
1293     }
1294
1295     return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
1296 }
1297
1298 void InputMethodContextEcoreWl::OnStaged( Dali::Actor actor )
1299 {
1300   int windowId = GetWindowIdFromActor( actor );
1301
1302   if( mWindowId != windowId )
1303   {
1304     mWindowId = windowId;
1305
1306     // Reset
1307     Finalize();
1308     Initialize();
1309   }
1310 }
1311
1312 } // Adaptor
1313
1314 } // Internal
1315
1316 } // Dali