2 * Copyright (c) 2017 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 <imf-manager-impl.h>
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/integration-api/debug.h>
26 #include <singleton-service-impl.h>
27 #include <adaptor-impl.h>
42 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_IMF_MANAGER");
46 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
47 size_t Utf8SequenceLength(const unsigned char leadByte)
51 if ((leadByte & 0x80) == 0 ) //ASCII character (lead bit zero)
55 else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
59 else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
63 else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
71 unsigned int ConvertByteToVisualPosition( const char* utf8String, unsigned int cursorBytePosition )
74 // 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.
75 size_t visualCharacterIndex = 0;
78 // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
79 const char leadByte = utf8String[byteIndex];
80 while( leadByte != '\0' )
82 // attr->end_index is provided as a byte position not character and we need to know the character position.
83 const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
84 if ( byteIndex == cursorBytePosition )
86 return visualCharacterIndex;
87 // end loop as found cursor position that matches byte position
91 byteIndex += currentSequenceLength; // jump to next character
92 visualCharacterIndex++; // increment character count so we know our position for when we get a match
94 DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( utf8String ));
97 return visualCharacterIndex;
102 return ImfManager::Get();
105 TypeRegistration IMF_MANAGER_TYPE( typeid(Dali::ImfManager), typeid(Dali::BaseHandle), Create );
109 void ImfManager::Finalize()
111 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Finalize\n" );
114 DisconnectCallbacks();
119 bool ImfManager::IsAvailable()
121 bool available( false );
123 Dali::SingletonService service( SingletonService::Get() );
126 available = service.GetSingleton( typeid( Dali::ImfManager ) );
131 Dali::ImfManager ImfManager::Get()
133 Dali::ImfManager manager;
134 ImfManager *imfManager = NULL;
136 Dali::SingletonService service( SingletonService::Get() );
142 // Check whether the singleton is already created
143 Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ImfManager ) );
146 // If so, downcast the handle
147 imfManager = dynamic_cast< ImfManager* >( handle.GetObjectPtr() );
148 manager = Dali::ImfManager( imfManager );
150 else if ( Adaptor::IsAvailable() )
152 // Create instance and register singleton only if the adaptor is available
153 imfManager = new ImfManager();
154 manager = Dali::ImfManager( imfManager );
155 service.Register( typeid( manager ), manager );
159 DALI_LOG_ERROR("Failed to get native window handle\n");
162 if ( ( imfManager != NULL ) && !imfManager->mInited )
164 imfManager->ConnectCallbacks();
165 imfManager->mInited = true;
171 ImfManager::ImfManager()
172 : mTextInputManager( TextInputManager::Get() ),
173 mPreEditCursorPosition( 0 ),
174 mEditCursorPosition( 0 ),
176 mRestoreAfterFocusLost( false )
180 ImfManager::~ImfManager()
185 void ImfManager::ConnectCallbacks()
187 mTextInputManager.PreEditStringSignal().Connect( this, &ImfManager::PreEditStringChange );
188 mTextInputManager.PreEditCursorSignal().Connect( this, &ImfManager::PreEditCursorChange );
189 mTextInputManager.CommitStringSignal().Connect( this, &ImfManager::CommitString );
190 mTextInputManager.DeleteSurroundingTextSignal().Connect( this, &ImfManager::DeleteSurroundingText );
193 void ImfManager::DisconnectCallbacks()
195 mTextInputManager.PreEditStringSignal().Disconnect( this, &ImfManager::PreEditStringChange );
196 mTextInputManager.PreEditCursorSignal().Disconnect( this, &ImfManager::PreEditCursorChange );
197 mTextInputManager.CommitStringSignal().Disconnect( this, &ImfManager::CommitString );
198 mTextInputManager.DeleteSurroundingTextSignal().Disconnect( this, &ImfManager::DeleteSurroundingText );
201 void ImfManager::PreEditStringChange( unsigned int serial, const std::string text, const std::string commit )
204 int visualCursorPosition = 0;
205 if( text.length() > 0 )
207 visualCursorPosition = ConvertByteToVisualPosition( text.c_str(), mPreEditCursorPosition );
209 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::PreEditChanged to %s, pre-edit cursor %d \n",text.c_str(), mPreEditCursorPosition );
212 // get the latest visual cursor pre-edit position
214 Dali::ImfManager handle( this );
215 Dali::ImfManager::ImfEventData imfEventData( Dali::ImfManager::PREEDIT, text, visualCursorPosition, visualCursorPosition );
216 Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
218 if( callbackData.update )
220 mEditCursorPosition = callbackData.cursorPosition;
221 mSurroundingText = callbackData.currentText;
224 if( callbackData.preeditResetRequired )
226 mPreEditCursorPosition = 0;
229 void ImfManager::PreEditCursorChange( int cursor )
231 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::PreEditCursorChange %d\n", cursor );
233 mPreEditCursorPosition = cursor;
237 void ImfManager::CommitString( unsigned int serial, const std::string commit )
239 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::CommitString\n", commit.c_str() );
241 Dali::ImfManager handle( this );
242 Dali::ImfManager::ImfEventData imfEventData( Dali::ImfManager::COMMIT, commit, 0, 0 );
243 Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
245 if( callbackData.update )
247 SetCursorPosition( callbackData.cursorPosition );
248 SetSurroundingText( callbackData.currentText );
249 mEditCursorPosition = callbackData.cursorPosition;
250 mPreEditCursorPosition = mEditCursorPosition;
251 NotifyCursorPosition();
255 void ImfManager::NotifyCursorPosition()
257 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::NotifyCursorPosition \n" );
259 // Set surrounding text also sets the cursor/ anchor position
260 SetSurroundingText( mSurroundingText );
263 void ImfManager::DeleteSurroundingText( int index, unsigned int length )
265 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteSurroundingText %d %d \n", index, length );
267 Dali::ImfManager::ImfEventData imfData( Dali::ImfManager::DELETESURROUNDING, std::string(),index, length );
268 Dali::ImfManager handle( this );
269 mEventSignal.Emit( handle, imfData );
272 void ImfManager::Activate()
274 Dali::ImfManager handle( this );
275 mActivatedSignal.Emit( handle );
279 void ImfManager::Deactivate()
281 // do nothing for now
284 void ImfManager::Reset()
286 mSurroundingText = "";
287 mPreEditCursorPosition = 0;
288 mEditCursorPosition = 0;
289 mTextInputManager.Reset();
292 void* ImfManager::GetContext()
297 bool ImfManager::RestoreAfterFocusLost() const
299 return mRestoreAfterFocusLost;
302 void ImfManager::SetRestoreAfterFocusLost( bool toggle )
304 mRestoreAfterFocusLost = toggle;
307 unsigned int ImfManager::GetCursorPosition() const
309 return mEditCursorPosition;
312 void ImfManager::SetCursorPosition( unsigned int cursorPosition )
314 mEditCursorPosition = cursorPosition;
317 void ImfManager::SetSurroundingText( const std::string& text )
319 mSurroundingText = text;
320 mTextInputManager.SetSurroundingText( text, mEditCursorPosition, mEditCursorPosition /*anchor*/ );
323 const std::string& ImfManager::GetSurroundingText() const
325 return mSurroundingText;
328 void ImfManager::NotifyTextInputMultiLine( bool multiLine )
332 Dali::Rect< int > ImfManager::GetInputMethodArea()
334 TextInputManager::SeatInfo& info = mTextInputManager.GetLastActiveSeat();
335 return info.mInputPanelDimensions;
338 void ImfManager::ApplyOptions(const InputMethodOptions& options)
342 void ImfManager::SetInputPanelUserData( const std::string& data )
346 void ImfManager::GetInputPanelUserData( std::string& data )
350 Dali::ImfManager::State ImfManager::GetInputPanelState()
352 return Dali::ImfManager::DEFAULT;
355 void ImfManager::SetReturnKeyState( bool visible )
359 void ImfManager::AutoEnableInputPanel( bool enabled )
363 void ImfManager::ShowInputPanel()
367 void ImfManager::HideInputPanel()
371 Dali::ImfManager::KeyboardType ImfManager::GetKeyboardType()
373 return Dali::ImfManager::KeyboardType::SOFTWARE_KEYBOARD;
376 std::string ImfManager::GetInputPanelLocale()
381 Dali::ImfManager::TextDirection ImfManager::GetTextDirection()
383 TextInputManager::SeatInfo& info = mTextInputManager.GetLastActiveSeat();
384 return (Dali::ImfManager::TextDirection)info.mTextDirection;