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