2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "toolkit-imf-manager.h"
22 #include <boost/bind.hpp>
23 #include <Ecore_IMF.h>
26 #include <dali/dali.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/integration-api/events/key-event-integ.h>
39 class ImfManager : public Dali::BaseObject
42 typedef Dali::ImfManager::ImfManagerSignalV2 ImfManagerSignalV2;
43 typedef Dali::ImfManager::ImfEventSignalV2 ImfEventSignalV2;
46 static Dali::ImfManager Get();
48 ImfManager( /* Ecore_X_Window ecoreXwin */ );
49 void ConnectCallbacks();
50 void DisconnectCallbacks();
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();
69 ImfManagerSignalV2& ActivatedSignal() { return mActivatedSignalV2; }
70 ImfEventSignalV2& EventReceivedSignal() { return mEventSignalV2; }
73 virtual ~ImfManager();
76 void CreateContext( /*Ecore_X_Window ecoreXwin*/ );
81 ImfManager( const ImfManager& );
82 ImfManager& operator=( ImfManager& );
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.
91 std::vector<Dali::Integration::KeyEvent> mKeyEvents; ///< Stores key events to be sent from idle call-back.
92 ImfManagerSignalV2 mActivatedSignalV2;
93 ImfEventSignalV2 mEventSignalV2;
96 static Dali::ImfManager mToolkitImfManager;
100 inline static Internal::Adaptor::ImfManager& GetImplementation(Dali::ImfManager& imfManager)
102 Dali::ImfManager actualImfManager = ImfManager::Get();
104 BaseObject& handle = actualImfManager.GetBaseObject();
105 return static_cast<Internal::Adaptor::ImfManager&>(handle);
108 inline static const Internal::Adaptor::ImfManager& GetImplementation(const Dali::ImfManager& imfManager)
110 Dali::ImfManager actualImfManager = ImfManager::Get();
112 const BaseObject& handle = imfManager.GetBaseObject();
113 return static_cast<const Internal::Adaptor::ImfManager&>(handle);
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)
127 if ((leadByte & 0x80) == 0 ) //ASCII character (lead bit zero)
131 else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
135 else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
139 else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
147 // Static function calls used by ecore 'c' style callback registration
148 void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
152 ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
153 imfManager->CommitReceived( data, imfContext, event_info );
157 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
161 ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
162 imfManager->PreEditChanged( data, imfContext, event_info );
166 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
170 ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
171 return imfManager->RetrieveSurrounding( data, imfContext, text, cursorPosition );
180 * Called when an IMF delete surrounding event is received.
181 * Here we tell the application that it should delete a certain range.
183 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
187 ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
188 imfManager->DeleteSurrounding( data, imfContext, event_info );
192 } // unnamed namespace
194 Dali::ImfManager Dali::Internal::Adaptor::ImfManager::mToolkitImfManager;
197 Dali::ImfManager ImfManager::Get()
199 Dali::ImfManager manager;
201 if( ! mToolkitImfManager )
203 mToolkitImfManager = Dali::ImfManager( new Dali::Internal::Adaptor::ImfManager() );
205 return mToolkitImfManager;
208 ImfManager::ImfManager( /*Ecore_X_Window ecoreXwin*/ )
210 mIMFCursorPosition( 0 ),
211 mSurroundingText(""),
212 mRestoreAfterFocusLost( false ),
213 mIdleCallbackConnected( false ),
217 CreateContext( /*ecoreXwin*/ );
219 //VirtualKeyboard::ConnectCallbacks( mIMFContext );
222 ImfManager::~ImfManager()
224 //VirtualKeyboard::DisconnectCallbacks( mIMFContext );
225 DisconnectCallbacks();
227 //ecore_imf_shutdown();
230 void ImfManager::CreateContext( /*Ecore_X_Window ecoreXwin*/ )
234 void ImfManager::DeleteContext()
238 // Callbacks for predicitive text support.
239 void ImfManager::ConnectCallbacks()
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 );
248 void ImfManager::DisconnectCallbacks()
250 // if ( mIMFContext )
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 );
258 void ImfManager::Activate()
260 // // Reset mIdleCallbackConnected
261 // mIdleCallbackConnected = false;
263 // if ( mIMFContext )
265 // ecore_imf_context_focus_in( mIMFContext );
266 // // emit keyboard activated signal
267 // Dali::ImfManager handle( this );
268 // mActivatedSignalV2.Emit( handle );
272 void ImfManager::Deactivate()
277 // ecore_imf_context_focus_out( mIMFContext );
279 // // Reset mIdleCallbackConnected
280 // mIdleCallbackConnected = false;
283 void ImfManager::Reset()
285 // if ( mIMFContext )
287 // ecore_imf_context_reset( mIMFContext );
291 Ecore_IMF_Context* ImfManager::GetContext()
293 //return mIMFContext;
297 bool ImfManager::RestoreAfterFocusLost() const
299 return mRestoreAfterFocusLost;
302 void ImfManager::SetRestoreAferFocusLost( bool toggle )
304 mRestoreAfterFocusLost = toggle;
307 void ImfManager::PreEditChanged( void *, Ecore_IMF_Context *imfContext, void *event_info )
309 // char *preEditString( NULL );
310 // int cursorPosition( 0 );
311 // Eina_List *attrs = NULL;
312 // Eina_List *l = NULL;
314 // Ecore_IMF_Preedit_Attr *attr;
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 );
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) ))
324 // if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
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' )
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 )
336 // cursorPosition = visualCharacterIndex;
338 // // end loop as found cursor position that matches byte position
342 // byteIndex += currentSequenceLength; // jump to next character
343 // visualCharacterIndex++; // increment character count so we know our position for when we get a match
345 // DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
350 // if ( Dali::Adaptor::IsAvailable() )
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 )
359 // SetCursorPosition( callbackData.cursorPosition );
360 // SetSurroundingText( callbackData.currentText );
361 // NotifyCursorPosition();
363 // if ( callbackData.preeditResetRequired )
368 // free( preEditString );
371 void ImfManager::CommitReceived( void *, Ecore_IMF_Context *imfContext, void *event_info )
373 // if ( Dali::Adaptor::IsAvailable() )
375 // const std::string keyString( (char *)event_info );
376 // const int cursorOffset( 0 );
377 // const int numberOfChars( 0 );
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 );
383 // if ( callbackData.update )
385 // SetCursorPosition( callbackData.cursorPosition );
386 // SetSurroundingText( callbackData.currentText );
388 // NotifyCursorPosition();
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.
398 Eina_Bool ImfManager::RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
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 );
408 // std::string surroundingText( GetSurroundingText() );
409 // if ( !surroundingText.empty() )
411 // *text = strdup( surroundingText.c_str() );
415 // *text = strdup( "" );
418 // if ( cursorPosition )
420 // *cursorPosition = GetCursorPosition();
426 * Called when an IMF delete surrounding event is received.
427 * Here we tell the application that it should delete a certain range.
429 void ImfManager::DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
431 // if ( Dali::Adaptor::IsAvailable() )
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 );
443 void ImfManager::NotifyCursorPosition()
445 // if ( mIMFContext )
447 // ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
451 int ImfManager::GetCursorPosition()
453 return mIMFCursorPosition;
456 void ImfManager::SetCursorPosition( unsigned int cursorPosition )
458 mIMFCursorPosition = ( int )cursorPosition;
461 void ImfManager::SetSurroundingText( std::string text )
463 mSurroundingText = text;
466 std::string ImfManager::GetSurroundingText()
468 return mSurroundingText;
476 /********************************************************************************/
477 /********************************* PUBLIC CLASS *******************************/
478 /********************************************************************************/
480 ImfManager::ImfManager()
484 ImfManager::~ImfManager()
488 ImfManager ImfManager::Get()
490 return Internal::Adaptor::ImfManager::Get();
493 ImfContext ImfManager::GetContext()
495 return reinterpret_cast<ImfContext>( Internal::Adaptor::ImfManager::GetImplementation(*this).GetContext() );
498 void ImfManager::Activate()
500 Internal::Adaptor::ImfManager::GetImplementation(*this).Activate();
503 void ImfManager::Deactivate()
505 Internal::Adaptor::ImfManager::GetImplementation(*this).Deactivate();
508 bool ImfManager::RestoreAfterFocusLost() const
510 return Internal::Adaptor::ImfManager::GetImplementation(*this).RestoreAfterFocusLost();
513 void ImfManager::SetRestoreAferFocusLost( bool toggle )
515 Internal::Adaptor::ImfManager::GetImplementation(*this).SetRestoreAferFocusLost( toggle );
518 void ImfManager::Reset()
520 Internal::Adaptor::ImfManager::GetImplementation(*this).Reset();
523 void ImfManager::NotifyCursorPosition()
525 Internal::Adaptor::ImfManager::GetImplementation(*this).NotifyCursorPosition();
528 void ImfManager::SetCursorPosition( unsigned int SetCursorPosition )
530 Internal::Adaptor::ImfManager::GetImplementation(*this).SetCursorPosition( SetCursorPosition );
533 int ImfManager::GetCursorPosition()
535 return Internal::Adaptor::ImfManager::GetImplementation(*this).GetCursorPosition();
538 void ImfManager::SetSurroundingText( std::string text )
540 Internal::Adaptor::ImfManager::GetImplementation(*this).SetSurroundingText( text );
543 std::string ImfManager::GetSurroundingText()
545 return Internal::Adaptor::ImfManager::GetImplementation(*this).GetSurroundingText();
548 ImfManager::ImfManagerSignalV2& ImfManager::ActivatedSignal()
550 return Internal::Adaptor::ImfManager::GetImplementation(*this).ActivatedSignal();
553 ImfManager::ImfEventSignalV2& ImfManager::EventReceivedSignal()
555 return Internal::Adaptor::ImfManager::GetImplementation(*this).EventReceivedSignal();
558 ImfManager::ImfManager(Internal::Adaptor::ImfManager *impl)