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