Fix conversion warnings for event refactor
[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/internal/input/linux/dali-ecore-imf.h>
23 #include <dali/internal/input/ubuntu-x11/dali-ecore-input.h>
24 #include <dali/public-api/events/key-event.h>
25 #include <dali/public-api/adaptor-framework/key.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/integration-api/debug.h>
28
29 // INTERNAL INCLUDES
30 #include <dali/integration-api/adaptor.h>
31 #include <dali/internal/adaptor/common/adaptor-impl.h>
32 #include <dali/internal/system/common/locale-utils.h>
33 #include <dali/internal/system/common/singleton-service-impl.h>
34 #include <dali/internal/input/common/virtual-keyboard-impl.h>
35 #include <dali/internal/input/common/key-impl.h>
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_INPUT_METHOD_CONTEXT");
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     InputMethodContextX* inputMethodContext = reinterpret_cast< InputMethodContextX* > ( data );
84     inputMethodContext->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     InputMethodContextX* inputMethodContext = reinterpret_cast< InputMethodContextX* > ( data );
93     inputMethodContext->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     InputMethodContextX* inputMethodContext = reinterpret_cast< InputMethodContextX* > ( data );
102     return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
103   }
104   else
105   {
106     return false;
107   }
108 }
109
110 /**
111  * Called when an InputMethodContext 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     InputMethodContextX* inputMethodContext = reinterpret_cast< InputMethodContextX* > ( data );
119     inputMethodContext->DeleteSurrounding( data, imfContext, event_info );
120   }
121 }
122
123 } // unnamed namespace
124
125 InputMethodContextPtr InputMethodContextX::New()
126 {
127   InputMethodContextPtr manager;
128
129   if ( Adaptor::IsAvailable() )
130   {
131     // Create instance and register singleton only if the adaptor is available
132     Adaptor& adaptorImpl( Adaptor::GetImplementation( Adaptor::Get() ) );
133     Any nativeWindow = adaptorImpl.GetNativeWindowHandle();
134
135     // The Ecore_X_Window needs to use the InputMethodContext.
136     // Only when the render surface is window, we can get the Ecore_X_Window.
137     Ecore_X_Window ecoreXwin( AnyCast<Ecore_X_Window>(nativeWindow) );
138     if (ecoreXwin)
139     {
140       // If we fail to get Ecore_X_Window, we can't use the InputMethodContext correctly.
141       // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
142       // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
143
144       manager = new InputMethodContextX( ecoreXwin );
145     }
146     else
147     {
148       DALI_LOG_ERROR("Failed to get native window handle\n");
149     }
150   }
151
152   return manager;
153 }
154
155 void InputMethodContextX::Finalize()
156 {
157   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Finalize\n" );
158   VirtualKeyboard::DisconnectCallbacks( mIMFContext );
159   DisconnectCallbacks();
160   DeleteContext();
161 }
162
163 InputMethodContextX::InputMethodContextX( Ecore_X_Window ecoreXwin )
164 : mIMFContext(),
165   mEcoreXwin( ecoreXwin ),
166   mIMFCursorPosition( 0 ),
167   mSurroundingText(),
168   mRestoreAfterFocusLost( false ),
169   mIdleCallbackConnected( false )
170 {
171   ecore_imf_init();
172 }
173
174 InputMethodContextX::~InputMethodContextX()
175 {
176   Finalize();
177   ecore_imf_shutdown();
178 }
179
180 void InputMethodContextX::Initialize()
181 {
182   CreateContext( mEcoreXwin );
183   ConnectCallbacks();
184   VirtualKeyboard::ConnectCallbacks( mIMFContext );
185 }
186
187 void InputMethodContextX::CreateContext( Ecore_X_Window ecoreXwin )
188 {
189   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CreateContext\n" );
190
191   const char *contextId = ecore_imf_context_default_id_get();
192   if( contextId )
193   {
194     mIMFContext = ecore_imf_context_add( contextId );
195
196     if( mIMFContext )
197     {
198       if( ecoreXwin )
199       {
200         ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast<void*>( ecoreXwin ) );
201       }
202     }
203     else
204     {
205       DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
206     }
207   }
208   else
209   {
210     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
211   }
212 }
213
214 void InputMethodContextX::DeleteContext()
215 {
216   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DeleteContext\n" );
217
218   if ( mIMFContext )
219   {
220     ecore_imf_context_del( mIMFContext );
221     mIMFContext = NULL;
222   }
223 }
224
225 // Callbacks for predicitive text support.
226 void InputMethodContextX::ConnectCallbacks()
227 {
228   if ( mIMFContext )
229   {
230     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::ConnectCallbacks\n" );
231
232     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit,    this );
233     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit,     this );
234     ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
235
236     ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
237   }
238 }
239
240 void InputMethodContextX::DisconnectCallbacks()
241 {
242   if ( mIMFContext )
243   {
244     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DisconnectCallbacks\n" );
245
246     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit );
247     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit );
248     ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
249
250     // We do not need to unset the retrieve surrounding callback.
251   }
252 }
253
254 void InputMethodContextX::Activate()
255 {
256   // Reset mIdleCallbackConnected
257   mIdleCallbackConnected = false;
258
259   if ( mIMFContext )
260   {
261     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Activate\n" );
262
263     ecore_imf_context_focus_in( mIMFContext );
264
265     // emit keyboard activated signal
266     Dali::InputMethodContext handle( this );
267     mActivatedSignal.Emit( handle );
268   }
269 }
270
271 void InputMethodContextX::Deactivate()
272 {
273   if( mIMFContext )
274   {
275     DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Deactivate\n" );
276
277     Reset();
278     ecore_imf_context_focus_out( mIMFContext );
279   }
280
281   // Reset mIdleCallbackConnected
282   mIdleCallbackConnected = false;
283 }
284
285 void InputMethodContextX::Reset()
286 {
287   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Reset\n" );
288
289   if ( mIMFContext )
290   {
291     ecore_imf_context_reset( mIMFContext );
292   }
293 }
294
295 ImfContext* InputMethodContextX::GetContext()
296 {
297   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetContext\n" );
298
299   return mIMFContext;
300 }
301
302 bool InputMethodContextX::RestoreAfterFocusLost() const
303 {
304   return mRestoreAfterFocusLost;
305 }
306
307 void InputMethodContextX::SetRestoreAfterFocusLost( bool toggle )
308 {
309   mRestoreAfterFocusLost = toggle;
310 }
311
312 /**
313  * Called when an InputMethodContext Pre-Edit changed event is received.
314  * We are still predicting what the user is typing.  The latest string is what the InputMethodContext module thinks
315  * the user wants to type.
316  */
317 void InputMethodContextX::PreEditChanged( void*, ImfContext* imfContext, void* event_info )
318 {
319   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::PreEditChanged\n" );
320   auto context = reinterpret_cast<Ecore_IMF_Context*>(imfContext);
321
322   char* preEditString( NULL );
323   int cursorPosition( 0 );
324   Eina_List* attrs = NULL;
325   Eina_List* l = NULL;
326
327   Ecore_IMF_Preedit_Attr* attr;
328
329   // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
330   // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
331   ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
332
333   if ( attrs )
334   {
335     // iterate through the list of attributes getting the type, start and end position.
336     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) ) ))
337     {
338 #ifdef DALI_PROFILE_UBUNTU
339       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
340 #else // DALI_PROFILE_UBUNTU
341       if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
342 #endif // DALI_PROFILE_UBUNTU
343       {
344         // 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.
345
346         size_t visualCharacterIndex = 0;
347         size_t byteIndex = 0;
348
349         // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
350         const char leadByte = preEditString[byteIndex];
351         while( leadByte != '\0' )
352         {
353           // attr->end_index is provided as a byte position not character and we need to know the character position.
354           const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
355           if ( byteIndex == attr->end_index )
356           {
357             cursorPosition = static_cast<int>( visualCharacterIndex );
358             break;
359             // end loop as found cursor position that matches byte position
360           }
361           else
362           {
363             byteIndex += currentSequenceLength; // jump to next character
364             visualCharacterIndex++;  // increment character count so we know our position for when we get a match
365           }
366
367           DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
368         }
369       }
370     }
371   }
372
373   if ( Dali::Adaptor::IsAvailable() )
374   {
375     Dali::InputMethodContext handle( this );
376     Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
377     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
378
379     if( callbackData.update )
380     {
381       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
382
383       NotifyCursorPosition();
384     }
385
386     if( callbackData.preeditResetRequired )
387     {
388       Reset();
389     }
390   }
391   free( preEditString );
392 }
393
394 void InputMethodContextX::CommitReceived( void*, ImfContext* imfContext, void* event_info )
395 {
396   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CommitReceived\n" );
397
398   if ( Dali::Adaptor::IsAvailable() )
399   {
400     const std::string keyString( static_cast<char*>( event_info ) );
401
402     Dali::InputMethodContext handle( this );
403     Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
404     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
405
406     if( callbackData.update )
407     {
408       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
409
410       NotifyCursorPosition();
411     }
412   }
413 }
414
415 /**
416  * Called when an InputMethodContext retrieve surround event is received.
417  * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
418  * We need to signal the application to tell us this information.
419  */
420 bool InputMethodContextX::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
421 {
422   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::RetrieveSurrounding\n" );
423
424   Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
425   Dali::InputMethodContext handle( this );
426   Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
427
428   if( callbackData.update )
429   {
430     if( text )
431     {
432       *text = strdup( callbackData.currentText.c_str() );
433     }
434
435     if( cursorPosition )
436     {
437       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
438       *cursorPosition = mIMFCursorPosition;
439     }
440   }
441
442   return EINA_TRUE;
443 }
444
445 /**
446  * Called when an InputMethodContext delete surrounding event is received.
447  * Here we tell the application that it should delete a certain range.
448  */
449 void InputMethodContextX::DeleteSurrounding( void* data, ImfContext* imfContext, void* event_info )
450 {
451   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DeleteSurrounding\n" );
452
453   if( Dali::Adaptor::IsAvailable() )
454   {
455     Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( event_info );
456
457     Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
458     Dali::InputMethodContext handle( this );
459     Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
460
461     if( callbackData.update )
462     {
463       mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
464
465       NotifyCursorPosition();
466     }
467   }
468 }
469
470 void InputMethodContextX::NotifyCursorPosition()
471 {
472   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::NotifyCursorPosition\n" );
473
474   if( mIMFContext )
475   {
476     ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
477   }
478 }
479
480 void InputMethodContextX::SetCursorPosition( unsigned int cursorPosition )
481 {
482   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetCursorPosition\n" );
483
484   mIMFCursorPosition = static_cast<int>( cursorPosition );
485 }
486
487 unsigned int InputMethodContextX::GetCursorPosition() const
488 {
489   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetCursorPosition\n" );
490
491   return static_cast<unsigned int>( mIMFCursorPosition );
492 }
493
494 void InputMethodContextX::SetSurroundingText( const std::string& text )
495 {
496   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetSurroundingText\n" );
497
498   mSurroundingText = text;
499 }
500
501 const std::string& InputMethodContextX::GetSurroundingText() const
502 {
503   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetSurroundingText\n" );
504
505   return mSurroundingText;
506 }
507
508 void InputMethodContextX::NotifyTextInputMultiLine( bool multiLine )
509 {
510 }
511
512 Dali::InputMethodContext::TextDirection InputMethodContextX::GetTextDirection()
513 {
514   Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
515
516     if ( mIMFContext )
517     {
518       char* locale( NULL );
519       ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
520
521       if ( locale )
522       {
523         direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
524         free( locale );
525       }
526     }
527
528   return direction;
529 }
530
531 Rect<int> InputMethodContextX::GetInputMethodArea()
532 {
533   int xPos, yPos, width, height;
534
535   width = height = xPos = yPos = 0;
536
537   if( mIMFContext )
538   {
539     ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
540   }
541   else
542   {
543     DALI_LOG_WARNING("VKB Unable to get InputMethodContext Context so GetSize unavailable\n");
544   }
545
546   return Rect<int>(xPos,yPos,width,height);
547 }
548
549 void InputMethodContextX::ApplyOptions( const InputMethodOptions& options )
550 {
551   using namespace Dali::InputMethod::Category;
552
553   int index;
554
555   if (mIMFContext == NULL)
556   {
557     DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
558     return;
559   }
560
561   if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
562   {
563   }
564   if ( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
565   {
566   }
567   if ( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
568   {
569   }
570   if ( mOptions.CompareAndSet(VARIATION, options, index) )
571   {
572   }
573 }
574
575 void InputMethodContextX::SetInputPanelData( const std::string& data )
576 {
577   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelData\n" );
578
579   if( mIMFContext )
580   {
581     int length = data.length();
582     ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
583   }
584 }
585
586 void InputMethodContextX::GetInputPanelData( std::string& data )
587 {
588   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelData\n" );
589
590   if( mIMFContext )
591   {
592     int length = 4096; // The max length is 4096 bytes
593     Dali::Vector< char > buffer;
594     buffer.Resize( length );
595     ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
596     data = std::string( buffer.Begin(), buffer.End() );
597   }
598 }
599
600 Dali::InputMethodContext::State InputMethodContextX::GetInputPanelState()
601 {
602   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelState\n" );
603
604   if( mIMFContext )
605   {
606     int value;
607     value = ecore_imf_context_input_panel_state_get( mIMFContext );
608
609     switch (value)
610     {
611       case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
612       {
613         return Dali::InputMethodContext::SHOW;
614         break;
615       }
616
617       case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
618       {
619         return Dali::InputMethodContext::HIDE;
620         break;
621       }
622
623       case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
624       {
625         return Dali::InputMethodContext::WILL_SHOW;
626         break;
627       }
628
629       default:
630       {
631         return Dali::InputMethodContext::DEFAULT;
632       }
633     }
634   }
635   return Dali::InputMethodContext::DEFAULT;
636 }
637
638 void InputMethodContextX::SetReturnKeyState( bool visible )
639 {
640   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetReturnKeyState\n" );
641
642   if( mIMFContext )
643   {
644     ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
645   }
646 }
647
648 void InputMethodContextX::AutoEnableInputPanel( bool enabled )
649 {
650   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::AutoEnableInputPanel\n" );
651
652   if( mIMFContext )
653   {
654     ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
655   }
656 }
657
658 void InputMethodContextX::ShowInputPanel()
659 {
660   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::ShowInputPanel\n" );
661
662   if( mIMFContext )
663   {
664     ecore_imf_context_input_panel_show( mIMFContext );
665   }
666 }
667
668 void InputMethodContextX::HideInputPanel()
669 {
670   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::HideInputPanel\n" );
671
672   if( mIMFContext )
673   {
674     ecore_imf_context_input_panel_hide( mIMFContext );
675   }
676 }
677
678 Dali::InputMethodContext::KeyboardType InputMethodContextX::GetKeyboardType()
679 {
680   return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
681 }
682
683 std::string InputMethodContextX::GetInputPanelLocale()
684 {
685   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLocale\n" );
686
687   std::string locale = "";
688
689   if( mIMFContext )
690   {
691     char* value = NULL;
692     ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
693
694     if( value )
695     {
696       std::string valueCopy( value );
697       locale = valueCopy;
698
699       // The locale string retrieved must be freed with free().
700       free( value );
701     }
702   }
703   return locale;
704 }
705
706 bool InputMethodContextX::FilterEventKey( const Dali::KeyEvent& keyEvent )
707 {
708   bool eventHandled( false );
709
710   // If a device key then skip ecore_imf_context_filter_event.
711   if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))
712   {
713     //check whether it's key down or key up event
714     if ( keyEvent.state == KeyEvent::Down )
715     {
716       eventHandled = ProcessEventKeyDown( keyEvent );
717     }
718     else if ( keyEvent.state == KeyEvent::Up )
719     {
720       eventHandled = ProcessEventKeyUp( keyEvent );
721     }
722   }
723
724   return eventHandled;
725 }
726
727 void InputMethodContextX::AllowTextPrediction( bool prediction )
728 {
729   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::AllowTextPrediction\n" );
730
731   if( mIMFContext )
732   {
733     ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
734   }
735 }
736
737 bool InputMethodContextX::IsTextPredictionAllowed() const
738 {
739   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::IsTextPredictionAllowed\n" );
740   bool prediction = false;
741   if( mIMFContext )
742   {
743     prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
744   }
745   return prediction;
746 }
747
748 bool InputMethodContextX::ProcessEventKeyDown( const KeyEvent& keyEvent )
749 {
750   bool eventHandled( false );
751   if ( mIMFContext )
752   {
753     Integration::KeyEvent integKeyEvent( keyEvent );
754     std::string key = integKeyEvent.logicalKey;
755
756     std::string compose = keyEvent.GetCompose();
757
758     // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
759     Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
760     ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
761     ecoreKeyDownEvent.key = key.c_str();
762     ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
763     ecoreKeyDownEvent.compose = compose.c_str();
764     ecoreKeyDownEvent.timestamp = keyEvent.time;
765     ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
766     ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
767 #ifdef ECORE_IMF_1_13
768     ecoreKeyDownEvent.dev_name  = "";
769     ecoreKeyDownEvent.dev_class = ECORE_IMF_DEVICE_CLASS_KEYBOARD;
770     ecoreKeyDownEvent.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
771 #endif // ECORE_IMF_1_13
772
773     // 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.
774     if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
775                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
776                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
777                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
778     {
779       eventHandled = 0;
780     }
781     else
782     {
783       eventHandled = ecore_imf_context_filter_event(mIMFContext,
784                                                     ECORE_IMF_EVENT_KEY_DOWN,
785                                                     reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ));
786     }
787
788     // If the event has not been handled by InputMethodContext then check if we should reset our IMFcontext
789     if (!eventHandled)
790     {
791       if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
792           !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
793           !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
794       {
795         ecore_imf_context_reset(mIMFContext);
796       }
797     }
798   }
799   return eventHandled;
800 }
801
802 bool InputMethodContextX::ProcessEventKeyUp( const KeyEvent& keyEvent )
803 {
804   bool eventHandled( false );
805   if( mIMFContext )
806   {
807     Integration::KeyEvent integKeyEvent( keyEvent );
808     std::string key = integKeyEvent.logicalKey;
809
810     std::string compose = keyEvent.GetCompose();
811
812     // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
813     Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
814     ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
815     ecoreKeyUpEvent.key = key.c_str();
816     ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
817     ecoreKeyUpEvent.compose = compose.c_str();
818     ecoreKeyUpEvent.timestamp = keyEvent.time;
819     ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
820     ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
821 #ifdef ECORE_IMF_1_13
822     ecoreKeyUpEvent.dev_name  = "";
823 #endif // ECORE_IMF_1_13
824
825     eventHandled = ecore_imf_context_filter_event(mIMFContext,
826                                                   ECORE_IMF_EVENT_KEY_UP,
827                                                   reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ));
828   }
829   return eventHandled;
830 }
831
832 Ecore_IMF_Keyboard_Modifiers InputMethodContextX::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
833 {
834   unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE );  // If no other matches returns NONE.
835
836   if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT )  // enums from ecore_input/Ecore_Input.h
837   {
838     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;  // enums from ecore_imf/ecore_imf.h
839   }
840
841   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
842   {
843     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
844   }
845
846   if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
847   {
848     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
849   }
850
851   if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
852   {
853     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
854   }
855
856   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
857   {
858     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
859   }
860
861   return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
862 }
863
864 Ecore_IMF_Keyboard_Locks InputMethodContextX::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
865 {
866     unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
867
868     if( modifier & ECORE_EVENT_LOCK_NUM )
869     {
870       lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
871     }
872
873     if( modifier & ECORE_EVENT_LOCK_CAPS )
874     {
875       lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
876     }
877
878     if( modifier & ECORE_EVENT_LOCK_SCROLL )
879     {
880       lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
881     }
882
883     return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
884 }
885
886 } // Adaptor
887
888 } // Internal
889
890 } // Dali