37a86e4e54dfd002bd1e65803aaaf464d1b63bbc
[platform/core/uifw/dali-adaptor.git] / adaptors / wayland / input / text / imf / imf-manager-impl-wl.cpp
1 /*
2  * Copyright (c) 2017 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 <imf-manager-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <singleton-service-impl.h>
27 #include <adaptor-impl.h>
28 #include <string.h>
29
30 namespace Dali
31 {
32
33 namespace Internal
34 {
35
36 namespace Adaptor
37 {
38
39 namespace
40 {
41
42 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_IMF_MANAGER");
44 #endif
45
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)
48 {
49   size_t length = 0;
50
51   if ((leadByte & 0x80) == 0 )          //ASCII character (lead bit zero)
52   {
53     length = 1;
54   }
55   else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
56   {
57     length = 2;
58   }
59   else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
60   {
61     length = 3;
62   }
63   else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
64   {
65     length = 4;
66   }
67
68   return length;
69 }
70
71 unsigned int ConvertByteToVisualPosition( const char* utf8String, unsigned int cursorBytePosition )
72 {
73
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;
76   size_t byteIndex = 0;
77
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' )
81   {
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 )
85     {
86       return visualCharacterIndex;
87       // end loop as found cursor position that matches byte position
88     }
89     else
90     {
91       byteIndex += currentSequenceLength; // jump to next character
92       visualCharacterIndex++;  // increment character count so we know our position for when we get a match
93     }
94     DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( utf8String ));
95   }
96
97   return visualCharacterIndex;
98 }
99
100 BaseHandle Create()
101 {
102   return ImfManager::Get();
103 }
104
105 TypeRegistration IMF_MANAGER_TYPE( typeid(Dali::ImfManager), typeid(Dali::BaseHandle), Create );
106
107 }
108
109 void ImfManager::Finalize()
110 {
111   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Finalize\n" );
112   if ( mInited )
113   {
114     DisconnectCallbacks();
115     mInited = false;
116   }
117 }
118
119 bool ImfManager::IsAvailable()
120 {
121   bool available( false );
122
123   Dali::SingletonService service( SingletonService::Get() );
124   if ( service )
125   {
126     available = service.GetSingleton( typeid( Dali::ImfManager ) );
127   }
128   return available;
129 }
130
131 Dali::ImfManager ImfManager::Get()
132 {
133   Dali::ImfManager manager;
134   ImfManager *imfManager = NULL;
135
136   Dali::SingletonService service( SingletonService::Get() );
137   if (! service )
138   {
139     return manager;
140   }
141
142   // Check whether the singleton is already created
143   Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ImfManager ) );
144   if( handle )
145   {
146     // If so, downcast the handle
147     imfManager = dynamic_cast< ImfManager* >( handle.GetObjectPtr() );
148     manager = Dali::ImfManager( imfManager );
149   }
150   else if ( Adaptor::IsAvailable() )
151   {
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 );
156   }
157   else
158   {
159     DALI_LOG_ERROR("Failed to get native window handle\n");
160   }
161
162   if ( ( imfManager != NULL ) && !imfManager->mInited )
163   {
164     imfManager->ConnectCallbacks();
165     imfManager->mInited = true;
166   }
167
168   return manager;
169 }
170
171 ImfManager::ImfManager()
172 : mTextInputManager( TextInputManager::Get() ),
173   mPreEditCursorPosition( 0 ),
174   mEditCursorPosition( 0 ),
175   mInited( false ),
176   mRestoreAfterFocusLost( false )
177 {
178 }
179
180 ImfManager::~ImfManager()
181 {
182   Finalize();
183 }
184
185 void ImfManager::ConnectCallbacks()
186 {
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 );
191
192 }
193 void ImfManager::DisconnectCallbacks()
194 {
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 );
199 }
200
201 void ImfManager::PreEditStringChange( unsigned int serial, const std::string text, const std::string commit  )
202 {
203
204   int visualCursorPosition = 0;
205   if( text.length() > 0 )
206   {
207     visualCursorPosition = ConvertByteToVisualPosition( text.c_str(), mPreEditCursorPosition );
208   }
209   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::PreEditChanged to %s, pre-edit cursor %d \n",text.c_str(), mPreEditCursorPosition );
210
211
212   // get the latest visual cursor pre-edit position
213
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 );
217
218   if( callbackData.update )
219   {
220     mEditCursorPosition = callbackData.cursorPosition;
221     mSurroundingText = callbackData.currentText;
222   }
223
224   if( callbackData.preeditResetRequired )
225   {
226     mPreEditCursorPosition = 0;
227   }
228 }
229 void ImfManager::PreEditCursorChange( int cursor )
230 {
231   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::PreEditCursorChange %d\n", cursor );
232
233   mPreEditCursorPosition = cursor;
234
235 }
236
237 void ImfManager::CommitString( unsigned int serial, const std::string commit )
238 {
239   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::CommitString\n", commit.c_str() );
240
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 );
244
245   if( callbackData.update )
246   {
247     SetCursorPosition( callbackData.cursorPosition );
248     SetSurroundingText( callbackData.currentText );
249     mEditCursorPosition = callbackData.cursorPosition;
250     mPreEditCursorPosition = mEditCursorPosition;
251     NotifyCursorPosition();
252   }
253
254 }
255 void ImfManager::NotifyCursorPosition()
256 {
257   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::NotifyCursorPosition \n" );
258
259   // Set surrounding text also sets the cursor/ anchor position
260   SetSurroundingText( mSurroundingText );
261 }
262
263 void ImfManager::DeleteSurroundingText( int index, unsigned int length )
264 {
265   DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteSurroundingText %d %d \n", index, length );
266
267   Dali::ImfManager::ImfEventData imfData( Dali::ImfManager::DELETESURROUNDING, std::string(),index, length );
268   Dali::ImfManager handle( this );
269   mEventSignal.Emit( handle, imfData );
270 }
271
272 void ImfManager::Activate()
273 {
274   Dali::ImfManager handle( this );
275   mActivatedSignal.Emit( handle );
276
277 }
278
279 void ImfManager::Deactivate()
280 {
281   // do nothing for now
282 }
283
284 void ImfManager::Reset()
285 {
286   mSurroundingText = "";
287   mPreEditCursorPosition = 0;
288   mEditCursorPosition  = 0;
289   mTextInputManager.Reset();
290 }
291
292 void* ImfManager::GetContext()
293 {
294   return this;
295 }
296
297 bool ImfManager::RestoreAfterFocusLost() const
298 {
299   return mRestoreAfterFocusLost;
300 }
301
302 void ImfManager::SetRestoreAfterFocusLost( bool toggle )
303 {
304   mRestoreAfterFocusLost = toggle;
305 }
306
307 unsigned int ImfManager::GetCursorPosition() const
308 {
309   return mEditCursorPosition;
310 }
311
312 void ImfManager::SetCursorPosition( unsigned int cursorPosition )
313 {
314   mEditCursorPosition = cursorPosition;
315 }
316
317 void ImfManager::SetSurroundingText(  const std::string& text )
318 {
319   mSurroundingText = text;
320   mTextInputManager.SetSurroundingText( text, mEditCursorPosition, mEditCursorPosition /*anchor*/ );
321 }
322
323 const std::string& ImfManager::GetSurroundingText() const
324 {
325   return mSurroundingText;
326 }
327
328 void ImfManager::NotifyTextInputMultiLine( bool multiLine )
329 {
330 }
331
332 Dali::Rect< int > ImfManager::GetInputMethodArea()
333 {
334   TextInputManager::SeatInfo& info = mTextInputManager.GetLastActiveSeat();
335   return info.mInputPanelDimensions;
336 }
337
338 void ImfManager::ApplyOptions(const InputMethodOptions& options)
339 {
340 }
341
342 void ImfManager::SetInputPanelData( const std::string& data )
343 {
344 }
345
346 void ImfManager::GetInputPanelData( std::string& data )
347 {
348 }
349
350 Dali::ImfManager::State ImfManager::GetInputPanelState()
351 {
352   return Dali::ImfManager::DEFAULT;
353 }
354
355 void ImfManager::SetReturnKeyState( bool visible )
356 {
357 }
358
359 void ImfManager::AutoEnableInputPanel( bool enabled )
360 {
361 }
362
363 void ImfManager::ShowInputPanel()
364 {
365 }
366
367 void ImfManager::HideInputPanel()
368 {
369 }
370
371 Dali::ImfManager::KeyboardType ImfManager::GetKeyboardType()
372 {
373   return Dali::ImfManager::KeyboardType::SOFTWARE_KEYBOARD;
374 }
375
376 std::string ImfManager::GetInputPanelLocale()
377 {
378   return NULL;
379 }
380
381 Dali::ImfManager::TextDirection ImfManager::GetTextDirection()
382 {
383   TextInputManager::SeatInfo& info = mTextInputManager.GetLastActiveSeat();
384   return (Dali::ImfManager::TextDirection)info.mTextDirection;
385 }
386
387 } // Adaptor
388
389 } // Internal
390
391 } // Dali