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