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