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;
56 if (ecore_x_e_virtual_keyboard_state_get(rootWin) == ECORE_X_VIRTUAL_KEYBOARD_STATE_ON)
57 s_isSystemKeypadShow = true;
60 Eina_Bool InputMethodContextEfl::windowPropertyChanged(void*, int, void* event)
62 Ecore_X_Event_Window_Property* propertyEvent = static_cast<Ecore_X_Event_Window_Property*>(event);
64 if (propertyEvent->atom == s_externalKeyboardProperty) {
66 if (ecore_x_window_prop_card32_get(propertyEvent->win, s_externalKeyboardProperty, &value, 1) <= 0 || s_shouldUseExternalKeyboard == value)
67 return ECORE_CALLBACK_PASS_ON;
69 s_shouldUseExternalKeyboard = value;
71 #if ENABLE(TIZEN_FOCUS_UI)
72 if (!s_shouldUseExternalKeyboard) {
73 Vector<RefPtr<WebPageProxy> > pages;
74 EwkViewImpl::pages(pages);
76 for (size_t i = 0; i < pages.size(); ++i)
77 pages[i]->setFocusUIEnabled(false);
80 } else if (propertyEvent->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE) {
81 if (ecore_x_e_virtual_keyboard_state_get(propertyEvent->win) == ECORE_X_VIRTUAL_KEYBOARD_STATE_ON)
82 s_isSystemKeypadShow = true;
84 s_isSystemKeypadShow = false;
87 return ECORE_CALLBACK_PASS_ON;
91 InputMethodContextEfl::InputMethodContextEfl(EwkViewImpl* viewImpl, PassOwnPtr<Ecore_IMF_Context> context)
92 : m_viewImpl(viewImpl)
95 #if ENABLE(TIZEN_ISF_PORT)
97 , m_state(ECORE_IMF_INPUT_PANEL_STATE_HIDE)
98 , m_candidateState(ECORE_IMF_CANDIDATE_PANEL_HIDE)
99 , m_inputPickerType(-1)
100 , m_doNotHandleFakeKeyEvent(false)
101 , m_fakeKeyEventTimer(this, &InputMethodContextEfl::fakeKeyEventTimerFired)
102 , m_approximateCursorPosition(0)
103 , m_isLastKeyEventFiltered(false)
106 #if ENABLE(TIZEN_ISF_PORT)
107 if (!s_externalKeyboardProperty)
108 initializeExternalKeyboard();
111 ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
112 ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
116 InputMethodContextEfl::~InputMethodContextEfl()
120 #if ENABLE(TIZEN_ISF_PORT)
121 void InputMethodContextEfl::onIMFInputPanelStateChanged(void* data, Ecore_IMF_Context*, int state)
123 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
125 inputMethodContext->setState(state);
127 if (state == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
128 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
129 if (!s_shouldUseExternalKeyboard && inputMethodContext->m_viewImpl->pageClient->isClipboardWindowOpened())
130 inputMethodContext->m_viewImpl->pageClient->closeClipboardWindow();
133 if (inputMethodContext->m_viewImpl->page()->editorState().hasComposition)
134 inputMethodContext->resetIMFContext();
136 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,closed", 0);
137 } else if (state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
138 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,opened", 0);
141 void InputMethodContextEfl::onIMFInputPanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
143 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
144 if (!inputMethodContext->m_context)
148 ecore_imf_context_input_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
149 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "inputmethod,changed", &rect);
151 inputMethodContext->setIMERect(IntRect(rect.x, rect.y, rect.w, rect.h));
154 void InputMethodContextEfl::onIMFCandidatePanelStateChanged(void* data, Ecore_IMF_Context*, int state)
156 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
158 inputMethodContext->setCandidateState(state);
160 if (state == ECORE_IMF_CANDIDATE_PANEL_SHOW)
161 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,opened", 0);
163 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,closed", 0);
166 void InputMethodContextEfl::onIMFCandidatePanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
168 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
169 if (!inputMethodContext->m_context)
173 ecore_imf_context_candidate_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
174 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,changed", &rect);
177 Eina_Bool InputMethodContextEfl::onIMFRetrieveSurrounding(void* data, Ecore_IMF_Context*, char** text, int* offset)
179 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
180 if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused || (!text && !offset))
183 const EditorState& editor = inputMethodContext->m_viewImpl->page()->editorState();
187 if (!inputMethodContext->m_approximateSurroundingText.isNull())
188 utf8Text = inputMethodContext->m_approximateSurroundingText.utf8();
190 utf8Text = editor.surroundingText.utf8();
191 size_t length = utf8Text.length();
193 *text = static_cast<char*>(malloc((length + 1) * sizeof(char)));
198 strncpy(*text, utf8Text.data(), length);
203 if (!inputMethodContext->m_approximateSurroundingText.isNull())
204 *offset = inputMethodContext->m_approximateCursorPosition;
206 *offset = editor.cursorPosition;
212 void InputMethodContextEfl::onIMFDeleteSurrounding(void* data, Ecore_IMF_Context*, void* eventInfo)
214 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
215 if (!eventInfo || !inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
218 inputMethodContext->requestFakeKeyEvent();
220 Ecore_IMF_Event_Delete_Surrounding* event = static_cast<Ecore_IMF_Event_Delete_Surrounding*>(eventInfo);
221 inputMethodContext->m_viewImpl->page()->deleteSurroundingText(event->offset, event->n_chars);
223 inputMethodContext->updateApproximateText(String(), event->offset, event->n_chars);
226 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
228 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
229 if (!eventInfo || !inputMethodContext->m_focused)
232 inputMethodContext->requestFakeKeyEvent();
234 String completeString = String::fromUTF8(static_cast<char*>(eventInfo));
235 inputMethodContext->m_viewImpl->page()->confirmComposition(completeString);
237 inputMethodContext->updateApproximateText(completeString, 0, 0);
240 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
241 unsigned getUTF8CharacterIndex(const char* string, unsigned byteIndex)
244 const char* end = string + byteIndex;
246 while (*string && string < end) {
249 if ((*string & 0x80) == 0x00)
251 else if ((*string & 0xe0) == 0xc0)
253 else if ((*string & 0xf0) == 0xe0)
255 else if ((*string & 0xf8) == 0xf0)
257 else if ((*string & 0xfc) == 0xf8)
259 else if ((*string & 0xfe) == 0xfc)
265 while (*string && offset--)
273 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
275 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
277 if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
280 WebPageProxy* page = inputMethodContext->m_viewImpl->page();
281 if (!page->focusedFrame())
284 inputMethodContext->requestFakeKeyEvent();
286 const EditorState& editor = inputMethodContext->m_viewImpl->page()->editorState();
287 PageClientImpl* pageClient = inputMethodContext->m_viewImpl->pageClient.get();
289 if (!editor.selectionIsNone && !editor.selectionIsRange) {
290 caretRect = editor.selectionRect;
291 caretRect.scale(pageClient->scaleFactor());
295 evas_object_geometry_get(inputMethodContext->m_viewImpl->view(), &viewX, &viewY, 0, 0);
297 int x = caretRect.x() - pageClient->scrollPosition().x() + viewX;
298 int y = caretRect.y() - pageClient->scrollPosition().y() + viewY;
299 int w = caretRect.width();
300 int h = caretRect.height();
301 ecore_imf_context_cursor_location_set(context, x, y, w, h);
304 Eina_List* preeditAttrs = 0;
305 int cursorPosition = 0;
307 ecore_imf_context_preedit_string_with_attributes_get(context, &buffer, &preeditAttrs, &cursorPosition);
309 String preeditString = String::fromUTF8(buffer);
310 Vector<CompositionUnderline> underlines;
314 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
315 Eina_List* listIterator = 0;
316 EINA_LIST_FOREACH(preeditAttrs, listIterator, item) {
317 Ecore_IMF_Preedit_Attr* preeditAttr = static_cast<Ecore_IMF_Preedit_Attr*>(item);
319 unsigned startIndex = getUTF8CharacterIndex(buffer, preeditAttr->start_index);
320 unsigned endIndex = getUTF8CharacterIndex(buffer, preeditAttr->end_index);
321 switch (preeditAttr->preedit_type) {
322 case ECORE_IMF_PREEDIT_TYPE_SUB1:
323 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), false));
325 case ECORE_IMF_PREEDIT_TYPE_SUB2:
326 case ECORE_IMF_PREEDIT_TYPE_SUB3:
327 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(255, 255, 255), false));
329 case ECORE_IMF_PREEDIT_TYPE_SUB4:
330 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(46, 168, 255), false));
332 case ECORE_IMF_PREEDIT_TYPE_SUB5:
333 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 98, 195), false));
335 case ECORE_IMF_PREEDIT_TYPE_SUB6:
336 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(118, 222, 55), false));
338 case ECORE_IMF_PREEDIT_TYPE_SUB7:
339 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 153, 153), false));
346 EINA_LIST_FREE(preeditAttrs, item)
350 if (underlines.isEmpty())
351 underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
353 page->setComposition(preeditString, underlines, cursorPosition);
358 inputMethodContext->updateApproximateText(preeditString, 0, 0);
361 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
363 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
364 if (!eventInfo || !inputMethodContext->m_focused)
367 inputMethodContext->m_viewImpl->page()->confirmComposition(String::fromUTF8(static_cast<char*>(eventInfo)));
370 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
372 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
374 if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
378 ecore_imf_context_preedit_string_get(context, &buffer, 0);
382 String preeditString = String::fromUTF8(buffer);
384 Vector<CompositionUnderline> underlines;
385 underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
386 inputMethodContext->m_viewImpl->page()->setComposition(preeditString, underlines, 0);
390 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::createIMFContext(Evas* canvas)
392 const char* defaultContextID = ecore_imf_context_default_id_get();
393 if (!defaultContextID)
396 OwnPtr<Ecore_IMF_Context> imfContext = adoptPtr(ecore_imf_context_add(defaultContextID));
400 Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(canvas);
401 ecore_imf_context_client_window_set(imfContext.get(), reinterpret_cast<void*>(ecore_evas_window_get(ecoreEvas)));
402 ecore_imf_context_client_canvas_set(imfContext.get(), canvas);
404 return imfContext.release();
407 void InputMethodContextEfl::handleMouseUpEvent(const Evas_Event_Mouse_Up*)
409 #if ENABLE(TIZEN_ISF_PORT)
415 ecore_imf_context_reset(m_context.get());
419 void InputMethodContextEfl::handleKeyDownEvent(const Evas_Event_Key_Down* downEvent, bool* isFiltered)
421 #if ENABLE(TIZEN_ISF_PORT)
425 const EditorState& state = m_viewImpl->page()->editorState();
427 if (!m_isLastKeyEventFiltered && !m_approximateSurroundingText.isNull())
428 ecore_imf_context_cursor_position_set(m_context.get(), m_approximateCursorPosition);
430 if (m_fakeKeyEventTimer.isActive())
431 m_fakeKeyEventTimer.stop();
433 m_viewImpl->page()->prepareKeyDownEvent();
435 m_doNotHandleFakeKeyEvent = true;
438 Ecore_IMF_Event inputMethodEvent;
439 ecore_imf_evas_event_key_down_wrap(const_cast<Evas_Event_Key_Down*>(downEvent), &inputMethodEvent.key_down);
441 *isFiltered = ecore_imf_context_filter_event(m_context.get(), ECORE_IMF_EVENT_KEY_DOWN, &inputMethodEvent);
443 #if ENABLE(TIZEN_ISF_PORT)
444 m_doNotHandleFakeKeyEvent = false;
445 m_isLastKeyEventFiltered = *isFiltered;
448 if (!strcmp(downEvent->key, "BackSpace")) {
449 if (state.cursorPosition > 0)
450 updateApproximateText(String(), state.cursorPosition - 1, 1);
451 } else if (!strcmp(downEvent->key, "Delete")) {
452 if (state.cursorPosition < state.surroundingText.length())
453 updateApproximateText(String(), state.cursorPosition, 1);
455 updateApproximateText(String::fromUTF8(downEvent->compose), 0, 0);
460 #if ENABLE(TIZEN_ISF_PORT)
461 void InputMethodContextEfl::updateTextInputState()
463 const EditorState& editor = m_viewImpl->page()->editorState();
464 if (editor.shouldIgnoreCompositionSelectionChange || editor.updateEditorRectOnly)
466 if (editor.isContentEditable)
467 showIMFContext(editor);
471 m_approximateSurroundingText = String();
474 ecore_imf_context_cursor_position_set(m_context.get(), editor.cursorPosition);
477 void InputMethodContextEfl::updateTextInputStateByUserAction(bool setFocus)
479 const EditorState& editor = m_viewImpl->page()->editorState();
481 if (editor.isContentEditable) {
483 evas_object_focus_set(m_viewImpl->view(), true);
485 showIMFContext(editor, true);
490 void InputMethodContextEfl::updateTextInputState()
495 const EditorState& editor = m_viewImpl->page()->editorState();
497 if (editor.isContentEditable) {
501 ecore_imf_context_reset(m_context.get());
502 ecore_imf_context_focus_in(m_context.get());
508 if (editor.hasComposition)
509 m_viewImpl->page()->cancelComposition();
512 ecore_imf_context_reset(m_context.get());
513 ecore_imf_context_focus_out(m_context.get());
518 #if ENABLE(TIZEN_ISF_PORT)
519 void InputMethodContextEfl::initializeIMFContext(Ecore_IMF_Context* context, Ecore_IMF_Input_Panel_Layout layout, int layoutVariation, Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType)
521 ecore_imf_context_input_panel_enabled_set(context, false);
522 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_STATE_EVENT, onIMFInputPanelStateChanged, this);
523 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, onIMFInputPanelGeometryChanged, this);
524 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, onIMFCandidatePanelStateChanged, this);
525 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, onIMFCandidatePanelGeometryChanged, this);
526 ecore_imf_context_retrieve_surrounding_callback_set(context, onIMFRetrieveSurrounding, this);
527 ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, onIMFDeleteSurrounding, this);
528 ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
529 ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
531 ecore_imf_context_input_panel_layout_set(context, layout);
532 if (layoutVariation >= 0)
533 ecore_imf_context_input_panel_layout_variation_set(context, layoutVariation);
534 ecore_imf_context_input_panel_return_key_type_set(context, returnKeyType);
537 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::takeContext(uintptr_t contextID)
539 size_t i = m_contextList.size();
542 if (m_contextList[i].first == contextID) {
543 PassOwnPtr<Ecore_IMF_Context> context = m_contextList[i].second.release();
544 m_contextList.remove(i);
549 return PassOwnPtr<Ecore_IMF_Context>();
552 void InputMethodContextEfl::setIMFContext(const EditorState& editor)
554 const String& type = editor.inputMethodHints;
555 Ecore_IMF_Input_Panel_Layout layout;
556 int layoutVariation = -1;
557 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
559 if (type == "number") {
560 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
561 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_NORMAL;
562 } else if (type == "signedNumber") {
563 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
564 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED;
565 } else if (type == "decimalNumber") {
566 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
567 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_DECIMAL;
568 } else if (type == "signedDecimalNumber") {
569 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
570 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL;
571 } else if (type == "email")
572 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL;
573 else if (type == "url")
574 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_URL;
575 else if (type == "tel")
576 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER;
577 else if (type == "password")
578 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD;
580 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
581 if (type == "search")
582 returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH;
585 OwnPtr<Ecore_IMF_Context> context;
586 if (m_contextID == editor.inputMethodContextID)
587 context = m_context.release();
589 context = takeContext(editor.inputMethodContextID);
594 context = createIMFContext(evas_object_evas_get(m_viewImpl->view()));
597 initializeIMFContext(context.get(), layout, layoutVariation, returnKeyType);
600 m_context = context.release();
601 m_contextID = editor.inputMethodContextID;
603 if (type == "password" || type == "plugin")
604 ecore_imf_context_prediction_allow_set(m_context.get(), false);
606 ecore_imf_context_prediction_allow_set(m_context.get(), true);
608 if (type.isEmpty() || type == "textarea")
609 ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE);
611 ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
614 bool InputMethodContextEfl::isShow()
616 return (m_context && m_focused && ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
619 Ecore_IMF_Autocapital_Type InputMethodContextEfl::autoCapitalType()
621 return (m_context ? ecore_imf_context_autocapital_type_get(m_context.get()) : ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
624 void InputMethodContextEfl::onFocusIn()
626 if (m_inputPickerType >= 0) {
627 showInputPicker(m_viewImpl->page()->editorState());
631 if (!m_context || !m_focused)
634 ecore_imf_context_focus_in(m_context.get());
635 ecore_imf_context_input_panel_show(m_context.get());
636 if (!isSystemKeypadShow())
637 setState(ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW);
640 void InputMethodContextEfl::onFocusOut()
642 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
643 if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
644 if (m_viewImpl->pageClient->isClipboardWindowOpened())
645 m_viewImpl->pageClient->closeClipboardWindow();
649 #if ENABLE(TIZEN_FOCUS_UI)
650 m_viewImpl->page()->setFocusUIEnabled(false);
653 if (!m_context || !m_focused)
656 ecore_imf_context_input_panel_hide(m_context.get());
657 ecore_imf_context_focus_out(m_context.get());
660 void InputMethodContextEfl::revertIMFContext()
665 if (m_contextList.size() >= maxContextSize)
666 m_contextList.remove(0);
668 PassOwnPtr<Ecore_IMF_Context> imfContext = m_context.release();
669 m_contextList.append(std::make_pair(m_contextID, imfContext));
673 void InputMethodContextEfl::resetIMFContext()
678 m_doNotHandleFakeKeyEvent = true;
679 ecore_imf_context_reset(m_context.get());
680 m_doNotHandleFakeKeyEvent = false;
683 void InputMethodContextEfl::showIMFContext(const EditorState& editor, bool isUserAction)
685 Ewk_Settings* settings = ewk_view_settings_get(m_viewImpl->view());
686 bool isContextTransition = (m_contextID && m_contextID != editor.inputMethodContextID);
688 if (!isUserAction && !isContextTransition) {
689 if (!ewk_settings_uses_keypad_without_user_action_get(settings) || (m_focused && m_contextID == editor.inputMethodContextID))
693 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
694 if (m_viewImpl->pageClient->isClipboardWindowOpened())
698 if (m_contextID != editor.inputMethodContextID)
703 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
704 if (editor.inputMethodHints == "date")
705 m_inputPickerType = EWK_INPUT_TYPE_DATE;
706 else if (editor.inputMethodHints == "datetime")
707 m_inputPickerType = EWK_INPUT_TYPE_DATETIME;
708 else if (editor.inputMethodHints == "datetime-local")
709 m_inputPickerType = EWK_INPUT_TYPE_DATETIMELOCAL;
710 else if (editor.inputMethodHints == "month")
711 m_inputPickerType = EWK_INPUT_TYPE_MONTH;
712 else if (editor.inputMethodHints == "time")
713 m_inputPickerType = EWK_INPUT_TYPE_TIME;
714 else if (editor.inputMethodHints == "week")
715 m_inputPickerType = EWK_INPUT_TYPE_WEEK;
717 m_inputPickerType = -1;
719 if (m_inputPickerType >= 0) {
720 showInputPicker(editor);
721 m_contextID = editor.inputMethodContextID;
725 #endif // ENABLE(TIZEN_INPUT_TAG_EXTENSION)
727 bool hasFocus = evas_object_focus_get(m_viewImpl->view());
729 if (!ewk_settings_default_keypad_enabled_get(settings)) {
731 Eina_Rectangle dummyRectForCustomKeypadCallback;
732 memset(&dummyRectForCustomKeypadCallback, 0, sizeof(Eina_Rectangle));
733 evas_object_smart_callback_call(m_viewImpl->view(), "inputmethod,changed", &dummyRectForCustomKeypadCallback);
738 setIMFContext(editor);
745 // input field zoom for external keyboard
746 if (s_shouldUseExternalKeyboard)
747 ewk_view_focused_node_adjust(m_viewImpl->view(), EINA_TRUE);
750 ewk_view_focused_node_adjust(m_viewImpl->view());
754 ecore_imf_context_focus_in(m_context.get());
755 ecore_imf_context_input_panel_show(m_context.get());
756 setState(ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW);
759 void InputMethodContextEfl::hideIMFContext()
761 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
762 if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW || m_candidateState == ECORE_IMF_CANDIDATE_PANEL_SHOW) {
763 if (m_viewImpl->pageClient->isClipboardWindowOpened())
764 m_viewImpl->pageClient->closeClipboardWindow();
768 m_inputPickerType = -1;
774 if (evas_object_focus_get(m_viewImpl->view())) {
776 ecore_imf_context_input_panel_hide(m_context.get());
777 ecore_imf_context_focus_out(m_context.get());
783 void InputMethodContextEfl::destroyIMFContextList()
785 m_contextList.clear();
788 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
789 void InputMethodContextEfl::showInputPicker(const EditorState& editorState)
791 if (editorState.selectionIsRange || !evas_object_focus_get(m_viewImpl->view()))
794 ewkViewInputPickerRequest(m_viewImpl->view(), static_cast<Ewk_Input_Type>(m_inputPickerType), editorState.surroundingText);
795 m_inputPickerType = -1;
799 bool InputMethodContextEfl::isIMEPostion(int x, int y)
801 if (m_state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
802 return m_imeRect.contains(x, y);
807 void InputMethodContextEfl::removeIMFContext(uintptr_t contextID)
809 if (m_contextID == contextID)
812 takeContext(contextID);
815 void InputMethodContextEfl::requestFakeKeyEvent()
817 if (m_doNotHandleFakeKeyEvent || m_fakeKeyEventTimer.isActive())
820 m_fakeKeyEventTimer.startOneShot(0);
821 m_viewImpl->page()->prepareKeyDownEvent();
824 void InputMethodContextEfl::fakeKeyEventTimerFired(WebCore::Timer<InputMethodContextEfl>*)
827 if (!m_approximateSurroundingText.isNull()) {
828 if (!m_approximateCursorPosition)
829 ch = m_approximateSurroundingText[0];
830 else if (m_approximateCursorPosition > m_approximateSurroundingText.length())
831 ch = m_approximateSurroundingText[m_approximateSurroundingText.length() - 1];
833 ch = m_approximateSurroundingText[m_approximateCursorPosition - 1];
837 if (Unicode::isSeparatorSpace(ch))
839 else if (Unicode::isPrintableChar(ch))
844 CString stringForEvent = string.utf8();
845 const char* data = stringForEvent.data();
847 Evas_Event_Key_Down downEvent;
848 memset(&downEvent, 0, sizeof(Evas_Event_Key_Down));
849 downEvent.key = data;
850 downEvent.string = data;
851 NativeWebKeyboardEvent nativeEvent(&downEvent, true);
852 nativeEvent.setInputMethodContextID(m_viewImpl->page()->editorState().inputMethodContextID);
853 m_viewImpl->page()->handleKeyboardEvent(nativeEvent);
855 Evas_Event_Key_Up upEvent;
856 memset(&upEvent, 0, sizeof(Evas_Event_Key_Up));
858 upEvent.string = data;
859 m_viewImpl->page()->handleKeyboardEvent(NativeWebKeyboardEvent(&upEvent));
862 void InputMethodContextEfl::updateApproximateText(const String& text, unsigned removePosition, unsigned removeLength)
864 if (m_approximateSurroundingText.isNull()) {
865 const EditorState& state = m_viewImpl->page()->editorState();
867 m_approximateSurroundingText = state.surroundingText;
868 if (m_approximateSurroundingText.isNull())
869 m_approximateSurroundingText = emptyString();
870 m_approximateCursorPosition = state.cursorPosition;
873 if (!text.isNull()) {
874 m_approximateSurroundingText.insert(text, m_approximateCursorPosition);
875 m_approximateCursorPosition += text.length();
877 m_approximateSurroundingText.remove(removePosition, removeLength);
878 if (m_approximateCursorPosition > removePosition && m_approximateCursorPosition <= removePosition + removeLength)
879 m_approximateCursorPosition = removePosition;
883 bool InputMethodContextEfl::recalcFilterEvent(const Ecore_IMF_Event* event)
888 m_doNotHandleFakeKeyEvent = true;
889 bool isFiltered = ecore_imf_context_filter_event(m_context.get(), ECORE_IMF_EVENT_KEY_DOWN, const_cast<Ecore_IMF_Event*>(event));
890 m_doNotHandleFakeKeyEvent = false;
894 #endif // #if ENABLE(TIZEN_ISF_PORT)