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