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