2 * Copyright (c) 2021 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.
20 #include <dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h>
23 #include <Ecore_Input.h>
26 #include <Ecore_Wl2.h>
28 #include <Ecore_Wayland.h>
31 #include <dali/devel-api/common/singleton-service.h>
32 #include <dali/integration-api/debug.h>
33 #include <dali/public-api/adaptor-framework/key.h>
34 #include <dali/public-api/events/key-event.h>
35 #include <dali/public-api/object/type-registry.h>
38 #include <dali/integration-api/adaptor-framework/adaptor.h>
39 #include <dali/integration-api/adaptor-framework/scene-holder.h>
40 #include <dali/internal/input/common/key-impl.h>
41 #include <dali/internal/system/common/locale-utils.h>
42 #include <dali/internal/window-system/common/window-render-surface.h>
43 #include <dali/public-api/adaptor-framework/input-method.h>
45 Ecore_IMF_Input_Panel_Layout panelLayoutMap[] =
47 ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL,
48 ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER,
49 ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL,
50 ECORE_IMF_INPUT_PANEL_LAYOUT_URL,
51 ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER,
52 ECORE_IMF_INPUT_PANEL_LAYOUT_IP,
53 ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH,
54 ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY,
55 ECORE_IMF_INPUT_PANEL_LAYOUT_HEX,
56 ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL,
57 ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD,
58 ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME,
59 ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON,
60 ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE};
62 Ecore_IMF_Autocapital_Type autoCapitalMap[] =
64 ECORE_IMF_AUTOCAPITAL_TYPE_NONE,
65 ECORE_IMF_AUTOCAPITAL_TYPE_WORD,
66 ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE,
67 ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER,
70 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyTypeMap[] =
72 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT,
73 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE,
74 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO,
75 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN,
76 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN,
77 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT,
78 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH,
79 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND,
80 ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN};
90 #if defined(DEBUG_ENABLED)
91 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
94 const int kUninitializedWindowId = 0;
96 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
97 size_t Utf8SequenceLength(const unsigned char leadByte)
101 if((leadByte & 0x80) == 0) //ASCII character (lead bit zero)
105 else if((leadByte & 0xe0) == 0xc0) //110x xxxx
109 else if((leadByte & 0xf0) == 0xe0) //1110 xxxx
113 else if((leadByte & 0xf8) == 0xf0) //1111 0xxx
117 else if((leadByte & 0xfc) == 0xf8) //1111 10xx
121 else if((leadByte & 0xfe) == 0xfc) //1111 110x
129 // Static function calls used by ecore 'c' style callback registration
130 void Commit(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
134 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
135 inputMethodContext->CommitReceived(data, imfContext, eventInfo);
139 void PreEdit(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
143 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
144 inputMethodContext->PreEditChanged(data, imfContext, eventInfo);
148 Eina_Bool ImfRetrieveSurrounding(void* data, Ecore_IMF_Context* imfContext, char** text, int* cursorPosition)
152 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
153 return inputMethodContext->RetrieveSurrounding(data, imfContext, text, cursorPosition);
161 void InputPanelStateChangeCallback(void* data, Ecore_IMF_Context* context, int value)
167 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
170 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
172 inputMethodContext->StatusChangedSignal().Emit(true);
176 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
178 inputMethodContext->StatusChangedSignal().Emit(false);
182 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
191 void InputPanelLanguageChangeCallback(void* data, Ecore_IMF_Context* context, int value)
197 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
198 // Emit the signal that the language has changed
199 inputMethodContext->LanguageChangedSignal().Emit(value);
202 void InputPanelGeometryChangedCallback(void* data, Ecore_IMF_Context* context, int value)
208 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
209 // Emit signal that the keyboard is resized
210 inputMethodContext->ResizedSignal().Emit(value);
213 void InputPanelKeyboardTypeChangedCallback(void* data, Ecore_IMF_Context* context, int value)
220 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
223 case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
225 // Emit Signal that the keyboard type is changed to Software Keyboard
226 inputMethodContext->KeyboardTypeChangedSignal().Emit(Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD);
229 case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
231 // Emit Signal that the keyboard type is changed to Hardware Keyboard
232 inputMethodContext->KeyboardTypeChangedSignal().Emit(Dali::InputMethodContext::KeyboardType::HARDWARE_KEYBOARD);
239 * Called when an IMF delete surrounding event is received.
240 * Here we tell the application that it should delete a certain range.
242 void ImfDeleteSurrounding(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
246 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
247 inputMethodContext->DeleteSurrounding(data, imfContext, eventInfo);
252 * Called when the input method sends a private command.
254 void PrivateCommand(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
258 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
259 inputMethodContext->SendPrivateCommand(data, imfContext, eventInfo);
264 * Called when the input method commits content, such as an image.
266 void CommitContent(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
270 InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
271 inputMethodContext->SendCommitContent(data, imfContext, eventInfo);
275 int GetWindowIdFromActor(Dali::Actor actor)
277 int windowId = kUninitializedWindowId;
279 if(actor.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
281 Any nativeWindowHandle = Dali::Integration::SceneHolder::Get(actor).GetNativeHandle();
283 #ifdef ECORE_WAYLAND2
284 windowId = ecore_wl2_window_id_get(AnyCast<Ecore_Wl2_Window*>(nativeWindowHandle));
286 windowId = ecore_wl_window_id_get(AnyCast<Ecore_Wl_Window*>(nativeWindowHandle));
295 return Dali::InputMethodContext::New(Dali::Actor());
298 Dali::TypeRegistration type(typeid(Dali::InputMethodContext), typeid(Dali::BaseHandle), Create);
300 } // unnamed namespace
302 InputMethodContextPtr InputMethodContextEcoreWl::New(Dali::Actor actor)
304 InputMethodContextPtr inputMethodContext;
306 // Create instance only if the adaptor is available and the valid actor exists
307 if(actor && Dali::Adaptor::IsAvailable())
309 inputMethodContext = new InputMethodContextEcoreWl(actor);
311 return inputMethodContext;
314 void InputMethodContextEcoreWl::Finalize()
316 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContext::Finalize\n");
318 DisconnectCallbacks();
322 InputMethodContextEcoreWl::InputMethodContextEcoreWl(Dali::Actor actor)
324 mIMFCursorPosition(0),
326 mRestoreAfterFocusLost(false),
327 mIdleCallbackConnected(false),
328 mWindowId(GetWindowIdFromActor(actor))
332 actor.OnSceneSignal().Connect(this, &InputMethodContextEcoreWl::OnStaged);
335 InputMethodContextEcoreWl::~InputMethodContextEcoreWl()
338 ecore_imf_shutdown();
341 void InputMethodContextEcoreWl::Initialize()
345 ApplyBackupOperations();
348 void InputMethodContextEcoreWl::CreateContext()
350 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContext::CreateContext\n");
352 if(mWindowId == kUninitializedWindowId)
357 const char* contextId = ecore_imf_context_default_id_get();
360 mIMFContext = ecore_imf_context_add(contextId);
364 ecore_imf_context_client_window_set(mIMFContext, reinterpret_cast<void*>(mWindowId));
368 DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
373 DALI_LOG_WARNING("InputMethodContext Unable to get IMFContext\n");
377 void InputMethodContextEcoreWl::DeleteContext()
379 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteContext\n");
383 ecore_imf_context_del(mIMFContext);
388 // Callbacks for predicitive text support.
389 void InputMethodContextEcoreWl::ConnectCallbacks()
393 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::ConnectCallbacks\n");
395 ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit, this);
396 ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit, this);
397 ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this);
398 ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand, this);
399 ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT, CommitContent, this);
401 ecore_imf_context_input_panel_event_callback_add(mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback, this);
402 ecore_imf_context_input_panel_event_callback_add(mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback, this);
403 ecore_imf_context_input_panel_event_callback_add(mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, this);
404 ecore_imf_context_input_panel_event_callback_add(mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback, this);
406 ecore_imf_context_retrieve_surrounding_callback_set(mIMFContext, ImfRetrieveSurrounding, this);
410 void InputMethodContextEcoreWl::DisconnectCallbacks()
414 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::DisconnectCallbacks\n");
416 ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit);
417 ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit);
418 ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding);
419 ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand);
420 ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT, CommitContent);
422 ecore_imf_context_input_panel_event_callback_del(mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback);
423 ecore_imf_context_input_panel_event_callback_del(mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback);
424 ecore_imf_context_input_panel_event_callback_del(mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback);
425 ecore_imf_context_input_panel_event_callback_del(mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback);
427 // We do not need to unset the retrieve surrounding callback.
431 void InputMethodContextEcoreWl::Activate()
433 // Reset mIdleCallbackConnected
434 mIdleCallbackConnected = false;
438 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::Activate\n");
440 ecore_imf_context_focus_in(mIMFContext);
442 // emit keyboard activated signal
443 Dali::InputMethodContext handle(this);
444 mActivatedSignal.Emit(handle);
448 void InputMethodContextEcoreWl::Deactivate()
452 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::Deactivate\n");
455 ecore_imf_context_focus_out(mIMFContext);
458 // Reset mIdleCallbackConnected
459 mIdleCallbackConnected = false;
462 void InputMethodContextEcoreWl::Reset()
464 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::Reset\n");
468 ecore_imf_context_reset(mIMFContext);
472 ImfContext* InputMethodContextEcoreWl::GetContext()
474 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetContext\n");
479 bool InputMethodContextEcoreWl::RestoreAfterFocusLost() const
481 return mRestoreAfterFocusLost;
484 void InputMethodContextEcoreWl::SetRestoreAfterFocusLost(bool toggle)
486 mRestoreAfterFocusLost = toggle;
490 * Called when an InputMethodContext Pre-Edit changed event is received.
491 * We are still predicting what the user is typing. The latest string is what the InputMethodContext module thinks
492 * the user wants to type.
494 void InputMethodContextEcoreWl::PreEditChanged(void*, ImfContext* imfContext, void* eventInfo)
496 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::PreEditChanged\n");
497 auto context = static_cast<Ecore_IMF_Context*>(imfContext);
499 char* preEditString(NULL);
500 int cursorPosition(0);
501 Eina_List* attrs = NULL;
504 Ecore_IMF_Preedit_Attr* attr;
506 mPreeditAttrs.Clear();
508 // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
509 // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
510 ecore_imf_context_preedit_string_with_attributes_get(context, &preEditString, &attrs, &cursorPosition);
514 // iterate through the list of attributes getting the type, start and end position.
515 for(l = attrs, (attr = static_cast<Ecore_IMF_Preedit_Attr*>(eina_list_data_get(l))); l; l = eina_list_next(l), (attr = static_cast<Ecore_IMF_Preedit_Attr*>(eina_list_data_get(l))))
517 Dali::InputMethodContext::PreeditAttributeData data;
521 size_t visualCharacterIndex = 0;
522 size_t byteIndex = 0;
524 // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
525 char leadByte = preEditString[byteIndex];
527 while(leadByte != '\0')
529 leadByte = preEditString[byteIndex]; // Update the character to get the number of its byte
531 // attr->end_index is provided as a byte position not character and we need to know the character position.
532 const size_t currentSequenceLength = Utf8SequenceLength(leadByte); // returns number of bytes used to represent character.
533 if(byteIndex <= attr->start_index)
535 data.startIndex = visualCharacterIndex;
537 if(byteIndex >= attr->end_index)
539 data.endIndex = visualCharacterIndex;
541 // end loop as found cursor position that matches byte position
545 byteIndex += currentSequenceLength; // jump to next character
546 visualCharacterIndex++; // increment character count so we know our position for when we get a match
550 switch(attr->preedit_type)
552 case ECORE_IMF_PREEDIT_TYPE_NONE:
554 data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
557 case ECORE_IMF_PREEDIT_TYPE_SUB1:
559 data.preeditType = Dali::InputMethodContext::PreeditStyle::UNDERLINE;
562 case ECORE_IMF_PREEDIT_TYPE_SUB2:
564 data.preeditType = Dali::InputMethodContext::PreeditStyle::REVERSE;
567 case ECORE_IMF_PREEDIT_TYPE_SUB3:
569 data.preeditType = Dali::InputMethodContext::PreeditStyle::HIGHLIGHT;
572 case ECORE_IMF_PREEDIT_TYPE_SUB4:
574 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1;
577 case ECORE_IMF_PREEDIT_TYPE_SUB5:
579 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2;
582 case ECORE_IMF_PREEDIT_TYPE_SUB6:
584 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3;
587 case ECORE_IMF_PREEDIT_TYPE_SUB7:
589 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4;
594 data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
598 mPreeditAttrs.PushBack(data);
602 if(Dali::Adaptor::IsAvailable())
604 Dali::InputMethodContext handle(this);
605 Dali::InputMethodContext::EventData eventData(Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0);
606 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit(handle, eventData);
608 if(callbackData.update)
610 SetCursorPosition(callbackData.cursorPosition);
611 SetSurroundingText(callbackData.currentText);
613 NotifyCursorPosition();
616 if(callbackData.preeditResetRequired)
624 void InputMethodContextEcoreWl::CommitReceived(void*, ImfContext* imfContext, void* eventInfo)
626 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::CommitReceived\n");
628 if(Dali::Adaptor::IsAvailable())
630 const std::string keyString(static_cast<char*>(eventInfo));
632 Dali::InputMethodContext handle(this);
633 Dali::InputMethodContext::EventData eventData(Dali::InputMethodContext::COMMIT, keyString, 0, 0);
634 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit(handle, eventData);
636 if(callbackData.update)
638 SetCursorPosition(callbackData.cursorPosition);
639 SetSurroundingText(callbackData.currentText);
641 NotifyCursorPosition();
647 * Called when an InputMethodContext retrieve surround event is received.
648 * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
649 * We need to signal the application to tell us this information.
651 bool InputMethodContextEcoreWl::RetrieveSurrounding(void* data, ImfContext* imfContext, char** text, int* cursorPosition)
653 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::RetrieveSurrounding\n");
655 Dali::InputMethodContext::EventData imfData(Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0);
656 Dali::InputMethodContext handle(this);
657 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit(handle, imfData);
659 if(callbackData.update)
663 mIMFCursorPosition = static_cast<int>(callbackData.cursorPosition);
664 *cursorPosition = mIMFCursorPosition;
669 const char* plainText = callbackData.currentText.c_str();
673 // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
674 *text = strdup(plainText);
676 // If the current input panel is password mode, dali should replace the plain text with '*' (Asterisk) character.
677 if((ecore_imf_context_input_hint_get(mIMFContext) & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA) && *text)
679 for(char* iter = *text; *iter; ++iter)
694 * Called when an InputMethodContext delete surrounding event is received.
695 * Here we tell the application that it should delete a certain range.
697 void InputMethodContextEcoreWl::DeleteSurrounding(void* data, ImfContext* imfContext, void* eventInfo)
699 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteSurrounding\n");
701 if(Dali::Adaptor::IsAvailable())
703 Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>(eventInfo);
705 Dali::InputMethodContext::EventData imfData(Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars);
706 Dali::InputMethodContext handle(this);
707 mEventSignal.Emit(handle, imfData);
712 * Called when the input method sends a private command.
714 void InputMethodContextEcoreWl::SendPrivateCommand(void* data, ImfContext* imfContext, void* eventInfo)
716 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendPrivateCommand\n");
718 if(Dali::Adaptor::IsAvailable())
720 const char* privateCommandSendEvent = static_cast<const char*>(eventInfo);
722 Dali::InputMethodContext::EventData imfData(Dali::InputMethodContext::PRIVATE_COMMAND, privateCommandSendEvent, 0, 0);
723 Dali::InputMethodContext handle(this);
724 mEventSignal.Emit(handle, imfData);
729 * Called when the input method commits content, such as an image.
731 void InputMethodContextEcoreWl::SendCommitContent(void* data, ImfContext* imfContext, void* eventInfo)
733 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent\n");
735 if(Dali::Adaptor::IsAvailable())
737 Ecore_IMF_Event_Commit_Content* commitContent = static_cast<Ecore_IMF_Event_Commit_Content*>(eventInfo);
740 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent commit content : %s, description : %s, mime type : %s\n", commitContent->content_uri, commitContent->description, commitContent->mime_types);
741 mContentReceivedSignal.Emit(commitContent->content_uri, commitContent->description, commitContent->mime_types);
746 void InputMethodContextEcoreWl::NotifyCursorPosition()
748 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::NotifyCursorPosition\n");
752 ecore_imf_context_cursor_position_set(mIMFContext, mIMFCursorPosition);
756 void InputMethodContextEcoreWl::SetCursorPosition(unsigned int cursorPosition)
758 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetCursorPosition\n");
760 mIMFCursorPosition = static_cast<int>(cursorPosition);
763 unsigned int InputMethodContextEcoreWl::GetCursorPosition() const
765 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetCursorPosition\n");
767 return static_cast<unsigned int>(mIMFCursorPosition);
770 void InputMethodContextEcoreWl::SetSurroundingText(const std::string& text)
772 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetSurroundingText\n");
774 mSurroundingText = text;
777 const std::string& InputMethodContextEcoreWl::GetSurroundingText() const
779 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetSurroundingText\n");
781 return mSurroundingText;
784 void InputMethodContextEcoreWl::NotifyTextInputMultiLine(bool multiLine)
788 Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
789 ecore_imf_context_input_hint_set(mIMFContext,
790 static_cast<Ecore_IMF_Input_Hints>(multiLine ? (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) : (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
793 mBackupOperations[Operation::NOTIFY_TEXT_INPUT_MULTILINE] = std::bind(&InputMethodContextEcoreWl::NotifyTextInputMultiLine, this, multiLine);
796 Dali::InputMethodContext::TextDirection InputMethodContextEcoreWl::GetTextDirection()
798 Dali::InputMethodContext::TextDirection direction(Dali::InputMethodContext::LEFT_TO_RIGHT);
803 ecore_imf_context_input_panel_language_locale_get(mIMFContext, &locale);
807 direction = static_cast<Dali::InputMethodContext::TextDirection>(Locale::GetDirection(std::string(locale)));
815 Rect<int> InputMethodContextEcoreWl::GetInputMethodArea()
817 int xPos, yPos, width, height;
819 width = height = xPos = yPos = 0;
823 ecore_imf_context_input_panel_geometry_get(mIMFContext, &xPos, &yPos, &width, &height);
827 DALI_LOG_WARNING("VKB Unable to get IMFContext so GetSize unavailable\n");
828 // return 0 as real size unknown.
831 return Rect<int>(xPos, yPos, width, height);
834 void InputMethodContextEcoreWl::ApplyOptions(const InputMethodOptions& options)
836 using namespace Dali::InputMethod::Category;
840 if(mIMFContext == NULL)
842 DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
846 if(mOptions.CompareAndSet(PANEL_LAYOUT, options, index))
848 ecore_imf_context_input_panel_layout_set(mIMFContext, panelLayoutMap[index]);
850 // Sets the input hint which allows input methods to fine-tune their behavior.
851 if(panelLayoutMap[index] == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD)
853 ecore_imf_context_input_hint_set(mIMFContext, static_cast<Ecore_IMF_Input_Hints>(ecore_imf_context_input_hint_get(mIMFContext) | ECORE_IMF_INPUT_HINT_SENSITIVE_DATA));
857 ecore_imf_context_input_hint_set(mIMFContext, static_cast<Ecore_IMF_Input_Hints>(ecore_imf_context_input_hint_get(mIMFContext) & ~ECORE_IMF_INPUT_HINT_SENSITIVE_DATA));
860 if(mOptions.CompareAndSet(BUTTON_ACTION, options, index))
862 ecore_imf_context_input_panel_return_key_type_set(mIMFContext, returnKeyTypeMap[index]);
864 if(mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index))
866 ecore_imf_context_autocapital_type_set(mIMFContext, autoCapitalMap[index]);
868 if(mOptions.CompareAndSet(VARIATION, options, index))
870 ecore_imf_context_input_panel_layout_variation_set(mIMFContext, index);
874 void InputMethodContextEcoreWl::SetInputPanelData(const std::string& data)
876 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelData\n");
880 int length = data.length();
881 ecore_imf_context_input_panel_imdata_set(mIMFContext, data.c_str(), length);
884 mBackupOperations[Operation::SET_INPUT_PANEL_DATA] = std::bind(&InputMethodContextEcoreWl::SetInputPanelData, this, data);
887 void InputMethodContextEcoreWl::GetInputPanelData(std::string& data)
889 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelData\n");
893 int length = 4096; // The max length is 4096 bytes
894 Dali::Vector<char> buffer;
895 buffer.Resize(length);
896 ecore_imf_context_input_panel_imdata_get(mIMFContext, &buffer[0], &length);
897 data = std::string(buffer.Begin(), buffer.End());
901 Dali::InputMethodContext::State InputMethodContextEcoreWl::GetInputPanelState()
903 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelState\n");
908 value = ecore_imf_context_input_panel_state_get(mIMFContext);
912 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
914 return Dali::InputMethodContext::SHOW;
918 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
920 return Dali::InputMethodContext::HIDE;
924 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
926 return Dali::InputMethodContext::WILL_SHOW;
932 return Dali::InputMethodContext::DEFAULT;
936 return Dali::InputMethodContext::DEFAULT;
939 void InputMethodContextEcoreWl::SetReturnKeyState(bool visible)
941 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetReturnKeyState\n");
945 ecore_imf_context_input_panel_return_key_disabled_set(mIMFContext, !visible);
948 mBackupOperations[Operation::SET_RETURN_KEY_STATE] = std::bind(&InputMethodContextEcoreWl::SetReturnKeyState, this, visible);
951 void InputMethodContextEcoreWl::AutoEnableInputPanel(bool enabled)
953 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::AutoEnableInputPanel\n");
957 ecore_imf_context_input_panel_enabled_set(mIMFContext, enabled);
960 mBackupOperations[Operation::AUTO_ENABLE_INPUT_PANEL] = std::bind(&InputMethodContextEcoreWl::AutoEnableInputPanel, this, enabled);
963 void InputMethodContextEcoreWl::ShowInputPanel()
965 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::ShowInputPanel\n");
969 ecore_imf_context_input_panel_show(mIMFContext);
973 void InputMethodContextEcoreWl::HideInputPanel()
975 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::HideInputPanel\n");
979 ecore_imf_context_input_panel_hide(mIMFContext);
983 Dali::InputMethodContext::KeyboardType InputMethodContextEcoreWl::GetKeyboardType()
985 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetKeyboardType\n");
990 value = ecore_imf_context_keyboard_mode_get(mIMFContext);
994 case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
996 return Dali::InputMethodContext::SOFTWARE_KEYBOARD;
999 case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
1001 return Dali::InputMethodContext::HARDWARE_KEYBOARD;
1007 return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
1010 std::string InputMethodContextEcoreWl::GetInputPanelLocale()
1012 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLocale\n");
1014 std::string locale = "";
1019 ecore_imf_context_input_panel_language_locale_get(mIMFContext, &value);
1023 std::string valueCopy(value);
1026 // The locale string retrieved must be freed with free().
1033 void InputMethodContextEcoreWl::SetContentMIMETypes(const std::string& mimeTypes)
1035 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetContentMIMETypes\n");
1039 ecore_imf_context_mime_type_accept_set(mIMFContext, mimeTypes.c_str());
1042 mBackupOperations[Operation::SET_CONTENT_MIME_TYPES] = std::bind(&InputMethodContextEcoreWl::SetContentMIMETypes, this, mimeTypes);
1045 bool InputMethodContextEcoreWl::FilterEventKey(const Dali::KeyEvent& keyEvent)
1047 bool eventHandled(false);
1049 // If a device key then skip ecore_imf_context_filter_event.
1050 if(!KeyLookup::IsDeviceButton(keyEvent.GetKeyName().c_str()))
1052 //check whether it's key down or key up event
1053 if(keyEvent.GetState() == Dali::KeyEvent::DOWN)
1055 eventHandled = ProcessEventKeyDown(keyEvent);
1057 else if(keyEvent.GetState() == Dali::KeyEvent::UP)
1059 eventHandled = ProcessEventKeyUp(keyEvent);
1063 return eventHandled;
1066 void InputMethodContextEcoreWl::AllowTextPrediction(bool prediction)
1068 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::AllowTextPrediction\n");
1072 ecore_imf_context_prediction_allow_set(mIMFContext, prediction);
1075 mBackupOperations[Operation::ALLOW_TEXT_PREDICTION] = std::bind(&InputMethodContextEcoreWl::AllowTextPrediction, this, prediction);
1078 bool InputMethodContextEcoreWl::IsTextPredictionAllowed() const
1080 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::IsTextPredictionAllowed\n");
1081 bool prediction = false;
1084 prediction = ecore_imf_context_prediction_allow_get(mIMFContext);
1089 void InputMethodContextEcoreWl::SetInputPanelLanguage(Dali::InputMethodContext::InputPanelLanguage language)
1091 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelLanguage\n");
1096 case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
1098 ecore_imf_context_input_panel_language_set(mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC);
1101 case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
1103 ecore_imf_context_input_panel_language_set(mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET);
1109 mBackupOperations[Operation::SET_INPUT_PANEL_LANGUAGE] = std::bind(&InputMethodContextEcoreWl::SetInputPanelLanguage, this, language);
1112 Dali::InputMethodContext::InputPanelLanguage InputMethodContextEcoreWl::GetInputPanelLanguage() const
1114 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLanguage\n");
1118 value = ecore_imf_context_input_panel_language_get(mIMFContext);
1122 case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
1124 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
1127 case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
1129 return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
1134 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
1137 void InputMethodContextEcoreWl::SetInputPanelPosition(unsigned int x, unsigned int y)
1139 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelPosition\n");
1143 ecore_imf_context_input_panel_position_set(mIMFContext, x, y);
1146 mBackupOperations[Operation::SET_INPUT_PANEL_POSITION] = std::bind(&InputMethodContextEcoreWl::SetInputPanelPosition, this, x, y);
1149 void InputMethodContextEcoreWl::GetPreeditStyle(Dali::InputMethodContext::PreEditAttributeDataContainer& attrs) const
1151 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetPreeditStyle\n");
1152 attrs = mPreeditAttrs;
1155 bool InputMethodContextEcoreWl::ProcessEventKeyDown(const Dali::KeyEvent& keyEvent)
1157 bool eventHandled(false);
1160 Integration::KeyEvent integKeyEvent(keyEvent.GetKeyName(), keyEvent.GetLogicalKey(), keyEvent.GetKeyString(), keyEvent.GetKeyCode(), keyEvent.GetKeyModifier(), keyEvent.GetTime(), static_cast<Integration::KeyEvent::State>(keyEvent.GetState()), keyEvent.GetCompose(), keyEvent.GetDeviceName(), keyEvent.GetDeviceClass(), keyEvent.GetDeviceSubclass());
1161 std::string key = integKeyEvent.logicalKey;
1163 std::string compose = integKeyEvent.compose;
1164 std::string deviceName = integKeyEvent.deviceName;
1166 // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
1167 Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
1168 ecoreKeyDownEvent.keyname = integKeyEvent.keyName.c_str();
1169 ecoreKeyDownEvent.key = key.c_str();
1170 ecoreKeyDownEvent.string = integKeyEvent.keyString.c_str();
1171 ecoreKeyDownEvent.compose = compose.c_str();
1172 ecoreKeyDownEvent.timestamp = integKeyEvent.time;
1173 ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier(integKeyEvent.keyModifier);
1174 ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock(integKeyEvent.keyModifier);
1175 ecoreKeyDownEvent.dev_name = deviceName.c_str();
1176 ecoreKeyDownEvent.dev_class = static_cast<Ecore_IMF_Device_Class>(integKeyEvent.deviceClass); //ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1177 ecoreKeyDownEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass>(integKeyEvent.deviceSubclass); //ECORE_IMF_DEVICE_SUBCLASS_NONE;
1178 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
1179 ecoreKeyDownEvent.keycode = integKeyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
1180 #endif // Since ecore_imf 1.22 version
1182 // If the device is IME and the focused key is the direction keys, then we should send a key event to move a key cursor.
1183 if((integKeyEvent.deviceName == "ime") && ((!strncmp(integKeyEvent.keyName.c_str(), "Left", 4)) ||
1184 (!strncmp(integKeyEvent.keyName.c_str(), "Right", 5)) ||
1185 (!strncmp(integKeyEvent.keyName.c_str(), "Up", 2)) ||
1186 (!strncmp(integKeyEvent.keyName.c_str(), "Down", 4))))
1192 eventHandled = ecore_imf_context_filter_event(mIMFContext,
1193 ECORE_IMF_EVENT_KEY_DOWN,
1194 reinterpret_cast<Ecore_IMF_Event*>(&ecoreKeyDownEvent));
1197 // If the event has not been handled by InputMethodContext then check if we should reset our input method context
1200 if(!strcmp(integKeyEvent.keyName.c_str(), "Escape") ||
1201 !strcmp(integKeyEvent.keyName.c_str(), "Return") ||
1202 !strcmp(integKeyEvent.keyName.c_str(), "KP_Enter"))
1204 ecore_imf_context_reset(mIMFContext);
1208 return eventHandled;
1211 bool InputMethodContextEcoreWl::ProcessEventKeyUp(const Dali::KeyEvent& keyEvent)
1213 bool eventHandled(false);
1216 Integration::KeyEvent integKeyEvent(keyEvent.GetKeyName(), keyEvent.GetLogicalKey(), keyEvent.GetKeyString(), keyEvent.GetKeyCode(), keyEvent.GetKeyModifier(), keyEvent.GetTime(), static_cast<Integration::KeyEvent::State>(keyEvent.GetState()), keyEvent.GetCompose(), keyEvent.GetDeviceName(), keyEvent.GetDeviceClass(), keyEvent.GetDeviceSubclass());
1217 std::string key = integKeyEvent.logicalKey;
1219 std::string compose = integKeyEvent.compose;
1220 std::string deviceName = integKeyEvent.deviceName;
1222 // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
1223 Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
1224 ecoreKeyUpEvent.keyname = integKeyEvent.keyName.c_str();
1225 ecoreKeyUpEvent.key = key.c_str();
1226 ecoreKeyUpEvent.string = integKeyEvent.keyString.c_str();
1227 ecoreKeyUpEvent.compose = compose.c_str();
1228 ecoreKeyUpEvent.timestamp = integKeyEvent.time;
1229 ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier(integKeyEvent.keyModifier);
1230 ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock(integKeyEvent.keyModifier);
1231 ecoreKeyUpEvent.dev_name = deviceName.c_str();
1232 ecoreKeyUpEvent.dev_class = static_cast<Ecore_IMF_Device_Class>(integKeyEvent.deviceClass); //ECORE_IMF_DEVICE_CLASS_KEYBOARD;
1233 ecoreKeyUpEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass>(integKeyEvent.deviceSubclass); //ECORE_IMF_DEVICE_SUBCLASS_NONE;
1234 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
1235 ecoreKeyUpEvent.keycode = integKeyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
1236 #endif // Since ecore_imf 1.22 version
1238 eventHandled = ecore_imf_context_filter_event(mIMFContext,
1239 ECORE_IMF_EVENT_KEY_UP,
1240 reinterpret_cast<Ecore_IMF_Event*>(&ecoreKeyUpEvent));
1242 return eventHandled;
1245 Ecore_IMF_Keyboard_Modifiers InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFModifier(unsigned int ecoreModifier)
1247 unsigned int modifier(ECORE_IMF_KEYBOARD_MODIFIER_NONE); // If no other matches returns NONE.
1249 if(ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT) // enums from ecore_input/Ecore_Input.h
1251 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT; // enums from ecore_imf/ecore_imf.h
1254 if(ecoreModifier & ECORE_EVENT_MODIFIER_ALT)
1256 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
1259 if(ecoreModifier & ECORE_EVENT_MODIFIER_CTRL)
1261 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
1264 if(ecoreModifier & ECORE_EVENT_MODIFIER_WIN)
1266 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
1269 if(ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR)
1271 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
1274 return static_cast<Ecore_IMF_Keyboard_Modifiers>(modifier);
1277 Ecore_IMF_Keyboard_Locks InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFLock(unsigned int modifier)
1279 unsigned int lock(ECORE_IMF_KEYBOARD_LOCK_NONE); // If no other matches, returns NONE.
1281 if(modifier & ECORE_EVENT_LOCK_NUM)
1283 lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
1286 if(modifier & ECORE_EVENT_LOCK_CAPS)
1288 lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
1291 if(modifier & ECORE_EVENT_LOCK_SCROLL)
1293 lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
1296 return static_cast<Ecore_IMF_Keyboard_Locks>(lock);
1299 void InputMethodContextEcoreWl::OnStaged(Dali::Actor actor)
1301 int windowId = GetWindowIdFromActor(actor);
1303 if(mWindowId != windowId)
1305 mWindowId = windowId;
1313 } // namespace Adaptor
1315 } // namespace Internal