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