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