Implement base class to enable EvasPlugin to create the scene for rendering
[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 #include <dali/public-api/events/key-event.h>
26 #include <dali/public-api/adaptor-framework/key.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/integration-api/debug.h>
29
30 // INTERNAL INCLUDES
31 #include <dali/integration-api/adaptor.h>
32 #include <dali/internal/system/common/locale-utils.h>
33 #include <dali/internal/system/common/singleton-service-impl.h>
34 #include <dali/public-api/adaptor-framework/input-method.h>
35 #include <dali/internal/input/common/key-impl.h>
36 #include <dali/internal/window-system/common/window-render-surface.h>
37
38 #define TOKEN_STRING(x) #x
39
40 Ecore_IMF_Input_Panel_Layout panelLayoutMap[] =
41 {
42    ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL,
43    ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER,
44    ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL,
45    ECORE_IMF_INPUT_PANEL_LAYOUT_URL,
46    ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER,
47    ECORE_IMF_INPUT_PANEL_LAYOUT_IP,
48    ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH,
49    ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY,
50    ECORE_IMF_INPUT_PANEL_LAYOUT_HEX,
51    ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL,
52    ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD,
53    ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME,
54    ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON,
55    ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE
56 };
57
58 Ecore_IMF_Autocapital_Type autoCapitalMap[] =
59 {
60    ECORE_IMF_AUTOCAPITAL_TYPE_NONE,
61    ECORE_IMF_AUTOCAPITAL_TYPE_WORD,
62    ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE,
63    ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER,
64 };
65
66 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyTypeMap[] =
67 {
68    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT,
69    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE,
70    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO,
71    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN,
72    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN,
73    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT,
74    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH,
75    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND,
76    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN
77 };
78
79 namespace Dali
80 {
81
82 namespace Internal
83 {
84
85 namespace Adaptor
86 {
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 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
95 size_t Utf8SequenceLength(const unsigned char leadByte)
96 {
97   size_t length = 0;
98
99   if ((leadByte & 0x80) == 0 )          //ASCII character (lead bit zero)
100   {
101     length = 1;
102   }
103   else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
104   {
105     length = 2;
106   }
107   else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
108   {
109     length = 3;
110   }
111   else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
112   {
113     length = 4;
114   }
115
116   return length;
117 }
118
119 // Static function calls used by ecore 'c' style callback registration
120 void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
121 {
122   if ( data )
123   {
124     InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
125     inputMethodContext->CommitReceived( data, imfContext, event_info );
126   }
127 }
128
129 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
130 {
131   if ( data )
132   {
133     InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
134     inputMethodContext->PreEditChanged( data, imfContext, event_info );
135   }
136 }
137
138 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
139 {
140   if ( data )
141   {
142     InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
143     return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
144   }
145   else
146   {
147     return false;
148   }
149 }
150
151 void InputPanelStateChangeCallback( void* data, Ecore_IMF_Context* context, int value )
152 {
153   if (!data)
154   {
155     return;
156   }
157   InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
158   switch (value)
159   {
160     case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
161     {
162       inputMethodContext->StatusChangedSignal().Emit( true );
163       break;
164     }
165
166     case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
167     {
168       inputMethodContext->StatusChangedSignal().Emit( false );
169       break;
170     }
171
172     case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
173     default:
174     {
175       // Do nothing
176       break;
177     }
178   }
179 }
180
181 void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value )
182 {
183   if (!data)
184   {
185     return;
186   }
187   InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
188   // Emit the signal that the language has changed
189   inputMethodContext->LanguageChangedSignal().Emit(value);
190 }
191
192 void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value )
193 {
194   if (!data)
195   {
196     return;
197   }
198   InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
199   // Emit signal that the keyboard is resized
200   inputMethodContext->ResizedSignal().Emit(value);
201 }
202
203 void InputPanelKeyboardTypeChangedCallback( void *data, Ecore_IMF_Context *context, int value )
204 {
205   if( !data )
206   {
207     return;
208   }
209
210   InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
211   switch (value)
212   {
213     case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
214     {
215       // Emit Signal that the keyboard type is changed to Software Keyboard
216       inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD );
217       break;
218     }
219     case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
220     {
221       // Emit Signal that the keyboard type is changed to Hardware Keyboard
222       inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::HARDWARE_KEYBOARD );
223       break;
224     }
225   }
226 }
227
228 /**
229  * Called when an IMF delete surrounding event is received.
230  * Here we tell the application that it should delete a certain range.
231  */
232 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
233 {
234   if ( data )
235   {
236     InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
237     inputMethodContext->DeleteSurrounding( data, imfContext, event_info );
238   }
239 }
240
241 /**
242  * Called when the input method sends a private command.
243  */
244 void PrivateCommand( void *data, Ecore_IMF_Context *imfContext, void *event_info )
245 {
246   if ( data )
247   {
248     InputMethodContextEcoreWl* inputMethodContext = reinterpret_cast< InputMethodContextEcoreWl* > ( data );
249     inputMethodContext->SendPrivateCommand( data, imfContext, event_info );
250   }
251 }
252
253 BaseHandle Create()
254 {
255   return Dali::InputMethodContext::New();
256 }
257
258 Dali::TypeRegistration type( typeid(Dali::InputMethodContext), typeid(Dali::BaseHandle), Create );
259
260 } // unnamed namespace
261
262 InputMethodContextPtr InputMethodContextEcoreWl::New()
263 {
264   InputMethodContextPtr inputMethodContext;
265
266   // Create instance only if the adaptor is available
267   if ( Dali::Adaptor::IsAvailable() )
268   {
269     Any nativeWindow = Dali::Adaptor::Get().GetNativeWindowHandle();
270
271     // The window needs to use the InputMethodContext.
272     // Only when the render surface is window, we can get the window.
273     if( !nativeWindow.Empty() )
274     {
275       inputMethodContext = new InputMethodContextEcoreWl();
276     }
277     else
278     {
279       DALI_LOG_ERROR("Failed to get native window handle, can't create InputMethodContext instance.\n");
280     }
281   }
282   return inputMethodContext;
283 }
284
285 void InputMethodContextEcoreWl::Finalize()
286 {
287   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::Finalize\n" );
288
289   DisconnectCallbacks();
290   DeleteContext();
291 }
292
293 InputMethodContextEcoreWl::InputMethodContextEcoreWl()
294 : mIMFContext(),
295   mIMFCursorPosition( 0 ),
296   mSurroundingText(),
297   mRestoreAfterFocusLost( false ),
298   mIdleCallbackConnected( false )
299 {
300   ecore_imf_init();
301 }
302
303 InputMethodContextEcoreWl::~InputMethodContextEcoreWl()
304 {
305   Finalize();
306   ecore_imf_shutdown();
307 }
308
309 void InputMethodContextEcoreWl::Initialize()
310 {
311   CreateContext();
312   ConnectCallbacks();
313 }
314
315 void InputMethodContextEcoreWl::CreateContext()
316 {
317   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::CreateContext\n" );
318
319   const char *contextId = ecore_imf_context_default_id_get();
320   if( contextId )
321   {
322     mIMFContext = ecore_imf_context_add( contextId );
323
324     if( mIMFContext )
325     {
326       // If we fail to get window id, we can't use the InputMethodContext correctly.
327       // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
328       // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
329       Dali::RenderSurfaceInterface& renderSurface = Dali::Adaptor::Get().GetSurface();
330       WindowRenderSurface& windowRenderSurface = static_cast< WindowRenderSurface& >( renderSurface );
331
332       int windowId = windowRenderSurface.GetNativeWindowId();
333       if( windowId != 0 )
334       {
335         ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast< void* >( windowId ) );
336       }
337     }
338     else
339     {
340       DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
341     }
342   }
343   else
344   {
345     DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
346   }
347 }
348
349 void InputMethodContextEcoreWl::DeleteContext()
350 {
351   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteContext\n" );
352
353   if ( mIMFContext )
354   {
355     ecore_imf_context_del( mIMFContext );
356     mIMFContext = NULL;
357   }
358 }
359
360 // Callbacks for predicitive text support.
361 void InputMethodContextEcoreWl::ConnectCallbacks()
362 {
363   if ( mIMFContext )
364   {
365     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ConnectCallbacks\n" );
366
367     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,      PreEdit,    this );
368     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,               Commit,     this );
369     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING,   ImfDeleteSurrounding, this );
370     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand, this );
371
372     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback, this );
373     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback, this );
374     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, this );
375     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback, this );
376
377     ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
378   }
379 }
380
381 void InputMethodContextEcoreWl::DisconnectCallbacks()
382 {
383   if ( mIMFContext )
384   {
385     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DisconnectCallbacks\n" );
386
387     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,      PreEdit );
388     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,               Commit );
389     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING,   ImfDeleteSurrounding );
390     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand );
391
392     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback     );
393     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback  );
394     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback );
395     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback );
396
397     // We do not need to unset the retrieve surrounding callback.
398   }
399 }
400
401 void InputMethodContextEcoreWl::Activate()
402 {
403   // Reset mIdleCallbackConnected
404   mIdleCallbackConnected = false;
405
406   if ( mIMFContext )
407   {
408     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Activate\n" );
409
410     ecore_imf_context_focus_in( mIMFContext );
411
412     // emit keyboard activated signal
413     Dali::InputMethodContext handle( this );
414     mActivatedSignal.Emit( handle );
415   }
416 }
417
418 void InputMethodContextEcoreWl::Deactivate()
419 {
420   if( mIMFContext )
421   {
422     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Deactivate\n" );
423
424     Reset();
425     ecore_imf_context_focus_out( mIMFContext );
426   }
427
428   // Reset mIdleCallbackConnected
429   mIdleCallbackConnected = false;
430 }
431
432 void InputMethodContextEcoreWl::Reset()
433 {
434   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Reset\n" );
435
436   if ( mIMFContext )
437   {
438     ecore_imf_context_reset( mIMFContext );
439   }
440 }
441
442 ImfContext* InputMethodContextEcoreWl::GetContext()
443 {
444   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetContext\n" );
445
446   return mIMFContext;
447 }
448
449 bool InputMethodContextEcoreWl::RestoreAfterFocusLost() const
450 {
451   return mRestoreAfterFocusLost;
452 }
453
454 void InputMethodContextEcoreWl::SetRestoreAfterFocusLost( bool toggle )
455 {
456   mRestoreAfterFocusLost = toggle;
457 }
458
459 /**
460  * Called when an InputMethodContext Pre-Edit changed event is received.
461  * We are still predicting what the user is typing.  The latest string is what the InputMethodContext module thinks
462  * the user wants to type.
463  */
464 void InputMethodContextEcoreWl::PreEditChanged( void*, ImfContext* imfContext, void* event_info )
465 {
466   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::PreEditChanged\n" );
467   auto context = reinterpret_cast<Ecore_IMF_Context*>(imfContext);
468
469   char* preEditString( NULL );
470   int cursorPosition( 0 );
471   Eina_List* attrs = NULL;
472   Eina_List* l = NULL;
473
474   Ecore_IMF_Preedit_Attr* attr;
475
476   // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
477   // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
478   ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
479
480   if ( attrs )
481   {
482     // iterate through the list of attributes getting the type, start and end position.
483     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) ) ))
484     {
485 #ifdef DALI_PROFILE_UBUNTU
486       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
487 #else // DALI_PROFILE_UBUNTU
488       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
489 #endif // DALI_PROFILE_UBUNTU
490       {
491         // check first byte so know how many bytes a character is represented by as keyboard returns cursor position in bytes. Which is different for some languages.
492
493         size_t visualCharacterIndex = 0;
494         size_t byteIndex = 0;
495
496         // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
497         const char leadByte = preEditString[byteIndex];
498         while( leadByte != '\0' )
499         {
500           // attr->end_index is provided as a byte position not character and we need to know the character position.
501           const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
502           if ( byteIndex == attr->end_index )
503           {
504             cursorPosition = visualCharacterIndex;
505             break;
506             // end loop as found cursor position that matches byte position
507           }
508           else
509           {
510             byteIndex += currentSequenceLength; // jump to next character
511             visualCharacterIndex++;  // increment character count so we know our position for when we get a match
512           }
513
514           DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
515         }
516       }
517     }
518   }
519
520   if ( Dali::Adaptor::IsAvailable() )
521   {
522     Dali::InputMethodContext handle( this );
523     Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
524     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
525
526     if ( callbackData.update )
527     {
528       SetCursorPosition( callbackData.cursorPosition );
529       SetSurroundingText( callbackData.currentText );
530
531       NotifyCursorPosition();
532     }
533
534     if ( callbackData.preeditResetRequired )
535     {
536       Reset();
537     }
538   }
539   free( preEditString );
540 }
541
542 void InputMethodContextEcoreWl::CommitReceived( void*, ImfContext* imfContext, void* event_info )
543 {
544   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::CommitReceived\n" );
545
546   if ( Dali::Adaptor::IsAvailable() )
547   {
548     const std::string keyString( static_cast<char*>( event_info ) );
549
550     Dali::InputMethodContext handle( this );
551     Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
552     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
553
554     if( callbackData.update )
555     {
556       SetCursorPosition( callbackData.cursorPosition );
557       SetSurroundingText( callbackData.currentText );
558
559       NotifyCursorPosition();
560     }
561   }
562 }
563
564 /**
565  * Called when an InputMethodContext retrieve surround event is received.
566  * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
567  * We need to signal the application to tell us this information.
568  */
569 bool InputMethodContextEcoreWl::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
570 {
571   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::RetrieveSurrounding\n" );
572
573   Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
574   Dali::InputMethodContext handle( this );
575   Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
576
577   if( callbackData.update )
578   {
579     if( text )
580     {
581       // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
582       *text = strdup( callbackData.currentText.c_str() );
583     }
584
585     if( cursorPosition )
586     {
587       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
588       *cursorPosition = mIMFCursorPosition;
589     }
590   }
591
592   return EINA_TRUE;
593 }
594
595 /**
596  * Called when an InputMethodContext delete surrounding event is received.
597  * Here we tell the application that it should delete a certain range.
598  */
599 void InputMethodContextEcoreWl::DeleteSurrounding( void* data, ImfContext* imfContext, void* event_info )
600 {
601   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteSurrounding\n" );
602
603   if( Dali::Adaptor::IsAvailable() )
604   {
605     Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( event_info );
606
607     Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
608     Dali::InputMethodContext handle( this );
609     mEventSignal.Emit( handle, imfData );
610   }
611 }
612
613 /**
614  * Called when the input method sends a private command.
615  */
616 void InputMethodContextEcoreWl::SendPrivateCommand( void* data, ImfContext* imfContext, void* event_info )
617 {
618   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendPrivateCommand\n" );
619
620   if( Dali::Adaptor::IsAvailable() )
621   {
622     const char* privateCommandSendEvent = static_cast<const char*>( event_info );
623
624     Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::PRIVATE_COMMAND, privateCommandSendEvent, 0, 0 );
625     Dali::InputMethodContext handle( this );
626     mEventSignal.Emit( handle, imfData );
627   }
628 }
629
630 void InputMethodContextEcoreWl::NotifyCursorPosition()
631 {
632   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::NotifyCursorPosition\n" );
633
634   if( mIMFContext )
635   {
636     ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
637   }
638 }
639
640 void InputMethodContextEcoreWl::SetCursorPosition( unsigned int cursorPosition )
641 {
642   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetCursorPosition\n" );
643
644   mIMFCursorPosition = static_cast<int>( cursorPosition );
645 }
646
647 unsigned int InputMethodContextEcoreWl::GetCursorPosition() const
648 {
649   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetCursorPosition\n" );
650
651   return static_cast<unsigned int>( mIMFCursorPosition );
652 }
653
654 void InputMethodContextEcoreWl::SetSurroundingText( const std::string& text )
655 {
656   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetSurroundingText\n" );
657
658   mSurroundingText = text;
659 }
660
661 const std::string& InputMethodContextEcoreWl::GetSurroundingText() const
662 {
663   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetSurroundingText\n" );
664
665   return mSurroundingText;
666 }
667
668 void InputMethodContextEcoreWl::NotifyTextInputMultiLine( bool multiLine )
669 {
670   Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
671   ecore_imf_context_input_hint_set( mIMFContext,
672                                     static_cast< Ecore_IMF_Input_Hints >( multiLine ?
673                                       (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) :
674                                       (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
675 }
676
677 Dali::InputMethodContext::TextDirection InputMethodContextEcoreWl::GetTextDirection()
678 {
679   Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
680
681     if ( mIMFContext )
682     {
683       char* locale( NULL );
684       ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
685
686       if ( locale )
687       {
688         direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
689         free( locale );
690       }
691     }
692
693   return direction;
694 }
695
696 Rect<int> InputMethodContextEcoreWl::GetInputMethodArea()
697 {
698   int xPos, yPos, width, height;
699
700   width = height = xPos = yPos = 0;
701
702   if( mIMFContext )
703   {
704     ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
705   }
706   else
707   {
708     DALI_LOG_WARNING("VKB Unable to get IMFContext so GetSize unavailable\n");
709   // return 0 as real size unknown.
710   }
711
712   return Rect<int>(xPos,yPos,width,height);
713 }
714
715 void InputMethodContextEcoreWl::ApplyOptions( const InputMethodOptions& options )
716 {
717   using namespace Dali::InputMethod::Category;
718
719   int index;
720
721   if (mIMFContext == NULL)
722   {
723     DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
724     return;
725   }
726
727   if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
728   {
729     ecore_imf_context_input_panel_layout_set( mIMFContext, panelLayoutMap[index] );
730   }
731   if ( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
732   {
733     ecore_imf_context_input_panel_return_key_type_set( mIMFContext, returnKeyTypeMap[index] );
734   }
735   if ( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
736   {
737     ecore_imf_context_autocapital_type_set( mIMFContext, autoCapitalMap[index] );
738   }
739   if ( mOptions.CompareAndSet(VARIATION, options, index) )
740   {
741     ecore_imf_context_input_panel_layout_variation_set( mIMFContext, index );
742   }
743 }
744
745 void InputMethodContextEcoreWl::SetInputPanelData( const std::string& data )
746 {
747   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelData\n" );
748
749   if( mIMFContext )
750   {
751     int length = data.length();
752     ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
753   }
754 }
755
756 void InputMethodContextEcoreWl::GetInputPanelData( std::string& data )
757 {
758   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelData\n" );
759
760   if( mIMFContext )
761   {
762     int length = 4096; // The max length is 4096 bytes
763     Dali::Vector< char > buffer;
764     buffer.Resize( length );
765     ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
766     data = std::string( buffer.Begin(), buffer.End() );
767   }
768 }
769
770 Dali::InputMethodContext::State InputMethodContextEcoreWl::GetInputPanelState()
771 {
772   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelState\n" );
773
774   if( mIMFContext )
775   {
776     int value;
777     value = ecore_imf_context_input_panel_state_get( mIMFContext );
778
779     switch (value)
780     {
781       case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
782       {
783         return Dali::InputMethodContext::SHOW;
784         break;
785       }
786
787       case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
788       {
789         return Dali::InputMethodContext::HIDE;
790         break;
791       }
792
793       case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
794       {
795         return Dali::InputMethodContext::WILL_SHOW;
796         break;
797       }
798
799       default:
800       {
801         return Dali::InputMethodContext::DEFAULT;
802       }
803     }
804   }
805   return Dali::InputMethodContext::DEFAULT;
806 }
807
808 void InputMethodContextEcoreWl::SetReturnKeyState( bool visible )
809 {
810   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetReturnKeyState\n" );
811
812   if( mIMFContext )
813   {
814     ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
815   }
816 }
817
818 void InputMethodContextEcoreWl::AutoEnableInputPanel( bool enabled )
819 {
820   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AutoEnableInputPanel\n" );
821
822   if( mIMFContext )
823   {
824     ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
825   }
826 }
827
828 void InputMethodContextEcoreWl::ShowInputPanel()
829 {
830   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ShowInputPanel\n" );
831
832   if( mIMFContext )
833   {
834     ecore_imf_context_input_panel_show( mIMFContext );
835   }
836 }
837
838 void InputMethodContextEcoreWl::HideInputPanel()
839 {
840   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::HideInputPanel\n" );
841
842   if( mIMFContext )
843   {
844     ecore_imf_context_input_panel_hide( mIMFContext );
845   }
846 }
847
848 Dali::InputMethodContext::KeyboardType InputMethodContextEcoreWl::GetKeyboardType()
849 {
850   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetKeyboardType\n" );
851
852 #ifdef OVER_TIZEN_VERSION_4
853   if( mIMFContext )
854   {
855     int value;
856     value = ecore_imf_context_keyboard_mode_get( mIMFContext );
857
858     switch (value)
859     {
860       case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
861       {
862         return Dali::InputMethodContext::SOFTWARE_KEYBOARD;
863         break;
864       }
865       case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
866       {
867         return Dali::InputMethodContext::HARDWARE_KEYBOARD;
868         break;
869       }
870     }
871   }
872 #endif // OVER_TIZEN_VERSION_4
873   return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
874 }
875
876 std::string InputMethodContextEcoreWl::GetInputPanelLocale()
877 {
878   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLocale\n" );
879
880   std::string locale = "";
881
882   if( mIMFContext )
883   {
884     char* value = NULL;
885     ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
886
887     if( value )
888     {
889       std::string valueCopy( value );
890       locale = valueCopy;
891
892       // The locale string retrieved must be freed with free().
893       free( value );
894     }
895   }
896   return locale;
897 }
898
899 bool InputMethodContextEcoreWl::FilterEventKey( const Dali::KeyEvent& keyEvent )
900 {
901   bool eventHandled( false );
902
903   // If a device key then skip ecore_imf_context_filter_event.
904   if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))
905   {
906     //check whether it's key down or key up event
907     if ( keyEvent.state == KeyEvent::Down )
908     {
909       eventHandled = ProcessEventKeyDown( keyEvent );
910     }
911     else if ( keyEvent.state == KeyEvent::Up )
912     {
913       eventHandled = ProcessEventKeyUp( keyEvent );
914     }
915   }
916
917   return eventHandled;
918 }
919
920 void InputMethodContextEcoreWl::AllowTextPrediction( bool prediction )
921 {
922   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AllowTextPrediction\n" );
923
924   if( mIMFContext )
925   {
926     ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
927   }
928 }
929
930 bool InputMethodContextEcoreWl::IsTextPredictionAllowed() const
931 {
932   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::IsTextPredictionAllowed\n" );
933   bool prediction = false;
934   if( mIMFContext )
935   {
936     prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
937   }
938   return prediction;
939 }
940
941 bool InputMethodContextEcoreWl::ProcessEventKeyDown( const KeyEvent& keyEvent )
942 {
943   bool eventHandled( false );
944   if ( mIMFContext )
945   {
946     Integration::KeyEvent integKeyEvent( keyEvent );
947     std::string key = integKeyEvent.logicalKey;
948
949     std::string compose = keyEvent.GetCompose();
950     std::string deviceName = keyEvent.GetDeviceName();
951
952     // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
953     Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
954     ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
955     ecoreKeyDownEvent.key = key.c_str();
956     ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
957     ecoreKeyDownEvent.compose = compose.c_str();
958     ecoreKeyDownEvent.timestamp = keyEvent.time;
959     ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
960     ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
961     ecoreKeyDownEvent.dev_name = deviceName.c_str();
962     ecoreKeyDownEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
963     ecoreKeyDownEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
964
965     // 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.
966     if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
967                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
968                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
969                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
970     {
971       eventHandled = 0;
972     }
973     else
974     {
975       eventHandled = ecore_imf_context_filter_event(mIMFContext,
976                                                     ECORE_IMF_EVENT_KEY_DOWN,
977                                                     reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ) );
978     }
979
980     // If the event has not been handled by InputMethodContext then check if we should reset our input method context
981     if (!eventHandled)
982     {
983       if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
984           !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
985           !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
986       {
987         ecore_imf_context_reset(mIMFContext);
988       }
989     }
990   }
991   return eventHandled;
992 }
993
994 bool InputMethodContextEcoreWl::ProcessEventKeyUp( const KeyEvent& keyEvent )
995 {
996   bool eventHandled( false );
997   if( mIMFContext )
998   {
999     Integration::KeyEvent integKeyEvent( keyEvent );
1000     std::string key = integKeyEvent.logicalKey;
1001
1002     std::string compose = keyEvent.GetCompose();
1003     std::string deviceName = keyEvent.GetDeviceName();
1004
1005     // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
1006     Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
1007     ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
1008     ecoreKeyUpEvent.key = key.c_str();
1009     ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
1010     ecoreKeyUpEvent.compose = compose.c_str();
1011     ecoreKeyUpEvent.timestamp = keyEvent.time;
1012     ecoreKeyUpEvent.modifiers =  EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
1013     ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
1014     ecoreKeyUpEvent.dev_name = deviceName.c_str();
1015     ecoreKeyUpEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1016     ecoreKeyUpEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
1017
1018     eventHandled = ecore_imf_context_filter_event(mIMFContext,
1019                                                   ECORE_IMF_EVENT_KEY_UP,
1020                                                   reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ) );
1021   }
1022   return eventHandled;
1023 }
1024
1025 Ecore_IMF_Keyboard_Modifiers InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
1026 {
1027   unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE );  // If no other matches returns NONE.
1028
1029   if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT )  // enums from ecore_input/Ecore_Input.h
1030   {
1031     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;  // enums from ecore_imf/ecore_imf.h
1032   }
1033
1034   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
1035   {
1036     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
1037   }
1038
1039   if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
1040   {
1041     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
1042   }
1043
1044   if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
1045   {
1046     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
1047   }
1048
1049   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
1050   {
1051     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
1052   }
1053
1054   return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
1055 }
1056
1057 Ecore_IMF_Keyboard_Locks InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
1058 {
1059     unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
1060
1061     if( modifier & ECORE_EVENT_LOCK_NUM )
1062     {
1063       lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
1064     }
1065
1066     if( modifier & ECORE_EVENT_LOCK_CAPS )
1067     {
1068       lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
1069     }
1070
1071     if( modifier & ECORE_EVENT_LOCK_SCROLL )
1072     {
1073       lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
1074     }
1075
1076     return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
1077 }
1078
1079 } // Adaptor
1080
1081 } // Internal
1082
1083 } // Dali