Revert "[Tizen] ecore-wl2: applying ecore-wl2"
[platform/core/uifw/dali-adaptor.git] / dali / internal / input / tizen-wayland / imf-manager-impl-ecore-wl.cpp
1 /*
2  * Copyright (c) 2017 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 // Ecore is littered with C style cast
20 #pragma GCC diagnostic push
21 #pragma GCC diagnostic ignored "-Wold-style-cast"
22
23 #include <dali/internal/input/tizen-wayland/imf-manager-impl-ecore-wl.h>
24 #include <Ecore_Input.h>
25
26 // EXTERNAL INCLUDES
27 #include <dali/public-api/events/key-event.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/integration-api/debug.h>
30
31 // INTERNAL INCLUDES
32 #include <dali/devel-api/adaptor-framework/input-method-devel.h>
33 #include <dali/integration-api/adaptor.h>
34 #include <dali/internal/system/common/locale-utils.h>
35 #include <dali/internal/window-system/tizen-wayland/window-render-surface-ecore-wl.h>
36 #include <dali/internal/adaptor/common/adaptor-impl.h>
37 #include <dali/internal/system/common/singleton-service-impl.h>
38
39 #define TOKEN_STRING(x) #x
40
41 Ecore_IMF_Input_Panel_Layout panelLayoutMap[] =
42 {
43    ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL,
44    ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER,
45    ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL,
46    ECORE_IMF_INPUT_PANEL_LAYOUT_URL,
47    ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER,
48    ECORE_IMF_INPUT_PANEL_LAYOUT_IP,
49    ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH,
50    ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY,
51    ECORE_IMF_INPUT_PANEL_LAYOUT_HEX,
52    ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL,
53    ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD,
54    ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME,
55    ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON,
56    ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE
57 };
58
59 Ecore_IMF_Autocapital_Type autoCapitalMap[] =
60 {
61    ECORE_IMF_AUTOCAPITAL_TYPE_NONE,
62    ECORE_IMF_AUTOCAPITAL_TYPE_WORD,
63    ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE,
64    ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER,
65 };
66
67 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyTypeMap[] =
68 {
69    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT,
70    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE,
71    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO,
72    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN,
73    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN,
74    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT,
75    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH,
76    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND,
77    ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN
78 };
79
80 namespace Dali
81 {
82
83 namespace Internal
84 {
85
86 namespace Adaptor
87 {
88
89 namespace
90 {
91 #if defined(DEBUG_ENABLED)
92 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_IMF_MANAGER");
93 #endif
94
95 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
96 size_t Utf8SequenceLength(const unsigned char leadByte)
97 {
98   size_t length = 0;
99
100   if ((leadByte & 0x80) == 0 )          //ASCII character (lead bit zero)
101   {
102     length = 1;
103   }
104   else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
105   {
106     length = 2;
107   }
108   else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
109   {
110     length = 3;
111   }
112   else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
113   {
114     length = 4;
115   }
116
117   return length;
118 }
119
120 // Static function calls used by ecore 'c' style callback registration
121 void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
122 {
123   if ( data )
124   {
125     ImfManagerEcoreWl* imfManager = reinterpret_cast< ImfManagerEcoreWl* > ( data );
126     imfManager->CommitReceived( data, imfContext, event_info );
127   }
128 }
129
130 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
131 {
132   if ( data )
133   {
134     ImfManagerEcoreWl* imfManager = reinterpret_cast< ImfManagerEcoreWl* > ( data );
135     imfManager->PreEditChanged( data, imfContext, event_info );
136   }
137 }
138
139 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
140 {
141   if ( data )
142   {
143     ImfManagerEcoreWl* imfManager = reinterpret_cast< ImfManagerEcoreWl* > ( data );
144     return imfManager->RetrieveSurrounding( data, imfContext, text, cursorPosition );
145   }
146   else
147   {
148     return false;
149   }
150 }
151
152 void InputPanelStateChangeCallback( void* data, Ecore_IMF_Context* context, int value )
153 {
154   if (!data)
155   {
156     return;
157   }
158   ImfManagerEcoreWl* imfManager = reinterpret_cast< ImfManagerEcoreWl* > ( data );
159   switch (value)
160   {
161     case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
162     {
163       imfManager->StatusChangedSignal().Emit( true );
164       break;
165     }
166
167     case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
168     {
169       imfManager->StatusChangedSignal().Emit( false );
170       break;
171     }
172
173     case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
174     default:
175     {
176       // Do nothing
177       break;
178     }
179   }
180 }
181
182 void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value )
183 {
184   if (!data)
185   {
186     return;
187   }
188   ImfManagerEcoreWl* imfManager = reinterpret_cast< ImfManagerEcoreWl* > ( data );
189   // Emit the signal that the language has changed
190   imfManager->LanguageChangedSignal().Emit(value);
191 }
192
193 void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value )
194 {
195   if (!data)
196   {
197     return;
198   }
199   ImfManagerEcoreWl* imfManager = reinterpret_cast< ImfManagerEcoreWl* > ( data );  // Emit signal that the keyboard is resized
200   // Emit signal that the keyboard is resized
201   imfManager->ResizedSignal().Emit(value);
202 }
203
204 void InputPanelKeyboardTypeChangedCallback( void *data, Ecore_IMF_Context *context, int value )
205 {
206   if( !data )
207   {
208     return;
209   }
210
211   ImfManagerEcoreWl* imfManager = reinterpret_cast< ImfManagerEcoreWl* > ( data );
212   switch (value)
213   {
214     case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
215     {
216       // Emit Signal that the keyboard type is changed to Software Keyboard
217       imfManager->KeyboardTypeChangedSignal().Emit( Dali::ImfManager::KeyboardType::SOFTWARE_KEYBOARD );
218       break;
219     }
220     case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
221     {
222       // Emit Signal that the keyboard type is changed to Hardware Keyboard
223       imfManager->KeyboardTypeChangedSignal().Emit( Dali::ImfManager::KeyboardType::HARDWARE_KEYBOARD );
224       break;
225     }
226   }
227 }
228
229 /**
230  * Called when an IMF delete surrounding event is received.
231  * Here we tell the application that it should delete a certain range.
232  */
233 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
234 {
235   if ( data )
236   {
237     ImfManagerEcoreWl* imfManager = reinterpret_cast< ImfManagerEcoreWl* > ( data );
238     imfManager->DeleteSurrounding( data, imfContext, event_info );
239   }
240 }
241
242 /**
243  * Called when the input method sends a private command.
244  */
245 void PrivateCommand( void *data, Ecore_IMF_Context *imfContext, void *event_info )
246 {
247   if ( data )
248   {
249     ImfManagerEcoreWl* imfManager = reinterpret_cast< ImfManagerEcoreWl* > ( data );
250     imfManager->SendPrivateCommand( data, imfContext, event_info );
251   }
252 }
253
254 BaseHandle Create()
255 {
256   return ImfManagerEcoreWl::Get();
257 }
258
259 TypeRegistration IMF_MANAGER_TYPE( typeid(Dali::ImfManager), typeid(Dali::BaseHandle), Create );
260
261 } // unnamed namespace
262
263 bool ImfManagerEcoreWl::IsAvailable()
264 {
265   bool available( false );
266
267   Dali::SingletonService service( SingletonService::Get() );
268   if ( service )
269   {
270     available = service.GetSingleton( typeid( Dali::ImfManager ) );
271   }
272
273   return available;
274 }
275
276 Dali::ImfManager ImfManagerEcoreWl::Get()
277 {
278   Dali::ImfManager manager;
279
280   Dali::SingletonService service( SingletonService::Get() );
281   if ( service )
282   {
283     // Check whether the singleton is already created
284     Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ImfManager ) );
285     if( handle )
286     {
287       // If so, downcast the handle
288       manager = Dali::ImfManager( dynamic_cast< ImfManager* >( handle.GetObjectPtr() ) );
289     }
290     else if ( Adaptor::IsAvailable() )
291     {
292       // Create instance and register singleton only if the adaptor is available
293
294       Adaptor& adaptorImpl( Adaptor::GetImplementation( Adaptor::Get() ) );
295       Any nativeWindow = adaptorImpl.GetNativeWindowHandle();
296
297       // The Ecore_Wl_Window needs to use the ImfManager.
298       // Only when the render surface is window, we can get the Ecore_Wl_Window.
299       Ecore_Wl_Window *ecoreWwin( AnyCast< Ecore_Wl_Window* >( nativeWindow ) );
300       if (ecoreWwin)
301       {
302         // If we fail to get Ecore_Wl_Window, we can't use the ImfManager correctly.
303         // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
304         // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
305
306         manager = Dali::ImfManager( new ImfManagerEcoreWl( ecoreWwin ) );
307         service.Register( typeid( manager ), manager );
308       }
309       else
310       {
311         DALI_LOG_ERROR("Failed to get native window handle\n");
312       }
313     }
314   }
315
316   return manager;
317 }
318
319 ImfManagerEcoreWl::ImfManagerEcoreWl( Ecore_Wl_Window *ecoreWlwin )
320 : mIMFContext(),
321   mIMFCursorPosition( 0 ),
322   mSurroundingText(),
323   mRestoreAfterFocusLost( false ),
324   mIdleCallbackConnected( false )
325 {
326   ecore_imf_init();
327   CreateContext( ecoreWlwin );
328
329   ConnectCallbacks();
330 }
331
332 ImfManagerEcoreWl::~ImfManagerEcoreWl()
333 {
334   DisconnectCallbacks();
335
336   DeleteContext();
337   ecore_imf_shutdown();
338 }
339
340 void ImfManagerEcoreWl::CreateContext( Ecore_Wl_Window *ecoreWlwin )
341 {
342   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::CreateContext\n" );
343
344   const char *contextId = ecore_imf_context_default_id_get();
345   if( contextId )
346   {
347     mIMFContext = ecore_imf_context_add( contextId );
348
349     if( mIMFContext )
350     {
351       if( ecoreWlwin )
352       {
353           ecore_imf_context_client_window_set( mIMFContext,
354             reinterpret_cast<void*>( ecore_wl_window_id_get(ecoreWlwin)) );
355       }
356     }
357     else
358     {
359       DALI_LOG_WARNING("IMF Unable to get IMF Context\n");
360     }
361   }
362   else
363   {
364     DALI_LOG_WARNING("IMF Unable to get IMF Context\n");
365   }
366 }
367
368 void ImfManagerEcoreWl::DeleteContext()
369 {
370   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteContext\n" );
371
372   if ( mIMFContext )
373   {
374     ecore_imf_context_del( mIMFContext );
375     mIMFContext = NULL;
376   }
377 }
378
379 // Callbacks for predicitive text support.
380 void ImfManagerEcoreWl::ConnectCallbacks()
381 {
382   if ( mIMFContext )
383   {
384     DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::ConnectCallbacks\n" );
385
386     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,      PreEdit,    this );
387     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,               Commit,     this );
388     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING,   ImfDeleteSurrounding, this );
389     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand, this );
390
391     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback, this );
392     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback, this );
393     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, this );
394     ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback, this );
395
396     ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
397   }
398 }
399
400 void ImfManagerEcoreWl::DisconnectCallbacks()
401 {
402   if ( mIMFContext )
403   {
404     DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DisconnectCallbacks\n" );
405
406     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,      PreEdit );
407     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,               Commit );
408     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING,   ImfDeleteSurrounding );
409     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand );
410
411     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback     );
412     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback  );
413     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback );
414     ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback );
415
416     // We do not need to unset the retrieve surrounding callback.
417   }
418 }
419
420 void ImfManagerEcoreWl::Activate()
421 {
422   // Reset mIdleCallbackConnected
423   mIdleCallbackConnected = false;
424
425   if ( mIMFContext )
426   {
427     DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Activate\n" );
428
429     ecore_imf_context_focus_in( mIMFContext );
430
431     // emit keyboard activated signal
432     Dali::ImfManager handle( this );
433     mActivatedSignal.Emit( handle );
434   }
435 }
436
437 void ImfManagerEcoreWl::Deactivate()
438 {
439   if( mIMFContext )
440   {
441     DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Deactivate\n" );
442
443     Reset();
444     ecore_imf_context_focus_out( mIMFContext );
445   }
446
447   // Reset mIdleCallbackConnected
448   mIdleCallbackConnected = false;
449 }
450
451 void ImfManagerEcoreWl::Reset()
452 {
453   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Reset\n" );
454
455   if ( mIMFContext )
456   {
457     ecore_imf_context_reset( mIMFContext );
458   }
459 }
460
461 ImfContext* ImfManagerEcoreWl::GetContext()
462 {
463   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetContext\n" );
464
465   return reinterpret_cast<ImfContext*>(mIMFContext);
466 }
467
468 bool ImfManagerEcoreWl::RestoreAfterFocusLost() const
469 {
470   return mRestoreAfterFocusLost;
471 }
472
473 void ImfManagerEcoreWl::SetRestoreAfterFocusLost( bool toggle )
474 {
475   mRestoreAfterFocusLost = toggle;
476 }
477
478 /**
479  * Called when an IMF Pre-Edit changed event is received.
480  * We are still predicting what the user is typing.  The latest string is what the IMF module thinks
481  * the user wants to type.
482  */
483 void ImfManagerEcoreWl::PreEditChanged( void*, Ecore_IMF_Context* imfContext, void* event_info )
484 {
485   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::PreEditChanged\n" );
486
487   char* preEditString( NULL );
488   int cursorPosition( 0 );
489   Eina_List* attrs = NULL;
490   Eina_List* l = NULL;
491
492   Ecore_IMF_Preedit_Attr* attr;
493
494   // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
495   // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
496   ecore_imf_context_preedit_string_with_attributes_get( imfContext, &preEditString, &attrs, &cursorPosition );
497
498   if ( attrs )
499   {
500     // iterate through the list of attributes getting the type, start and end position.
501     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) ) ))
502     {
503 #ifdef DALI_PROFILE_UBUNTU
504       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
505 #else // DALI_PROFILE_UBUNTU
506       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
507 #endif // DALI_PROFILE_UBUNTU
508       {
509         // 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.
510
511         size_t visualCharacterIndex = 0;
512         size_t byteIndex = 0;
513
514         // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
515         const char leadByte = preEditString[byteIndex];
516         while( leadByte != '\0' )
517         {
518           // attr->end_index is provided as a byte position not character and we need to know the character position.
519           const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
520           if ( byteIndex == attr->end_index )
521           {
522             cursorPosition = visualCharacterIndex;
523             break;
524             // end loop as found cursor position that matches byte position
525           }
526           else
527           {
528             byteIndex += currentSequenceLength; // jump to next character
529             visualCharacterIndex++;  // increment character count so we know our position for when we get a match
530           }
531
532           DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
533         }
534       }
535     }
536   }
537
538   if ( Dali::Adaptor::IsAvailable() )
539   {
540     Dali::ImfManager handle( this );
541     Dali::ImfManager::ImfEventData imfEventData( Dali::ImfManager::PREEDIT, preEditString, cursorPosition, 0 );
542     Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
543
544     if ( callbackData.update )
545     {
546       SetCursorPosition( callbackData.cursorPosition );
547       SetSurroundingText( callbackData.currentText );
548
549       NotifyCursorPosition();
550     }
551
552     if ( callbackData.preeditResetRequired )
553     {
554       Reset();
555     }
556   }
557   free( preEditString );
558 }
559
560 void ImfManagerEcoreWl::CommitReceived( void*, Ecore_IMF_Context* imfContext, void* event_info )
561 {
562   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::CommitReceived\n" );
563
564   if ( Dali::Adaptor::IsAvailable() )
565   {
566     const std::string keyString( static_cast<char*>( event_info ) );
567
568     Dali::ImfManager handle( this );
569     Dali::ImfManager::ImfEventData imfEventData( Dali::ImfManager::COMMIT, keyString, 0, 0 );
570     Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
571
572     if( callbackData.update )
573     {
574       SetCursorPosition( callbackData.cursorPosition );
575       SetSurroundingText( callbackData.currentText );
576
577       NotifyCursorPosition();
578     }
579   }
580 }
581
582 /**
583  * Called when an IMF retrieve surround event is received.
584  * Here the IMF module wishes to know the string we are working with and where within the string the cursor is
585  * We need to signal the application to tell us this information.
586  */
587 Eina_Bool ImfManagerEcoreWl::RetrieveSurrounding( void* data, Ecore_IMF_Context* imfContext, char** text, int* cursorPosition )
588 {
589   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::RetrieveSurrounding\n" );
590
591   Dali::ImfManager::ImfEventData imfData( Dali::ImfManager::GETSURROUNDING, std::string(), 0, 0 );
592   Dali::ImfManager handle( this );
593   Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfData );
594
595   if( callbackData.update )
596   {
597     if( text )
598     {
599       // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
600       *text = strdup( callbackData.currentText.c_str() );
601     }
602
603     if( cursorPosition )
604     {
605       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
606       *cursorPosition = mIMFCursorPosition;
607     }
608   }
609
610   return EINA_TRUE;
611 }
612
613 /**
614  * Called when an IMF delete surrounding event is received.
615  * Here we tell the application that it should delete a certain range.
616  */
617 void ImfManagerEcoreWl::DeleteSurrounding( void* data, Ecore_IMF_Context* imfContext, void* event_info )
618 {
619   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteSurrounding\n" );
620
621   if( Dali::Adaptor::IsAvailable() )
622   {
623     Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( event_info );
624
625     Dali::ImfManager::ImfEventData imfData( Dali::ImfManager::DELETESURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
626     Dali::ImfManager handle( this );
627     mEventSignal.Emit( handle, imfData );
628   }
629 }
630
631 /**
632  * Called when the input method sends a private command.
633  */
634 void ImfManagerEcoreWl::SendPrivateCommand( void* data, Ecore_IMF_Context* imfContext, void* event_info )
635 {
636   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SendPrivateCommand\n" );
637
638   if( Dali::Adaptor::IsAvailable() )
639   {
640     const char* privateCommandSendEvent = static_cast<const char*>( event_info );
641
642     Dali::ImfManager::ImfEventData imfData( Dali::ImfManager::PRIVATECOMMAND, privateCommandSendEvent, 0, 0 );
643     Dali::ImfManager handle( this );
644     mEventSignal.Emit( handle, imfData );
645   }
646 }
647
648 void ImfManagerEcoreWl::NotifyCursorPosition()
649 {
650   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::NotifyCursorPosition\n" );
651
652   if( mIMFContext )
653   {
654     ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
655   }
656 }
657
658 void ImfManagerEcoreWl::SetCursorPosition( unsigned int cursorPosition )
659 {
660   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetCursorPosition\n" );
661
662   mIMFCursorPosition = static_cast<int>( cursorPosition );
663 }
664
665 unsigned int ImfManagerEcoreWl::GetCursorPosition() const
666 {
667   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetCursorPosition\n" );
668
669   return static_cast<unsigned int>( mIMFCursorPosition );
670 }
671
672 void ImfManagerEcoreWl::SetSurroundingText( const std::string& text )
673 {
674   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetSurroundingText\n" );
675
676   mSurroundingText = text;
677 }
678
679 const std::string& ImfManagerEcoreWl::GetSurroundingText() const
680 {
681   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetSurroundingText\n" );
682
683   return mSurroundingText;
684 }
685
686 void ImfManagerEcoreWl::NotifyTextInputMultiLine( bool multiLine )
687 {
688   Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
689   ecore_imf_context_input_hint_set( mIMFContext,
690                                     static_cast< Ecore_IMF_Input_Hints >( multiLine ?
691                                       (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) :
692                                       (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
693 }
694
695 Dali::ImfManager::TextDirection ImfManagerEcoreWl::GetTextDirection()
696 {
697   Dali::ImfManager::TextDirection direction ( Dali::ImfManager::LeftToRight );
698
699   if ( ImfManager::IsAvailable() /* We do not want to create an instance of ImfManager */ )
700   {
701     if ( mIMFContext )
702     {
703       char* locale( NULL );
704       ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
705
706       if ( locale )
707       {
708         direction = static_cast< Dali::ImfManager::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
709         free( locale );
710       }
711     }
712   }
713   return direction;
714 }
715
716 Rect<int> ImfManagerEcoreWl::GetInputMethodArea()
717 {
718   int xPos, yPos, width, height;
719
720   width = height = xPos = yPos = 0;
721
722   if( mIMFContext )
723   {
724     ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
725   }
726   else
727   {
728     DALI_LOG_WARNING("VKB Unable to get IMF Context so GetSize unavailable\n");
729   // return 0 as real size unknown.
730   }
731
732   return Rect<int>(xPos,yPos,width,height);
733 }
734
735 void ImfManagerEcoreWl::ApplyOptions( const InputMethodOptions& options )
736 {
737   using namespace Dali::InputMethod::Category;
738
739   int index;
740
741   if (mIMFContext == NULL)
742   {
743     DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
744     return;
745   }
746
747   if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
748   {
749     ecore_imf_context_input_panel_layout_set( mIMFContext, panelLayoutMap[index] );
750   }
751   if ( mOptions.CompareAndSet(AUTO_CAPITALISE, options, index) )
752   {
753     ecore_imf_context_autocapital_type_set( mIMFContext, autoCapitalMap[index] );
754   }
755   if ( mOptions.CompareAndSet(ACTION_BUTTON_TITLE, options, index) )
756   {
757     ecore_imf_context_input_panel_return_key_type_set( mIMFContext, returnKeyTypeMap[index] );
758   }
759   if ( mOptions.CompareAndSet(VARIATION, options, index) )
760   {
761     ecore_imf_context_input_panel_layout_variation_set( mIMFContext, index );
762   }
763 }
764
765 void ImfManagerEcoreWl::SetInputPanelData( const std::string& data )
766 {
767   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetInputPanelData\n" );
768
769   if( mIMFContext )
770   {
771     int length = data.length();
772     ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
773   }
774 }
775
776 void ImfManagerEcoreWl::GetInputPanelData( std::string& data )
777 {
778   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetInputPanelData\n" );
779
780   if( mIMFContext )
781   {
782     int length = 4096; // The max length is 4096 bytes
783     Dali::Vector< char > buffer;
784     buffer.Resize( length );
785     ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
786     data = std::string( buffer.Begin(), buffer.End() );
787   }
788 }
789
790 Dali::ImfManager::State ImfManagerEcoreWl::GetInputPanelState()
791 {
792   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetInputPanelState\n" );
793
794   if( mIMFContext )
795   {
796     int value;
797     value = ecore_imf_context_input_panel_state_get( mIMFContext );
798
799     switch (value)
800     {
801       case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
802       {
803         return Dali::ImfManager::SHOW;
804         break;
805       }
806
807       case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
808       {
809         return Dali::ImfManager::HIDE;
810         break;
811       }
812
813       case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
814       {
815         return Dali::ImfManager::WILL_SHOW;
816         break;
817       }
818
819       default:
820       {
821         return Dali::ImfManager::DEFAULT;
822       }
823     }
824   }
825   return Dali::ImfManager::DEFAULT;
826 }
827
828 void ImfManagerEcoreWl::SetReturnKeyState( bool visible )
829 {
830   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetReturnKeyState\n" );
831
832   if( mIMFContext )
833   {
834     ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
835   }
836 }
837
838 void ImfManagerEcoreWl::AutoEnableInputPanel( bool enabled )
839 {
840   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::AutoEnableInputPanel\n" );
841
842   if( mIMFContext )
843   {
844     ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
845   }
846 }
847
848 void ImfManagerEcoreWl::ShowInputPanel()
849 {
850   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::ShowInputPanel\n" );
851
852   if( mIMFContext )
853   {
854     ecore_imf_context_input_panel_show( mIMFContext );
855   }
856 }
857
858 void ImfManagerEcoreWl::HideInputPanel()
859 {
860   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::HideInputPanel\n" );
861
862   if( mIMFContext )
863   {
864     ecore_imf_context_input_panel_hide( mIMFContext );
865   }
866 }
867
868 Dali::ImfManager::KeyboardType ImfManagerEcoreWl::GetKeyboardType()
869 {
870   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetKeyboardType\n" );
871
872 #ifdef OVER_TIZEN_VERSION_4
873   if( mIMFContext )
874   {
875     int value;
876     value = ecore_imf_context_keyboard_mode_get( mIMFContext );
877
878     switch (value)
879     {
880       case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
881       {
882         return Dali::ImfManager::SOFTWARE_KEYBOARD;
883         break;
884       }
885       case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
886       {
887         return Dali::ImfManager::HARDWARE_KEYBOARD;
888         break;
889       }
890     }
891   }
892 #endif // OVER_TIZEN_VERSION_4
893   return Dali::ImfManager::KeyboardType::SOFTWARE_KEYBOARD;
894 }
895
896 std::string ImfManagerEcoreWl::GetInputPanelLocale()
897 {
898   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetInputPanelLocale\n" );
899
900   std::string locale = "";
901
902   if( mIMFContext )
903   {
904     char* value = NULL;
905     ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
906
907     if( value )
908     {
909       std::string valueCopy( value );
910       locale = valueCopy;
911
912       // The locale string retrieved must be freed with free().
913       free( value );
914     }
915   }
916   return locale;
917 }
918
919 } // Adaptor
920
921 } // Internal
922
923 } // Dali
924
925 #pragma GCC diagnostic pop