2 * Copyright (c) 2022 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 <dali/internal/input/ubuntu-x11/input-method-context-impl-x.h>
22 #include <dali/devel-api/common/singleton-service.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/events/key-event.h>
25 #include <dali/public-api/object/type-registry.h>
28 #include <dali/integration-api/adaptor-framework/adaptor.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
30 #include <dali/internal/input/common/key-impl.h>
31 #include <dali/internal/input/common/virtual-keyboard-impl.h>
32 #include <dali/internal/input/linux/dali-ecore-imf.h>
33 #include <dali/internal/input/ubuntu-x11/dali-ecore-input.h>
34 #include <dali/internal/system/common/locale-utils.h>
35 #include <dali/internal/system/linux/dali-ecore.h>
36 #include <dali/public-api/adaptor-framework/key.h>
46 #if defined(DEBUG_ENABLED)
47 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
50 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
51 size_t Utf8SequenceLength(const unsigned char leadByte)
55 if((leadByte & 0x80) == 0) //ASCII character (lead bit zero)
59 else if((leadByte & 0xe0) == 0xc0) //110x xxxx
63 else if((leadByte & 0xf0) == 0xe0) //1110 xxxx
67 else if((leadByte & 0xf8) == 0xf0) //1111 0xxx
71 else if((leadByte & 0xfc) == 0xf8) //1111 10xx
75 else if((leadByte & 0xfe) == 0xfc) //1111 110x
83 // Static function calls used by ecore 'c' style callback registration
84 void Commit(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
88 InputMethodContextX* inputMethodContext = static_cast<InputMethodContextX*>(data);
89 inputMethodContext->CommitReceived(data, imfContext, eventInfo);
93 void PreEdit(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
97 InputMethodContextX* inputMethodContext = static_cast<InputMethodContextX*>(data);
98 inputMethodContext->PreEditChanged(data, imfContext, eventInfo);
102 Eina_Bool ImfRetrieveSurrounding(void* data, Ecore_IMF_Context* imfContext, char** text, int* cursorPosition)
106 InputMethodContextX* inputMethodContext = static_cast<InputMethodContextX*>(data);
107 return inputMethodContext->RetrieveSurrounding(data, imfContext, text, cursorPosition);
116 * Called when an InputMethodContext delete surrounding event is received.
117 * Here we tell the application that it should delete a certain range.
119 void ImfDeleteSurrounding(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
123 InputMethodContextX* inputMethodContext = static_cast<InputMethodContextX*>(data);
124 inputMethodContext->DeleteSurrounding(data, imfContext, eventInfo);
128 } // unnamed namespace
130 InputMethodContextPtr InputMethodContextX::New(Dali::Actor actor)
132 InputMethodContextPtr manager;
134 if(actor && Dali::Adaptor::IsAvailable())
136 manager = new InputMethodContextX(actor);
142 void InputMethodContextX::Finalize()
144 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::Finalize\n");
145 DisconnectCallbacks();
149 InputMethodContextX::InputMethodContextX(Dali::Actor actor)
152 mIMFCursorPosition(0),
154 mRestoreAfterFocusLost(false),
155 mIdleCallbackConnected(false)
159 actor.OnSceneSignal().Connect(this, &InputMethodContextX::OnStaged);
162 InputMethodContextX::~InputMethodContextX()
165 ecore_imf_shutdown();
168 void InputMethodContextX::Initialize()
174 void InputMethodContextX::CreateContext()
176 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::CreateContext\n");
183 const char* contextId = ecore_imf_context_default_id_get();
186 mIMFContext = ecore_imf_context_add(contextId);
190 ecore_imf_context_client_window_set(mIMFContext, reinterpret_cast<void*>(mEcoreXwin));
194 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
199 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
203 void InputMethodContextX::DeleteContext()
205 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::DeleteContext\n");
209 ecore_imf_context_del(mIMFContext);
214 // Callbacks for predicitive text support.
215 void InputMethodContextX::ConnectCallbacks()
219 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::ConnectCallbacks\n");
221 ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit, this);
222 ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit, this);
223 ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this);
225 ecore_imf_context_retrieve_surrounding_callback_set(mIMFContext, ImfRetrieveSurrounding, this);
229 void InputMethodContextX::DisconnectCallbacks()
233 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::DisconnectCallbacks\n");
235 ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreEdit);
236 ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_COMMIT, Commit);
237 ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding);
239 // We do not need to unset the retrieve surrounding callback.
243 void InputMethodContextX::Activate()
245 // Reset mIdleCallbackConnected
246 mIdleCallbackConnected = false;
250 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::Activate\n");
252 ecore_imf_context_focus_in(mIMFContext);
254 // emit keyboard activated signal
255 Dali::InputMethodContext handle(this);
256 mActivatedSignal.Emit(handle);
260 void InputMethodContextX::Deactivate()
264 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::Deactivate\n");
267 ecore_imf_context_focus_out(mIMFContext);
270 // Reset mIdleCallbackConnected
271 mIdleCallbackConnected = false;
274 void InputMethodContextX::Reset()
276 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::Reset\n");
280 ecore_imf_context_reset(mIMFContext);
284 ImfContext* InputMethodContextX::GetContext()
286 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::GetContext\n");
291 bool InputMethodContextX::RestoreAfterFocusLost() const
293 return mRestoreAfterFocusLost;
296 void InputMethodContextX::SetRestoreAfterFocusLost(bool toggle)
298 mRestoreAfterFocusLost = toggle;
302 * Called when an InputMethodContext Pre-Edit changed event is received.
303 * We are still predicting what the user is typing. The latest string is what the InputMethodContext module thinks
304 * the user wants to type.
306 void InputMethodContextX::PreEditChanged(void*, ImfContext* imfContext, void* eventInfo)
308 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::PreEditChanged\n");
309 auto context = static_cast<Ecore_IMF_Context*>(imfContext);
311 char* preEditString(NULL);
312 int cursorPosition(0);
313 Eina_List* attrs = NULL;
316 Ecore_IMF_Preedit_Attr* attr;
318 mPreeditAttrs.Clear();
320 // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
321 // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
322 ecore_imf_context_preedit_string_with_attributes_get(context, &preEditString, &attrs, &cursorPosition);
326 // iterate through the list of attributes getting the type, start and end position.
327 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))))
329 Dali::InputMethodContext::PreeditAttributeData data;
333 size_t visualCharacterIndex = 0;
334 size_t byteIndex = 0;
336 // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
337 char leadByte = preEditString[byteIndex];
339 while(leadByte != '\0')
341 leadByte = preEditString[byteIndex]; // Update the character to get the number of its byte
343 // attr->end_index is provided as a byte position not character and we need to know the character position.
344 const size_t currentSequenceLength = Utf8SequenceLength(leadByte); // returns number of bytes used to represent character.
345 if(byteIndex <= attr->start_index)
347 data.startIndex = visualCharacterIndex;
349 if(byteIndex >= attr->end_index)
351 data.endIndex = visualCharacterIndex;
353 // end loop as found cursor position that matches byte position
357 byteIndex += currentSequenceLength; // jump to next character
358 visualCharacterIndex++; // increment character count so we know our position for when we get a match
362 switch(attr->preedit_type)
364 case ECORE_IMF_PREEDIT_TYPE_NONE:
366 data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
369 case ECORE_IMF_PREEDIT_TYPE_SUB1:
371 data.preeditType = Dali::InputMethodContext::PreeditStyle::UNDERLINE;
374 case ECORE_IMF_PREEDIT_TYPE_SUB2:
376 data.preeditType = Dali::InputMethodContext::PreeditStyle::REVERSE;
379 case ECORE_IMF_PREEDIT_TYPE_SUB3:
381 data.preeditType = Dali::InputMethodContext::PreeditStyle::HIGHLIGHT;
384 case ECORE_IMF_PREEDIT_TYPE_SUB4:
386 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1;
389 case ECORE_IMF_PREEDIT_TYPE_SUB5:
391 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2;
394 case ECORE_IMF_PREEDIT_TYPE_SUB6:
396 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3;
399 case ECORE_IMF_PREEDIT_TYPE_SUB7:
401 data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4;
406 data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
410 mPreeditAttrs.PushBack(data);
414 if(Dali::Adaptor::IsAvailable())
416 Dali::InputMethodContext handle(this);
417 Dali::InputMethodContext::EventData eventData(Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0);
418 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit(handle, eventData);
420 if(callbackData.update)
422 mIMFCursorPosition = static_cast<int>(callbackData.cursorPosition);
424 NotifyCursorPosition();
427 if(callbackData.preeditResetRequired)
435 void InputMethodContextX::CommitReceived(void*, ImfContext* imfContext, void* eventInfo)
437 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::CommitReceived\n");
439 if(Dali::Adaptor::IsAvailable())
441 const std::string keyString(static_cast<char*>(eventInfo));
443 Dali::InputMethodContext handle(this);
444 Dali::InputMethodContext::EventData eventData(Dali::InputMethodContext::COMMIT, keyString, 0, 0);
445 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit(handle, eventData);
447 if(callbackData.update)
449 mIMFCursorPosition = static_cast<int>(callbackData.cursorPosition);
451 NotifyCursorPosition();
457 * Called when an InputMethodContext retrieve surround event is received.
458 * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
459 * We need to signal the application to tell us this information.
461 bool InputMethodContextX::RetrieveSurrounding(void* data, ImfContext* imfContext, char** text, int* cursorPosition)
463 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::RetrieveSurrounding\n");
465 Dali::InputMethodContext::EventData imfData(Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0);
466 Dali::InputMethodContext handle(this);
467 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit(handle, imfData);
469 if(callbackData.update)
473 *text = strdup(callbackData.currentText.c_str());
478 mIMFCursorPosition = static_cast<int>(callbackData.cursorPosition);
479 *cursorPosition = mIMFCursorPosition;
487 * Called when an InputMethodContext delete surrounding event is received.
488 * Here we tell the application that it should delete a certain range.
490 void InputMethodContextX::DeleteSurrounding(void* data, ImfContext* imfContext, void* eventInfo)
492 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::DeleteSurrounding\n");
494 if(Dali::Adaptor::IsAvailable())
496 Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>(eventInfo);
498 Dali::InputMethodContext::EventData imfData(Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars);
499 Dali::InputMethodContext handle(this);
500 Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit(handle, imfData);
502 if(callbackData.update)
504 mIMFCursorPosition = static_cast<int>(callbackData.cursorPosition);
506 NotifyCursorPosition();
511 void InputMethodContextX::NotifyCursorPosition()
513 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::NotifyCursorPosition\n");
517 ecore_imf_context_cursor_position_set(mIMFContext, mIMFCursorPosition);
521 void InputMethodContextX::SetCursorPosition(unsigned int cursorPosition)
523 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::SetCursorPosition\n");
525 mIMFCursorPosition = static_cast<int>(cursorPosition);
528 unsigned int InputMethodContextX::GetCursorPosition() const
530 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::GetCursorPosition\n");
532 return static_cast<unsigned int>(mIMFCursorPosition);
535 void InputMethodContextX::SetSurroundingText(const std::string& text)
537 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::SetSurroundingText\n");
539 mSurroundingText = text;
542 const std::string& InputMethodContextX::GetSurroundingText() const
544 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::GetSurroundingText\n");
546 return mSurroundingText;
549 void InputMethodContextX::NotifyTextInputMultiLine(bool multiLine)
553 Dali::InputMethodContext::TextDirection InputMethodContextX::GetTextDirection()
555 Dali::InputMethodContext::TextDirection direction(Dali::InputMethodContext::LEFT_TO_RIGHT);
560 ecore_imf_context_input_panel_language_locale_get(mIMFContext, &locale);
564 direction = static_cast<Dali::InputMethodContext::TextDirection>(Locale::GetDirection(std::string(locale)));
572 Rect<int> InputMethodContextX::GetInputMethodArea()
574 int xPos, yPos, width, height;
576 width = height = xPos = yPos = 0;
580 ecore_imf_context_input_panel_geometry_get(mIMFContext, &xPos, &yPos, &width, &height);
584 DALI_LOG_WARNING("VKB Unable to get InputMethodContext Context so GetSize unavailable\n");
587 return Rect<int>(xPos, yPos, width, height);
590 void InputMethodContextX::ApplyOptions(const InputMethodOptions& options)
592 using namespace Dali::InputMethod::Category;
596 if(mIMFContext == NULL)
598 DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
602 if(mOptions.CompareAndSet(PANEL_LAYOUT, options, index))
605 if(mOptions.CompareAndSet(BUTTON_ACTION, options, index))
608 if(mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index))
611 if(mOptions.CompareAndSet(VARIATION, options, index))
616 void InputMethodContextX::SetInputPanelData(const std::string& data)
618 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelData\n");
622 int length = data.length();
623 ecore_imf_context_input_panel_imdata_set(mIMFContext, data.c_str(), length);
627 void InputMethodContextX::GetInputPanelData(std::string& data)
629 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelData\n");
633 int length = 4096; // The max length is 4096 bytes
634 Dali::Vector<char> buffer;
635 buffer.Resize(length);
636 ecore_imf_context_input_panel_imdata_get(mIMFContext, &buffer[0], &length);
637 data = std::string(buffer.Begin(), buffer.End());
641 Dali::InputMethodContext::State InputMethodContextX::GetInputPanelState()
643 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelState\n");
648 value = ecore_imf_context_input_panel_state_get(mIMFContext);
652 case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
654 return Dali::InputMethodContext::SHOW;
658 case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
660 return Dali::InputMethodContext::HIDE;
664 case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
666 return Dali::InputMethodContext::WILL_SHOW;
672 return Dali::InputMethodContext::DEFAULT;
676 return Dali::InputMethodContext::DEFAULT;
679 void InputMethodContextX::SetReturnKeyState(bool visible)
681 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::SetReturnKeyState\n");
685 ecore_imf_context_input_panel_return_key_disabled_set(mIMFContext, !visible);
689 void InputMethodContextX::AutoEnableInputPanel(bool enabled)
691 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::AutoEnableInputPanel\n");
695 ecore_imf_context_input_panel_enabled_set(mIMFContext, enabled);
699 void InputMethodContextX::ShowInputPanel()
701 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::ShowInputPanel\n");
705 ecore_imf_context_input_panel_show(mIMFContext);
709 void InputMethodContextX::HideInputPanel()
711 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::HideInputPanel\n");
715 ecore_imf_context_input_panel_hide(mIMFContext);
719 Dali::InputMethodContext::KeyboardType InputMethodContextX::GetKeyboardType()
721 return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
724 std::string InputMethodContextX::GetInputPanelLocale()
726 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLocale\n");
728 std::string locale = "";
733 ecore_imf_context_input_panel_language_locale_get(mIMFContext, &value);
737 std::string valueCopy(value);
740 // The locale string retrieved must be freed with free().
747 void InputMethodContextX::SetContentMIMETypes(const std::string& mimeTypes)
749 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::SetContentMIMETypes\n");
750 // ecore_imf_context_mime_type_accept_set() is supported from ecore-imf 1.20.0 version.
753 bool InputMethodContextX::FilterEventKey(const Dali::KeyEvent& keyEvent)
755 bool eventHandled(false);
757 // If a device key then skip ecore_imf_context_filter_event.
758 if(!KeyLookup::IsDeviceButton(keyEvent.GetKeyName().c_str()))
760 //check whether it's key down or key up event
761 if(keyEvent.GetState() == Dali::KeyEvent::DOWN)
763 eventHandled = ProcessEventKeyDown(keyEvent);
765 else if(keyEvent.GetState() == Dali::KeyEvent::UP)
767 eventHandled = ProcessEventKeyUp(keyEvent);
774 void InputMethodContextX::AllowTextPrediction(bool prediction)
776 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::AllowTextPrediction\n");
780 ecore_imf_context_prediction_allow_set(mIMFContext, prediction);
784 bool InputMethodContextX::IsTextPredictionAllowed() const
786 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::IsTextPredictionAllowed\n");
787 bool prediction = false;
790 prediction = ecore_imf_context_prediction_allow_get(mIMFContext);
795 void InputMethodContextX::SetInputPanelLanguage(Dali::InputMethodContext::InputPanelLanguage language)
797 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelLanguage\n");
802 case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
804 ecore_imf_context_input_panel_language_set(mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC);
807 case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
809 ecore_imf_context_input_panel_language_set(mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET);
816 Dali::InputMethodContext::InputPanelLanguage InputMethodContextX::GetInputPanelLanguage() const
818 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLanguage\n");
822 value = ecore_imf_context_input_panel_language_get(mIMFContext);
826 case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
828 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
831 case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
833 return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
838 return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
841 void InputMethodContextX::SetInputPanelPosition(unsigned int x, unsigned int y)
843 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelPosition\n");
845 // ecore_imf_context_input_panel_position_set() is supported from ecore-imf 1.21.0 version.
848 bool InputMethodContextX::SetInputPanelPositionAlign(int x, int y, Dali::InputMethodContext::InputPanelAlign align)
850 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelPositionAlign\n");
854 void InputMethodContextX::GetPreeditStyle(Dali::InputMethodContext::PreEditAttributeDataContainer& attrs) const
856 DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextX::GetPreeditStyle\n");
857 attrs = mPreeditAttrs;
860 bool InputMethodContextX::ProcessEventKeyDown(const Dali::KeyEvent& keyEvent)
862 bool eventHandled(false);
865 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());
866 std::string key = integKeyEvent.logicalKey;
868 std::string compose = integKeyEvent.compose;
870 // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
871 Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
872 ecoreKeyDownEvent.keyname = integKeyEvent.keyName.c_str();
873 ecoreKeyDownEvent.key = key.c_str();
874 ecoreKeyDownEvent.string = integKeyEvent.keyString.c_str();
875 ecoreKeyDownEvent.compose = compose.c_str();
876 ecoreKeyDownEvent.timestamp = integKeyEvent.time;
877 ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier(integKeyEvent.keyModifier);
878 ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock(integKeyEvent.keyModifier);
880 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
881 #if(ECORE_VERSION_MINOR >= 14)
882 ecoreKeyDownEvent.dev_name = "";
883 ecoreKeyDownEvent.dev_class = ECORE_IMF_DEVICE_CLASS_KEYBOARD;
884 ecoreKeyDownEvent.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
885 #endif // Since ecore_imf 1.14 version
886 #if(ECORE_VERSION_MINOR >= 22)
887 ecoreKeyDownEvent.keycode = integKeyEvent.keyCode;
888 #endif // Since ecore_imf 1.22 version
889 #endif // Since ecore_imf Version 1
891 // 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.
892 if((integKeyEvent.deviceName == "ime") && ((!strncmp(integKeyEvent.keyName.c_str(), "Left", 4)) ||
893 (!strncmp(integKeyEvent.keyName.c_str(), "Right", 5)) ||
894 (!strncmp(integKeyEvent.keyName.c_str(), "Up", 2)) ||
895 (!strncmp(integKeyEvent.keyName.c_str(), "Down", 4))))
901 eventHandled = ecore_imf_context_filter_event(mIMFContext,
902 ECORE_IMF_EVENT_KEY_DOWN,
903 reinterpret_cast<Ecore_IMF_Event*>(&ecoreKeyDownEvent));
906 // If the event has not been handled by InputMethodContext then check if we should reset our IMFcontext
909 if(!strcmp(integKeyEvent.keyName.c_str(), "Escape") ||
910 !strcmp(integKeyEvent.keyName.c_str(), "Return") ||
911 !strcmp(integKeyEvent.keyName.c_str(), "KP_Enter"))
913 ecore_imf_context_reset(mIMFContext);
920 bool InputMethodContextX::ProcessEventKeyUp(const Dali::KeyEvent& keyEvent)
922 bool eventHandled(false);
925 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());
927 std::string key = integKeyEvent.logicalKey;
929 std::string compose = integKeyEvent.compose;
931 // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
932 Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
933 ecoreKeyUpEvent.keyname = integKeyEvent.keyName.c_str();
934 ecoreKeyUpEvent.key = key.c_str();
935 ecoreKeyUpEvent.string = integKeyEvent.keyString.c_str();
936 ecoreKeyUpEvent.compose = compose.c_str();
937 ecoreKeyUpEvent.timestamp = integKeyEvent.time;
938 ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier(integKeyEvent.keyModifier);
939 ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock(integKeyEvent.keyModifier);
940 #if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
941 #if(ECORE_VERSION_MINOR >= 14)
942 ecoreKeyUpEvent.dev_name = "";
943 #endif // Since ecore_imf 1.14 version
944 #if(ECORE_VERSION_MINOR >= 22)
945 ecoreKeyUpEvent.keycode = integKeyEvent.keyCode;
946 #endif // Since ecore_imf 1.22 version
947 #endif // Since ecore_imf Version 1
949 eventHandled = ecore_imf_context_filter_event(mIMFContext,
950 ECORE_IMF_EVENT_KEY_UP,
951 reinterpret_cast<Ecore_IMF_Event*>(&ecoreKeyUpEvent));
956 Ecore_IMF_Keyboard_Modifiers InputMethodContextX::EcoreInputModifierToEcoreIMFModifier(unsigned int ecoreModifier)
958 unsigned int modifier(ECORE_IMF_KEYBOARD_MODIFIER_NONE); // If no other matches returns NONE.
960 if(ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT) // enums from ecore_input/Ecore_Input.h
962 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT; // enums from ecore_imf/ecore_imf.h
965 if(ecoreModifier & ECORE_EVENT_MODIFIER_ALT)
967 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
970 if(ecoreModifier & ECORE_EVENT_MODIFIER_CTRL)
972 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
975 if(ecoreModifier & ECORE_EVENT_MODIFIER_WIN)
977 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
980 if(ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR)
982 modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
985 return static_cast<Ecore_IMF_Keyboard_Modifiers>(modifier);
988 Ecore_IMF_Keyboard_Locks InputMethodContextX::EcoreInputModifierToEcoreIMFLock(unsigned int modifier)
990 unsigned int lock(ECORE_IMF_KEYBOARD_LOCK_NONE); // If no other matches, returns NONE.
992 if(modifier & ECORE_EVENT_LOCK_NUM)
994 lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
997 if(modifier & ECORE_EVENT_LOCK_CAPS)
999 lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
1002 if(modifier & ECORE_EVENT_LOCK_SCROLL)
1004 lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
1007 return static_cast<Ecore_IMF_Keyboard_Locks>(lock);
1010 void InputMethodContextX::OnStaged(Dali::Actor actor)
1012 Ecore_X_Window ecoreXwin(AnyCast<Ecore_X_Window>(Dali::Integration::SceneHolder::Get(actor).GetNativeHandle()));
1014 if(mEcoreXwin != ecoreXwin)
1016 mEcoreXwin = ecoreXwin;
1024 } // namespace Adaptor
1026 } // namespace Internal