Remove DALI_ADAPTOR_COMPILATION define
[platform/core/uifw/dali-adaptor.git] / dali / internal / input / ubuntu-x11 / input-method-context-impl-x.cpp
1 /*
2  * Copyright (c) 2019 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/input-method-context-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/public-api/adaptor-framework/key.h>
28 #include <dali/integration-api/adaptors/adaptor.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
30 #include <dali/internal/input/common/key-impl.h>
31 #include <dali/internal/input/common/virtual-keyboard-impl.h>
32 #include <dali/internal/input/linux/dali-ecore-imf.h>
33 #include <dali/internal/input/tizen-wayland/ecore-virtual-keyboard.h>
34 #include <dali/internal/input/ubuntu-x11/dali-ecore-input.h>
35 #include <dali/internal/system/common/locale-utils.h>
36 #include <dali/internal/system/common/singleton-service-impl.h>
37 #include <dali/internal/system/linux/dali-ecore.h>
38
39 namespace Dali
40 {
41
42 namespace Internal
43 {
44
45 namespace Adaptor
46 {
47
48 namespace
49 {
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
52 #endif
53
54 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
55 size_t Utf8SequenceLength(const unsigned char leadByte)
56 {
57   size_t length = 0;
58
59   if ((leadByte & 0x80) == 0 )          //ASCII character (lead bit zero)
60   {
61     length = 1;
62   }
63   else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
64   {
65     length = 2;
66   }
67   else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
68   {
69     length = 3;
70   }
71   else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
72   {
73     length = 4;
74   }
75
76   return length;
77 }
78
79 // Static function calls used by ecore 'c' style callback registration
80 void Commit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
81 {
82   if ( data )
83   {
84     InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
85     inputMethodContext->CommitReceived( data, imfContext, eventInfo );
86   }
87 }
88
89 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
90 {
91   if ( data )
92   {
93     InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
94     inputMethodContext->PreEditChanged( data, imfContext, eventInfo );
95   }
96 }
97
98 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
99 {
100   if ( data )
101   {
102     InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
103     return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
104   }
105   else
106   {
107     return false;
108   }
109 }
110
111 /**
112  * Called when an InputMethodContext delete surrounding event is received.
113  * Here we tell the application that it should delete a certain range.
114  */
115 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
116 {
117   if ( data )
118   {
119     InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
120     inputMethodContext->DeleteSurrounding( data, imfContext, eventInfo );
121   }
122 }
123
124 } // unnamed namespace
125
126 InputMethodContextPtr InputMethodContextX::New( Dali::Actor actor )
127 {
128   InputMethodContextPtr manager;
129
130   if( actor && Dali::Adaptor::IsAvailable() )
131   {
132     manager = new InputMethodContextX( actor );
133   }
134
135   return manager;
136 }
137
138 void InputMethodContextX::Finalize()
139 {
140   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Finalize\n" );
141   VirtualKeyboard::DisconnectCallbacks( mIMFContext );
142   DisconnectCallbacks();
143   DeleteContext();
144 }
145
146 InputMethodContextX::InputMethodContextX( Dali::Actor actor )
147 : mIMFContext(),
148   mEcoreXwin( 0 ),
149   mIMFCursorPosition( 0 ),
150   mSurroundingText(),
151   mRestoreAfterFocusLost( false ),
152   mIdleCallbackConnected( false ),
153   mPreeditType( Dali::InputMethodContext::PreeditStyle::NONE )
154 {
155   ecore_imf_init();
156
157   actor.OnStageSignal().Connect( this, &InputMethodContextX::OnStaged );
158 }
159
160 InputMethodContextX::~InputMethodContextX()
161 {
162   Finalize();
163   ecore_imf_shutdown();
164 }
165
166 void InputMethodContextX::Initialize()
167 {
168   CreateContext();
169   ConnectCallbacks();
170   VirtualKeyboard::ConnectCallbacks( mIMFContext );
171 }
172
173 void InputMethodContextX::CreateContext()
174 {
175   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CreateContext\n" );
176
177   if( !mEcoreXwin )
178   {
179     return;
180   }
181
182   const char *contextId = ecore_imf_context_default_id_get();
183   if( contextId )
184   {
185     mIMFContext = ecore_imf_context_add( contextId );
186
187     if( mIMFContext )
188     {
189       ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast<void*>( mEcoreXwin ) );
190     }
191     else
192     {
193       DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
194     }
195   }
196   else
197   {
198     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
199   }
200 }
201
202 void InputMethodContextX::DeleteContext()
203 {
204   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DeleteContext\n" );
205
206   if ( mIMFContext )
207   {
208     ecore_imf_context_del( mIMFContext );
209     mIMFContext = NULL;
210   }
211 }
212
213 // Callbacks for predicitive text support.
214 void InputMethodContextX::ConnectCallbacks()
215 {
216   if ( mIMFContext )
217   {
218     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::ConnectCallbacks\n" );
219
220     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit,    this );
221     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit,     this );
222     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
223
224     ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
225   }
226 }
227
228 void InputMethodContextX::DisconnectCallbacks()
229 {
230   if ( mIMFContext )
231   {
232     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DisconnectCallbacks\n" );
233
234     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit );
235     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit );
236     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
237
238     // We do not need to unset the retrieve surrounding callback.
239   }
240 }
241
242 void InputMethodContextX::Activate()
243 {
244   // Reset mIdleCallbackConnected
245   mIdleCallbackConnected = false;
246
247   if ( mIMFContext )
248   {
249     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Activate\n" );
250
251     ecore_imf_context_focus_in( mIMFContext );
252
253     // emit keyboard activated signal
254     Dali::InputMethodContext handle( this );
255     mActivatedSignal.Emit( handle );
256   }
257 }
258
259 void InputMethodContextX::Deactivate()
260 {
261   if( mIMFContext )
262   {
263     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Deactivate\n" );
264
265     Reset();
266     ecore_imf_context_focus_out( mIMFContext );
267   }
268
269   // Reset mIdleCallbackConnected
270   mIdleCallbackConnected = false;
271 }
272
273 void InputMethodContextX::Reset()
274 {
275   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Reset\n" );
276
277   if ( mIMFContext )
278   {
279     ecore_imf_context_reset( mIMFContext );
280   }
281 }
282
283 ImfContext* InputMethodContextX::GetContext()
284 {
285   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetContext\n" );
286
287   return mIMFContext;
288 }
289
290 bool InputMethodContextX::RestoreAfterFocusLost() const
291 {
292   return mRestoreAfterFocusLost;
293 }
294
295 void InputMethodContextX::SetRestoreAfterFocusLost( bool toggle )
296 {
297   mRestoreAfterFocusLost = toggle;
298 }
299
300 /**
301  * Called when an InputMethodContext Pre-Edit changed event is received.
302  * We are still predicting what the user is typing.  The latest string is what the InputMethodContext module thinks
303  * the user wants to type.
304  */
305 void InputMethodContextX::PreEditChanged( void*, ImfContext* imfContext, void* eventInfo )
306 {
307   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::PreEditChanged\n" );
308   auto context = static_cast<Ecore_IMF_Context*>( imfContext );
309
310   char* preEditString( NULL );
311   int cursorPosition( 0 );
312   Eina_List* attrs = NULL;
313   Eina_List* l = NULL;
314
315   Ecore_IMF_Preedit_Attr* attr;
316
317   // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
318   // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
319   ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
320
321   if ( attrs )
322   {
323     // iterate through the list of attributes getting the type, start and end position.
324     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) ) ))
325     {
326       switch( attr->preedit_type )
327       {
328         case ECORE_IMF_PREEDIT_TYPE_NONE:
329         {
330           mPreeditType = Dali::InputMethodContext::PreeditStyle::NONE;
331           break;
332         }
333         case ECORE_IMF_PREEDIT_TYPE_SUB1:
334         {
335           mPreeditType = Dali::InputMethodContext::PreeditStyle::UNDERLINE;
336           break;
337         }
338         case ECORE_IMF_PREEDIT_TYPE_SUB2:
339         {
340           mPreeditType = Dali::InputMethodContext::PreeditStyle::REVERSE;
341           break;
342         }
343         case ECORE_IMF_PREEDIT_TYPE_SUB3:
344         {
345           mPreeditType = Dali::InputMethodContext::PreeditStyle::HIGHLIGHT;
346           break;
347         }
348         default:
349         {
350           break;
351         }
352       }
353
354 #ifdef DALI_PROFILE_UBUNTU
355       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
356 #else // DALI_PROFILE_UBUNTU
357       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
358 #endif // DALI_PROFILE_UBUNTU
359       {
360         // 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.
361
362         size_t visualCharacterIndex = 0;
363         size_t byteIndex = 0;
364
365         // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
366         const char leadByte = preEditString[byteIndex];
367         while( leadByte != '\0' )
368         {
369           // attr->end_index is provided as a byte position not character and we need to know the character position.
370           const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
371           if ( byteIndex == attr->end_index )
372           {
373             cursorPosition = static_cast<int>( visualCharacterIndex );
374             break;
375             // end loop as found cursor position that matches byte position
376           }
377           else
378           {
379             byteIndex += currentSequenceLength; // jump to next character
380             visualCharacterIndex++;  // increment character count so we know our position for when we get a match
381           }
382
383           DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
384         }
385       }
386     }
387   }
388
389   if ( Dali::Adaptor::IsAvailable() )
390   {
391     Dali::InputMethodContext handle( this );
392     Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
393     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
394
395     if( callbackData.update )
396     {
397       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
398
399       NotifyCursorPosition();
400     }
401
402     if( callbackData.preeditResetRequired )
403     {
404       Reset();
405     }
406   }
407   free( preEditString );
408 }
409
410 void InputMethodContextX::CommitReceived( void*, ImfContext* imfContext, void* eventInfo )
411 {
412   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CommitReceived\n" );
413
414   if ( Dali::Adaptor::IsAvailable() )
415   {
416     const std::string keyString( static_cast<char*>( eventInfo ) );
417
418     Dali::InputMethodContext handle( this );
419     Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
420     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
421
422     if( callbackData.update )
423     {
424       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
425
426       NotifyCursorPosition();
427     }
428   }
429 }
430
431 /**
432  * Called when an InputMethodContext retrieve surround event is received.
433  * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
434  * We need to signal the application to tell us this information.
435  */
436 bool InputMethodContextX::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
437 {
438   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::RetrieveSurrounding\n" );
439
440   Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
441   Dali::InputMethodContext handle( this );
442   Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
443
444   if( callbackData.update )
445   {
446     if( text )
447     {
448       *text = strdup( callbackData.currentText.c_str() );
449     }
450
451     if( cursorPosition )
452     {
453       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
454       *cursorPosition = mIMFCursorPosition;
455     }
456   }
457
458   return EINA_TRUE;
459 }
460
461 /**
462  * Called when an InputMethodContext delete surrounding event is received.
463  * Here we tell the application that it should delete a certain range.
464  */
465 void InputMethodContextX::DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo )
466 {
467   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DeleteSurrounding\n" );
468
469   if( Dali::Adaptor::IsAvailable() )
470   {
471     Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( eventInfo );
472
473     Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
474     Dali::InputMethodContext handle( this );
475     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
476
477     if( callbackData.update )
478     {
479       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
480
481       NotifyCursorPosition();
482     }
483   }
484 }
485
486 void InputMethodContextX::NotifyCursorPosition()
487 {
488   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::NotifyCursorPosition\n" );
489
490   if( mIMFContext )
491   {
492     ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
493   }
494 }
495
496 void InputMethodContextX::SetCursorPosition( unsigned int cursorPosition )
497 {
498   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetCursorPosition\n" );
499
500   mIMFCursorPosition = static_cast<int>( cursorPosition );
501 }
502
503 unsigned int InputMethodContextX::GetCursorPosition() const
504 {
505   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetCursorPosition\n" );
506
507   return static_cast<unsigned int>( mIMFCursorPosition );
508 }
509
510 void InputMethodContextX::SetSurroundingText( const std::string& text )
511 {
512   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetSurroundingText\n" );
513
514   mSurroundingText = text;
515 }
516
517 const std::string& InputMethodContextX::GetSurroundingText() const
518 {
519   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetSurroundingText\n" );
520
521   return mSurroundingText;
522 }
523
524 void InputMethodContextX::NotifyTextInputMultiLine( bool multiLine )
525 {
526 }
527
528 Dali::InputMethodContext::TextDirection InputMethodContextX::GetTextDirection()
529 {
530   Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
531
532     if ( mIMFContext )
533     {
534       char* locale( NULL );
535       ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
536
537       if ( locale )
538       {
539         direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
540         free( locale );
541       }
542     }
543
544   return direction;
545 }
546
547 Rect<int> InputMethodContextX::GetInputMethodArea()
548 {
549   int xPos, yPos, width, height;
550
551   width = height = xPos = yPos = 0;
552
553   if( mIMFContext )
554   {
555     ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
556   }
557   else
558   {
559     DALI_LOG_WARNING("VKB Unable to get InputMethodContext Context so GetSize unavailable\n");
560   }
561
562   return Rect<int>(xPos,yPos,width,height);
563 }
564
565 void InputMethodContextX::ApplyOptions( const InputMethodOptions& options )
566 {
567   using namespace Dali::InputMethod::Category;
568
569   int index;
570
571   if (mIMFContext == NULL)
572   {
573     DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
574     return;
575   }
576
577   if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
578   {
579   }
580   if ( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
581   {
582   }
583   if ( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
584   {
585   }
586   if ( mOptions.CompareAndSet(VARIATION, options, index) )
587   {
588   }
589 }
590
591 void InputMethodContextX::SetInputPanelData( const std::string& data )
592 {
593   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelData\n" );
594
595   if( mIMFContext )
596   {
597     int length = data.length();
598     ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
599   }
600 }
601
602 void InputMethodContextX::GetInputPanelData( std::string& data )
603 {
604   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelData\n" );
605
606   if( mIMFContext )
607   {
608     int length = 4096; // The max length is 4096 bytes
609     Dali::Vector< char > buffer;
610     buffer.Resize( length );
611     ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
612     data = std::string( buffer.Begin(), buffer.End() );
613   }
614 }
615
616 Dali::InputMethodContext::State InputMethodContextX::GetInputPanelState()
617 {
618   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelState\n" );
619
620   if( mIMFContext )
621   {
622     int value;
623     value = ecore_imf_context_input_panel_state_get( mIMFContext );
624
625     switch (value)
626     {
627       case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
628       {
629         return Dali::InputMethodContext::SHOW;
630         break;
631       }
632
633       case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
634       {
635         return Dali::InputMethodContext::HIDE;
636         break;
637       }
638
639       case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
640       {
641         return Dali::InputMethodContext::WILL_SHOW;
642         break;
643       }
644
645       default:
646       {
647         return Dali::InputMethodContext::DEFAULT;
648       }
649     }
650   }
651   return Dali::InputMethodContext::DEFAULT;
652 }
653
654 void InputMethodContextX::SetReturnKeyState( bool visible )
655 {
656   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetReturnKeyState\n" );
657
658   if( mIMFContext )
659   {
660     ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
661   }
662 }
663
664 void InputMethodContextX::AutoEnableInputPanel( bool enabled )
665 {
666   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::AutoEnableInputPanel\n" );
667
668   if( mIMFContext )
669   {
670     ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
671   }
672 }
673
674 void InputMethodContextX::ShowInputPanel()
675 {
676   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::ShowInputPanel\n" );
677
678   if( mIMFContext )
679   {
680     ecore_imf_context_input_panel_show( mIMFContext );
681   }
682 }
683
684 void InputMethodContextX::HideInputPanel()
685 {
686   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::HideInputPanel\n" );
687
688   if( mIMFContext )
689   {
690     ecore_imf_context_input_panel_hide( mIMFContext );
691   }
692 }
693
694 Dali::InputMethodContext::KeyboardType InputMethodContextX::GetKeyboardType()
695 {
696   return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
697 }
698
699 std::string InputMethodContextX::GetInputPanelLocale()
700 {
701   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLocale\n" );
702
703   std::string locale = "";
704
705   if( mIMFContext )
706   {
707     char* value = NULL;
708     ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
709
710     if( value )
711     {
712       std::string valueCopy( value );
713       locale = valueCopy;
714
715       // The locale string retrieved must be freed with free().
716       free( value );
717     }
718   }
719   return locale;
720 }
721
722 void InputMethodContextX::SetContentMIMETypes( const std::string& mimeTypes )
723 {
724   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetContentMIMETypes\n" );
725   // ecore_imf_context_mime_type_accept_set() is supported from ecore-imf 1.20.0 version.
726 }
727
728 bool InputMethodContextX::FilterEventKey( const Dali::KeyEvent& keyEvent )
729 {
730   bool eventHandled( false );
731
732   // If a device key then skip ecore_imf_context_filter_event.
733   if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))
734   {
735     //check whether it's key down or key up event
736     if ( keyEvent.state == KeyEvent::Down )
737     {
738       eventHandled = ProcessEventKeyDown( keyEvent );
739     }
740     else if ( keyEvent.state == KeyEvent::Up )
741     {
742       eventHandled = ProcessEventKeyUp( keyEvent );
743     }
744   }
745
746   return eventHandled;
747 }
748
749 void InputMethodContextX::AllowTextPrediction( bool prediction )
750 {
751   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::AllowTextPrediction\n" );
752
753   if( mIMFContext )
754   {
755     ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
756   }
757 }
758
759 bool InputMethodContextX::IsTextPredictionAllowed() const
760 {
761   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::IsTextPredictionAllowed\n" );
762   bool prediction = false;
763   if( mIMFContext )
764   {
765     prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
766   }
767   return prediction;
768 }
769
770 void InputMethodContextX::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
771 {
772   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelLanguage\n" );
773   if( mIMFContext )
774   {
775     switch (language)
776     {
777       case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
778       {
779         ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC );
780         break;
781       }
782       case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
783       {
784         ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET );
785         break;
786       }
787     }
788   }
789 }
790
791 Dali::InputMethodContext::InputPanelLanguage InputMethodContextX::GetInputPanelLanguage() const
792 {
793   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLanguage\n" );
794   if( mIMFContext )
795   {
796     int value;
797     value =  ecore_imf_context_input_panel_language_get( mIMFContext );
798
799     switch (value)
800     {
801       case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
802       {
803         return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
804         break;
805       }
806       case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
807       {
808         return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
809         break;
810       }
811     }
812   }
813   return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
814 }
815
816 void InputMethodContextX::SetInputPanelPosition( unsigned int x, unsigned int y )
817 {
818   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelPosition\n" );
819
820   // ecore_imf_context_input_panel_position_set() is supported from ecore-imf 1.21.0 version.
821 }
822
823 Dali::InputMethodContext::PreeditStyle InputMethodContextX::GetPreeditStyle() const
824 {
825   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetPreeditStyle\n" );
826   return mPreeditType;
827 }
828
829 bool InputMethodContextX::ProcessEventKeyDown( const KeyEvent& keyEvent )
830 {
831   bool eventHandled( false );
832   if ( mIMFContext )
833   {
834     Integration::KeyEvent integKeyEvent( keyEvent );
835     std::string key = integKeyEvent.logicalKey;
836
837     std::string compose = keyEvent.GetCompose();
838
839     // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
840     Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
841     ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
842     ecoreKeyDownEvent.key = key.c_str();
843     ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
844     ecoreKeyDownEvent.compose = compose.c_str();
845     ecoreKeyDownEvent.timestamp = keyEvent.time;
846     ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
847     ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
848
849 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
850 #if (ECORE_VERSION_MINOR >= 14)
851     ecoreKeyDownEvent.dev_name  = "";
852     ecoreKeyDownEvent.dev_class = ECORE_IMF_DEVICE_CLASS_KEYBOARD;
853     ecoreKeyDownEvent.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
854 #endif // Since ecore_imf 1.14 version
855 #if (ECORE_VERSION_MINOR >= 22)
856     ecoreKeyDownEvent.keycode = keyEvent.keyCode;
857 #endif // Since ecore_imf 1.22 version
858 #endif // Since ecore_imf Version 1
859
860     // If the device is IME and the focused key is the direction keys, then we should send a key event to move a key cursor.
861     if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
862                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
863                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
864                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
865     {
866       eventHandled = 0;
867     }
868     else
869     {
870       eventHandled = ecore_imf_context_filter_event(mIMFContext,
871                                                     ECORE_IMF_EVENT_KEY_DOWN,
872                                                     reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ));
873     }
874
875     // If the event has not been handled by InputMethodContext then check if we should reset our IMFcontext
876     if (!eventHandled)
877     {
878       if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
879           !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
880           !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
881       {
882         ecore_imf_context_reset(mIMFContext);
883       }
884     }
885   }
886   return eventHandled;
887 }
888
889 bool InputMethodContextX::ProcessEventKeyUp( const KeyEvent& keyEvent )
890 {
891   bool eventHandled( false );
892   if( mIMFContext )
893   {
894     Integration::KeyEvent integKeyEvent( keyEvent );
895     std::string key = integKeyEvent.logicalKey;
896
897     std::string compose = keyEvent.GetCompose();
898
899     // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
900     Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
901     ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
902     ecoreKeyUpEvent.key = key.c_str();
903     ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
904     ecoreKeyUpEvent.compose = compose.c_str();
905     ecoreKeyUpEvent.timestamp = keyEvent.time;
906     ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
907     ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
908 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
909 #if (ECORE_VERSION_MINOR >= 14)
910     ecoreKeyUpEvent.dev_name  = "";
911 #endif // Since ecore_imf 1.14 version
912 #if (ECORE_VERSION_MINOR >= 22)
913     ecoreKeyUpEvent.keycode = keyEvent.keyCode;
914 #endif // Since ecore_imf 1.22 version
915 #endif // Since ecore_imf Version 1
916
917     eventHandled = ecore_imf_context_filter_event(mIMFContext,
918                                                   ECORE_IMF_EVENT_KEY_UP,
919                                                   reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ));
920   }
921   return eventHandled;
922 }
923
924 Ecore_IMF_Keyboard_Modifiers InputMethodContextX::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
925 {
926   unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE );  // If no other matches returns NONE.
927
928   if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT )  // enums from ecore_input/Ecore_Input.h
929   {
930     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;  // enums from ecore_imf/ecore_imf.h
931   }
932
933   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
934   {
935     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
936   }
937
938   if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
939   {
940     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
941   }
942
943   if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
944   {
945     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
946   }
947
948   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
949   {
950     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
951   }
952
953   return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
954 }
955
956 Ecore_IMF_Keyboard_Locks InputMethodContextX::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
957 {
958     unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
959
960     if( modifier & ECORE_EVENT_LOCK_NUM )
961     {
962       lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
963     }
964
965     if( modifier & ECORE_EVENT_LOCK_CAPS )
966     {
967       lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
968     }
969
970     if( modifier & ECORE_EVENT_LOCK_SCROLL )
971     {
972       lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
973     }
974
975     return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
976 }
977
978 void InputMethodContextX::OnStaged( Dali::Actor actor )
979 {
980   Ecore_X_Window ecoreXwin( AnyCast< Ecore_X_Window >( Dali::Integration::SceneHolder::Get( actor ).GetNativeHandle() ) );
981
982   if( mEcoreXwin != ecoreXwin )
983   {
984     mEcoreXwin = ecoreXwin;
985
986     // Reset
987     Finalize();
988     Initialize();
989   }
990 }
991
992 } // Adaptor
993
994 } // Internal
995
996 } // Dali