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