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