Add AllowTextPrediction/IsTextPredictionAllowed api
[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_Input.h>
27
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/system/common/singleton-service-impl.h>
37 #include <dali/public-api/adaptor-framework/input-method.h>
38 #include <dali/internal/input/common/key-impl.h>
39 #include <dali/internal/window-system/common/window-render-surface.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
269   // Create instance only if the adaptor is available
270   if ( Dali::Adaptor::IsAvailable() )
271   {
272     Any nativeWindow = Dali::Adaptor::Get().GetNativeWindowHandle();
273
274     // The window needs to use the InputMethodContext.
275     // Only when the render surface is window, we can get the window.
276     if( !nativeWindow.Empty() )
277     {
278       inputMethodContext = new InputMethodContextEcoreWl();
279     }
280     else
281     {
282       DALI_LOG_ERROR("Failed to get native window handle, can't create InputMethodContext instance.\n");
283     }
284   }
285   return inputMethodContext;
286 }
287
288 void InputMethodContextEcoreWl::Finalize()
289 {
290   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::Finalize\n" );
291
292   DisconnectCallbacks();
293   DeleteContext();
294 }
295
296 InputMethodContextEcoreWl::InputMethodContextEcoreWl()
297 : mIMFContext(),
298   mIMFCursorPosition( 0 ),
299   mSurroundingText(),
300   mRestoreAfterFocusLost( false ),
301   mIdleCallbackConnected( false )
302 {
303   ecore_imf_init();
304 }
305
306 InputMethodContextEcoreWl::~InputMethodContextEcoreWl()
307 {
308   Finalize();
309   ecore_imf_shutdown();
310 }
311
312 void InputMethodContextEcoreWl::Initialize()
313 {
314   CreateContext();
315   ConnectCallbacks();
316 }
317
318 void InputMethodContextEcoreWl::CreateContext()
319 {
320   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::CreateContext\n" );
321
322   const char *contextId = ecore_imf_context_default_id_get();
323   if( contextId )
324   {
325     mIMFContext = ecore_imf_context_add( contextId );
326
327     if( mIMFContext )
328     {
329       // If we fail to get window id, we can't use the InputMethodContext correctly.
330       // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
331       // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
332       RenderSurface& renderSurface = Dali::Adaptor::Get().GetSurface();
333       WindowRenderSurface& windowRenderSurface = static_cast< WindowRenderSurface& >( renderSurface );
334
335       int windowId = windowRenderSurface.GetNativeWindowId();
336       if( windowId != 0 )
337       {
338         ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast< void* >( windowId ) );
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 void InputMethodContextEcoreWl::AllowTextPrediction( bool prediction )
924 {
925   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AllowTextPrediction\n" );
926
927   if( mIMFContext )
928   {
929     ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
930   }
931 }
932
933 bool InputMethodContextEcoreWl::IsTextPredictionAllowed() const
934 {
935   DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::IsTextPredictionAllowed\n" );
936   bool prediction = false;
937   if( mIMFContext )
938   {
939     prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
940   }
941   return prediction;
942 }
943
944 bool InputMethodContextEcoreWl::ProcessEventKeyDown( const KeyEvent& keyEvent )
945 {
946   bool eventHandled( false );
947   if ( mIMFContext )
948   {
949     // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
950     Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
951     ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
952     ecoreKeyDownEvent.key = keyEvent.keyPressedName.c_str();
953     ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
954     ecoreKeyDownEvent.compose = keyEvent.GetCompose().c_str();
955     ecoreKeyDownEvent.timestamp = keyEvent.time;
956     ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
957     ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
958     ecoreKeyDownEvent.dev_name = keyEvent.GetDeviceName().c_str();
959     ecoreKeyDownEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
960     ecoreKeyDownEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
961
962     // 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.
963     if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
964                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
965                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
966                                    (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
967     {
968       eventHandled = 0;
969     }
970     else
971     {
972       eventHandled = ecore_imf_context_filter_event(mIMFContext,
973                                                     ECORE_IMF_EVENT_KEY_DOWN,
974                                                     (Ecore_IMF_Event *) &ecoreKeyDownEvent);
975     }
976
977     // If the event has not been handled by InputMethodContext then check if we should reset our input method context
978     if (!eventHandled)
979     {
980       if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
981           !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
982           !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
983       {
984         ecore_imf_context_reset(mIMFContext);
985       }
986     }
987   }
988   return eventHandled;
989 }
990
991 bool InputMethodContextEcoreWl::ProcessEventKeyUp( const KeyEvent& keyEvent )
992 {
993   bool eventHandled( false );
994   if( mIMFContext )
995   {
996     // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
997     Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
998     ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
999     ecoreKeyUpEvent.key = keyEvent.keyPressedName.c_str();
1000     ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
1001     ecoreKeyUpEvent.compose = keyEvent.GetCompose().c_str();
1002     ecoreKeyUpEvent.timestamp = keyEvent.time;
1003     ecoreKeyUpEvent.modifiers =  EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
1004     ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
1005     ecoreKeyUpEvent.dev_name = keyEvent.GetDeviceName().c_str();
1006     ecoreKeyUpEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1007     ecoreKeyUpEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
1008
1009     eventHandled = ecore_imf_context_filter_event(mIMFContext,
1010                                                   ECORE_IMF_EVENT_KEY_UP,
1011                                                   (Ecore_IMF_Event *) &ecoreKeyUpEvent);
1012   }
1013   return eventHandled;
1014 }
1015
1016 Ecore_IMF_Keyboard_Modifiers InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
1017 {
1018   unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE );  // If no other matches returns NONE.
1019
1020   if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT )  // enums from ecore_input/Ecore_Input.h
1021   {
1022     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;  // enums from ecore_imf/ecore_imf.h
1023   }
1024
1025   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
1026   {
1027     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
1028   }
1029
1030   if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
1031   {
1032     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
1033   }
1034
1035   if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
1036   {
1037     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
1038   }
1039
1040   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
1041   {
1042     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
1043   }
1044
1045   return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
1046 }
1047
1048 Ecore_IMF_Keyboard_Locks InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
1049 {
1050     unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
1051
1052     if( modifier & ECORE_EVENT_LOCK_NUM )
1053     {
1054       lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
1055     }
1056
1057     if( modifier & ECORE_EVENT_LOCK_CAPS )
1058     {
1059       lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
1060     }
1061
1062     if( modifier & ECORE_EVENT_LOCK_SCROLL )
1063     {
1064       lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
1065     }
1066
1067     return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
1068 }
1069
1070 } // Adaptor
1071
1072 } // Internal
1073
1074 } // Dali
1075
1076 #pragma GCC diagnostic pop