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