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