e895caee6bb75d630c46ed959b7a5714dc1c7058
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit / dali-toolkit-test-utils / toolkit-imf-manager.cpp
1 /*
2  * Copyright (c) 2014 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 "toolkit-imf-manager.h"
20
21 // EXTERNAL INCLUDES
22 #include <boost/bind.hpp>
23 #include <Ecore_IMF.h>
24 #include <Ecore_X.h>
25
26 #include <dali/dali.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/integration-api/events/key-event-integ.h>
29
30 namespace Dali
31 {
32 namespace Internal
33 {
34 namespace Adaptor
35 {
36 class RenderSurface;
37
38
39 class ImfManager : public Dali::BaseObject
40 {
41 public:
42   typedef Dali::ImfManager::ImfManagerSignalV2 ImfManagerSignalV2;
43   typedef Dali::ImfManager::ImfEventSignalV2 ImfEventSignalV2;
44
45 public:
46   static Dali::ImfManager Get();
47
48   ImfManager( /* Ecore_X_Window ecoreXwin */ );
49   void ConnectCallbacks();
50   void DisconnectCallbacks();
51   void Activate();
52   void Deactivate();
53   void Reset();
54
55   Ecore_IMF_Context* GetContext();
56   bool RestoreAfterFocusLost() const;
57   void SetRestoreAferFocusLost( bool toggle );
58   void PreEditChanged( void *data, Ecore_IMF_Context *imfContext, void *event_info );
59   void CommitReceived( void *data, Ecore_IMF_Context *imfContext, void *event_info );
60   Eina_Bool RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition );
61   void DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info );
62   void NotifyCursorPosition();
63   int GetCursorPosition();
64   void SetCursorPosition( unsigned int cursorPosition );
65   void SetSurroundingText( std::string text );
66   std::string GetSurroundingText();
67
68 public:  // Signals
69   ImfManagerSignalV2& ActivatedSignal() { return mActivatedSignalV2; }
70   ImfEventSignalV2& EventReceivedSignal() { return mEventSignalV2; }
71
72 protected:
73   virtual ~ImfManager();
74
75 private:
76   void CreateContext( /*Ecore_X_Window ecoreXwin*/ );
77   void DeleteContext();
78
79 private:
80   // Undefined
81   ImfManager( const ImfManager& );
82   ImfManager& operator=( ImfManager& );
83
84 private:
85   Ecore_IMF_Context* mIMFContext;
86   int mIMFCursorPosition;
87   std::string mSurroundingText;
88   bool mRestoreAfterFocusLost:1;             ///< Whether the keyboard needs to be restored (activated ) after focus regained.
89   bool mIdleCallbackConnected:1;             ///< Whether the idle callback is already connected.
90
91   std::vector<Dali::Integration::KeyEvent> mKeyEvents; ///< Stores key events to be sent from idle call-back.
92   ImfManagerSignalV2      mActivatedSignalV2;
93   ImfEventSignalV2        mEventSignalV2;
94
95
96   static Dali::ImfManager mToolkitImfManager;
97
98 public:
99
100 inline static Internal::Adaptor::ImfManager& GetImplementation(Dali::ImfManager& imfManager)
101 {
102   Dali::ImfManager actualImfManager = ImfManager::Get();
103
104   BaseObject& handle = actualImfManager.GetBaseObject();
105   return static_cast<Internal::Adaptor::ImfManager&>(handle);
106 }
107
108 inline static const  Internal::Adaptor::ImfManager& GetImplementation(const Dali::ImfManager& imfManager)
109 {
110   Dali::ImfManager actualImfManager = ImfManager::Get();
111
112   const BaseObject& handle = imfManager.GetBaseObject();
113   return static_cast<const Internal::Adaptor::ImfManager&>(handle);
114 }
115
116 };
117
118
119 namespace
120 {
121
122 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
123 size_t Utf8SequenceLength(const unsigned char leadByte)
124 {
125   size_t length = 0;
126
127   if ((leadByte & 0x80) == 0 )          //ASCII character (lead bit zero)
128   {
129     length = 1;
130   }
131   else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
132   {
133     length = 2;
134   }
135   else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
136   {
137     length = 3;
138   }
139   else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
140   {
141     length = 4;
142   }
143
144   return length;
145 }
146
147 // Static function calls used by ecore 'c' style callback registration
148 void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
149 {
150   if ( data )
151   {
152     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
153     imfManager->CommitReceived( data, imfContext, event_info );
154   }
155 }
156
157 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
158 {
159   if ( data )
160   {
161     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
162     imfManager->PreEditChanged( data, imfContext, event_info );
163   }
164 }
165
166 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
167 {
168   if ( data )
169   {
170     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
171     return imfManager->RetrieveSurrounding( data, imfContext, text, cursorPosition );
172   }
173   else
174   {
175     return false;
176   }
177 }
178
179 /**
180  * Called when an IMF delete surrounding event is received.
181  * Here we tell the application that it should delete a certain range.
182  */
183 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
184 {
185   if ( data )
186   {
187     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
188     imfManager->DeleteSurrounding( data, imfContext, event_info );
189   }
190 }
191
192 } // unnamed namespace
193
194 Dali::ImfManager Dali::Internal::Adaptor::ImfManager::mToolkitImfManager;
195
196
197 Dali::ImfManager ImfManager::Get()
198 {
199   Dali::ImfManager manager;
200
201   if( ! mToolkitImfManager )
202   {
203     mToolkitImfManager = Dali::ImfManager( new Dali::Internal::Adaptor::ImfManager() );
204   }
205   return mToolkitImfManager;
206 }
207
208 ImfManager::ImfManager( /*Ecore_X_Window ecoreXwin*/ )
209 : mIMFContext(),
210   mIMFCursorPosition( 0 ),
211   mSurroundingText(""),
212   mRestoreAfterFocusLost( false ),
213   mIdleCallbackConnected( false ),
214   mKeyEvents()
215 {
216   //ecore_imf_init();
217   CreateContext( /*ecoreXwin*/ );
218   ConnectCallbacks();
219   //VirtualKeyboard::ConnectCallbacks( mIMFContext );
220 }
221
222 ImfManager::~ImfManager()
223 {
224   //VirtualKeyboard::DisconnectCallbacks( mIMFContext );
225   DisconnectCallbacks();
226   DeleteContext();
227   //ecore_imf_shutdown();
228 }
229
230 void ImfManager::CreateContext( /*Ecore_X_Window ecoreXwin*/ )
231 {
232 }
233
234 void ImfManager::DeleteContext()
235 {
236 }
237
238 // Callbacks for predicitive text support.
239 void ImfManager::ConnectCallbacks()
240 {
241   //if ( mIMFContext )  {
242   //ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit,    this );
243   //ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit,     this );
244   //ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
245   //}
246 }
247
248 void ImfManager::DisconnectCallbacks()
249 {
250   // if ( mIMFContext )
251   // {
252   //   ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit );
253   //   ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit );
254   //   ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
255   // }
256 }
257
258 void ImfManager::Activate()
259 {
260   // // Reset mIdleCallbackConnected
261   // mIdleCallbackConnected = false;
262
263   // if ( mIMFContext )
264   // {
265   //   ecore_imf_context_focus_in( mIMFContext );
266   //   // emit keyboard activated signal
267   //   Dali::ImfManager handle( this );
268   //   mActivatedSignalV2.Emit( handle );
269   // }
270 }
271
272 void ImfManager::Deactivate()
273 {
274   // if( mIMFContext )
275   // {
276   //   Reset();
277   //   ecore_imf_context_focus_out( mIMFContext );
278   // }
279   // // Reset mIdleCallbackConnected
280   // mIdleCallbackConnected = false;
281 }
282
283 void ImfManager::Reset()
284 {
285   // if ( mIMFContext )
286   // {
287   //   ecore_imf_context_reset( mIMFContext );
288   // }
289 }
290
291 Ecore_IMF_Context* ImfManager::GetContext()
292 {
293   //return mIMFContext;
294   return NULL;
295 }
296
297 bool ImfManager::RestoreAfterFocusLost() const
298 {
299   return mRestoreAfterFocusLost;
300 }
301
302 void ImfManager::SetRestoreAferFocusLost( bool toggle )
303 {
304   mRestoreAfterFocusLost = toggle;
305 }
306
307 void ImfManager::PreEditChanged( void *, Ecore_IMF_Context *imfContext, void *event_info )
308 {
309   // char *preEditString( NULL );
310   // int cursorPosition( 0 );
311   // Eina_List *attrs = NULL;
312   // Eina_List *l = NULL;
313
314   // Ecore_IMF_Preedit_Attr *attr;
315
316   // // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
317   // // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
318   // ecore_imf_context_preedit_string_with_attributes_get( imfContext, &preEditString, &attrs, &cursorPosition );
319   // if ( attrs )
320   // {
321   //   // iterate through the list of attributes getting the type, start and end position.
322   //   for ( l = attrs, (attr =  (Ecore_IMF_Preedit_Attr*)eina_list_data_get(l) ); l; l = eina_list_next(l), ( attr = (Ecore_IMF_Preedit_Attr*)eina_list_data_get(l) ))
323   //   {
324   //     if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
325   //     {
326   //       // 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.
327   //       size_t visualCharacterIndex = 0;
328   //       size_t byteIndex = 0;
329   //       // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
330   //       while ( preEditString[byteIndex] != '\0' )
331   //       {
332   //         // attr->end_index is provided as a byte position not character and we need to know the character position.
333   //         size_t currentSequenceLength = Utf8SequenceLength(preEditString[byteIndex]); // returns number of bytes used to represent character.
334   //         if ( byteIndex == attr->end_index )
335   //         {
336   //           cursorPosition = visualCharacterIndex;
337   //           break;
338   //           // end loop as found cursor position that matches byte position
339   //         }
340   //         else
341   //         {
342   //           byteIndex += currentSequenceLength; // jump to next character
343   //           visualCharacterIndex++;  // increment character count so we know our position for when we get a match
344   //         }
345   //         DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
346   //       }
347   //     }
348   //   }
349   // }
350   // if ( Dali::Adaptor::IsAvailable() )
351   // {
352   //   std::string keyString ( preEditString );
353   //   int numberOfChars( 0 );
354   //   Dali::ImfManager handle( this );
355   //   Dali::ImfManager::ImfEventData imfEventData ( Dali::ImfManager::PREEDIT, keyString, cursorPosition, numberOfChars );
356   //   Dali::ImfManager::ImfCallbackData callbackData = mEventSignalV2.Emit( handle, imfEventData );
357   //   if ( callbackData.update )
358   //   {
359   //     SetCursorPosition( callbackData.cursorPosition );
360   //     SetSurroundingText( callbackData.currentText );
361   //     NotifyCursorPosition();
362   //   }
363   //   if ( callbackData.preeditResetRequired )
364   //   {
365   //     Reset();
366   //   }
367   // }
368   // free( preEditString );
369 }
370
371 void ImfManager::CommitReceived( void *, Ecore_IMF_Context *imfContext, void *event_info )
372 {
373   // if ( Dali::Adaptor::IsAvailable() )
374   // {
375   //   const std::string keyString( (char *)event_info );
376   //   const int cursorOffset( 0 );
377   //   const int numberOfChars( 0 );
378
379   //   Dali::ImfManager handle( this );
380   //   Dali::ImfManager::ImfEventData imfEventData ( Dali::ImfManager::COMMIT, keyString, cursorOffset, numberOfChars );
381   //   Dali::ImfManager::ImfCallbackData callbackData = mEventSignalV2.Emit( handle, imfEventData );
382
383   //   if ( callbackData.update )
384   //   {
385   //     SetCursorPosition( callbackData.cursorPosition );
386   //     SetSurroundingText( callbackData.currentText );
387
388   //     NotifyCursorPosition();
389   //   }
390   // }
391 }
392
393 /**
394  * Called when an IMF retrieve surround event is received.
395  * Here the IMF module wishes to know the string we are working with and where within the string the cursor is
396  * We need to signal the application to tell us this information.
397  */
398 Eina_Bool ImfManager::RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
399 {
400   // std::string keyString ( "" );
401   // int cursorOffset( 0 );
402   // int numberOfChars( 0 );
403   // Dali::ImfManager::ImfEventData imfData ( Dali::ImfManager::GETSURROUNDING , keyString, cursorOffset, numberOfChars );
404   // Dali::ImfManager handle( this );
405   // mEventSignalV2.Emit( handle, imfData );
406   // if ( text )
407   // {
408   //   std::string surroundingText( GetSurroundingText() );
409   //   if ( !surroundingText.empty() )
410   //   {
411   //     *text = strdup( surroundingText.c_str() );
412   //   }
413   //   else
414   //   {
415   //     *text = strdup( "" );
416   //   }
417   // }
418   // if ( cursorPosition )
419   // {
420   //   *cursorPosition = GetCursorPosition();
421   // }
422   return EINA_TRUE;
423 }
424
425 /**
426  * Called when an IMF delete surrounding event is received.
427  * Here we tell the application that it should delete a certain range.
428  */
429 void ImfManager::DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
430 {
431   // if ( Dali::Adaptor::IsAvailable() )
432   // {
433   //   Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = (Ecore_IMF_Event_Delete_Surrounding*) event_info;
434   //   const std::string keyString( "" );
435   //   const int cursorOffset( deleteSurroundingEvent->offset );
436   //   const int numberOfChars( deleteSurroundingEvent->n_chars );
437   //   Dali::ImfManager::ImfEventData imfData ( Dali::ImfManager::DELETESURROUNDING , keyString, cursorOffset, numberOfChars );
438   //   Dali::ImfManager handle( this );
439   //   mEventSignalV2.Emit( handle, imfData );
440   // }
441 }
442
443 void ImfManager::NotifyCursorPosition()
444 {
445   // if ( mIMFContext )
446   // {
447   //   ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
448   // }
449 }
450
451 int ImfManager::GetCursorPosition()
452 {
453   return mIMFCursorPosition;
454 }
455
456 void ImfManager::SetCursorPosition( unsigned int cursorPosition )
457 {
458   mIMFCursorPosition = ( int )cursorPosition;
459 }
460
461 void ImfManager::SetSurroundingText( std::string text )
462 {
463   mSurroundingText = text;
464 }
465
466 std::string ImfManager::GetSurroundingText()
467 {
468   return mSurroundingText;
469 }
470
471 } // Adaptor
472
473 } // Internal
474
475
476 /********************************************************************************/
477 /*********************************  PUBLIC CLASS  *******************************/
478 /********************************************************************************/
479
480 ImfManager::ImfManager()
481 {
482 }
483
484 ImfManager::~ImfManager()
485 {
486 }
487
488 ImfManager ImfManager::Get()
489 {
490   return Internal::Adaptor::ImfManager::Get();
491 }
492
493 ImfContext ImfManager::GetContext()
494 {
495   return reinterpret_cast<ImfContext>( Internal::Adaptor::ImfManager::GetImplementation(*this).GetContext() );
496 }
497
498 void ImfManager::Activate()
499 {
500   Internal::Adaptor::ImfManager::GetImplementation(*this).Activate();
501 }
502
503 void ImfManager::Deactivate()
504 {
505   Internal::Adaptor::ImfManager::GetImplementation(*this).Deactivate();
506 }
507
508 bool ImfManager::RestoreAfterFocusLost() const
509 {
510   return Internal::Adaptor::ImfManager::GetImplementation(*this).RestoreAfterFocusLost();
511 }
512
513 void ImfManager::SetRestoreAferFocusLost( bool toggle )
514 {
515   Internal::Adaptor::ImfManager::GetImplementation(*this).SetRestoreAferFocusLost( toggle );
516 }
517
518 void ImfManager::Reset()
519 {
520   Internal::Adaptor::ImfManager::GetImplementation(*this).Reset();
521 }
522
523 void ImfManager::NotifyCursorPosition()
524 {
525   Internal::Adaptor::ImfManager::GetImplementation(*this).NotifyCursorPosition();
526 }
527
528 void ImfManager::SetCursorPosition( unsigned int SetCursorPosition )
529 {
530   Internal::Adaptor::ImfManager::GetImplementation(*this).SetCursorPosition( SetCursorPosition );
531 }
532
533 int ImfManager::GetCursorPosition()
534 {
535   return Internal::Adaptor::ImfManager::GetImplementation(*this).GetCursorPosition();
536 }
537
538 void ImfManager::SetSurroundingText( std::string text )
539 {
540   Internal::Adaptor::ImfManager::GetImplementation(*this).SetSurroundingText( text );
541 }
542
543 std::string ImfManager::GetSurroundingText()
544 {
545   return Internal::Adaptor::ImfManager::GetImplementation(*this).GetSurroundingText();
546 }
547
548 ImfManager::ImfManagerSignalV2& ImfManager::ActivatedSignal()
549 {
550   return Internal::Adaptor::ImfManager::GetImplementation(*this).ActivatedSignal();
551 }
552
553 ImfManager::ImfEventSignalV2& ImfManager::EventReceivedSignal()
554 {
555   return Internal::Adaptor::ImfManager::GetImplementation(*this).EventReceivedSignal();
556 }
557
558 ImfManager::ImfManager(Internal::Adaptor::ImfManager *impl)
559   : BaseHandle(impl)
560 {
561 }
562
563 } // namespace Dali