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 bool ImfManager::IsAvailable()
111 bool available( false );
113 Dali::SingletonService service( SingletonService::Get() );
116 available = service.GetSingleton( typeid( Dali::ImfManager ) );
121 Dali::ImfManager ImfManager::Get()
123 Dali::ImfManager manager;
125 Dali::SingletonService service( SingletonService::Get() );
131 // Check whether the singleton is already created
132 Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ImfManager ) );
135 // If so, downcast the handle
136 manager = Dali::ImfManager( dynamic_cast< ImfManager* >( handle.GetObjectPtr() ) );
138 else if ( Adaptor::IsAvailable() )
140 // Create instance and register singleton only if the adaptor is available
141 manager = Dali::ImfManager( new ImfManager() );
142 service.Register( typeid( manager ), manager );
146 DALI_LOG_ERROR("Failed to get native window handle\n");
150 ImfManager::ImfManager()
151 : mTextInputManager( TextInputManager::Get() ),
152 mPreEditCursorPosition( 0 ),
153 mEditCursorPosition( 0 ),
154 mRestoreAfterFocusLost( false )
158 ImfManager::~ImfManager()
160 DisconnectCallbacks();
163 void ImfManager::ConnectCallbacks()
165 mTextInputManager.PreEditStringSignal().Connect( this, &ImfManager::PreEditStringChange );
166 mTextInputManager.PreEditCursorSignal().Connect( this, &ImfManager::PreEditCursorChange );
167 mTextInputManager.CommitStringSignal().Connect( this, &ImfManager::CommitString );
168 mTextInputManager.DeleteSurroundingTextSignal().Connect( this, &ImfManager::DeleteSurroundingText );
171 void ImfManager::DisconnectCallbacks()
173 mTextInputManager.PreEditStringSignal().Disconnect( this, &ImfManager::PreEditStringChange );
174 mTextInputManager.PreEditCursorSignal().Disconnect( this, &ImfManager::PreEditCursorChange );
175 mTextInputManager.CommitStringSignal().Disconnect( this, &ImfManager::CommitString );
176 mTextInputManager.DeleteSurroundingTextSignal().Disconnect( this, &ImfManager::DeleteSurroundingText );
179 void ImfManager::PreEditStringChange( unsigned int serial, const std::string text, const std::string commit )
182 int visualCursorPosition = 0;
183 if( text.length() > 0 )
185 visualCursorPosition = ConvertByteToVisualPosition( text.c_str(), mPreEditCursorPosition );
187 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::PreEditChanged to %s, pre-edit cursor %d \n",text.c_str(), mPreEditCursorPosition );
190 // get the latest visual cursor pre-edit position
192 Dali::ImfManager handle( this );
193 Dali::ImfManager::ImfEventData imfEventData( Dali::ImfManager::PREEDIT, text, visualCursorPosition, visualCursorPosition );
194 Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
196 if( callbackData.update )
198 mEditCursorPosition = callbackData.cursorPosition;
199 mSurroundingText = callbackData.currentText;
202 if( callbackData.preeditResetRequired )
204 mPreEditCursorPosition = 0;
207 void ImfManager::PreEditCursorChange( int cursor )
209 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::PreEditCursorChange %d\n", cursor );
211 mPreEditCursorPosition = cursor;
215 void ImfManager::CommitString( unsigned int serial, const std::string commit )
217 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::CommitString\n", commit.c_str() );
219 Dali::ImfManager handle( this );
220 Dali::ImfManager::ImfEventData imfEventData( Dali::ImfManager::COMMIT, commit, 0, 0 );
221 Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
223 if( callbackData.update )
225 SetCursorPosition( callbackData.cursorPosition );
226 SetSurroundingText( callbackData.currentText );
227 mEditCursorPosition = callbackData.cursorPosition;
228 mPreEditCursorPosition = mEditCursorPosition;
229 NotifyCursorPosition();
233 void ImfManager::NotifyCursorPosition()
235 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::NotifyCursorPosition \n" );
237 // Set surrounding text also sets the cursor/ anchor position
238 SetSurroundingText( mSurroundingText );
241 void ImfManager::DeleteSurroundingText( int index, unsigned int length )
243 DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteSurroundingText %d %d \n", index, length );
245 Dali::ImfManager::ImfEventData imfData( Dali::ImfManager::DELETESURROUNDING, std::string(),index, length );
246 Dali::ImfManager handle( this );
247 mEventSignal.Emit( handle, imfData );
250 void ImfManager::Activate()
252 Dali::ImfManager handle( this );
253 mActivatedSignal.Emit( handle );
257 void ImfManager::Deactivate()
259 // do nothing for now
262 void ImfManager::Reset()
264 mSurroundingText = "";
265 mPreEditCursorPosition = 0;
266 mEditCursorPosition = 0;
267 mTextInputManager.Reset();
270 void* ImfManager::GetContext()
275 bool ImfManager::RestoreAfterFocusLost() const
277 return mRestoreAfterFocusLost;
280 void ImfManager::SetRestoreAfterFocusLost( bool toggle )
282 mRestoreAfterFocusLost = toggle;
285 unsigned int ImfManager::GetCursorPosition() const
287 return mEditCursorPosition;
290 void ImfManager::SetCursorPosition( unsigned int cursorPosition )
292 mEditCursorPosition = cursorPosition;
295 void ImfManager::SetSurroundingText( const std::string& text )
297 mSurroundingText = text;
298 mTextInputManager.SetSurroundingText( text, mEditCursorPosition, mEditCursorPosition /*anchor*/ );
301 const std::string& ImfManager::GetSurroundingText() const
303 return mSurroundingText;
306 void ImfManager::NotifyTextInputMultiLine( bool multiLine )
310 Dali::Rect< int > ImfManager::GetInputMethodArea()
312 TextInputManager::SeatInfo& info = mTextInputManager.GetLastActiveSeat();
313 return info.mInputPanelDimensions;
316 void ImfManager::ApplyOptions(const InputMethodOptions& options)
320 void ImfManager::SetInputPanelData( const std::string& data )
324 void ImfManager::GetInputPanelData( std::string& data )
328 Dali::ImfManager::State ImfManager::GetInputPanelState()
330 return Dali::ImfManager::DEFAULT;
333 void ImfManager::SetReturnKeyState( bool visible )
337 void ImfManager::AutoEnableInputPanel( bool enabled )
341 void ImfManager::ShowInputPanel()
345 void ImfManager::HideInputPanel()
349 Dali::ImfManager::KeyboardType ImfManager::GetKeyboardType()
351 return Dali::ImfManager::KeyboardType::SOFTWARE_KEYBOARD;
354 std::string ImfManager::GetInputPanelLocale()
359 Dali::ImfManager::TextDirection ImfManager::GetTextDirection()
361 TextInputManager::SeatInfo& info = mTextInputManager.GetLastActiveSeat();
362 return (Dali::ImfManager::TextDirection)info.mTextDirection;