2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include "toolkit-imf-manager.h"
21 #include <boost/bind.hpp>
22 #include <Ecore_IMF.h>
25 #include <dali/dali.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/events/key-event-integ.h>
38 class ImfManager : public Dali::BaseObject
41 typedef Dali::ImfManager::ImfManagerSignalV2 ImfManagerSignalV2;
42 typedef Dali::ImfManager::ImfEventSignalV2 ImfEventSignalV2;
45 static Dali::ImfManager Get();
47 ImfManager( /* Ecore_X_Window ecoreXwin */ );
48 void ConnectCallbacks();
49 void DisconnectCallbacks();
54 Ecore_IMF_Context* GetContext();
55 bool RestoreAfterFocusLost() const;
56 void SetRestoreAferFocusLost( bool toggle );
57 void PreEditChanged( void *data, Ecore_IMF_Context *imfContext, void *event_info );
58 void CommitReceived( void *data, Ecore_IMF_Context *imfContext, void *event_info );
59 Eina_Bool RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition );
60 void DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info );
61 void NotifyCursorPosition();
62 int GetCursorPosition();
63 void SetCursorPosition( unsigned int cursorPosition );
64 void SetSurroundingText( std::string text );
65 std::string GetSurroundingText();
68 ImfManagerSignalV2& ActivatedSignal() { return mActivatedSignalV2; }
69 ImfEventSignalV2& EventReceivedSignal() { return mEventSignalV2; }
72 virtual ~ImfManager();
75 void CreateContext( /*Ecore_X_Window ecoreXwin*/ );
80 ImfManager( const ImfManager& );
81 ImfManager& operator=( ImfManager& );
84 Ecore_IMF_Context* mIMFContext;
85 int mIMFCursorPosition;
86 std::string mSurroundingText;
87 bool mRestoreAfterFocusLost:1; ///< Whether the keyboard needs to be restored (activated ) after focus regained.
88 bool mIdleCallbackConnected:1; ///< Whether the idle callback is already connected.
90 std::vector<Dali::Integration::KeyEvent> mKeyEvents; ///< Stores key events to be sent from idle call-back.
91 ImfManagerSignalV2 mActivatedSignalV2;
92 ImfEventSignalV2 mEventSignalV2;
95 static Dali::ImfManager mToolkitImfManager;
99 inline static Internal::Adaptor::ImfManager& GetImplementation(Dali::ImfManager& imfManager)
101 Dali::ImfManager actualImfManager = ImfManager::Get();
103 BaseObject& handle = actualImfManager.GetBaseObject();
104 return static_cast<Internal::Adaptor::ImfManager&>(handle);
107 inline static const Internal::Adaptor::ImfManager& GetImplementation(const Dali::ImfManager& imfManager)
109 Dali::ImfManager actualImfManager = ImfManager::Get();
111 const BaseObject& handle = imfManager.GetBaseObject();
112 return static_cast<const Internal::Adaptor::ImfManager&>(handle);
121 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
122 size_t Utf8SequenceLength(const unsigned char leadByte)
126 if ((leadByte & 0x80) == 0 ) //ASCII character (lead bit zero)
130 else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
134 else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
138 else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
146 // Static function calls used by ecore 'c' style callback registration
147 void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
151 ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
152 imfManager->CommitReceived( data, imfContext, event_info );
156 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
160 ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
161 imfManager->PreEditChanged( data, imfContext, event_info );
165 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
169 ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
170 return imfManager->RetrieveSurrounding( data, imfContext, text, cursorPosition );
179 * Called when an IMF delete surrounding event is received.
180 * Here we tell the application that it should delete a certain range.
182 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
186 ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
187 imfManager->DeleteSurrounding( data, imfContext, event_info );
191 } // unnamed namespace
193 Dali::ImfManager Dali::Internal::Adaptor::ImfManager::mToolkitImfManager;
196 Dali::ImfManager ImfManager::Get()
198 Dali::ImfManager manager;
200 if( ! mToolkitImfManager )
202 mToolkitImfManager = Dali::ImfManager( new Dali::Internal::Adaptor::ImfManager() );
204 return mToolkitImfManager;
207 ImfManager::ImfManager( /*Ecore_X_Window ecoreXwin*/ )
209 mIMFCursorPosition( 0 ),
210 mSurroundingText(""),
211 mRestoreAfterFocusLost( false ),
212 mIdleCallbackConnected( false ),
216 CreateContext( /*ecoreXwin*/ );
218 //VirtualKeyboard::ConnectCallbacks( mIMFContext );
221 ImfManager::~ImfManager()
223 //VirtualKeyboard::DisconnectCallbacks( mIMFContext );
224 DisconnectCallbacks();
226 //ecore_imf_shutdown();
229 void ImfManager::CreateContext( /*Ecore_X_Window ecoreXwin*/ )
233 void ImfManager::DeleteContext()
237 // Callbacks for predicitive text support.
238 void ImfManager::ConnectCallbacks()
240 //if ( mIMFContext ) {
241 //ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit, this );
242 //ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit, this );
243 //ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
247 void ImfManager::DisconnectCallbacks()
249 // if ( mIMFContext )
251 // ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit );
252 // ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit );
253 // ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
257 void ImfManager::Activate()
259 // // Reset mIdleCallbackConnected
260 // mIdleCallbackConnected = false;
262 // if ( mIMFContext )
264 // ecore_imf_context_focus_in( mIMFContext );
265 // // emit keyboard activated signal
266 // Dali::ImfManager handle( this );
267 // mActivatedSignalV2.Emit( handle );
271 void ImfManager::Deactivate()
276 // ecore_imf_context_focus_out( mIMFContext );
278 // // Reset mIdleCallbackConnected
279 // mIdleCallbackConnected = false;
282 void ImfManager::Reset()
284 // if ( mIMFContext )
286 // ecore_imf_context_reset( mIMFContext );
290 Ecore_IMF_Context* ImfManager::GetContext()
292 //return mIMFContext;
296 bool ImfManager::RestoreAfterFocusLost() const
298 return mRestoreAfterFocusLost;
301 void ImfManager::SetRestoreAferFocusLost( bool toggle )
303 mRestoreAfterFocusLost = toggle;
306 void ImfManager::PreEditChanged( void *, Ecore_IMF_Context *imfContext, void *event_info )
308 // char *preEditString( NULL );
309 // int cursorPosition( 0 );
310 // Eina_List *attrs = NULL;
311 // Eina_List *l = NULL;
313 // Ecore_IMF_Preedit_Attr *attr;
315 // // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
316 // // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
317 // ecore_imf_context_preedit_string_with_attributes_get( imfContext, &preEditString, &attrs, &cursorPosition );
320 // // iterate through the list of attributes getting the type, start and end position.
321 // 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 // if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
325 // // 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.
326 // size_t visualCharacterIndex = 0;
327 // size_t byteIndex = 0;
328 // // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
329 // while ( preEditString[byteIndex] != '\0' )
331 // // attr->end_index is provided as a byte position not character and we need to know the character position.
332 // size_t currentSequenceLength = Utf8SequenceLength(preEditString[byteIndex]); // returns number of bytes used to represent character.
333 // if ( byteIndex == attr->end_index )
335 // cursorPosition = visualCharacterIndex;
337 // // end loop as found cursor position that matches byte position
341 // byteIndex += currentSequenceLength; // jump to next character
342 // visualCharacterIndex++; // increment character count so we know our position for when we get a match
344 // DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
349 // if ( Dali::Adaptor::IsAvailable() )
351 // std::string keyString ( preEditString );
352 // int numberOfChars( 0 );
353 // Dali::ImfManager handle( this );
354 // Dali::ImfManager::ImfEventData imfEventData ( Dali::ImfManager::PREEDIT, keyString, cursorPosition, numberOfChars );
355 // Dali::ImfManager::ImfCallbackData callbackData = mEventSignalV2.Emit( handle, imfEventData );
356 // if ( callbackData.update )
358 // SetCursorPosition( callbackData.cursorPosition );
359 // SetSurroundingText( callbackData.currentText );
360 // NotifyCursorPosition();
362 // if ( callbackData.preeditResetRequired )
367 // free( preEditString );
370 void ImfManager::CommitReceived( void *, Ecore_IMF_Context *imfContext, void *event_info )
372 // if ( Dali::Adaptor::IsAvailable() )
374 // const std::string keyString( (char *)event_info );
375 // const int cursorOffset( 0 );
376 // const int numberOfChars( 0 );
378 // Dali::ImfManager handle( this );
379 // Dali::ImfManager::ImfEventData imfEventData ( Dali::ImfManager::COMMIT, keyString, cursorOffset, numberOfChars );
380 // Dali::ImfManager::ImfCallbackData callbackData = mEventSignalV2.Emit( handle, imfEventData );
382 // if ( callbackData.update )
384 // SetCursorPosition( callbackData.cursorPosition );
385 // SetSurroundingText( callbackData.currentText );
387 // NotifyCursorPosition();
393 * Called when an IMF retrieve surround event is received.
394 * Here the IMF module wishes to know the string we are working with and where within the string the cursor is
395 * We need to signal the application to tell us this information.
397 Eina_Bool ImfManager::RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
399 // std::string keyString ( "" );
400 // int cursorOffset( 0 );
401 // int numberOfChars( 0 );
402 // Dali::ImfManager::ImfEventData imfData ( Dali::ImfManager::GETSURROUNDING , keyString, cursorOffset, numberOfChars );
403 // Dali::ImfManager handle( this );
404 // mEventSignalV2.Emit( handle, imfData );
407 // std::string surroundingText( GetSurroundingText() );
408 // if ( !surroundingText.empty() )
410 // *text = strdup( surroundingText.c_str() );
414 // *text = strdup( "" );
417 // if ( cursorPosition )
419 // *cursorPosition = GetCursorPosition();
425 * Called when an IMF delete surrounding event is received.
426 * Here we tell the application that it should delete a certain range.
428 void ImfManager::DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
430 // if ( Dali::Adaptor::IsAvailable() )
432 // Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = (Ecore_IMF_Event_Delete_Surrounding*) event_info;
433 // const std::string keyString( "" );
434 // const int cursorOffset( deleteSurroundingEvent->offset );
435 // const int numberOfChars( deleteSurroundingEvent->n_chars );
436 // Dali::ImfManager::ImfEventData imfData ( Dali::ImfManager::DELETESURROUNDING , keyString, cursorOffset, numberOfChars );
437 // Dali::ImfManager handle( this );
438 // mEventSignalV2.Emit( handle, imfData );
442 void ImfManager::NotifyCursorPosition()
444 // if ( mIMFContext )
446 // ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
450 int ImfManager::GetCursorPosition()
452 return mIMFCursorPosition;
455 void ImfManager::SetCursorPosition( unsigned int cursorPosition )
457 mIMFCursorPosition = ( int )cursorPosition;
460 void ImfManager::SetSurroundingText( std::string text )
462 mSurroundingText = text;
465 std::string ImfManager::GetSurroundingText()
467 return mSurroundingText;
475 /********************************************************************************/
476 /********************************* PUBLIC CLASS *******************************/
477 /********************************************************************************/
479 ImfManager::ImfManager()
483 ImfManager::~ImfManager()
487 ImfManager ImfManager::Get()
489 return Internal::Adaptor::ImfManager::Get();
492 ImfContext ImfManager::GetContext()
494 return reinterpret_cast<ImfContext>( Internal::Adaptor::ImfManager::GetImplementation(*this).GetContext() );
497 void ImfManager::Activate()
499 Internal::Adaptor::ImfManager::GetImplementation(*this).Activate();
502 void ImfManager::Deactivate()
504 Internal::Adaptor::ImfManager::GetImplementation(*this).Deactivate();
507 bool ImfManager::RestoreAfterFocusLost() const
509 return Internal::Adaptor::ImfManager::GetImplementation(*this).RestoreAfterFocusLost();
512 void ImfManager::SetRestoreAferFocusLost( bool toggle )
514 Internal::Adaptor::ImfManager::GetImplementation(*this).SetRestoreAferFocusLost( toggle );
517 void ImfManager::Reset()
519 Internal::Adaptor::ImfManager::GetImplementation(*this).Reset();
522 void ImfManager::NotifyCursorPosition()
524 Internal::Adaptor::ImfManager::GetImplementation(*this).NotifyCursorPosition();
527 void ImfManager::SetCursorPosition( unsigned int SetCursorPosition )
529 Internal::Adaptor::ImfManager::GetImplementation(*this).SetCursorPosition( SetCursorPosition );
532 int ImfManager::GetCursorPosition()
534 return Internal::Adaptor::ImfManager::GetImplementation(*this).GetCursorPosition();
537 void ImfManager::SetSurroundingText( std::string text )
539 Internal::Adaptor::ImfManager::GetImplementation(*this).SetSurroundingText( text );
542 std::string ImfManager::GetSurroundingText()
544 return Internal::Adaptor::ImfManager::GetImplementation(*this).GetSurroundingText();
547 ImfManager::ImfManagerSignalV2& ImfManager::ActivatedSignal()
549 return Internal::Adaptor::ImfManager::GetImplementation(*this).ActivatedSignal();
552 ImfManager::ImfEventSignalV2& ImfManager::EventReceivedSignal()
554 return Internal::Adaptor::ImfManager::GetImplementation(*this).EventReceivedSignal();
557 ImfManager::ImfManager(Internal::Adaptor::ImfManager *impl)