2 Copyright (C) 2011 Samsung Electronics
3 Copyright (C) 2012 Intel Corporation. All rights reserved.
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 #include "InputMethodContextEfl.h"
24 #include "EwkViewImpl.h"
25 #include "WebPageProxy.h"
26 #include <Ecore_Evas.h>
27 #include <Ecore_IMF_Evas.h>
29 using namespace WebCore;
33 #if ENABLE(TIZEN_ISF_PORT)
34 const unsigned InputMethodContextEfl::maxContextSize = 10;
35 Ecore_X_Atom InputMethodContextEfl::s_externalKeyboardProperty = 0;
36 bool InputMethodContextEfl::s_shouldUseExternalKeyboard = false;
37 bool InputMethodContextEfl::s_isSystemKeypadShow = false;
39 void InputMethodContextEfl::initializeExternalKeyboard()
41 s_externalKeyboardProperty = ecore_x_atom_get("X External Keyboard Exist");
42 if (!s_externalKeyboardProperty)
45 Ecore_X_Window rootWin = ecore_x_window_root_first_get();
46 ecore_x_event_mask_set(rootWin, ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
48 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, windowPropertyChanged, 0);
51 if (ecore_x_window_prop_card32_get(rootWin, s_externalKeyboardProperty, &value, 1) <= 0)
54 s_shouldUseExternalKeyboard = value;
57 Eina_Bool InputMethodContextEfl::windowPropertyChanged(void*, int, void* event)
59 Ecore_X_Event_Window_Property* propertyEvent = static_cast<Ecore_X_Event_Window_Property*>(event);
61 if (propertyEvent->atom != s_externalKeyboardProperty)
62 return ECORE_CALLBACK_PASS_ON;
65 if (ecore_x_window_prop_card32_get(propertyEvent->win, s_externalKeyboardProperty, &value, 1) <= 0 || s_shouldUseExternalKeyboard == value)
66 return ECORE_CALLBACK_PASS_ON;
68 s_shouldUseExternalKeyboard = value;
70 #if ENABLE(TIZEN_FOCUS_UI)
71 if (!s_shouldUseExternalKeyboard) {
72 Vector<RefPtr<WebPageProxy> > pages;
73 EwkViewImpl::pages(pages);
75 for (size_t i = 0; i < pages.size(); ++i)
76 pages[i]->setSpatialNavigationEnabled(false);
80 return ECORE_CALLBACK_PASS_ON;
84 InputMethodContextEfl::InputMethodContextEfl(EwkViewImpl* viewImpl, PassOwnPtr<Ecore_IMF_Context> context)
85 : m_viewImpl(viewImpl)
88 #if ENABLE(TIZEN_ISF_PORT)
90 , m_state(ECORE_IMF_INPUT_PANEL_STATE_HIDE)
91 , m_inputPickerType(-1)
92 , m_doNotHandleFakeKeyEvent(false)
93 , m_fakeKeyEventTimer(this, &InputMethodContextEfl::fakeKeyEventTimerFired)
96 #if ENABLE(TIZEN_ISF_PORT)
97 if (!s_externalKeyboardProperty)
98 initializeExternalKeyboard();
100 m_IMEStatusChangeHandler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, IMEStatusChangeCallback, this);
103 ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
104 ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
108 InputMethodContextEfl::~InputMethodContextEfl()
110 ecore_event_handler_del(m_IMEStatusChangeHandler);
111 m_IMEStatusChangeHandler = 0;
114 #if ENABLE(TIZEN_ISF_PORT)
115 void InputMethodContextEfl::onIMFInputPanelStateChanged(void* data, Ecore_IMF_Context*, int state)
117 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
119 inputMethodContext->setState(state);
121 if (state == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
122 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
123 if (inputMethodContext->m_viewImpl->pageClient->isClipboardWindowOpened())
124 inputMethodContext->m_viewImpl->pageClient->closeClipboardWindow();
127 if (inputMethodContext->m_viewImpl->page()->editorState().hasComposition)
128 inputMethodContext->resetIMFContext();
130 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,closed", 0);
131 } else if (state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
132 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,opened", 0);
135 void InputMethodContextEfl::onIMFInputPanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
137 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
138 if (!inputMethodContext->m_context)
142 ecore_imf_context_input_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
143 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "inputmethod,changed", &rect);
145 inputMethodContext->setIMERect(IntRect(rect.x, rect.y, rect.w, rect.h));
148 void InputMethodContextEfl::onIMFCandidatePanelStateChanged(void* data, Ecore_IMF_Context*, int state)
150 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
152 if (state == ECORE_IMF_CANDIDATE_PANEL_SHOW)
153 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,opened", 0);
155 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,closed", 0);
158 void InputMethodContextEfl::onIMFCandidatePanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
160 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
161 if (!inputMethodContext->m_context)
165 ecore_imf_context_candidate_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
166 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,changed", &rect);
169 Eina_Bool InputMethodContextEfl::onIMFRetrieveSurrounding(void* data, Ecore_IMF_Context*, char** text, int* offset)
171 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
172 if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused || (!text && !offset))
175 const EditorState& editor = inputMethodContext->m_viewImpl->page()->editorState();
178 CString utf8Text(editor.surroundingText.utf8());
179 size_t length = utf8Text.length();
181 *text = static_cast<char*>(malloc((length + 1) * sizeof(char)));
186 strncpy(*text, utf8Text.data(), length);
191 *offset = editor.cursorPosition;
196 void InputMethodContextEfl::onIMFDeleteSurrounding(void* data, Ecore_IMF_Context*, void* eventInfo)
198 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
199 if (!eventInfo || !inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
202 inputMethodContext->requestFakeKeyEvent();
204 Ecore_IMF_Event_Delete_Surrounding* event = static_cast<Ecore_IMF_Event_Delete_Surrounding*>(eventInfo);
205 inputMethodContext->m_viewImpl->page()->deleteSurroundingText(event->offset, event->n_chars);
208 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
210 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
211 if (!eventInfo || !inputMethodContext->m_focused)
214 inputMethodContext->requestFakeKeyEvent();
216 inputMethodContext->m_viewImpl->page()->confirmComposition(String::fromUTF8(static_cast<char*>(eventInfo)));
219 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
220 unsigned getUTF8CharacterIndex(const char* string, unsigned byteIndex)
223 const char* end = string + byteIndex;
225 while (*string && string < end) {
228 if ((*string & 0x80) == 0x00)
230 else if ((*string & 0xe0) == 0xc0)
232 else if ((*string & 0xf0) == 0xe0)
234 else if ((*string & 0xf8) == 0xf0)
236 else if ((*string & 0xfc) == 0xf8)
238 else if ((*string & 0xfe) == 0xfc)
244 while (*string && offset--)
252 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
254 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
256 if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
259 WebPageProxy* page = inputMethodContext->m_viewImpl->page();
260 if (!page->focusedFrame())
263 inputMethodContext->requestFakeKeyEvent();
265 const EditorState& editor = inputMethodContext->m_viewImpl->page()->editorState();
266 PageClientImpl* pageClient = inputMethodContext->m_viewImpl->pageClient.get();
268 if (!editor.selectionIsNone && !editor.selectionIsRange) {
269 caretRect = editor.selectionRect;
270 caretRect.scale(pageClient->scaleFactor());
274 evas_object_geometry_get(inputMethodContext->m_viewImpl->view(), &viewX, &viewY, 0, 0);
276 int x = caretRect.x() - pageClient->scrollPosition().x() + viewX;
277 int y = caretRect.y() - pageClient->scrollPosition().y() + viewY;
278 int w = caretRect.width();
279 int h = caretRect.height();
280 ecore_imf_context_cursor_location_set(context, x, y, w, h);
283 Eina_List* preeditAttrs = 0;
284 int cursorPosition = 0;
286 ecore_imf_context_preedit_string_with_attributes_get(context, &buffer, &preeditAttrs, &cursorPosition);
288 String preeditString = String::fromUTF8(buffer);
289 Vector<CompositionUnderline> underlines;
293 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
294 Eina_List* listIterator = 0;
295 EINA_LIST_FOREACH(preeditAttrs, listIterator, item) {
296 Ecore_IMF_Preedit_Attr* preeditAttr = static_cast<Ecore_IMF_Preedit_Attr*>(item);
298 unsigned startIndex = getUTF8CharacterIndex(buffer, preeditAttr->start_index);
299 unsigned endIndex = getUTF8CharacterIndex(buffer, preeditAttr->end_index);
300 switch (preeditAttr->preedit_type) {
301 case ECORE_IMF_PREEDIT_TYPE_SUB1:
302 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), false));
304 case ECORE_IMF_PREEDIT_TYPE_SUB2:
305 case ECORE_IMF_PREEDIT_TYPE_SUB3:
306 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(255, 255, 255), false));
308 case ECORE_IMF_PREEDIT_TYPE_SUB4:
309 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(46, 168, 255), false));
311 case ECORE_IMF_PREEDIT_TYPE_SUB5:
312 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 98, 195), false));
314 case ECORE_IMF_PREEDIT_TYPE_SUB6:
315 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(118, 222, 55), false));
317 case ECORE_IMF_PREEDIT_TYPE_SUB7:
318 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 153, 153), false));
325 EINA_LIST_FREE(preeditAttrs, item)
329 if (underlines.isEmpty())
330 underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
332 page->setComposition(preeditString, underlines, cursorPosition);
338 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
340 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
341 if (!eventInfo || !inputMethodContext->m_focused)
344 inputMethodContext->m_viewImpl->page()->confirmComposition(String::fromUTF8(static_cast<char*>(eventInfo)));
347 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
349 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
351 if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
355 ecore_imf_context_preedit_string_get(context, &buffer, 0);
359 String preeditString = String::fromUTF8(buffer);
361 Vector<CompositionUnderline> underlines;
362 underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
363 inputMethodContext->m_viewImpl->page()->setComposition(preeditString, underlines, 0);
367 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::createIMFContext(Evas* canvas)
369 const char* defaultContextID = ecore_imf_context_default_id_get();
370 if (!defaultContextID)
373 OwnPtr<Ecore_IMF_Context> imfContext = adoptPtr(ecore_imf_context_add(defaultContextID));
377 Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(canvas);
378 ecore_imf_context_client_window_set(imfContext.get(), reinterpret_cast<void*>(ecore_evas_window_get(ecoreEvas)));
379 ecore_imf_context_client_canvas_set(imfContext.get(), canvas);
381 return imfContext.release();
384 void InputMethodContextEfl::handleMouseUpEvent(const Evas_Event_Mouse_Up*)
386 #if ENABLE(TIZEN_ISF_PORT)
392 ecore_imf_context_reset(m_context.get());
396 void InputMethodContextEfl::handleKeyDownEvent(const Evas_Event_Key_Down* downEvent, bool* isFiltered)
398 #if ENABLE(TIZEN_FOCUS_UI)
399 if (s_shouldUseExternalKeyboard && strncmp(downEvent->keyname, "XF86", 4))
400 m_viewImpl->page()->setSpatialNavigationEnabled(true);
403 #if ENABLE(TIZEN_ISF_PORT)
407 if (m_fakeKeyEventTimer.isActive())
408 m_fakeKeyEventTimer.stop();
410 m_viewImpl->page()->prepareKeyDownEvent();
412 m_doNotHandleFakeKeyEvent = true;
415 Ecore_IMF_Event inputMethodEvent;
416 ecore_imf_evas_event_key_down_wrap(const_cast<Evas_Event_Key_Down*>(downEvent), &inputMethodEvent.key_down);
418 *isFiltered = ecore_imf_context_filter_event(m_context.get(), ECORE_IMF_EVENT_KEY_DOWN, &inputMethodEvent);
420 #if ENABLE(TIZEN_ISF_PORT)
421 m_doNotHandleFakeKeyEvent = false;
425 #if ENABLE(TIZEN_ISF_PORT)
426 void InputMethodContextEfl::updateTextInputState()
428 const EditorState& editor = m_viewImpl->page()->editorState();
429 if (editor.shouldIgnoreCompositionSelectionChange || editor.updateEditorRectOnly)
432 if (editor.isContentEditable)
433 showIMFContext(editor);
438 ecore_imf_context_cursor_position_set(m_context.get(), editor.cursorPosition);
441 void InputMethodContextEfl::updateTextInputStateByUserAction(bool setFocus)
443 const EditorState& editor = m_viewImpl->page()->editorState();
445 if (editor.isContentEditable) {
447 evas_object_focus_set(m_viewImpl->view(), true);
449 showIMFContext(editor, true);
454 void InputMethodContextEfl::updateTextInputState()
459 const EditorState& editor = m_viewImpl->page()->editorState();
461 if (editor.isContentEditable) {
465 ecore_imf_context_reset(m_context.get());
466 ecore_imf_context_focus_in(m_context.get());
472 if (editor.hasComposition)
473 m_viewImpl->page()->cancelComposition();
476 ecore_imf_context_reset(m_context.get());
477 ecore_imf_context_focus_out(m_context.get());
482 #if ENABLE(TIZEN_ISF_PORT)
483 void InputMethodContextEfl::initializeIMFContext(Ecore_IMF_Context* context, Ecore_IMF_Input_Panel_Layout layout, int layoutVariation, Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType)
485 ecore_imf_context_input_panel_enabled_set(context, false);
486 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_STATE_EVENT, onIMFInputPanelStateChanged, this);
487 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, onIMFInputPanelGeometryChanged, this);
488 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, onIMFCandidatePanelStateChanged, this);
489 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, onIMFCandidatePanelGeometryChanged, this);
490 ecore_imf_context_retrieve_surrounding_callback_set(context, onIMFRetrieveSurrounding, this);
491 ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, onIMFDeleteSurrounding, this);
492 ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
493 ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
495 ecore_imf_context_input_panel_layout_set(context, layout);
496 if (layoutVariation >= 0)
497 ecore_imf_context_input_panel_layout_variation_set(context, layoutVariation);
498 ecore_imf_context_input_panel_return_key_type_set(context, returnKeyType);
501 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::takeContext(uintptr_t contextID)
503 size_t i = m_contextList.size();
506 if (m_contextList[i].first == contextID) {
507 PassOwnPtr<Ecore_IMF_Context> context = m_contextList[i].second.release();
508 m_contextList.remove(i);
513 return PassOwnPtr<Ecore_IMF_Context>();
516 void InputMethodContextEfl::setIMFContext(const EditorState& editor)
518 const String& type = editor.inputMethodHints;
519 Ecore_IMF_Input_Panel_Layout layout;
520 int layoutVariation = -1;
521 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
523 if (type == "number") {
524 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
525 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_NORMAL;
526 } else if (type == "signedNumber") {
527 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
528 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED;
529 } else if (type == "decimalNumber") {
530 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
531 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_DECIMAL;
532 } else if (type == "signedDecimalNumber") {
533 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
534 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL;
535 } else if (type == "email")
536 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL;
537 else if (type == "url")
538 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_URL;
539 else if (type == "tel")
540 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER;
541 else if (type == "password")
542 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD;
544 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
545 if (type == "search")
546 returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH;
549 OwnPtr<Ecore_IMF_Context> context;
550 if (m_contextID == editor.inputMethodContextID)
551 context = m_context.release();
553 context = takeContext(editor.inputMethodContextID);
558 context = createIMFContext(evas_object_evas_get(m_viewImpl->view()));
561 initializeIMFContext(context.get(), layout, layoutVariation, returnKeyType);
564 m_context = context.release();
565 m_contextID = editor.inputMethodContextID;
567 if (type == "password" || type == "plugin")
568 ecore_imf_context_prediction_allow_set(m_context.get(), false);
570 ecore_imf_context_prediction_allow_set(m_context.get(), true);
572 if (type.isEmpty() || type == "textarea")
573 ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE);
575 ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
578 bool InputMethodContextEfl::isShow()
580 return (m_context && m_focused && ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
583 Ecore_IMF_Autocapital_Type InputMethodContextEfl::autoCapitalType()
585 return (m_context ? ecore_imf_context_autocapital_type_get(m_context.get()) : ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
588 void InputMethodContextEfl::onFocusIn()
590 if (m_inputPickerType >= 0) {
591 showInputPicker(m_viewImpl->page()->editorState());
595 if (!m_context || !m_focused)
598 ecore_imf_context_focus_in(m_context.get());
599 ecore_imf_context_input_panel_show(m_context.get());
601 setKeyboardMode(true);
604 void InputMethodContextEfl::onFocusOut()
606 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
607 if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
608 if (m_viewImpl->pageClient->isClipboardWindowOpened())
609 m_viewImpl->pageClient->closeClipboardWindow();
613 #if ENABLE(TIZEN_FOCUS_UI)
614 m_viewImpl->page()->setSpatialNavigationEnabled(false);
617 if (!m_context || !m_focused)
620 ecore_imf_context_input_panel_hide(m_context.get());
621 ecore_imf_context_focus_out(m_context.get());
623 setKeyboardMode(false);
626 void InputMethodContextEfl::revertIMFContext()
631 if (m_contextList.size() >= maxContextSize)
632 m_contextList.remove(0);
634 PassOwnPtr<Ecore_IMF_Context> imfContext = m_context.release();
635 m_contextList.append(std::make_pair(m_contextID, imfContext));
639 void InputMethodContextEfl::resetIMFContext()
644 m_doNotHandleFakeKeyEvent = true;
645 ecore_imf_context_reset(m_context.get());
646 m_doNotHandleFakeKeyEvent = false;
649 void InputMethodContextEfl::showIMFContext(const EditorState& editor, bool isUserAction)
651 Ewk_Settings* settings = ewk_view_settings_get(m_viewImpl->view());
652 bool isContextTransition = (m_context ? m_contextID != editor.inputMethodContextID : m_state != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
654 if (!isUserAction && !isContextTransition) {
655 if (!ewk_settings_uses_keypad_without_user_action_get(settings) || (m_focused && m_contextID == editor.inputMethodContextID))
659 if (m_contextID != editor.inputMethodContextID)
664 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
665 if (editor.inputMethodHints == "date")
666 m_inputPickerType = EWK_INPUT_TYPE_DATE;
667 else if (editor.inputMethodHints == "datetime")
668 m_inputPickerType = EWK_INPUT_TYPE_DATETIME;
669 else if (editor.inputMethodHints == "datetime-local")
670 m_inputPickerType = EWK_INPUT_TYPE_DATETIMELOCAL;
671 else if (editor.inputMethodHints == "month")
672 m_inputPickerType = EWK_INPUT_TYPE_MONTH;
673 else if (editor.inputMethodHints == "time")
674 m_inputPickerType = EWK_INPUT_TYPE_TIME;
675 else if (editor.inputMethodHints == "week")
676 m_inputPickerType = EWK_INPUT_TYPE_WEEK;
678 m_inputPickerType = -1;
680 if (m_inputPickerType >= 0) {
681 showInputPicker(editor);
682 m_contextID = editor.inputMethodContextID;
687 #if !ENABLE(TIZEN_DATALIST_ELEMENT)
688 Vector<String> optionList = m_viewImpl->page()->getFocusedInputElementDataList();
689 if (optionList.size() > 0) {
690 if (editor.selectionIsRange || !evas_object_focus_get(m_viewImpl->view()))
693 if (editor.inputMethodHints == "tel")
694 ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_TELEPHONE, optionList);
695 else if (editor.inputMethodHints == "number")
696 ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_NUMBER, optionList);
697 else if (editor.inputMethodHints == "email")
698 ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_EMAIL, optionList);
699 else if (editor.inputMethodHints == "url")
700 ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_URL, optionList);
702 ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_TEXT, optionList);
704 m_contextID = editor.inputMethodContextID;
709 #endif // ENABLE(TIZEN_INPUT_TAG_EXTENSION)
711 bool hasFocus = evas_object_focus_get(m_viewImpl->view());
713 if (!ewk_settings_default_keypad_enabled_get(settings)) {
715 Eina_Rectangle dummyRectForCustomKeypadCallback;
716 memset(&dummyRectForCustomKeypadCallback, 0, sizeof(Eina_Rectangle));
717 evas_object_smart_callback_call(m_viewImpl->view(), "inputmethod,changed", &dummyRectForCustomKeypadCallback);
722 setIMFContext(editor);
729 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
730 if (m_viewImpl->pageClient->isClipboardWindowOpened())
731 m_viewImpl->pageClient->closeClipboardWindow();
734 // input field zoom for external keyboard
735 if (s_shouldUseExternalKeyboard)
736 ewk_view_focused_node_adjust(m_viewImpl->view(), EINA_TRUE);
739 ewk_view_focused_node_adjust(m_viewImpl->view(), EINA_FALSE);
743 ecore_imf_context_focus_in(m_context.get());
744 ecore_imf_context_input_panel_show(m_context.get());
746 setKeyboardMode(true);
749 void InputMethodContextEfl::hideIMFContext()
751 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
752 if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
753 if (m_viewImpl->pageClient->isClipboardWindowOpened())
754 m_viewImpl->pageClient->closeClipboardWindow();
758 m_inputPickerType = -1;
760 if (!m_context || !m_focused)
763 if (ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE
764 && evas_object_focus_get(m_viewImpl->view())) {
766 ecore_imf_context_input_panel_hide(m_context.get());
767 ecore_imf_context_focus_out(m_context.get());
770 setKeyboardMode(false);
776 void InputMethodContextEfl::destroyIMFContextList()
778 m_contextList.clear();
781 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
782 void InputMethodContextEfl::showInputPicker(const EditorState& editorState)
784 if (editorState.selectionIsRange || !evas_object_focus_get(m_viewImpl->view()))
787 ewkViewInputPickerRequest(m_viewImpl->view(), static_cast<Ewk_Input_Type>(m_inputPickerType), editorState.surroundingText);
788 m_inputPickerType = -1;
792 bool InputMethodContextEfl::isIMEPostion(int x, int y)
794 if (m_state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
795 return m_imeRect.contains(x, y);
800 void InputMethodContextEfl::removeIMFContext(uintptr_t contextID)
802 if (m_contextID == contextID)
805 takeContext(contextID);
808 void InputMethodContextEfl::setKeyboardMode(bool isOn)
810 Evas_Object* parent = elm_object_parent_widget_get(m_viewImpl->view());
812 const char* type = elm_object_widget_type_get(parent);
813 if (type && !strcmp(type, "elm_win")) {
814 elm_win_keyboard_mode_set(parent, isOn ? ELM_WIN_KEYBOARD_ON : ELM_WIN_KEYBOARD_OFF);
818 parent = elm_object_parent_widget_get(parent);
822 void InputMethodContextEfl::requestFakeKeyEvent()
824 if (m_doNotHandleFakeKeyEvent || m_fakeKeyEventTimer.isActive())
827 m_fakeKeyEventTimer.startOneShot(0);
828 m_viewImpl->page()->prepareKeyDownEvent();
831 void InputMethodContextEfl::fakeKeyEventTimerFired(WebCore::Timer<InputMethodContextEfl>*)
833 const char* text = " ";
835 Evas_Event_Key_Down downEvent;
836 memset(&downEvent, 0, sizeof(Evas_Event_Key_Down));
837 downEvent.key = text;
838 downEvent.string = text;
839 m_viewImpl->page()->handleKeyboardEvent(NativeWebKeyboardEvent(&downEvent, true));
841 Evas_Event_Key_Up upEvent;
842 memset(&upEvent, 0, sizeof(Evas_Event_Key_Up));
844 upEvent.string = text;
845 m_viewImpl->page()->handleKeyboardEvent(NativeWebKeyboardEvent(&upEvent));
848 Eina_Bool InputMethodContextEfl::IMEStatusChangeCallback(void* data, int type, void* event)
850 // Callback to get Virtual keyboard state from window manager.
851 // In case it is invoked from other than WebPage.
852 Ecore_X_Event_Window_Property* ev = static_cast<Ecore_X_Event_Window_Property*>(event);
854 Ecore_X_Virtual_Keyboard_State state = ecore_x_e_virtual_keyboard_state_get(ev->win);
855 if (state == ECORE_X_VIRTUAL_KEYBOARD_STATE_ON)
856 s_isSystemKeypadShow = true;
857 else if (state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)
858 s_isSystemKeypadShow = false;
860 return ECORE_CALLBACK_PASS_ON;
862 #endif // #if ENABLE(TIZEN_ISF_PORT)