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